

      /*********************************************************************
       *                              makeTrace.c                          *
       *                                                                   *
       *                 for trace data load testing                       *
       *********************************************************************/

/*                                     Story

   This is derived from adsend. It's purpose is to execute a test ordered by
   Ray Buland: To have one machine producing trace_buf's, and broadcasting
   them onto a dedicated wire. To have two machines listening: one running
   WaveServer, the other an export. To then crank up the rate of trace_buf's 
   until something breaks. Thus I was directed to do. Alex 11/12/02
*/


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/timeb.h>
#include <ctype.h>
#include <conio.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <string.h>
#include <process.h>    /* for _getpid() */
#include <earthworm.h>
#include <transport.h>
#include <trace_buf.h>
#include "makeTrace.h"

/* Functions prototypes
   ********************/
void CombGuideChk( int *, int, int * );
int  GetArgs( int, char **, char ** );
int  GetConfig( char * );
int  GetDAQ( short *, unsigned long * );
int  GuideChk( short *, int, int, int, double *, double *, double, double );
void InitCon( void );
void InitDAQ( int );
void irige_init( struct TIME_BUFF * );
int  Irige( struct TIME_BUFF *, long, int, int, short *, int, int );
void LogAndReportError( int, char * );
void LogConfig( void );
void LogSta( int, SCN * );
void PrintGmtime( double, int );
void LogitGmtime( double, int );
int  ReadSta( char *, unsigned char, int, SCN * );
void ReportError( int, char * );
void SetCurPos( int, int );
void StopDAQ( void );
int  NoSend( int );
int  NoTimeSynch( int );
int  inc( SCN* );

/* Global configuration parameters
   *******************************/
extern unsigned char ModuleId;   // Data source id placed in the trace header
extern int    OnboardChans;      // The number of channels on the DAQ board
extern int    NumMuxBoards;      // Number of mux cards
extern double ChanRate;          // Rate in samples per second per channel
extern long    ChanMsgSize;			// Message size in samples per channel
extern int    NumTimeCodeChan;   // How many time-code channels there are
extern int    *TimeCodeChan;     // The chans where we find the IRIGE signals
extern long   OutKey;            // Key to ring where traces will live
extern int    Year;              // The current year
extern int    NumGuide;          // Number of guide channels
extern int    *GuideChan;        // The chans where we find the reference voltage
extern int    SendBadTime;       // Send data even if no IRIGE signal is present
extern int    UpdateSysClock;    // Update PC clock with good IRIGE time
extern int    YearFromPC;        // Take year from PC instead of "Year"

extern int    Nchan;             // Number of channels to send
extern int		Rate;
extern int    IrigeIsLocalTime;  // Set to 1 if IRIGE represents local time; 0 if GMT time.
extern int    ErrNoLockTime;     // If no guide lock for ErrNoLockTime sec, report an error
extern int    Debug=0;        

/* Global variables
   ****************/
SHM_INFO      OutRegion;         // Info structure for output region
pid_t         MyPid;             // process id, sent with heartbeat
static SCN    ChanList[MAX_CHAN];         // Array to fill with SCN values


int main( int argc, char *argv[] )
{
	double	startTime;			// Header start time
	double  tnow, twait, tfirst;
	double  tnextSend;
	double  packetDt;
	double  PtsSent=0;
	double  PktsSent=0;
	double  tShowNext=0;
	unsigned long nPacket=0;			// number of packets sent
   int       i, j,             // Loop indexes
             traceBufSize;     // Size of the trace buffer, in bytes
   long    *halfBuf,          // Pointer to half buffer of A/D data
            *traceDat;         // Where the data points are stored in the trace msg
   char     *traceBuf;         // Where the trace message is assembled
   unsigned  halfBufSize,      // Size of the half buffer in number of samples
             scan = 0;         // Scan number of first scan in a message
   unsigned char InstId;       // Installation id placed in the trace header
   MSG_LOGO  logo;             // Logo of message to put out
   TRACE_HEADER    *traceHead; // Where the trace header is stored
   SCN			seedName;
   int           rc;                     // Function return code
   int         *tracePtr;              // Pointer into traceBuf for demuxing
   int         *halfPtr;               // Pointer into halfBuf for demuxing

/* Get command line arguments
   **************************/
   if ( argc < 2 )
   {
      printf( " missing command file name\n");
      return -1;
   }

/* Initialize name of log-file & open it
   *************************************/
   logit_init( argv[1], 0, 256, 1 );

/* Read configuration parameters
   *****************************/
   if ( GetConfig( argv[1] ) < 0 )
   {
      printf( "makeTrace: Error reading configuration file. Exiting.\n" );
      return -1;
   }

/* Get our Process ID for restart purposes
   ***************************************/
   MyPid = _getpid();
   if( MyPid == -1 )
   {
      logit("e", "makeTrace: Cannot get PID. Exiting.\n" );
      return -1;
   }
   logit(""," MakeTrace version 1.0 \n");

/* Set up the logo of outgoing waveform messages
   *********************************************/
   if ( GetLocalInst( &InstId ) < 0 )
   {
      printf( "MakeTrace: Error getting the local installation id. Exiting.\n" );
      return -1;
   }
   if( Debug ==1) logit( "", "Local InstId:         %8u\n", InstId );

   logo.instid = InstId;
   logo.mod    = ModuleId;
   GetType( "TYPE_TRACEBUF", &logo.type );

/* Allocate some array space
   *************************/
   halfBufSize = (int)(ChanMsgSize * Nchan);
   if( Debug ==1) logit( "t", "Half buffer size: %u samples\n", halfBufSize );

   halfBuf = (int *) calloc( halfBufSize, sizeof(int) );
   if ( halfBuf == NULL )
   {
      logit( "", "Cannot allocate the A/D buffer\n" );
      return -1;
   }
   traceBufSize = sizeof(TRACE_HEADER) + (ChanMsgSize * sizeof(int));
   if ( traceBufSize > MAX_TRACEBUF_SIZ)
   {
	   logit("e","Trace Buffer too large: %d\n", traceBufSize);
	   logit("e","Max legal size: %d\n",MAX_TRACEBUF_SIZ);
	   return -1;
   }
   if( Debug ==1) logit( "e", "Trace buffer size: %d bytes\n", traceBufSize );
   if( Debug ==1) logit( "e", "Trace buffer header size: %d bytes\n", sizeof(TRACE_HEADER) );
   traceBuf = (char *) malloc( traceBufSize );
   if ( traceBuf == NULL )
   {
      logit( "", "Cannot allocate the trace buffer\n" );
      return -1;
   }
   traceHead = (TRACE_HEADER *) &traceBuf[0];
   traceDat  = (int *) &traceBuf[sizeof(TRACE_HEADER)];


   /* make up a station name list
   ******************************/
   if (Nchan > MAX_CHAN)
   {
	   logit("e"," %d channels requested. %d is max\n",Nchan,MAX_CHAN);
	   return -1;
   }

   strcpy(seedName.sta,"AAAAA");
   strcpy(seedName.comp, "AAA");
   strcpy(seedName.net, "AA");
   logit("","Nchan: %d\n",Nchan);
   logit("","ChanMsgSize: %d\n",ChanMsgSize);  
   logit("","ChanRate: %f\n",ChanRate);

	for (i=0; i<Nchan; i++)
	{

		strcpy( ChanList[i].sta, seedName.sta);
		strcpy( ChanList[i].comp, seedName.comp);
		strcpy( ChanList[i].net, seedName.net);
		ChanList[i].pin = i;
		if(Debug ==1)logit("","%8d %s %s %s\n",
			ChanList [i].pin,ChanList[i].sta, ChanList[i].comp, ChanList[i].net);
		if( inc(&seedName)<0)
		{
			logit("e","Name inc failed\n");
			return -1;
		}
	}

	/* Initialize the console display
	******************************/
	InitCon();
	SetCurPos(4,6); printf("Nchan: %d",Nchan);
	SetCurPos(4,7); printf("MsgSize: %d",ChanMsgSize);
	SetCurPos(4,8); printf("Rate: %f",ChanRate);

/* Attach to existing transport ring and send first heartbeat
   **********************************************************/
   tport_attach( &OutRegion, OutKey );
   logit( "t", "Attached to transport ring: %d\n", OutKey );

	/* get initial time for the header time stamps
	**********************************************/
	hrtime_ew(&startTime);
	if( Debug ==1) logit("","startTime: %lf\n",startTime);

	/* calculate inter-packet time
	******************************/
	packetDt = 1.0 / ( Nchan * (ChanRate/ChanMsgSize) );
	if( Debug ==1) logit("","packetDt: %f\n",packetDt);
	SetCurPos(40,6); printf("Inter packet time: %f sec",packetDt);

/************************* The main program loop   *********************/

  while ( tport_getflag( &OutRegion ) != TERMINATE  &&
	   tport_getflag( &OutRegion ) != MyPid         )
   {
	   /* Update the scan count
	   *********************/
	   scan += (unsigned)ChanMsgSize;
	   
	   SetCurPos( 10, 10 );
	   printf( "%d", scan );
	   
	  /* Position the screen cursor for error messages
	  *********************************************/
      SetCurPos( 4, 22 );
	  
	  /* Loop through the trace messages to be sent out
	  **********************************************/
      for ( i = 0; i < Nchan; i++ )
      {
		  /* Fill the trace buffer header
		  ****************************/
		  traceHead->nsamp      = ChanMsgSize;         // Number of samples in message
		  traceHead->samprate   = ChanRate;            // Sample rate; nominal
		  traceHead->quality[0] = '\0';                // One bit per condition
		  traceHead->quality[1] = '\0';                // One bit per condition
		  
		  strcpy( traceHead->datatype, "i4" );         // Data format code
		  strcpy( traceHead->sta,  ChanList[i].sta );  // Site name
		  strcpy( traceHead->net,  ChanList[i].net );  // Network name
		  strcpy( traceHead->chan, ChanList[i].comp ); // Component/channel code
		  traceHead->pinno = ChanList[i].pin;          // Pin number
		  
		  /* Set the trace start and end times.
		  Times are in seconds since midnight 1/1/1970
		  ********************************************/
		  traceHead->starttime = startTime;
		  traceHead->endtime   = traceHead->starttime + (ChanMsgSize - 1)/ChanRate;
		  startTime = startTime + (double)ChanMsgSize/ChanRate;
		  
		  /* Transfer ChanMsgSize samples from halfBuf to traceBuf
		  *****************************************************/
		  tracePtr = &traceDat[0];
		  halfPtr  = &halfBuf[i];
		  for ( j = 0; j < ChanMsgSize; j++ )
		  {
			  traceDat[j] = j%10;
		  }
		  
		  /* sleep a bit if necessary
		  ***************************/
		  /* Mystery: I had weird results (sometimes) with the following:
		  hrtime_ew( &tnow ); 
		  Doing it in-line, as below, works. weird, no? */
		  {
			  struct _timeb t;
			  
			  _ftime( &t );
			  SetCurPos( 4, 22 );
			  //logit("","t.time: %ld  t.millitm: %u\n",t.time, t.millitm);
			  tnow = (double)t.time + (double)t.millitm*0.001;
		  }
		  SetCurPos( 4, 22 );
		  if(Debug ==1) logit("","\nnPacket: %d\n",nPacket);
		  if(Debug ==1) logit(""," tnow:     %lf\n", tnow);
		  
		  if(nPacket == 0 ) tfirst = tnow;	// mark the time of the first packet

		  tnextSend = nPacket*packetDt + tfirst;
		  SetCurPos( 4, 22 );
		  if(Debug ==1) logit("","tnextSend: %lf\n",tnextSend);
		  twait = tnextSend - tnow;
		  if (twait > 0 )
		  {
			  sleep_ew((unsigned)(twait*1000. +.5));
			  SetCurPos( 4, 22 );
			  if(Debug ==1) logit("e","sleeping: %d\n", (unsigned)(twait*1000. +.5));
				  else
				  printf("sleeping: %d\n", (unsigned)(twait*1000. +.5));
		  }

		  /* Send the message
		  *******************/
		  rc = tport_putmsg( &OutRegion, &logo, traceBufSize, traceBuf );
		  if ( rc == PUT_TOOBIG )
		  {
			  logit("e","Trace message for channel %d too big\n", i );
			  return -1;
		  }
		  if ( rc == PUT_NOTRACK )
		  {
			  logit("e","Tracking error while sending channel %d\n", i );
			  return -1;
		  }
		  nPacket++;	// count outgoing packets

		  /* keep statistics on what' been sent
		  *************************************/
		  PtsSent = PtsSent + ChanMsgSize;
		  PktsSent++;

		  /* Show data rates
		  ******************/
		  if (tnow >= tShowNext )
		  {
			  SetCurPos( 18, 12 );
			  printf( "%6.lf", nPacket*ChanMsgSize/(tnow-tfirst) );
			  SetCurPos( 18, 14 );
			  printf( "%6.1lf", nPacket/(tnow-tfirst) );
			  tShowNext = tnow + 2.0;
		  }
      }
      SetCurPos( 0, 0 );
   }

/* Clean up and exit program
   *************************/
   free( halfBuf );
   free( ChanList );

   logit( "t", "makeTrace terminating.\n" );
   return 0;
}


int inc( SCN* name)
{
	
	name->sta[4] = name->sta[4]+1;
	if (name->sta[4] == '[')
	{
		name->sta[4] = 'A'; 
		name->sta[3]++; 
	}
		if (name->sta[3] == '[')
	{
		name->sta[3] = 'A'; 
		name->sta[2]++; 
	}
		if (name->sta[2] == '[')
	{
		name->sta[2] = 'A'; 
		name->sta[1]++; 
	}
		if (name->sta[1] == '[')
	{
		name->sta[1] = 'A'; 
		name->sta[0]++; 
	}
		if (name->sta[0] == '[')
	{
		name->sta[0] = 'A'; 
		name->comp[2]++;		// overflow into component name
	}
		if (name->comp[2] == '[')
	{
		name->comp[2] = 'A'; 
		name->comp[1]++; 
	}
		if (name->comp[1] == '[')
	{
		name->comp[1] = 'A'; 
		name->comp[0]++; 
	}
		if (name->comp[0] == '[')
	{
		name->comp[0] = 'A'; 
		name->net[1]++;		// overflow into network name
	}
		if (name->net[1] == '[')
	{
		name->net[1] = 'A'; 
		name->net[0]++; 
	}
		if (name->net[0] == '[')
	{
		logit("e","Cannot generate this many names\n");
		return -1; 
	}

	return 0;
}