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 */
110 /* [Fix] C-DEX JST2000 */
111 /* Thanks to Mr. Kuramatsu for the report and the patch. */
113 /**********************************************************************/
119 #if defined(REFCLOCK) && defined(CLOCK_JJY)
124 #include <sys/time.h>
130 #include "ntp_refclock.h"
131 #include "ntp_calendar.h"
132 #include "ntp_stdlib.h"
134 /**********************************************************************/
137 * Interface definitions
139 #define DEVICE "/dev/jjy%d" /* device name and unit */
140 #define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
141 #define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
142 #define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
143 #define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
144 #define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */
145 #define SPEED232_SEIKO_TIMESYS_TDC_300 B2400 /* UART speed (2400 baud) */
146 #define SPEED232_TELEPHONE B2400 /* UART speed (4800 baud) */
147 #define REFID "JJY" /* reference ID */
148 #define DESCRIPTION "JJY Receiver"
149 #define PRECISION (-3) /* precision assumed (about 100 ms) */
152 * JJY unit control structure
155 struct jjyRawDataBreak {
156 const char * pString ;
160 #define MAX_TIMESTAMP 6
161 #define MAX_RAWBUF 100
162 #define MAX_LOOPBACK 5
165 /* Set up by the function "jjy_start_xxxxxxxx" */
166 char unittype ; /* UNITTYPE_XXXXXXXXXX */
167 short operationmode ; /* Echo Keisokuki LT-2000 */
168 int linespeed ; /* SPEED232_XXXXXXXXXX */
169 short linediscipline ; /* LDISC_CLK or LDISC_RAW */
171 char bInitError ; /* Set by jjy_start if any error during initialization */
172 short iProcessState ; /* JJY_PROCESS_STATE_XXXXXX */
173 char bReceiveFlag ; /* Set and reset by jjy_receive */
174 char bLineError ; /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/
175 short iCommandSeq ; /* 0:Idle Non-Zero:Issued */
178 int year, month, day, hour, minute, second, msecond ;
180 int iTimestampCount ; /* TS-JJY01, TS-GPS01, Telephone-JJY */
181 int iTimestamp [ MAX_TIMESTAMP ] ; /* Serial second ( 0 - 86399 ) */
183 char sRawBuf [ MAX_RAWBUF ] ;
185 struct jjyRawDataBreak *pRawBreak ;
186 char bWaitBreakString ;
187 char sLineBuf [ MAX_RAWBUF ] ;
189 char sTextBuf [ MAX_RAWBUF ] ;
191 char bSkipCntrlCharOnly ;
192 /* Telephone JJY auto measurement of the loopback delay */
194 short iLoopbackCount ;
195 struct timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ;
196 char bLoopbackTimeout[MAX_LOOPBACK] ;
197 short iLoopbackValidCount ;
198 /* Telephone JJY timer */
199 short iTeljjySilentTimer ;
200 short iTeljjyStateTimer ;
201 /* Telephone JJY control finite state machine */
204 short iClockCommandSeq ;
206 short iModemSilentCount ;
207 short iModemSilentTimer ;
208 short iModemStateTimer ;
209 /* Modem control finite state machine */
212 short iModemCommandSeq ;
215 #define UNITTYPE_TRISTATE_JJY01 1
216 #define UNITTYPE_CDEX_JST2000 2
217 #define UNITTYPE_ECHOKEISOKUKI_LT2000 3
218 #define UNITTYPE_CITIZENTIC_JJY200 4
219 #define UNITTYPE_TRISTATE_GPSCLOCK01 5
220 #define UNITTYPE_SEIKO_TIMESYS_TDC_300 6
221 #define UNITTYPE_TELEPHONE 100
223 #define JJY_PROCESS_STATE_IDLE 0
224 #define JJY_PROCESS_STATE_POLL 1
225 #define JJY_PROCESS_STATE_RECEIVE 2
226 #define JJY_PROCESS_STATE_DONE 3
227 #define JJY_PROCESS_STATE_ERROR 4
229 /**********************************************************************/
232 * Function calling structure
235 * |-- jjy_start_tristate_jjy01
236 * |-- jjy_start_cdex_jst2000
237 * |-- jjy_start_echokeisokuki_lt2000
238 * |-- jjy_start_citizentic_jjy200
239 * |-- jjy_start_tristate_gpsclock01
240 * |-- jjy_start_seiko_tsys_tdc_300
241 * |-- jjy_start_telephone
246 * |-- jjy_poll_tristate_jjy01
247 * |-- jjy_poll_cdex_jst2000
248 * |-- jjy_poll_echokeisokuki_lt2000
249 * |-- jjy_poll_citizentic_jjy200
250 * |-- jjy_poll_tristate_gpsclock01
251 * |-- jjy_poll_seiko_tsys_tdc_300
252 * |-- jjy_poll_telephone
254 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
257 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
261 * |-- jjy_receive_tristate_jjy01
263 * |-- jjy_receive_cdex_jst2000
265 * |-- jjy_receive_echokeisokuki_lt2000
267 * |-- jjy_receive_citizentic_jjy200
269 * |-- jjy_receive_tristate_gpsclock01
271 * |-- jjy_receive_seiko_tsys_tdc_300
273 * |-- jjy_receive_telephone
275 * | |-- modem_control
276 * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
278 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
280 * |-- modem_disconnect
282 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
285 * |-- jjy_timer_telephone
287 * | |-- modem_control
288 * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
290 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
291 * |-- modem_disconnect
293 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
295 * Function prototypes
298 static int jjy_start (int, struct peer *);
299 static int jjy_start_tristate_jjy01 (int, struct peer *, struct jjyunit *);
300 static int jjy_start_cdex_jst2000 (int, struct peer *, struct jjyunit *);
301 static int jjy_start_echokeisokuki_lt2000 (int, struct peer *, struct jjyunit *);
302 static int jjy_start_citizentic_jjy200 (int, struct peer *, struct jjyunit *);
303 static int jjy_start_tristate_gpsclock01 (int, struct peer *, struct jjyunit *);
304 static int jjy_start_seiko_tsys_tdc_300 (int, struct peer *, struct jjyunit *);
305 static int jjy_start_telephone (int, struct peer *, struct jjyunit *);
307 static void jjy_shutdown (int, struct peer *);
309 static void jjy_poll (int, struct peer *);
310 static void jjy_poll_tristate_jjy01 (int, struct peer *);
311 static void jjy_poll_cdex_jst2000 (int, struct peer *);
312 static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *);
313 static void jjy_poll_citizentic_jjy200 (int, struct peer *);
314 static void jjy_poll_tristate_gpsclock01 (int, struct peer *);
315 static void jjy_poll_seiko_tsys_tdc_300 (int, struct peer *);
316 static void jjy_poll_telephone (int, struct peer *);
318 static void jjy_receive (struct recvbuf *);
319 static int jjy_receive_tristate_jjy01 (struct recvbuf *);
320 static int jjy_receive_cdex_jst2000 (struct recvbuf *);
321 static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
322 static int jjy_receive_citizentic_jjy200 (struct recvbuf *);
323 static int jjy_receive_tristate_gpsclock01 (struct recvbuf *);
324 static int jjy_receive_seiko_tsys_tdc_300 (struct recvbuf *);
325 static int jjy_receive_telephone (struct recvbuf *);
327 static void jjy_timer (int, struct peer *);
328 static void jjy_timer_telephone (int, struct peer *);
330 static void jjy_synctime ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
331 static void jjy_write_clockstats ( struct peer *, int, const char* ) ;
333 static int getRawDataBreakPosition ( struct jjyunit *, int ) ;
335 static short getModemState ( struct jjyunit * ) ;
336 static int isModemStateConnect ( short ) ;
337 static int isModemStateDisconnect ( short ) ;
338 static int isModemStateTimerOn ( struct jjyunit * ) ;
339 static void modem_connect ( int, struct peer * ) ;
340 static void modem_disconnect ( int, struct peer * ) ;
341 static int modem_receive ( struct recvbuf * ) ;
342 static void modem_timer ( int, struct peer * );
344 static void printableString ( char*, int, const char*, int ) ;
349 struct refclock refclock_jjy = {
350 jjy_start, /* start up driver */
351 jjy_shutdown, /* shutdown driver */
352 jjy_poll, /* transmit poll message */
353 noentry, /* not used */
354 noentry, /* not used */
355 noentry, /* not used */
356 jjy_timer /* 1 second interval timer */
360 * Start up driver return code
362 #define RC_START_SUCCESS 1
363 #define RC_START_ERROR 0
366 * Local constants definition
369 #define MAX_LOGTEXT 100
375 #define FALSE (!TRUE)
378 /* Local constants definition for the return code of the jjy_receive_xxxxxxxx */
380 #define JJY_RECEIVE_DONE 0
381 #define JJY_RECEIVE_SKIP 1
382 #define JJY_RECEIVE_UNPROCESS 2
383 #define JJY_RECEIVE_WAIT 3
384 #define JJY_RECEIVE_ERROR 4
386 /* Local constants definition for the 2nd parameter of the jjy_write_clockstats */
388 #define JJY_CLOCKSTATS_MARK_NONE 0
389 #define JJY_CLOCKSTATS_MARK_JJY 1
390 #define JJY_CLOCKSTATS_MARK_SEND 2
391 #define JJY_CLOCKSTATS_MARK_RECEIVE 3
392 #define JJY_CLOCKSTATS_MARK_INFORMATION 4
393 #define JJY_CLOCKSTATS_MARK_ATTENTION 5
394 #define JJY_CLOCKSTATS_MARK_WARNING 6
395 #define JJY_CLOCKSTATS_MARK_ERROR 7
397 /* Local constants definition for the clockstats messages */
399 #define JJY_CLOCKSTATS_MESSAGE_ECHOBACK "* Echoback"
400 #define JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY "* Ignore replay : [%s]"
401 #define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2 "* Over midnight : timestamp=%d, %d"
402 #define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3 "* Over midnight : timestamp=%d, %d, %d"
403 #define JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE "* Unsure timestamp : %s"
404 #define JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY "* Loopback delay : %d.%03d mSec."
405 #define JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST "* Delay adjustment : %d mSec. ( valid=%hd/%d )"
406 #define JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST "* Delay adjustment : None ( valid=%hd/%d )"
408 #define JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY "# Unexpected reply : [%s]"
409 #define JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH "# Invalid length : length=%d"
410 #define JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY "# Too many reply : count=%d"
411 #define JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY "# Invalid reply : [%s]"
412 #define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2 "# Slow reply : timestamp=%d, %d"
413 #define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3 "# Slow reply : timestamp=%d, %d, %d"
414 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE "# Invalid date : rc=%d year=%d month=%d day=%d"
415 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME "# Invalid time : rc=%d hour=%d minute=%d second=%d"
416 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME "# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d"
417 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP "# Invalid leap : leapsecond=[%s]"
418 #define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS "# Invalid status : status=[%s]"
420 /* Debug print macro */
423 #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 ) ; } }
425 #define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)
428 /**************************************************************************************************/
429 /* jjy_start - open the devices and initialize data for processing */
430 /**************************************************************************************************/
432 jjy_start ( int unit, struct peer *peer )
435 struct refclockproc *pp ;
439 char sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ;
443 printf( "refclock_jjy.c : jjy_start : %s mode=%d dev=%s unit=%d\n",
444 ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ;
448 /* Allocate memory for the unit structure */
449 up = emalloc( sizeof(*up) ) ;
451 msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ;
452 return RC_START_ERROR ;
454 memset ( up, 0, sizeof(*up) ) ;
456 up->bInitError = FALSE ;
457 up->iProcessState = JJY_PROCESS_STATE_IDLE ;
458 up->bReceiveFlag = FALSE ;
459 up->iCommandSeq = 0 ;
461 up->iTimestampCount = 0 ;
462 up->bWaitBreakString = FALSE ;
463 up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ;
464 up->bSkipCntrlCharOnly = TRUE ;
466 /* Set up the device name */
467 snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ;
469 snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ;
470 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
473 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
475 switch ( peer->ttl ) {
478 rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ;
481 rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ;
484 rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ;
487 rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ;
490 rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ;
493 rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ;
496 rc = jjy_start_telephone ( unit, peer, up ) ;
499 if ( 101 <= peer->ttl && peer->ttl <= 180 ) {
500 rc = jjy_start_telephone ( unit, peer, up ) ;
502 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
503 ntoa(&peer->srcadr), peer->ttl ) ;
504 free ( (void*) up ) ;
505 return RC_START_ERROR ;
510 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error",
511 ntoa(&peer->srcadr), peer->ttl ) ;
512 free ( (void*) up ) ;
513 return RC_START_ERROR ;
516 /* Open the device */
517 fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ;
519 free ( (void*) up ) ;
520 return RC_START_ERROR ;
524 * Initialize variables
528 pp->clockdesc = DESCRIPTION ;
530 pp->io.clock_recv = jjy_receive ;
531 pp->io.srcclock = peer ;
534 if ( ! io_addclock(&pp->io) ) {
539 return RC_START_ERROR ;
541 memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ;
543 peer->precision = PRECISION ;
545 snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ;
546 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
548 return RC_START_SUCCESS ;
552 /**************************************************************************************************/
553 /* jjy_shutdown - shutdown the clock */
554 /**************************************************************************************************/
556 jjy_shutdown ( int unit, struct peer *peer )
560 struct refclockproc *pp;
566 if ( -1 != pp->io.fd ) {
567 io_closeclock ( &pp->io ) ;
573 snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ;
574 record_clock_stats( &peer->srcadr, sLog ) ;
578 /**************************************************************************************************/
579 /* jjy_receive - receive data from the serial interface */
580 /**************************************************************************************************/
582 jjy_receive ( struct recvbuf *rbufp )
585 static const char *sFunctionName = "jjy_receive" ;
589 struct refclockproc *pp ;
592 l_fp tRecvTimestamp; /* arrival timestamp */
594 char *pBuf, sLogText [ MAX_LOGTEXT ] ;
595 size_t iLen, iCopyLen ;
596 int i, j, iReadRawBuf, iBreakPosition ;
599 * Initialize pointers and read the timecode and timestamp
601 peer = rbufp->recv_peer ;
606 * Get next input line
608 if ( up->linediscipline == LDISC_RAW ) {
610 pp->lencode = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ;
611 /* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions (OVERRUN)" */
612 /* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */
613 /* To avoid its claim, pass the value BMAX-1. */
616 * Append received charaters to temporary buffer
619 i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ;
620 i ++ , up->iRawBufLen ++ ) {
621 up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ;
623 up->sRawBuf[up->iRawBufLen] = 0 ;
628 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
632 printf( "\nrefclock_jjy.c : %s : Len=%d ", sFunctionName, pp->lencode ) ;
633 for ( i = 0 ; i < pp->lencode ; i ++ ) {
634 if ( iscntrl( (u_char)(pp->a_lastcode[i] & 0x7F) ) ) {
635 printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ;
637 printf( "%c", pp->a_lastcode[i] ) ;
644 * The reply with <CR><LF> gives a blank line
647 if ( pp->lencode == 0 ) return ;
650 * Receiving data is not expected
653 if ( up->iProcessState == JJY_PROCESS_STATE_IDLE
654 || up->iProcessState == JJY_PROCESS_STATE_DONE
655 || up->iProcessState == JJY_PROCESS_STATE_ERROR ) {
656 /* Discard received data */
660 printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ;
667 * We get down to business
670 pp->lastrec = tRecvTimestamp ;
674 up->iProcessState = JJY_PROCESS_STATE_RECEIVE ;
675 up->bReceiveFlag = TRUE ;
678 iBreakPosition = up->iRawBufLen - 1 ;
679 for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) {
681 if ( up->linediscipline == LDISC_RAW ) {
683 if ( up->bWaitBreakString ) {
684 iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ;
685 if ( iBreakPosition == -1 ) {
686 /* Break string have not come yet */
687 if ( up->iRawBufLen < MAX_RAWBUF - 2
688 || iReadRawBuf > 0 ) {
689 /* Temporary buffer is not full */
692 /* Temporary buffer is full */
693 iBreakPosition = up->iRawBufLen - 1 ;
697 iBreakPosition = up->iRawBufLen - 1 ;
700 /* Copy charaters from temporary buffer to process buffer */
701 up->iLineBufLen = up->iTextBufLen = 0 ;
702 for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) {
704 /* Copy all characters */
705 up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ;
708 /* Copy printable characters */
709 if ( ! iscntrl( (u_char)up->sRawBuf[i] ) ) {
710 up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ;
715 up->sLineBuf[up->iLineBufLen] = 0 ;
716 up->sTextBuf[up->iTextBufLen] = 0 ;
718 printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n",
719 sFunctionName, up->iLineBufLen, up->iTextBufLen ) ;
722 if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) {
724 printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n",
725 sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ;
727 if ( iBreakPosition + 1 < up->iRawBufLen ) {
728 iReadRawBuf = iBreakPosition + 1 ;
738 if ( up->linediscipline == LDISC_RAW ) {
739 pBuf = up->sLineBuf ;
740 iLen = up->iLineBufLen ;
742 pBuf = pp->a_lastcode ;
746 iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ;
747 memcpy( sLogText, pBuf, iCopyLen ) ;
748 sLogText[iCopyLen] = '\0' ;
749 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ;
751 switch ( up->unittype ) {
753 case UNITTYPE_TRISTATE_JJY01 :
754 rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
757 case UNITTYPE_CDEX_JST2000 :
758 rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
761 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
762 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
765 case UNITTYPE_CITIZENTIC_JJY200 :
766 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
769 case UNITTYPE_TRISTATE_GPSCLOCK01 :
770 rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
773 case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
774 rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ;
777 case UNITTYPE_TELEPHONE :
778 rc = jjy_receive_telephone ( rbufp ) ;
782 rc = JJY_RECEIVE_ERROR ;
788 case JJY_RECEIVE_DONE :
789 case JJY_RECEIVE_SKIP :
790 up->iProcessState = JJY_PROCESS_STATE_DONE ;
792 case JJY_RECEIVE_ERROR :
793 up->iProcessState = JJY_PROCESS_STATE_ERROR ;
799 if ( up->linediscipline == LDISC_RAW ) {
800 if ( rc == JJY_RECEIVE_UNPROCESS ) {
803 iReadRawBuf = iBreakPosition + 1 ;
804 if ( iReadRawBuf >= up->iRawBufLen ) {
805 /* Processed all received data */
810 if ( up->linediscipline == LDISC_CLK ) {
816 if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) {
817 for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) {
818 up->sRawBuf[i] = up->sRawBuf[j] ;
820 up->iRawBufLen -= iReadRawBuf ;
821 if ( up->iRawBufLen < 0 ) {
826 up->bReceiveFlag = FALSE ;
830 /**************************************************************************************************/
833 getRawDataBreakPosition ( struct jjyunit *up, int iStart )
838 if ( iStart >= up->iRawBufLen ) {
840 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
845 for ( i = iStart ; i < up->iRawBufLen ; i ++ ) {
847 for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) {
849 if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) {
851 if ( strncmp( up->sRawBuf + i,
852 up->pRawBreak[j].pString,
853 up->pRawBreak[j].iLength ) == 0 ) {
856 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n",
857 iStart, i + up->pRawBreak[j].iLength - 1 ) ;
859 return i + up->pRawBreak[j].iLength - 1 ;
867 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
873 /**************************************************************************************************/
874 /* jjy_poll - called by the transmit procedure */
875 /**************************************************************************************************/
877 jjy_poll ( int unit, struct peer *peer )
880 char sLog [ 40 ], sReach [ 9 ] ;
883 struct refclockproc *pp;
888 if ( up->bInitError ) {
889 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ;
893 if ( pp->polls > 0 && up->iLineCount == 0 ) {
895 * No reply for last command
897 refclock_report ( peer, CEVNT_TIMEOUT ) ;
902 sReach[0] = peer->reach & 0x80 ? '1' : '0' ;
903 sReach[1] = peer->reach & 0x40 ? '1' : '0' ;
904 sReach[2] = peer->reach & 0x20 ? '1' : '0' ;
905 sReach[3] = peer->reach & 0x10 ? '1' : '0' ;
906 sReach[4] = peer->reach & 0x08 ? '1' : '0' ;
907 sReach[5] = peer->reach & 0x04 ? '1' : '0' ;
908 sReach[6] = peer->reach & 0x02 ? '1' : '0' ;
909 sReach[7] = 0 ; /* This poll */
912 snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ;
913 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
915 up->iProcessState = JJY_PROCESS_STATE_POLL ;
916 up->iCommandSeq = 0 ;
917 up->iReceiveSeq = 0 ;
919 up->bLineError = FALSE ;
922 switch ( up->unittype ) {
924 case UNITTYPE_TRISTATE_JJY01 :
925 jjy_poll_tristate_jjy01 ( unit, peer ) ;
928 case UNITTYPE_CDEX_JST2000 :
929 jjy_poll_cdex_jst2000 ( unit, peer ) ;
932 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
933 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
936 case UNITTYPE_CITIZENTIC_JJY200 :
937 jjy_poll_citizentic_jjy200 ( unit, peer ) ;
940 case UNITTYPE_TRISTATE_GPSCLOCK01 :
941 jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
944 case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
945 jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ;
948 case UNITTYPE_TELEPHONE :
949 jjy_poll_telephone ( unit, peer ) ;
959 /**************************************************************************************************/
960 /* jjy_timer - called at one-second intervals */
961 /**************************************************************************************************/
963 jjy_timer ( int unit, struct peer *peer )
966 struct refclockproc *pp ;
971 printf ( "refclock_jjy.c : jjy_timer\n" ) ;
978 if ( up->bReceiveFlag ) {
981 printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ;
987 switch ( up->unittype ) {
989 case UNITTYPE_TELEPHONE :
990 jjy_timer_telephone ( unit, peer ) ;
1000 /**************************************************************************************************/
1002 /**************************************************************************************************/
1004 jjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
1007 char sLog [ 80 ], cStatus ;
1008 const char *pStatus ;
1010 pp->year = up->year ;
1011 pp->day = ymd2yd( up->year, up->month, up->day ) ;
1012 pp->hour = up->hour ;
1013 pp->minute = up->minute ;
1014 pp->second = up->second ;
1015 pp->nsec = up->msecond * 1000000 ;
1021 if ( pp->hour < 0 ) {
1024 if ( pp->day < 1 ) {
1026 pp->day = ymd2yd( pp->year, 12, 31 ) ;
1031 * Process the new sample in the median filter and determine the
1032 * timecode timestamp.
1035 if ( ! refclock_process( pp ) ) {
1036 refclock_report( peer, CEVNT_BADTIME ) ;
1040 pp->lastref = pp->lastrec ;
1042 refclock_receive( peer ) ;
1045 * Write into the clockstats file
1047 snprintf ( sLog, sizeof(sLog),
1048 "%04d/%02d/%02d %02d:%02d:%02d.%03d JST ( %04d/%03d %02d:%02d:%02d.%03d UTC )",
1049 up->year, up->month, up->day,
1050 up->hour, up->minute, up->second, up->msecond,
1051 pp->year, pp->day, pp->hour, pp->minute, pp->second,
1052 (int)(pp->nsec/1000000) ) ;
1053 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
1058 switch ( peer->status ) {
1059 case 0 : cStatus = ' ' ; pStatus = "Reject" ; break ;
1060 case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ;
1061 case 2 : cStatus = '.' ; pStatus = "Excess" ; break ;
1062 case 3 : cStatus = '-' ; pStatus = "Outlier" ; break ;
1063 case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ;
1064 case 5 : cStatus = '#' ; pStatus = "Selected" ; break ;
1065 case 6 : cStatus = '*' ; pStatus = "Sys.Peer" ; break ;
1066 case 7 : cStatus = 'o' ; pStatus = "PPS.Peer" ; break ;
1070 snprintf ( sLog, sizeof(sLog),
1071 "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.",
1072 peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ;
1073 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1077 /*################################################################################################*/
1078 /*################################################################################################*/
1080 /*## The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02 ##*/
1082 /*## server 127.127.40.X mode 1 ##*/
1084 /*################################################################################################*/
1085 /*################################################################################################*/
1087 /* Command Response Remarks */
1088 /* -------------------- ---------------------------------------- ---------------------------- */
1089 /* dcst<CR><LF> VALID<CR><LF> or INVALID<CR><LF> */
1090 /* stus<CR><LF> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
1091 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> XXX is the day of the week */
1092 /* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */
1093 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
1095 /*################################################################################################*/
1097 #define TS_JJY01_COMMAND_NUMBER_DATE 1
1098 #define TS_JJY01_COMMAND_NUMBER_TIME 2
1099 #define TS_JJY01_COMMAND_NUMBER_STIM 3
1100 #define TS_JJY01_COMMAND_NUMBER_STUS 4
1101 #define TS_JJY01_COMMAND_NUMBER_DCST 5
1103 #define TS_JJY01_REPLY_DATE "yyyy/mm/dd www"
1104 #define TS_JJY01_REPLY_STIM "hh:mm:ss"
1105 #define TS_JJY01_REPLY_STUS_ADJUSTED "adjusted"
1106 #define TS_JJY01_REPLY_STUS_UNADJUSTED "unadjusted"
1107 #define TS_JJY01_REPLY_DCST_VALID "valid"
1108 #define TS_JJY01_REPLY_DCST_INVALID "invalid"
1110 #define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */
1111 #define TS_JJY01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
1112 #define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */
1113 #define TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED 8 /* Length without <CR><LF> */
1114 #define TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED 10 /* Length without <CR><LF> */
1115 #define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */
1116 #define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */
1120 const char commandNumber ;
1121 const char *command ;
1123 int iExpectedReplyLength [ 2 ] ;
1124 } tristate_jjy01_command_sequence[] =
1126 { 0, NULL, 0, { 0, 0 } }, /* Idle */
1127 { TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID , TS_JJY01_REPLY_LENGTH_DCST_INVALID } },
1128 { TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } },
1129 { TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME , TS_JJY01_REPLY_LENGTH_TIME } },
1130 { TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE , TS_JJY01_REPLY_LENGTH_DATE } },
1131 { TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM , TS_JJY01_REPLY_LENGTH_STIM } },
1132 /* End of command */
1133 { 0, NULL, 0, { 0, 0 } }
1136 /**************************************************************************************************/
1139 jjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up )
1142 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ;
1144 up->unittype = UNITTYPE_TRISTATE_JJY01 ;
1145 up->linespeed = SPEED232_TRISTATE_JJY01 ;
1146 up->linediscipline = LDISC_CLK ;
1152 /**************************************************************************************************/
1155 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
1157 struct jjyunit *up ;
1158 struct refclockproc *pp ;
1169 /* Initialize pointers */
1171 peer = rbufp->recv_peer ;
1172 pp = peer->procptr ;
1175 if ( up->linediscipline == LDISC_RAW ) {
1176 pBuf = up->sTextBuf ;
1177 iLen = up->iTextBufLen ;
1179 pBuf = pp->a_lastcode ;
1180 iLen = pp->lencode ;
1183 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
1185 /* Check expected reply */
1187 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1188 /* Command sequence has not been started, or has been completed */
1189 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1191 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1192 up->bLineError = TRUE ;
1193 return JJY_RECEIVE_ERROR ;
1196 /* Check reply length */
1198 if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
1199 && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
1200 /* Unexpected reply length */
1201 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1203 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1204 up->bLineError = TRUE ;
1205 return JJY_RECEIVE_ERROR ;
1210 switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
1212 case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
1214 rc = sscanf ( pBuf, "%4d/%2d/%2d",
1215 &up->year, &up->month, &up->day ) ;
1217 if ( rc != 3 || up->year < 2000 || 2099 <= up->year
1218 || up->month < 1 || 12 < up->month
1219 || up->day < 1 || 31 < up->day ) {
1221 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
1222 rc, up->year, up->month, up->day ) ;
1223 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1224 up->bLineError = TRUE ;
1225 return JJY_RECEIVE_ERROR ;
1230 case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1231 case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
1233 if ( up->iTimestampCount >= 2 ) {
1234 /* Too many time reply */
1235 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
1236 up->iTimestampCount ) ;
1237 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1238 up->bLineError = TRUE ;
1239 return JJY_RECEIVE_ERROR ;
1242 rc = sscanf ( pBuf, "%2d:%2d:%2d",
1243 &up->hour, &up->minute, &up->second ) ;
1245 if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
1248 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
1249 rc, up->hour, up->minute, up->second ) ;
1250 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1251 up->bLineError = TRUE ;
1252 return JJY_RECEIVE_ERROR ;
1255 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
1257 up->iTimestampCount++ ;
1263 case TS_JJY01_COMMAND_NUMBER_STUS :
1265 if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
1266 TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0
1267 || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
1268 TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
1271 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1273 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1274 up->bLineError = TRUE ;
1275 return JJY_RECEIVE_ERROR ;
1280 case TS_JJY01_COMMAND_NUMBER_DCST :
1282 if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
1283 TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
1284 || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
1285 TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
1288 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1290 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1291 up->bLineError = TRUE ;
1292 return JJY_RECEIVE_ERROR ;
1297 default : /* Unexpected reply */
1299 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1301 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1302 up->bLineError = TRUE ;
1303 return JJY_RECEIVE_ERROR ;
1307 if ( up->iTimestampCount == 2 ) {
1308 /* Process date and time */
1310 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
1311 && up->iTimestamp[0] <= up->iTimestamp[1] ) {
1312 /* 3 commands (time,date,stim) was excuted in two seconds */
1313 jjy_synctime( peer, pp, up ) ;
1314 return JJY_RECEIVE_DONE ;
1315 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
1316 /* Over midnight, and date is unsure */
1317 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
1318 up->iTimestamp[0], up->iTimestamp[1] ) ;
1319 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1320 return JJY_RECEIVE_SKIP ;
1323 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
1324 up->iTimestamp[0], up->iTimestamp[1] ) ;
1325 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1326 up->bLineError = TRUE ;
1327 return JJY_RECEIVE_ERROR ;
1332 /* Issue next command */
1334 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
1335 up->iCommandSeq ++ ;
1338 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1339 /* Command sequence completed */
1340 return JJY_RECEIVE_DONE ;
1343 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1344 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1345 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1346 refclock_report ( peer, CEVNT_FAULT ) ;
1349 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1351 return JJY_RECEIVE_WAIT ;
1355 /**************************************************************************************************/
1358 jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
1361 static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1364 struct refclockproc *pp ;
1365 struct jjyunit *up ;
1373 up->bLineError = FALSE ;
1374 up->iTimestampCount = 0 ;
1376 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1377 /* Skip "dcst" and "stus" commands */
1378 up->iCommandSeq = 2 ;
1379 up->iLineCount = 2 ;
1384 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
1385 sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1391 * Send a first command
1394 up->iCommandSeq ++ ;
1396 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1397 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1398 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1399 refclock_report ( peer, CEVNT_FAULT ) ;
1402 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1406 /*################################################################################################*/
1407 /*################################################################################################*/
1409 /*## The C-DEX Co. Ltd. JJY receiver JST2000 ##*/
1411 /*## server 127.127.40.X mode 2 ##*/
1413 /*################################################################################################*/
1414 /*################################################################################################*/
1416 /* Command Response Remarks */
1417 /* -------------------- ---------------------------------------- ---------------------------- */
1418 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> J is a fixed character */
1420 /*################################################################################################*/
1422 static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
1424 { "\x03", 1 }, { NULL, 0 }
1427 /**************************************************************************************************/
1430 jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
1433 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
1435 up->unittype = UNITTYPE_CDEX_JST2000 ;
1436 up->linespeed = SPEED232_CDEX_JST2000 ;
1437 up->linediscipline = LDISC_RAW ;
1439 up->pRawBreak = cdex_jst2000_raw_break ;
1440 up->bWaitBreakString = TRUE ;
1442 up->bSkipCntrlCharOnly = FALSE ;
1448 /**************************************************************************************************/
1451 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
1454 struct jjyunit *up ;
1455 struct refclockproc *pp ;
1458 char *pBuf, sLog [ 100 ] ;
1462 /* Initialize pointers */
1464 peer = rbufp->recv_peer ;
1465 pp = peer->procptr ;
1468 if ( up->linediscipline == LDISC_RAW ) {
1469 pBuf = up->sTextBuf ;
1470 iLen = up->iTextBufLen ;
1472 pBuf = pp->a_lastcode ;
1473 iLen = pp->lencode ;
1476 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
1478 /* Check expected reply */
1480 if ( up->iCommandSeq != 1 ) {
1481 /* Command sequence has not been started, or has been completed */
1482 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1484 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1485 up->bLineError = TRUE ;
1486 return JJY_RECEIVE_ERROR ;
1489 /* Wait until ETX comes */
1491 if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
1492 return JJY_RECEIVE_UNPROCESS ;
1495 /* Check reply length */
1498 /* Unexpected reply length */
1499 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1501 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1502 up->bLineError = TRUE ;
1503 return JJY_RECEIVE_ERROR ;
1506 /* JYYMMDDWHHMMSSS */
1508 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
1509 &up->year, &up->month, &up->day,
1510 &up->hour, &up->minute, &up->second,
1513 if ( rc != 7 || up->month < 1 || up->month > 12 ||
1514 up->day < 1 || up->day > 31 || up->hour > 23 ||
1515 up->minute > 59 || up->second > 60 ) {
1516 /* Invalid date and time */
1517 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1518 rc, up->year, up->month, up->day,
1519 up->hour, up->minute, up->second ) ;
1520 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1521 up->bLineError = TRUE ;
1522 return JJY_RECEIVE_ERROR ;
1526 up->msecond *= 100 ;
1528 jjy_synctime( peer, pp, up ) ;
1530 return JJY_RECEIVE_DONE ;
1534 /**************************************************************************************************/
1537 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1540 struct refclockproc *pp ;
1541 struct jjyunit *up ;
1543 pp = peer->procptr ;
1546 up->bLineError = FALSE ;
1547 up->iRawBufLen = 0 ;
1548 up->iLineBufLen = 0 ;
1549 up->iTextBufLen = 0 ;
1552 * Send "<ENQ>1J<ETX>" command
1555 up->iCommandSeq ++ ;
1557 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
1558 refclock_report ( peer, CEVNT_FAULT ) ;
1561 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
1565 /*################################################################################################*/
1566 /*################################################################################################*/
1568 /*## The Echo Keisokuki Co. Ltd. JJY receiver LT2000 ##*/
1570 /*## server 127.127.40.X mode 3 ##*/
1572 /*################################################################################################*/
1573 /*################################################################################################*/
1575 /* Command Response Remarks */
1576 /* -------------------- ---------------------------------------- ---------------------------- */
1577 /* # Mode 1 ( Request & Send ) */
1578 /* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
1579 /* C Mode 2 ( Continuous ) */
1580 /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> 0.5 sec before time stamp */
1581 /* <SUB> Second signal */
1583 /*################################################################################################*/
1585 #define ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1
1586 #define ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 2
1587 #define ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 3
1589 #define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND "#"
1590 #define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME "T"
1591 #define ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS "C"
1593 /**************************************************************************************************/
1596 jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
1599 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
1601 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
1602 up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
1603 up->linediscipline = LDISC_CLK ;
1605 up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
1611 /**************************************************************************************************/
1614 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1617 struct jjyunit *up ;
1618 struct refclockproc *pp ;
1621 char *pBuf, sLog [ 100 ], sErr [ 60 ] ;
1624 int i, ibcc, ibcc1, ibcc2 ;
1626 /* Initialize pointers */
1628 peer = rbufp->recv_peer ;
1629 pp = peer->procptr ;
1632 if ( up->linediscipline == LDISC_RAW ) {
1633 pBuf = up->sTextBuf ;
1634 iLen = up->iTextBufLen ;
1636 pBuf = pp->a_lastcode ;
1637 iLen = pp->lencode ;
1640 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
1642 /* Check reply length */
1644 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1646 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1648 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1650 /* Unexpected reply length */
1651 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1653 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1654 up->bLineError = TRUE ;
1655 return JJY_RECEIVE_ERROR ;
1658 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
1659 /* YYMMDDWHHMMSS<BCC1><BCC2> */
1661 for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
1665 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1666 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
1667 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1668 snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
1669 pBuf[13] & 0xFF, pBuf[14] & 0xFF,
1671 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1673 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1674 up->bLineError = TRUE ;
1675 return JJY_RECEIVE_ERROR ;
1680 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1682 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1684 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1686 /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1688 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1689 &up->year, &up->month, &up->day,
1690 &up->hour, &up->minute, &up->second ) ;
1692 if ( rc != 6 || up->month < 1 || up->month > 12
1693 || up->day < 1 || up->day > 31
1694 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1695 /* Invalid date and time */
1696 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1697 rc, up->year, up->month, up->day,
1698 up->hour, up->minute, up->second ) ;
1699 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1700 up->bLineError = TRUE ;
1701 return JJY_RECEIVE_ERROR ;
1706 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1707 || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1708 /* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
1712 if ( up->second < 0 ) {
1715 if ( up->minute < 0 ) {
1718 if ( up->hour < 0 ) {
1721 if ( up->day < 1 ) {
1723 if ( up->month < 1 ) {
1734 jjy_synctime( peer, pp, up ) ;
1739 if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1740 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1742 iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1743 if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen ) {
1744 refclock_report ( peer, CEVNT_FAULT ) ;
1747 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1751 return JJY_RECEIVE_DONE ;
1755 /**************************************************************************************************/
1758 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1761 struct refclockproc *pp ;
1762 struct jjyunit *up ;
1766 pp = peer->procptr ;
1769 up->bLineError = FALSE ;
1772 * Send "T" or "C" command
1775 switch ( up->operationmode ) {
1776 case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
1779 case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
1780 case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
1786 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
1787 refclock_report ( peer, CEVNT_FAULT ) ;
1790 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
1794 /*################################################################################################*/
1795 /*################################################################################################*/
1797 /*## The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 ##*/
1799 /*## server 127.127.40.X mode 4 ##*/
1801 /*################################################################################################*/
1802 /*################################################################################################*/
1804 /* Command Response Remarks */
1805 /* -------------------- ---------------------------------------- ---------------------------- */
1806 /* 'XX YY/MM/DD W HH:MM:SS<CR> XX:OK|NG|ER W:0(Mon)-6(Sun) */
1808 /*################################################################################################*/
1811 jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
1814 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
1816 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
1817 up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
1818 up->linediscipline = LDISC_CLK ;
1824 /**************************************************************************************************/
1827 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1830 struct jjyunit *up ;
1831 struct refclockproc *pp ;
1834 char *pBuf, sLog [ 100 ], sMsg [ 16 ] ;
1837 char cApostrophe, sStatus[3] ;
1840 /* Initialize pointers */
1842 peer = rbufp->recv_peer ;
1843 pp = peer->procptr ;
1846 if ( up->linediscipline == LDISC_RAW ) {
1847 pBuf = up->sTextBuf ;
1848 iLen = up->iTextBufLen ;
1850 pBuf = pp->a_lastcode ;
1851 iLen = pp->lencode ;
1854 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
1857 * JJY-200 sends a timestamp every second.
1858 * So, a timestamp is ignored unless it is right after polled.
1861 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
1862 return JJY_RECEIVE_SKIP ;
1865 /* Check reply length */
1868 /* Unexpected reply length */
1869 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1871 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1872 up->bLineError = TRUE ;
1873 return JJY_RECEIVE_ERROR ;
1876 /* 'XX YY/MM/DD W HH:MM:SS<CR> */
1878 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1879 &cApostrophe, sStatus,
1880 &up->year, &up->month, &up->day, &iWeekday,
1881 &up->hour, &up->minute, &up->second ) ;
1884 if ( rc != 9 || cApostrophe != '\''
1885 || ( strcmp( sStatus, "OK" ) != 0
1886 && strcmp( sStatus, "NG" ) != 0
1887 && strcmp( sStatus, "ER" ) != 0 )
1888 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
1890 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1891 /* Invalid date and time */
1892 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1893 rc, up->year, up->month, up->day,
1894 up->hour, up->minute, up->second ) ;
1895 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1896 up->bLineError = TRUE ;
1897 return JJY_RECEIVE_ERROR ;
1898 } else if ( strcmp( sStatus, "NG" ) == 0
1899 || strcmp( sStatus, "ER" ) == 0 ) {
1900 /* Timestamp is unsure */
1901 snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
1902 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
1904 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
1905 return JJY_RECEIVE_SKIP ;
1911 jjy_synctime( peer, pp, up ) ;
1913 return JJY_RECEIVE_DONE ;
1917 /**************************************************************************************************/
1920 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1923 struct refclockproc *pp ;
1924 struct jjyunit *up ;
1926 pp = peer->procptr ;
1929 up->bLineError = FALSE ;
1933 /*################################################################################################*/
1934 /*################################################################################################*/
1936 /*## The Tristate Ltd. GPS clock TS-GPS01 ##*/
1938 /*## server 127.127.40.X mode 5 ##*/
1940 /*################################################################################################*/
1941 /*################################################################################################*/
1943 /* This clock has NMEA mode and command/respose mode. */
1944 /* When this jjy driver are used, set to command/respose mode of this clock */
1945 /* by the onboard switch SW4, and make sure the LED-Y is tured on. */
1946 /* Other than this JJY driver, the refclock driver type 20, generic NMEA driver, */
1947 /* works with the NMEA mode of this clock. */
1949 /* Command Response Remarks */
1950 /* -------------------- ---------------------------------------- ---------------------------- */
1951 /* stus<CR><LF> *R|*G|*U|+U<CR><LF> */
1952 /* date<CR><LF> YY/MM/DD<CR><LF> */
1953 /* time<CR><LF> HH:MM:SS<CR><LF> */
1955 /*################################################################################################*/
1957 #define TS_GPS01_COMMAND_NUMBER_DATE 1
1958 #define TS_GPS01_COMMAND_NUMBER_TIME 2
1959 #define TS_GPS01_COMMAND_NUMBER_STUS 4
1961 #define TS_GPS01_REPLY_DATE "yyyy/mm/dd"
1962 #define TS_GPS01_REPLY_TIME "hh:mm:ss"
1963 #define TS_GPS01_REPLY_STUS_RTC "*R"
1964 #define TS_GPS01_REPLY_STUS_GPS "*G"
1965 #define TS_GPS01_REPLY_STUS_UTC "*U"
1966 #define TS_GPS01_REPLY_STUS_PPS "+U"
1968 #define TS_GPS01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */
1969 #define TS_GPS01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
1970 #define TS_GPS01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */
1974 char commandNumber ;
1975 const char *command ;
1977 int iExpectedReplyLength ;
1978 } tristate_gps01_command_sequence[] =
1980 { 0, NULL, 0, 0 }, /* Idle */
1981 { TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
1982 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1983 { TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
1984 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1985 /* End of command */
1989 /**************************************************************************************************/
1992 jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
1995 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
1997 up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
1998 up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
1999 up->linediscipline = LDISC_CLK ;
2005 /**************************************************************************************************/
2008 jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
2011 static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ;
2014 struct jjyunit *up ;
2015 struct refclockproc *pp ;
2026 /* Initialize pointers */
2028 peer = rbufp->recv_peer ;
2029 pp = peer->procptr ;
2032 if ( up->linediscipline == LDISC_RAW ) {
2033 pBuf = up->sTextBuf ;
2034 iLen = up->iTextBufLen ;
2036 pBuf = pp->a_lastcode ;
2037 iLen = pp->lencode ;
2040 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
2042 /* Ignore NMEA data stream */
2045 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2048 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2049 sFunctionName, pBuf ) ;
2052 return JJY_RECEIVE_WAIT ;
2056 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
2058 if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2059 return JJY_RECEIVE_WAIT ;
2060 } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2066 * Ignore NMEA data stream after command prompt
2069 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2072 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2073 sFunctionName, pBuf ) ;
2076 return JJY_RECEIVE_WAIT ;
2079 /* Check expected reply */
2081 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2082 /* Command sequence has not been started, or has been completed */
2083 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2085 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2086 up->bLineError = TRUE ;
2087 return JJY_RECEIVE_ERROR ;
2090 /* Check reply length */
2092 if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
2093 /* Unexpected reply length */
2094 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2096 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2097 up->bLineError = TRUE ;
2098 return JJY_RECEIVE_ERROR ;
2103 switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
2105 case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
2107 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
2109 if ( rc != 3 || up->year < 2000 || 2099 <= up->year
2110 || up->month < 1 || 12 < up->month
2111 || up->day < 1 || 31 < up->day ) {
2113 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
2114 rc, up->year, up->month, up->day ) ;
2115 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2116 up->bLineError = TRUE ;
2117 return JJY_RECEIVE_ERROR ;
2122 case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
2124 if ( up->iTimestampCount >= 2 ) {
2125 /* Too many time reply */
2126 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
2127 up->iTimestampCount ) ;
2128 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2129 up->bLineError = TRUE ;
2130 return JJY_RECEIVE_ERROR ;
2133 rc = sscanf ( pBuf, "%2d:%2d:%2d",
2134 &up->hour, &up->minute, &up->second ) ;
2137 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2139 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2140 rc, up->hour, up->minute, up->second ) ;
2141 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2142 up->bLineError = TRUE ;
2143 return JJY_RECEIVE_ERROR ;
2146 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
2148 up->iTimestampCount++ ;
2154 case TS_GPS01_COMMAND_NUMBER_STUS :
2156 if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2157 || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2158 || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2159 || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
2162 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2164 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2165 up->bLineError = TRUE ;
2166 return JJY_RECEIVE_ERROR ;
2171 default : /* Unexpected reply */
2173 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2175 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2176 up->bLineError = TRUE ;
2177 return JJY_RECEIVE_ERROR ;
2181 if ( up->iTimestampCount == 2 ) {
2182 /* Process date and time */
2184 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
2185 && up->iTimestamp[0] <= up->iTimestamp[1] ) {
2186 /* 3 commands (time,date,stim) was excuted in two seconds */
2187 jjy_synctime( peer, pp, up ) ;
2188 return JJY_RECEIVE_DONE ;
2189 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
2190 /* Over midnight, and date is unsure */
2191 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
2192 up->iTimestamp[0], up->iTimestamp[1] ) ;
2193 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
2194 return JJY_RECEIVE_SKIP ;
2197 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
2198 up->iTimestamp[0], up->iTimestamp[1] ) ;
2199 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2200 up->bLineError = TRUE ;
2201 return JJY_RECEIVE_ERROR ;
2206 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2207 /* Command sequence completed */
2208 jjy_synctime( peer, pp, up ) ;
2209 return JJY_RECEIVE_DONE ;
2212 /* Issue next command */
2214 if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
2215 up->iCommandSeq ++ ;
2218 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2219 /* Command sequence completed */
2220 up->iProcessState = JJY_PROCESS_STATE_DONE ;
2221 return JJY_RECEIVE_DONE ;
2224 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
2225 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2226 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2227 refclock_report ( peer, CEVNT_FAULT ) ;
2230 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2232 return JJY_RECEIVE_WAIT ;
2236 /**************************************************************************************************/
2239 jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
2242 static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
2245 struct refclockproc *pp ;
2246 struct jjyunit *up ;
2251 pp = peer->procptr ;
2254 up->iTimestampCount = 0 ;
2256 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
2257 /* Skip "stus" command */
2258 up->iCommandSeq = 1 ;
2259 up->iLineCount = 1 ;
2264 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
2265 sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
2271 * Send a first command
2274 up->iCommandSeq ++ ;
2276 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
2277 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2278 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2279 refclock_report ( peer, CEVNT_FAULT ) ;
2282 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2286 /*################################################################################################*/
2287 /*################################################################################################*/
2289 /*## The SEIKO TIME SYSTEMS TDC-300 ##*/
2291 /*## server 127.127.40.X mode 6 ##*/
2293 /*################################################################################################*/
2294 /*################################################################################################*/
2296 /* Type Response Remarks */
2297 /* -------------------- ---------------------------------------- ---------------------------- */
2298 /* Type 1 <STX>HH:MM:SS<ETX> */
2299 /* Type 2 <STX>YYMMDDHHMMSSWLSCU<ETX> W:0(Sun)-6(Sat) */
2300 /* Type 3 <STX>YYMMDDWHHMMSS<ETX> W:0(Sun)-6(Sat) */
2301 /* <STX><xE5><ETX> 5 to 10 mSec. before second */
2303 /*################################################################################################*/
2305 static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
2307 { "\x03", 1 }, { NULL, 0 }
2310 /**************************************************************************************************/
2313 jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
2316 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
2318 up->unittype = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
2319 up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
2320 up->linediscipline = LDISC_RAW ;
2322 up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
2323 up->bWaitBreakString = TRUE ;
2325 up->bSkipCntrlCharOnly = FALSE ;
2331 /**************************************************************************************************/
2334 jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
2338 struct refclockproc *pp ;
2339 struct jjyunit *up ;
2341 char *pBuf, sLog [ 100 ] ;
2347 /* Initialize pointers */
2349 peer = rbufp->recv_peer ;
2350 pp = peer->procptr ;
2353 if ( up->linediscipline == LDISC_RAW ) {
2354 pBuf = up->sTextBuf ;
2355 iLen = up->iTextBufLen ;
2357 pBuf = pp->a_lastcode ;
2358 iLen = pp->lencode ;
2361 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
2364 * TDC-300 sends a timestamp every second.
2365 * So, a timestamp is ignored unless it is right after polled.
2368 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
2369 return JJY_RECEIVE_SKIP ;
2372 /* Process timestamp */
2374 up->iReceiveSeq ++ ;
2378 case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
2380 for ( i = 0 ; i < iLen ; i ++ ) {
2384 rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
2385 &up->hour, &up->minute, &up->second ) ;
2388 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2390 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2391 rc, up->hour, up->minute, up->second ) ;
2392 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2393 up->bLineError = TRUE ;
2394 return JJY_RECEIVE_ERROR ;
2395 } else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
2396 /* Uncertainty date guard */
2397 return JJY_RECEIVE_WAIT ;
2401 pTime = localtime( &now ) ;
2402 up->year = pTime->tm_year ;
2403 up->month = pTime->tm_mon + 1 ;
2404 up->day = pTime->tm_mday ;
2408 case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
2410 for ( i = 0 ; i < iLen ; i ++ ) {
2414 rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
2415 &up->year, &up->month, &up->day,
2416 &up->hour, &up->minute, &up->second, &iWeekday ) ;
2419 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2421 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2422 /* Invalid date and time */
2423 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2424 rc, up->year, up->month, up->day,
2425 up->hour, up->minute, up->second ) ;
2426 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2427 up->bLineError = TRUE ;
2428 return JJY_RECEIVE_ERROR ;
2433 case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
2435 rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
2436 &up->year, &up->month, &up->day, &iWeekday,
2437 &up->hour, &up->minute, &up->second ) ;
2440 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2442 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2443 /* Invalid date and time */
2444 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2445 rc, up->year, up->month, up->day,
2446 up->hour, up->minute, up->second ) ;
2447 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2448 up->bLineError = TRUE ;
2449 return JJY_RECEIVE_ERROR ;
2452 return JJY_RECEIVE_WAIT ;
2454 case 1 : /* Type 3 : <STX><xE5><ETX> */
2456 if ( ( *pBuf & 0xFF ) != 0xE5 ) {
2457 /* Invalid second signal */
2458 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2460 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2461 up->bLineError = TRUE ;
2462 return JJY_RECEIVE_ERROR ;
2463 } else if ( up->iReceiveSeq == 1 ) {
2464 /* Wait for next timestamp */
2465 up->iReceiveSeq -- ;
2466 return JJY_RECEIVE_WAIT ;
2467 } else if ( up->iReceiveSeq >= 3 ) {
2468 /* Unexpected second signal */
2469 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2471 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2472 up->bLineError = TRUE ;
2473 return JJY_RECEIVE_ERROR ;
2478 default : /* Unexpected reply length */
2480 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2482 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2483 up->bLineError = TRUE ;
2484 return JJY_RECEIVE_ERROR ;
2491 jjy_synctime( peer, pp, up ) ;
2493 return JJY_RECEIVE_DONE ;
2497 /**************************************************************************************************/
2500 jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
2503 struct refclockproc *pp ;
2504 struct jjyunit *up ;
2506 pp = peer->procptr ;
2509 up->bLineError = FALSE ;
2513 /*################################################################################################*/
2514 /*################################################################################################*/
2516 /*## Telephone JJY ##*/
2518 /*## server 127.127.40.X mode 100 to 180 ##*/
2520 /*################################################################################################*/
2521 /*################################################################################################*/
2523 /* Prompt Command Response Remarks */
2524 /* -------------------- -------------------- -------------------- -------------------------- */
2525 /* Name<SP>?<SP> TJJY<CR> Welcome messages TJJY is a guest user ID */
2526 /* > 4DATE<CR> YYYYMMDD<CR> */
2527 /* > LEAPSEC<CR> XX<CR> One of <SP>0, +1, -1 */
2528 /* > TIME<CR> HHMMSS<CR> 3 times on second */
2529 /* > BYE<CR> Sayounara messages */
2531 /*################################################################################################*/
2533 static struct jjyRawDataBreak teljjy_raw_break [ ] =
2544 #define TELJJY_STATE_IDLE 0
2545 #define TELJJY_STATE_DAILOUT 1
2546 #define TELJJY_STATE_LOGIN 2
2547 #define TELJJY_STATE_CONNECT 3
2548 #define TELJJY_STATE_BYE 4
2550 #define TELJJY_EVENT_NULL 0
2551 #define TELJJY_EVENT_START 1
2552 #define TELJJY_EVENT_CONNECT 2
2553 #define TELJJY_EVENT_DISCONNECT 3
2554 #define TELJJY_EVENT_COMMAND 4
2555 #define TELJJY_EVENT_LOGIN 5 /* Posted by the jjy_receive_telephone */
2556 #define TELJJY_EVENT_PROMPT 6 /* Posted by the jjy_receive_telephone */
2557 #define TELJJY_EVENT_DATA 7 /* Posted by the jjy_receive_telephone */
2558 #define TELJJY_EVENT_ERROR 8 /* Posted by the jjy_receive_telephone */
2559 #define TELJJY_EVENT_SILENT 9 /* Posted by the jjy_timer_telephone */
2560 #define TELJJY_EVENT_TIMEOUT 10 /* Posted by the jjy_timer_telephone */
2562 static void teljjy_control ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2564 static int teljjy_idle_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2565 static int teljjy_idle_dialout ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2566 static int teljjy_dial_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2567 static int teljjy_dial_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2568 static int teljjy_dial_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2569 static int teljjy_login_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2570 static int teljjy_login_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2571 static int teljjy_login_conn ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2572 static int teljjy_login_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2573 static int teljjy_login_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2574 static int teljjy_login_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2575 static int teljjy_conn_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2576 static int teljjy_conn_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2577 static int teljjy_conn_send ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2578 static int teljjy_conn_data ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2579 static int teljjy_conn_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2580 static int teljjy_conn_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2581 static int teljjy_bye_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2582 static int teljjy_bye_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2583 static int teljjy_bye_modem ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2585 static int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) =
2586 { /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
2587 /* NULL */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2588 /* START */ { teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2589 /* CONNECT */ { teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2590 /* DISCONNECT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_disc , teljjy_conn_disc , teljjy_bye_disc },
2591 /* COMMAND */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem },
2592 /* LOGIN */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
2593 /* PROMPT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn , teljjy_conn_send , teljjy_bye_ignore },
2594 /* DATA */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data , teljjy_bye_ignore },
2595 /* ERROR */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
2596 /* SILENT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
2597 /* TIMEOUT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem }
2600 static short iTeljjyNextState [ ] [ 5 ] =
2601 { /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
2602 /* NULL */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2603 /* START */ { TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2604 /* CONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_LOGIN , TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2605 /* DISCONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE },
2606 /* COMMAND */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2607 /* LOGIN */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
2608 /* PROMPT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE , TELJJY_STATE_BYE },
2609 /* DATA */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2610 /* ERROR */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
2611 /* SILENT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
2612 /* TIMEOUT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE }
2615 static short iTeljjyPostEvent [ ] [ 5 ] =
2616 { /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
2617 /* NULL */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2618 /* START */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2619 /* CONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2620 /* DISCONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2621 /* COMMAND */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2622 /* LOGIN */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2623 /* PROMPT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2624 /* DATA */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2625 /* ERROR */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2626 /* SILENT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
2627 /* TIMEOUT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
2630 static short iTeljjySilentTimeout [ 5 ] = { 0, 0, 10, 5, 0 } ;
2631 static short iTeljjyStateTimeout [ 5 ] = { 0, 120, 60, 60, 40 } ;
2633 #define TELJJY_STAY_CLOCK_STATE 0
2634 #define TELJJY_CHANGE_CLOCK_STATE 1
2636 /* Command and replay */
2638 #define TELJJY_REPLY_NONE 0
2639 #define TELJJY_REPLY_4DATE 1
2640 #define TELJJY_REPLY_TIME 2
2641 #define TELJJY_REPLY_LEAPSEC 3
2642 #define TELJJY_REPLY_LOOP 4
2643 #define TELJJY_REPLY_PROMPT 5
2644 #define TELJJY_REPLY_LOOPBACK 6
2645 #define TELJJY_REPLY_COM 7
2647 #define TELJJY_COMMAND_START_SKIP_LOOPBACK 7
2651 const char *command ;
2653 int iEchobackReplyLength ;
2654 int iExpectedReplyType ;
2655 int iExpectedReplyLength ;
2656 } teljjy_command_sequence[] =
2658 { NULL, 0, 0, 0, 0 }, /* Idle */
2659 { "LOOP\r" , 5, 4, TELJJY_REPLY_LOOP , 0 }, /* Getting into loopback mode */
2660 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2661 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2662 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2663 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2664 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2665 { "COM\r" , 4, 3, TELJJY_REPLY_COM , 0 }, /* Exit from loopback mode */
2666 /* TELJJY_COMMAND_START_SKIP_LOOPBACK */
2667 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
2668 { "4DATE\r" , 6, 5, TELJJY_REPLY_4DATE , 8 },
2669 { "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
2670 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
2671 { "BYE\r" , 4, 3, TELJJY_REPLY_NONE , 0 },
2672 /* End of command */
2673 { NULL, 0, 0, 0, 0 }
2676 #define TELJJY_LOOPBACK_DELAY_THRESHOLD 700 /* Milli second */
2679 #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 ) ; } }
2681 #define DEBUG_TELJJY_PRINTF(sFunc)
2684 /**************************************************************************************************/
2687 jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
2690 char sLog [ 80 ], sFirstThreeDigits [ 4 ] ;
2691 int iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
2693 size_t iFirstThreeDigitsCount ;
2695 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
2697 up->unittype = UNITTYPE_TELEPHONE ;
2698 up->linespeed = SPEED232_TELEPHONE ;
2699 up->linediscipline = LDISC_RAW ;
2701 up->pRawBreak = teljjy_raw_break ;
2702 up->bWaitBreakString = TRUE ;
2704 up->bSkipCntrlCharOnly = TRUE ;
2706 up->iClockState = TELJJY_STATE_IDLE ;
2707 up->iClockEvent = TELJJY_EVENT_NULL ;
2709 /* Check the telephone number */
2711 if ( sys_phone[0] == NULL ) {
2712 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
2713 up->bInitError = TRUE ;
2717 if ( sys_phone[1] != NULL ) {
2718 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
2719 up->bInitError = TRUE ;
2723 iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
2724 for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
2725 if ( isdigit( (u_char)sys_phone[0][i] ) ) {
2726 if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
2727 sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ;
2729 iNumberOfDigitsOfPhoneNumber ++ ;
2730 } else if ( sys_phone[0][i] == ',' ) {
2732 if ( iCommaCount > 1 ) {
2733 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
2734 up->bInitError = TRUE ;
2737 iFirstThreeDigitsCount = 0 ;
2738 iCommaPosition = i ;
2739 } else if ( sys_phone[0][i] != '-' ) {
2740 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
2741 up->bInitError = TRUE ;
2745 sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
2747 if ( iCommaCount == 1 ) {
2748 if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
2749 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
2750 up->bInitError = TRUE ;
2755 if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
2756 /* Too short or too long */
2757 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
2758 up->bInitError = TRUE ;
2762 if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
2763 || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
2764 || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
2765 || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
2766 || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
2767 || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
2768 || ( sFirstThreeDigits[0] == '0' && sFirstThreeDigits[2] == '0' ) ) {
2769 /* Not allowed because of emergency numbers or special service numbers */
2770 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
2771 up->bInitError = TRUE ;
2775 snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
2776 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2778 if ( peer->minpoll < 8 ) {
2779 /* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
2780 int oldminpoll = peer->minpoll ;
2782 if ( peer->ppoll < peer->minpoll ) {
2783 peer->ppoll = peer->minpoll ;
2785 if ( peer->maxpoll < peer->minpoll ) {
2786 peer->maxpoll = peer->minpoll ;
2788 snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
2789 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2796 /**************************************************************************************************/
2799 jjy_receive_telephone ( struct recvbuf *rbufp )
2802 static const char *sFunctionName = "jjy_receive_telephone" ;
2806 struct refclockproc *pp ;
2807 struct jjyunit *up ;
2810 short iPreviousModemState ;
2812 peer = rbufp->recv_peer ;
2813 pp = peer->procptr ;
2816 DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2818 if ( up->iClockState == TELJJY_STATE_IDLE
2819 || up->iClockState == TELJJY_STATE_DAILOUT
2820 || up->iClockState == TELJJY_STATE_BYE ) {
2822 iPreviousModemState = getModemState( up ) ;
2824 modem_receive ( rbufp ) ;
2826 if ( iPreviousModemState != up->iModemState ) {
2827 /* Modem state is changed just now. */
2828 if ( isModemStateDisconnect( up->iModemState ) ) {
2829 up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2830 teljjy_control ( peer, pp, up ) ;
2831 } else if ( isModemStateConnect( up->iModemState ) ) {
2832 up->iClockEvent = TELJJY_EVENT_CONNECT ;
2833 teljjy_control ( peer, pp, up ) ;
2837 return JJY_RECEIVE_WAIT ;
2841 if ( up->linediscipline == LDISC_RAW ) {
2842 pBuf = up->sTextBuf ;
2843 iLen = up->iTextBufLen ;
2845 pBuf = pp->a_lastcode ;
2846 iLen = pp->lencode ;
2849 up->iTeljjySilentTimer = 0 ;
2850 if ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN ; }
2851 else if ( iLen == 1 && strncmp( pBuf, ">" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
2852 else if ( iLen >= 1 && strncmp( pBuf, "?" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR ; }
2853 else { up->iClockEvent = TELJJY_EVENT_DATA ; }
2855 teljjy_control ( peer, pp, up ) ;
2857 return JJY_RECEIVE_WAIT ;
2861 /**************************************************************************************************/
2864 jjy_poll_telephone ( int unit, struct peer *peer )
2867 static const char *sFunctionName = "jjy_poll_telephone" ;
2870 struct refclockproc *pp ;
2871 struct jjyunit *up ;
2873 pp = peer->procptr ;
2876 DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2878 if ( up->iClockState == TELJJY_STATE_IDLE ) {
2879 up->iRawBufLen = 0 ;
2880 up->iLineBufLen = 0 ;
2881 up->iTextBufLen = 0 ;
2884 up->iClockEvent = TELJJY_EVENT_START ;
2885 teljjy_control ( peer, pp, up ) ;
2889 /**************************************************************************************************/
2892 jjy_timer_telephone ( int unit, struct peer *peer )
2895 static const char *sFunctionName = "jjy_timer_telephone" ;
2898 struct refclockproc *pp ;
2899 struct jjyunit *up ;
2900 short iPreviousModemState ;
2902 pp = peer->procptr ;
2905 DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2907 if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
2908 up->iTeljjySilentTimer++ ;
2909 if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
2910 up->iClockEvent = TELJJY_EVENT_SILENT ;
2911 teljjy_control ( peer, pp, up ) ;
2915 if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
2916 up->iTeljjyStateTimer++ ;
2917 if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
2918 up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
2919 teljjy_control ( peer, pp, up ) ;
2923 if ( isModemStateTimerOn( up ) ) {
2925 iPreviousModemState = getModemState( up ) ;
2927 modem_timer ( unit, peer ) ;
2929 if ( iPreviousModemState != up->iModemState ) {
2930 /* Modem state is changed just now. */
2931 if ( isModemStateDisconnect( up->iModemState ) ) {
2932 up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2933 teljjy_control ( peer, pp, up ) ;
2934 } else if ( isModemStateConnect( up->iModemState ) ) {
2935 up->iClockEvent = TELJJY_EVENT_CONNECT ;
2936 teljjy_control ( peer, pp, up ) ;
2944 /**************************************************************************************************/
2947 teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
2951 short iPostEvent = TELJJY_EVENT_NULL ;
2953 DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
2955 rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
2957 if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
2958 iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
2961 printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd iPostEvent=%hd\n",
2962 up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
2965 up->iTeljjySilentTimer = 0 ;
2966 if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
2967 /* Telephone JJY state is changing now */
2968 up->iTeljjyStateTimer = 0 ;
2969 up->bLineError = FALSE ;
2970 up->iClockCommandSeq = 0 ;
2971 up->iTimestampCount = 0 ;
2972 up->iLoopbackCount = 0 ;
2973 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
2974 up->bLoopbackTimeout[i] = FALSE ;
2976 if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
2977 /* Telephone JJY state is changing to IDLE just now */
2978 up->iProcessState = JJY_PROCESS_STATE_DONE ;
2981 up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
2985 if ( iPostEvent != TELJJY_EVENT_NULL ) {
2986 up->iClockEvent = iPostEvent ;
2987 teljjy_control ( peer, pp, up ) ;
2990 up->iClockEvent = TELJJY_EVENT_NULL ;
2994 /**************************************************************************************************/
2997 teljjy_setDelay ( struct peer *peer, struct jjyunit *up )
3001 int milliSecond, microSecond ;
3003 gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
3005 up->delayTime[up->iLoopbackCount].tv_sec -= up->sendTime[up->iLoopbackCount].tv_sec ;
3006 up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
3007 if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
3008 up->delayTime[up->iLoopbackCount].tv_sec -- ;
3009 up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
3012 milliSecond = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
3013 microSecond = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
3014 milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
3016 snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
3017 milliSecond, microSecond ) ;
3019 if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
3020 /* Delay > 700 mS */
3021 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3023 /* Delay <= 700 mS */
3024 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3029 /**************************************************************************************************/
3032 teljjy_getDelay ( struct peer *peer, struct jjyunit *up )
3035 struct timeval maxTime, minTime, averTime ;
3037 int minIndex = 0, maxIndex = 0, iAverCount = 0 ;
3038 int iThresholdSecond, iThresholdMicroSecond ;
3041 minTime.tv_sec = minTime.tv_usec = 0 ;
3042 maxTime.tv_sec = maxTime.tv_usec = 0 ;
3044 iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
3045 iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
3047 up->iLoopbackValidCount = 0 ;
3049 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3050 if ( up->bLoopbackTimeout[i]
3051 || up->delayTime[i].tv_sec > iThresholdSecond
3052 || ( up->delayTime[i].tv_sec == iThresholdSecond
3053 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3056 if ( up->iLoopbackValidCount == 0 ) {
3057 minTime.tv_sec = up->delayTime[i].tv_sec ;
3058 minTime.tv_usec = up->delayTime[i].tv_usec ;
3059 maxTime.tv_sec = up->delayTime[i].tv_sec ;
3060 maxTime.tv_usec = up->delayTime[i].tv_usec ;
3061 minIndex = maxIndex = i ;
3062 } else if ( minTime.tv_sec > up->delayTime[i].tv_sec
3063 || ( minTime.tv_sec == up->delayTime[i].tv_sec
3064 && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
3065 minTime.tv_sec = up->delayTime[i].tv_sec ;
3066 minTime.tv_usec = up->delayTime[i].tv_usec ;
3068 } else if ( maxTime.tv_sec < up->delayTime[i].tv_sec
3069 || ( maxTime.tv_sec == up->delayTime[i].tv_sec
3070 && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
3071 maxTime.tv_sec = up->delayTime[i].tv_sec ;
3072 maxTime.tv_usec = up->delayTime[i].tv_usec ;
3075 up->iLoopbackValidCount ++ ;
3078 if ( up->iLoopbackValidCount < 2 ) {
3082 averTime.tv_usec = 0;
3084 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3085 if ( up->bLoopbackTimeout[i]
3086 || up->delayTime[i].tv_sec > iThresholdSecond
3087 || ( up->delayTime[i].tv_sec == iThresholdSecond
3088 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3091 if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
3094 if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
3097 averTime.tv_usec += up->delayTime[i].tv_usec ;
3101 if ( iAverCount == 0 ) {
3102 /* This is never happened. */
3103 /* Previous for-if-for blocks assure iAverCount > 0. */
3104 /* This code avoids a claim by the coverity scan tool. */
3108 /* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
3110 iPercent = ( peer->ttl - 100 ) ;
3112 /* Average delay time in milli second */
3114 return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
3118 /******************************/
3120 teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3123 DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
3125 return TELJJY_STAY_CLOCK_STATE ;
3129 /******************************/
3131 teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3134 DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
3136 modem_connect ( peer->refclkunit, peer ) ;
3138 return TELJJY_CHANGE_CLOCK_STATE ;
3142 /******************************/
3144 teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3147 DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
3149 return TELJJY_STAY_CLOCK_STATE ;
3153 /******************************/
3155 teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3158 DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
3160 return TELJJY_CHANGE_CLOCK_STATE ;
3164 /******************************/
3166 teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3169 DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
3171 return TELJJY_CHANGE_CLOCK_STATE ;
3175 /******************************/
3177 teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3180 DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
3182 return TELJJY_STAY_CLOCK_STATE ;
3186 /******************************/
3188 teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3191 DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
3193 return TELJJY_CHANGE_CLOCK_STATE ;
3197 /******************************/
3199 teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3204 DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
3206 up->bLineError = FALSE ;
3207 up->iClockCommandSeq = 0 ;
3208 up->iTimestampCount = 0 ;
3209 up->iLoopbackCount = 0 ;
3210 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3211 up->bLoopbackTimeout[i] = FALSE ;
3214 return TELJJY_CHANGE_CLOCK_STATE ;
3218 /******************************/
3220 teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3226 DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
3228 /* Send a guest user ID */
3232 iCmdLen = strlen( pCmd ) ;
3233 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
3234 refclock_report( peer, CEVNT_FAULT ) ;
3237 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3239 return TELJJY_STAY_CLOCK_STATE ;
3243 /******************************/
3245 teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3248 DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
3250 if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
3251 refclock_report( peer, CEVNT_FAULT ) ;
3254 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
3256 up->iTeljjySilentTimer = 0 ;
3258 return TELJJY_CHANGE_CLOCK_STATE ;
3262 /******************************/
3264 teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3267 DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
3269 return TELJJY_CHANGE_CLOCK_STATE ;
3273 /******************************/
3275 teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3278 DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
3280 return TELJJY_STAY_CLOCK_STATE ;
3284 /******************************/
3286 teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3289 DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
3291 return TELJJY_CHANGE_CLOCK_STATE ;
3295 /******************************/
3297 teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3301 int i, iLen, iNextClockState ;
3303 DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
3305 if ( up->iClockCommandSeq > 0
3306 && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
3307 /* Command sequence has been completed */
3308 return TELJJY_CHANGE_CLOCK_STATE ;
3311 if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
3314 up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
3316 } else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
3317 /* Loopback start */
3319 up->iLoopbackCount = 0 ;
3320 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3321 up->bLoopbackTimeout[i] = FALSE ;
3324 } else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
3325 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3326 && up->iLoopbackCount < MAX_LOOPBACK ) {
3327 /* Loopback character comes */
3330 printf( "refclock_jjy.c : teljjy_conn_send : iLoopbackCount=%d\n",
3331 up->iLoopbackCount ) ;
3335 teljjy_setDelay( peer, up ) ;
3337 up->iLoopbackCount ++ ;
3341 up->iClockCommandSeq++ ;
3343 pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
3344 iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
3346 if ( pCmd != NULL ) {
3348 if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
3349 refclock_report( peer, CEVNT_FAULT ) ;
3352 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3353 /* Loopback character and timestamp */
3354 gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
3355 up->bLoopbackMode = TRUE ;
3357 /* Regular command */
3358 up->bLoopbackMode = FALSE ;
3361 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3363 if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
3364 /* Last command of the command sequence */
3365 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3367 /* More commands to be issued */
3368 iNextClockState = TELJJY_STAY_CLOCK_STATE ;
3373 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3377 return iNextClockState ;
3381 /******************************/
3383 teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3392 DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
3394 if ( up->linediscipline == LDISC_RAW ) {
3395 pBuf = up->sTextBuf ;
3396 iLen = up->iTextBufLen ;
3398 pBuf = pp->a_lastcode ;
3399 iLen = pp->lencode ;
3402 if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3403 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3404 && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
3405 && up->iLoopbackCount < MAX_LOOPBACK ) {
3408 teljjy_setDelay( peer, up ) ;
3410 up->iLoopbackCount ++ ;
3412 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3413 && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
3414 /* Maybe echoback */
3416 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
3418 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3419 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
3420 /* 4DATE<CR> -> YYYYMMDD<CR> */
3422 rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
3424 if ( rc != 3 || up->year < 2000 || 2099 <= up->year
3425 || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
3427 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
3428 rc, up->year, up->month, up->day ) ;
3429 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3430 up->bLineError = TRUE ;
3433 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3434 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
3435 && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
3436 /* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
3438 rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
3440 if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
3441 /* Invalid leap second */
3442 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
3444 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3445 up->bLineError = TRUE ;
3448 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3449 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
3450 /* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
3452 rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
3454 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
3456 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
3457 rc, up->hour, up->minute, up->second ) ;
3458 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3459 up->bLineError = TRUE ;
3461 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
3463 up->iTimestampCount++ ;
3465 if ( up->iTimestampCount == 6 && ! up->bLineError ) {
3467 printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
3469 up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
3471 bAdjustment = TRUE ;
3473 if ( peer->ttl == 100 ) {
3477 /* mode=101 to 110 */
3478 up->msecond = teljjy_getDelay( peer, up ) ;
3479 if (up->msecond < 0 ) {
3481 bAdjustment = FALSE ;
3485 if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
3486 && up->iTimestamp[2] <= up->iTimestamp[3]
3487 && ( up->iTimestamp[3] + 1 ) == up->iTimestamp[4]
3488 && ( up->iTimestamp[4] + 1 ) == up->iTimestamp[5] ) {
3489 /* Non over midnight */
3491 jjy_synctime( peer, pp, up ) ;
3493 if ( peer->ttl != 100 ) {
3494 if ( bAdjustment ) {
3495 snprintf( sLog, sizeof(sLog),
3496 JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
3497 up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3498 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3500 snprintf( sLog, sizeof(sLog),
3501 JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
3502 up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3503 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3510 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
3511 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3512 /* Loopback noise ( Unexpected replay ) */
3514 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
3516 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3520 up->bLineError = TRUE ;
3522 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
3524 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3528 return TELJJY_STAY_CLOCK_STATE ;
3532 /******************************/
3534 teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3539 DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
3541 if ( up->iClockCommandSeq >= 1
3542 && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
3546 printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
3549 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3550 up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
3552 up->iTeljjySilentTimer = 0 ;
3553 return teljjy_conn_send( peer, pp, up ) ;
3558 if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
3559 refclock_report( peer, CEVNT_FAULT ) ;
3562 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3564 up->iTeljjySilentTimer = 0 ;
3566 return TELJJY_STAY_CLOCK_STATE ;
3570 /******************************/
3572 teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3575 DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
3577 return TELJJY_CHANGE_CLOCK_STATE ;
3581 /******************************/
3583 teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3586 DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
3588 return TELJJY_STAY_CLOCK_STATE ;
3592 /******************************/
3594 teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3597 DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
3599 return TELJJY_CHANGE_CLOCK_STATE ;
3603 /******************************/
3605 teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3608 DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
3610 modem_disconnect ( peer->refclkunit, peer ) ;
3612 return TELJJY_STAY_CLOCK_STATE ;
3616 /*################################################################################################*/
3617 /*################################################################################################*/
3619 /*## Modem control finite state machine ##*/
3621 /*################################################################################################*/
3622 /*################################################################################################*/
3624 /* struct jjyunit.iModemState */
3626 #define MODEM_STATE_DISCONNECT 0
3627 #define MODEM_STATE_INITIALIZE 1
3628 #define MODEM_STATE_DAILING 2
3629 #define MODEM_STATE_CONNECT 3
3630 #define MODEM_STATE_ESCAPE 4
3632 /* struct jjyunit.iModemEvent */
3634 #define MODEM_EVENT_NULL 0
3635 #define MODEM_EVENT_INITIALIZE 1
3636 #define MODEM_EVENT_DIALOUT 2
3637 #define MODEM_EVENT_DISCONNECT 3
3638 #define MODEM_EVENT_RESP_OK 4
3639 #define MODEM_EVENT_RESP_CONNECT 5
3640 #define MODEM_EVENT_RESP_RING 6
3641 #define MODEM_EVENT_RESP_NO_CARRIER 7
3642 #define MODEM_EVENT_RESP_ERROR 8
3643 #define MODEM_EVENT_RESP_CONNECT_X 9
3644 #define MODEM_EVENT_RESP_NO_DAILTONE 10
3645 #define MODEM_EVENT_RESP_BUSY 11
3646 #define MODEM_EVENT_RESP_NO_ANSWER 12
3647 #define MODEM_EVENT_RESP_UNKNOWN 13
3648 #define MODEM_EVENT_SILENT 14
3649 #define MODEM_EVENT_TIMEOUT 15
3651 /* Function prototypes */
3653 static void modem_control ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3655 static int modem_disc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3656 static int modem_disc_init ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3657 static int modem_init_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3658 static int modem_init_start ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3659 static int modem_init_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3660 static int modem_init_resp00 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3661 static int modem_init_resp04 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3662 static int modem_dial_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3663 static int modem_dial_dialout ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3664 static int modem_dial_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3665 static int modem_dial_connect ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3666 static int modem_dial_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3667 static int modem_conn_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3668 static int modem_conn_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3669 static int modem_esc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3670 static int modem_esc_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3671 static int modem_esc_data ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3672 static int modem_esc_silent ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3673 static int modem_esc_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3675 static int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) =
3676 { /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
3677 /* NULL */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3678 /* INITIALIZE */ { modem_disc_init , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3679 /* DIALOUT */ { modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
3680 /* DISCONNECT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_escape },
3681 /* RESP: 0: OK */ { modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
3682 /* RESP: 1: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
3683 /* RESP: 2: RING */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
3684 /* RESP: 3: NO CARRIER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3685 /* RESP: 4: ERROR */ { modem_disc_ignore, modem_init_resp04, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3686 /* RESP: 5: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
3687 /* RESP: 6: NO DAILTONE */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3688 /* RESP: 7: BUSY */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3689 /* RESP: 8: NO ANSWER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
3690 /* RESP: 9: UNKNOWN */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
3691 /* SILENT */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
3692 /* TIMEOUT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_disc }
3695 static short iModemNextState [ ] [ 5 ] =
3696 { /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
3697 /* NULL */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3698 /* INITIALIZE */ { MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3699 /* DIALOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3700 /* DISCONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE },
3701 /* RESP: 0: OK */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3702 /* RESP: 1: CONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3703 /* RESP: 2: RING */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3704 /* RESP: 3: NO CARRIER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3705 /* RESP: 4: ERROR */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3706 /* RESP: 5: CONNECT X */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3707 /* RESP: 6: NO DAILTONE */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3708 /* RESP: 7: BUSY */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3709 /* RESP: 8: NO ANSWER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3710 /* RESP: 9: UNKNOWN */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
3711 /* SILENT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
3712 /* TIMEOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
3715 static short iModemPostEvent [ ] [ 5 ] =
3716 { /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
3717 /* NULL */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3718 /* INITIALIZE */ { MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3719 /* DIALOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3720 /* DISCONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
3721 /* RESP: 0: OK */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3722 /* RESP: 1: CONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3723 /* RESP: 2: RING */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3724 /* RESP: 3: NO CARRIER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3725 /* RESP: 4: ERROR */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3726 /* RESP: 5: CONNECT X */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3727 /* RESP: 6: NO DAILTONE */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3728 /* RESP: 7: BUSY */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3729 /* RESP: 8: NO ANSWER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3730 /* RESP: 9: UNKNOWN */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3731 /* SILENT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
3732 /* TIMEOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
3735 static short iModemSilentTimeout [ 5 ] = { 0, 0, 0, 0, 5 } ;
3736 static short iModemStateTimeout [ 5 ] = { 0, 20, 90, 0, 20 } ;
3738 #define STAY_MODEM_STATE 0
3739 #define CHANGE_MODEM_STATE 1
3742 #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 ) ; } }
3744 #define DEBUG_MODEM_PRINTF(sFunc)
3747 /**************************************************************************************************/
3750 getModemState ( struct jjyunit *up )
3752 return up->iModemState ;
3755 /**************************************************************************************************/
3758 isModemStateConnect ( short iCheckState )
3760 return ( iCheckState == MODEM_STATE_CONNECT ) ;
3763 /**************************************************************************************************/
3766 isModemStateDisconnect ( short iCheckState )
3768 return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
3771 /**************************************************************************************************/
3774 isModemStateTimerOn ( struct jjyunit *up )
3776 return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
3779 /**************************************************************************************************/
3782 modem_connect ( int unit, struct peer *peer )
3784 struct refclockproc *pp;
3787 pp = peer->procptr ;
3790 DEBUG_MODEM_PRINTF( "modem_connect" ) ;
3792 up->iModemEvent = MODEM_EVENT_INITIALIZE ;
3794 modem_control ( peer, pp, up ) ;
3798 /**************************************************************************************************/
3801 modem_disconnect ( int unit, struct peer *peer )
3803 struct refclockproc *pp;
3806 pp = peer->procptr ;
3809 DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
3811 up->iModemEvent = MODEM_EVENT_DISCONNECT ;
3813 modem_control ( peer, pp, up ) ;
3817 /**************************************************************************************************/
3820 modem_receive ( struct recvbuf *rbufp )
3825 struct refclockproc *pp;
3830 static const char *sFunctionName = "modem_receive" ;
3833 peer = rbufp->recv_peer ;
3834 pp = peer->procptr ;
3837 DEBUG_MODEM_PRINTF( sFunctionName ) ;
3839 if ( up->linediscipline == LDISC_RAW ) {
3840 pBuf = up->sTextBuf ;
3841 iLen = up->iTextBufLen ;
3843 pBuf = pp->a_lastcode ;
3844 iLen = pp->lencode ;
3847 if ( iLen == 2 && strncmp( pBuf, "OK" , 2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK ; }
3848 else if ( iLen == 7 && strncmp( pBuf, "CONNECT" , 7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT ; }
3849 else if ( iLen == 4 && strncmp( pBuf, "RING" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING ; }
3850 else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER ; }
3851 else if ( iLen == 5 && strncmp( pBuf, "ERROR" , 5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR ; }
3852 else if ( iLen >= 8 && strncmp( pBuf, "CONNECT " , 8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X ; }
3853 else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
3854 else if ( iLen == 4 && strncmp( pBuf, "BUSY" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY ; }
3855 else if ( iLen == 9 && strncmp( pBuf, "NO ANSWER" , 9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER ; }
3856 else { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN ; }
3862 iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3863 strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3864 sResp[iCopyLen] = 0 ;
3865 printf ( "refclock_jjy.c : modem_receive : iLen=%zu pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
3868 modem_control ( peer, pp, up ) ;
3874 /**************************************************************************************************/
3877 modem_timer ( int unit, struct peer *peer )
3880 struct refclockproc *pp ;
3881 struct jjyunit *up ;
3883 pp = peer->procptr ;
3886 DEBUG_MODEM_PRINTF( "modem_timer" ) ;
3888 if ( iModemSilentTimeout[up->iModemState] != 0 ) {
3889 up->iModemSilentTimer++ ;
3890 if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
3891 up->iModemEvent = MODEM_EVENT_SILENT ;
3892 modem_control ( peer, pp, up ) ;
3896 if ( iModemStateTimeout[up->iModemState] != 0 ) {
3897 up->iModemStateTimer++ ;
3898 if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
3899 up->iModemEvent = MODEM_EVENT_TIMEOUT ;
3900 modem_control ( peer, pp, up ) ;
3906 /**************************************************************************************************/
3909 modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3913 short iPostEvent = MODEM_EVENT_NULL ;
3915 DEBUG_MODEM_PRINTF( "modem_control" ) ;
3917 rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
3919 if ( rc == CHANGE_MODEM_STATE ) {
3920 iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
3923 printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d iPostEvent=%d\n",
3924 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
3928 if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
3929 up->iModemSilentCount = 0 ;
3930 up->iModemStateTimer = 0 ;
3931 up->iModemCommandSeq = 0 ;
3934 up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
3937 if ( iPostEvent != MODEM_EVENT_NULL ) {
3938 up->iModemEvent = iPostEvent ;
3939 modem_control ( peer, pp, up ) ;
3942 up->iModemEvent = MODEM_EVENT_NULL ;
3946 /******************************/
3948 modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3951 DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
3953 return STAY_MODEM_STATE ;
3957 /******************************/
3959 modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3962 DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
3964 return CHANGE_MODEM_STATE ;
3968 /******************************/
3970 modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3973 DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
3975 return STAY_MODEM_STATE ;
3979 /******************************/
3981 modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3984 DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
3986 up->iModemCommandSeq = 0 ;
3990 printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
3994 return modem_init_resp00( peer, pp, up ) ;
3998 /******************************/
4000 modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4006 int iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
4007 int iNextModemState = STAY_MODEM_STATE ;
4009 DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
4011 up->iModemCommandSeq++ ;
4013 switch ( up->iModemCommandSeq ) {
4016 /* En = Echoback 0:Off 1:On */
4017 /* Qn = Result codes 0:On 1:Off */
4018 /* Vn = Result codes 0:Numeric 1:Text */
4019 pCmd = "ATE0Q0V1\r\n" ;
4023 /* Mn = Speaker switch 0:Off 1:On until remote carrier detected 2:On */
4024 if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
4025 /* fudge 127.127.40.n flag3 0 */
4026 iSpeakerSwitch = 0 ;
4028 /* fudge 127.127.40.n flag3 1 */
4029 iSpeakerSwitch = 2 ;
4032 /* Ln = Speaker volume 0:Very low 1:Low 2:Middle 3:High */
4033 if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
4034 /* fudge 127.127.40.n flag4 0 */
4035 iSpeakerVolume = 1 ;
4037 /* fudge 127.127.40.n flag4 1 */
4038 iSpeakerVolume = 2 ;
4042 snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
4046 /* &Kn = Flow control 4:XON/XOFF */
4047 pCmd = "AT&K4\r\n" ;
4051 /* +MS = Protocol V22B:1200,2400bps
\81iV.22bis) */
4052 pCmd = "AT+MS=V22B\r\n" ;
4056 /* %Cn = Data compression 0:No data compression */
4057 pCmd = "AT%C0\r\n" ;
4061 /* \Nn = Error correction 0:Normal mode 1:Direct mode 2:V42,MNP 3:V42,MNP,Normal */
4062 if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
4063 /* fudge 127.127.40.n flag2 0 */
4064 iErrorCorrection = 0 ;
4066 /* fudge 127.127.40.n flag2 1 */
4067 iErrorCorrection = 3 ;
4071 snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
4075 /* Hn = Hook 0:Hook-On ( Disconnect ) 1:Hook-Off ( Connect ) */
4080 /* Initialize completion */
4082 iNextModemState = CHANGE_MODEM_STATE ;
4091 if ( pCmd != NULL ) {
4093 iCmdLen = strlen( pCmd ) ;
4094 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4095 refclock_report( peer, CEVNT_FAULT ) ;
4098 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4102 return iNextModemState ;
4106 /******************************/
4108 modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4111 DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
4113 return modem_init_resp00( peer, pp, up ) ;
4117 /******************************/
4119 modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4122 DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
4125 printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
4129 return CHANGE_MODEM_STATE ;
4133 /******************************/
4135 modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4138 DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
4140 return STAY_MODEM_STATE ;
4144 /******************************/
4146 modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4153 DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
4156 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
4157 /* fudge 127.127.40.n flag1 0 */
4158 cToneOrPulse = 'T' ;
4160 /* fudge 127.127.40.n flag1 1 */
4161 cToneOrPulse = 'P' ;
4164 /* Connect ( Dial number ) */
4165 snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
4168 iCmdLen = strlen( sCmd ) ;
4169 if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
4170 refclock_report( peer, CEVNT_FAULT ) ;
4173 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
4175 return STAY_MODEM_STATE ;
4179 /******************************/
4181 modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4184 DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
4187 printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
4191 return modem_conn_escape( peer, pp, up ) ;
4195 /******************************/
4197 modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4200 DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
4202 return CHANGE_MODEM_STATE ;
4206 /******************************/
4208 modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4211 DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
4214 printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
4218 modem_esc_disc( peer, pp, up ) ;
4220 return CHANGE_MODEM_STATE ;
4224 /******************************/
4226 modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4229 DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
4231 return STAY_MODEM_STATE ;
4235 /******************************/
4237 modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4240 DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
4242 return CHANGE_MODEM_STATE ;
4246 /******************************/
4248 modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4251 DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
4253 return STAY_MODEM_STATE ;
4257 /******************************/
4259 modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4265 DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
4267 /* Escape command ( Go to command mode ) */
4271 iCmdLen = strlen( pCmd ) ;
4272 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4273 refclock_report( peer, CEVNT_FAULT ) ;
4276 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4278 return STAY_MODEM_STATE ;
4282 /******************************/
4284 modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4287 DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
4289 up->iModemSilentTimer = 0 ;
4291 return STAY_MODEM_STATE ;
4295 /******************************/
4297 modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4300 DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
4302 up->iModemSilentCount ++ ;
4304 if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
4307 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
4310 modem_esc_escape( peer, pp, up ) ;
4311 up->iModemSilentTimer = 0 ;
4312 return STAY_MODEM_STATE ;
4317 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
4320 return modem_esc_disc( peer, pp, up ) ;
4323 /******************************/
4325 modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4331 DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
4337 iCmdLen = strlen( pCmd ) ;
4338 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4339 refclock_report( peer, CEVNT_FAULT ) ;
4342 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4344 return CHANGE_MODEM_STATE ;
4348 /*################################################################################################*/
4349 /*################################################################################################*/
4351 /*## jjy_write_clockstats ##*/
4353 /*################################################################################################*/
4354 /*################################################################################################*/
4357 jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
4361 const char * pMark ;
4362 int iMarkLen, iDataLen ;
4365 case JJY_CLOCKSTATS_MARK_JJY :
4368 case JJY_CLOCKSTATS_MARK_SEND :
4371 case JJY_CLOCKSTATS_MARK_RECEIVE :
4374 case JJY_CLOCKSTATS_MARK_INFORMATION :
4377 case JJY_CLOCKSTATS_MARK_ATTENTION :
4380 case JJY_CLOCKSTATS_MARK_WARNING :
4383 case JJY_CLOCKSTATS_MARK_ERROR :
4391 iDataLen = strlen( pData ) ;
4392 iMarkLen = strlen( pMark ) ;
4393 strcpy( sLog, pMark ) ; /* Harmless because of enough length */
4394 printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
4398 printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
4401 record_clock_stats( &peer->srcadr, sLog ) ;
4405 /*################################################################################################*/
4406 /*################################################################################################*/
4408 /*## printableString ##*/
4410 /*################################################################################################*/
4411 /*################################################################################################*/
4414 printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
4416 const char *printableControlChar[] = {
4417 "<NUL>", "<SOH>", "<STX>", "<ETX>",
4418 "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
4419 "<BS>" , "<HT>" , "<LF>" , "<VT>" ,
4420 "<FF>" , "<CR>" , "<SO>" , "<SI>" ,
4421 "<DLE>", "<DC1>", "<DC2>", "<DC3>",
4422 "<DC4>", "<NAK>", "<SYN>", "<ETB>",
4423 "<CAN>", "<EM>" , "<SUB>", "<ESC>",
4424 "<FS>" , "<GS>" , "<RS>" , "<US>" ,
4431 InputLen = (size_t)iInputLen;
4432 OutputLen = (size_t)iOutputLen;
4433 for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
4434 if ( isprint( (unsigned char)sInput[i] ) ) {
4436 if ( j + 1 >= OutputLen )
4438 sOutput[j] = sInput[i] ;
4439 } else if ( ( sInput[i] & 0xFF ) <
4440 COUNTOF(printableControlChar) ) {
4441 n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
4442 if ( j + n + 1 >= OutputLen )
4444 strlcpy( sOutput + j,
4445 printableControlChar[sInput[i] & 0xFF],
4449 if ( j + n + 1 >= OutputLen )
4451 snprintf( sOutput + j, OutputLen - j, "<x%X>",
4452 sInput[i] & 0xFF ) ;
4457 sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
4461 /**************************************************************************************************/
4464 int refclock_jjy_bs ;
4465 #endif /* REFCLOCK */