/* * Module DTSS$PROVIDER.C * Version V1.0-1 */ /* * Copyright (c) 1990,1991,1992 by * Digital Equipment Corporation, Maynard, Mass. * * This software is furnished under a license and may be used and copied * only in accordance with the terms of such license and with the * inclusion of the above copyright notice. This software or any other * copies thereof may not be provided or otherwise made available to any * other person. No title to and ownership of the software is hereby * transferred. * * The information in this software is subject to change without notice * and should not be construed as a commitment by Digitial Equipment * Corporation. * * Digital assumes no responsibility for the use or reliablity of its * software on equipment which is not supplied by Digital. * * FACILITY: Distributed Time Synchronization Service (DTSS) * * ABSTRACT: * Implements a DECdts time provider which obtains time from * the following list of radio receivers, connected thru a * RS232 terminal interface. Please refer to the DECdts * Concepts Manual for information about the geographical * coverage of these radio providers. * * * * Time Provider Radio Model Compilation Switch * ==================================================================== * Heath Compony Model GC-100 Radio Receiver (WWV) | TP_GC1000 * ------------------------------------------------+------------------- * Precision Standard Time Inc. Model OEM-10 (WWV) | TP_PSTI * ------------------------------------------------+------------------- * Spectracom Synchronized Clock Model 8170 (WWVB)| TP_SPEC * ------------------------------------------------+------------------- * Traconex Integrated Time Source Model 1020 (WWV)| TP_TRAC * ------------------------------------------------+------------------- * Hopf Electronics Receiver Model 6020 | TP_HOPF * ------------------------------------------------+------------------- * NULL time provider (Hi resolution external clk) + TP_NULL * ==================================================================== * * TO COMPILE: * * The program will conditionally compile to produce one of the * supported time provider types. To generate a particular time * time provider object, use the '/DEFINE' switch to define the provider * type. The compilation switches and provider types are listed * in the tables above. * * $! * $! This DCL Command Procedure will compile and link some * $! of the DTSS time provider examples. * $! * $ define = "TP_TRAC" * $ name = "DTSS$PROVIDER_TRAC" * $ GOSUB BUILD * $ define = "TP_SPEC" * $ name = "DTSS$PROVIDER_SPEC" * $ GOSUB BUILD * $ define = "TP_PSTI" * $ name = "DTSS$PROVIDER_PSTI" * $ GOSUB BUILD * $ define = "TP_HOPF" * $ name = "DTSS$PROVIDER_HOPF" * $ GOSUB BUILD * $ EXIT * $ * $ BUILD: * $ CC/OBJ='name/G_FLOAT/DEFINE=('define=1) DTSS$PROVIDER.C * $ LINK/EXE='name 'name, - * SYS$LIBRARY:VAXCRTLG.OLB/LIB, SYS$INPUT:/OPTIONS * SYS$SHARE:DTSS$SHR.EXE/SHARE * $ RETURN * * * * TO RUN: * * Four logical names are translated at program start from * the system logical name table which control the characteristics * of the time provider's operation, they are: * * Logical name * DTSS$_TP_DEVICE : Device to which provider attached. * This is usually an RS232 port to which the provider * radio is attatched. The terminal characteristics of * the port must be set using the 'set term/perm' DCL * command. Each provider type requires specific settings * which are documented in the provider specific documentation * in the code below. * * Format: Any ASCII string. * * DTSS$_TP_INACCURACY : Systematic inaccuracy in ms. * Each radio clock specifies the amount of systematic * inaccuracy which is returned with each time-stamp. * This is usually proportional to the number of miles * the device is physically located from the transmission * center from which time is read. The inaccuracy specified * by this parameter is added to the times returned to the * time server. * * Format: a non-negative integer. * * DTSS$_TP_POLL_RATE : Rate in seconds that the device is * polled. This value will override the DTSS management * parameter 'synchronization hold down'. * * Format: an integer (seconds) in the range 1 second to 31 days; * * DTSS$_TP_TIME_STAMPS : This parameter specifies the number * of timestamps which are read and returned to the * time server at each synchronization. * * Format: an integer in the range 1 to 6; * * DTSS$_TP_MAXERROR : If the difference between the time * provider and the local clock differs more than * maxerror, then the timeprovider is considered faulty, * and its timestamp is ignored. * * Format: a non-negative integer (seconds). * * DTSS$_TP_FIRSTSYNC : If this value is TRUE, then the * DTSS$TP_MAXERROR parameter is ignored on the first * synchronization. * * Format: 0 , false; otherwise TRUE. * * DTSS$_TP_VERBOSE : Display info to std out * * Format: 0, false; otherwise TRUE. * * This is an example session, only setting the dtss$_tp_device * logical is required, all others are optional: * * $ ! * $ ! set the terminal characteristics. The exact characteristics * $ ! are specific to the external device. Important characteristics * $ ! to consider are buad rate and parity. After setting the * $ ! terminal characteristics, set host _TTA3:/dte, can be used * $ ! to test the external device and the terminal characteristics. * $ ! * $ set term _TTA3:/passall/passthru/eightbit/perm * $ * $ ! * $ ! now define the time provider logicals, only the device * $ ! name is required * $ ! * $ define/sys DTSS$_TP_DEVICE _TTA3: ! your device - required * $ define/sys DTSS$_TP_TIME_STAMPS 4 ! read 4 times each synch * $ define/sys DTSS$_TP_POLL_RATE 30 ! synch each 30 seconds * $ * $ ! * $ ! run the provider detatched at priority 10 * $ ! * $ run/detach/priority=10/process_name=DTSS$PROVIDER dtss$provider.exe * $ * * ENVIRONMENT: VAX/VMS V5.5 * * AUTHOR: * * Distributed Processing Engineering - DPE/DTSS * */ #pragma nostandard /* A VMS only Module */ #include /* standard I/O definitions */ #include /* I/O definitions */ #include /* error return value (SS$) definitions */ #include /* descriptor definitions */ #include /* Logical name definitions */ #include /* isxxx macros, etc. */ #include /* tm structure definition */ #include "dtssprovider.h" /* utc library routines & dtss tpi defs */ /* * Constants */ #define BUFSIZE 40 /* Length of ascii time string */ #define K_NS_PER_SEC (1000000000) #define K_MS_PER_SEC (1000) #define K_NS_PER_MS (K_NS_PER_SEC / K_MS_PER_SEC) typedef struct IOsb { /* IO status Block */ unsigned short status; unsigned short byteCount; unsigned long devStatus; } IOsb; /* * Forward Definitions */ InitIPC( unsigned short *tstpChan, unsigned short *tptsChan ); SendReply( unsigned short tptsChan, TPrspMsg *timeResponse ); ReadRequest( unsigned short tstpChan, TPreqMsg *timeResponse ); void InitializeTPdefaults(int *pollrate, int *timestamps, int *inaccuracy, int *tmorate, int *clockSet, int *retries, int *firstsynch, int *maxtperror, int *isverbose); int QueryProvider(unsigned short ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime); int ValidateTime(struct utc *systemTime, struct utc *externalTime); /* * External Routines */ /* * Macros */ /* * Global Variables */ static int ttchan; /* channel number of term */ $DESCRIPTOR(TSTPLOG, "DTSS$_TSTP_MBX"); /* tpts mailbox */ $DESCRIPTOR(TPTSLOG, "DTSS$_TPTS_MBX"); /* tstp mailbox */ $DESCRIPTOR(TPDEVICE, "DTSS$_TP_DEVICE"); /* Device name parameter */ $DESCRIPTOR(TPINACC, "DTSS$_TP_INACCURACY"); /* Inaccuracy parameter */ $DESCRIPTOR(TPRATE, "DTSS$_TP_POLL_RATE"); /* Poll rate parameter */ $DESCRIPTOR(TPSTAMPS, "DTSS$_TP_TIME_STAMPS"); /* Time stamps parameter */ $DESCRIPTOR(MAXERROR, "DTSS$_TP_MAXERROR"); /* Max error allowed on TP */ $DESCRIPTOR(FIRSTSYNC,"DTSS$_TP_FIRSTSYNC"); /* Always synch first time */ $DESCRIPTOR(VERBOSE, "DTSS$_TP_VERBOSE"); /* Print info out. */ $DESCRIPTOR(PROCESS_NAME, "DTSS$PROVIDER"); /* Process name when OK */ $DESCRIPTOR(LNM_TABLE,"LNM$SYSTEM_TABLE") ; /* Table to search */ unsigned long INACCURACY; /* base inaccuracy of TP */ unsigned long POLLRATE; /* seconds between TP syncs */ unsigned long TIMESTAMP; /* time stamps at each sync */ unsigned long TMORATE; /* timeout */ unsigned long CLOCKSET; /* allow clock sets? */ unsigned long RETRIES; /* retries allowed. */ unsigned long FIRSTSYNCH; /* always synch first time */ unsigned long MAXTPERROR; /* Max error on TP. */ unsigned long ISVERBOSE; /* Print info. */ unsigned long SYNCHCOUNT; /* current synch. number */ /* *++ * InitTP() * * Functional Description: * * * This is the first routine called by the DECdts time provider, it is * called at the beginning of each synchronization. This allows us * do any necessary initializations. * * * Inputs: * * None. * * Implicit Inputs: * * The TP year info is valid. * Note that the TP does not read any year info. The year * info is manually dialed into the hardware by setting the * appropriate DIP switches. If the DIP switches are not * set correctly, the year and date info of the TP may be faulty. * The DIP switches must be set each year. * * On the PSTI, it is also possible to issue an SY command * to initialize the year info at machine startup. * * Outputs: * * * Implicit Outputs: * * * Value Returned: * * The Value returned by this routine directly impacts the * result of a synchronization. If this routine returns * failure, then the DECdts Time Provider will abort the * synchronization. * * 1 if success, 0 otherwise. * * * Side Effects: * * None. *-- */ InitTP() { unsigned long status; #ifndef TP_NULL /* * Assign a channel to the terminal port device connected to the * TP device. */ status = SYS$ASSIGN(&TPDEVICE, /* device name descriptor */ &ttchan, /* channel number */ 0, /* access mode */ 0); /* mailbox */ #else /* * The NULL TP example does not perform any I/O with the external * time source. */ status = 1; #endif return( status ); } /* End of routine initTP */ /* *++ * ExitTP() * * Functional Description: * * This is the last user routine called by the DECdts time provider. It * allows us to detach the TP's IPC channel to the Time service process. * It also allows this process to detach from the Time Provider device. * * * * Inputs: * * ttchan - channel to time provider device * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * status - Status of deassign. * * Side Effects: * * None. *-- */ ExitTP( ttchan ) unsigned short ttchan; { unsigned long status; status = SYS$DASSGN( ttchan ); return( status ); } /* End of routine ExitTP */ /* *++ * ReadTimes() * * Functional Description: * * Parse out time stamps from the radio clock input. * * Inputs: * * timeStamps - the number of timestamps to read * fd - radio clock file descriptor * * Outputs: * * tpTimeMsg - buffer to return the timestamp data. * * Value Returned: * * 1 - Success * 0 - Failure * *-- */ int ReadTimes( timeStamps, retries, ttchan, tpTimeMsg ) unsigned long timeStamps; unsigned long retries; int ttchan; TPtimeMsg *tpTimeMsg; { int i; /* temp, index */ int retry; int status; retry = retries; /* * Now Read The Time Stamps. * Note that this loop will terminate having read timeStamps timestamps * or exhusting retry retries. and thus is non-infinite. */ i = 0; while ( i < timeStamps ) { status = QueryProvider(ttchan, &tpTimeMsg->timeStampList[i].beforeTime, &tpTimeMsg->timeStampList[i].TPtime, &tpTimeMsg->timeStampList[i].afterTime ); if (status & 1) { status = ValidateTime(&tpTimeMsg->timeStampList[i].afterTime, &tpTimeMsg->timeStampList[i].TPtime); if (!(status & 1)) PrintValidationError(&tpTimeMsg->timeStampList[i].afterTime, &tpTimeMsg->timeStampList[i].TPtime); } if (status & 1) { i += 1; } else { if (retry-- == 0) return(0); } } return(1); } /* *++ * main() * * Functional Description: * * The Time Provider program communicates with the Distributed * Time Synchronization Service and with a time provider * device. This module implements the DECdts TP interface. * * * Inputs: * * None. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * IPC with DTSS$SERVICE. * * Value Returned: * * None. * * Side Effects: * * None. * *-- */ main( argc, argv ) int argc; char *argv[]; { TPreqMsg timeServiceRequest; TPrspMsg TMOresponse; TPrspMsg timeResponse; unsigned long status; unsigned short tstpChan; unsigned short tptsChan; char value[255]; int i; short size; unsigned long attr = LNM$M_CASE_BLIND; /* attributes mask */ struct { short bufln ; short itmcd ; long *bufad ; long *rtnln ; long term; } litmlst = { 255, LNM$_STRING, &value, &size, 0 }; /* * read the startup parameters */ InitializeTPdefaults(&POLLRATE, &TIMESTAMP, &INACCURACY, &TMORATE, &CLOCKSET, &RETRIES, &FIRSTSYNCH, &MAXTPERROR, &ISVERBOSE); /* * keep count of synchs attempted. */ SYNCHCOUNT = 0; /* * Set the process name to dtss$provider */ if (!(status = SYS$SETPRN( &PROCESS_NAME ))&1) exit(status); status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPRATE, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; POLLRATE = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPSTAMPS, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; TIMESTAMP = atoi( value ); if (TIMESTAMP > K_MAX_TIMESTAMPS || TIMESTAMP < K_MIN_TIMESTAMPS ) { fprintf(stderr,"The time stamp value is out of legal range\n"); fprintf(stderr,"Legal Range is %d to %d\n", K_MIN_TIMESTAMPS,K_MAX_TIMESTAMPS); exit(1); } } status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPINACC, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; INACCURACY = atoi( value ) ; } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPRATE, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; POLLRATE = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &MAXERROR, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; MAXTPERROR = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &VERBOSE, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; ISVERBOSE = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &FIRSTSYNC, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; FIRSTSYNCH = atoi( value ); } ; value[0] = '\0'; status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPDEVICE, 0, &litmlst ); if ((status & 1)) { value[size] = '\0'; } ; /* * Echo back the input parameters. */ fprintf(stderr,"PARAMETERS SET:\n"); fprintf(stderr,"TP_DEVICE: %s\n",value); fprintf(stderr,"TP_INACCURACY: %d seconds\n", INACCURACY); fprintf(stderr,"TP_POLL_RATE: %d seconds\n", POLLRATE); fprintf(stderr,"TP_TIME_STAMPS: %d timestamps\n", TIMESTAMP); fprintf(stderr,"TP_MAXERROR: %d seconds\n", MAXTPERROR); fprintf(stderr,"TP_FIRSTSYNC: %s\n", FIRSTSYNCH?"TRUE":"FALSE"); fprintf(stderr,"TP_VERBOSE: %s\n\n\n", ISVERBOSE?"TRUE":"FALSE"); /* * Initialize the interprocess communication. * Die if this fails. */ status = InitIPC( &tstpChan, &tptsChan ); if ( !(status & 1) ) exit( status ); /* * Prepare a time out response message to issue to the service * which will identify this process as active, and * tell the service how long it must wait for the time response. */ TMOresponse.version_major = K_TPI_VERSION_MAJOR; TMOresponse.version_minor = K_TPI_VERSION_MINOR; TMOresponse.status = K_TPI_SUCCESS; TMOresponse.TPmsgType = K_TPI_CTL_MESSAGE; TMOresponse.TPdata.TPctlMsg.nextPoll = POLLRATE; TMOresponse.TPdata.TPctlMsg.timeout = TMORATE; TMOresponse.TPdata.TPctlMsg.noClockSet = CLOCKSET; /* * Goto Work! * Issue a synchronous IO request to the server request * mailbox. When the the server responds, Reply to the * response mailbox with the set of TP times. Exit the * program if there is any error associated with the * IPC. * */ for (;;) { status = ReadRequest( tstpChan, &timeServiceRequest ); if ( !(status & 1) ) exit( status ); /* * increment the synchcount, * make sure it doesn't loop around to 1 again * since on synch #1 the MAX TP ERROR value * is ignored. */ SYNCHCOUNT++; SYNCHCOUNT = (SYNCHCOUNT==0)?2:SYNCHCOUNT; timeResponse.version_major = K_TPI_VERSION_MAJOR; timeResponse.version_minor = K_TPI_VERSION_MINOR; timeResponse.TPsyncID = timeServiceRequest.TPsyncID; timeResponse.TPdata.TimeMsg.timeStampCount = 0; timeResponse.status = K_TPI_SUCCESS; timeResponse.TPmsgType = K_TPI_TIME_MESSAGE; /* * Initialize the time provider hardware. */ status = InitTP(); if ( !( status & 1 ) ) { timeResponse.status = K_TPI_FAILURE; if (!(status = SendReply ( tptsChan, &timeResponse ))&1) exit(status); } else { /* * Send the initial repsonse, informing the * the time service that we are alive and well, * and that it should wait for the time stamps * to arrive. */ TMOresponse.TPsyncID = timeServiceRequest.TPsyncID; status = SendReply( tptsChan, &TMOresponse ); if ( !(status & 1) ) exit( status ); status = ReadTimes(TIMESTAMP, RETRIES, ttchan, &timeResponse.TPdata.TimeMsg); if ( status & 1 ) { timeResponse.TPdata.TimeMsg.timeStampCount = TIMESTAMP; timeResponse.status = K_TPI_SUCCESS; } else { timeResponse.status = K_TPI_FAILURE; } status = SendReply( tptsChan, &timeResponse ); if ( !(status & 1) ) exit( status ); /* * Debugging output. */ if (ISVERBOSE) PrintTimes( &timeResponse ); /* * Call for the Time Provider Hardware to do any necessary * cleanup by calling ExitTP. */ ExitTP( ttchan ); } } } /* End of main program*/ /* *++ * ValidateTime() * * Functional Description: * * This routine confirms that the time returned from the system, is * within MAXTPERROR seconds of the time returned by the external * device. * * Inputs: * * systemTime - time returned by the system. * externalTime- time returned by the external device. * * Implicit Inputs: * * SYNCHCOUNT - current synch number. * FIRSTSYNCH - allow first synch to always validate. * MAXTPERROR - greatest difference between two times. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * Returns TRUE iff * (abs(externalTime - systemTime) <= MAXTPERROR) || * (FIRSTSYNCH && SYNCHCOUNT == 1) * * Side Effects: * * None. * *-- */ int ValidateTime(systemTime,externalTime) struct utc *systemTime; struct utc *externalTime; { utc_t result; struct timespec inaccsp; struct reltimespec timesp; /* * find the difference between the system time and the * time reported by the external clock. */ if (utc_subtime(&result,systemTime,externalTime) || utc_abstime(&result,&result) || utc_binreltime(×p,&inaccsp,&result)) exit(0); /* * if the difference is less than the max error, or * if first synch is enabled, return true. */ return( ((SYNCHCOUNT == 1) && (FIRSTSYNCH)) || (timesp.tv_sec <= MAXTPERROR) ); } /* *++ * InitIPC() * * Functional Description: * * This routine creates a temporary Mailbox to which the Time Service * Process will write its requests. * * Inputs: * * None. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * None. * * Side Effects: * * None. * *-- */ InitIPC( tstpChan, tptsChan ) unsigned short *tstpChan; unsigned short *tptsChan; { unsigned long status; /* * Create a request channel to the time service. Mark the mailbox * for delete so that it will go away when this process deassigns * its channel. Note that the service will only attach to the * mailbox while it is communicating with the TP, it is generally * detatched. */ status = SYS$CREMBX (1, /* prmflag */ tstpChan, /* channel */ sizeof(TPreqMsg), /* maxmsg */ sizeof(TPreqMsg)*2, /* bufquo */ 0x0330, /* promsk */ 0, /* access in current mode */ &TSTPLOG); /* DTSS$_TSTP_MBX */ if ( !(status & 1) ) return( status ); if ( !(( status = SYS$DELMBX ( *tstpChan ) ) & 1) ) return( status ); /* * Assign a channel to the TP to TS mailbox which was created by * the DTSS$Service process. */ status = SYS$ASSIGN (&TPTSLOG, /* TPtoTS mailbox */ tptsChan, /* channel */ 0, /* access mode */ 0); /* mailbox */ return ( status ); } /* End of routine InitIPC */ /* *++ * SendReply() * * Functional Description: * * This routine writes a response message to the Time Service Process's * response Mailbox. * * Inputs: * * tptsChan - The channel to the TS response mailbox * * timeResponse - the address of the response message which * is to be written to the TS. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * int - the status of the write request. * * Side Effects: * * None. * *-- */ SendReply( unsigned short tptsChan, TPrspMsg *timeResponse) { IOsb iosb; unsigned long status; status = SYS$QIOW(0, /* efn */ tptsChan, /* chan */ IO$_WRITEVBLK | /* func */ IO$M_NORSWAIT | IO$M_NOW, &iosb, /* I/O status block */ 0, /* ast addr */ 0, /* ast prm */ timeResponse, /* P1 = buffer to write */ sizeof(TPrspMsg), /* P2 = size in bytes */ 0, /* P3 */ 0, /* P4 */ 0, /* P5 */ 0); /* P6 */ if ( !(status & 1) ) return( status ); if ( !(iosb.status & 1) ) return( iosb.status ); return( status ); } /* End of routine sendReply */ /* *++ * ReadRequest() * * Functional Description: * * This routine reads a request message written by the Time Service * process to the TSTP mailbox. * * Inputs: * * None. * * Implicit Inputs: * * The Channel to the request mailbox is attached. * * Outputs: * * timeRequest - the address of the structure which will * receive the Time Service request message. * * Implicit Outputs: * * None. * * Value Returned: * * int - the status of the read of the mailbox. * * Side Effects: * * None. * *-- */ ReadRequest( unsigned short tstpChan, TPreqMsg *timeRequest) { IOsb iosb; unsigned long status; status = SYS$QIOW(0, /* efn */ tstpChan, /* chan */ IO$_READVBLK, /* func */ &iosb, /* I/O status block */ 0, /* ast addr */ 0, /* ast prm */ timeRequest, /* P1 = buffer to write */ sizeof(TPreqMsg), /* P2 = size in bytes */ 0, /* P3 */ 0, /* P4 */ 0, /* P5 */ 0); /* P6 */ if ( !(status & 1) ) return( status ); if ( !(iosb.status & 1) ) return( status ); /* * Check that we got the size message we expected. */ if (iosb.byteCount != sizeof(TPreqMsg)) { (void) fprintf(stderr, "rqstMsg size %d, expected %d\n", iosb.byteCount, sizeof(TPreqMsg)); return( SS$_NODATA ); } if (timeRequest->version_major != K_TPI_VERSION_MAJOR || timeRequest->version_minor != K_TPI_VERSION_MINOR) { (void) fprintf(stderr,"TPI version mismatch \n"); return( SS$_NODATA ); } return( status ); } /* End of routine ReadRequest */ #ifdef TP_PSTI /* ********************************************************** * PSTI Specific Routines. ********************************************************** */ /* * PSTI specific constants */ #define M_PSTI_AVAIL 0x08 /* bit to test for time availability */ #define M_PSTI_OUT_OF_SPEC 0x40 /* out of spec time mask */ #define M_PSTI_HARD_FAULT 0x20 /* PSTI hardware fault */ #define M_PSTI_SIGNAL_FAULT 0x10 /* PSTI signal fault time mask */ #define PSTI_PROMPT "QA0000"/* prompt string for OEM time */ #define PSTI_RESPONSE_LENGTH (13) /* bytes returned by QA */ #define PSTI_NOCLOCKSET (0) /* allow the clock to be affected */ #define PSTI_POLL_RATE (60) /* sixty seconds between tp polls */ #define PSTI_TIME_STAMPS (3) /* number of time samples to read */ #define PSTI_INACCURACY (30) /* 30ms of inaccuracy default */ #define PSTI_TMORATE (30) /* 30 secs to respond to TS request*/ #define PSTI_QIO_TIMEOUT (3) /* seconds till read QIO times out */ #define PSTI_RETRIES (5) /* allow 5 retries after a TP failure*/ #define PSTI_ISVERBOSE (1) /* generate output */ #define PSTI_MAXTPERROR (60) /* ignore deltas greater than 60 */ #define PSTI_FIRSTSYNCH (1) /* synch up the first time thru */ /* * There are only 6 bits of valid data in any PSTI data byte. Bit * 7 and 0 are used for parity checks and other purposes. * Mask07 strips bit 7 and bit 0 from a PSTI data byte, * then it normalizes the data into a byte. */ #define Mask07( dataByte ) (( dataByte & 0x7F) >> 1 ) /* * Mask07AndAdd strips non data bits from two bytes and then concatenates * them into a single value. Used for data that does not fit in a single * byte of information. */ #define Mask07AndAdd(dataByteHi, dataByteLo) \ ( Mask07(dataByteLo) + ( Mask07(dataByteHi) << 6 )) /* *++ * InitializeTPdefaults() * * Functional Description: * * Initialize the default input parameters for the external time * provider. * * * * Inputs: * Implicit Inputs: * * * Outputs: * * pollrate - int to be set to the default poll rate * timestamp- int to be set to the default number of * timestamps to read from the external time provider. * inaccuracy-int to be set to the default inaccuracy for the * external time provider (systematic error). * tmorate -int to be set to the default time-out rate (the * number of seconds the dtss server must wait for * the data response). * clockset - int to be set to true if the system clock should not * be affected by the results of the TP synch, false if * the clock can be modified by the results of the TP * synch. * retries - int to be set to the number of times the program is * allowed to resend a request after the * external time source has returned a failure. * firstsync- boolean, assume that the time returned by the external * clock is correct on the first synchronization * maxtperror-if the difference between the local clock and the * time provider differs by more than maxtperror, the * external clock is assumed faulty. * local clock and the time provider * isverbose -boolean, > 0 indicates that informational messages * will be displayed. * * * Implicit Outputs: * none. * * Value Returned: * none. * * Side Effects: * none. * *-- */ void InitializeTPdefaults(pollrate,timestamp, inaccuracy,tmorate, clockSet,retries, firstsynch,maxtperror, isverbose) int *pollrate, *timestamp, *inaccuracy, *tmorate, *clockSet, *retries, *firstsynch, *maxtperror, *isverbose; { *pollrate = PSTI_POLL_RATE; /* seconds */ *timestamp = PSTI_TIME_STAMPS; /* int, 1-6 */ *inaccuracy= PSTI_INACCURACY; /* milliseconds */ *tmorate = PSTI_TMORATE; /* seconds */ *clockSet = PSTI_NOCLOCKSET; /* int, t/f - 1/0 */ *retries = PSTI_RETRIES; /* int > 0 */ *firstsynch= PSTI_FIRSTSYNCH; /* int > 0 */ *maxtperror= PSTI_MAXTPERROR; /* seconds */ *isverbose = PSTI_ISVERBOSE; /* int > 0 */ } /* End of routine InitializeTPdefaults */ /* *++ * QueryProvider() * * Functional Description: * * This routine issues a single QA300 command to the PSTI device. * It returns the Binary Absolute Time represented by the PSTI * data returned. * * * Inputs: * * ttchan - The active channel to the PSTI device. * * Implicit Inputs: * * None. * * Outputs: * * TPtime - The Time returned by the PSTI device. * * Implicit Outputs: * * * Value Returned: * * 0 - Failure - The PSTI device failed. * 1 - Success - The PSTI device was contacted. * * Side Effects: * * *-- */ int QueryProvider(unsigned short ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime) { /* * Passing Binary encoded data. See PSTI dip switches for * baud. Set terminal characteristics for Eightbit,pasall, * pasthru. */ char TPdata[PSTI_RESPONSE_LENGTH+1]; int status; int retSize; IOsb TPIOSB; /* status block for PSTI */ struct {long null; long mask;} term_mask = {0, 0x0000}; /* * now a structure to set the terminator * character for the read. */ (void) utc_gettime( beforeTime ); /* * post qiow read to the psti with a timeout. This also purges * the input buffer of any residue characters. */ status = SYS$QIOW(0, /* event flag */ ttchan, /* channel number */ IO$_READPROMPT | /* function code */ IO$M_TIMED | IO$M_NOECHO | IO$M_PURGE, &TPIOSB, /* io status block */ 0, /* ast entry */ 0, /* ast parameter */ TPdata, /* buffer for user data */ PSTI_RESPONSE_LENGTH, /* buffer size of response */ PSTI_QIO_TIMEOUT, /* P3; secs to timeout */ &term_mask, /* P4: mask specifying terminators */ PSTI_PROMPT, /* P5; prompt string */ strlen(PSTI_PROMPT)); /* P6; length of prompt */ (void) utc_gettime( afterTime ); if ( !(status & 1) ) { (void) fprintf(stderr, "M_PSTI: QIO Status failure %x\n", status); return ( status ); } if ( !(TPIOSB.status & 1) ) { (void) fprintf(stderr, "M_PSTI: IOSB Status failure %x\n", TPIOSB.status); return ( TPIOSB.status ); } /* * check that we got the correct number of bytes. * Otherwise return hard error. */ if (TPIOSB.byteCount != PSTI_RESPONSE_LENGTH) { (void) fprintf(stderr, "M_PSTI: response length failure %x\n", TPIOSB.byteCount); return(0); } /* * Check all the status bits, make sure this time is truely valid. * Additional stamps? */ if ( !(TPdata[0] & M_PSTI_AVAIL) ) { (void) fprintf(stderr, "M_PSTI: time not Available %x\n", TPdata[0]); return(0); } if ( TPdata[0] & M_PSTI_OUT_OF_SPEC ) { (void) fprintf(stderr, "M_PSTI: out of spec detected %x\n", TPdata[0]); return(0); } if ( TPdata[0] & M_PSTI_SIGNAL_FAULT ) { (void) fprintf(stderr, "M_PSTI: out of spec detected %x\n", TPdata[0]); return(0); } if ( TPdata[0] & M_PSTI_HARD_FAULT ) { (void) fprintf(stderr, "M_PSTI: hard fault detected %x\n", TPdata[0]); return(0); } /* * Convert the data returned by the PSTI into struct utc. */ return(CvtTPtoUTC( TPdata, TPtime )); } /* *++ * CvtTPtoUTC() * * Functional Description: * * This routine converts the response string of the PSTI QA command * into a Binary Absolute Time value. * * * * Inputs: * * respString - The QA command string. * * * Implicit Inputs: * * None. * * Outputs: * * TPtime - The converted utc value. * * Implicit Outputs: * * None. * * Value Returned: * * None. * * Side Effects: * * None. * *-- */ CvtTPtoUTC( TPdata, TPtime ) char *TPdata; struct utc *TPtime; { long tns, ins; struct tm time, inacc; /* * convert bytes 2 and 3 into msec. */ tns = (Mask07AndAdd(TPdata[2], TPdata[3])) * K_NS_PER_MS; /* * convert bytes 4,5,6 into sec, mins, hours */ time.tm_sec = Mask07(TPdata[4]); time.tm_min = Mask07(TPdata[5]); time.tm_hour = Mask07(TPdata[6]); /* * convert bytes 7 and 8 into day of year */ time.tm_yday = Mask07AndAdd(TPdata[7],TPdata[8]); /* * convert byte 9 (offset from 1986) into current year */ time.tm_year = 1986 + Mask07(TPdata[9]) - 1900; /* * get it yearday into mon and day */ MonthDay (time.tm_year, time.tm_yday, &time.tm_mon, &time.tm_mday); time.tm_isdst = 0; /* * Get the inaccuracy */ inacc.tm_sec = INACCURACY / K_MS_PER_SEC; inacc.tm_min = 0; inacc.tm_hour = 0; inacc.tm_yday = 0; inacc.tm_isdst = 0; ins = (INACCURACY % K_MS_PER_SEC) * K_NS_PER_MS; if (utc_mkgmtime(TPtime, &time, tns, &inacc, ins)) return(0); else return(1); } /* End of routine CvtTPtoUTC */ /* *++ * MonthDay() * * Functional Description: * * This routine Converts the current year, and the current day of * the year (ie 174th day of 1989) to a month and * day in month format ( 12 - 31 - 1989 ). This serves to convert * the PSTI date into something we can more easily handle. * * * Inputs: * * currYear - The current year as an integer. * yearDay - The current day in the year. * * Implicit Inputs: * * None. * * Outputs: * * currMonth - The numerical month ( 1 - 12 ) * dayInMonth - The day in the month ( 1 - 31 ) * * Implicit Outputs: * * None. * * Value Returned: * * None. * * Side Effects: * * None. * *-- */ MonthDay(currYear, yearDay, currMonth, dayInMonth) int currYear; /* current year - 1900 */ int yearDay; /* day of year */ int *currMonth; /* ptr to month */ int *dayInMonth; /* ptr to day of month */ { int dayTab [2] [13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; /* table for get_month and day from day of year input */ int i, leap; leap = (currYear%4 == 0 && currYear%100 != 0) || (currYear+300)%400 == 0; for (i=1; yearDay > dayTab[leap] [i]; i++) yearDay -= dayTab[leap] [i]; *currMonth = i-1; *dayInMonth = yearDay; } #endif #ifdef TP_GC1000 /* ********************************************************** * GC1000 Specific Routines. ********************************************************** */ #define GC1000_PROMPT " " /* Prompt string for clock trigger */ #define GC1000_RESPONSE_LENGTH (24) /* Number of bytes returned by clock */ #define GC1000_NOCLOCKSET (0) /* allow the clock to be affected */ #define GC1000_POLL_RATE (60) /* sixty seconds between tp polls */ #define GC1000_TIME_STAMPS (3) /* number of time samples to read */ #define GC1000_INACCURACY (30) /* 30ms of inaccuracy default */ #define GC1000_TMORATE (30) /* 30 secs to respond to TS request */ #define GC1000_QIO_TIMEOUT (3) /* seconds till read QIO times out */ #define GC1000_RETRIES (5) /* allow 5 retries after a TP failure */ #define GC1000_ISVERBOSE (1) /* generate output */ #define GC1000_MAXTPERROR (60) /* ignore deltas greater than 60 */ #define GC1000_FIRSTSYNCH (1) /* synch up the first time thru */ /* *++ * InitializeTPdefaults() * * Functional Description: * * Initialize the default input parameters for the external time * provider. * * * * Inputs: * Implicit Inputs: * * * Outputs: * * pollrate - int to be set to the default poll rate * timestamp- int to be set to the default number of * timestamps to read from the external time provider. * inaccuracy-int to be set to the default inaccuracy for the * external time provider (systematic error). * tmorate -int to be set to the default time-out rate (the * number of seconds the dtss server must wait for * the data response). * clockset - int to be set to true if the system clock should not * be affected by the results of the TP synch, false if * the clock can be modified by the results of the TP * synch. * retries - int to be set to the number of times the program is * allowed to resend a request after the * external time source has returned a failure. * firstsync- boolean, assume that the time returned by the external * clock is correct on the first synchronization * maxtperror-if the difference between the local clock and the * time provider differs by more than maxtperror, the * external clock is assumed faulty. * local clock and the time provider * isverbose -boolean, > 0 indicates that informational messages * will be displayed. * * * * Implicit Outputs: * none. * * Value Returned: * none. * * Side Effects: * none. * *-- */ void InitializeTPdefaults(pollrate,timestamp, inaccuracy,tmorate, clockSet,retries, firstsynch, maxtperror, isverbose) int *pollrate, *timestamp, *inaccuracy, *tmorate, *clockSet, *retries, *firstsynch, *maxtperror, *isverbose; { *pollrate = GC1000_POLL_RATE; /* seconds */ *timestamp = GC1000_TIME_STAMPS; /* int, 1-6 */ *inaccuracy= GC1000_INACCURACY; /* seconds */ *tmorate = GC1000_TMORATE; /* seconds */ *clockSet = GC1000_NOCLOCKSET; /* int, t/f - 1/0 */ *retries = GC1000_RETRIES; /* int > 0 */ *firstsynch= GC1000_FIRSTSYNCH; /* int > 0 */ *maxtperror= GC1000_MAXTPERROR; /* seconds */ *isverbose = GC1000_ISVERBOSE; /* int > 0 */ } /* End of routine InitializeTPdefaults */ /* *++ * QueryProvider() * * Functional Description: * * This routine issues a single trigger command to the GC1000 device. * It returns the Binary Absolute Time represented by the GC1000 * data returned. * * * Inputs: * * ttchan - The active channel to the GC1000 device. * * Implicit Inputs: * * None. * * Outputs: * * TPtime - The Time returned by the GC1000 device. * * Implicit Outputs: * * * Value Returned: * * 0 - Failure - The GC1000 device failed. * 1 - Success - The GC1000 device was contacted. * * Side Effects: * * *-- */ int QueryProvider(unsigned short ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime) { char TPdata[GC1000_RESPONSE_LENGTH+1]; int status; IOsb TPIOSB; /* status block for GC1000 */ (void) utc_gettime( beforeTime ); /* * post qiow read to the clock with a timeout. This also purges * the input buffer of any residue characters. */ status = SYS$QIOW(0, /* event flag */ ttchan, /* channel number */ IO$_READPROMPT | /* function code */ IO$M_TIMED | IO$M_NOECHO | IO$M_PURGE, &TPIOSB, /* io status block */ 0, /* ast entry */ 0, /* ast parameter */ TPdata, /* buffer for user data */ GC1000_RESPONSE_LENGTH, /* buffer size of response */ GC1000_QIO_TIMEOUT, /* P3; secs to timeout */ 0, /* P4: terminator mask */ GC1000_PROMPT, /* P5; prompt string */ strlen(GC1000_PROMPT)); /* P6; length of prompt */ (void) utc_gettime( afterTime ); if ( !(status & 1) ) { (void) fprintf(stderr, "M_GC1000: QIO Status failure %x\n", status); return ( status ); } if ( !(TPIOSB.status & 1) ) { (void) fprintf(stderr, "M_GC1000: IOSB Status failure %x\n", TPIOSB.status); return ( TPIOSB.status ); } /* * check that we got the correct number of bytes. * Otherwise return hard error. * (Subtract one for the ) */ if (TPIOSB.byteCount != GC1000_RESPONSE_LENGTH-1) { (void) fprintf(stderr, "M_GC1000: response length failure %x\n", TPIOSB.byteCount); return(0); } /* * Check the return buffer to make sure it's a valid time * buf[0:1] Hours * buf[2] ':' * buf[3:4] Minutes * buf[5] ':' * buf[6:7] Seconds * buf[8] '.' * buf[9] Tenths * buf[10:14] blanks * buf[15:16] Month * buf[17] '/' * buf[18:19] Day * buf[20] '/' * buf[21:22] Year * buf[23] */ if ( TPdata[0] == '?' ) { /* (void) fprintf(stderr, "M_GC1000: clock not synchronized\n"); */ return(0); } /* * If tenths of seconds are '?', then we are drifting */ if ( TPdata[9] == '?' ) { #ifdef DEBUG TPdata[9] = '0'; #else /* (void) fprintf(stderr, "M_GC1000: time not accurate\n"); */ return(0); #endif } /* * Check delimiters for proper positions */ if ( ( TPdata[2] != ':' ) || ( TPdata[5] != ':' ) || ( TPdata[8] != '.' ) || ( TPdata[17] != '/' ) || ( TPdata[20] != '/' ) ) { (void) fprintf(stderr, "M_GC1000: time/date string format invalid\n"); return(0); } /* * Check fields for proper characters */ if ( !( isdigit(TPdata[0]) ) || !( isdigit(TPdata[1]) ) || !( isdigit(TPdata[3]) ) || !( isdigit(TPdata[4]) ) || !( isdigit(TPdata[6]) ) || !( isdigit(TPdata[7]) ) || !( isdigit(TPdata[9]) ) || !( isdigit(TPdata[15]) ) || !( isdigit(TPdata[16]) ) || !( isdigit(TPdata[18]) ) || !( isdigit(TPdata[19]) ) || !( isdigit(TPdata[21]) ) || !( isdigit(TPdata[22]) ) ) { (void) fprintf(stderr, "M_GC1000: time/date field format invalid\n"); return(0); } /* * Convert the data returned by the GC1000 into struct utc. */ return(CvtTPtoUTC( TPdata, TPtime )); } /* *++ * CvtTPtoUTC() * * Functional Description: * * This routine converts the response string of the GC1000 * into a Binary Absolute Time value. * * Inputs: * * The GC1000 date/time string in the format: * "HH:MM:SS.D_____MM/DD/YY" (where '_' is a space) * * Implicit Inputs: * * None. * * Outputs: * * TPtime - The converted utc value. * * Implicit Outputs: * * None. * * Value Returned: * * None. * * Side Effects: * * None. * *-- */ CvtTPtoUTC( TPdata, TPtime ) char *TPdata; struct utc *TPtime; { long tns, ins, dns, dns_inacc; struct tm time, inacc, delta, delta_inacc; struct utc TPdelta; struct utc TPraw; /* * convert all fields in record */ if ( sscanf( TPdata, "%d:%d:%d.%d %d/%d/%d", &time.tm_hour, &time.tm_min, &time.tm_sec, &tns, &time.tm_mon, &time.tm_mday, &time.tm_year ) == EOF ) { (void) fprintf(stderr, "M_GC1000: time/date field conversion failed\n"); return(0); } /* * fix year 2000 wraparound */ if ( time.tm_year < 90 ) time.tm_year += 100; /* * convert tenths of seconds (hundreds of ms) into ns */ tns = tns * 100 * K_NS_PER_MS; /* * Adjust the months to be zero based */ time.tm_mon -= 1; /* * Zero out the unused fields */ time.tm_wday = 0; time.tm_yday = 0; time.tm_isdst = 0; /* * Get the inaccuracy */ inacc.tm_sec = INACCURACY / K_MS_PER_SEC; inacc.tm_min = 0; inacc.tm_hour = 0; inacc.tm_yday = 0; inacc.tm_isdst = 0; ins = (INACCURACY % K_MS_PER_SEC) * K_NS_PER_MS; if (utc_mkgmtime(&TPraw, &time, tns, &inacc, ins)) return(0); /* * Adjust the time for the clock delays: * 1.00 seconds from trigger to response * 0.024 seconds from response to processed ( at 9600 baud ) */ delta.tm_hour = 0; delta.tm_min = 0; delta.tm_sec = 1; delta.tm_wday = 0; delta.tm_mday = 0; delta.tm_mon = 0; delta.tm_year = 0; delta.tm_yday = 0; delta.tm_isdst = 0; dns = 24 * K_NS_PER_MS; delta_inacc.tm_hour = 0; delta_inacc.tm_min = 0; delta_inacc.tm_sec = 0; delta_inacc.tm_wday = 0; delta_inacc.tm_mday = 0; delta_inacc.tm_mon = 0; delta_inacc.tm_year = 0; delta_inacc.tm_yday = 0; delta_inacc.tm_isdst= 0; dns_inacc = 0; if (utc_mkreltime(&TPdelta, &delta, dns, &delta_inacc, dns_inacc)) return(0); if (utc_addtime(TPtime, &TPdelta, &TPraw)) return(0); else return(1); } /* End of routine CvtTPtoUTC */ #endif #ifdef TP_SPEC /* ********************************************************** * Spectracom Specific Routines. ********************************************************** */ /* * Spectracom character conversion macros */ #define CVT_ASCII_TO_INT(chr) ((chr) - '0') #define CVT_ASCII_TO_INT_AND_ADD(chrhi, chrlo) \ ((CVT_ASCII_TO_INT(chrhi) << 6) + CVT_ASCII_TO_INT(chrlo)) /* * Literals */ #define M_SPECTRACOM_CLOCK_RESET (0x1) /* Clock reset */ #define M_SPECTRACOM_YEAR_MISMATCH (0x2) /* Year mismatch */ #define M_SPECTRACOM_AVAIL (0x4) /* Time not available */ #define M_SPECTRACOM_SIGNAL_FAULT (0x8) /* Signal fault */ #define M_SPECTRACOM_HARD_FAULT (0x10) /* Hardware fault */ #define M_SPECTRACOM_OUT_OF_SPEC (0x20) /* Time out of spec */ #define M_SPECTRACOM_PM_TIME (0x8) /* PM indication */ #define M_SPECTRACOM_12_HR (0x10) /* 12 hour mode */ #define SPECTRACOM_NOCLOCKSET (0) /* allow the clock to be affected */ #define SPECTRACOM_POLL_RATE (60) /* sixty seconds between tp polls */ #define SPECTRACOM_TIME_STAMPS (3) /* number of time samples to read */ #define SPECTRACOM_INACCURACY (30) /* 30ms of inaccuracy default */ #define SPECTRACOM_TMORATE (30) /* 30 seconds to respond to TS request */ #define SPECTRACOM_RETRIES (2) /* allow 2 errors per radio read */ #define SPECTRACOM_PROMPT "T" #define SPECTRACOM_RESPONSE_LENGTH (26) /* Length of valid response */ #define SPECTRACOM_TIMEOUT (30) /* Allow 30 seconds for radio * * clock to respond to TS */ #define SPECTRACOM_QIO_TIMEOUT (5) /* Allow 5 secs to respond */ #define SPECTRACOM_RETRY (2) /* Retry twice on error */ #define SPECTRACOM_ISVERBOSE (1) /* generate output */ #define SPECTRACOM_MAXTPERROR (60)/* ignore deltas greater than 60 */ #define SPECTRACOM_FIRSTSYNCH (1) /* synch up the first time thru */ /* *++ * InitializeTPdefaults() * * Functional Description: * * Initialize the default input parameters for the external time * provider. * * * * Inputs: * Implicit Inputs: * * * Outputs: * * pollrate - int to be set to the default poll rate * timestamp- int to be set to the default number of * timestamps to read from the external time provider. * inaccuracy-int to be set to the default inaccuracy for the * external time provider (systematic error). * tmorate -int to be set to the default time-out rate (the * number of seconds the dtss server must wait for * the data response). * clockset - int to be set to true if the system clock should not * be affected by the results of the TP synch, false if * the clock can be modified by the results of the TP * synch. * retries - int to be set to the number of times the program is * allowed to resend a request after the * external time source has returned a failure. * firstsync- boolean, assume that the time returned by the external * clock is correct on the first synchronization * maxtperror-if the difference between the local clock and the * time provider differs by more than maxtperror, the * external clock is assumed faulty. * local clock and the time provider * isverbose -boolean, > 0 indicates that informational messages * will be displayed. * * * * Implicit Outputs: * none. * * Value Returned: * none. * * Side Effects: * none. * *-- */ void InitializeTPdefaults(pollrate,timestamp, inaccuracy,tmorate, clockSet,retries, firstsynch,maxtperror, isverbose) int *pollrate, *timestamp, *inaccuracy, *tmorate, *clockSet, *retries, *firstsynch, *maxtperror, *isverbose; { *pollrate = SPECTRACOM_POLL_RATE; /* seconds */ *timestamp = SPECTRACOM_TIME_STAMPS; /* int, 1-6 */ *inaccuracy= SPECTRACOM_INACCURACY; /* seconds */ *tmorate = SPECTRACOM_TIMEOUT; /* seconds */ *clockSet = SPECTRACOM_NOCLOCKSET; /* int, t/f - 1/0 */ *retries = SPECTRACOM_RETRIES; /* int > 0 */ *firstsynch= SPECTRACOM_FIRSTSYNCH; /* int > 0 */ *maxtperror= SPECTRACOM_MAXTPERROR; /* seconds */ *isverbose = SPECTRACOM_ISVERBOSE; /* int > 0 */ } /* End of routine InitializeTPdefaults */ /* *++ * QueryProvider() * * Functional Description: * * Query the provider for the time. Generate the timestamp triplet. * * Inputs: * * ttchan - channel to read. * * Outputs: * * TPtime - return utc time, the time read from provider * beforeTime - the utc just before the command is sent * afterTime - the utc just after the on time marker arrived. * * Value Returned: * * -1 Unequivocal failure - Radio clock fault * 0 Success * 1 Timeout failure - retry warranted. * *-- */ int QueryProvider(unsigned short ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime) { char TPdata[SPECTRACOM_RESPONSE_LENGTH + 1]; /* Response buffer */ int status; int retSize; IOsb TPIOSB; /* status block for spectracom */ struct {long null; long mask;} term_mask = {0, 0x0000}; /* * now a structure to set the terminator * character for the read. */ /* * Record 'before' timestamp */ (void) utc_gettime(beforeTime); /* * post qiow read to the spectracom with a timeout. This also purges * the input buffer of any residue characters. */ status = SYS$QIOW(0, /* event flag */ ttchan, /* channel number */ IO$_READPROMPT | /* function code */ IO$M_TIMED | IO$M_NOECHO | IO$M_PURGE, &TPIOSB, /* io status block */ 0, /* ast entry */ 0, /* ast parameter */ TPdata, /* buffer for user data */ SPECTRACOM_RESPONSE_LENGTH, /* buffer size of response */ SPECTRACOM_QIO_TIMEOUT, /* P3; secs to timeout */ &term_mask, /* P4: mask specifying terminators */ SPECTRACOM_PROMPT, /* P5; prompt string */ strlen(SPECTRACOM_PROMPT)); /* P6; length of prompt */ /* * Record 'after' timestamp */ (void) utc_gettime(afterTime); if ( !(status & 1) ) { (void) fprintf(stderr, "M_SPEC: QIO Status failure %x\n", status); return ( status ); } if ( !(TPIOSB.status & 1) ) { (void) fprintf(stderr, "M_SPEC: IOSB Status failure %x bytes %d\n", TPIOSB.status, TPIOSB.byteCount); return ( TPIOSB.status ); } /* * check that we got the correct number of bytes. * Otherwise return hard error. */ if (TPIOSB.byteCount != SPECTRACOM_RESPONSE_LENGTH) { (void) fprintf(stderr, "M_SPEC: response length failure %x\n", TPIOSB.byteCount); return(0); } TPdata[SPECTRACOM_RESPONSE_LENGTH] = '\0'; /* * Now parse the radio clock data to determine the actual time. */ return(ParseTime(TPtime, TPdata)); } /* *++ * ParseTime() * * Functional Description: * * Convert the radio clock text data string into a numerical utc. * * Inputs: * * buffer - the radio clock data string. * * Outputs: * * utcTime - utc returned by the parse * * Value Returned: * * 1 - Success * 0 - Failure * *-- */ int ParseTime (utcTime, buffer) struct utc *utcTime; char *buffer; { static char daytab[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; struct tm timetm; struct tm inacc; unsigned long ins = 0; unsigned long tns; char status; int leapyear; int i; /* * Convert and parse status bytes */ status = buffer[2]; if (status == '*') { (void) fprintf(stderr, "dtssprovider: Spectracom manually set, ignoring time\n"); return(0); } if (status == '?') { (void) fprintf(stderr, "dtssprovider: Spectracom has lost signal\n"); return(0); } if (buffer[3] == '$') { (void) fprintf(stderr, "dtssprovider: Spectracom year incorrect in switches\n"); return(0); } /* * Check clock qualtity indicator */ if (buffer[3] == 'A') ins += 9 * K_NS_PER_MS; /* Add additional 9 ms. */ else if (buffer[3] == 'B') ins += 99 * K_NS_PER_MS; /* Add additional 99 ms. */ else if (buffer[3] == 'C') ins += 499 * K_NS_PER_MS; /* Add additional 499 ms. */ else if (buffer[3] == 'D') return(0); /* Clock too far out */ if ((buffer[0] != '\015' || buffer[1] != '\n') || (buffer[13] != ':') || (buffer[16] != ':') || (buffer[19] != '.')) { (void) fprintf(stderr, "dtssprovider: radio clock fault\n"); (void) fprintf(stderr, "time returned - %26s\n", buffer); return(0); } /* * Convert bytes 2 and 3 into year. If the result is before 1990, the * century most have rolled over. */ timetm.tm_year = CVT_ASCII_TO_INT(buffer[4]) * 10 + CVT_ASCII_TO_INT(buffer[5]); if (timetm.tm_year < 90) timetm.tm_year += 100; /* * Convert bytes 5, 6 and 7 into day of year */ timetm.tm_yday = CVT_ASCII_TO_INT(buffer[7]) * 100 + CVT_ASCII_TO_INT(buffer[8]) * 10 + CVT_ASCII_TO_INT(buffer[9]); /* * Convert bytes 9 and 10 into hours */ timetm.tm_hour = CVT_ASCII_TO_INT(buffer[11]) * 10 + CVT_ASCII_TO_INT(buffer[12]); /* * Convert bytes 12 and 13 into minutes */ timetm.tm_min = CVT_ASCII_TO_INT(buffer[14]) * 10 + CVT_ASCII_TO_INT(buffer[15]); /* * Convert bytes 15 and 16 into seconds */ timetm.tm_sec = CVT_ASCII_TO_INT(buffer[17]) * 10 + CVT_ASCII_TO_INT(buffer[18]); /* * Convert bytes 18, 19 and 20 into nanoseconds */ tns = (CVT_ASCII_TO_INT(buffer[20]) * 100 + CVT_ASCII_TO_INT(buffer[21]) * 10 + CVT_ASCII_TO_INT(buffer[22])) * K_NS_PER_MS; /* * Compute month and day of month */ leapyear = ((timetm.tm_year % 4 == 0) && (timetm.tm_year % 100 != 0)) || ((timetm.tm_year + 300) % 400 == 0); timetm.tm_mday = timetm.tm_yday; for (i=1; timetm.tm_mday > daytab[leapyear][i]; i++) timetm.tm_mday -= daytab[leapyear][i]; timetm.tm_mon = i-1; /* * Check values */ if (timetm.tm_sec > 60 || /* Leap seconds */ timetm.tm_min > 59 || timetm.tm_hour > 23 || timetm.tm_yday > 366) { (void) fprintf(stderr, "dtssprovider: radio clock fault\n"); (void) fprintf(stderr, "time returned - %26s\n", buffer); return(0); } /* * Convert the data returned by radio clock into a struct utc. * Call the DTSS API */ (void)memset((void *)&inacc,0,sizeof(struct tm)); inacc.tm_sec = INACCURACY / K_MS_PER_SEC; ins = (INACCURACY % K_MS_PER_SEC) * K_NS_PER_MS; return((utc_mkgmtime(utcTime, &timetm, tns, &inacc, ins)== 0) ? 1 : 0); } #endif #ifdef TP_TRAC /* ********************************************************** * Traconex Specific Routines. * ********************************************************** */ /* * Traconex character conversion macros */ #define CVT_ASCII_TO_INT(chr) ((chr) - '0') #define CVT_ASCII_TO_INT_AND_ADD(chrhi, chrlo) \ ((CVT_ASCII_TO_INT(chrhi) << 6) + CVT_ASCII_TO_INT(chrlo)) /* * Traconex Literals */ #define M_TRACONEX_CLOCK_RESET (0x1) /* Clock reset */ #define M_TRACONEX_YEAR_MISMATCH (0x2) /* Year mismatch */ #define M_TRACONEX_AVAIL (0x4) /* Time not available */ #define M_TRACONEX_SIGNAL_FAULT (0x8) /* Signal fault */ #define M_TRACONEX_HARD_FAULT (0x10) /* Hardware fault */ #define M_TRACONEX_OUT_OF_SPEC (0x20) /* Time out of spec */ #define M_TRACONEX_PM_TIME (0x8) /* PM indication */ #define M_TRACONEX_12_HR (0x10) /* 12 hour mode */ #define TRACONEX_PROMPT "\003QU0000" #define TRACONEX_PROMPT_LENGTH (9) #define TRACONEX_RESPONSE_LENGTH (10) /* Length of valid resp. */ #define TRACONEX_TIMEOUT (45) /* Allow 45 seconds for TPP * * to respond to TS */ #define TRACONEX_RETRY (5) /* Retry 5 times */ #define TRACONEX_QIO_TIMEOUT (30) /* allow 30 secs for radio to resp*/ #define TRACONEX_NOCLOCKSET (0) /* allow the clock to be affected */ #define TRACONEX_POLL_RATE (60) /* sixty seconds between tp polls */ #define TRACONEX_TIME_STAMPS (3) /* number of time samples to read */ #define TRACONEX_INACCURACY (30) /* 30ms of inaccuracy default */ #define TRACONEX_ISVERBOSE (1) /* generate output */ #define TRACONEX_MAXTPERROR (60) /* ignore deltas greater than 60 */ #define TRACONEX_FIRSTSYNCH (1) /* synch up the first time thru */ /* *++ * InitializeTPdefaults() * * Functional Description: * * Initialize the default input parameters for the external time * provider. * * * * Inputs: * None. * * Implicit Inputs: * * * Outputs: * * pollrate - int to be set to the default poll rate * timestamp- int to be set to the default number of * timestamps to read from the external time provider. * inaccuracy-int to be set to the default inaccuracy for the * external time provider (systematic error). * tmorate -int to be set to the default time-out rate (the * number of seconds the dtss server must wait for * the data response). * clockset - int to be set to true if the system clock should not * be affected by the results of the TP synch, false if * the clock can be modified by the results of the TP * synch. * retries - int to be set to the number of times the program is * allowed to resend a request after the * external time source has returned a failure. * firstsync- boolean, assume that the time returned by the external * clock is correct on the first synchronization * maxtperror-if the difference between the local clock and the * time provider differs by more than maxtperror, the * external clock is assumed faulty. * local clock and the time provider * isverbose -boolean, > 0 indicates that informational messages * will be displayed. * * * * Implicit Outputs: * none. * * Value Returned: * none. * * Side Effects: * none. * *-- */ void InitializeTPdefaults(pollrate,timestamp, inaccuracy,tmorate, clockSet,retries, firstsynch,maxtperror, isverbose) int *pollrate, *timestamp, *inaccuracy, *tmorate, *clockSet, *retries, *firstsynch, *maxtperror, *isverbose; { *pollrate = TRACONEX_POLL_RATE; /* seconds */ *timestamp = TRACONEX_TIME_STAMPS; /* int, 1-6 */ *inaccuracy= TRACONEX_INACCURACY; /* seconds */ *tmorate = TRACONEX_TIMEOUT; /* seconds */ *clockSet = TRACONEX_NOCLOCKSET; /* int, t/f - 1/0 */ *retries = TRACONEX_RETRY; /* int > 0 */ *firstsynch= TRACONEX_FIRSTSYNCH; /* int > 0 */ *maxtperror= TRACONEX_MAXTPERROR; /* seconds */ *isverbose = TRACONEX_ISVERBOSE; /* int > 0 */ } /* End of routine InitializeTPdefaults */ /* *++ * QueryProvider() * * Functional Description: * * Query the provider for the time. Generate the timestamp triplet. * * Inputs: * * ttchan - channel to read. * * Outputs: * * TPtime - return utc time, the time read from provider * beforeTime - the utc just before the on time marker arrived * afterTime - the utc just after the on time marker arrived. * * Value Returned: * * -1 Unequivocal failure - Stratum too far from TP. * 0 Success * 1 Timeout failure - retry warented. * *-- */ int QueryProvider(unsigned short ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime) { /* * Posting and reading characters. * See Traconex DIP switches for speed and parity for * data exchange. */ char TPdata[TRACONEX_RESPONSE_LENGTH+1]; /* Response buffer */ static char traconex_prompt_string[TRACONEX_PROMPT_LENGTH] = {0,'0','3','Q','U','0','0','0','0'}; int status; int retSize; IOsb TPIOSB; /* status block for PSTI */ struct {long null; long mask;} term_mask = {0, 0x0000}; /* * now a structure to set the terminator * character for the read. */ /* * Record 'before' timestamp */ (void) utc_gettime(beforeTime); /* * post qiow read to the psti with a timeout. This also purges * the input buffer of any residue characters. */ status = SYS$QIOW(0, /* event flag */ ttchan, /* channel number */ IO$_READPROMPT | /* function code */ IO$M_TIMED | IO$M_NOECHO | IO$M_PURGE, &TPIOSB, /* io status block */ 0, /* ast entry */ 0, /* ast parameter */ TPdata, /* buffer for user data */ TRACONEX_RESPONSE_LENGTH, /* buffer size of response */ TRACONEX_QIO_TIMEOUT, /* P3; secs to timeout */ &term_mask, /* P4: mask specifying terminators */ traconex_prompt_string, /* P5; prompt string */ TRACONEX_PROMPT_LENGTH); /* P6; length of prompt */ /* * Record 'after' timestamp */ (void) utc_gettime(afterTime); if ( !(status & 1) ) { (void) fprintf(stderr, "M_TRAC: QIO Status failure %x\n", status); return ( status ); } if ( !(TPIOSB.status & 1) ) { (void) fprintf(stderr, "M_TRAC: IOSB Status failure %x\n", TPIOSB.status); (void) fprintf(stderr, "M_TRAC: Bytes Read: %d\n",TPIOSB.byteCount); return ( TPIOSB.status ); } /* * check that we got the correct number of bytes. * Otherwise return hard error. */ if (TPIOSB.byteCount != TRACONEX_RESPONSE_LENGTH) { (void) fprintf(stderr, "M_TRAC: response length failure %x\n", TPIOSB.byteCount); return(0); } /* * Now parse the radio clock data to determine the actual time. */ return(ParseTime(TPtime, TPdata)); } /* *++ * ParseTime() * * Functional Description: * * Convert the radio clock text data string into a numerical utc. * * Inputs: * * buffer - the radio clock data string. * * Outputs: * * utcTime - utc returned by the parse * * Value Returned: * * 0 - Buffer, parse was successful * -1 - hard Failure. * 1 - Temporary failure - Retry later. * *-- */ int ParseTime (utcTime, buffer) struct utc *utcTime; char *buffer; { static char daytab[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; struct tm timetm; struct tm inacc; unsigned long ins; unsigned long tns; int status1, status2; int leapyear; int i; /* * Convert and parse status bytes */ status1 = CVT_ASCII_TO_INT(buffer[0]); status2 = CVT_ASCII_TO_INT(buffer[1]); if (status1 & M_TRACONEX_OUT_OF_SPEC) { (void) printf("dtssprovider: Traconex out of spec\n"); return(0); } if (status1 & M_TRACONEX_HARD_FAULT) { (void)printf("dtssprovider: Traconex hardware fault\n"); return(0); } if (status1 & M_TRACONEX_SIGNAL_FAULT) { (void) printf("dtssprovider: Traconex signal fault\n"); return(0); } if (!(status1 & M_TRACONEX_AVAIL)) { (void) printf("dtssprovider: Traconex time not available\n"); return(0); } if (status1 & M_TRACONEX_YEAR_MISMATCH) { (void) printf("dtssprovider: Traconex year mismatch\n"); return(0); } /* * Convert bytes 2 and 3 into ms. */ tns = (CVT_ASCII_TO_INT_AND_ADD(buffer[2], buffer[3])) * K_NS_PER_MS; /* * Convert bytes 4, 5 and 6 into secs, mins and hours */ timetm.tm_sec = CVT_ASCII_TO_INT(buffer[4]); timetm.tm_min = CVT_ASCII_TO_INT(buffer[5]); timetm.tm_hour = CVT_ASCII_TO_INT(buffer[6]); /* * Handle 12/24 hour and Military modes */ if (status2 & M_TRACONEX_12_HR) { if (status2 & M_TRACONEX_PM_TIME) { if (timetm.tm_hour != 12) timetm.tm_hour += 12; } else { if (timetm.tm_hour == 12) timetm.tm_hour = 0; } } /* * Convert bytes 7 and 8 into day of year */ timetm.tm_yday = CVT_ASCII_TO_INT_AND_ADD(buffer[7], buffer[8]); /* * Convert byte 9 (offset from 1986) into year */ timetm.tm_year = CVT_ASCII_TO_INT(buffer[9]) + 1986 - 1900; /* * Compute month and day of month */ leapyear = ((timetm.tm_year % 4 == 0) && (timetm.tm_year % 100 != 0)) || ((timetm.tm_year + 300) % 400 == 0); timetm.tm_mday = timetm.tm_yday; for (i=1; timetm.tm_mday > daytab[leapyear][i]; i++) timetm.tm_mday -= daytab[leapyear][i]; timetm.tm_mon = i-1; /* * Check values */ if (timetm.tm_sec > 60 || /* Leap seconds */ timetm.tm_min > 59 || timetm.tm_hour > 23 || timetm.tm_yday > 366) { (void) fprintf(stderr, "dtssprovider: radio clock fault\n"); (void) fprintf(stderr, "time returned - %d %d:%02d:%02d.%09d\n", timetm.tm_yday, timetm.tm_hour, timetm.tm_min, timetm.tm_sec, tns); } /* * Convert the data returned by radio clock into a struct utc. * Call the DTSS API */ (void)memset((void *)&inacc,0,sizeof(struct tm)); inacc.tm_sec = INACCURACY / K_MS_PER_SEC; ins = (INACCURACY % K_MS_PER_SEC) * K_NS_PER_MS; return((utc_mkgmtime(utcTime, &timetm, tns, &inacc, ins) == 0) ? 1 : 0); } #endif #ifdef TP_HOPF /* ********************************************************** * HOPF Specific Routines. ********************************************************** */ /* * HOPF specific constants */ #define M_HOPF_FLAG_STX 2 /* 'STX' header flag */ /* * HOPF status byte 1 */ #define M_HOPF_TIME_RADIO 0x08 /* bit to test for time availability */ #define M_HOPF_TIME_CLOCK 0x04 /* internal clock mode */ #define M_HOPF_DST_IND 0x02 /* DST indicator */ #define M_HOPF_DST_ANN 0x01 /* DST announcement */ /* * HOPF status byte 2 */ #define M_HOPF_UTC_IND 0x08 /* UTC indicator */ #define M_HOPF_WEEK_DAY 0x07 /* day of week */ #define HOPF_NOCLOCKSET (0) /* allow the clock to be affected */ #define HOPF_POLL_RATE (60) /* sixty seconds between tp polls */ #define HOPF_TIME_STAMPS (3) /* number of time samples to read */ #define HOPF_INACCURACY (30) /* 30ms of inaccuracy default */ #define HOPF_TMORATE (30) /* 30 secs to respond to TS request*/ #define HOPF_PROMPT "g02" /* prompt string for TP time */ #define HOPF_RESPONSE_LENGTH 18 /* max. # of bytes returned by TP */ #define HOPF_RESPONSE_NUMLEN 15 /* min # of numerical bytes required from TP */ #define HOPF_QIO_TIMEOUT1 1 #define HOPF_QIO_TIMEOUT2 2 /* seconds till read QIO times out */ #define HOPF_RETRIES 5 /* allow 5 retries after a TP failure*/ #define HOPF_ISVERBOSE 1 /* generate output */ #define HOPF_MAXTPERROR 60 /* ignore deltas greater than 60 */ #define HOPF_FIRSTSYNCH 1 /* synch up the first time thru */ /* *++ * InitializeTPdefaults() * * Functional Description: * * Initialize the default input parameters for the external time * provider. * * * * Inputs: * Implicit Inputs: * * * Outputs: * * pollrate - int to be set to the default poll rate * timestamp- int to be set to the default number of * timestamps to read from the external time provider. * inaccuracy-int to be set to the default inaccuracy for the * external time provider (systematic error). * tmorate -int to be set to the default time-out rate (the * number of seconds the dtss server must wait for * the data response). * clockset - int to be set to true if the system clock should not * be affected by the results of the TP synch, false if * the clock can be modified by the results of the TP * synch. * retries - int to be set to the number of times the program is * allowed to resend a request after the * external time source has returned a failure. * firstsync- boolean, assume that the time returned by the external * clock is correct on the first synchronization * maxtperror-if the difference between the local clock and the * time provider differs by more than maxtperror, the * external clock is assumed faulty. * local clock and the time provider * isverbose -boolean, > 0 indicates that informational messages * will be displayed. * * * * Implicit Outputs: * none. * * Value Returned: * none. * * Side Effects: * none. * *-- */ void InitializeTPdefaults(pollrate,timestamp, inaccuracy,tmorate, clockSet,retries, firstsynch,maxtperror, isverbose) int *pollrate, *timestamp, *inaccuracy, *tmorate, *clockSet, *retries, *firstsynch, *maxtperror, *isverbose; { *pollrate = HOPF_POLL_RATE; /* seconds */ *timestamp = HOPF_TIME_STAMPS; /* int, 1-6 */ *inaccuracy= HOPF_INACCURACY; /* seconds */ *tmorate = HOPF_TMORATE; /* seconds */ *clockSet = HOPF_NOCLOCKSET; /* int, t/f - 1/0 */ *retries = HOPF_RETRIES; /* int > 0 */ *firstsynch= HOPF_FIRSTSYNCH; /* int > 0 */ *maxtperror= HOPF_MAXTPERROR; /* seconds */ *isverbose = HOPF_ISVERBOSE; /* int > 0 */ } /* End of routine InitializeTPdefaults */ /* *++ * QueryProvider() * * Functional Description: * * This routine issues a single 'g02' command to the HOPF device. * It returns the Binary Absolute Time represented by the HOPF * data returned. * * * Inputs: * * ttchan - The active channel to the HOPF device. * * Implicit Inputs: * * None. * * Outputs: * * TPtime - The Time returned by the HOPF device. * * Implicit Outputs: * * * Value Returned: * * 0 - Failure - The HOPF device failed. * 1 - Success - The HOPF device was contacted. * * Side Effects: * * *-- */ int QueryProvider(unsigned short ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime) { /* * passing binary encoded data. Set terminal char to * eightbit,passall, and pasthru. */ char HOPFdata[HOPF_RESPONSE_LENGTH]; int status; int retSize; int count,i,temp; IOsb hopfIOSB; /* status block for HOPF */ struct {long null; long mask;} term_mask = {0, 0x0008}; /* * now a structure to set the terminator * character 'ETX' for the read. */ /* * First, post a qiow read to the HOPF with a timeout first to purge * the input buffer of any residue characters. */ status = SYS$QIOW(0, /* event flag */ ttchan, /* channel number */ IO$_READVBLK | /* function code */ IO$M_TIMED | IO$M_PURGE, &hopfIOSB, /* io status block */ 0, /* ast entry */ 0, /* ast parameter */ HOPFdata, /* buffer for user data */ HOPF_RESPONSE_LENGTH, /* buffer size of response */ HOPF_QIO_TIMEOUT1, /* P3; secs to timeout */ 0, /* P4: mask specifying terminators */ 0, /* P5; prompt string */ 0); /* P6; length of prompt */ /* * Next, get the internal UTC time first. */ (void) utc_gettime( beforeTime ); /* * Now, post a qiow write to the HOPF to ask for UTC time. */ status = SYS$QIOW(0, /* event flag */ ttchan, /* channel number */ IO$_WRITEVBLK, /* function code */ &hopfIOSB, /* io status block */ 0, /* ast entry */ 0, /* ast parameter */ HOPF_PROMPT, /* buffer for user data */ strlen(HOPF_PROMPT), /* buffer size of response */ 0, /* P3; secs to timeout */ 0, /* P4: mask specifying terminators */ 0, /* P5; prompt string */ 0); /* P6; length of prompt */ /* * Now, post a qiow read to the HOPF with a timeout and a special * terminator of "ETX". */ status = SYS$QIOW(0, /* event flag */ ttchan, /* channel number */ IO$_READVBLK | /* function code */ IO$M_TIMED, &hopfIOSB, /* io status block */ 0, /* ast entry */ 0, /* ast parameter */ HOPFdata, /* buffer for user data */ HOPF_RESPONSE_LENGTH, /* buffer size of response */ HOPF_QIO_TIMEOUT2, /* P3; secs to timeout */ &term_mask, /* P4: mask specifying terminators */ 0, /* P5; prompt string */ 0); /* P6; length of prompt */ /* * Now get the internal UTC time last. */ (void) utc_gettime( afterTime ); /* * Now do the various checks to ensure that we have a valid UTC time * string from the HOPF receiver. */ if ( !(status & 1) ) { (void) fprintf(stderr, "M_HOPF: QIO Status failure %x\n", status); return ( status ); } if ( !(hopfIOSB.status & 1) ) { (void) fprintf(stderr, "M_HOPF: IOSB Status failure %x\n", hopfIOSB.status); return ( hopfIOSB.status ); } /* * First check for 'STX' */ if ( HOPFdata[0] != M_HOPF_FLAG_STX ) { (void) fprintf(stderr, "M_HOPF: Missing STX %s\n", HOPFdata[0]); return ( 0 ); } /* * Now search for the 'LF' which terminates the numerical string. */ for (i=0; i< hopfIOSB.byteCount;i++) { if (HOPFdata[i] == '\n' ) count = i ; } /* * Check the position of 'LF' to ensure that we got the correct * number of bytes. */ if (count != HOPF_RESPONSE_NUMLEN) { (void) fprintf(stderr, "M_HOPF: string length failure %x\n", count); return(0); } /* * Now convert status bytes for various checks. */ temp = (HOPFdata[1] - '0' ); if ( HOPFdata[1] > '9' ) { temp = (HOPFdata[1] - 'A' ) + 10; } HOPFdata[1] = temp ; temp = (HOPFdata[2] - '0' ); if ( HOPFdata[2] > '9' ) { temp = (HOPFdata[2] - 'A' ) + 10; } HOPFdata[2] = temp ; /* * Check that we got the correct number of bytes. * Otherwise return hard error. */ if (hopfIOSB.byteCount < HOPF_RESPONSE_NUMLEN) { (void) fprintf(stderr, "M_HOPF: response length failure %x\n", hopfIOSB.byteCount); return(0); } /* * Check all the status bits, make sure this time is truely valid. */ /* * First check, if receiver gets radio datagram. */ if ( !(HOPFdata[1] & M_HOPF_TIME_RADIO) ) { (void) fprintf(stderr, "M_HOPF: radio time not Available %x\n", HOPFdata[1]); return(0); } /* * Now check, if internal clock is running. */ if ( !(HOPFdata[1] & M_HOPF_TIME_CLOCK) ) { (void) fprintf(stderr, "M_HOPF: no internal clock time %x\n", HOPFdata[1]); return(0); } /* * Now check, if we got UTC time. */ if ( !(HOPFdata[2] & M_HOPF_UTC_IND) ) { (void) fprintf(stderr, "M_HOPF: no UTC time %x\n", HOPFdata[2]); return(0); } /* * Now convert the data to integers. */ for ( i=3;i 0 indicates that informational messages * will be displayed. * * * Implicit Outputs: * none. * * Value Returned: * none. * * Side Effects: * none. * *-- */ void InitializeTPdefaults(pollrate,timestamp, inaccuracy,tmorate, clockSet,retries, firstsynch,maxtperror, isverbose) int *pollrate, *timestamp, *inaccuracy, *tmorate, *clockSet, *retries, *firstsynch, *maxtperror, *isverbose; { *pollrate = NULL_POLL_RATE; /* seconds */ *timestamp = NULL_TIME_STAMPS; /* int, 1-6 */ *inaccuracy= NULL_INACCURACY; /* milliseconds */ *tmorate = NULL_TMORATE; /* seconds */ *clockSet = NULL_NOCLOCKSET; /* int, t/f - 1/0 */ *retries = NULL_RETRIES; /* int > 0 */ *firstsynch= NULL_FIRSTSYNCH; /* int > 0 */ *maxtperror= NULL_MAXTPERROR; /* seconds */ *isverbose = NULL_ISVERBOSE; /* int > 0 */ } /* End of routine InitializeTPdefaults */ /* *++ * QueryProvider() * * Functional Description: * * Return the inaccuracy only. * * * Inputs: * * ttchan - The active channel to the HOPF device. * * Implicit Inputs: * * None. * * Outputs: * * TPtime - The Time returned by the HOPF device. * * Implicit Outputs: * * * Value Returned: * * 0 - Failure - The HOPF device failed. * 1 - Success - The HOPF device was contacted. * * Side Effects: * * *-- */ int QueryProvider(unsigned short ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime) { long ins,inst,tns; struct tm inacc,inacctm,timetm; /* * Depending upon the clock implementation, the time and/or the * inaccuracy could also be read from the time device using RS232 * for example. In that case, the radio time provider examples may * provide useful examples. * In the following example, the inaccuracy as defined by the * user inaccuracy value is converted and returned to the time * server. Since the noclockset bit was set to one in the * initialization routine, the actual time is ignored, but * the system inaccuracy is nonmonotonically set by * the server to the value returned in the inacc tm struct. */ /* * Get the inaccuracy into a tm struct */ inacc.tm_sec = INACCURACY / K_MS_PER_SEC; inacc.tm_min = 0; inacc.tm_hour = 0; inacc.tm_yday = 0; inacc.tm_isdst = 0; ins = (INACCURACY % K_MS_PER_SEC) * K_NS_PER_MS; (void)utc_gettime(beforeTime); (void)utc_localtime(NULL,&timetm,&tns,&inacctm,&inst); (void)utc_mklocaltime(TPtime,&timetm,0,&inacc,ins); (void)utc_gettime(afterTime); } #endif /* TP_NULL */ /* ********************************************************** * output Routines. ********************************************************** */ /* *++ * PrintTimes() * * Functional Description: * * Print the Result of a synchronization. * * * Inputs: * * before,after,tptimes - time values used in the synch. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * None. * * Side Effects: * * None. *-- */ PrintTimes( timeResponse ) TPrspMsg *timeResponse; { int i; char timestr[UTC_MAX_STR_LEN]; if ( timeResponse->status == K_TPI_FAILURE ) { (void) fprintf(stdout, "K_TPI_FAILURE\n"); (void) fprintf(stdout, "********************* %u *********************\n", SYNCHCOUNT); return; } (void) printf("TPsuccessful\n"); (void) printf("Serial Number : %d\n", timeResponse->TPsyncID); (void) printf("Time Stamps : %d\n", timeResponse->TPdata.TimeMsg.timeStampCount); for ( i = 0; i < timeResponse->TPdata.TimeMsg.timeStampCount; i++) { (void) printf("Before Time\t:"); utc_ascgmtime(timestr,UTC_MAX_STR_LEN, &timeResponse->TPdata.TimeMsg.timeStampList[i].beforeTime); (void) printf("%s\nTP Time\t\t:",timestr); utc_ascgmtime(timestr,UTC_MAX_STR_LEN, &timeResponse->TPdata.TimeMsg.timeStampList[i].TPtime); (void) printf("%s\nAfter Time\t:",timestr); utc_ascgmtime(timestr,UTC_MAX_STR_LEN, &timeResponse->TPdata.TimeMsg.timeStampList[i].afterTime); (void) printf("%s\n",timestr); } (void)printf("******************************************\n"); } /* *++ * PrintValidationError() * * Functional Description: * * The timeprovider is returning invalid times, report * to the user. * * Inputs: * * None. * * Implicit Inputs: * * SYNCHCOUNT,MAXTPERROR. * * Outputs: * * None. * * Implicit Outputs: * * * Value Returned: * * None. * * Side Effects: * * None. * *-- */ PrintValidationError(systemTime,externalTime) struct utc *systemTime; struct utc *externalTime; { char timestr[UTC_MAX_STR_LEN]; fprintf(stderr,"\n!!!!!!!!! DTSS: EXTERNAL TIME SOURCE IS FAULTY !!!!!!!!!\n"); fprintf(stderr,"The external time did not validate\n"); fprintf(stderr,"Synchronization Count: %u\n",SYNCHCOUNT); fprintf(stderr,"Error Tolerance: %u\n",MAXTPERROR); utc_ascgmtime(timestr,UTC_MAX_STR_LEN,systemTime); fprintf(stderr,"System Time: %s\n",timestr); utc_ascgmtime(timestr,UTC_MAX_STR_LEN,externalTime); fprintf(stderr,"External Device Time: %s\n",timestr); fprintf(stderr,"\n!!!!!!!!!!!!!!!!!!\n"); } #pragma standard