2 * refclock_jjy - clock driver for JJY receivers
5 /**********************************************************************/
7 /* Copyright (C) 2001-2015, Takao Abe. All rights reserved. */
9 /* Permission to use, copy, modify, and distribute this software */
10 /* and its documentation for any purpose is hereby granted */
11 /* without fee, provided that the following conditions are met: */
13 /* One retains the entire copyright notice properly, and both the */
14 /* copyright notice and this license. in the documentation and/or */
15 /* other materials provided with the distribution. */
17 /* This software and the name of the author must not be used to */
18 /* endorse or promote products derived from this software without */
19 /* prior written permission. */
21 /* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */
22 /* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */
23 /* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */
24 /* PARTICULAR PURPOSE. */
25 /* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */
26 /* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
27 /* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
28 /* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */
29 /* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */
30 /* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */
31 /* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */
32 /* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
34 /* This driver is developed in my private time, and is opened as */
35 /* voluntary contributions for the NTP. */
36 /* The manufacturer of the JJY receiver has not participated in */
37 /* a development of this driver. */
38 /* The manufacturer does not warrant anything about this driver, */
39 /* and is not liable for anything about this driver. */
41 /**********************************************************************/
43 /* Author Takao Abe */
44 /* Email takao_abe@xurb.jp */
45 /* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */
47 /* The email address abetakao@bea.hi-ho.ne.jp is never read */
48 /* from 2010, because a few filtering rule are provided by the */
49 /* "hi-ho.ne.jp", and lots of spam mail are reached. */
50 /* New email address for supporting the refclock_jjy is */
51 /* takao_abe@xurb.jp */
53 /**********************************************************************/
58 /* [New] Support the Tristate Ltd. JJY receiver */
61 /* [Change] Log to clockstats even if bad reply */
62 /* [Fix] PRECISION = (-3) (about 100 ms) */
63 /* [Add] Support the C-DEX Co.Ltd. JJY receiver */
66 /* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */
69 /* [Fix] Portability for FreeBSD ( patched by the user ) */
72 /* [Change] Command send timing for the Tristate Ltd. JJY receiver */
73 /* JJY-01 ( Firmware version 2.01 ) */
74 /* Thanks to Andy Taki for testing under FreeBSD */
77 /* [Add] Support the Echo Keisokuki LT-2000 receiver */
80 /* [Fix] C-DEX JST2000 */
81 /* Thanks to Hideo Kuramatsu for the patch */
84 /* [Add] Support the CITIZEN T.I.C JJY-200 receiver */
87 /* [Change] Bug 1618 ( Harmless ) */
88 /* Code clean up ( Remove unreachable codes ) in */
90 /* [Change] Change clockstats format of the Tristate JJY01/02 */
91 /* Issues more command to get the status of the receiver */
92 /* when "fudge 127.127.40.X flag1 1" is specified */
93 /* ( DATE,STIM -> DCST,STUS,DATE,STIM ) */
96 /* [Add] Support the Tristate Ltd. TS-GPSclock-01 */
99 /* [Add] Support the Telephone JJY */
100 /* [Change] Split the start up routine into each JJY receivers. */
101 /* Change raw data internal bufferring process */
102 /* Change over midnight handling of TS-JJY01 and TS-GPS01 */
103 /* to put DATE command between before and after TIME's. */
104 /* Unify the writing clockstats of all JJY receivers. */
107 /* [Add] Support the SEIKO TIME SYSTEMS TDC-300 */
109 /**********************************************************************/
115 #if defined(REFCLOCK) && defined(CLOCK_JJY)
120 #include <sys/time.h>
126 #include "ntp_refclock.h"
127 #include "ntp_calendar.h"
128 #include "ntp_stdlib.h"
130 /**********************************************************************/
133 * Interface definitions
135 #define DEVICE "/dev/jjy%d" /* device name and unit */
136 #define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
137 #define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
138 #define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
139 #define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
140 #define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */
141 #define SPEED232_SEIKO_TIMESYS_TDC_300 B2400 /* UART speed (2400 baud) */
142 #define SPEED232_TELEPHONE B2400 /* UART speed (4800 baud) */
143 #define REFID "JJY" /* reference ID */
144 #define DESCRIPTION "JJY Receiver"
145 #define PRECISION (-3) /* precision assumed (about 100 ms) */
148 * JJY unit control structure
151 struct jjyRawDataBreak {
152 const char * pString ;
156 #define MAX_TIMESTAMP 6
157 #define MAX_RAWBUF 100
158 #define MAX_LOOPBACK 5
161 /* Set up by the function "jjy_start_xxxxxxxx" */
162 char unittype ; /* UNITTYPE_XXXXXXXXXX */
163 short operationmode ; /* Echo Keisokuki LT-2000 */
164 int linespeed ; /* SPEED232_XXXXXXXXXX */
165 short linediscipline ; /* LDISC_CLK or LDISC_RAW */
167 char bInitError ; /* Set by jjy_start if any error during initialization */
168 short iProcessState ; /* JJY_PROCESS_STATE_XXXXXX */
169 char bReceiveFlag ; /* Set and reset by jjy_receive */
170 char bLineError ; /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/
171 short iCommandSeq ; /* 0:Idle Non-Zero:Issued */
174 int year, month, day, hour, minute, second, msecond ;
176 int iTimestampCount ; /* TS-JJY01, TS-GPS01, Telephone-JJY */
177 int iTimestamp [ MAX_TIMESTAMP ] ; /* Serial second ( 0 - 86399 ) */
179 char sRawBuf [ MAX_RAWBUF ] ;
181 struct jjyRawDataBreak *pRawBreak ;
182 char bWaitBreakString ;
183 char sLineBuf [ MAX_RAWBUF ] ;
185 char sTextBuf [ MAX_RAWBUF ] ;
187 char bSkipCntrlCharOnly ;
188 /* Telephone JJY auto measurement of the loopback delay */
190 short iLoopbackCount ;
191 struct timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ;
192 char bLoopbackTimeout[MAX_LOOPBACK] ;
193 short iLoopbackValidCount ;
194 /* Telephone JJY timer */
195 short iTeljjySilentTimer ;
196 short iTeljjyStateTimer ;
197 /* Telephone JJY control finite state machine */
200 short iClockCommandSeq ;
202 short iModemSilentCount ;
203 short iModemSilentTimer ;
204 short iModemStateTimer ;
205 /* Modem control finite state machine */
208 short iModemCommandSeq ;
211 #define UNITTYPE_TRISTATE_JJY01 1
212 #define UNITTYPE_CDEX_JST2000 2
213 #define UNITTYPE_ECHOKEISOKUKI_LT2000 3
214 #define UNITTYPE_CITIZENTIC_JJY200 4
215 #define UNITTYPE_TRISTATE_GPSCLOCK01 5
216 #define UNITTYPE_SEIKO_TIMESYS_TDC_300 6
217 #define UNITTYPE_TELEPHONE 100
219 #define JJY_PROCESS_STATE_IDLE 0
220 #define JJY_PROCESS_STATE_POLL 1
221 #define JJY_PROCESS_STATE_RECEIVE 2
222 #define JJY_PROCESS_STATE_DONE 3
223 #define JJY_PROCESS_STATE_ERROR 4
225 /**********************************************************************/
228 * Function calling structure
231 * |-- jjy_start_tristate_jjy01
232 * |-- jjy_start_cdex_jst2000
233 * |-- jjy_start_echokeisokuki_lt2000
234 * |-- jjy_start_citizentic_jjy200
235 * |-- jjy_start_tristate_gpsclock01
236 * |-- jjy_start_seiko_tsys_tdc_300
237 * |-- jjy_start_telephone
242 * |-- jjy_poll_tristate_jjy01
243 * |-- jjy_poll_cdex_jst2000
244 * |-- jjy_poll_echokeisokuki_lt2000
245 * |-- jjy_poll_citizentic_jjy200
246 * |-- jjy_poll_tristate_gpsclock01
247 * |-- jjy_poll_seiko_tsys_tdc_300
248 * |-- jjy_poll_telephone
250 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
253 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
257 * |-- jjy_receive_tristate_jjy01
259 * |-- jjy_receive_cdex_jst2000
261 * |-- jjy_receive_echokeisokuki_lt2000
263 * |-- jjy_receive_citizentic_jjy200
265 * |-- jjy_receive_tristate_gpsclock01
267 * |-- jjy_receive_seiko_tsys_tdc_300
269 * |-- jjy_receive_telephone
271 * | |-- modem_control
272 * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
274 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
276 * |-- modem_disconnect
278 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
281 * |-- jjy_timer_telephone
283 * | |-- modem_control
284 * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
286 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
287 * |-- modem_disconnect
289 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
291 * Function prototypes
294 static int jjy_start (int, struct peer *);
295 static int jjy_start_tristate_jjy01 (int, struct peer *, struct jjyunit *);
296 static int jjy_start_cdex_jst2000 (int, struct peer *, struct jjyunit *);
297 static int jjy_start_echokeisokuki_lt2000 (int, struct peer *, struct jjyunit *);
298 static int jjy_start_citizentic_jjy200 (int, struct peer *, struct jjyunit *);
299 static int jjy_start_tristate_gpsclock01 (int, struct peer *, struct jjyunit *);
300 static int jjy_start_seiko_tsys_tdc_300 (int, struct peer *, struct jjyunit *);
301 static int jjy_start_telephone (int, struct peer *, struct jjyunit *);
303 static void jjy_shutdown (int, struct peer *);
305 static void jjy_poll (int, struct peer *);
306 static void jjy_poll_tristate_jjy01 (int, struct peer *);
307 static void jjy_poll_cdex_jst2000 (int, struct peer *);
308 static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *);
309 static void jjy_poll_citizentic_jjy200 (int, struct peer *);
310 static void jjy_poll_tristate_gpsclock01 (int, struct peer *);
311 static void jjy_poll_seiko_tsys_tdc_300 (int, struct peer *);
312 static void jjy_poll_telephone (int, struct peer *);
314 static void jjy_receive (struct recvbuf *);
315 static int jjy_receive_tristate_jjy01 (struct recvbuf *);
316 static int jjy_receive_cdex_jst2000 (struct recvbuf *);
317 static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
318 static int jjy_receive_citizentic_jjy200 (struct recvbuf *);
319 static int jjy_receive_tristate_gpsclock01 (struct recvbuf *);
320 static int jjy_receive_seiko_tsys_tdc_300 (struct recvbuf *);
321 static int jjy_receive_telephone (struct recvbuf *);
323 static void jjy_timer (int, struct peer *);
324 static void jjy_timer_telephone (int, struct peer *);
326 static void jjy_synctime ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
327 static void jjy_write_clockstats ( struct peer *, int, const char* ) ;
329 static int getRawDataBreakPosition ( struct jjyunit *, int ) ;
331 static short getModemState ( struct jjyunit * ) ;
332 static int isModemStateConnect ( short ) ;
333 static int isModemStateDisconnect ( short ) ;
334 static int isModemStateTimerOn ( struct jjyunit * ) ;
335 static void modem_connect ( int, struct peer * ) ;
336 static void modem_disconnect ( int, struct peer * ) ;
337 static int modem_receive ( struct recvbuf * ) ;
338 static void modem_timer ( int, struct peer * );
340 static void printableString ( char*, int, const char*, int ) ;
345 struct refclock refclock_jjy = {
346 jjy_start, /* start up driver */
347 jjy_shutdown, /* shutdown driver */
348 jjy_poll, /* transmit poll message */
349 noentry, /* not used */
350 noentry, /* not used */
351 noentry, /* not used */
352 jjy_timer /* 1 second interval timer */
356 * Start up driver return code
358 #define RC_START_SUCCESS 1
359 #define RC_START_ERROR 0
362 * Local constants definition
365 #define MAX_LOGTEXT 100
371 #define FALSE (!TRUE)
374 /* Local constants definition for the return code of the jjy_receive_xxxxxxxx */
376 #define JJY_RECEIVE_DONE 0
377 #define JJY_RECEIVE_SKIP 1
378 #define JJY_RECEIVE_UNPROCESS 2
379 #define JJY_RECEIVE_WAIT 3
380 #define JJY_RECEIVE_ERROR 4
382 /* Local constants definition for the 2nd parameter of the jjy_write_clockstats */
384 #define JJY_CLOCKSTATS_MARK_NONE 0
385 #define JJY_CLOCKSTATS_MARK_JJY 1
386 #define JJY_CLOCKSTATS_MARK_SEND 2
387 #define JJY_CLOCKSTATS_MARK_RECEIVE 3
388 #define JJY_CLOCKSTATS_MARK_INFORMATION 4
389 #define JJY_CLOCKSTATS_MARK_ATTENTION 5
390 #define JJY_CLOCKSTATS_MARK_WARNING 6
391 #define JJY_CLOCKSTATS_MARK_ERROR 7
393 /* Local constants definition for the clockstats messages */
395 #define JJY_CLOCKSTATS_MESSAGE_ECHOBACK "* Echoback"
396 #define JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY "* Ignore replay : [%s]"
397 #define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2 "* Over midnight : timestamp=%d, %d"
398 #define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3 "* Over midnight : timestamp=%d, %d, %d"
399 #define JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE "* Unsure timestamp : %s"
400 #define JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY "* Loopback delay : %d.%03d mSec."
401 #define JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST "* Delay adjustment : %d mSec. ( valid=%hd/%d )"
402 #define JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST "* Delay adjustment : None ( valid=%hd/%d )"
404 #define JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY "# Unexpected reply : [%s]"
405 #define JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH "# Invalid length : length=%d"
406 #define JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY "# Too many reply : count=%d"
407 #define JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY "# Invalid reply : [%s]"
408 #define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2 "# Slow reply : timestamp=%d, %d"
409 #define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3 "# Slow reply : timestamp=%d, %d, %d"
410 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE "# Invalid date : rc=%d year=%d month=%d day=%d"
411 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME "# Invalid time : rc=%d hour=%d minute=%d second=%d"
412 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME "# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d"
413 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP "# Invalid leap : leapsecond=[%s]"
414 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS "# Invalid status : status=[%s]"
416 /* Debug print macro */
419 #define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen) { if ( debug ) { printf ( "refclock_jjy.c : %s : iProcessState=%d bLineError=%d iCommandSeq=%d iLineCount=%d iTimestampCount=%d iLen=%d\n", sFunc, up->iProcessState, up->bLineError, up->iCommandSeq, up->iLineCount, up->iTimestampCount, iLen ) ; } }
421 #define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)
424 /**************************************************************************************************/
425 /* jjy_start - open the devices and initialize data for processing */
426 /**************************************************************************************************/
428 jjy_start ( int unit, struct peer *peer )
431 struct refclockproc *pp ;
435 char sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ;
439 printf( "refclock_jjy.c : jjy_start : %s mode=%d dev=%s unit=%d\n",
440 ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ;
444 /* Allocate memory for the unit structure */
445 up = emalloc( sizeof(*up) ) ;
447 msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ;
448 return RC_START_ERROR ;
450 memset ( up, 0, sizeof(*up) ) ;
452 up->bInitError = FALSE ;
453 up->iProcessState = JJY_PROCESS_STATE_IDLE ;
454 up->bReceiveFlag = FALSE ;
455 up->iCommandSeq = 0 ;
457 up->iTimestampCount = 0 ;
458 up->bWaitBreakString = FALSE ;
459 up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ;
460 up->bSkipCntrlCharOnly = TRUE ;
462 /* Set up the device name */
463 snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ;
465 snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ;
466 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
469 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
471 switch ( peer->ttl ) {
474 rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ;
477 rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ;
480 rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ;
483 rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ;
486 rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ;
489 rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ;
492 rc = jjy_start_telephone ( unit, peer, up ) ;
495 if ( 101 <= peer->ttl && peer->ttl <= 180 ) {
496 rc = jjy_start_telephone ( unit, peer, up ) ;
498 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
499 ntoa(&peer->srcadr), peer->ttl ) ;
500 free ( (void*) up ) ;
501 return RC_START_ERROR ;
506 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error",
507 ntoa(&peer->srcadr), peer->ttl ) ;
508 free ( (void*) up ) ;
509 return RC_START_ERROR ;
512 /* Open the device */
513 fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ;
515 free ( (void*) up ) ;
516 return RC_START_ERROR ;
520 * Initialize variables
524 pp->clockdesc = DESCRIPTION ;
526 pp->io.clock_recv = jjy_receive ;
527 pp->io.srcclock = peer ;
530 if ( ! io_addclock(&pp->io) ) {
535 return RC_START_ERROR ;
537 memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ;
539 peer->precision = PRECISION ;
541 snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ;
542 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
544 return RC_START_SUCCESS ;
548 /**************************************************************************************************/
549 /* jjy_shutdown - shutdown the clock */
550 /**************************************************************************************************/
552 jjy_shutdown ( int unit, struct peer *peer )
556 struct refclockproc *pp;
562 if ( -1 != pp->io.fd ) {
563 io_closeclock ( &pp->io ) ;
569 snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ;
570 record_clock_stats( &peer->srcadr, sLog ) ;
574 /**************************************************************************************************/
575 /* jjy_receive - receive data from the serial interface */
576 /**************************************************************************************************/
578 jjy_receive ( struct recvbuf *rbufp )
581 static const char *sFunctionName = "jjy_receive" ;
585 struct refclockproc *pp ;
588 l_fp tRecvTimestamp; /* arrival timestamp */
590 char *pBuf, sLogText [ MAX_LOGTEXT ] ;
592 int i, j, iReadRawBuf, iBreakPosition ;
595 * Initialize pointers and read the timecode and timestamp
597 peer = rbufp->recv_peer ;
602 * Get next input line
604 if ( up->linediscipline == LDISC_RAW ) {
606 pp->lencode = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ;
607 /* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions (OVERRUN)" */
608 /* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */
609 /* To avoid its claim, pass the value BMAX-1. */
612 * Append received charaters to temporary buffer
615 i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ;
616 i ++ , up->iRawBufLen ++ ) {
617 up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ;
619 up->sRawBuf[up->iRawBufLen] = 0 ;
624 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
628 printf( "\nrefclock_jjy.c : %s : Len=%d ", sFunctionName, pp->lencode ) ;
629 for ( i = 0 ; i < pp->lencode ; i ++ ) {
630 if ( iscntrl( (u_char)(pp->a_lastcode[i] & 0x7F) ) ) {
631 printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ;
633 printf( "%c", pp->a_lastcode[i] ) ;
640 * The reply with <CR><LF> gives a blank line
643 if ( pp->lencode == 0 ) return ;
646 * Receiving data is not expected
649 if ( up->iProcessState == JJY_PROCESS_STATE_IDLE
650 || up->iProcessState == JJY_PROCESS_STATE_DONE
651 || up->iProcessState == JJY_PROCESS_STATE_ERROR ) {
652 /* Discard received data */
656 printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ;
663 * We get down to business
666 pp->lastrec = tRecvTimestamp ;
670 up->iProcessState = JJY_PROCESS_STATE_RECEIVE ;
671 up->bReceiveFlag = TRUE ;
674 iBreakPosition = up->iRawBufLen - 1 ;
675 for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) {
677 if ( up->linediscipline == LDISC_RAW ) {
679 if ( up->bWaitBreakString ) {
680 iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ;
681 if ( iBreakPosition == -1 ) {
682 /* Break string have not come yet */
683 if ( up->iRawBufLen < MAX_RAWBUF - 2
684 || iReadRawBuf > 0 ) {
685 /* Temporary buffer is not full */
688 /* Temporary buffer is full */
689 iBreakPosition = up->iRawBufLen - 1 ;
693 iBreakPosition = up->iRawBufLen - 1 ;
696 /* Copy charaters from temporary buffer to process buffer */
697 up->iLineBufLen = up->iTextBufLen = 0 ;
698 for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) {
700 /* Copy all characters */
701 up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ;
704 /* Copy printable characters */
705 if ( ! iscntrl( (u_char)up->sRawBuf[i] ) ) {
706 up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ;
711 up->sLineBuf[up->iLineBufLen] = 0 ;
712 up->sTextBuf[up->iTextBufLen] = 0 ;
714 printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n",
715 sFunctionName, up->iLineBufLen, up->iTextBufLen ) ;
718 if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) {
720 printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n",
721 sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ;
723 if ( iBreakPosition + 1 < up->iRawBufLen ) {
724 iReadRawBuf = iBreakPosition + 1 ;
734 if ( up->linediscipline == LDISC_RAW ) {
735 pBuf = up->sLineBuf ;
736 iLen = up->iLineBufLen ;
738 pBuf = pp->a_lastcode ;
742 iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ;
743 strncpy( sLogText, pBuf, iCopyLen ) ;
744 sLogText[iCopyLen] = 0 ;
745 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ;
747 switch ( up->unittype ) {
749 case UNITTYPE_TRISTATE_JJY01 :
750 rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
753 case UNITTYPE_CDEX_JST2000 :
754 rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
757 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
758 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
761 case UNITTYPE_CITIZENTIC_JJY200 :
762 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
765 case UNITTYPE_TRISTATE_GPSCLOCK01 :
766 rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
769 case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
770 rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ;
773 case UNITTYPE_TELEPHONE :
774 rc = jjy_receive_telephone ( rbufp ) ;
778 rc = JJY_RECEIVE_ERROR ;
784 case JJY_RECEIVE_DONE :
785 case JJY_RECEIVE_SKIP :
786 up->iProcessState = JJY_PROCESS_STATE_DONE ;
788 case JJY_RECEIVE_ERROR :
789 up->iProcessState = JJY_PROCESS_STATE_ERROR ;
795 if ( up->linediscipline == LDISC_RAW ) {
796 if ( rc == JJY_RECEIVE_UNPROCESS ) {
799 iReadRawBuf = iBreakPosition + 1 ;
800 if ( iReadRawBuf >= up->iRawBufLen ) {
801 /* Processed all received data */
806 if ( up->linediscipline == LDISC_CLK ) {
812 if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) {
813 for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) {
814 up->sRawBuf[i] = up->sRawBuf[j] ;
816 up->iRawBufLen -= iReadRawBuf ;
817 if ( up->iRawBufLen < 0 ) {
822 up->bReceiveFlag = FALSE ;
826 /**************************************************************************************************/
829 getRawDataBreakPosition ( struct jjyunit *up, int iStart )
834 if ( iStart >= up->iRawBufLen ) {
836 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
841 for ( i = iStart ; i < up->iRawBufLen ; i ++ ) {
843 for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) {
845 if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) {
847 if ( strncmp( up->sRawBuf + i,
848 up->pRawBreak[j].pString,
849 up->pRawBreak[j].iLength ) == 0 ) {
852 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n",
853 iStart, i + up->pRawBreak[j].iLength - 1 ) ;
855 return i + up->pRawBreak[j].iLength - 1 ;
863 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
869 /**************************************************************************************************/
870 /* jjy_poll - called by the transmit procedure */
871 /**************************************************************************************************/
873 jjy_poll ( int unit, struct peer *peer )
876 char sLog [ 40 ], sReach [ 9 ] ;
879 struct refclockproc *pp;
884 if ( up->bInitError ) {
885 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ;
889 if ( pp->polls > 0 && up->iLineCount == 0 ) {
891 * No reply for last command
893 refclock_report ( peer, CEVNT_TIMEOUT ) ;
898 sReach[0] = peer->reach & 0x80 ? '1' : '0' ;
899 sReach[1] = peer->reach & 0x40 ? '1' : '0' ;
900 sReach[2] = peer->reach & 0x20 ? '1' : '0' ;
901 sReach[3] = peer->reach & 0x10 ? '1' : '0' ;
902 sReach[4] = peer->reach & 0x08 ? '1' : '0' ;
903 sReach[5] = peer->reach & 0x04 ? '1' : '0' ;
904 sReach[6] = peer->reach & 0x02 ? '1' : '0' ;
905 sReach[7] = 0 ; /* This poll */
908 snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ;
909 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
911 up->iProcessState = JJY_PROCESS_STATE_POLL ;
912 up->iCommandSeq = 0 ;
913 up->iReceiveSeq = 0 ;
915 up->bLineError = FALSE ;
918 switch ( up->unittype ) {
920 case UNITTYPE_TRISTATE_JJY01 :
921 jjy_poll_tristate_jjy01 ( unit, peer ) ;
924 case UNITTYPE_CDEX_JST2000 :
925 jjy_poll_cdex_jst2000 ( unit, peer ) ;
928 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
929 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
932 case UNITTYPE_CITIZENTIC_JJY200 :
933 jjy_poll_citizentic_jjy200 ( unit, peer ) ;
936 case UNITTYPE_TRISTATE_GPSCLOCK01 :
937 jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
940 case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
941 jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ;
944 case UNITTYPE_TELEPHONE :
945 jjy_poll_telephone ( unit, peer ) ;
955 /**************************************************************************************************/
956 /* jjy_timer - called at one-second intervals */
957 /**************************************************************************************************/
959 jjy_timer ( int unit, struct peer *peer )
962 struct refclockproc *pp ;
967 printf ( "refclock_jjy.c : jjy_timer\n" ) ;
974 if ( up->bReceiveFlag ) {
977 printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ;
983 switch ( up->unittype ) {
985 case UNITTYPE_TELEPHONE :
986 jjy_timer_telephone ( unit, peer ) ;
996 /**************************************************************************************************/
998 /**************************************************************************************************/
1000 jjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
1003 char sLog [ 80 ], cStatus ;
1004 const char *pStatus ;
1006 pp->year = up->year ;
1007 pp->day = ymd2yd( up->year, up->month, up->day ) ;
1008 pp->hour = up->hour ;
1009 pp->minute = up->minute ;
1010 pp->second = up->second ;
1011 pp->nsec = up->msecond * 1000000 ;
1017 if ( pp->hour < 0 ) {
1020 if ( pp->day < 1 ) {
1022 pp->day = ymd2yd( pp->year, 12, 31 ) ;
1027 * Process the new sample in the median filter and determine the
1028 * timecode timestamp.
1031 if ( ! refclock_process( pp ) ) {
1032 refclock_report( peer, CEVNT_BADTIME ) ;
1036 pp->lastref = pp->lastrec ;
1038 refclock_receive( peer ) ;
1041 * Write into the clockstats file
1043 snprintf ( sLog, sizeof(sLog),
1044 "%04d/%02d/%02d %02d:%02d:%02d.%03d JST ( %04d/%03d %02d:%02d:%02d.%03d UTC )",
1045 up->year, up->month, up->day,
1046 up->hour, up->minute, up->second, up->msecond,
1047 pp->year, pp->day, pp->hour, pp->minute, pp->second,
1048 (int)(pp->nsec/1000000) ) ;
1049 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
1054 switch ( peer->status ) {
1055 case 0 : cStatus = ' ' ; pStatus = "Reject" ; break ;
1056 case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ;
1057 case 2 : cStatus = '.' ; pStatus = "Excess" ; break ;
1058 case 3 : cStatus = '-' ; pStatus = "Outlier" ; break ;
1059 case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ;
1060 case 5 : cStatus = '#' ; pStatus = "Selected" ; break ;
1061 case 6 : cStatus = '*' ; pStatus = "Sys.Peer" ; break ;
1062 case 7 : cStatus = 'o' ; pStatus = "PPS.Peer" ; break ;
1066 snprintf ( sLog, sizeof(sLog),
1067 "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.",
1068 peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ;
1069 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1073 /*################################################################################################*/
1074 /*################################################################################################*/
1076 /*## The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02 ##*/
1078 /*## server 127.127.40.X mode 1 ##*/
1080 /*################################################################################################*/
1081 /*################################################################################################*/
1083 /* Command Response Remarks */
1084 /* -------------------- ---------------------------------------- ---------------------------- */
1085 /* dcst<CR><LF> VALID<CR><LF> or INVALID<CR><LF> */
1086 /* stus<CR><LF> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
1087 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> XXX is the day of the week */
1088 /* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */
1089 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
1091 /*################################################################################################*/
1093 #define TS_JJY01_COMMAND_NUMBER_DATE 1
1094 #define TS_JJY01_COMMAND_NUMBER_TIME 2
1095 #define TS_JJY01_COMMAND_NUMBER_STIM 3
1096 #define TS_JJY01_COMMAND_NUMBER_STUS 4
1097 #define TS_JJY01_COMMAND_NUMBER_DCST 5
1099 #define TS_JJY01_REPLY_DATE "yyyy/mm/dd www"
1100 #define TS_JJY01_REPLY_STIM "hh:mm:ss"
1101 #define TS_JJY01_REPLY_STUS_ADJUSTED "adjusted"
1102 #define TS_JJY01_REPLY_STUS_UNADJUSTED "unadjusted"
1103 #define TS_JJY01_REPLY_DCST_VALID "valid"
1104 #define TS_JJY01_REPLY_DCST_INVALID "invalid"
1106 #define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */
1107 #define TS_JJY01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
1108 #define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */
1109 #define TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED 8 /* Length without <CR><LF> */
1110 #define TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED 10 /* Length without <CR><LF> */
1111 #define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */
1112 #define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */
1116 const char commandNumber ;
1117 const char *command ;
1119 int iExpectedReplyLength [ 2 ] ;
1120 } tristate_jjy01_command_sequence[] =
1122 { 0, NULL, 0, { 0, 0 } }, /* Idle */
1123 { TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID , TS_JJY01_REPLY_LENGTH_DCST_INVALID } },
1124 { TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } },
1125 { TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME , TS_JJY01_REPLY_LENGTH_TIME } },
1126 { TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE , TS_JJY01_REPLY_LENGTH_DATE } },
1127 { TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM , TS_JJY01_REPLY_LENGTH_STIM } },
1128 /* End of command */
1129 { 0, NULL, 0, { 0, 0 } }
1132 /**************************************************************************************************/
1135 jjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up )
1138 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ;
1140 up->unittype = UNITTYPE_TRISTATE_JJY01 ;
1141 up->linespeed = SPEED232_TRISTATE_JJY01 ;
1142 up->linediscipline = LDISC_CLK ;
1148 /**************************************************************************************************/
1151 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
1153 struct jjyunit *up ;
1154 struct refclockproc *pp ;
1165 /* Initialize pointers */
1167 peer = rbufp->recv_peer ;
1168 pp = peer->procptr ;
1171 if ( up->linediscipline == LDISC_RAW ) {
1172 pBuf = up->sTextBuf ;
1173 iLen = up->iTextBufLen ;
1175 pBuf = pp->a_lastcode ;
1176 iLen = pp->lencode ;
1179 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
1181 /* Check expected reply */
1183 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1184 /* Command sequence has not been started, or has been completed */
1185 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1187 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1188 up->bLineError = TRUE ;
1189 return JJY_RECEIVE_ERROR ;
1192 /* Check reply length */
1194 if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
1195 && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
1196 /* Unexpected reply length */
1197 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1199 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1200 up->bLineError = TRUE ;
1201 return JJY_RECEIVE_ERROR ;
1206 switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
1208 case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
1210 rc = sscanf ( pBuf, "%4d/%2d/%2d",
1211 &up->year, &up->month, &up->day ) ;
1213 if ( rc != 3 || up->year < 2000 || 2099 <= up->year
1214 || up->month < 1 || 12 < up->month
1215 || up->day < 1 || 31 < up->day ) {
1217 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
1218 rc, up->year, up->month, up->day ) ;
1219 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1220 up->bLineError = TRUE ;
1221 return JJY_RECEIVE_ERROR ;
1226 case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1227 case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
1229 if ( up->iTimestampCount >= 2 ) {
1230 /* Too many time reply */
1231 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
1232 up->iTimestampCount ) ;
1233 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1234 up->bLineError = TRUE ;
1235 return JJY_RECEIVE_ERROR ;
1238 rc = sscanf ( pBuf, "%2d:%2d:%2d",
1239 &up->hour, &up->minute, &up->second ) ;
1241 if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
1244 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
1245 rc, up->hour, up->minute, up->second ) ;
1246 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1247 up->bLineError = TRUE ;
1248 return JJY_RECEIVE_ERROR ;
1251 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
1253 up->iTimestampCount++ ;
1259 case TS_JJY01_COMMAND_NUMBER_STUS :
1261 if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
1262 TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0
1263 || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
1264 TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
1267 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1269 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1270 up->bLineError = TRUE ;
1271 return JJY_RECEIVE_ERROR ;
1276 case TS_JJY01_COMMAND_NUMBER_DCST :
1278 if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
1279 TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
1280 || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
1281 TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
1284 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1286 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1287 up->bLineError = TRUE ;
1288 return JJY_RECEIVE_ERROR ;
1293 default : /* Unexpected reply */
1295 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1297 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1298 up->bLineError = TRUE ;
1299 return JJY_RECEIVE_ERROR ;
1303 if ( up->iTimestampCount == 2 ) {
1304 /* Process date and time */
1306 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
1307 && up->iTimestamp[0] <= up->iTimestamp[1] ) {
1308 /* 3 commands (time,date,stim) was excuted in two seconds */
1309 jjy_synctime( peer, pp, up ) ;
1310 return JJY_RECEIVE_DONE ;
1311 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
1312 /* Over midnight, and date is unsure */
1313 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
1314 up->iTimestamp[0], up->iTimestamp[1] ) ;
1315 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1316 return JJY_RECEIVE_SKIP ;
1319 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
1320 up->iTimestamp[0], up->iTimestamp[1] ) ;
1321 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1322 up->bLineError = TRUE ;
1323 return JJY_RECEIVE_ERROR ;
1328 /* Issue next command */
1330 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
1331 up->iCommandSeq ++ ;
1334 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1335 /* Command sequence completed */
1336 return JJY_RECEIVE_DONE ;
1339 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1340 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1341 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1342 refclock_report ( peer, CEVNT_FAULT ) ;
1345 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1347 return JJY_RECEIVE_WAIT ;
1351 /**************************************************************************************************/
1354 jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
1357 static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1360 struct refclockproc *pp ;
1361 struct jjyunit *up ;
1369 up->bLineError = FALSE ;
1370 up->iTimestampCount = 0 ;
1372 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1373 /* Skip "dcst" and "stus" commands */
1374 up->iCommandSeq = 2 ;
1375 up->iLineCount = 2 ;
1380 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
1381 sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1387 * Send a first command
1390 up->iCommandSeq ++ ;
1392 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1393 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1394 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1395 refclock_report ( peer, CEVNT_FAULT ) ;
1398 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1402 /*################################################################################################*/
1403 /*################################################################################################*/
1405 /*## The C-DEX Co. Ltd. JJY receiver JST2000 ##*/
1407 /*## server 127.127.40.X mode 2 ##*/
1409 /*################################################################################################*/
1410 /*################################################################################################*/
1412 /* Command Response Remarks */
1413 /* -------------------- ---------------------------------------- ---------------------------- */
1414 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> J is a fixed character */
1416 /*################################################################################################*/
1418 static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
1420 { "\x03", 1 }, { NULL, 0 }
1423 /**************************************************************************************************/
1426 jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
1429 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
1431 up->unittype = UNITTYPE_CDEX_JST2000 ;
1432 up->linespeed = SPEED232_CDEX_JST2000 ;
1433 up->linediscipline = LDISC_RAW ;
1435 up->pRawBreak = cdex_jst2000_raw_break ;
1436 up->bWaitBreakString = TRUE ;
1438 up->bSkipCntrlCharOnly = FALSE ;
1444 /**************************************************************************************************/
1447 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
1450 struct jjyunit *up ;
1451 struct refclockproc *pp ;
1454 char *pBuf, sLog [ 100 ] ;
1458 /* Initialize pointers */
1460 peer = rbufp->recv_peer ;
1461 pp = peer->procptr ;
1464 if ( up->linediscipline == LDISC_RAW ) {
1465 pBuf = up->sTextBuf ;
1466 iLen = up->iTextBufLen ;
1468 pBuf = pp->a_lastcode ;
1469 iLen = pp->lencode ;
1472 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
1474 /* Check expected reply */
1476 if ( up->iCommandSeq != 1 ) {
1477 /* Command sequence has not been started, or has been completed */
1478 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1480 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1481 up->bLineError = TRUE ;
1482 return JJY_RECEIVE_ERROR ;
1485 /* Wait until ETX comes */
1487 if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
1488 return JJY_RECEIVE_UNPROCESS ;
1491 /* Check reply length */
1494 /* Unexpected reply length */
1495 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1497 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1498 up->bLineError = TRUE ;
1499 return JJY_RECEIVE_ERROR ;
1502 /* JYYMMDD HHMMSSS */
1504 rc = sscanf ( pBuf, "J%2d%2d%2d %2d%2d%2d%1d",
1505 &up->year, &up->month, &up->day,
1506 &up->hour, &up->minute, &up->second,
1509 if ( rc != 7 || up->month < 1 || up->month > 12 ||
1510 up->day < 1 || up->day > 31 || up->hour > 23 ||
1511 up->minute > 59 || up->second > 60 ) {
1512 /* Invalid date and time */
1513 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1514 rc, up->year, up->month, up->day,
1515 up->hour, up->minute, up->second ) ;
1516 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1517 up->bLineError = TRUE ;
1518 return JJY_RECEIVE_ERROR ;
1522 up->msecond *= 100 ;
1524 jjy_synctime( peer, pp, up ) ;
1526 return JJY_RECEIVE_DONE ;
1530 /**************************************************************************************************/
1533 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1536 struct refclockproc *pp ;
1537 struct jjyunit *up ;
1539 pp = peer->procptr ;
1542 up->bLineError = FALSE ;
1543 up->iRawBufLen = 0 ;
1544 up->iLineBufLen = 0 ;
1545 up->iTextBufLen = 0 ;
1548 * Send "<ENQ>1J<ETX>" command
1551 up->iCommandSeq ++ ;
1553 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
1554 refclock_report ( peer, CEVNT_FAULT ) ;
1557 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
1561 /*################################################################################################*/
1562 /*################################################################################################*/
1564 /*## The Echo Keisokuki Co. Ltd. JJY receiver LT2000 ##*/
1566 /*## server 127.127.40.X mode 3 ##*/
1568 /*################################################################################################*/
1569 /*################################################################################################*/
1571 /* Command Response Remarks */
1572 /* -------------------- ---------------------------------------- ---------------------------- */
1573 /* # Mode 1 ( Request & Send ) */
1574 /* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
1575 /* C Mode 2 ( Continuous ) */
1576 /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> 0.5 sec before time stamp */
1577 /* <SUB> Second signal */
1579 /*################################################################################################*/
1581 #define ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1
1582 #define ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 2
1583 #define ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 3
1585 #define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND "#"
1586 #define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME "T"
1587 #define ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS "C"
1589 /**************************************************************************************************/
1592 jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
1595 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
1597 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
1598 up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
1599 up->linediscipline = LDISC_CLK ;
1601 up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
1607 /**************************************************************************************************/
1610 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1613 struct jjyunit *up ;
1614 struct refclockproc *pp ;
1617 char *pBuf, sLog [ 100 ], sErr [ 60 ] ;
1620 int i, ibcc, ibcc1, ibcc2 ;
1622 /* Initialize pointers */
1624 peer = rbufp->recv_peer ;
1625 pp = peer->procptr ;
1628 if ( up->linediscipline == LDISC_RAW ) {
1629 pBuf = up->sTextBuf ;
1630 iLen = up->iTextBufLen ;
1632 pBuf = pp->a_lastcode ;
1633 iLen = pp->lencode ;
1636 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
1638 /* Check reply length */
1640 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1642 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1644 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1646 /* Unexpected reply length */
1647 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1649 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1650 up->bLineError = TRUE ;
1651 return JJY_RECEIVE_ERROR ;
1654 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
1655 /* YYMMDDWHHMMSS<BCC1><BCC2> */
1657 for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
1661 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1662 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
1663 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1664 snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
1665 pBuf[13] & 0xFF, pBuf[14] & 0xFF,
1667 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1669 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1670 up->bLineError = TRUE ;
1671 return JJY_RECEIVE_ERROR ;
1676 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1678 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1680 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1682 /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1684 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1685 &up->year, &up->month, &up->day,
1686 &up->hour, &up->minute, &up->second ) ;
1688 if ( rc != 6 || up->month < 1 || up->month > 12
1689 || up->day < 1 || up->day > 31
1690 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1691 /* Invalid date and time */
1692 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1693 rc, up->year, up->month, up->day,
1694 up->hour, up->minute, up->second ) ;
1695 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1696 up->bLineError = TRUE ;
1697 return JJY_RECEIVE_ERROR ;
1702 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1703 || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1704 /* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
1708 if ( up->second < 0 ) {
1711 if ( up->minute < 0 ) {
1714 if ( up->hour < 0 ) {
1717 if ( up->day < 1 ) {
1719 if ( up->month < 1 ) {
1730 jjy_synctime( peer, pp, up ) ;
1735 if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1736 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1738 iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1739 if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen ) {
1740 refclock_report ( peer, CEVNT_FAULT ) ;
1743 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1747 return JJY_RECEIVE_DONE ;
1751 /**************************************************************************************************/
1754 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1757 struct refclockproc *pp ;
1758 struct jjyunit *up ;
1762 pp = peer->procptr ;
1765 up->bLineError = FALSE ;
1768 * Send "T" or "C" command
1771 switch ( up->operationmode ) {
1772 case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
1775 case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
1776 case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
1782 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
1783 refclock_report ( peer, CEVNT_FAULT ) ;
1786 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
1790 /*################################################################################################*/
1791 /*################################################################################################*/
1793 /*## The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 ##*/
1795 /*## server 127.127.40.X mode 4 ##*/
1797 /*################################################################################################*/
1798 /*################################################################################################*/
1800 /* Command Response Remarks */
1801 /* -------------------- ---------------------------------------- ---------------------------- */
1802 /* 'XX YY/MM/DD W HH:MM:SS<CR> XX:OK|NG|ER W:0(Mon)-6(Sun) */
1804 /*################################################################################################*/
1807 jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
1810 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
1812 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
1813 up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
1814 up->linediscipline = LDISC_CLK ;
1820 /**************************************************************************************************/
1823 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1826 struct jjyunit *up ;
1827 struct refclockproc *pp ;
1830 char *pBuf, sLog [ 100 ], sMsg [ 16 ] ;
1833 char cApostrophe, sStatus[3] ;
1836 /* Initialize pointers */
1838 peer = rbufp->recv_peer ;
1839 pp = peer->procptr ;
1842 if ( up->linediscipline == LDISC_RAW ) {
1843 pBuf = up->sTextBuf ;
1844 iLen = up->iTextBufLen ;
1846 pBuf = pp->a_lastcode ;
1847 iLen = pp->lencode ;
1850 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
1853 * JJY-200 sends a timestamp every second.
1854 * So, a timestamp is ignored unless it is right after polled.
1857 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
1858 return JJY_RECEIVE_SKIP ;
1861 /* Check reply length */
1864 /* Unexpected reply length */
1865 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1867 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1868 up->bLineError = TRUE ;
1869 return JJY_RECEIVE_ERROR ;
1872 /* 'XX YY/MM/DD W HH:MM:SS<CR> */
1874 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1875 &cApostrophe, sStatus,
1876 &up->year, &up->month, &up->day, &iWeekday,
1877 &up->hour, &up->minute, &up->second ) ;
1880 if ( rc != 9 || cApostrophe != '\''
1881 || ( strcmp( sStatus, "OK" ) != 0
1882 && strcmp( sStatus, "NG" ) != 0
1883 && strcmp( sStatus, "ER" ) != 0 )
1884 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
1886 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1887 /* Invalid date and time */
1888 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1889 rc, up->year, up->month, up->day,
1890 up->hour, up->minute, up->second ) ;
1891 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1892 up->bLineError = TRUE ;
1893 return JJY_RECEIVE_ERROR ;
1894 } else if ( strcmp( sStatus, "NG" ) == 0
1895 || strcmp( sStatus, "ER" ) == 0 ) {
1896 /* Timestamp is unsure */
1897 snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
1898 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
1900 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
1901 return JJY_RECEIVE_SKIP ;
1907 jjy_synctime( peer, pp, up ) ;
1909 return JJY_RECEIVE_DONE ;
1913 /**************************************************************************************************/
1916 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1919 struct refclockproc *pp ;
1920 struct jjyunit *up ;
1922 pp = peer->procptr ;
1925 up->bLineError = FALSE ;
1929 /*################################################################################################*/
1930 /*################################################################################################*/
1932 /*## The Tristate Ltd. GPS clock TS-GPS01 ##*/
1934 /*## server 127.127.40.X mode 5 ##*/
1936 /*################################################################################################*/
1937 /*################################################################################################*/
1939 /* This clock has NMEA mode and command/respose mode. */
1940 /* When this jjy driver are used, set to command/respose mode of this clock */
1941 /* by the onboard switch SW4, and make sure the LED-Y is tured on. */
1942 /* Other than this JJY driver, the refclock driver type 20, generic NMEA driver, */
1943 /* works with the NMEA mode of this clock. */
1945 /* Command Response Remarks */
1946 /* -------------------- ---------------------------------------- ---------------------------- */
1947 /* stus<CR><LF> *R|*G|*U|+U<CR><LF> */
1948 /* date<CR><LF> YY/MM/DD<CR><LF> */
1949 /* time<CR><LF> HH:MM:SS<CR><LF> */
1951 /*################################################################################################*/
1953 #define TS_GPS01_COMMAND_NUMBER_DATE 1
1954 #define TS_GPS01_COMMAND_NUMBER_TIME 2
1955 #define TS_GPS01_COMMAND_NUMBER_STUS 4
1957 #define TS_GPS01_REPLY_DATE "yyyy/mm/dd"
1958 #define TS_GPS01_REPLY_TIME "hh:mm:ss"
1959 #define TS_GPS01_REPLY_STUS_RTC "*R"
1960 #define TS_GPS01_REPLY_STUS_GPS "*G"
1961 #define TS_GPS01_REPLY_STUS_UTC "*U"
1962 #define TS_GPS01_REPLY_STUS_PPS "+U"
1964 #define TS_GPS01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */
1965 #define TS_GPS01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
1966 #define TS_GPS01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */
1970 char commandNumber ;
1971 const char *command ;
1973 int iExpectedReplyLength ;
1974 } tristate_gps01_command_sequence[] =
1976 { 0, NULL, 0, 0 }, /* Idle */
1977 { TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
1978 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1979 { TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
1980 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1981 /* End of command */
1985 /**************************************************************************************************/
1988 jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
1991 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
1993 up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
1994 up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
1995 up->linediscipline = LDISC_CLK ;
2001 /**************************************************************************************************/
2004 jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
2007 static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ;
2010 struct jjyunit *up ;
2011 struct refclockproc *pp ;
2022 /* Initialize pointers */
2024 peer = rbufp->recv_peer ;
2025 pp = peer->procptr ;
2028 if ( up->linediscipline == LDISC_RAW ) {
2029 pBuf = up->sTextBuf ;
2030 iLen = up->iTextBufLen ;
2032 pBuf = pp->a_lastcode ;
2033 iLen = pp->lencode ;
2036 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
2038 /* Ignore NMEA data stream */
2041 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2044 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2045 sFunctionName, pBuf ) ;
2048 return JJY_RECEIVE_WAIT ;
2052 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
2054 if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2055 return JJY_RECEIVE_WAIT ;
2056 } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2062 * Ignore NMEA data stream after command prompt
2065 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2068 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2069 sFunctionName, pBuf ) ;
2072 return JJY_RECEIVE_WAIT ;
2075 /* Check expected reply */
2077 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2078 /* Command sequence has not been started, or has been completed */
2079 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2081 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2082 up->bLineError = TRUE ;
2083 return JJY_RECEIVE_ERROR ;
2086 /* Check reply length */
2088 if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
2089 /* Unexpected reply length */
2090 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2092 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2093 up->bLineError = TRUE ;
2094 return JJY_RECEIVE_ERROR ;
2099 switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
2101 case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
2103 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
2105 if ( rc != 3 || up->year < 2000 || 2099 <= up->year
2106 || up->month < 1 || 12 < up->month
2107 || up->day < 1 || 31 < up->day ) {
2109 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
2110 rc, up->year, up->month, up->day ) ;
2111 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2112 up->bLineError = TRUE ;
2113 return JJY_RECEIVE_ERROR ;
2118 case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
2120 if ( up->iTimestampCount >= 2 ) {
2121 /* Too many time reply */
2122 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
2123 up->iTimestampCount ) ;
2124 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2125 up->bLineError = TRUE ;
2126 return JJY_RECEIVE_ERROR ;
2129 rc = sscanf ( pBuf, "%2d:%2d:%2d",
2130 &up->hour, &up->minute, &up->second ) ;
2133 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2135 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2136 rc, up->hour, up->minute, up->second ) ;
2137 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2138 up->bLineError = TRUE ;
2139 return JJY_RECEIVE_ERROR ;
2142 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
2144 up->iTimestampCount++ ;
2150 case TS_GPS01_COMMAND_NUMBER_STUS :
2152 if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2153 || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2154 || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2155 || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
2158 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2160 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2161 up->bLineError = TRUE ;
2162 return JJY_RECEIVE_ERROR ;
2167 default : /* Unexpected reply */
2169 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2171 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2172 up->bLineError = TRUE ;
2173 return JJY_RECEIVE_ERROR ;
2177 if ( up->iTimestampCount == 2 ) {
2178 /* Process date and time */
2180 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
2181 && up->iTimestamp[0] <= up->iTimestamp[1] ) {
2182 /* 3 commands (time,date,stim) was excuted in two seconds */
2183 jjy_synctime( peer, pp, up ) ;
2184 return JJY_RECEIVE_DONE ;
2185 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
2186 /* Over midnight, and date is unsure */
2187 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
2188 up->iTimestamp[0], up->iTimestamp[1] ) ;
2189 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
2190 return JJY_RECEIVE_SKIP ;
2193 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
2194 up->iTimestamp[0], up->iTimestamp[1] ) ;
2195 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2196 up->bLineError = TRUE ;
2197 return JJY_RECEIVE_ERROR ;
2202 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2203 /* Command sequence completed */
2204 jjy_synctime( peer, pp, up ) ;
2205 return JJY_RECEIVE_DONE ;
2208 /* Issue next command */
2210 if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
2211 up->iCommandSeq ++ ;
2214 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2215 /* Command sequence completed */
2216 up->iProcessState = JJY_PROCESS_STATE_DONE ;
2217 return JJY_RECEIVE_DONE ;
2220 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
2221 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2222 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2223 refclock_report ( peer, CEVNT_FAULT ) ;
2226 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2228 return JJY_RECEIVE_WAIT ;
2232 /**************************************************************************************************/
2235 jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
2238 static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
2241 struct refclockproc *pp ;
2242 struct jjyunit *up ;
2247 pp = peer->procptr ;
2250 up->iTimestampCount = 0 ;
2252 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
2253 /* Skip "stus" command */
2254 up->iCommandSeq = 1 ;
2255 up->iLineCount = 1 ;
2260 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
2261 sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
2267 * Send a first command
2270 up->iCommandSeq ++ ;
2272 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
2273 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2274 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2275 refclock_report ( peer, CEVNT_FAULT ) ;
2278 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2282 /*################################################################################################*/
2283 /*################################################################################################*/
2285 /*## The SEIKO TIME SYSTEMS TDC-300 ##*/
2287 /*## server 127.127.40.X mode 6 ##*/
2289 /*################################################################################################*/
2290 /*################################################################################################*/
2292 /* Type Response Remarks */
2293 /* -------------------- ---------------------------------------- ---------------------------- */
2294 /* Type 1 <STX>HH:MM:SS<ETX> */
2295 /* Type 2 <STX>YYMMDDHHMMSSWLSCU<ETX> W:0(Sun)-6(Sat) */
2296 /* Type 3 <STX>YYMMDDWHHMMSS<ETX> W:0(Sun)-6(Sat) */
2297 /* <STX><xE5><ETX> 5 to 10 mSec. before second */
2299 /*################################################################################################*/
2301 static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
2303 { "\x03", 1 }, { NULL, 0 }
2306 /**************************************************************************************************/
2309 jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
2312 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
2314 up->unittype = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
2315 up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
2316 up->linediscipline = LDISC_RAW ;
2318 up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
2319 up->bWaitBreakString = TRUE ;
2321 up->bSkipCntrlCharOnly = FALSE ;
2327 /**************************************************************************************************/
2330 jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
2334 struct refclockproc *pp ;
2335 struct jjyunit *up ;
2337 char *pBuf, sLog [ 100 ] ;
2343 /* Initialize pointers */
2345 peer = rbufp->recv_peer ;
2346 pp = peer->procptr ;
2349 if ( up->linediscipline == LDISC_RAW ) {
2350 pBuf = up->sTextBuf ;
2351 iLen = up->iTextBufLen ;
2353 pBuf = pp->a_lastcode ;
2354 iLen = pp->lencode ;
2357 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
2360 * TDC-300 sends a timestamp every second.
2361 * So, a timestamp is ignored unless it is right after polled.
2364 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
2365 return JJY_RECEIVE_SKIP ;
2368 /* Process timestamp */
2370 up->iReceiveSeq ++ ;
2374 case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
2376 for ( i = 0 ; i < iLen ; i ++ ) {
2380 rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
2381 &up->hour, &up->minute, &up->second ) ;
2384 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2386 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2387 rc, up->hour, up->minute, up->second ) ;
2388 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2389 up->bLineError = TRUE ;
2390 return JJY_RECEIVE_ERROR ;
2391 } else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
2392 /* Uncertainty date guard */
2393 return JJY_RECEIVE_WAIT ;
2397 pTime = localtime( &now ) ;
2398 up->year = pTime->tm_year ;
2399 up->month = pTime->tm_mon + 1 ;
2400 up->day = pTime->tm_mday ;
2404 case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
2406 for ( i = 0 ; i < iLen ; i ++ ) {
2410 rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
2411 &up->year, &up->month, &up->day,
2412 &up->hour, &up->minute, &up->second, &iWeekday ) ;
2415 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2417 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2418 /* Invalid date and time */
2419 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2420 rc, up->year, up->month, up->day,
2421 up->hour, up->minute, up->second ) ;
2422 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2423 up->bLineError = TRUE ;
2424 return JJY_RECEIVE_ERROR ;
2429 case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
2431 rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
2432 &up->year, &up->month, &up->day, &iWeekday,
2433 &up->hour, &up->minute, &up->second ) ;
2436 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2438 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2439 /* Invalid date and time */
2440 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2441 rc, up->year, up->month, up->day,
2442 up->hour, up->minute, up->second ) ;
2443 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2444 up->bLineError = TRUE ;
2445 return JJY_RECEIVE_ERROR ;
2448 return JJY_RECEIVE_WAIT ;
2450 case 1 : /* Type 3 : <STX><xE5><ETX> */
2452 if ( ( *pBuf & 0xFF ) != 0xE5 ) {
2453 /* Invalid second signal */
2454 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2456 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2457 up->bLineError = TRUE ;
2458 return JJY_RECEIVE_ERROR ;
2459 } else if ( up->iReceiveSeq == 1 ) {
2460 /* Wait for next timestamp */
2461 up->iReceiveSeq -- ;
2462 return JJY_RECEIVE_WAIT ;
2463 } else if ( up->iReceiveSeq >= 3 ) {
2464 /* Unexpected second signal */
2465 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2467 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2468 up->bLineError = TRUE ;
2469 return JJY_RECEIVE_ERROR ;
2474 default : /* Unexpected reply length */
2476 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2478 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2479 up->bLineError = TRUE ;
2480 return JJY_RECEIVE_ERROR ;
2487 jjy_synctime( peer, pp, up ) ;
2489 return JJY_RECEIVE_DONE ;
2493 /**************************************************************************************************/
2496 jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
2499 struct refclockproc *pp ;
2500 struct jjyunit *up ;
2502 pp = peer->procptr ;
2505 up->bLineError = FALSE ;
2509 /*################################################################################################*/
2510 /*################################################################################################*/
2512 /*## Telephone JJY ##*/
2514 /*## server 127.127.40.X mode 100 to 180 ##*/
2516 /*################################################################################################*/
2517 /*################################################################################################*/
2519 /* Prompt Command Response Remarks */
2520 /* -------------------- -------------------- -------------------- -------------------------- */
2521 /* Name<SP>?<SP> TJJY<CR> Welcome messages TJJY is a guest user ID */
2522 /* > 4DATE<CR> YYYYMMDD<CR> */
2523 /* > LEAPSEC<CR> XX<CR> One of <SP>0, +1, -1 */
2524 /* > TIME<CR> HHMMSS<CR> 3 times on second */
2525 /* > BYE<CR> Sayounara messages */
2527 /*################################################################################################*/
2529 static struct jjyRawDataBreak teljjy_raw_break [ ] =
2540 #define TELJJY_STATE_IDLE 0
2541 #define TELJJY_STATE_DAILOUT 1
2542 #define TELJJY_STATE_LOGIN 2
2543 #define TELJJY_STATE_CONNECT 3
2544 #define TELJJY_STATE_BYE 4
2546 #define TELJJY_EVENT_NULL 0
2547 #define TELJJY_EVENT_START 1
2548 #define TELJJY_EVENT_CONNECT 2
2549 #define TELJJY_EVENT_DISCONNECT 3
2550 #define TELJJY_EVENT_COMMAND 4
2551 #define TELJJY_EVENT_LOGIN 5 /* Posted by the jjy_receive_telephone */
2552 #define TELJJY_EVENT_PROMPT 6 /* Posted by the jjy_receive_telephone */
2553 #define TELJJY_EVENT_DATA 7 /* Posted by the jjy_receive_telephone */
2554 #define TELJJY_EVENT_ERROR 8 /* Posted by the jjy_receive_telephone */
2555 #define TELJJY_EVENT_SILENT 9 /* Posted by the jjy_timer_telephone */
2556 #define TELJJY_EVENT_TIMEOUT 10 /* Posted by the jjy_timer_telephone */
2558 static void teljjy_control ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2560 static int teljjy_idle_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2561 static int teljjy_idle_dialout ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2562 static int teljjy_dial_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2563 static int teljjy_dial_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2564 static int teljjy_dial_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2565 static int teljjy_login_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2566 static int teljjy_login_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2567 static int teljjy_login_conn ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2568 static int teljjy_login_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2569 static int teljjy_login_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2570 static int teljjy_login_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2571 static int teljjy_conn_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2572 static int teljjy_conn_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2573 static int teljjy_conn_send ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2574 static int teljjy_conn_data ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2575 static int teljjy_conn_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2576 static int teljjy_conn_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2577 static int teljjy_bye_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2578 static int teljjy_bye_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2579 static int teljjy_bye_modem ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2581 static int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) =
2582 { /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
2583 /* NULL */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2584 /* START */ { teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2585 /* CONNECT */ { teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2586 /* DISCONNECT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_disc , teljjy_conn_disc , teljjy_bye_disc },
2587 /* COMMAND */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem },
2588 /* LOGIN */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
2589 /* PROMPT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn , teljjy_conn_send , teljjy_bye_ignore },
2590 /* DATA */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data , teljjy_bye_ignore },
2591 /* ERROR */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
2592 /* SILENT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
2593 /* TIMEOUT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem }
2596 static short iTeljjyNextState [ ] [ 5 ] =
2597 { /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
2598 /* NULL */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2599 /* START */ { TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2600 /* CONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_LOGIN , TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2601 /* DISCONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE },
2602 /* COMMAND */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2603 /* LOGIN */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
2604 /* PROMPT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE , TELJJY_STATE_BYE },
2605 /* DATA */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2606 /* ERROR */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
2607 /* SILENT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2608 /* TIMEOUT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE }
2611 static short iTeljjyPostEvent [ ] [ 5 ] =
2612 { /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
2613 /* NULL */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2614 /* START */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2615 /* CONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2616 /* DISCONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2617 /* COMMAND */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2618 /* LOGIN */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2619 /* PROMPT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2620 /* DATA */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2621 /* ERROR */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2622 /* SILENT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2623 /* TIMEOUT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
2626 static short iTeljjySilentTimeout [ 5 ] = { 0, 0, 10, 5, 0 } ;
2627 static short iTeljjyStateTimeout [ 5 ] = { 0, 120, 60, 60, 40 } ;
2629 #define TELJJY_STAY_CLOCK_STATE 0
2630 #define TELJJY_CHANGE_CLOCK_STATE 1
2632 /* Command and replay */
2634 #define TELJJY_REPLY_NONE 0
2635 #define TELJJY_REPLY_4DATE 1
2636 #define TELJJY_REPLY_TIME 2
2637 #define TELJJY_REPLY_LEAPSEC 3
2638 #define TELJJY_REPLY_LOOP 4
2639 #define TELJJY_REPLY_PROMPT 5
2640 #define TELJJY_REPLY_LOOPBACK 6
2641 #define TELJJY_REPLY_COM 7
2643 #define TELJJY_COMMAND_START_SKIP_LOOPBACK 7
2647 const char *command ;
2649 int iEchobackReplyLength ;
2650 int iExpectedReplyType ;
2651 int iExpectedReplyLength ;
2652 } teljjy_command_sequence[] =
2654 { NULL, 0, 0, 0, 0 }, /* Idle */
2655 { "LOOP\r" , 5, 4, TELJJY_REPLY_LOOP , 0 }, /* Getting into loopback mode */
2656 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2657 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2658 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2659 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2660 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2661 { "COM\r" , 4, 3, TELJJY_REPLY_COM , 0 }, /* Exit from loopback mode */
2662 /* TELJJY_COMMAND_START_SKIP_LOOPBACK */
2663 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
2664 { "4DATE\r" , 6, 5, TELJJY_REPLY_4DATE , 8 },
2665 { "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
2666 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
2667 { "BYE\r" , 4, 3, TELJJY_REPLY_NONE , 0 },
2668 /* End of command */
2669 { NULL, 0, 0, 0, 0 }
2672 #define TELJJY_LOOPBACK_DELAY_THRESHOLD 700 /* Milli second */
2675 #define DEBUG_TELJJY_PRINTF(sFunc) { if ( debug ) { printf ( "refclock_jjy.c : %s : iClockState=%d iClockEvent=%d iTeljjySilentTimer=%d iTeljjyStateTimer=%d iClockCommandSeq=%d\n", sFunc, up->iClockState, up->iClockEvent, up->iTeljjySilentTimer, up->iTeljjyStateTimer, up->iClockCommandSeq ) ; } }
2677 #define DEBUG_TELJJY_PRINTF(sFunc)
2680 /**************************************************************************************************/
2683 jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
2686 char sLog [ 80 ], sFirstThreeDigits [ 4 ] ;
2687 int i, iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
2688 int iFirstThreeDigitsCount ;
2690 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
2692 up->unittype = UNITTYPE_TELEPHONE ;
2693 up->linespeed = SPEED232_TELEPHONE ;
2694 up->linediscipline = LDISC_RAW ;
2696 up->pRawBreak = teljjy_raw_break ;
2697 up->bWaitBreakString = TRUE ;
2699 up->bSkipCntrlCharOnly = TRUE ;
2701 up->iClockState = TELJJY_STATE_IDLE ;
2702 up->iClockEvent = TELJJY_EVENT_NULL ;
2704 /* Check the telephone number */
2706 if ( sys_phone[0] == NULL ) {
2707 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
2708 up->bInitError = TRUE ;
2712 if ( sys_phone[1] != NULL ) {
2713 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
2714 up->bInitError = TRUE ;
2718 iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
2719 for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
2720 if ( isdigit( (u_char)sys_phone[0][i] ) ) {
2721 if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
2722 sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ;
2724 iNumberOfDigitsOfPhoneNumber ++ ;
2725 } else if ( sys_phone[0][i] == ',' ) {
2727 if ( iCommaCount > 1 ) {
2728 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
2729 up->bInitError = TRUE ;
2732 iFirstThreeDigitsCount = 0 ;
2733 iCommaPosition = i ;
2734 } else if ( sys_phone[0][i] != '-' ) {
2735 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
2736 up->bInitError = TRUE ;
2740 sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
2742 if ( iCommaCount == 1 ) {
2743 if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
2744 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
2745 up->bInitError = TRUE ;
2750 if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
2751 /* Too short or too long */
2752 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
2753 up->bInitError = TRUE ;
2757 if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
2758 || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
2759 || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
2760 || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
2761 || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
2762 || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
2763 || ( sFirstThreeDigits[0] == '0' && sFirstThreeDigits[2] == '0' ) ) {
2764 /* Not allowed because of emergency numbers or special service numbers */
2765 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
2766 up->bInitError = TRUE ;
2770 snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
2771 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2773 if ( peer->minpoll < 8 ) {
2774 /* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
2775 int oldminpoll = peer->minpoll ;
2777 if ( peer->ppoll < peer->minpoll ) {
2778 peer->ppoll = peer->minpoll ;
2780 if ( peer->maxpoll < peer->minpoll ) {
2781 peer->maxpoll = peer->minpoll ;
2783 snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
2784 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2791 /**************************************************************************************************/
2794 jjy_receive_telephone ( struct recvbuf *rbufp )
2797 static const char *sFunctionName = "jjy_receive_telephone" ;
2801 struct refclockproc *pp ;
2802 struct jjyunit *up ;
2805 short iPreviousModemState ;
2807 peer = rbufp->recv_peer ;
2808 pp = peer->procptr ;
2811 DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2813 if ( up->iClockState == TELJJY_STATE_IDLE
2814 || up->iClockState == TELJJY_STATE_DAILOUT
2815 || up->iClockState == TELJJY_STATE_BYE ) {
2817 iPreviousModemState = getModemState( up ) ;
2819 modem_receive ( rbufp ) ;
2821 if ( iPreviousModemState != up->iModemState ) {
2822 /* Modem state is changed just now. */
2823 if ( isModemStateDisconnect( up->iModemState ) ) {
2824 up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2825 teljjy_control ( peer, pp, up ) ;
2826 } else if ( isModemStateConnect( up->iModemState ) ) {
2827 up->iClockEvent = TELJJY_EVENT_CONNECT ;
2828 teljjy_control ( peer, pp, up ) ;
2832 return JJY_RECEIVE_WAIT ;
2836 if ( up->linediscipline == LDISC_RAW ) {
2837 pBuf = up->sTextBuf ;
2838 iLen = up->iTextBufLen ;
2840 pBuf = pp->a_lastcode ;
2841 iLen = pp->lencode ;
2844 up->iTeljjySilentTimer = 0 ;
2845 if ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN ; }
2846 else if ( iLen == 1 && strncmp( pBuf, ">" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
2847 else if ( iLen >= 1 && strncmp( pBuf, "?" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR ; }
2848 else { up->iClockEvent = TELJJY_EVENT_DATA ; }
2850 teljjy_control ( peer, pp, up ) ;
2852 return JJY_RECEIVE_WAIT ;
2856 /**************************************************************************************************/
2859 jjy_poll_telephone ( int unit, struct peer *peer )
2862 static const char *sFunctionName = "jjy_poll_telephone" ;
2865 struct refclockproc *pp ;
2866 struct jjyunit *up ;
2868 pp = peer->procptr ;
2871 DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2873 if ( up->iClockState == TELJJY_STATE_IDLE ) {
2874 up->iRawBufLen = 0 ;
2875 up->iLineBufLen = 0 ;
2876 up->iTextBufLen = 0 ;
2879 up->iClockEvent = TELJJY_EVENT_START ;
2880 teljjy_control ( peer, pp, up ) ;
2884 /**************************************************************************************************/
2887 jjy_timer_telephone ( int unit, struct peer *peer )
2890 static const char *sFunctionName = "jjy_timer_telephone" ;
2893 struct refclockproc *pp ;
2894 struct jjyunit *up ;
2895 short iPreviousModemState ;
2897 pp = peer->procptr ;
2900 DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2902 if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
2903 up->iTeljjySilentTimer++ ;
2904 if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
2905 up->iClockEvent = TELJJY_EVENT_SILENT ;
2906 teljjy_control ( peer, pp, up ) ;
2910 if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
2911 up->iTeljjyStateTimer++ ;
2912 if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
2913 up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
2914 teljjy_control ( peer, pp, up ) ;
2918 if ( isModemStateTimerOn( up ) ) {
2920 iPreviousModemState = getModemState( up ) ;
2922 modem_timer ( unit, peer ) ;
2924 if ( iPreviousModemState != up->iModemState ) {
2925 /* Modem state is changed just now. */
2926 if ( isModemStateDisconnect( up->iModemState ) ) {
2927 up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2928 teljjy_control ( peer, pp, up ) ;
2929 } else if ( isModemStateConnect( up->iModemState ) ) {
2930 up->iClockEvent = TELJJY_EVENT_CONNECT ;
2931 teljjy_control ( peer, pp, up ) ;
2939 /**************************************************************************************************/
2942 teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
2946 short iPostEvent = TELJJY_EVENT_NULL ;
2948 DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
2950 rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
2952 if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
2953 iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
2956 printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd iPostEvent=%hd\n",
2957 up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
2960 up->iTeljjySilentTimer = 0 ;
2961 if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
2962 /* Telephone JJY state is changing now */
2963 up->iTeljjyStateTimer = 0 ;
2964 up->bLineError = FALSE ;
2965 up->iClockCommandSeq = 0 ;
2966 up->iTimestampCount = 0 ;
2967 up->iLoopbackCount = 0 ;
2968 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
2969 up->bLoopbackTimeout[i] = FALSE ;
2971 if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
2972 /* Telephone JJY state is changing to IDLE just now */
2973 up->iProcessState = JJY_PROCESS_STATE_DONE ;
2976 up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
2980 if ( iPostEvent != TELJJY_EVENT_NULL ) {
2981 up->iClockEvent = iPostEvent ;
2982 teljjy_control ( peer, pp, up ) ;
2985 up->iClockEvent = TELJJY_EVENT_NULL ;
2989 /**************************************************************************************************/
2992 teljjy_setDelay ( struct peer *peer, struct jjyunit *up )
2996 int milliSecond, microSecond ;
2998 gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
3000 up->delayTime[up->iLoopbackCount].tv_sec -= up->sendTime[up->iLoopbackCount].tv_sec ;
3001 up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
3002 if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
3003 up->delayTime[up->iLoopbackCount].tv_sec -- ;
3004 up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
3007 milliSecond = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
3008 microSecond = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
3009 milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
3011 snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
3012 milliSecond, microSecond ) ;
3014 if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
3015 /* Delay > 700 mS */
3016 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3018 /* Delay <= 700 mS */
3019 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3024 /**************************************************************************************************/
3027 teljjy_getDelay ( struct peer *peer, struct jjyunit *up )
3030 struct timeval maxTime, minTime, averTime ;
3032 int minIndex = 0, maxIndex = 0, iAverCount = 0 ;
3033 int iThresholdSecond, iThresholdMicroSecond ;
3036 minTime.tv_sec = minTime.tv_usec = 0 ;
3037 maxTime.tv_sec = maxTime.tv_usec = 0 ;
3039 iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
3040 iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
3042 up->iLoopbackValidCount = 0 ;
3044 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3045 if ( up->bLoopbackTimeout[i]
3046 || up->delayTime[i].tv_sec > iThresholdSecond
3047 || ( up->delayTime[i].tv_sec == iThresholdSecond
3048 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3051 if ( up->iLoopbackValidCount == 0 ) {
3052 minTime.tv_sec = up->delayTime[i].tv_sec ;
3053 minTime.tv_usec = up->delayTime[i].tv_usec ;
3054 maxTime.tv_sec = up->delayTime[i].tv_sec ;
3055 maxTime.tv_usec = up->delayTime[i].tv_usec ;
3056 minIndex = maxIndex = i ;
3057 } else if ( minTime.tv_sec > up->delayTime[i].tv_sec
3058 || ( minTime.tv_sec == up->delayTime[i].tv_sec
3059 && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
3060 minTime.tv_sec = up->delayTime[i].tv_sec ;
3061 minTime.tv_usec = up->delayTime[i].tv_usec ;
3063 } else if ( maxTime.tv_sec < up->delayTime[i].tv_sec
3064 || ( maxTime.tv_sec == up->delayTime[i].tv_sec
3065 && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
3066 maxTime.tv_sec = up->delayTime[i].tv_sec ;
3067 maxTime.tv_usec = up->delayTime[i].tv_usec ;
3070 up->iLoopbackValidCount ++ ;
3073 if ( up->iLoopbackValidCount < 2 ) {
3077 averTime.tv_usec = 0;
3079 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3080 if ( up->bLoopbackTimeout[i]
3081 || up->delayTime[i].tv_sec > iThresholdSecond
3082 || ( up->delayTime[i].tv_sec == iThresholdSecond
3083 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3086 if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
3089 if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
3092 averTime.tv_usec += up->delayTime[i].tv_usec ;
3096 if ( iAverCount == 0 ) {
3097 /* This is never happened. */
3098 /* Previous for-if-for blocks assure iAverCount > 0. */
3099 /* This code avoids a claim by the coverity scan tool. */
3103 /* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
3105 iPercent = ( peer->ttl - 100 ) ;
3107 /* Average delay time in milli second */
3109 return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
3113 /******************************/
3115 teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3118 DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
3120 return TELJJY_STAY_CLOCK_STATE ;
3124 /******************************/
3126 teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3129 DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
3131 modem_connect ( peer->refclkunit, peer ) ;
3133 return TELJJY_CHANGE_CLOCK_STATE ;
3137 /******************************/
3139 teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3142 DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
3144 return TELJJY_STAY_CLOCK_STATE ;
3148 /******************************/
3150 teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3153 DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
3155 return TELJJY_CHANGE_CLOCK_STATE ;
3159 /******************************/
3161 teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3164 DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
3166 return TELJJY_CHANGE_CLOCK_STATE ;
3170 /******************************/
3172 teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3175 DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
3177 return TELJJY_STAY_CLOCK_STATE ;
3181 /******************************/
3183 teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3186 DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
3188 return TELJJY_CHANGE_CLOCK_STATE ;
3192 /******************************/
3194 teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3199 DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
3201 up->bLineError = FALSE ;
3202 up->iClockCommandSeq = 0 ;
3203 up->iTimestampCount = 0 ;
3204 up->iLoopbackCount = 0 ;
3205 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3206 up->bLoopbackTimeout[i] = FALSE ;
3209 return TELJJY_CHANGE_CLOCK_STATE ;
3213 /******************************/
3215 teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3221 DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
3223 /* Send a guest user ID */
3227 iCmdLen = strlen( pCmd ) ;
3228 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
3229 refclock_report( peer, CEVNT_FAULT ) ;
3232 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3234 return TELJJY_STAY_CLOCK_STATE ;
3238 /******************************/
3240 teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3243 DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
3245 if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
3246 refclock_report( peer, CEVNT_FAULT ) ;
3249 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
3251 up->iTeljjySilentTimer = 0 ;
3253 return TELJJY_CHANGE_CLOCK_STATE ;
3257 /******************************/
3259 teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3262 DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
3264 return TELJJY_CHANGE_CLOCK_STATE ;
3268 /******************************/
3270 teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3273 DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
3275 return TELJJY_STAY_CLOCK_STATE ;
3279 /******************************/
3281 teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3284 DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
3286 return TELJJY_CHANGE_CLOCK_STATE ;
3290 /******************************/
3292 teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3296 int i, iLen, iNextClockState ;
3298 DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
3300 if ( up->iClockCommandSeq > 0
3301 && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
3302 /* Command sequence has been completed */
3303 return TELJJY_CHANGE_CLOCK_STATE ;
3306 if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
3309 up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
3311 } else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
3312 /* Loopback start */
3314 up->iLoopbackCount = 0 ;
3315 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3316 up->bLoopbackTimeout[i] = FALSE ;
3319 } else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
3320 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3321 && up->iLoopbackCount < MAX_LOOPBACK ) {
3322 /* Loopback character comes */
3325 printf( "refclock_jjy.c : teljjy_conn_send : iLoopbackCount=%d\n",
3326 up->iLoopbackCount ) ;
3330 teljjy_setDelay( peer, up ) ;
3332 up->iLoopbackCount ++ ;
3336 up->iClockCommandSeq++ ;
3338 pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
3339 iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
3341 if ( pCmd != NULL ) {
3343 if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
3344 refclock_report( peer, CEVNT_FAULT ) ;
3347 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3348 /* Loopback character and timestamp */
3349 gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
3350 up->bLoopbackMode = TRUE ;
3352 /* Regular command */
3353 up->bLoopbackMode = FALSE ;
3356 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3358 if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
3359 /* Last command of the command sequence */
3360 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3362 /* More commands to be issued */
3363 iNextClockState = TELJJY_STAY_CLOCK_STATE ;
3368 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3372 return iNextClockState ;
3376 /******************************/
3378 teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3387 DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
3389 if ( up->linediscipline == LDISC_RAW ) {
3390 pBuf = up->sTextBuf ;
3391 iLen = up->iTextBufLen ;
3393 pBuf = pp->a_lastcode ;
3394 iLen = pp->lencode ;
3397 if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3398 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3399 && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
3400 && up->iLoopbackCount < MAX_LOOPBACK ) {
3403 teljjy_setDelay( peer, up ) ;
3405 up->iLoopbackCount ++ ;
3407 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3408 && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
3409 /* Maybe echoback */
3411 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
3413 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3414 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
3415 /* 4DATE<CR> -> YYYYMMDD<CR> */
3417 rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
3419 if ( rc != 3 || up->year < 2000 || 2099 <= up->year
3420 || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
3422 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
3423 rc, up->year, up->month, up->day ) ;
3424 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3425 up->bLineError = TRUE ;
3428 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3429 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
3430 && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
3431 /* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
3433 rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
3435 if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
3436 /* Invalid leap second */
3437 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
3439 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3440 up->bLineError = TRUE ;
3443 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3444 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
3445 /* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
3447 rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
3449 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
3451 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
3452 rc, up->hour, up->minute, up->second ) ;
3453 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3454 up->bLineError = TRUE ;
3456 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
3458 up->iTimestampCount++ ;
3460 if ( up->iTimestampCount == 6 && ! up->bLineError ) {
3462 printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
3464 up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
3466 bAdjustment = TRUE ;
3468 if ( peer->ttl == 100 ) {
3472 /* mode=101 to 110 */
3473 up->msecond = teljjy_getDelay( peer, up ) ;
3474 if (up->msecond < 0 ) {
3476 bAdjustment = FALSE ;
3480 if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
3481 && up->iTimestamp[2] <= up->iTimestamp[3]
3482 && ( up->iTimestamp[3] + 1 ) == up->iTimestamp[4]
3483 && ( up->iTimestamp[4] + 1 ) == up->iTimestamp[5] ) {
3484 /* Non over midnight */
3486 jjy_synctime( peer, pp, up ) ;
3488 if ( peer->ttl != 100 ) {
3489 if ( bAdjustment ) {
3490 snprintf( sLog, sizeof(sLog),
3491 JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
3492 up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3493 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3495 snprintf( sLog, sizeof(sLog),
3496 JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
3497 up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3498 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3505 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
3506 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3507 /* Loopback noise ( Unexpected replay ) */
3509 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
3511 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3515 up->bLineError = TRUE ;
3517 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
3519 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3523 return TELJJY_STAY_CLOCK_STATE ;
3527 /******************************/
3529 teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3534 DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
3536 if ( up->iClockCommandSeq >= 1
3537 && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
3541 printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
3544 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3545 up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
3547 up->iTeljjySilentTimer = 0 ;
3548 return teljjy_conn_send( peer, pp, up ) ;
3553 if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
3554 refclock_report( peer, CEVNT_FAULT ) ;
3557 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3559 up->iTeljjySilentTimer = 0 ;
3561 return TELJJY_STAY_CLOCK_STATE ;
3565 /******************************/
3567 teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3570 DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
3572 return TELJJY_CHANGE_CLOCK_STATE ;
3576 /******************************/
3578 teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3581 DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
3583 return TELJJY_STAY_CLOCK_STATE ;
3587 /******************************/
3589 teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3592 DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
3594 return TELJJY_CHANGE_CLOCK_STATE ;
3598 /******************************/
3600 teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3603 DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
3605 modem_disconnect ( peer->refclkunit, peer ) ;
3607 return TELJJY_STAY_CLOCK_STATE ;
3611 /*################################################################################################*/
3612 /*################################################################################################*/
3614 /*## Modem control finite state machine ##*/
3616 /*################################################################################################*/
3617 /*################################################################################################*/
3619 /* struct jjyunit.iModemState */
3621 #define MODEM_STATE_DISCONNECT 0
3622 #define MODEM_STATE_INITIALIZE 1
3623 #define MODEM_STATE_DAILING 2
3624 #define MODEM_STATE_CONNECT 3
3625 #define MODEM_STATE_ESCAPE 4
3627 /* struct jjyunit.iModemEvent */
3629 #define MODEM_EVENT_NULL 0
3630 #define MODEM_EVENT_INITIALIZE 1
3631 #define MODEM_EVENT_DIALOUT 2
3632 #define MODEM_EVENT_DISCONNECT 3
3633 #define MODEM_EVENT_RESP_OK 4
3634 #define MODEM_EVENT_RESP_CONNECT 5
3635 #define MODEM_EVENT_RESP_RING 6
3636 #define MODEM_EVENT_RESP_NO_CARRIER 7
3637 #define MODEM_EVENT_RESP_ERROR 8
3638 #define MODEM_EVENT_RESP_CONNECT_X 9
3639 #define MODEM_EVENT_RESP_NO_DAILTONE 10
3640 #define MODEM_EVENT_RESP_BUSY 11
3641 #define MODEM_EVENT_RESP_NO_ANSWER 12
3642 #define MODEM_EVENT_RESP_UNKNOWN 13
3643 #define MODEM_EVENT_SILENT 14
3644 #define MODEM_EVENT_TIMEOUT 15
3646 /* Function prototypes */
3648 static void modem_control ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3650 static int modem_disc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3651 static int modem_disc_init ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3652 static int modem_init_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3653 static int modem_init_start ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3654 static int modem_init_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3655 static int modem_init_resp00 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3656 static int modem_init_resp04 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3657 static int modem_dial_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3658 static int modem_dial_dialout ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3659 static int modem_dial_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3660 static int modem_dial_connect ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3661 static int modem_dial_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3662 static int modem_conn_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3663 static int modem_conn_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3664 static int modem_esc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3665 static int modem_esc_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3666 static int modem_esc_data ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3667 static int modem_esc_silent ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3668 static int modem_esc_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3670 static int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) =
3671 { /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
3672 /* NULL */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3673 /* INITIALIZE */ { modem_disc_init , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3674 /* DIALOUT */ { modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
3675 /* DISCONNECT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_escape },
3676 /* RESP: 0: OK */ { modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
3677 /* RESP: 1: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
3678 /* RESP: 2: RING */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
3679 /* RESP: 3: NO CARRIER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3680 /* RESP: 4: ERROR */ { modem_disc_ignore, modem_init_resp04, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3681 /* RESP: 5: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
3682 /* RESP: 6: NO DAILTONE */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3683 /* RESP: 7: BUSY */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3684 /* RESP: 8: NO ANSWER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3685 /* RESP: 9: UNKNOWN */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
3686 /* SILENT */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
3687 /* TIMEOUT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_disc }
3690 static short iModemNextState [ ] [ 5 ] =
3691 { /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
3692 /* NULL */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3693 /* INITIALIZE */ { MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3694 /* DIALOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3695 /* DISCONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE },
3696 /* RESP: 0: OK */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3697 /* RESP: 1: CONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3698 /* RESP: 2: RING */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3699 /* RESP: 3: NO CARRIER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3700 /* RESP: 4: ERROR */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3701 /* RESP: 5: CONNECT X */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3702 /* RESP: 6: NO DAILTONE */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3703 /* RESP: 7: BUSY */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3704 /* RESP: 8: NO ANSWER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3705 /* RESP: 9: UNKNOWN */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3706 /* SILENT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
3707 /* TIMEOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
3710 static short iModemPostEvent [ ] [ 5 ] =
3711 { /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
3712 /* NULL */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3713 /* INITIALIZE */ { MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3714 /* DIALOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3715 /* DISCONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
3716 /* RESP: 0: OK */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3717 /* RESP: 1: CONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3718 /* RESP: 2: RING */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3719 /* RESP: 3: NO CARRIER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3720 /* RESP: 4: ERROR */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3721 /* RESP: 5: CONNECT X */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3722 /* RESP: 6: NO DAILTONE */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3723 /* RESP: 7: BUSY */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3724 /* RESP: 8: NO ANSWER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3725 /* RESP: 9: UNKNOWN */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3726 /* SILENT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3727 /* TIMEOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
3730 static short iModemSilentTimeout [ 5 ] = { 0, 0, 0, 0, 5 } ;
3731 static short iModemStateTimeout [ 5 ] = { 0, 20, 90, 0, 20 } ;
3733 #define STAY_MODEM_STATE 0
3734 #define CHANGE_MODEM_STATE 1
3737 #define DEBUG_MODEM_PRINTF(sFunc) { if ( debug ) { printf ( "refclock_jjy.c : %s : iModemState=%d iModemEvent=%d iModemSilentTimer=%d iModemStateTimer=%d\n", sFunc, up->iModemState, up->iModemEvent, up->iModemSilentTimer, up->iModemStateTimer ) ; } }
3739 #define DEBUG_MODEM_PRINTF(sFunc)
3742 /**************************************************************************************************/
3745 getModemState ( struct jjyunit *up )
3747 return up->iModemState ;
3750 /**************************************************************************************************/
3753 isModemStateConnect ( short iCheckState )
3755 return ( iCheckState == MODEM_STATE_CONNECT ) ;
3758 /**************************************************************************************************/
3761 isModemStateDisconnect ( short iCheckState )
3763 return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
3766 /**************************************************************************************************/
3769 isModemStateTimerOn ( struct jjyunit *up )
3771 return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
3774 /**************************************************************************************************/
3777 modem_connect ( int unit, struct peer *peer )
3779 struct refclockproc *pp;
3782 pp = peer->procptr ;
3785 DEBUG_MODEM_PRINTF( "modem_connect" ) ;
3787 up->iModemEvent = MODEM_EVENT_INITIALIZE ;
3789 modem_control ( peer, pp, up ) ;
3793 /**************************************************************************************************/
3796 modem_disconnect ( int unit, struct peer *peer )
3798 struct refclockproc *pp;
3801 pp = peer->procptr ;
3804 DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
3806 up->iModemEvent = MODEM_EVENT_DISCONNECT ;
3808 modem_control ( peer, pp, up ) ;
3812 /**************************************************************************************************/
3815 modem_receive ( struct recvbuf *rbufp )
3820 struct refclockproc *pp;
3825 static const char *sFunctionName = "modem_receive" ;
3828 peer = rbufp->recv_peer ;
3829 pp = peer->procptr ;
3832 DEBUG_MODEM_PRINTF( sFunctionName ) ;
3834 if ( up->linediscipline == LDISC_RAW ) {
3835 pBuf = up->sTextBuf ;
3836 iLen = up->iTextBufLen ;
3838 pBuf = pp->a_lastcode ;
3839 iLen = pp->lencode ;
3842 if ( iLen == 2 && strncmp( pBuf, "OK" , 2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK ; }
3843 else if ( iLen == 7 && strncmp( pBuf, "CONNECT" , 7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT ; }
3844 else if ( iLen == 4 && strncmp( pBuf, "RING" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING ; }
3845 else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER ; }
3846 else if ( iLen == 5 && strncmp( pBuf, "ERROR" , 5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR ; }
3847 else if ( iLen >= 8 && strncmp( pBuf, "CONNECT " , 8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X ; }
3848 else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
3849 else if ( iLen == 4 && strncmp( pBuf, "BUSY" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY ; }
3850 else if ( iLen == 9 && strncmp( pBuf, "NO ANSWER" , 9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER ; }
3851 else { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN ; }
3857 iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3858 strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3859 sResp[iCopyLen] = 0 ;
3860 printf ( "refclock_jjy.c : modem_receive : iLen=%d pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
3863 modem_control ( peer, pp, up ) ;
3869 /**************************************************************************************************/
3872 modem_timer ( int unit, struct peer *peer )
3875 struct refclockproc *pp ;
3876 struct jjyunit *up ;
3878 pp = peer->procptr ;
3881 DEBUG_MODEM_PRINTF( "modem_timer" ) ;
3883 if ( iModemSilentTimeout[up->iModemState] != 0 ) {
3884 up->iModemSilentTimer++ ;
3885 if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
3886 up->iModemEvent = MODEM_EVENT_SILENT ;
3887 modem_control ( peer, pp, up ) ;
3891 if ( iModemStateTimeout[up->iModemState] != 0 ) {
3892 up->iModemStateTimer++ ;
3893 if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
3894 up->iModemEvent = MODEM_EVENT_TIMEOUT ;
3895 modem_control ( peer, pp, up ) ;
3901 /**************************************************************************************************/
3904 modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3908 short iPostEvent = MODEM_EVENT_NULL ;
3910 DEBUG_MODEM_PRINTF( "modem_control" ) ;
3912 rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
3914 if ( rc == CHANGE_MODEM_STATE ) {
3915 iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
3918 printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d iPostEvent=%d\n",
3919 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
3923 if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
3924 up->iModemSilentCount = 0 ;
3925 up->iModemStateTimer = 0 ;
3926 up->iModemCommandSeq = 0 ;
3929 up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
3932 if ( iPostEvent != MODEM_EVENT_NULL ) {
3933 up->iModemEvent = iPostEvent ;
3934 modem_control ( peer, pp, up ) ;
3937 up->iModemEvent = MODEM_EVENT_NULL ;
3941 /******************************/
3943 modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3946 DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
3948 return STAY_MODEM_STATE ;
3952 /******************************/
3954 modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3957 DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
3959 return CHANGE_MODEM_STATE ;
3963 /******************************/
3965 modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3968 DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
3970 return STAY_MODEM_STATE ;
3974 /******************************/
3976 modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3979 DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
3981 up->iModemCommandSeq = 0 ;
3985 printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
3989 return modem_init_resp00( peer, pp, up ) ;
3993 /******************************/
3995 modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4001 int iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
4002 int iNextModemState = STAY_MODEM_STATE ;
4004 DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
4006 up->iModemCommandSeq++ ;
4008 switch ( up->iModemCommandSeq ) {
4011 /* En = Echoback 0:Off 1:On */
4012 /* Qn = Result codes 0:On 1:Off */
4013 /* Vn = Result codes 0:Numeric 1:Text */
4014 pCmd = "ATE0Q0V1\r\n" ;
4018 /* Mn = Speaker switch 0:Off 1:On until remote carrier detected 2:On */
4019 if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
4020 /* fudge 127.127.40.n flag3 0 */
4021 iSpeakerSwitch = 0 ;
4023 /* fudge 127.127.40.n flag3 1 */
4024 iSpeakerSwitch = 2 ;
4027 /* Ln = Speaker volume 0:Very low 1:Low 2:Middle 3:High */
4028 if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
4029 /* fudge 127.127.40.n flag4 0 */
4030 iSpeakerVolume = 1 ;
4032 /* fudge 127.127.40.n flag4 1 */
4033 iSpeakerVolume = 2 ;
4037 snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
4041 /* &Kn = Flow control 4:XON/XOFF */
4042 pCmd = "AT&K4\r\n" ;
4046 /* +MS = Protocol V22B:1200,2400bps
\81iV.22bis) */
4047 pCmd = "AT+MS=V22B\r\n" ;
4051 /* %Cn = Data compression 0:No data compression */
4052 pCmd = "AT%C0\r\n" ;
4056 /* \Nn = Error correction 0:Normal mode 1:Direct mode 2:V42,MNP 3:V42,MNP,Normal */
4057 if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
4058 /* fudge 127.127.40.n flag2 0 */
4059 iErrorCorrection = 0 ;
4061 /* fudge 127.127.40.n flag2 1 */
4062 iErrorCorrection = 3 ;
4066 snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
4070 /* Hn = Hook 0:Hook-On ( Disconnect ) 1:Hook-Off ( Connect ) */
4075 /* Initialize completion */
4077 iNextModemState = CHANGE_MODEM_STATE ;
4086 if ( pCmd != NULL ) {
4088 iCmdLen = strlen( pCmd ) ;
4089 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4090 refclock_report( peer, CEVNT_FAULT ) ;
4093 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4097 return iNextModemState ;
4101 /******************************/
4103 modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4106 DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
4108 return modem_init_resp00( peer, pp, up ) ;
4112 /******************************/
4114 modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4117 DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
4120 printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
4124 return CHANGE_MODEM_STATE ;
4128 /******************************/
4130 modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4133 DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
4135 return STAY_MODEM_STATE ;
4139 /******************************/
4141 modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4148 DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
4151 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
4152 /* fudge 127.127.40.n flag1 0 */
4153 cToneOrPulse = 'T' ;
4155 /* fudge 127.127.40.n flag1 1 */
4156 cToneOrPulse = 'P' ;
4159 /* Connect ( Dial number ) */
4160 snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
4163 iCmdLen = strlen( sCmd ) ;
4164 if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
4165 refclock_report( peer, CEVNT_FAULT ) ;
4168 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
4170 return STAY_MODEM_STATE ;
4174 /******************************/
4176 modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4179 DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
4182 printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
4186 return modem_conn_escape( peer, pp, up ) ;
4190 /******************************/
4192 modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4195 DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
4197 return CHANGE_MODEM_STATE ;
4201 /******************************/
4203 modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4206 DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
4209 printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
4213 modem_esc_disc( peer, pp, up ) ;
4215 return CHANGE_MODEM_STATE ;
4219 /******************************/
4221 modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4224 DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
4226 return STAY_MODEM_STATE ;
4230 /******************************/
4232 modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4235 DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
4237 return CHANGE_MODEM_STATE ;
4241 /******************************/
4243 modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4246 DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
4248 return STAY_MODEM_STATE ;
4252 /******************************/
4254 modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4260 DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
4262 /* Escape command ( Go to command mode ) */
4266 iCmdLen = strlen( pCmd ) ;
4267 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4268 refclock_report( peer, CEVNT_FAULT ) ;
4271 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4273 return STAY_MODEM_STATE ;
4277 /******************************/
4279 modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4282 DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
4284 up->iModemSilentTimer = 0 ;
4286 return STAY_MODEM_STATE ;
4290 /******************************/
4292 modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4295 DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
4297 up->iModemSilentCount ++ ;
4299 if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
4302 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
4305 modem_esc_escape( peer, pp, up ) ;
4306 up->iModemSilentTimer = 0 ;
4307 return STAY_MODEM_STATE ;
4312 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
4315 return modem_esc_disc( peer, pp, up ) ;
4318 /******************************/
4320 modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4326 DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
4332 iCmdLen = strlen( pCmd ) ;
4333 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4334 refclock_report( peer, CEVNT_FAULT ) ;
4337 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4339 return CHANGE_MODEM_STATE ;
4343 /*################################################################################################*/
4344 /*################################################################################################*/
4346 /*## jjy_write_clockstats ##*/
4348 /*################################################################################################*/
4349 /*################################################################################################*/
4352 jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
4356 const char * pMark ;
4357 int iMarkLen, iDataLen ;
4360 case JJY_CLOCKSTATS_MARK_JJY :
4363 case JJY_CLOCKSTATS_MARK_SEND :
4366 case JJY_CLOCKSTATS_MARK_RECEIVE :
4369 case JJY_CLOCKSTATS_MARK_INFORMATION :
4372 case JJY_CLOCKSTATS_MARK_ATTENTION :
4375 case JJY_CLOCKSTATS_MARK_WARNING :
4378 case JJY_CLOCKSTATS_MARK_ERROR :
4386 iDataLen = strlen( pData ) ;
4387 iMarkLen = strlen( pMark ) ;
4388 strcpy( sLog, pMark ) ; /* Harmless because of enough length */
4389 printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
4393 printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
4396 record_clock_stats( &peer->srcadr, sLog ) ;
4400 /*################################################################################################*/
4401 /*################################################################################################*/
4403 /*## printableString ##*/
4405 /*################################################################################################*/
4406 /*################################################################################################*/
4409 printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
4411 const char *printableControlChar[] = {
4412 "<NUL>", "<SOH>", "<STX>", "<ETX>",
4413 "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
4414 "<BS>" , "<HT>" , "<LF>" , "<VT>" ,
4415 "<FF>" , "<CR>" , "<SO>" , "<SI>" ,
4416 "<DLE>", "<DC1>", "<DC2>", "<DC3>",
4417 "<DC4>", "<NAK>", "<SYN>", "<ETB>",
4418 "<CAN>", "<EM>" , "<SUB>", "<ESC>",
4419 "<FS>" , "<GS>" , "<RS>" , "<US>" ,
4426 InputLen = (size_t)iInputLen;
4427 OutputLen = (size_t)iOutputLen;
4428 for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
4429 if ( isprint( (unsigned char)sInput[i] ) ) {
4431 if ( j + 1 >= OutputLen )
4433 sOutput[j] = sInput[i] ;
4434 } else if ( ( sInput[i] & 0xFF ) <
4435 COUNTOF(printableControlChar) ) {
4436 n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
4437 if ( j + n + 1 >= OutputLen )
4439 strlcpy( sOutput + j,
4440 printableControlChar[sInput[i] & 0xFF],
4444 if ( j + n + 1 >= OutputLen )
4446 snprintf( sOutput + j, OutputLen - j, "<x%X>",
4447 sInput[i] & 0xFF ) ;
4452 sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
4456 /**************************************************************************************************/
4459 int refclock_jjy_bs ;
4460 #endif /* REFCLOCK */