/****************************************************************************/ /* Copyright 1991 MBARI */ /****************************************************************************/ /* $Header: file.c,v 2.6 96/05/30 15:07:55 bobh Exp $ */ /* Summary : File Handling Routines for `extract` */ /* Filename : file.c */ /* Author : Robert Herlien (rah) */ /* Project : OASIS Mooring */ /* $Revision: 2.6 $ */ /* Created : 02/05/91 */ /****************************************************************************/ /* Modification History: */ /* 05feb92 rah - created */ /* $Log: file.c,v $ * Revision 2.6 96/05/30 15:07:55 15:07:55 bobh (Bob Herlien) * Update for version in use during 1995-6 deployment * * Revision 2.5 94/12/15 10:59:38 10:59:38 hebo (Bob Herlien) * Accumulated minor changes, mainly due to move to tsunami * * Revision 2.4 94/01/21 14:36:15 14:36:15 hebo (Bob Herlien) * Added support for date ranges in cfg file * * Revision 2.1 94/01/17 11:07:40 11:07:40 hebo (Bob Herlien) * Misc changes * * Revision 2.0 92/08/31 15:35:51 15:35:51 hebo (Bob Herlien) * Auguest 1992 Deployment. Changed to allow multiple sensors of same type. * * Revision 1.2 92/05/12 18:19:29 18:19:29 hebo (Bob Herlien) * Added spectroradiometer decoding (spec.c) * * Revision 1.1 92/03/16 15:42:31 15:42:31 hebo (Bob Herlien) * Ignore leading blanks on "begin" line * * Revision 1.0 92/02/25 10:46:59 10:46:59 hebo (Bob Herlien) * Initial revision */ /****************************************************************************/ #include /* Standard I/O */ #include /* MBARI type definitions */ #include /* MBARI constants */ #include /* OASIS controller definitions */ #include /* Time */ #include /* for isspace() */ #include /* for strcmp() */ #include /* variable argument lists */ #define UUBUFSIZE 512 /* Size of uu decode buffer */ #define LINEBUFSIZE 512 /* Size of line buffer */ #define BNAMESIZE 64 /* Size of file base name */ #define NAMESIZE 256 /* Space allocated for file names */ #define BASE_DIR "/oasis/" #define CFG_DIR "/oasis/cfg" #define HDR_DIR "/oasis/cfg" #define OASIS_CHAN 2 /* Analog chan num for OASIS stuff */ #define DEC(c) (((c) - ' ') & 0x3f) /* uudecode macro */ typedef struct /************************************/ { /* FilePtr struct - File Ptr and name*/ FILE *fp; /* File pointer */ Int ftime; /* Time that name of file represents*/ /* as in yyddd (year, julday) */ char *fname; /* File base name */ } FilePtr; /************************************/ typedef struct /************************************/ { /* CalStruct - Funcs to read cal files*/ char *cs_name; /* Keyword in cfg file */ Status (*cs_func)(); /* Function to read cal file */ Void *cs_parm; /* Ptr parm to pass to cs_func */ MBool cs_got_dated_cal; /* Boolean - parsed a dated cal line*/ } CalStruct; /************************************/ /********************************/ /* External Functions */ /********************************/ Extern Status read_atlas_cal( char *name, AtlasCal *cp ); Extern Status read_ctd_cal( char *name, CTDCal *ccp ); Extern Status read_no3_cal( char *name, No3Cal *no3cp ); Extern Status read_spec_cal( char *name, SpecCal *scp ); Extern Status read_satlantic_cal( char *name, SatlanticCal *scp ); /********************************/ /* External Data */ /********************************/ Extern Int itime; /* Integer year/day as yyddd */ /********************************/ /* Forward Declarations */ /********************************/ Status store_dirname( char *name, char *where ); Status store_fname( char *name, char **where ); Status analog_cal( char *parm, Analog *cp, char *tail ); Status storeOasisChan( char *parm, Nat32 *where ); /********************************/ /* Global Data */ /********************************/ Global char can_name[BNAMESIZE]; /* Name of OASIS can */ Global AtlasCal atlas_cal; /* ATLAS calibration */ Global Analog analog[ANALOG_CHANS]; /* Analog calibration */ Global CTDCal ctd_cal[NUM_CTDS]; /* Structs to hold CTD calibrations */ Global No3Cal no3_cal[NUM_NO3S]; /* Structs to hold NO3 calibrations */ Global SpecCal spec_cal[NUM_SPECS]; /* Structs to hold Spect calibrations*/ Global SatlanticCal satlantic_cal; /* Struct to hold Satlantic cal */ Global Nat32 oasisAnalogChan = OASIS_CHAN; /********************************/ /* Module Local Data */ /********************************/ MLocal double dfiletime; /* Time portion of data file name */ /* E.g. m1a.93001.01 => 93001.01 */ MLocal Byte uubuf[UUBUFSIZE]; /* Buffer for raw uuencoded data */ MLocal char base_dir[NAMESIZE]; /* Name of base dir for output data */ MLocal char hdr_dir[NAMESIZE]; /* Name of directory for headers */ MLocal char cfg_file[NAMESIZE]; /* Name of OASIS configuration file */ MLocal char line_buf[LINEBUFSIZE]; /* Place to scan line input */ MLocal char keywd_buf[NAMESIZE]; /* String buffer for keyword compare*/ MLocal char name_buf[NAMESIZE]; /* String buffer for name parameter */ MLocal char *oasis_m1b_name = "oasis.m1b"; MLocal FilePtr files[] = /* File ptrs and names for outputs */ { {NULLF, 0, "error"}, {NULLF, 0, ""}, {NULLF, 0, "atlas"}, {NULLF, 0, "oasis"}, {NULLF, 0, "par"}, {NULLF, 0, "ctd"}, {NULLF, 0, "spectro"}, {NULLF, 0, "adcp"}, {NULLF, 0, "gps"}, {NULLF, 0, "modem"}, {NULLF, 0, "pco2"}, {NULLF, 0, "ctd2"}, {NULLF, 0, "ctd"}, {NULLF, 0, "spectro10"}, {NULLF, 0, "spectro20"}, {NULLF, 0, "nitrate"}, {NULLF, 0, "nitrate2"}, {NULLF, 0, "specprr"}, {NULLF, 0, "satlantic"}, {NULLF, 0, "gps"}, {NULLF, 0, "nrl"}, {NULLF, 0, "oxygen"}, {NULLF, 0, "fluor"}, {NULLF, 0, "transmiss"}, {NULLF, 0, "no3"}, {NULLF, 0, "no3.2"}, {NULLF, 0, "ac9"}, {NULLF, 0, "pump"}, {NULLF, 0, "pump"} }; MLocal CalStruct cals[] = /* File funcs and names for calibr */ { { "errors", store_fname, (Void *)&(files[ERRORF].fname), FALSE }, { "data", store_dirname, (Void *)base_dir, FALSE }, { "header", store_dirname, (Void *)hdr_dir, FALSE }, { "analog", analog_cal, (Void *)analog, FALSE }, { "oasis_chan", storeOasisChan, (Void *)&oasisAnalogChan, FALSE }, #ifndef ARGOS { "atlas", read_atlas_cal, (Void *)&atlas_cal, FALSE }, { "ctd", read_ctd_cal, (Void *)&ctd_cal[CTD_CAL], FALSE }, { "ctd2", read_ctd_cal, (Void *)&ctd_cal[CTD2_CAL], FALSE }, { "ctd3", read_ctd_cal, (Void *)&ctd_cal[CTD3_CAL], FALSE }, { "no3", read_no3_cal, (Void *)&no3_cal[NO3_CAL], FALSE }, { "no3.2", read_no3_cal, (Void *)&no3_cal[NO3_CAL2], FALSE }, { "spectro", read_spec_cal, (Void *)&spec_cal[SPECTRO_CAL], FALSE }, { "spectro10", read_spec_cal, (Void *)&spec_cal[SPECTRO2_CAL], FALSE }, { "spectro20", read_spec_cal, (Void *)&spec_cal[SPECTRO3_CAL], FALSE }, { "satlantic", read_satlantic_cal, (Void *)&satlantic_cal, FALSE }, #endif { "specprr", read_spec_cal, (Void *)&spec_cal[SPECPRR_CAL], FALSE } }; /************************************************************************/ /* Function : get_begin_line */ /* Purpose : Look for "begin" line in uuencode file */ /* Inputs : FILE pointer */ /* Outputs : Log number n from "begin 644 oasis.n". */ /************************************************************************/ Int32 get_begin_line( FILE *fd ) { Int32 unused, lognum; while ( fgets((char *)uubuf, sizeof(uubuf), fd) != NULL ) { if ( sscanf((char *)uubuf, " begin %d oasis.%d", &unused, &lognum) >= 2) return( lognum ); } return( ERROR ); } /* get_begin_line() */ /************************************************************************/ /* Function : uuopen */ /* Purpose : Open a uuencoded file, check its "begin" line */ /* Inputs : Name of file */ /* Outputs : FILE pointer */ /************************************************************************/ FILE *uuopen( char *name ) { FILE *fd; if ( (fd = fopen(name, "rb")) == (FILE *)NULL ) printf("Cannot open %s\n", name); return( fd ); } /* uuopen() */ /************************************************************************/ /* Function : uudecode */ /* Purpose : Decode a group of 3 binary bytes from 4 input characters*/ /* Inputs : Ptr to input chars, ptr to output, number of bytes */ /* Outputs : None */ /************************************************************************/ Void uudecode( Byte *in, Byte *out, Int len ) { Byte *p; p =out; if ( len >= 1 ) *p++ = (DEC(*in) << 2) | (DEC(in[1]) >> 4); if ( len >= 2 ) *p++ = (DEC(in[1]) << 4) | (DEC(in[2]) >> 2); if ( len >= 3 ) *p = (DEC(in[2]) << 6) | (DEC(in[3])); } /* uudecode() */ /************************************************************************/ /* Function : uugetline */ /* Purpose : Read and decode one line from a uuencoded file */ /* Inputs : Buffer for resulting data, size of buffer, FILE ptr */ /* Outputs : Number characters read, UUERROR if error, or EOF */ /************************************************************************/ Int32 uugetline( Byte *buf, Int len, FILE *fd ) { Nat32 uulen, i; Byte *p, *q; char *p1; if ( fgets((char *)uubuf, sizeof(uubuf), fd) == NULL ) return( EOF ); if (strncmp((char *)uubuf, "end", 3) == 0) return( UUEND ); uulen = DEC(uubuf[0]); if ( (p1 = strchr((char *)uubuf, '\n')) != NULL ) *p1 = '\0'; if ( (p1 = strchr((char *)uubuf, '\r')) != NULL ) *p1 = '\0'; if ( strlen((char *)uubuf) != (((uulen + 2)/3 * 4) + 1) ) return( UUERROR ); p = &uubuf[1]; q = buf; for ( i = uulen; i > 0; i -= 3 ) { uudecode( p, q, i ); p += 4; q += 3; } return( uulen ); } /* uugetline() */ /************************************************************************/ /* Function : uuread */ /* Purpose : Read and decode len bytes from a uuencoded file */ /* Inputs : Buffer for resulting data, size of buffer, FILE ptr */ /* Outputs : Number characters read, UUERROR if error, or EOF */ /* Comment : OASIS records should always begin and end at new line */ /* This function calls uugetline() for the appropriate */ /* number of bytes, and returns UUERROR if size wrong */ /************************************************************************/ Int uuread( Byte *buf, Int len, FILE *fd ) { Int32 i, left; Byte *p; for ( p = buf, left = len; left > 0; ) { if ( (i = uugetline(p, left, fd)) <= 0 ) return( i ); left -= i; p += i; if ( left < 0 ) return( UUERROR ); } return( len ); } /* uuread() */ /************************************************************************/ /* Function : get_sensor_file */ /* Purpose : Get file pointer for given sensor */ /* Inputs : Sensor */ /* Outputs : None */ /************************************************************************/ FILE * get_sensor_file( Int sensor ) { FILE *fp, *hdrp; Int c; if ( (fp = files[sensor].fp) != NULLF ) { if ( files[sensor].ftime == itime ) return( fp ); fclose( fp ); } if ( files[sensor].fname[0] == '/' ) sprintf( line_buf, "%s/%05d", files[sensor].fname, itime ); else sprintf( line_buf, "%s/%s/%05d", base_dir, files[sensor].fname, itime ); if ( (fp = fopen(line_buf,"a")) == NULLF ) { if ( sensor == ERRORF ) fp = stderr; files[sensor].fp = fp; fprintf( files[ERRORF].fp, "Cannot open %s\n", line_buf ); return( fp ); } files[sensor].fp = fp; files[sensor].ftime = itime; sprintf( line_buf, "%s/%s.hdr", hdr_dir, files[sensor].fname ); if ( (hdrp = fopen(line_buf,"r")) != NULLF ) { if ( ftell(fp) == 0 ) while ( (c = fgetc(hdrp)) != EOF ) fputc(c, fp); fclose( hdrp ); } return( fp ); } /* get_sensor_file() */ /************************************************************************/ /* Function : close_sensor_files */ /* Purpose : Close all output files for sensors */ /* Inputs : None */ /* Outputs : None */ /************************************************************************/ Void close_sensor_files( Void ) { Int i; for ( i = ATLAS; i < SENSORS; i++ ) if ( files[i].fp != NULLF ) { fclose( files[i].fp ); files[i].fp = NULLF; } } /* close_sensor_files() */ /************************************************************************/ /* Function : print_error */ /* Purpose : Print error message to error file */ /* Inputs : Format string, arguments as in printf */ /* Outputs : None */ /************************************************************************/ Void print_error( char *fmt, ... ) { va_list ap; /* Argument pointer */ FILE *fp; /* Error file pointer */ va_start( ap, fmt ); if ( (fp = get_sensor_file(ERRORF)) == NULLF ) fp = stderr; vfprintf( fp, fmt, ap ); } /* print_error() */ /************************************************************************/ /* Function : print_sensor */ /* Purpose : Print to sensor file */ /* Inputs : Sensor, format string, arguments as in printf */ /* Outputs : None */ /************************************************************************/ Void print_sensor( Int sensor, char *fmt, ... ) { va_list ap; /* Argument pointer */ FILE *fp; /* Error file pointer */ va_start( ap, fmt ); if ( (fp = get_sensor_file(sensor)) != NULLF ) vfprintf( fp, fmt, ap ); } /* print_sensor() */ /************************************************************************/ /* Function : store_dirname */ /* Purpose : Store a directory name in local static data */ /* Inputs : Where to store name, name to store */ /* Outputs : OK */ /************************************************************************/ Status store_dirname( char *name, char *where ) { strncpy( where, name, BNAMESIZE ); return( OK ); } /* store_dirname() */ /************************************************************************/ /* Function : store_fname */ /* Purpose : Allocate space and store a file name */ /* Inputs : Name to store, where to put new pointer */ /* Outputs : OK or ERROR */ /************************************************************************/ Status store_fname( char *name, char **where ) { Reg char *p; if ( (p = (char *)malloc(strlen(name) + 1)) == NULL ) return( ERROR ); strcpy( p, name ); *where = p; return( OK ); } /* store_fname() */ /************************************************************************/ /* Function : analog_cal */ /* Purpose : Read analog calibration directly from cfg file */ /* Inputs : Dummy parameter, ptr to analog cal struct, ptr to tail */ /* of cfg file line */ /* Outputs : OK */ /************************************************************************/ Status analog_cal( char *parm, Analog *cp, char *tail ) { char unitname[UNITNAMELEN]; Int channel, i; double a, b, c, d; if ( (i = sscanf(tail, " %d %lf %lf %lf %lf %s", &channel, &a, &b, &c, &d, unitname)) >= 3 ) { analog[channel].a = a; analog[channel].b = b; analog[channel].c = c; analog[channel].d = d; if ( i >= 6 ) strncpy( analog[channel].units, unitname, UNITNAMELEN ); } return( OK ); } /* analog_cal() */ /************************************************************************/ /* Function : storeOasisChan */ /* Purpose : Store OASIS analog channel number */ /* Inputs : Dummy parameter, ptr to analog cal struct, ptr to tail */ /* of cfg file line */ /* Outputs : OK */ /************************************************************************/ Status storeOasisChan( char *parm, Nat32 *where ) { sscanf( parm, " %d", where ); return( OK ); } /* storeOasisChan() */ /************************************************************************/ /* Function : get_can_name */ /* Purpose : Get name of OASIS can, set base & hdr directory names */ /* Inputs : Name of data file */ /* Outputs : Ptr to Global variable can_name */ /* Side Effects: Fills in can_name with name of OASIS can */ /* Sets base and header directory names */ /* Sets Global variable dfiletime */ /* Sets name of OASIS data file, if necessary */ /************************************************************************/ Void get_can_name( char *dataname ) { Reg char *p, *q; Reg Nat32 i; if ( (p = strrchr(dataname, '/')) == NULL ) p = dataname; else p++; if ( (q = strchr(p, '.')) != NULL ) i = q - p; else i = strlen(p); strncpy( can_name, p, i ); can_name[i] = '\0'; if ( strncmp(can_name, "m1", 2) == 0 ) { sprintf( base_dir, "%s/m1", BASE_DIR ); sprintf( hdr_dir, "%s/m1", HDR_DIR ); } else { sprintf( base_dir, "%s/%s", BASE_DIR, can_name ); sprintf( hdr_dir, "%s/%s", HDR_DIR, can_name ); } if ( strcmp(can_name, "m1b") == 0 ) files[OASIS_CAN].fname = oasis_m1b_name; /* Now get data file name as a floating point number */ /* E.g., /dir/m1a.93001.01 -> (double)93001.01 */ for ( i = 0, q = p + strlen(p); (q != p) && (i < 2); ) if ( *--q == '.' ) /* Look for 2nd '.' from end*/ i++; if ( *q == '.' ) q++; if ( sscanf(q, "%lg", &dfiletime) < 1 ) dfiletime = 0.0; } /* get_can_name() */ /************************************************************************/ /* Function : read_cfg */ /* Purpose : Read OASIS configuration file */ /* Inputs : Ptr to cfg file name ptr */ /* Outputs : OK or ERROR */ /************************************************************************/ Status read_cfg( char **cfgname ) { Reg FILE *fp; Reg Int32 i; Nat32 n; Reg char *p; double starttime, endtime; MBool dated; memset( (void *)ctd_cal, sizeof(ctd_cal), 0 ); memset( (void *)no3_cal, sizeof(no3_cal), 0 ); memset( (void *)spec_cal, sizeof(spec_cal), 0 ); memset( (void *)analog, sizeof(analog), 0 ); if ( *cfgname == NULL ) { sprintf( cfg_file, "%s/%s.cfg", CFG_DIR, can_name ); *cfgname = cfg_file; } if ( (fp = fopen(*cfgname, "rb")) == (FILE *)NULL ) return( ERROR ); memset( (void *)&analog, 0, ANALOG_CHANS * sizeof(Analog) ); for ( i = 0; i < (sizeof(cals)/sizeof(CalStruct)); i++ ) cals[i].cs_got_dated_cal = FALSE; while ( fgets(line_buf, sizeof(line_buf), fp) != NULL ) { /* Read one line of input*/ p = line_buf; dated = FALSE; if ((i = sscanf(line_buf, " %lg - %lg%n", &starttime, &endtime, &n)) == 2) { p += n; dated = TRUE; } if ( sscanf(p, " %s%n %s", keywd_buf, &n, name_buf) == 2 ) for ( i = 0; i < (sizeof(cals)/sizeof(CalStruct)); i++ ) if ( strcasecmp(keywd_buf, cals[i].cs_name) == 0 ) if ( (dated && (dfiletime > starttime - .005) && (dfiletime < endtime + .005)) || (!dated && (!cals[i].cs_got_dated_cal)) ) { if ( (*cals[i].cs_func)(name_buf, cals[i].cs_parm, p+n) != OK ) printf("Can't read calibration file %s\n", name_buf); else if ( dated ) cals[i].cs_got_dated_cal = TRUE; break; } } fclose( fp ); return( OK ); } /* read_cfg() */ /************************************************************************/ /* Function : getIntelword */ /* Purpose : Get a word in Intel format from data stream */ /* Inputs : Ptr to data stream */ /* Outputs : Word */ /************************************************************************/ Nat16 getIntelword( Byte *p ) { Nat16 rtn; rtn = (Nat16)(*p); rtn += (Nat16)(p[1] << 8); return( rtn ); } /* getIntelword() */ /************************************************************************/ /* Function : getIntellong */ /* Purpose : Get a longword in Intel format from data stream */ /* Inputs : Ptr to data stream */ /* Outputs : Long */ /************************************************************************/ Nat32 getIntellong( Byte *p ) { Nat32 rtn; rtn = (Nat32)getIntelword(p); rtn += ((Nat32)getIntelword(&p[2]) << 16); return( rtn ); } /* getIntellong() */ /************************************************************************/ /* Function : getMotword */ /* Purpose : Get a word in Motorola format from data stream */ /* Inputs : Ptr to data stream */ /* Outputs : Word */ /************************************************************************/ Nat16 getMotword( Byte *p ) { Nat32 rtn; rtn = (Nat16)(*p << 8); rtn += (Nat16)(p[1]); return( rtn ); } /* getMotword() */