Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

gseputaway.c

Go to the documentation of this file.
00001 /******************************************************************
00002  * gseputaway.c - routines to enable GSE data to be stored from
00003  *                Earthworm
00004  *
00005  * S. Flower, Feb 2001
00006  *
00007  * Modified 11 Oct 2001 - instead of writing direct to the GSE
00008  * file we write to a temporary file and rename it when it is
00009  * complete - this ensures that the file can be read OK as soon
00010  * as it is available.
00011  *
00012  * Modified 11 Oct 2001 - removed the check that all requested
00013  * channels had been written - GSE can cope if there are missing
00014  * channels and the check was deleting files if all channels were
00015  * not present.
00016  *
00017  * Modified 26 Oct 2001 - fixed bug that puts gaps at wrong end
00018  * of output traces
00019  *
00020  * Modified 31st Jan 2002 - new routines to make dealing with
00021  * earthworm data structures easier to follow (pa_find_data())
00022  ******************************************************************/
00023 
00024 #include <stdio.h>
00025 #include <time.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <errno.h>
00029 #include <math.h>
00030 #if defined (_WINNT)
00031 #include <process.h>
00032 #include <io.h>
00033 #endif
00034 
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 
00038 #include "earthworm.h"
00039 #include "earthworm_defs.h"
00040 #include "trace_buf.h"
00041 #include "swap.h"
00042 #include "ws_clientII.h"
00043 #include "site.h"
00044 #include "time_ew.h"
00045 
00046 #include "gsehead.h"
00047 #include "seihead.h"
00048 
00049 
00050 /* the value used to represent missing data in GSE */
00051 #define GSE_MISSING_DATA_FLAG           0
00052 
00053 /* private global variables */
00054 static char *line_terminator;
00055 static char *file_open_mode;
00056 static char gse_filename [MAX_DIR_LEN];
00057 static char tmp_filename [MAX_DIR_LEN];
00058 static FILE *gse_fp;
00059 static int new_data_channel;
00060 static long channel_checksum = 0l;
00061 static int data_line_length;
00062 static int n_channels, channels_written;
00063 
00064 /* private forward declarations */
00065 static int open_gse_file (char *filename, char *msg_id, char *sta_code);
00066 static int write_gse_channel_header (int start_year, int start_month, int start_day,
00067                                      int start_hour, int start_min, double start_sec,
00068                                      char *chan_name, char *chan_type, char *aux_id,
00069                                      long n_samps,
00070                                      double frequency, double calib_value,
00071                                      double calib_period, char *instrum_name,
00072                                      double horiz_angle, double vert_angle);
00073 static int write_gse_channel_data (int n_samps, long *data);
00074 static int write_gse_channel_trailer (void);
00075 static int close_gse_file (void);
00076 
00077 
00078 
00079 /**********************************************************************
00080  * GSEPA_init
00081  *
00082  * Description: initialise GSE put away routines
00083  *
00084  * Input parameters: output_dir - the directory to be used for GSE
00085  *                                output files
00086  *                   output_format - "intel" or "sparc" for line termination
00087  *                   debug - flag for debugging output
00088  * Output parameters: none
00089  * Returns: EW_SUCCESS or EW_FAILURE
00090  *
00091  * Comments:
00092  *
00093  ***********************************************************************/
00094 int GSEPA_init (char *output_dir, char *output_format, int debug)
00095 
00096 {
00097     
00098   if (debug)
00099   {
00100     logit ("e", "Entering GSEPA_init, output dir: %s\n", output_dir);
00101   }
00102 
00103   /* make sure that the output directory exists */
00104   if (CreateDir (output_dir) != EW_SUCCESS)
00105   {
00106     logit ("e", "GSEPA_init: Call to CreateDir failed\n");
00107     return EW_FAILURE;
00108   }
00109 
00110 #if defined (_INTEL)
00111   if (! strcmp (output_format, "intel"))
00112   {
00113     line_terminator = "\n";
00114     file_open_mode = "w";
00115   }
00116   else if (! strcmp (output_format, "sparc"))
00117   {
00118     line_terminator = "\n";
00119     file_open_mode = "wb";
00120   }
00121   else
00122   {
00123     logit ("e", "GSEPA_init: can't recognise OutputFormat (%s)\n", output_format);
00124     return EW_FAILURE;
00125   }
00126 #elif defined (_SPARC)
00127   if (! strcmp (output_format, "sparc"))
00128   {
00129     line_terminator = "\n";
00130     file_open_mode = "w";
00131   }
00132   else if (! strcmp (output_format, "intel"))
00133   {
00134     line_terminator = "\r\n";
00135     file_open_mode = "wb";
00136   }
00137   else
00138   {
00139     logit ("e", "SEIPA_init: can't recognise OutputFormat (%s)\n", output_format);
00140     return EW_FAILURE;
00141   }
00142 #else
00143 #error "_INTEL or _SPARC must be set before compiling"
00144 #endif
00145 
00146   return EW_SUCCESS;
00147 
00148 }
00149 
00150 /****************************************************************************
00151  * GSEPA_next_ev
00152  *
00153  * Description: called when a snippet has been received,
00154  *              before it is processed
00155  *
00156  * Input parameters: trace_req - array of trace reqeust structures
00157  *                   n_reqs - size of array
00158  *                   output_dir - output directory
00159  *                   e_date, e_time - event time in the form
00160  *                                    'ccyymmdd' and 'hhmmss.ff'
00161  *                   debug - flag for debugging output
00162  * Output parameters: none
00163  * Returns: EW_SUCCESS or EW_FAILURE
00164  *
00165  * Comments:
00166  *
00167  ***********************************************************************/
00168 int GSEPA_next_ev (TRACE_REQ *trace_req, int n_reqs, char *output_dir,
00169                    char *e_date, char *e_time, int debug)
00170 {
00171 
00172   int event_year, event_month, event_day, event_hour, event_min;
00173   double event_sec;
00174   char string [100];
00175   TRACE_HEADER *trace_hdr;
00176 
00177   static int tmp_file_count = 0;
00178 
00179 
00180   if (debug)
00181   {
00182     logit ("e", "Entering GSEPA_next_ev, date/time: %s %s\n", e_date, e_time);
00183   }
00184 
00185   /* parse and store the date/time - we assume that it doesn't need to
00186    * be checked for validity - I don't know if that is correct */
00187   strcpy (string, e_date);
00188   event_day = atoi (&string[6]);
00189   string[6] = '\0';
00190   event_month = atoi (&string[4]);
00191   string[4] = '\0';
00192   event_year = atoi (string);
00193   strcpy (string, e_time);
00194   event_sec = atof (&string[4]);
00195   string[4] = '\0';
00196   event_min = atoi (&string[2]);
00197   string[2] = '\0';
00198   event_hour = atoi (string);
00199   
00200   /* use the temporary file as the output file - we will rename it to the proper GSE file name
00201    * when it is complete and closed */
00202   sprintf (tmp_filename, "%s%c%d_%d_gse.tmp",
00203            output_dir, DIR_DELIM, getpid (), tmp_file_count ++);
00204   sprintf (gse_filename, "%s%c%04d_%02d_%02d_%02d_%02d_%02.0f.gse",
00205            output_dir, DIR_DELIM, event_year, event_month, event_day,
00206            event_hour, event_min, event_sec);
00207 
00208   /* open the GSE file */
00209   trace_hdr = (TRACE_HEADER *) trace_req->pBuf;
00210   if (! open_gse_file (tmp_filename, "EW", trace_req->net))
00211   {
00212     logit ("e", "GSEPA_init: unable to open GSE output file\n");
00213     return EW_FAILURE;
00214   }
00215 
00216   /* store tracking information */
00217   n_channels = n_reqs;
00218   channels_written = 0;
00219 
00220   return EW_SUCCESS;
00221 
00222 }
00223 
00224 /*****************************************************************************
00225  * GSEPA_next
00226  *
00227  * Description: called once for each trace to be put away
00228  *
00229  * Input parameters: trace_req - the data to be stored
00230  *                   gap_thresh - size of any gap in seconds
00231  *                   debug - flag for debugging output
00232  * Output parameters: none
00233  * Returns: EW_SUCCESS or EW_FAILURE
00234  *
00235  * Comments: see pa_find_data()
00236  *
00237  *****************************************************************************/
00238 int GSEPA_next (TRACE_REQ *trace_req, double gap_thresh, int debug)
00239 
00240 {
00241 
00242   int status, loop_count;
00243   short short_val;
00244   long value, count;
00245   float float_val;
00246   double sample_time, double_val, data_end_time;
00247   char *data_ptr;
00248   struct Found_data data;
00249   time_t ltime;
00250   struct tm unix_time;
00251 
00252 
00253   if (debug) logit ("e", "Entering GSEPA_next\n");
00254 
00255   /* loop over the requested times for the data - the test for n_samples==0
00256    * is an emergency condition that could happen with very bad floating point
00257    * rounding errors (very unlikely though) */
00258   data.n_samples = 1;
00259   for (sample_time = trace_req->reqStarttime, loop_count = 0;
00260        (sample_time < trace_req->reqEndtime) && (data.n_samples > 0);
00261            sample_time += ((double) data.n_samples / data.sample_rate), loop_count ++)
00262   {
00263     /* get the data for this time */
00264     status = pa_find_data (trace_req, sample_time, &data);
00265     switch (status)
00266         {
00267     case FD_FOUND_REQUESTED:
00268     case FD_FOUND_GAP:
00269           break;
00270     case FD_NO_MORE_DATA:
00271       /* if no data has been found on previous calls, then exit
00272            * so that no data will be recorded for this channel */
00273           if (sample_time == trace_req->reqStarttime) return EW_SUCCESS;
00274 
00275           /* otherwise calculate the size of the gap to the end of requested data */
00276           data.n_samples = (long) (data.sample_rate * (trace_req->reqEndtime - sample_time));
00277           break;
00278 
00279     case FD_BAD_DATATYPE:
00280       logit("e", "GSEPA_next: unrecognised data type code, skipping this scn: %s.%s.%s\n",
00281             trace_req->sta, trace_req->chan, trace_req->net);
00282       return EW_FAILURE;
00283 
00284     case FD_CHANGED_SRATE:
00285       logit("e", "GSEPA_next: bad sample rate, skipping this scn: %s.%s.%s\n",
00286             trace_req->sta, trace_req->chan, trace_req->net);
00287       return EW_FAILURE;
00288         }
00289 
00290     /* adjust the number of samples to ensure it doesn't go beyond the end time */
00291         data_end_time = sample_time + ((double) data.n_samples / data.sample_rate);
00292         if (data_end_time > trace_req->reqEndtime)
00293           data.n_samples = (long) (data.sample_rate * (trace_req->reqEndtime - sample_time));
00294     if (debug) logit ("e", "Loop %d: %s %ld @ %.1lfHz, time %.3lf\n",
00295                       loop_count, status == FD_FOUND_REQUESTED ? "samples" : "gap",
00296                                           data.n_samples, data.sample_rate, sample_time);
00297 
00298     /* on the first time write the gse channel header */
00299     if (sample_time == trace_req->reqStarttime)
00300         {
00301       ltime = (time_t) sample_time;
00302       gmtime_ew (&ltime, &unix_time);
00303       if (! write_gse_channel_header (unix_time.tm_year + 1900, unix_time.tm_mon +1,
00304                                       unix_time.tm_mday, unix_time.tm_hour, unix_time.tm_min,
00305                                       ((double) unix_time.tm_sec) + (sample_time - (double) ltime),
00306                                       trace_req->sta, trace_req->chan, "-",
00307                                       (long) (data.sample_rate * (trace_req->reqEndtime - trace_req->reqStarttime)),
00308                                                                       data.sample_rate, -1.0, -1.0, "-", -1.0, -1.0))
00309           {
00310         logit ("e", "GSEPA_next: error starting new GSE channel\n");
00311         return EW_FAILURE;
00312           }
00313         }
00314 
00315         /* write the data */
00316         value = GSE_MISSING_DATA_FLAG;
00317         data_ptr = data.data;
00318         for (count=0; count<data.n_samples; count++)
00319         {
00320           if (status == FD_FOUND_REQUESTED)
00321           {
00322                 switch (data.data_type_code)
00323                 {
00324                 case FD_SHORT_INT:
00325                   short_val = *((short *) data_ptr);
00326           value = (long) short_val;
00327                   data_ptr += sizeof (short);
00328                   break;
00329                 case FD_LONG_INT:
00330                   value = *((long *) data_ptr);
00331                   data_ptr += sizeof (long);
00332                   break;
00333                 case FD_FLOAT:
00334                   float_val = *((float *) data_ptr);
00335           value = (long) float_val;
00336                   data_ptr += sizeof (float);
00337                   break;
00338                 case FD_DOUBLE:
00339                   double_val = *((double *) data_ptr);
00340           value = (long) double_val;
00341                   data_ptr += sizeof (double);
00342                   break;
00343                 }
00344           }
00345       write_gse_channel_data (1, &value);
00346         }
00347   }
00348 
00349   /* stop writing on this channel and fill in any gap at the end of the data */
00350   write_gse_channel_trailer ();
00351 
00352   if (debug)
00353   {
00354     logit ("e", "Successful completion of GSEPA_next\n");
00355   }
00356   return EW_SUCCESS;
00357 
00358 }
00359 
00360 /************************************************************************
00361  * GSEPA_end_ev
00362  *
00363  * Description: called when an event has been completely processed
00364  *
00365  * Input parameters: debug - flag for debugging output
00366  * Output parameters: none
00367  * Returns: EW_SUCCESS or EW_FAILURE
00368  *
00369  * Comments:
00370  *
00371  *****************************************************************************/
00372 int GSEPA_end_ev (int debug)
00373 
00374 {
00375 
00376   int ret_val;
00377 
00378 
00379   ret_val = EW_SUCCESS;
00380 
00381   /* check and close the GSE file */
00382   if (! close_gse_file ())
00383   {
00384     logit ("e", "GSEPA_end_ev: error writing to GSE file\n");
00385     ret_val = EW_FAILURE;
00386   }
00387 
00388   /* rename the temporary file to the proper GSE file name - the return value from
00389    * rename_ew() doesn't appear reliable, so check for the existence of the renamed
00390    * file after the rename operation */
00391   if (ret_val == EW_SUCCESS)
00392   {
00393     rename_ew (tmp_filename, gse_filename);
00394     if (access (gse_filename, 0))
00395     {
00396       logit ("e", "GSEPA_end_ev: unable to rename file (%s) to (%s)\n", tmp_filename, gse_filename);
00397       ret_val = EW_FAILURE;
00398     }
00399   }
00400 
00401   /* if there was an error, delete the file */
00402   if (ret_val != EW_SUCCESS)
00403   {
00404     logit ("e", "GSEPA_end_ev: output file is being deleted (%s)\n", tmp_filename);
00405     remove (tmp_filename);
00406   }
00407 
00408   return ret_val;
00409 
00410 }
00411 
00412 /************************************************************************
00413  * GSEPA_close
00414  *
00415  * Description: called at program shutdown
00416  *
00417  * Input parameters: debug - flag for debugging output
00418  * Output parameters: none
00419  * Returns: EW_SUCCESS or EW_FAILURE
00420  *
00421  * Comments:
00422  *
00423  *****************************************************************************/
00424 int GSEPA_close (int debug)
00425 {
00426 
00427   if (debug)
00428   {
00429     logit ("e", "Entering GSEPA_close: \n");
00430   }
00431 
00432   return EW_SUCCESS;
00433 
00434 }
00435 
00436 
00437 /************************************************************************
00438  ************************************************************************
00439  * All code below this point is private to this file
00440  ************************************************************************
00441  ************************************************************************/
00442 
00443 /************************************************************************
00444  * open_gse_file
00445  *
00446  * Description: open a GSE file and write the main header for the file
00447  *
00448  * Input parameters: filename - the file to write
00449  *                   msg_id - the message id
00450  *                   sta_code - the station code
00451  * Output parameters: none
00452  * Returns: TRUE if file written OK, FALSE otherwise
00453  *
00454  * Comments:
00455  *
00456  ************************************************************************/
00457 static int open_gse_file (char *filename, char *msg_id, char *sta_code)
00458 
00459 {
00460 
00461   /* attempt to open the file */
00462   gse_fp = fopen (filename, file_open_mode);
00463   if (! gse_fp) return FALSE;
00464 
00465   /* write the GSE header */
00466   fprintf (gse_fp, "BEGIN GSE2.0%s", line_terminator);
00467   fprintf (gse_fp, "MSG_TYPE DATA%s", line_terminator);
00468   fprintf (gse_fp, "MSG_ID %s %s%s", msg_id, sta_code, line_terminator);
00469   fprintf (gse_fp, "DATA_TYPE WAVEFORM GSE2.0%s", line_terminator);
00470 
00471   /* check the file */
00472   if (ferror (gse_fp)) return FALSE;
00473   return TRUE;
00474 
00475 }
00476 
00477 /************************************************************************
00478  * write_gse_channel_header
00479  *
00480  * Description: write a GSE channel header
00481  *
00482  * Input parameters: start_year, month, day - the date of the data
00483  *                   start_hour, min, sec - the time of the data
00484  *                   chan_name, type - the channel name and type
00485  *                                     (e.g. EKR1, SZ)
00486  *                   aux_id - auxiliary identification code
00487  *                   n_samps - number of samples in the following data block
00488  *                   frequency - the recording frequency (hz)
00489  *                   calib_value, calib_period - calibration details
00490  *                   instrum_name - GSE code for the sensor type
00491  *                   horiz_angle, vert_angle - sensor orientation
00492  * Output parameters: none
00493  * Returns: TRUE if file written OK, FALSE otherwise
00494  *
00495  * Comments:
00496  *
00497  ************************************************************************/
00498 static int write_gse_channel_header (int start_year, int start_month, int start_day,
00499                                      int start_hour, int start_min, double start_sec,
00500                                      char *chan_name, char *chan_type, char *aux_id,
00501                                      long n_samps,
00502                                      double frequency, double calib_value,
00503                                      double calib_period, char *instrum_name,
00504                                      double horiz_angle, double vert_angle)
00505 
00506 {
00507     
00508   /* write the header for this channel */
00509   fprintf (gse_fp, "WID2 %04d/%02d/%02d %02d:%02d:%06.3lf %-5.5s %-3.3s "
00510                "%-4.4s INT %8ld %11.6lf %10.2le %7.3lf %-6.6s %5.1lf %4.1lf%s",
00511            start_year, start_month, start_day, start_hour, start_min, start_sec,
00512            chan_name, chan_type, aux_id, n_samps, frequency, calib_value,
00513            calib_period, instrum_name, horiz_angle, vert_angle, line_terminator);
00514   fprintf (gse_fp, "DAT2%s", line_terminator);
00515 
00516   /* flag write_gse_channel_data to expect a new channel */
00517   new_data_channel = TRUE;
00518     
00519   /* check the file */
00520   if (ferror (gse_fp)) return FALSE;
00521   return TRUE;
00522 
00523 }
00524 
00525 /************************************************************************
00526  * write_gse_channel_data
00527  *
00528  * Description: write channel data in GSE format
00529  *
00530  * Input parameters: n_samps - the number of samples to write
00531  *                   data - the data to write
00532  * Output parameters: none
00533  * Returns: TRUE if file written OK, FALSE otherwise
00534  *
00535  * Comments: This routine may be called more than once if all the data
00536  *           is not available at one go - the total number of samples
00537  *           written must equal to number of samples declared in the header
00538  *
00539  ************************************************************************/
00540 static int write_gse_channel_data (int n_samps, long *data)
00541 
00542 {
00543 
00544   int count, length;
00545   long value;
00546   char string [100];
00547 
00548   static long modulo = 100000000;
00549 
00550 
00551   /* if this is the start of a new channel, reset the sample
00552    * counter and the checksum */
00553   if (new_data_channel)
00554   {
00555     data_line_length = 0;
00556     new_data_channel = FALSE;
00557     channel_checksum = 0l;
00558   }
00559 
00560   /* for each data sample ... */
00561   for (count=0; count<n_samps; count++)
00562   {
00563     /* format the sample, checking for missing data */
00564     value = *(data + count);
00565     sprintf (string, "%ld", value);
00566 
00567     /* write the sample using an 80 char. line length */
00568     length = strlen (string);
00569     if ((length + data_line_length +1) > 80)
00570     {
00571       fprintf (gse_fp, "%s", line_terminator);
00572       data_line_length = 0;
00573     }
00574     if (data_line_length > 0)
00575     {
00576       fprintf (gse_fp, " ");
00577       data_line_length ++;
00578     }
00579     fprintf (gse_fp, string);
00580     data_line_length += length;
00581           
00582     /* accumulate the checksum */
00583     if (labs (value) >= modulo) value -= (value / modulo) * modulo;
00584     channel_checksum += value;
00585     if (labs (channel_checksum) >= modulo)
00586       channel_checksum -= (channel_checksum / modulo) * modulo;
00587   }
00588 
00589   /* check the file */
00590   if (ferror (gse_fp)) return FALSE;
00591   return TRUE;
00592 
00593 }
00594 
00595 /************************************************************************
00596  * write_gse_channel_trailer
00597  *
00598  * Description: write trailer info. for a channel
00599  *
00600  * Input parameters: none
00601  * Output parameters: none
00602  * Returns: TRUE if file written OK, FALSE otherwise
00603  *
00604  * Comments:
00605  *
00606  ************************************************************************/
00607 static int write_gse_channel_trailer (void)
00608 
00609 {
00610 
00611   /* write the checksum for this channel */
00612   if (data_line_length > 0)
00613   {
00614     fprintf (gse_fp, "%s", line_terminator);
00615     data_line_length = 0;
00616   }
00617   fprintf (gse_fp, "CHK2 %d%s", abs (channel_checksum), line_terminator);
00618 
00619   /* check the file */
00620   if (ferror (gse_fp)) return FALSE;
00621   return TRUE;
00622 
00623 }
00624 
00625 /************************************************************************
00626  * close_gse_file
00627  *
00628  * Description: write trailer info. for a file and close it
00629  *
00630  * Input parameters: none
00631  * Output parameters: none
00632  * Returns: TRUE if file written OK, FALSE otherwise
00633  *
00634  * Comments:
00635  *
00636  ************************************************************************/
00637 static int close_gse_file (void)
00638 
00639 {
00640 
00641   int ret_val;
00642 
00643 
00644   /* write the GSE trailer */
00645   fprintf (gse_fp, "STOP%s", line_terminator);
00646   
00647   /* check the file */
00648   if (ferror (gse_fp)) ret_val = FALSE;
00649   else ret_val = TRUE;
00650 
00651   /* close it and return */
00652   fclose (gse_fp);
00653   return ret_val;
00654 
00655 }
00656 
00657 
00658 

Generated on Tue May 6 09:16:03 2003 for Earthworm Libs by doxygen1.3-rc3