
/*
 *
 *    $Id: sniffwave.c,v 1.38 2010/03/25 16:57:00 paulf Exp $
 *
 *    Revision history:
 *     $Log: sniffwave.c,v $
 *     Revision 1.38  2010/03/25 16:57:00  paulf
 *     okay, made it only show SCNL matches if L is specified
 *
 *     Revision 1.37  2010/03/25 16:48:50  paulf
 *     now will search for SCN or SNCL again, this is version 2.4
 *
 *     Revision 1.36  2010/03/25 15:29:47  paulf
 *     added logit_init() back in for WaveMsg2MakeLocal() but set disk logging to 0
 *
 *     Revision 1.35  2010/03/25 14:27:29  paulf
 *     removed logit() calls, untested as yet
 *
 *     Revision 1.34  2010/03/19 19:50:48  scott
 *     Made reporting of WaveMsg2MakeLocal error more robust
 *
 *     Revision 1.33  2010/03/19 17:46:36  scott
 *     Added check of return from WaveMsg2MakeLocal
 *
 *     Revision 1.32  2010/03/15 19:45:16  paulf
 *     okay, made the new feature allow sniffwave ringname and optionally y or s for data flag
 *
 *     Revision 1.31  2010/03/15 19:14:36  paulf
 *     sniffwave fixed to echo usage message if operator mistakenly does sniffwave WAVE_RING y mode, it is intended only for just the ring name
 *
 *     Revision 1.30  2009/09/24 21:21:23  stefan
 *     flush on each output line
 *
 *     Revision 1.29  2009/06/18 18:43:38  stefan
 *     formatting change only
 *
 *     Revision 1.28  2009/06/16 13:18:33  paulf
 *     fixed a number of loose ends from the new features, namely when the filter turns up no packets over the timeout period
 *
 *     Revision 1.27  2009/06/15 19:21:19  paulf
 *     upped the version number
 *
 *     Revision 1.26  2009/06/15 18:56:18  paulf
 *     many changes from the EW Class #7, latency, gap checking, and statistics at end of run with time out
 *
 *     Revision 1.25  2009/06/12 17:40:28  paulf
 *     fixed for windows
 *
 *     Revision 1.24  2009/06/12 15:29:49  paulf
 *     minor change to fix verbosity setting reading, during EW Class #7
 *
 *     Revision 1.23  2009/06/10 02:36:44  quintiliani
 *     Minor bug fix: removed unuseful lines about latency computation
 *
 *     Revision 1.22  2009/06/09 15:22:19  quintiliani
 *     Added the computation of latency (seconds) of the current tracebuf message
 *
 *     Revision 1.21  2008/01/19 19:55:14  paulf
 *     added a new command line allowed for sniffwave, just ring name
 *
 *     Revision 1.20  2007/12/16 06:02:02  paulf
 *     fixed sniffwave to handle systems where long could be 8 bytes
 *
 *     Revision 1.19  2007/03/23 15:53:15  stefan
 *     Earthworm Class March 2007, added statistics flag to sniffwave, y, n, or s options are now handled, tport fix made
 *
 *     Revision 1.18  2007/02/07 00:35:16  stefan
 *     help text revision
 *
 *     Revision 1.17  2007/02/02 19:06:59  stefan
 *     removed module verbosity for non-local modules
 *
 *     Revision 1.16  2006/12/28 23:07:54  lombard
 *     Added version number, printed with usage.
 *     Changed to specifically look for TYPE_TRACEBUF2 and TYPE_TRACE2_COMP_UA
 *     packets if SCNL given on command line, or to look for TYPE_TRACEBUF and
 *     TYPE_TRACE_COMP_UA packets if SCN is given on command line. Thus you cannot
 *     sniff for both SCNL and SCN packets at once with this command.
 *
 *     Revision 1.15  2006/12/01 02:12:58  stefan
 *     Added "verbose" option to print module, installation and type names along
 *     with the numbers. Without this extra parameter it works as before.
 *
 *     Revision 1.14  2006/07/26 20:23:00  stefan
 *     additional significant digits for sample rates < 1hz
 *
 *     Revision 1.13  2006/03/27 16:57:27  davek
 *     Added version and quality info to the sniffwave output for each tracebuf.
 *
 *     Revision 1.12  2005/03/30 23:13:26  dietz
 *     Now printing seconds to 4 decimal places.
 *
 *     Revision 1.11  2004/04/13 22:57:32  dietz
 *     modified to work with TYPE_TRACEBUF2 and TYPE_TRACE2_COMP_UA msgs
 *
 *     Revision 1.10  2003/10/31 17:20:43  dietz
 *     Will now sniff both TYPE_TRACEBUF and TYPE_TRACE_COMP_UA msg headers.
 *     Will accept strings "wild", "WILD", and "*" as wildcards in SCN.
 *
 *     Revision 1.9  2002/10/24 22:11:32  dietz
 *     Added message length to printed information
 *
 *     Revision 1.8  2002/07/12 17:49:57  dietz
 *     added #include <time_ew.h>
 *
 *     Revision 1.7  2002/02/02 00:28:58  dietz *     Changed to print instid and module on the tracebuf header summary line
 *
 *     Revision 1.6  2001/03/30 01:17:36  dietz
 *     *** empty log message ***
 *
 *     Revision 1.5  2001/03/30 01:10:18  dietz
 *     added newline after every 10 data samples, and an fflush(stdout)
 *     after each tracebuf message.
 *
 *     Revision 1.4  2001/03/29 23:51:03  dietz
 *     Changed ring flush statemnet to while( tport_get... != GET_NONE );
 *
 *     Revision 1.3  2000/08/08 18:18:28  lucky
 *     Lint cleanup
 *
 *     Revision 1.2  2000/05/31 18:29:10  dietz
 *     Fixed to print 4-byte data properly.
 *
 *     Revision 1.1  2000/02/14 19:36:09  lucky
 *     Initial revision
 *
 *
 */


  /*****************************************************************
   *                            sniffwave.c                        *
   *                                                               *
   * Program to read waveform messages from shared memory and      *
   * write to a disk file.                                         *
   *                                                               *
   * Modified by Lucky Vidmar Tue May 11 11:27:35 MDT 1999         *
   *   allows for more arguments which specify                     *
   *     Ring to read from                                         *
   *     SCN of the messages to print                              *
   *     Whether or not trace data should be printed               *
   *                                                               *
   *                                                               *
   * Usage: sniffwave  <Ring> <Sta> <Comp> <Net> <Loc> <Data y/n>  *
   *    or: sniffwave  <Ring> <Sta> <Comp> <Net> <Data y/n>        *
   *    or: sniffwave  <Ring>                                      *
   *                                                               *
   *****************************************************************/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <transport.h>
#include <swap.h>
#include <time_ew.h>
#include <trace_buf.h>
#include <earthworm.h>

#define NLOGO 4
#define VERSION "2.4"

int IsWild( char *str )
{
  if( (strcmp(str,"wild")==0)  ) return 1;
  if( (strcmp(str,"WILD")==0)  ) return 1;
  if( (strcmp(str,"*")   ==0)  ) return 1;
  return 0;
}

/* Variable and function declaration for checking gap for each SCNL */
#define MAX_LEN_STR_SCNL 30
typedef struct {
    char scnl[MAX_LEN_STR_SCNL];
    double last_sample_time;
} SCNL_LAST_SAMPLE_TIME;
#define MAX_NUM_SCNL 1000
int  check_for_gap_and_output_message(TRACE2_HEADER  *trh);


int main( int argc, char **argv )
{
   SHM_INFO        region;
   long            RingKey;         /* Key to the transport ring to read from */
   MSG_LOGO        getlogo[NLOGO], logo;
   long            gotsize;
   char            msg[MAX_TRACEBUF_SIZ];
   char           *getSta, *getComp, *getNet, *getLoc, *inRing;
   char            wildSta, wildComp, wildNet, wildLoc;
   unsigned char   Type_TraceBuf,Type_TraceBuf2;
   unsigned char   Type_TraceComp, Type_TraceComp2;
   unsigned char   InstWildcard, ModWildcard;
   short          *short_data;
   int            *long_data;
   TRACE2_HEADER  *trh;
   char            orig_datatype[3];
   char            stime[256];
   char            etime[256];
   int             dataflag;
   int             i;
   int             rc;
   int             verbose = 0; /* if verbose =1 print name and number for logo ids */
   int             useLoc = 0;
   int             nLogo = NLOGO;
   static unsigned char InstId;        /* local installation id              */
   char            ModName[MAX_MOD_STR];
   unsigned char   sequence_number = 0;
   int             statistics_flag;
   int             dataargument_position=5;
   double d_now;
   time_t monitor_start_time;
   double start_time, end_time;
   int seconds_to_live;
   unsigned long packet_total=0;
   unsigned long packet_total_size=0;
   
   seconds_to_live = 0;

  /* Initialize pointers
  **********************/
  trh  = (TRACE2_HEADER *) msg;
  long_data  =  (int *)( msg + sizeof(TRACE2_HEADER) );
  short_data = (short *)( msg + sizeof(TRACE2_HEADER) );

  /* Check command line argument
  *****************************/
  if ( !(argc==2 ||argc==3) && ( argc < 6 || argc > 8 ) )
  {
     fprintf(stderr, "%s version %s\n", argv[0], VERSION);
     fprintf(stderr,"Usage: %s <ring name> <station> <component> <network> [<loc>] <y/n/s/time> [v]\n", argv[0]);
     fprintf(stderr, "\n       Appending the optional \"v\" or \"verbose\" argument causes module, \n");
     fprintf(stderr, "       installation and type names to be printed in addition to usual ID numbers\n");
     fprintf(stderr, "\n       The <y/n/s> flag is a data flag or 'time in seconds'. If 'y' is specified, the full data\n");
     fprintf(stderr, "       contained in the tracebuf or tracebuf2 packet is printed out. \n");
     fprintf(stderr, "       If the flag is set to s, provide max/min/avg statistics of the trace data. \n");
     fprintf(stderr, "       If the flag is set to some number of seconds, the program runs only for that number of seconds.\n");
     fprintf(stderr, "\n       If you specify the location code or wild for the location code\n");
     fprintf(stderr, "       you'll get Tracebuf2 packets. Otherwise you'll get Tracebufs.\n");
     fprintf(stderr,"\nExample: %s WAVE_RING PHOB wild NC wild n\n", argv[0] );
     fprintf(stderr,"Example: %s WAVE_RING wild wild wild y verbose\n", argv[0] );
     fprintf(stderr,"NEW case, only use wavering arg to get all wild cards: %s WAVE_RING and further optionally put in the data flag y or s\n", argv[0] );
     exit( 1 );
  }

  /* check the verbosity level before ANY other tests on the command line */
  if (strcmp(argv[argc-1], "verbose") == 0 ||
       argv[argc-1][0]=='v') {
      argc--;
      verbose = 1;
  }

  if (argc == 2 || argc == 3) {
        /* new case, where all SCNL's are wild, usage is just sniffwave ringname */
        useLoc=wildSta=wildComp=wildNet=wildLoc=1;
        inRing  = argv[1];
  } else {

  	inRing  = argv[1];
  	getSta  = argv[2];
  	wildSta  = IsWild( getSta  );
  	getComp = argv[3];
  	wildComp = IsWild( getComp );
  	getNet  = argv[4];
  	wildNet  = IsWild( getNet  );
  }


  if (argc == 7 ) {
      getLoc  = argv[5];
      useLoc = 1;
      wildLoc  = IsWild( getLoc  );
      fprintf(stdout, "Sniffing %s for %s.%s.%s.%s\n",
          inRing, getSta, getComp, getNet, getLoc);

  } else if (argc == 3) {
      fprintf(stdout, "Sniffing %s for wild.wild.wild.wild\n",
          inRing );
      /* reset this stuff for grabbing data flag arg */
      dataargument_position = 2;
      useLoc = 0;
  } else if (argc != 2) {
      getLoc = NULL;
      nLogo = 4;
      useLoc = 0;
      fprintf(stdout, "Sniffing %s for %s.%s.%s and any SNCL with L as wild\n",
          inRing, getSta, getComp, getNet);
  }

  if (argc != 2) {
     dataflag=0;
     statistics_flag=0;
     if(strcmp (argv[dataargument_position + useLoc], "y") == 0)
        dataflag = 1;
     else if(strcmp (argv[dataargument_position + useLoc], "n") == 0)
        dataflag = 0;
     else if(strcmp (argv[dataargument_position + useLoc], "s") == 0)
        statistics_flag = 1;
     else if( (seconds_to_live = atoi(argv[dataargument_position + useLoc])) < 0 )
     {
       fprintf(stderr, "sniffwave: specify data flag - y or n or s or positive seconds to live\n");
       exit (1);
     }

  } else {
     dataflag = 0;
  }
  if (dataargument_position == 2) { 
	useLoc=1; /* turn this back on */
  }
  if (argc == 6) {
        /* turn on location code as wild anyway to show both SCN and SCNL */
        useLoc=1;
        wildLoc = 1;
  }
  /* logit_init but do NOT WRITE to disk, this is needed for WaveMsg2MakeLocal() which logit()s */
  logit_init("sniffwave", 200, 200, 0);

  /* Attach to ring
  *****************/
  if ((RingKey = GetKey( inRing )) == -1 )
  {
    fprintf( stderr, "Invalid RingName; exiting!\n" );
    exit( -1 );
  }
  tport_attach( &region, RingKey );

/* Look up local installation id
   *****************************/
   if ( GetLocalInst( &InstId ) != 0 )
   {
      fprintf(stderr, "sniffwave: error getting local installation id; exiting!\n" );
      return -1;
   }


  /* Specify logos to get
  ***********************/
  if ( GetType( "TYPE_TRACEBUF", &Type_TraceBuf ) != 0 ) {
     fprintf(stderr, "%s: Invalid message type <TYPE_TRACEBUF>!\n", argv[0] );
     exit( -1 );
  }
  if ( GetType( "TYPE_TRACE_COMP_UA", &Type_TraceComp ) != 0 ) {
     fprintf(stderr, "%s: Invalid message type <TYPE_TRACE_COMP_UA>!\n", argv[0] );
     exit( -1 );
  }
  if ( GetType( "TYPE_TRACEBUF2", &Type_TraceBuf2 ) != 0 ) {
     fprintf(stderr, "%s: Invalid message type <TYPE_TRACEBUF2>!\n", argv[0] );
     exit( -1 );
  }
  if ( GetType( "TYPE_TRACE2_COMP_UA", &Type_TraceComp2 ) != 0 ) {
     fprintf(stderr,"%s: Invalid message type <TYPE_TRACE2_COMP_UA>!\n", argv[0] );
     exit( -1 );
  }
  if ( GetModId( "MOD_WILDCARD", &ModWildcard ) != 0 ) {
     fprintf(stderr, "%s: Invalid moduleid <MOD_WILDCARD>!\n", argv[0] );
     exit( -1 );
  }
  if ( GetInst( "INST_WILDCARD", &InstWildcard ) != 0 ) {
     fprintf(stderr, "%s: Invalid instid <INST_WILDCARD>!\n", argv[0] );
     exit( -1 );
  }

  for( i=0; i<nLogo; i++ ) {
      getlogo[i].instid = InstWildcard;
      getlogo[i].mod    = ModWildcard;
  }
  getlogo[0].type = Type_TraceBuf;
  getlogo[1].type = Type_TraceComp;
  if (useLoc) {
      getlogo[2].type = Type_TraceBuf2;
      getlogo[3].type = Type_TraceComp2;
  }

  /* Flush the ring
  *****************/
  while ( tport_getmsg( &region, getlogo, nLogo, &logo, &gotsize,
            (char *)&msg, MAX_TRACEBUF_SIZ ) != GET_NONE )
  {
         packet_total++;
         packet_total_size+=gotsize;
  }
  fprintf( stderr, "sniffwave: inRing flushed %ld packets of %ld bytes total.\n",
		packet_total, packet_total_size);

  if (seconds_to_live > 0) {
        monitor_start_time = time(0);
        packet_total = packet_total_size = 0;
        start_time = 0.0;
  }
  while ( (!(seconds_to_live > 0) || 
         (time(0)-monitor_start_time < seconds_to_live)) &&
         tport_getflag( &region ) != TERMINATE ) 

  {

    rc = tport_copyfrom( &region, getlogo, nLogo,
               &logo, &gotsize, msg, MAX_TRACEBUF_SIZ, &sequence_number );

    if ( rc == GET_NONE )
    {
      sleep_ew( 200 );
      continue;
    }

    if ( rc == GET_TOOBIG )
    {
      fprintf( stderr, "sniffwave: retrieved message too big (%d) for msg\n",
        gotsize );
      continue;
    }

    if ( rc == GET_NOTRACK )
      fprintf( stderr, "sniffwave: Tracking error.\n");

    if ( rc == GET_MISS_LAPPED )
      fprintf( stderr, "sniffwave: Got lapped on the ring.\n");

    if ( rc == GET_MISS_SEQGAP )
      fprintf( stderr, "sniffwave: Gap in sequence numbers\n");

    if ( rc == GET_MISS )
      fprintf( stderr, "sniffwave: Missed messages\n");

    /* Check SCNL of the retrieved message */

    if ( (wildSta  || (strcmp(getSta,trh->sta)  ==0)) &&
         (wildComp || (strcmp(getComp,trh->chan)==0)) &&
         (wildNet  || (strcmp(getNet,trh->net)  ==0)) &&
         (((logo.type == Type_TraceBuf2 ||
            logo.type == Type_TraceComp2) &&
         (wildLoc  || (strcmp(getLoc,trh->loc) == 0))) ||
         ( getLoc != NULL && (logo.type == Type_TraceBuf ||
             logo.type == Type_TraceComp))))
    {
      strcpy(orig_datatype, trh->datatype);
      if(WaveMsg2MakeLocal( trh ) < 0)
      {
        char scnl[20], dt[3];        
        strcpy( scnl, "_____.___.__.__" );
        strncpy( scnl, trh->sta, 5 );
        strncpy( scnl+6, trh->chan, 3 );
        strncpy( scnl+10, trh->net, 2 );
        strncpy( scnl+13, trh->loc, 2 );
        for ( i=0; i<15; i++ ) {
          if ( !isalnum(scnl[i]) && !ispunct(scnl[i]))
            scnl[i] = ' ';
        }
        strncpy( dt, trh->datatype, 2 );
        for ( i=0; i<2; i++ ) {
          if ( !isalnum(dt[i]) && !ispunct(dt[i]))
            dt[i] = ' ';
        }
        dt[i] = 0;
        fprintf(stderr, "WARNING: WaveMsg2MakeLocal rejected tracebuf.  Discard (%s).\n", 
        	scnl );
        fprintf(stderr, "\tdatatype=[%s]\n", dt);
        continue;
      }


      if (seconds_to_live > 0) {
           if (start_time == 0.0)
                  start_time = trh->starttime;
           end_time = trh->endtime;
           packet_total++;
           packet_total_size += gotsize;
      }

      datestr23 (trh->starttime, stime, 256);
      datestr23 (trh->endtime,   etime, 256);

      if( logo.type == Type_TraceBuf2  ||
          logo.type == Type_TraceComp2    ) {
          fprintf( stdout, "%s.%s.%s.%s (0x%x 0x%x) ",
                   trh->sta, trh->chan, trh->net, trh->loc, trh->version[0], trh->version[1] );
      } else {
          fprintf( stdout, "%s.%s.%s ",
                   trh->sta, trh->chan, trh->net );
      }
      if (trh->samprate < 1.0) { /* more decimal places for slower sample rates */
          fprintf( stdout, "%d %s %d %6.4f %s (%.4f) %s (%.4f) %c%c \n",
               trh->pinno, orig_datatype, trh->nsamp, trh->samprate,
               stime, trh->starttime,
               etime, trh->endtime, trh->quality[0], trh->quality[1] );
      } else {
          fprintf( stdout, "%d %s %d %.1f %s (%.4f) %s (%.4f) %c%c ",
                         trh->pinno, orig_datatype, trh->nsamp, trh->samprate,
                         stime, trh->starttime,
                         etime, trh->endtime, trh->quality[0], trh->quality[1] );
      }
      if (verbose) {

          if (InstId == logo.instid) {
              sprintf( ModName, "%s", GetModIdName(logo.mod));
          } else {
              sprintf( ModName, "UnknownRemoteMod");
          }

          fprintf( stdout, "i%d=%s m%d=%s t%d=%s len%d",
                 (int)logo.instid, GetInstName(logo.instid), (int)logo.mod,
                 ModName, (int)logo.type, GetTypeName(logo.type), gotsize );
      } else {
          fprintf( stdout, "i%d m%d t%d len%d",
                 (int)logo.instid, (int)logo.mod, (int)logo.type, gotsize );
      }

      hrtime_ew( &d_now );
      fprintf( stdout, " [%.2f]", d_now - trh->endtime );

      fprintf( stdout, "\n");
	  fflush (stdout);

      /* TODO add a flag to output gap message or not */
      /* Check for gap and in case output message */
      check_for_gap_and_output_message(trh);

      if (dataflag == 1)
      {
        if( logo.type == Type_TraceBuf2 ||
            logo.type == Type_TraceBuf     )
        {
          if ( (strcmp (trh->datatype, "s2")==0) ||
               (strcmp (trh->datatype, "i2")==0)    )
          {
            for ( i = 0; i < trh->nsamp; i++ ) {
              fprintf ( stdout, "%6hd ", *(short_data+i) );
              if(i%10==9) fprintf ( stdout, "\n" );
            }
          }
          else if ( (strcmp (trh->datatype, "s4")==0) ||
                    (strcmp (trh->datatype, "i4")==0)    )
          {
            for ( i = 0; i < trh->nsamp; i++ ) {
              fprintf ( stdout, "%6d ", *(long_data+i) );
              if(i%10==9) fprintf ( stdout, "\n" );
            }
          }
          else
          {
             fprintf (stdout, "Unknown datatype %s\n", trh->datatype);
          }
        } else {
             fprintf (stdout, "Data values compressed\n");
        }
        fprintf (stdout, "\n");
        fflush (stdout);
      }
      if (statistics_flag == 1)
      {
        if( logo.type == Type_TraceBuf2 ||
            logo.type == Type_TraceBuf     )
        {
          int max=0;
          int min=0;
          double avg=0.0;
          short short_value;
          int long_value;

          if ( (strcmp (trh->datatype, "s2")==0) ||
               (strcmp (trh->datatype, "i2")==0)    )
          {
            for ( i = 0; i < trh->nsamp; i++ ) {
              short_value = *(short_data+i);
              if (short_value > max || max == 0) {
		max=short_value;
              }
              if (short_value < min || min == 0) {
		min=short_value;
              }
              avg += short_value;
            }
            avg = avg / trh->nsamp;
            fprintf(stdout, "Raw Data statistics max=%ld min=%ld avg=%f\n",
                       max, min, avg); 
            fprintf(stdout, "DC corrected statistics max=%f min=%f spread=%ld\n\n",
                       (double)(max - avg), (double)(min - avg), 
                       labs(max - min)); 
          }
          else if ( (strcmp (trh->datatype, "s4")==0) ||
                    (strcmp (trh->datatype, "i4")==0)    )
          {
            for ( i = 0; i < trh->nsamp; i++ ) {
              long_value = *(long_data+i);
              if (long_value > max || max == 0) {
		max=long_value;
              }
              if (long_value < min || min == 0) {
		min=long_value;
              }
              avg += long_value;
            }
            avg = avg / trh->nsamp;
            fprintf(stdout, "Raw Data statistics max=%ld min=%ld avg=%f\n",
                       max, min, avg); 
            fprintf(stdout, "DC corrected statistics max=%f min=%f spread=%ld\n\n",
                       (double)(max - avg), (double)(min - avg), 
                       labs(max - min)); 
          }
          else
          {
             fprintf (stdout, "Unknown datatype %s\n", trh->datatype);
          }
        } else {
             fprintf (stdout, "Data values compressed\n");
        }
        fflush (stdout);
       } /* end of statistics_flag if */
      } /* end of process this tracebuf if */
     } /* end of while loop */
     if (seconds_to_live > 0 && start_time > 0.0) 
     {
      		datestr23 (start_time, stime, 256);
      		datestr23 (end_time,   etime, 256);
 		fprintf(stdout, "Sniffed %s for %d seconds:\n", argv[1], seconds_to_live);
 		fprintf(stdout, "\tStart Time of first packet:  %s\n", stime);
 		fprintf(stdout, "\t   End Time of last packet:  %s\n", etime);
 		fprintf(stdout, "\t           Seconds of data:  %f\n", end_time - start_time);
 		fprintf(stdout, "\t             Bytes of data:  %d\n", packet_total_size);
 		fprintf(stdout, "\t Number of Packets of data:  %d\n", packet_total);
     } 
     if (seconds_to_live > 0 && start_time == 0.0)  {
 		fprintf(stdout, "Sniffed %s for %d seconds and found no packets matching desired SCN[L] filter.\n", argv[1], seconds_to_live);
     }
  exit (0);
}


// #define SAMPLE_TIME_DIFF_TOLLERANCE 0.001
int  check_for_gap_and_output_message(TRACE2_HEADER  *trh) {
    int ret = 0;
    static SCNL_LAST_SAMPLE_TIME scnl[MAX_NUM_SCNL];
    static int n_scnl = 0;
    char str_SCNL[MAX_LEN_STR_SCNL];
    int i = 0;
    int found = 0;
    char s_stime[256], s_lasttime[256];
    double gap_time;
    double SAMPLE_TIME_DIFF_TOLLERANCE;

    /* initialize a SCNL string from current packet */
    snprintf(str_SCNL, 30, "%s.%s.%s.%s", trh->sta, trh->chan, trh->net, trh->loc);

    /* search for SCNL string in scnl array */
    i = 0;
    while(i < n_scnl &&  !found) {
	if(strcmp(str_SCNL, scnl[i].scnl) == 0) {
	    found = 1;
	} else {
	    i++;
	}
    }

    if(!found) {
	/* just add if space is available */
	if(n_scnl < MAX_NUM_SCNL-1) {
	    strncpy(scnl[n_scnl].scnl, str_SCNL, MAX_LEN_STR_SCNL);
	    scnl[n_scnl].last_sample_time = trh->endtime;
	    n_scnl++;
	}  else {
	    /* TODO error message */
	}
    } else {
	/* compare to last sample time */
	SAMPLE_TIME_DIFF_TOLLERANCE = 2.0 * (1.0 / (double) trh->samprate);
	gap_time =  trh->starttime - scnl[i].last_sample_time;
	if(fabs(gap_time) > SAMPLE_TIME_DIFF_TOLLERANCE) {
	    datestr23 (scnl[i].last_sample_time, s_lasttime, 256);
	    datestr23 (trh->starttime,           s_stime, 256);
	    /* output message for gap */
	    fprintf(stdout, "Gap for %s (%s - %s)\n", scnl[i].scnl, s_lasttime, s_stime);
	}
	scnl[i].last_sample_time = trh->endtime;
    }

    return ret;
}
