2 * refclock_jjy - clock driver for JJY receivers
5 /**********************************************************************/
7 /* Copyright (C) 2001-2011, 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 */
98 /**********************************************************************/
104 #if defined(REFCLOCK) && defined(CLOCK_JJY)
109 #include <sys/time.h>
115 #include "ntp_refclock.h"
116 #include "ntp_calendar.h"
117 #include "ntp_stdlib.h"
119 /**********************************************************************/
121 /* The Tristate Ltd. JJY receiver JJY01 */
123 /* Command Response Remarks */
124 /* ------------ ---------------------- --------------------- */
125 /* dcst<CR><LF> VALID|INVALID<CR><LF> */
126 /* stus<CR><LF> ADJUSTED|UNADJUSTED<CR><LF> */
127 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */
128 /* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */
129 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
131 /* During synchronization after a receiver is turned on, */
132 /* It replies the past time from 2000/01/01 00:00:00. */
133 /* The function "refclock_process" checks the time and tells */
134 /* as an insanity time. */
136 /**********************************************************************/
138 /* The C-DEX Co. Ltd. JJY receiver JST2000 */
140 /* Command Response Remarks */
141 /* ------------ ---------------------- --------------------- */
142 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */
144 /**********************************************************************/
146 /* The Echo Keisokuki Co. Ltd. JJY receiver LT2000 */
148 /* Command Response Remarks */
149 /* ------------ ---------------------- --------------------- */
150 /* # Mode 1 (Request&Send) */
151 /* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
152 /* C Mode 2 (Continuous) */
153 /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
154 /* <SUB> Second signal */
156 /**********************************************************************/
158 /* The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 */
160 /* Command Response Remarks */
161 /* ------------ ---------------------- --------------------- */
162 /* 'XX YY/MM/DD W HH:MM:SS<CR> */
164 /* W: 0(Monday)-6(Sunday) */
166 /**********************************************************************/
168 /* The Tristate Ltd. GPS clock TS-GPSCLOCK-01 */
170 /* This clock has NMEA mode and command/respose mode. */
171 /* When this jjy driver are used, set to command/respose mode */
172 /* of this clock by the onboard switch SW4, and make sure the */
173 /* LED-Y is tured on. */
174 /* Other than this JJY driver, the refclock driver type 20, */
175 /* generic NMEA driver, works with the NMEA mode of this clock. */
177 /* Command Response Remarks */
178 /* ------------ ---------------------- --------------------- */
179 /* stus<CR><LF> *R|*G|*U|+U<CR><LF> */
180 /* date<CR><LF> YY/MM/DD<CR><LF> */
181 /* time<CR><LF> HH:MM:SS<CR><LF> */
183 /**********************************************************************/
186 * Interface definitions
188 #define DEVICE "/dev/jjy%d" /* device name and unit */
189 #define SPEED232 B9600 /* uart speed (9600 baud) */
190 #define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
191 #define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
192 #define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
193 #define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
194 #define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */
195 #define REFID "JJY" /* reference ID */
196 #define DESCRIPTION "JJY Receiver"
197 #define PRECISION (-3) /* precision assumed (about 100 ms) */
200 * JJY unit control structure
203 char unittype ; /* UNITTYPE_XXXXXXXXXX */
204 short operationmode ; /* Echo Keisokuki LT-2000 : 1 or 2 */
206 short linediscipline ; /* LDISC_CLK or LDISC_RAW */
207 char bPollFlag ; /* Set by jjy_pool and Reset by jjy_receive */
210 int year, month, day, hour, minute, second, msecond ;
212 #define MAX_LINECOUNT 8
213 #define MAX_RAWBUF 64
215 int charexpect [ MAX_LINECOUNT ] ;
217 char rawbuf [ MAX_RAWBUF ] ;
220 #define UNITTYPE_TRISTATE_JJY01 1
221 #define UNITTYPE_CDEX_JST2000 2
222 #define UNITTYPE_ECHOKEISOKUKI_LT2000 3
223 #define UNITTYPE_CITIZENTIC_JJY200 4
224 #define UNITTYPE_TRISTATE_GPSCLOCK01 5
227 * Function prototypes
230 static int jjy_start (int, struct peer *);
231 static void jjy_shutdown (int, struct peer *);
233 static void jjy_poll (int, struct peer *);
234 static void jjy_poll_tristate_jjy01 (int, struct peer *);
235 static void jjy_poll_cdex_jst2000 (int, struct peer *);
236 static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *);
237 static void jjy_poll_citizentic_jjy200 (int, struct peer *);
238 static void jjy_poll_tristate_gpsclock01 (int, struct peer *);
240 static void jjy_receive (struct recvbuf *);
241 static int jjy_receive_tristate_jjy01 (struct recvbuf *);
242 static int jjy_receive_cdex_jst2000 (struct recvbuf *);
243 static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
244 static int jjy_receive_citizentic_jjy200 (struct recvbuf *);
245 static int jjy_receive_tristate_gpsclock01 (struct recvbuf *);
247 static void printableString ( char*, int, char*, int ) ;
252 struct refclock refclock_jjy = {
253 jjy_start, /* start up driver */
254 jjy_shutdown, /* shutdown driver */
255 jjy_poll, /* transmit poll message */
256 noentry, /* not used */
257 noentry, /* not used */
258 noentry, /* not used */
259 NOFLAGS /* not used */
263 * Start up driver return code
265 #define RC_START_SUCCESS 1
266 #define RC_START_ERROR 0
269 * Local constants definition
272 #define MAX_LOGTEXT 64
275 * Tristate JJY01/JJY02 constants definition
278 #define TS_JJY01_COMMAND_NUMBER_DATE 1
279 #define TS_JJY01_COMMAND_NUMBER_TIME 2
280 #define TS_JJY01_COMMAND_NUMBER_STIM 3
281 #define TS_JJY01_COMMAND_NUMBER_STUS 4
282 #define TS_JJY01_COMMAND_NUMBER_DCST 5
284 #define TS_JJY01_REPLY_DATE "yyyy/mm/dd www\r\n"
285 #define TS_JJY01_REPLY_STIM "hh:mm:ss\r\n"
286 #define TS_JJY01_REPLY_STUS_YES "adjusted\r\n"
287 #define TS_JJY01_REPLY_STUS_NO "unadjusted\r\n"
288 #define TS_JJY01_REPLY_DCST_VALID "valid\r\n"
289 #define TS_JJY01_REPLY_DCST_INVALID "invalid\r\n"
291 #define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */
292 #define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */
293 #define TS_JJY01_REPLY_LENGTH_STUS_YES 8 /* Length without <CR><LF> */
294 #define TS_JJY01_REPLY_LENGTH_STUS_NO 10 /* Length without <CR><LF> */
295 #define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */
296 #define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */
300 const char commandNumber ;
301 const char *commandLog ;
302 const char *command ;
304 } tristate_jjy01_command_sequence[] =
306 /* dcst<CR><LF> -> VALID<CR><LF> or INVALID<CR><LF> */
307 { TS_JJY01_COMMAND_NUMBER_DCST, "dcst", "dcst\r\n", 6 },
308 /* stus<CR><LF> -> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
309 { TS_JJY01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
310 /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
311 { TS_JJY01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
312 /* stim<CR><LF> -> HH:MM:SS<CR><LF> */
313 { TS_JJY01_COMMAND_NUMBER_STIM, "stim", "stim\r\n", 6 },
319 * Tristate TS-GPSCLOCK01 constants definition
322 #define TS_GPSCLOCK01_COMMAND_NUMBER_DATE 1
323 #define TS_GPSCLOCK01_COMMAND_NUMBER_TIME 2
324 #define TS_GPSCLOCK01_COMMAND_NUMBER_STUS 4
326 #define TS_GPSCLOCK01_REPLY_DATE "yyyy/mm/dd\r\n"
327 #define TS_GPSCLOCK01_REPLY_TIME "hh:mm:ss\r\n"
328 #define TS_GPSCLOCK01_REPLY_STUS_RTC "*R\r\n"
329 #define TS_GPSCLOCK01_REPLY_STUS_GPS "*G\r\n"
330 #define TS_GPSCLOCK01_REPLY_STUS_UTC "*U\r\n"
331 #define TS_GPSCLOCK01_REPLY_STUS_PPS "+U\r\n"
333 #define TS_GPSCLOCK01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */
334 #define TS_GPSCLOCK01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
335 #define TS_GPSCLOCK01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */
340 const char *commandLog ;
341 const char *command ;
343 } tristate_gpsclock01_command_sequence[] =
345 /* stus<CR><LF> -> *R<CR><LF> or *G<CR><LF> or *U<CR><LF> or +U<CR><LF> */
346 { TS_GPSCLOCK01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
347 /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
348 { TS_GPSCLOCK01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
349 /* time<CR><LF> -> HH:MM:SS<CR><LF> */
350 { TS_GPSCLOCK01_COMMAND_NUMBER_TIME, "time", "time\r\n", 6 },
355 /**************************************************************************************************/
356 /* jjy_start - open the devices and initialize data for processing */
357 /**************************************************************************************************/
359 jjy_start ( int unit, struct peer *peer )
363 struct refclockproc *pp ;
369 char sLogText [ MAX_LOGTEXT ] , sDevText [ MAX_LOGTEXT ] ;
373 printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ;
374 printf ( DEVICE, unit ) ;
378 snprintf ( sDevText, sizeof(sDevText), DEVICE, unit ) ;
379 snprintf ( sLogText, sizeof(sLogText), "*Initialze* %s mode=%d", sDevText, peer->ttl ) ;
380 record_clock_stats ( &peer->srcadr, sLogText ) ;
385 pDeviceName = emalloc ( strlen(DEVICE) + 10 );
386 snprintf ( pDeviceName, strlen(DEVICE) + 10, DEVICE, unit ) ;
389 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
391 switch ( peer->ttl ) {
394 iDiscipline = LDISC_CLK ;
395 iSpeed232 = SPEED232_TRISTATE_JJY01 ;
398 iDiscipline = LDISC_RAW ;
399 iSpeed232 = SPEED232_CDEX_JST2000 ;
402 iDiscipline = LDISC_CLK ;
403 iSpeed232 = SPEED232_ECHOKEISOKUKI_LT2000 ;
406 iDiscipline = LDISC_CLK ;
407 iSpeed232 = SPEED232_CITIZENTIC_JJY200 ;
410 iDiscipline = LDISC_CLK ;
411 iSpeed232 = SPEED232_TRISTATE_GPSCLOCK01 ;
414 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
415 ntoa(&peer->srcadr), peer->ttl ) ;
416 free ( (void*) pDeviceName ) ;
417 return RC_START_ERROR ;
420 fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ;
422 free ( (void*) pDeviceName ) ;
423 return RC_START_ERROR ;
425 free ( (void*) pDeviceName ) ;
428 * Allocate and initialize unit structure
430 up = emalloc (sizeof(*up));
431 memset ( up, 0, sizeof(*up) ) ;
432 up->linediscipline = iDiscipline ;
435 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
437 switch ( peer->ttl ) {
440 * The mode 0 is a default clock type at this time.
441 * But this will be change to auto-detect mode in the future.
444 up->unittype = UNITTYPE_TRISTATE_JJY01 ;
447 /* Command sequence is defined by the struct tristate_jjy01_command_sequence, */
448 /* and the following 3 lines are not used in the mode LDISC_CLK. */
449 /* up->lineexpect = 2 ; */
450 /* up->charexpect[0] = 14 ; */ /* YYYY/MM/DD WWW<CR><LF> */
451 /* up->charexpect[1] = 8 ; */ /* HH:MM:SS<CR><LF> */
454 up->unittype = UNITTYPE_CDEX_JST2000 ;
456 up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
459 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
460 up->operationmode = 2 ; /* Mode 2 : Continuous mode */
462 switch ( up->operationmode ) {
464 up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
467 up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
472 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
474 up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
477 up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
481 /* The "default:" section of this switch block is never executed, */
482 /* because the former switch block traps the same "default:" case. */
483 /* This "default:" section codes are removed to avoid spending time */
484 /* in the future looking, though the codes are functionally harmless. */
490 pp->io.clock_recv = jjy_receive ;
491 pp->io.srcclock = peer ;
494 if ( ! io_addclock(&pp->io) ) {
499 return RC_START_ERROR ;
503 * Initialize miscellaneous variables
505 peer->precision = PRECISION ;
506 pp->clockdesc = DESCRIPTION ;
507 memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
509 return RC_START_SUCCESS ;
514 /**************************************************************************************************/
515 /* jjy_shutdown - shutdown the clock */
516 /**************************************************************************************************/
518 jjy_shutdown ( int unit, struct peer *peer )
522 struct refclockproc *pp;
526 if ( -1 != pp->io.fd )
527 io_closeclock ( &pp->io ) ;
534 /**************************************************************************************************/
535 /* jjy_receive - receive data from the serial interface */
536 /**************************************************************************************************/
538 jjy_receive ( struct recvbuf *rbufp )
542 struct refclockproc *pp ;
545 l_fp tRecvTimestamp; /* arrival timestamp */
547 char sLogText [ MAX_LOGTEXT ] ;
551 * Initialize pointers and read the timecode and timestamp
553 peer = rbufp->recv_peer ;
558 * Get next input line
560 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
562 if ( up->linediscipline == LDISC_RAW ) {
564 * The reply with <STX> and <ETX> may give a blank line
566 if ( pp->lencode == 0 && up->charcount == 0 ) return ;
568 * Copy received charaters to temporary buffer
571 i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ;
572 i ++ , up->charcount ++ ) {
573 up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
575 while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
576 for ( i = 0 ; i < up->charcount - 1 ; i ++ )
577 up->rawbuf[i] = up->rawbuf[i+1] ;
581 for ( i = 0 ; i < up->charcount ; i ++ ) {
582 if ( up->rawbuf[i] < ' ' ) {
587 if ( pp->lencode > 0 && up->linecount < up->lineexpect ) {
588 if ( bCntrlChar == 0 &&
589 up->charcount < up->charexpect[up->linecount] )
592 up->rawbuf[up->charcount] = 0 ;
595 * The reply with <CR><LF> gives a blank line
597 if ( pp->lencode == 0 ) return ;
600 * We get down to business
605 if ( up->linediscipline == LDISC_RAW ) {
606 printableString( sLogText, MAX_LOGTEXT, up->rawbuf, up->charcount ) ;
608 printableString( sLogText, MAX_LOGTEXT, pp->a_lastcode, pp->lencode ) ;
610 printf ( "jjy_receive (refclock_jjy.c) : [%s]\n", sLogText ) ;
614 pp->lastrec = tRecvTimestamp ;
618 if ( up->lineerror != 0 ) return ;
620 switch ( up->unittype ) {
622 case UNITTYPE_TRISTATE_JJY01 :
623 rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
626 case UNITTYPE_CDEX_JST2000 :
627 rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
630 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
631 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
634 case UNITTYPE_CITIZENTIC_JJY200 :
635 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
638 case UNITTYPE_TRISTATE_GPSCLOCK01 :
639 rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
648 if ( up->linediscipline == LDISC_RAW ) {
649 if ( up->linecount <= up->lineexpect &&
650 up->charcount > up->charexpect[up->linecount-1] ) {
652 i < up->charcount - up->charexpect[up->linecount-1] ;
654 up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
656 up->charcount -= up->charexpect[up->linecount-1] ;
668 if ( up->lineerror != 0 ) {
669 refclock_report ( peer, CEVNT_BADREPLY ) ;
670 strlcpy ( sLogText, "BAD REPLY [",
671 sizeof( sLogText ) ) ;
672 if ( up->linediscipline == LDISC_RAW ) {
673 strlcat ( sLogText, up->rawbuf,
674 sizeof( sLogText ) ) ;
676 strlcat ( sLogText, pp->a_lastcode,
677 sizeof( sLogText ) ) ;
679 sLogText[MAX_LOGTEXT-1] = 0 ;
680 if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 )
681 strlcat ( sLogText, "]",
682 sizeof( sLogText ) ) ;
683 record_clock_stats ( &peer->srcadr, sLogText ) ;
687 pp->year = up->year ;
688 pp->day = ymd2yd ( up->year, up->month, up->day ) ;
689 pp->hour = up->hour ;
690 pp->minute = up->minute ;
691 pp->second = up->second ;
692 pp->nsec = up->msecond * 1000000;
698 if ( pp->hour < 0 ) {
703 pp->day = ymd2yd ( pp->year, 12, 31 ) ;
708 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST ",
709 up->year, up->month, up->day, up->hour,
710 up->minute, up->second, up->msecond/100 ) ;
711 printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
712 pp->year, pp->day, pp->hour, pp->minute,
713 pp->second, (int)(pp->nsec/100000000) ) ;
718 * Process the new sample in the median filter and determine the
719 * timecode timestamp.
722 snprintf ( sLogText, sizeof(sLogText),
723 "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
724 up->year, up->month, up->day,
725 up->hour, up->minute, up->second, up->msecond/100 ) ;
726 record_clock_stats ( &peer->srcadr, sLogText ) ;
728 if ( ! refclock_process ( pp ) ) {
729 refclock_report(peer, CEVNT_BADTIME);
733 pp->lastref = pp->lastrec;
734 refclock_receive(peer);
738 /**************************************************************************************************/
741 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
744 static const char *sFunctionName = "jjy_receive_tristate_jjy01" ;
748 struct refclockproc *pp ;
755 int bOverMidnight = 0 ;
757 char sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ;
763 * Initialize pointers and read the timecode and timestamp
765 peer = rbufp->recv_peer ;
769 if ( up->linediscipline == LDISC_RAW ) {
771 iLen = up->charcount ;
773 pBuf = pp->a_lastcode ;
777 switch ( tristate_jjy01_command_sequence[up->linecount-1].commandNumber ) {
779 case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
781 if ( iLen != TS_JJY01_REPLY_LENGTH_DATE ) {
786 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year,
787 &up->month, &up->day ) ;
788 if ( rc != 3 || up->year < 2000 || up->month < 1 ||
789 up->month > 12 || up->day < 1 || up->day > 31 ) {
794 /*** Start of modification on 2004/10/31 ***/
796 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
797 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
798 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
799 * so this driver issues the second command "stim" after the reply of the first command "date".
804 * Codes of a next command issue are moved to the end of this function.
807 /*** End of modification ***/
811 case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
812 case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
814 if ( iLen != TS_JJY01_REPLY_LENGTH_STIM ) {
819 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour,
820 &up->minute, &up->second ) ;
821 if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
828 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
830 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver separately,
831 * and the JJY receiver replies a date and time separately.
832 * Just after midnight transitions, we ignore this time.
838 case TS_JJY01_COMMAND_NUMBER_STUS :
840 if ( ( iLen == TS_JJY01_REPLY_LENGTH_STUS_YES
841 && strncmp( pBuf, TS_JJY01_REPLY_STUS_YES,
842 TS_JJY01_REPLY_LENGTH_STUS_YES ) == 0 )
843 || ( iLen == TS_JJY01_REPLY_LENGTH_STUS_NO
844 && strncmp( pBuf, TS_JJY01_REPLY_STUS_NO,
845 TS_JJY01_REPLY_LENGTH_STUS_NO ) == 0 ) ) {
854 case TS_JJY01_COMMAND_NUMBER_DCST :
856 if ( ( iLen == TS_JJY01_REPLY_LENGTH_DCST_VALID
857 && strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
858 TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 )
859 || ( iLen == TS_JJY01_REPLY_LENGTH_DCST_INVALID
860 && strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
861 TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) ) {
870 default : /* Unexpected reply */
879 printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
880 snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
882 tristate_jjy01_command_sequence[up->linecount-1].commandLog,
883 ( up->lineerror == 0 )
884 ? ( ( bOverMidnight == 0 )
889 record_clock_stats ( &peer->srcadr, sLogText ) ;
891 /* Check before issue next command */
893 if ( up->lineerror != 0 ) {
894 /* Do not issue next command */
898 if ( bOverMidnight != 0 ) {
899 /* Do not issue next command */
903 if ( tristate_jjy01_command_sequence[up->linecount].command == NULL ) {
904 /* Command sequence completed */
908 /* Issue next command */
912 printf ( "%s (refclock_jjy.c) : send '%s'\n",
913 sFunctionName, tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
917 pCmd = tristate_jjy01_command_sequence[up->linecount].command ;
918 iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
919 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
920 refclock_report ( peer, CEVNT_FAULT ) ;
927 /**************************************************************************************************/
930 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
933 static const char *sFunctionName = "jjy_receive_cdex_jst2000" ;
937 struct refclockproc *pp ;
945 * Initialize pointers and read the timecode and timestamp
947 peer = rbufp->recv_peer ;
951 if ( up->linediscipline == LDISC_RAW ) {
953 iLen = up->charcount ;
955 pBuf = pp->a_lastcode ;
959 switch ( up->linecount ) {
961 case 1 : /* JYYMMDD HHMMSSS */
966 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
967 sFunctionName, iLen ) ;
973 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
974 &up->year, &up->month, &up->day,
975 &up->hour, &up->minute, &up->second,
977 if ( rc != 7 || up->month < 1 || up->month > 12 ||
978 up->day < 1 || up->day > 31 || up->hour > 23 ||
979 up->minute > 59 || up->second > 60 ) {
982 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n",
983 sFunctionName, rc, up->year,
984 up->month, up->day, up->hour,
985 up->minute, up->second,
996 default : /* Unexpected reply */
1007 /**************************************************************************************************/
1010 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1013 static const char *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
1016 struct jjyunit *up ;
1017 struct refclockproc *pp ;
1023 int i, ibcc, ibcc1, ibcc2 ;
1026 * Initialize pointers and read the timecode and timestamp
1028 peer = rbufp->recv_peer ;
1029 pp = peer->procptr ;
1032 if ( up->linediscipline == LDISC_RAW ) {
1034 iLen = up->charcount ;
1036 pBuf = pp->a_lastcode ;
1037 iLen = pp->lencode ;
1040 switch ( up->linecount ) {
1042 case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1044 if ( ( up->operationmode == 1 && iLen != 15 ) ||
1045 ( up->operationmode == 2 && iLen != 17 ) ) {
1048 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
1049 sFunctionName, iLen ) ;
1052 if ( up->operationmode == 1 ) {
1055 printf ( "%s (refclock_jjy.c) : send '#'\n", __func__ ) ;
1058 if ( write ( pp->io.fd, "#",1 ) != 1 ) {
1059 refclock_report ( peer, CEVNT_FAULT ) ;
1066 if ( up->operationmode == 1 ) {
1068 for ( i = ibcc = 0 ; i < 13 ; i ++ )
1070 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1071 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
1072 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1075 printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n",
1088 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1089 &up->year, &up->month, &up->day,
1090 &up->hour, &up->minute, &up->second ) ;
1091 if ( rc != 6 || up->month < 1 || up->month > 12 ||
1092 up->day < 1 || up->day > 31 || up->hour > 23 ||
1093 up->minute > 59 || up->second > 60 ) {
1096 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n",
1097 sFunctionName, rc, up->year,
1098 up->month, up->day, up->hour,
1099 up->minute, up->second ) ;
1108 if ( up->operationmode == 2 ) {
1110 /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
1113 if ( pp->second < 0 ) {
1116 if ( pp->minute < 0 ) {
1119 if ( pp->hour < 0 ) {
1122 if ( pp->day < 1 ) {
1124 pp->day = ymd2yd ( pp->year, 12, 31 ) ;
1130 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1133 printf ( "%s (refclock_jjy.c) : send '#'\n",
1137 if ( write ( pp->io.fd, "#",1 ) != 1 ) {
1138 refclock_report ( peer, CEVNT_FAULT ) ;
1145 default : /* Unexpected reply */
1149 printf ( "%s (refclock_jjy.c) : send '#'\n",
1153 if ( write ( pp->io.fd, "#",1 ) != 1 ) {
1154 refclock_report ( peer, CEVNT_FAULT ) ;
1166 /**************************************************************************************************/
1169 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1172 static const char *sFunctionName = "jjy_receive_citizentic_jjy200" ;
1175 struct jjyunit *up ;
1176 struct refclockproc *pp ;
1182 char cApostrophe, sStatus[3] ;
1186 * Initialize pointers and read the timecode and timestamp
1188 peer = rbufp->recv_peer ;
1189 pp = peer->procptr ;
1192 if ( up->linediscipline == LDISC_RAW ) {
1194 iLen = up->charcount ;
1196 pBuf = pp->a_lastcode ;
1197 iLen = pp->lencode ;
1201 * JJY-200 sends a timestamp every second.
1202 * So, a timestamp is ignored unless it is right after polled.
1204 if ( ! up->bPollFlag )
1207 switch ( up->linecount ) {
1209 case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
1214 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
1215 sFunctionName, iLen ) ;
1222 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1223 &cApostrophe, sStatus, &up->year,
1224 &up->month, &up->day, &iWeekday,
1225 &up->hour, &up->minute, &up->second ) ;
1227 if ( rc != 9 || cApostrophe != '\'' ||
1228 strcmp( sStatus, "OK" ) != 0 || up->month < 1 ||
1229 up->month > 12 || up->day < 1 || up->day > 31 ||
1230 iWeekday > 6 || up->hour > 23 || up->minute > 59 ||
1234 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n",
1235 sFunctionName, rc, cApostrophe,
1236 sStatus, up->year, up->month,
1237 up->day, iWeekday, up->hour,
1238 up->minute, up->second ) ;
1250 default : /* Unexpected reply */
1261 /**************************************************************************************************/
1264 jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
1267 static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ;
1270 struct jjyunit *up ;
1271 struct refclockproc *pp ;
1278 int bOverMidnight = 0 ;
1280 char sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ;
1286 * Initialize pointers and read the timecode and timestamp
1288 peer = rbufp->recv_peer ;
1289 pp = peer->procptr ;
1292 if ( up->linediscipline == LDISC_RAW ) {
1294 iLen = up->charcount ;
1296 pBuf = pp->a_lastcode ;
1297 iLen = pp->lencode ;
1301 * Ignore NMEA data stream
1304 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
1307 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
1308 sFunctionName, pBuf ) ;
1315 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
1317 if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
1319 } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
1325 * Ignore NMEA data stream after command prompt
1328 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
1331 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
1332 sFunctionName, pBuf ) ;
1338 switch ( tristate_gpsclock01_command_sequence[up->linecount-1].commandNumber ) {
1340 case TS_GPSCLOCK01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
1342 if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_DATE ) {
1347 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
1348 if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 ||
1349 up->day < 1 || up->day > 31 ) {
1356 case TS_GPSCLOCK01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1358 if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_TIME ) {
1363 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
1364 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1371 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
1373 * The command "date" and "time" were sent to the JJY receiver separately,
1374 * and the JJY receiver replies a date and time separately.
1375 * Just after midnight transitions, we ignore this time.
1382 case TS_GPSCLOCK01_COMMAND_NUMBER_STUS :
1384 if ( iLen == TS_GPSCLOCK01_REPLY_LENGTH_STUS
1385 && ( strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_RTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1386 || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_GPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1387 || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_UTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1388 || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_PPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 ) ) {
1397 default : /* Unexpected reply */
1404 /* Clockstats Log */
1406 printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
1407 snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
1409 tristate_gpsclock01_command_sequence[up->linecount-1].commandLog,
1410 ( up->lineerror == 0 )
1411 ? ( ( bOverMidnight == 0 )
1416 record_clock_stats ( &peer->srcadr, sLogText ) ;
1418 /* Check before issue next command */
1420 if ( up->lineerror != 0 ) {
1421 /* Do not issue next command */
1425 if ( bOverMidnight != 0 ) {
1426 /* Do not issue next command */
1430 if ( tristate_gpsclock01_command_sequence[up->linecount].command == NULL ) {
1431 /* Command sequence completed */
1435 /* Issue next command */
1439 printf ( "%s (refclock_jjy.c) : send '%s'\n",
1440 sFunctionName, tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
1444 pCmd = tristate_gpsclock01_command_sequence[up->linecount].command ;
1445 iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
1446 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1447 refclock_report ( peer, CEVNT_FAULT ) ;
1454 /**************************************************************************************************/
1455 /* jjy_poll - called by the transmit procedure */
1456 /**************************************************************************************************/
1458 jjy_poll ( int unit, struct peer *peer )
1462 struct refclockproc *pp;
1467 if ( pp->polls > 0 && up->linecount == 0 ) {
1469 * No reply for last command
1471 refclock_report ( peer, CEVNT_TIMEOUT ) ;
1476 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1487 switch ( up->unittype ) {
1489 case UNITTYPE_TRISTATE_JJY01 :
1490 jjy_poll_tristate_jjy01 ( unit, peer ) ;
1493 case UNITTYPE_CDEX_JST2000 :
1494 jjy_poll_cdex_jst2000 ( unit, peer ) ;
1497 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1498 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1501 case UNITTYPE_CITIZENTIC_JJY200 :
1502 jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1505 case UNITTYPE_TRISTATE_GPSCLOCK01 :
1506 jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
1516 /**************************************************************************************************/
1519 jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
1522 static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1526 struct refclockproc *pp;
1534 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1540 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
1541 sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1547 * Send a first command
1552 printf ( "%s (refclock_jjy.c) : send '%s'\n",
1554 tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
1558 pCmd = tristate_jjy01_command_sequence[up->linecount].command ;
1559 iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
1560 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1561 refclock_report ( peer, CEVNT_FAULT ) ;
1566 /**************************************************************************************************/
1569 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1572 struct refclockproc *pp;
1577 * Send "<ENQ>1J<ETX>" command
1582 printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1586 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
1587 refclock_report ( peer, CEVNT_FAULT ) ;
1592 /**************************************************************************************************/
1595 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1599 struct refclockproc *pp;
1607 * Send "T" or "C" command
1610 switch ( up->operationmode ) {
1611 case 1 : sCmd[0] = 'T' ; break ;
1612 case 2 : sCmd[0] = 'C' ; break ;
1618 printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1622 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
1623 refclock_report ( peer, CEVNT_FAULT ) ;
1628 /**************************************************************************************************/
1631 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1634 /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1638 /**************************************************************************************************/
1641 jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
1644 static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
1648 struct refclockproc *pp;
1656 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1662 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
1663 sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1669 * Send a first command
1674 printf ( "%s (refclock_jjy.c) : send '%s'\n",
1676 tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
1680 pCmd = tristate_gpsclock01_command_sequence[up->linecount].command ;
1681 iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
1682 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1683 refclock_report ( peer, CEVNT_FAULT ) ;
1688 /**************************************************************************************************/
1691 printableString ( char *sOutput, int iOutputLen, char *sInput, int iInputLen )
1693 const char *printableControlChar[] = {
1694 "<NUL>", "<SOH>", "<STX>", "<ETX>",
1695 "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
1696 "<BS>" , "<HT>" , "<LF>" , "<VT>" ,
1697 "<FF>" , "<CR>" , "<SO>" , "<SI>" ,
1698 "<DLE>", "<DC1>", "<DC2>", "<DC3>",
1699 "<DC4>", "<NAK>", "<SYN>", "<ETB>",
1700 "<CAN>", "<EM>" , "<SUB>", "<ESC>",
1701 "<FS>" , "<GS>" , "<RS>" , "<US>" ,
1708 InputLen = (size_t)iInputLen;
1709 OutputLen = (size_t)iOutputLen;
1710 for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
1711 if ( isprint( (unsigned char)sInput[i] ) ) {
1713 if ( j + 1 >= OutputLen )
1715 sOutput[j] = sInput[i] ;
1716 } else if ( ( sInput[i] & 0xFF ) <
1717 COUNTOF(printableControlChar) ) {
1718 n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
1719 if ( j + n + 1 >= OutputLen )
1721 strlcpy( sOutput + j,
1722 printableControlChar[sInput[i] & 0xFF],
1726 if ( j + n + 1 >= OutputLen )
1728 snprintf( sOutput + j, OutputLen - j, "<x%X>",
1729 sInput[i] & 0xFF ) ;
1734 sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
1738 /**************************************************************************************************/
1741 int refclock_jjy_bs ;
1742 #endif /* REFCLOCK */