Sync usage with man page.
[netbsd-mini2440.git] / dist / ntp / ntpd / refclock_jjy.c
blobd8e883eae8e0fb0bf20066141716867f90f85c24
1 /* $NetBSD: refclock_jjy.c,v 1.4 2007/01/06 19:45:23 kardel Exp $ */
3 /*
4 * refclock_jjy - clock driver for JJY receivers
5 */
7 /**********************************************************************/
8 /* */
9 /* Copyright (C) 2001-2004, Takao Abe. All rights reserved. */
10 /* */
11 /* Permission to use, copy, modify, and distribute this software */
12 /* and its documentation for any purpose is hereby granted */
13 /* without fee, provided that the following conditions are met: */
14 /* */
15 /* One retains the entire copyright notice properly, and both the */
16 /* copyright notice and this license. in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* This software and the name of the author must not be used to */
20 /* endorse or promote products derived from this software without */
21 /* prior written permission. */
22 /* */
23 /* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */
24 /* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */
25 /* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */
26 /* PARTICULAR PURPOSE. */
27 /* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */
28 /* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
29 /* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
30 /* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */
31 /* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */
32 /* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */
33 /* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */
34 /* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
35 /* */
36 /* This driver is developed in my private time, and is opened as */
37 /* voluntary contributions for the NTP. */
38 /* The manufacturer of the JJY receiver has not participated in */
39 /* a development of this driver. */
40 /* The manufacturer does not warrant anything about this driver, */
41 /* and is not liable for anything about this driver. */
42 /* */
43 /**********************************************************************/
44 /* */
45 /* Author Takao Abe */
46 /* Email abetakao@bea.hi-ho.ne.jp */
47 /* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */
48 /* */
49 /**********************************************************************/
50 /* */
51 /* History */
52 /* */
53 /* 2001/07/15 */
54 /* [New] Support the Tristate Ltd. JJY receiver */
55 /* */
56 /* 2001/08/04 */
57 /* [Change] Log to clockstats even if bad reply */
58 /* [Fix] PRECISION = (-3) (about 100 ms) */
59 /* [Add] Support the C-DEX Co.Ltd. JJY receiver */
60 /* */
61 /* 2001/12/04 */
62 /* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */
63 /* */
64 /* 2002/07/12 */
65 /* [Fix] Portability for FreeBSD ( patched by the user ) */
66 /* */
67 /* 2004/10/31 */
68 /* [Change] Command send timing for the Tristate Ltd. JJY receiver */
69 /* JJY-01 ( Firmware version 2.01 ) */
70 /* Thanks to Andy Taki for testing under FreeBSD */
71 /* */
72 /* 2004/11/28 */
73 /* [Add] Support the Echo Keisokuki LT-2000 receiver */
74 /* */
75 /* 2006/11/04 */
76 /* [Fix] C-DEX JST2000 */
77 /* Thanks to Hideo Kuramatsu for the patch */
78 /* */
79 /* 2009/04/05 */
80 /* [Add] Support the CITIZEN T.I.C JJY-200 receiver */
81 /* */
82 /**********************************************************************/
84 #ifdef HAVE_CONFIG_H
85 #include <config.h>
86 #endif
88 #if defined(REFCLOCK) && defined(CLOCK_JJY)
90 #include <stdio.h>
91 #include <ctype.h>
92 #include <string.h>
93 #include <sys/time.h>
94 #include <time.h>
96 #include "ntpd.h"
97 #include "ntp_io.h"
98 #include "ntp_tty.h"
99 #include "ntp_refclock.h"
100 #include "ntp_calendar.h"
101 #include "ntp_stdlib.h"
103 /**********************************************************************/
104 /* */
105 /* The Tristate Ltd. JJY receiver JJY01 */
106 /* */
107 /* Command Response Remarks */
108 /* ------------ ---------------------- --------------------- */
109 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */
110 /* time<CR><LF> HH:MM:SS<CR><LF> */
111 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
112 /* */
113 /* During synchronization after a receiver is turned on, */
114 /* It replies the past time from 2000/01/01 00:00:00. */
115 /* The function "refclock_process" checks the time and tells */
116 /* as an insanity time. */
117 /* */
118 /**********************************************************************/
119 /* */
120 /* The C-DEX Co. Ltd. JJY receiver JST2000 */
121 /* */
122 /* Command Response Remarks */
123 /* ------------ ---------------------- --------------------- */
124 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */
125 /* */
126 /**********************************************************************/
127 /* */
128 /* The Echo Keisokuki Co. Ltd. JJY receiver LT2000 */
129 /* */
130 /* Command Response Remarks */
131 /* ------------ ---------------------- --------------------- */
132 /* # Mode 1 (Request&Send) */
133 /* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
134 /* C Mode 2 (Continuous) */
135 /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
136 /* <SUB> Second signal */
137 /* */
138 /**********************************************************************/
139 /* */
140 /* The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 */
141 /* */
142 /* Command Response Remarks */
143 /* ------------ ---------------------- --------------------- */
144 /* 'XX YY/MM/DD W HH:MM:SS<CR> */
145 /* XX: OK|NG|ER */
146 /* W: 0(Monday)-6(Sunday) */
147 /* */
148 /**********************************************************************/
151 * Interface definitions
153 #define DEVICE "/dev/jjy%d" /* device name and unit */
154 #define SPEED232 B9600 /* uart speed (9600 baud) */
155 #define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
156 #define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
157 #define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
158 #define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
159 #define REFID "JJY" /* reference ID */
160 #define DESCRIPTION "JJY Receiver"
161 #define PRECISION (-3) /* precision assumed (about 100 ms) */
164 * JJY unit control structure
166 struct jjyunit {
167 char unittype ; /* UNITTYPE_XXXXXXXXXX */
168 short operationmode ; /* Echo Keisokuki LT-2000 : 1 or 2 */
169 short version ;
170 short linediscipline ; /* LDISC_CLK or LDISC_RAW */
171 char bPollFlag ; /* Set by jjy_pool and Reset by jjy_receive */
172 int linecount ;
173 int lineerror ;
174 int year, month, day, hour, minute, second, msecond ;
175 /* LDISC_RAW only */
176 #define MAX_LINECOUNT 8
177 #define MAX_RAWBUF 64
178 int lineexpect ;
179 int charexpect [ MAX_LINECOUNT ] ;
180 int charcount ;
181 char rawbuf [ MAX_RAWBUF ] ;
184 #define UNITTYPE_TRISTATE_JJY01 1
185 #define UNITTYPE_CDEX_JST2000 2
186 #define UNITTYPE_ECHOKEISOKUKI_LT2000 3
187 #define UNITTYPE_CITIZENTIC_JJY200 4
190 * Function prototypes
192 static int jjy_start P((int, struct peer *));
193 static void jjy_shutdown P((int, struct peer *));
194 static void jjy_poll P((int, struct peer *));
195 static void jjy_poll_tristate_jjy01 P((int, struct peer *));
196 static void jjy_poll_cdex_jst2000 P((int, struct peer *));
197 static void jjy_poll_echokeisokuki_lt2000 P((int, struct peer *));
198 static void jjy_poll_citizentic_jjy200 P((int, struct peer *));
199 static void jjy_receive P((struct recvbuf *));
200 static int jjy_receive_tristate_jjy01 P((struct recvbuf *));
201 static int jjy_receive_cdex_jst2000 P((struct recvbuf *));
202 static int jjy_receive_echokeisokuki_lt2000 P((struct recvbuf *));
203 static int jjy_receive_citizentic_jjy200 P((struct recvbuf *));
206 * Transfer vector
208 struct refclock refclock_jjy = {
209 jjy_start, /* start up driver */
210 jjy_shutdown, /* shutdown driver */
211 jjy_poll, /* transmit poll message */
212 noentry, /* not used */
213 noentry, /* not used */
214 noentry, /* not used */
215 NOFLAGS /* not used */
219 * Start up driver return code
221 #define RC_START_SUCCESS 1
222 #define RC_START_ERROR 0
225 * Local constants definition
228 #define MAX_LOGTEXT 64
231 /**************************************************************************************************/
232 /* jjy_start - open the devices and initialize data for processing */
233 /**************************************************************************************************/
234 static int
235 jjy_start ( int unit, struct peer *peer )
238 struct jjyunit *up ;
239 struct refclockproc *pp ;
240 int fd ;
241 char *pDeviceName ;
242 short iDiscipline ;
243 int iSpeed232 ;
245 #ifdef DEBUG
246 if ( debug ) {
247 printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ;
248 printf ( DEVICE, unit ) ;
249 printf ( "\n" ) ;
251 #endif
253 * Open serial port
255 if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
256 return RC_START_ERROR ;
258 sprintf ( pDeviceName, DEVICE, unit ) ;
261 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
263 switch ( peer->ttl ) {
264 case 0 :
265 case 1 :
266 iDiscipline = LDISC_CLK ;
267 iSpeed232 = SPEED232_TRISTATE_JJY01 ;
268 break ;
269 case 2 :
270 iDiscipline = LDISC_RAW ;
271 iSpeed232 = SPEED232_CDEX_JST2000 ;
272 break ;
273 case 3 :
274 iDiscipline = LDISC_CLK ;
275 iSpeed232 = SPEED232_ECHOKEISOKUKI_LT2000 ;
276 break ;
277 case 4 :
278 iDiscipline = LDISC_CLK ;
279 iSpeed232 = SPEED232_CITIZENTIC_JJY200 ;
280 break ;
281 default :
282 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
283 ntoa(&peer->srcadr), peer->ttl ) ;
284 free ( (void*) pDeviceName ) ;
285 return RC_START_ERROR ;
288 if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) {
289 free ( (void*) pDeviceName ) ;
290 return RC_START_ERROR ;
292 free ( (void*) pDeviceName ) ;
295 * Allocate and initialize unit structure
297 if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
298 close ( fd ) ;
299 return RC_START_ERROR ;
302 memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
303 up->linediscipline = iDiscipline ;
306 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
308 switch ( peer->ttl ) {
309 case 0 :
311 * The mode 0 is a default clock type at this time.
312 * But this will be change to auto-detect mode in the future.
314 case 1 :
315 up->unittype = UNITTYPE_TRISTATE_JJY01 ;
316 up->version = 100 ;
317 up->lineexpect = 2 ;
318 up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
319 up->charexpect[1] = 8 ; /* HH:MM:SS<CR><LF> */
320 break ;
321 case 2 :
322 up->unittype = UNITTYPE_CDEX_JST2000 ;
323 up->lineexpect = 1 ;
324 up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
325 break ;
326 case 3 :
327 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
328 up->operationmode = 2 ; /* Mode 2 : Continuous mode */
329 up->lineexpect = 1 ;
330 switch ( up->operationmode ) {
331 case 1 :
332 up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
333 break ;
334 case 2 :
335 up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
336 break ;
338 break ;
339 case 4 :
340 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
341 up->lineexpect = 1 ;
342 up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
343 break ;
344 default :
345 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
346 ntoa(&peer->srcadr), peer->ttl ) ;
347 close ( fd ) ;
348 free ( (void*) up ) ;
349 return RC_START_ERROR ;
352 pp = peer->procptr ;
353 pp->unitptr = (caddr_t) up ;
354 pp->io.clock_recv = jjy_receive ;
355 pp->io.srcclock = (caddr_t) peer ;
356 pp->io.datalen = 0 ;
357 pp->io.fd = fd ;
358 if ( ! io_addclock(&pp->io) ) {
359 close ( fd ) ;
360 free ( (void*) up ) ;
361 return RC_START_ERROR ;
365 * Initialize miscellaneous variables
367 peer->precision = PRECISION ;
368 peer->burst = 1 ;
369 pp->clockdesc = DESCRIPTION ;
370 memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
372 return RC_START_SUCCESS ;
377 /**************************************************************************************************/
378 /* jjy_shutdown - shutdown the clock */
379 /**************************************************************************************************/
380 static void
381 jjy_shutdown ( int unit, struct peer *peer )
384 struct jjyunit *up;
385 struct refclockproc *pp;
387 pp = peer->procptr ;
388 up = (struct jjyunit *) pp->unitptr ;
389 io_closeclock ( &pp->io ) ;
390 free ( (void*) up ) ;
395 /**************************************************************************************************/
396 /* jjy_receive - receive data from the serial interface */
397 /**************************************************************************************************/
398 static void
399 jjy_receive ( struct recvbuf *rbufp )
402 struct jjyunit *up ;
403 struct refclockproc *pp ;
404 struct peer *peer;
406 l_fp tRecvTimestamp; /* arrival timestamp */
407 int rc ;
408 char sLogText [ MAX_LOGTEXT ] ;
409 int i, bCntrlChar ;
412 * Initialize pointers and read the timecode and timestamp
414 peer = (struct peer *) rbufp->recv_srcclock ;
415 pp = peer->procptr ;
416 up = (struct jjyunit *) pp->unitptr ;
419 * Get next input line
421 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
423 if ( up->linediscipline == LDISC_RAW ) {
425 * The reply with <STX> and <ETX> may give a blank line
427 if ( pp->lencode == 0 && up->charcount == 0 ) return ;
429 * Copy received charaters to temporary buffer
431 for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
432 up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
434 while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
435 for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ;
436 up->charcount -- ;
438 bCntrlChar = 0 ;
439 for ( i = 0 ; i < up->charcount ; i ++ ) {
440 if ( up->rawbuf[i] < ' ' ) {
441 bCntrlChar = 1 ;
442 break ;
445 if ( pp->lencode > 0 && up->linecount < up->lineexpect ) {
446 if ( bCntrlChar == 0 && up->charcount < up->charexpect[up->linecount] ) return ;
448 up->rawbuf[up->charcount] = 0 ;
449 } else {
451 * The reply with <CR><LF> gives a blank line
453 if ( pp->lencode == 0 ) return ;
456 * We get down to business
459 pp->lastrec = tRecvTimestamp ;
461 up->linecount ++ ;
463 if ( up->lineerror != 0 ) return ;
465 switch ( up->unittype ) {
467 case UNITTYPE_TRISTATE_JJY01 :
468 rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
469 break ;
471 case UNITTYPE_CDEX_JST2000 :
472 rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
473 break ;
475 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
476 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
477 break ;
479 case UNITTYPE_CITIZENTIC_JJY200 :
480 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
481 break ;
483 default :
484 rc = 0 ;
485 break ;
489 if ( up->linediscipline == LDISC_RAW ) {
490 if ( up->linecount <= up->lineexpect && up->charcount > up->charexpect[up->linecount-1] ) {
491 for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) {
492 up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
494 up->charcount -= up->charexpect[up->linecount-1] ;
495 } else {
496 up->charcount = 0 ;
500 if ( rc == 0 ) return ;
502 up->bPollFlag = 0 ;
504 if ( up->lineerror != 0 ) {
505 refclock_report ( peer, CEVNT_BADREPLY ) ;
506 strcpy ( sLogText, "BAD REPLY [" ) ;
507 if ( up->linediscipline == LDISC_RAW ) {
508 strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
509 } else {
510 strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
512 sLogText[MAX_LOGTEXT-1] = 0 ;
513 if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
514 record_clock_stats ( &peer->srcadr, sLogText ) ;
515 return ;
518 pp->year = up->year ;
519 pp->day = ymd2yd ( up->year, up->month, up->day ) ;
520 pp->hour = up->hour ;
521 pp->minute = up->minute ;
522 pp->second = up->second ;
523 pp->nsec = up->msecond * 1000000;
526 * JST to UTC
528 pp->hour -= 9 ;
529 if ( pp->hour < 0 ) {
530 pp->hour += 24 ;
531 pp->day -- ;
532 if ( pp->day < 1 ) {
533 pp->year -- ;
534 pp->day = ymd2yd ( pp->year, 12, 31 ) ;
537 #ifdef DEBUG
538 if ( debug ) {
539 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST ",
540 up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
541 printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
542 pp->year, pp->day, pp->hour, pp->minute, pp->second, (int)(pp->nsec/100000000) ) ;
544 #endif
547 * Process the new sample in the median filter and determine the
548 * timecode timestamp.
551 sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
552 up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
553 record_clock_stats ( &peer->srcadr, sLogText ) ;
555 if ( ! refclock_process ( pp ) ) {
556 refclock_report(peer, CEVNT_BADTIME);
557 return ;
560 pp->lastref = pp->lastrec;
561 refclock_receive(peer);
565 /**************************************************************************************************/
567 static int
568 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
571 static char *sFunctionName = "jjy_receive_tristate_jjy01" ;
573 struct jjyunit *up ;
574 struct refclockproc *pp ;
575 struct peer *peer;
577 char *pBuf ;
578 int iLen ;
579 int rc ;
582 * Initialize pointers and read the timecode and timestamp
584 peer = (struct peer *) rbufp->recv_srcclock ;
585 pp = peer->procptr ;
586 up = (struct jjyunit *) pp->unitptr ;
588 if ( up->linediscipline == LDISC_RAW ) {
589 pBuf = up->rawbuf ;
590 iLen = up->charcount ;
591 } else {
592 pBuf = pp->a_lastcode ;
593 iLen = pp->lencode ;
596 switch ( up->linecount ) {
598 case 1 : /* YYYY/MM/DD WWW */
600 if ( iLen != 14 ) {
601 #ifdef DEBUG
602 if ( debug >= 2 ) {
603 printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
605 #endif
606 up->lineerror = 1 ;
607 break ;
609 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
610 if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
611 #ifdef DEBUG
612 if ( debug >= 2 ) {
613 printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
615 #endif
616 up->lineerror = 1 ;
617 break ;
620 /*** Start of modification on 2004/10/31 */
622 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
623 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
624 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
625 * so this driver issues the second command "stim" after the reply of the first command "date".
629 * Send "stim<CR><LF>" or "time<CR><LF>" command
633 if ( up->version >= 100 ) {
634 #ifdef DEBUG
635 if ( debug ) {
636 printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName ) ;
638 #endif
639 if ( write ( pp->io.fd, "stim\r\n",6 ) != 6 ) {
640 refclock_report ( peer, CEVNT_FAULT ) ;
642 } else {
643 #ifdef DEBUG
644 if ( debug ) {
645 printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName ) ;
647 #endif
648 if ( write ( pp->io.fd, "time\r\n",6 ) != 6 ) {
649 refclock_report ( peer, CEVNT_FAULT ) ;
652 /*** End of modification ***/
654 return 0 ;
656 case 2 : /* HH:MM:SS */
658 if ( iLen != 8 ) {
659 #ifdef DEBUG
660 if ( debug >= 2 ) {
661 printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
663 #endif
664 up->lineerror = 1 ;
665 break ;
667 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
668 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
669 #ifdef DEBUG
670 if ( debug >= 2 ) {
671 printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
673 #endif
674 up->lineerror = 1 ;
675 break ;
677 up->msecond = 0 ;
678 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
680 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
681 * But the JJY receiver replies a date and time separately.
682 * Just after midnight transitions, we ignore this time.
684 return 0 ;
686 break ;
688 default : /* Unexpected reply */
690 up->lineerror = 1 ;
691 break ;
695 return 1 ;
699 /**************************************************************************************************/
701 static int
702 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
705 static char *sFunctionName = "jjy_receive_cdex_jst2000" ;
707 struct jjyunit *up ;
708 struct refclockproc *pp ;
709 struct peer *peer;
711 char *pBuf ;
712 int iLen ;
713 int rc ;
716 * Initialize pointers and read the timecode and timestamp
718 peer = (struct peer *) rbufp->recv_srcclock ;
719 pp = peer->procptr ;
720 up = (struct jjyunit *) pp->unitptr ;
722 if ( up->linediscipline == LDISC_RAW ) {
723 pBuf = up->rawbuf ;
724 iLen = up->charcount ;
725 } else {
726 pBuf = pp->a_lastcode ;
727 iLen = pp->lencode ;
730 switch ( up->linecount ) {
732 case 1 : /* JYYMMDD HHMMSSS */
734 if ( iLen != 15 ) {
735 #ifdef DEBUG
736 if ( debug >= 2 ) {
737 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
739 #endif
740 up->lineerror = 1 ;
741 break ;
743 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
744 &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
745 if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
746 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
747 #ifdef DEBUG
748 if ( debug >= 2 ) {
749 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName,
750 rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ;
752 #endif
753 up->lineerror = 1 ;
754 break ;
756 up->year += 2000 ;
757 up->msecond *= 100 ;
758 break ;
760 default : /* Unexpected reply */
762 up->lineerror = 1 ;
763 break ;
767 return 1 ;
771 /**************************************************************************************************/
773 static int
774 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
777 static char *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
779 struct jjyunit *up ;
780 struct refclockproc *pp ;
781 struct peer *peer;
783 char *pBuf ;
784 int iLen ;
785 int rc ;
786 int i, ibcc, ibcc1, ibcc2 ;
789 * Initialize pointers and read the timecode and timestamp
791 peer = (struct peer *) rbufp->recv_srcclock ;
792 pp = peer->procptr ;
793 up = (struct jjyunit *) pp->unitptr ;
795 if ( up->linediscipline == LDISC_RAW ) {
796 pBuf = up->rawbuf ;
797 iLen = up->charcount ;
798 } else {
799 pBuf = pp->a_lastcode ;
800 iLen = pp->lencode ;
803 switch ( up->linecount ) {
805 case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
807 if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) {
808 #ifdef DEBUG
809 if ( debug >= 2 ) {
810 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
812 #endif
813 if ( up->operationmode == 1 ) {
814 #ifdef DEBUG
815 if ( debug ) {
816 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
818 #endif
819 if ( write ( pp->io.fd, "#",1 ) != 1 ) {
820 refclock_report ( peer, CEVNT_FAULT ) ;
823 up->lineerror = 1 ;
824 break ;
827 if ( up->operationmode == 1 ) {
829 for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ;
830 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
831 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
832 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
833 #ifdef DEBUG
834 if ( debug >= 2 ) {
835 printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ;
837 #endif
838 up->lineerror = 1 ;
839 break ;
844 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
845 &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ;
846 if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
847 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
848 #ifdef DEBUG
849 if ( debug >= 2 ) {
850 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName,
851 rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
853 #endif
854 up->lineerror = 1 ;
855 break ;
858 up->year += 2000 ;
860 if ( up->operationmode == 2 ) {
862 /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
863 up->msecond = 500 ;
864 pp->second -- ;
865 if ( pp->second < 0 ) {
866 pp->second = 59 ;
867 pp->minute -- ;
868 if ( pp->minute < 0 ) {
869 pp->minute = 59 ;
870 pp->hour -- ;
871 if ( pp->hour < 0 ) {
872 pp->hour = 23 ;
873 pp->day -- ;
874 if ( pp->day < 1 ) {
875 pp->year -- ;
876 pp->day = ymd2yd ( pp->year, 12, 31 ) ;
882 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
883 #ifdef DEBUG
884 if ( debug ) {
885 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
887 #endif
888 if ( write ( pp->io.fd, "#",1 ) != 1 ) {
889 refclock_report ( peer, CEVNT_FAULT ) ;
894 break ;
896 default : /* Unexpected reply */
898 #ifdef DEBUG
899 if ( debug ) {
900 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
902 #endif
903 if ( write ( pp->io.fd, "#",1 ) != 1 ) {
904 refclock_report ( peer, CEVNT_FAULT ) ;
907 up->lineerror = 1 ;
908 break ;
912 return 1 ;
916 /**************************************************************************************************/
918 static int
919 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
922 static char *sFunctionName = "jjy_receive_citizentic_jjy200" ;
924 struct jjyunit *up ;
925 struct refclockproc *pp ;
926 struct peer *peer;
928 char *pBuf ;
929 int iLen ;
930 int rc ;
931 char cApostrophe, sStatus[3] ;
932 int iWeekday ;
935 * Initialize pointers and read the timecode and timestamp
937 peer = (struct peer *) rbufp->recv_srcclock ;
938 pp = peer->procptr ;
939 up = (struct jjyunit *) pp->unitptr ;
941 if ( up->linediscipline == LDISC_RAW ) {
942 pBuf = up->rawbuf ;
943 iLen = up->charcount ;
944 } else {
945 pBuf = pp->a_lastcode ;
946 iLen = pp->lencode ;
950 * JJY-200 sends a timestamp every second.
951 * So, a timestamp is ignored unless it is right after polled.
953 if ( ! up->bPollFlag ) return 0 ;
955 switch ( up->linecount ) {
957 case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
959 if ( iLen != 23 ) {
960 #ifdef DEBUG
961 if ( debug >= 2 ) {
962 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
964 #endif
965 up->lineerror = 1 ;
966 break ;
969 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
970 &cApostrophe, sStatus,
971 &up->year, &up->month, &up->day, &iWeekday, &up->hour, &up->minute, &up->second ) ;
972 sStatus[2] = 0 ;
973 if ( rc != 9 || cApostrophe != '\'' || strcmp( sStatus, "OK" ) != 0
974 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
975 || iWeekday > 6
976 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
977 #ifdef DEBUG
978 if ( debug >= 2 ) {
979 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", sFunctionName,
980 rc, cApostrophe, sStatus, up->year, up->month, up->day, iWeekday, up->hour, up->minute, up->second ) ;
982 #endif
983 up->lineerror = 1 ;
984 break ;
987 up->year += 2000 ;
988 up->msecond = 0 ;
990 break ;
992 default : /* Unexpected reply */
994 up->lineerror = 1 ;
995 break ;
999 return 1 ;
1003 /**************************************************************************************************/
1004 /* jjy_poll - called by the transmit procedure */
1005 /**************************************************************************************************/
1006 static void
1007 jjy_poll ( int unit, struct peer *peer )
1010 struct jjyunit *up;
1011 struct refclockproc *pp;
1013 pp = peer->procptr;
1014 up = (struct jjyunit *) pp->unitptr ;
1016 if ( pp->polls > 0 && up->linecount == 0 ) {
1018 * No reply for last command
1020 refclock_report ( peer, CEVNT_TIMEOUT ) ;
1023 #ifdef DEBUG
1024 if ( debug ) {
1025 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1027 #endif
1029 pp->polls ++ ;
1031 up->bPollFlag = 1 ;
1032 up->linecount = 0 ;
1033 up->lineerror = 0 ;
1034 up->charcount = 0 ;
1036 switch ( up->unittype ) {
1038 case UNITTYPE_TRISTATE_JJY01 :
1039 jjy_poll_tristate_jjy01 ( unit, peer ) ;
1040 break ;
1042 case UNITTYPE_CDEX_JST2000 :
1043 jjy_poll_cdex_jst2000 ( unit, peer ) ;
1044 break ;
1046 case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1047 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1048 break ;
1050 case UNITTYPE_CITIZENTIC_JJY200 :
1051 jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1052 break ;
1054 default :
1055 break ;
1061 /**************************************************************************************************/
1063 static void
1064 jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
1067 struct refclockproc *pp;
1069 pp = peer->procptr;
1072 * Send "date<CR><LF>" command
1075 #ifdef DEBUG
1076 if ( debug ) {
1077 printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
1079 #endif
1081 if ( write ( pp->io.fd, "date\r\n",6 ) != 6 ) {
1082 refclock_report ( peer, CEVNT_FAULT ) ;
1087 /**************************************************************************************************/
1089 static void
1090 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1093 struct refclockproc *pp;
1095 pp = peer->procptr;
1098 * Send "<ENQ>1J<ETX>" command
1101 #ifdef DEBUG
1102 if ( debug ) {
1103 printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1105 #endif
1107 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
1108 refclock_report ( peer, CEVNT_FAULT ) ;
1113 /**************************************************************************************************/
1115 static void
1116 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1119 struct jjyunit *up;
1120 struct refclockproc *pp;
1122 char sCmd[2] ;
1124 pp = peer->procptr;
1125 up = (struct jjyunit *) pp->unitptr ;
1128 * Send "T" or "C" command
1131 switch ( up->operationmode ) {
1132 case 1 : sCmd[0] = 'T' ; break ;
1133 case 2 : sCmd[0] = 'C' ; break ;
1135 sCmd[1] = 0 ;
1137 #ifdef DEBUG
1138 if ( debug ) {
1139 printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1141 #endif
1143 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
1144 refclock_report ( peer, CEVNT_FAULT ) ;
1149 /**************************************************************************************************/
1151 static void
1152 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1155 /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1159 #else
1160 int refclock_jjy_bs ;
1161 #endif /* REFCLOCK */