xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_jjy.c (revision e19314b71341b008ff7f2dddecf21ab8fa1ed9fe)
1 /*	$NetBSD: refclock_jjy.c,v 1.2 2010/12/04 23:08:35 christos Exp $	*/
2 
3 /*
4  * refclock_jjy - clock driver for JJY receivers
5  */
6 
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 /**********************************************************************/
83 
84 #ifdef HAVE_CONFIG_H
85 #include <config.h>
86 #endif
87 
88 #if defined(REFCLOCK) && defined(CLOCK_JJY)
89 
90 #include <stdio.h>
91 #include <ctype.h>
92 #include <string.h>
93 #include <sys/time.h>
94 #include <time.h>
95 
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"
102 
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 /**********************************************************************/
149 
150 /*
151  * Interface definitions
152  */
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) */
162 
163 /*
164  * JJY unit control structure
165  */
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 ] ;
182 };
183 
184 #define	UNITTYPE_TRISTATE_JJY01	1
185 #define	UNITTYPE_CDEX_JST2000  	2
186 #define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
187 #define	UNITTYPE_CITIZENTIC_JJY200  	4
188 
189 /*
190  * Function prototypes
191  */
192 static	int 	jjy_start                   (int, struct peer *);
193 static	void	jjy_shutdown                (int, struct peer *);
194 static	void	jjy_poll                    (int, struct peer *);
195 static	void	jjy_poll_tristate_jjy01     (int, struct peer *);
196 static	void	jjy_poll_cdex_jst2000       (int, struct peer *);
197 static	void	jjy_poll_echokeisokuki_lt2000    (int, struct peer *);
198 static  void    jjy_poll_citizentic_jjy200          (int, struct peer *);
199 static	void	jjy_receive                 (struct recvbuf *);
200 static	int 	jjy_receive_tristate_jjy01  (struct recvbuf *);
201 static	int 	jjy_receive_cdex_jst2000    (struct recvbuf *);
202 static	int 	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
203 static  int     jjy_receive_citizentic_jjy200 (struct recvbuf *);
204 
205 /*
206  * Transfer vector
207  */
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 */
216 };
217 
218 /*
219  * Start up driver return code
220  */
221 #define	RC_START_SUCCESS	1
222 #define	RC_START_ERROR  	0
223 
224 /*
225  * Local constants definition
226  */
227 
228 #define	MAX_LOGTEXT	64
229 
230 
231 /**************************************************************************************************/
232 /*  jjy_start - open the devices and initialize data for processing                               */
233 /**************************************************************************************************/
234 static int
235 jjy_start ( int unit, struct peer *peer )
236 {
237 
238 	struct jjyunit      *up ;
239 	struct refclockproc *pp ;
240 	int 	fd ;
241 	char	*pDeviceName ;
242 	short	iDiscipline ;
243 	int 	iSpeed232 ;
244 
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" ) ;
250 	}
251 #endif
252 	/*
253 	 * Open serial port
254 	 */
255 	if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
256 		return RC_START_ERROR ;
257 	}
258 	sprintf ( pDeviceName, DEVICE, unit ) ;
259 
260 	/*
261 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
262 	 */
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 ;
286 	}
287 
288 	if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) {
289 		free ( (void*) pDeviceName ) ;
290 		return RC_START_ERROR ;
291 	}
292 	free ( (void*) pDeviceName ) ;
293 
294 	/*
295 	 * Allocate and initialize unit structure
296 	 */
297 	if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
298 		close ( fd ) ;
299 		return RC_START_ERROR ;
300 	}
301 
302 	memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
303 	up->linediscipline = iDiscipline ;
304 
305 	/*
306 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
307 	 */
308 	switch ( peer->ttl ) {
309 	case 0 :
310 		/*
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.
313 		 */
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 ;
337 		}
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 ;
350 	}
351 
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 ;
362 	}
363 
364 	/*
365 	 * Initialize miscellaneous variables
366 	 */
367 	peer->precision = PRECISION ;
368 	peer->burst     = 1 ;
369 	pp->clockdesc   = DESCRIPTION ;
370 	memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
371 
372 	return RC_START_SUCCESS ;
373 
374 }
375 
376 
377 /**************************************************************************************************/
378 /*  jjy_shutdown - shutdown the clock                                                             */
379 /**************************************************************************************************/
380 static void
381 jjy_shutdown ( int unit, struct peer *peer )
382 {
383 
384 	struct jjyunit      *up;
385 	struct refclockproc *pp;
386 
387 	pp = peer->procptr ;
388 	up = (struct jjyunit *) pp->unitptr ;
389 	io_closeclock ( &pp->io ) ;
390 	free ( (void*) up ) ;
391 
392 }
393 
394 
395 /**************************************************************************************************/
396 /*  jjy_receive - receive data from the serial interface                                          */
397 /**************************************************************************************************/
398 static void
399 jjy_receive ( struct recvbuf *rbufp )
400 {
401 
402 	struct jjyunit      *up ;
403 	struct refclockproc *pp ;
404 	struct peer         *peer;
405 
406 	l_fp	tRecvTimestamp;		/* arrival timestamp */
407 	int 	rc ;
408 	char	sLogText [ MAX_LOGTEXT ] ;
409 	int 	i, bCntrlChar ;
410 
411 	/*
412 	 * Initialize pointers and read the timecode and timestamp
413 	 */
414 	peer = (struct peer *) rbufp->recv_srcclock ;
415 	pp = peer->procptr ;
416 	up = (struct jjyunit *) pp->unitptr ;
417 
418 	/*
419 	 * Get next input line
420 	 */
421 	pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
422 
423 	if ( up->linediscipline == LDISC_RAW ) {
424 		/*
425 		 * The reply with <STX> and <ETX> may give a blank line
426 		 */
427 		if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
428 		/*
429 		 * Copy received charaters to temporary buffer
430 		 */
431 		for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
432 			up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
433 		}
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 -- ;
437 		}
438 		bCntrlChar = 0 ;
439 		for ( i = 0 ; i < up->charcount ; i ++ ) {
440 			if ( up->rawbuf[i] < ' ' ) {
441 				bCntrlChar = 1 ;
442 				break ;
443 			}
444 		}
445 		if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
446 			if ( bCntrlChar == 0  &&  up->charcount < up->charexpect[up->linecount] ) return ;
447 		}
448 		up->rawbuf[up->charcount] = 0 ;
449 	} else {
450 		/*
451 		 * The reply with <CR><LF> gives a blank line
452 		 */
453 		if ( pp->lencode == 0 ) return ;
454 	}
455 	/*
456 	 * We get down to business
457 	 */
458 
459 	pp->lastrec = tRecvTimestamp ;
460 
461 	up->linecount ++ ;
462 
463 	if ( up->lineerror != 0 ) return ;
464 
465 	switch ( up->unittype ) {
466 
467 	case UNITTYPE_TRISTATE_JJY01 :
468 		rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
469 		break ;
470 
471 	case UNITTYPE_CDEX_JST2000 :
472 		rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
473 		break ;
474 
475 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
476 		rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
477 		break ;
478 
479     case UNITTYPE_CITIZENTIC_JJY200 :
480         rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
481         break ;
482 
483 	default :
484 		rc = 0 ;
485 		break ;
486 
487 	}
488 
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]] ;
493 			}
494 			up->charcount -= up->charexpect[up->linecount-1] ;
495 		} else {
496 			up->charcount = 0 ;
497 		}
498 	}
499 
500 	if ( rc == 0 ) return ;
501 
502     up->bPollFlag = 0 ;
503 
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 ) ;
511 		}
512 		sLogText[MAX_LOGTEXT-1] = 0 ;
513 		if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
514 		record_clock_stats ( &peer->srcadr, sLogText ) ;
515 		return ;
516 	}
517 
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;
524 
525 	/*
526 	 * JST to UTC
527 	 */
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 ) ;
535 		}
536 	}
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) ) ;
543 	}
544 #endif
545 
546 	/*
547 	 * Process the new sample in the median filter and determine the
548 	 * timecode timestamp.
549 	 */
550 
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 ) ;
554 
555 	if ( ! refclock_process ( pp ) ) {
556 		refclock_report(peer, CEVNT_BADTIME);
557 		return ;
558 	}
559 
560 	pp->lastref = pp->lastrec;
561 	refclock_receive(peer);
562 
563 }
564 
565 /**************************************************************************************************/
566 
567 static int
568 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
569 {
570 
571 	struct jjyunit      *up ;
572 	struct refclockproc *pp ;
573 	struct peer         *peer;
574 
575 	char	*pBuf ;
576 	int 	iLen ;
577 	int 	rc ;
578 
579 	/*
580 	 * Initialize pointers and read the timecode and timestamp
581 	 */
582 	peer = (struct peer *) rbufp->recv_srcclock ;
583 	pp = peer->procptr ;
584 	up = (struct jjyunit *) pp->unitptr ;
585 
586 	if ( up->linediscipline == LDISC_RAW ) {
587 		pBuf = up->rawbuf ;
588 		iLen = up->charcount ;
589 	} else {
590 	    pBuf = pp->a_lastcode ;
591 	    iLen = pp->lencode ;
592 	}
593 
594 	switch ( up->linecount ) {
595 
596 	case 1 : /* YYYY/MM/DD WWW */
597 
598 		if ( iLen != 14 ) {
599 #ifdef DEBUG
600 	        if ( debug >= 2 ) {
601 		        printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d  iLen=%d )\n", __func__, up->linecount, iLen ) ;
602 	        }
603 #endif
604 			up->lineerror = 1 ;
605 			break ;
606 		}
607 		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
608 		if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
609 #ifdef DEBUG
610 	        if ( debug >= 2 ) {
611 		        printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", __func__, up->linecount ) ;
612 	        }
613 #endif
614 			up->lineerror = 1 ;
615 			break ;
616 		}
617 
618 		/*** Start of modification on 2004/10/31 */
619 		/*
620 		 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
621 		 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
622 		 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
623 		 * so this driver issues the second command "stim" after the reply of the first command "date".
624 		 */
625 
626 		/*
627 		 * Send "stim<CR><LF>" or "time<CR><LF>" command
628 		 */
629 
630 
631 		if ( up->version >= 100 ) {
632 #ifdef DEBUG
633 			if ( debug ) {
634 				printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", __func__ ) ;
635 			}
636 #endif
637 			if ( write ( pp->io.fd, "stim\r\n",6 ) != 6  ) {
638 				refclock_report ( peer, CEVNT_FAULT ) ;
639 			}
640 		} else {
641 #ifdef DEBUG
642 			if ( debug ) {
643 				printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", __func__ ) ;
644 			}
645 #endif
646 			if ( write ( pp->io.fd, "time\r\n",6 ) != 6  ) {
647 				refclock_report ( peer, CEVNT_FAULT ) ;
648 			}
649 		}
650 		/*** End of modification ***/
651 
652 		return 0 ;
653 
654 	case 2 : /* HH:MM:SS */
655 
656 		if ( iLen != 8 ) {
657 #ifdef DEBUG
658 	        if ( debug >= 2 ) {
659 		        printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d  iLen=%d )\n", __func__, up->linecount, iLen ) ;
660 	        }
661 #endif
662 			up->lineerror = 1 ;
663 			break ;
664 		}
665 		rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
666 		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
667 #ifdef DEBUG
668 	        if ( debug >= 2 ) {
669 		        printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", __func__, up->linecount ) ;
670 	        }
671 #endif
672 			up->lineerror = 1 ;
673 			break ;
674 		}
675 		up->msecond = 0 ;
676 		if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
677 			/*
678 			 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
679 			 * But the JJY receiver replies a date and time separately.
680 			 * Just after midnight transitions, we ignore this time.
681 			 */
682 			return 0 ;
683 		}
684 		break ;
685 
686 	default : /*  Unexpected reply */
687 
688 		up->lineerror = 1 ;
689 		break ;
690 
691 	}
692 
693 	return 1 ;
694 
695 }
696 
697 /**************************************************************************************************/
698 
699 static int
700 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
701 {
702 
703 	struct jjyunit      *up ;
704 	struct refclockproc *pp ;
705 	struct peer         *peer;
706 
707 	char	*pBuf ;
708 	int 	iLen ;
709 	int 	rc ;
710 
711 	/*
712 	 * Initialize pointers and read the timecode and timestamp
713 	 */
714 	peer = (struct peer *) rbufp->recv_srcclock ;
715 	pp = peer->procptr ;
716 	up = (struct jjyunit *) pp->unitptr ;
717 
718 	if ( up->linediscipline == LDISC_RAW ) {
719 		pBuf = up->rawbuf ;
720 		iLen = up->charcount ;
721 	} else {
722 	    pBuf = pp->a_lastcode ;
723 	    iLen = pp->lencode ;
724 	}
725 
726 	switch ( up->linecount ) {
727 
728 	case 1 : /* JYYMMDD HHMMSSS */
729 
730 		if ( iLen != 15 ) {
731 #ifdef DEBUG
732 	        if ( debug >= 2 ) {
733 		        printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", __func__, iLen ) ;
734 	        }
735 #endif
736 			up->lineerror = 1 ;
737 			break ;
738 		}
739 		rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
740 		              &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
741 		if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
742 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
743 #ifdef DEBUG
744 	        if ( debug >= 2 ) {
745 		        printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", __func__,
746 						 rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ;
747 	        }
748 #endif
749 			up->lineerror = 1 ;
750 			break ;
751 		}
752 		up->year    += 2000 ;
753 		up->msecond *= 100 ;
754 		break ;
755 
756 	default : /*  Unexpected reply */
757 
758 		up->lineerror = 1 ;
759 		break ;
760 
761 	}
762 
763 	return 1 ;
764 
765 }
766 
767 /**************************************************************************************************/
768 
769 static int
770 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
771 {
772 
773 	struct jjyunit      *up ;
774 	struct refclockproc *pp ;
775 	struct peer         *peer;
776 
777 	char	*pBuf ;
778 	int 	iLen ;
779 	int 	rc ;
780     int     i, ibcc, ibcc1, ibcc2 ;
781 
782 	/*
783 	 * Initialize pointers and read the timecode and timestamp
784 	 */
785 	peer = (struct peer *) rbufp->recv_srcclock ;
786 	pp = peer->procptr ;
787 	up = (struct jjyunit *) pp->unitptr ;
788 
789 	if ( up->linediscipline == LDISC_RAW ) {
790 		pBuf = up->rawbuf ;
791 		iLen = up->charcount ;
792 	} else {
793 	    pBuf = pp->a_lastcode ;
794 	    iLen = pp->lencode ;
795 	}
796 
797 	switch ( up->linecount ) {
798 
799 	case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
800 
801 		if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) {
802 #ifdef DEBUG
803 	        if ( debug >= 2 ) {
804 		        printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", __func__, iLen ) ;
805 	        }
806 #endif
807 			if ( up->operationmode == 1 ) {
808 #ifdef DEBUG
809 				if ( debug ) {
810 					printf ( "%s (refclock_jjy.c) : send '#'\n", __func__ ) ;
811 				}
812 #endif
813 				if ( write ( pp->io.fd, "#",1 ) != 1  ) {
814 					refclock_report ( peer, CEVNT_FAULT ) ;
815 				}
816 			}
817 			up->lineerror = 1 ;
818 			break ;
819 		}
820 
821 		if ( up->operationmode == 1 ) {
822 
823         	for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ;
824         	ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
825         	ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
826         	if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
827 #ifdef DEBUG
828 	        	if ( debug >= 2 ) {
829 		        	printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", __func__, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ;
830 	        	}
831 #endif
832 				up->lineerror = 1 ;
833 				break ;
834 			}
835 
836         }
837 
838 		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
839                       &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ;
840 		if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
841 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
842 #ifdef DEBUG
843 	        if ( debug >= 2 ) {
844 		        printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", __func__,
845 						 rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
846 	        }
847 #endif
848 			up->lineerror = 1 ;
849 			break ;
850 		}
851 
852 		up->year += 2000 ;
853 
854 		if ( up->operationmode == 2 ) {
855 
856 			/* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
857 			up->msecond = 500 ;
858 			pp->second -- ;
859 			if ( pp->second < 0 ) {
860 				pp->second = 59 ;
861 				pp->minute -- ;
862 				if ( pp->minute < 0 ) {
863 					pp->minute = 59 ;
864 					pp->hour -- ;
865 					if ( pp->hour < 0 ) {
866 						pp->hour = 23 ;
867 						pp->day -- ;
868 						if ( pp->day < 1 ) {
869 							pp->year -- ;
870 							pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
871 						}
872 					}
873 				}
874 			}
875 
876 			/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
877 #ifdef DEBUG
878 			if ( debug ) {
879 				printf ( "%s (refclock_jjy.c) : send '#'\n", __func__ ) ;
880 			}
881 #endif
882 			if ( write ( pp->io.fd, "#",1 ) != 1  ) {
883 				refclock_report ( peer, CEVNT_FAULT ) ;
884 			}
885 
886 		}
887 
888 		break ;
889 
890 	default : /*  Unexpected reply */
891 
892 #ifdef DEBUG
893 		if ( debug ) {
894 			printf ( "%s (refclock_jjy.c) : send '#'\n", __func__ ) ;
895 		}
896 #endif
897 		if ( write ( pp->io.fd, "#",1 ) != 1  ) {
898 			refclock_report ( peer, CEVNT_FAULT ) ;
899 		}
900 
901 		up->lineerror = 1 ;
902 		break ;
903 
904 	}
905 
906 	return 1 ;
907 
908 }
909 
910 /**************************************************************************************************/
911 
912 static int
913 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
914 {
915 
916     struct jjyunit      *up ;
917     struct refclockproc *pp ;
918     struct peer         *peer;
919 
920     char    *pBuf ;
921     int     iLen ;
922     int     rc ;
923     char    cApostrophe, sStatus[3] ;
924     int     iWeekday ;
925 
926     /*
927      * Initialize pointers and read the timecode and timestamp
928      */
929     peer = (struct peer *) rbufp->recv_srcclock ;
930     pp = peer->procptr ;
931     up = (struct jjyunit *) pp->unitptr ;
932 
933     if ( up->linediscipline == LDISC_RAW ) {
934         pBuf = up->rawbuf ;
935         iLen = up->charcount ;
936     } else {
937         pBuf = pp->a_lastcode ;
938         iLen = pp->lencode ;
939     }
940 
941     /*
942      * JJY-200 sends a timestamp every second.
943      * So, a timestamp is ignored unless it is right after polled.
944      */
945     if ( ! up->bPollFlag ) return 0 ;
946 
947     switch ( up->linecount ) {
948 
949     case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
950 
951         if ( iLen != 23 ) {
952 #ifdef DEBUG
953             if ( debug >= 2 ) {
954                 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", __func__, iLen ) ;
955             }
956 #endif
957             up->lineerror = 1 ;
958             break ;
959         }
960 
961         rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
962                       &cApostrophe, sStatus,
963                       &up->year, &up->month, &up->day, &iWeekday, &up->hour, &up->minute, &up->second ) ;
964         sStatus[2] = 0 ;
965         if ( rc != 9 || cApostrophe != '\'' || strcmp( sStatus, "OK" ) != 0
966           || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
967           || iWeekday > 6
968           || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
969 #ifdef DEBUG
970             if ( debug >= 2 ) {
971                 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", __func__,
972                          rc, cApostrophe, sStatus, up->year, up->month, up->day, iWeekday, up->hour, up->minute, up->second ) ;
973             }
974 #endif
975             up->lineerror = 1 ;
976             break ;
977         }
978 
979         up->year += 2000 ;
980         up->msecond = 0 ;
981 
982         break ;
983 
984     default : /* Unexpected reply */
985 
986         up->lineerror = 1 ;
987         break ;
988 
989     }
990 
991     return 1 ;
992 
993 }
994 
995 /**************************************************************************************************/
996 /*  jjy_poll - called by the transmit procedure                                                   */
997 /**************************************************************************************************/
998 static void
999 jjy_poll ( int unit, struct peer *peer )
1000 {
1001 
1002 	struct jjyunit      *up;
1003 	struct refclockproc *pp;
1004 
1005 	pp = peer->procptr;
1006 	up = (struct jjyunit *) pp->unitptr ;
1007 
1008 	if ( pp->polls > 0  &&  up->linecount == 0 ) {
1009 		/*
1010 		 * No reply for last command
1011 		 */
1012 		refclock_report ( peer, CEVNT_TIMEOUT ) ;
1013 	}
1014 
1015 #ifdef DEBUG
1016 	if ( debug ) {
1017 		printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1018 	}
1019 #endif
1020 
1021 	pp->polls ++ ;
1022 
1023     up->bPollFlag = 1 ;
1024 	up->linecount = 0 ;
1025 	up->lineerror = 0 ;
1026 	up->charcount = 0 ;
1027 
1028 	switch ( up->unittype ) {
1029 
1030 	case UNITTYPE_TRISTATE_JJY01 :
1031 		jjy_poll_tristate_jjy01  ( unit, peer ) ;
1032 		break ;
1033 
1034 	case UNITTYPE_CDEX_JST2000 :
1035 		jjy_poll_cdex_jst2000 ( unit, peer ) ;
1036 		break ;
1037 
1038 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1039 		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1040 		break ;
1041 
1042     case UNITTYPE_CITIZENTIC_JJY200 :
1043         jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1044         break ;
1045 
1046 	default :
1047 		break ;
1048 
1049 	}
1050 
1051 }
1052 
1053 /**************************************************************************************************/
1054 
1055 static void
1056 jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1057 {
1058 
1059 	struct refclockproc *pp;
1060 
1061 	pp = peer->procptr;
1062 
1063 	/*
1064 	 * Send "date<CR><LF>" command
1065 	 */
1066 
1067 #ifdef DEBUG
1068 	if ( debug ) {
1069 		printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
1070 	}
1071 #endif
1072 
1073 	if ( write ( pp->io.fd, "date\r\n",6 ) != 6  ) {
1074 		refclock_report ( peer, CEVNT_FAULT ) ;
1075 	}
1076 
1077 }
1078 
1079 /**************************************************************************************************/
1080 
1081 static void
1082 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1083 {
1084 
1085 	struct refclockproc *pp;
1086 
1087 	pp = peer->procptr;
1088 
1089 	/*
1090 	 * Send "<ENQ>1J<ETX>" command
1091 	 */
1092 
1093 #ifdef DEBUG
1094 	if ( debug ) {
1095 		printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1096 	}
1097 #endif
1098 
1099 	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1100 		refclock_report ( peer, CEVNT_FAULT ) ;
1101 	}
1102 
1103 }
1104 
1105 /**************************************************************************************************/
1106 
1107 static void
1108 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1109 {
1110 
1111 	struct jjyunit      *up;
1112 	struct refclockproc *pp;
1113 
1114 	char	sCmd[2] ;
1115 
1116 	pp = peer->procptr;
1117 	up = (struct jjyunit *) pp->unitptr ;
1118 
1119 	/*
1120 	 * Send "T" or "C" command
1121 	 */
1122 
1123 	switch ( up->operationmode ) {
1124 	case 1 : sCmd[0] = 'T' ; break ;
1125 	case 2 : sCmd[0] = 'C' ; break ;
1126 	}
1127 	sCmd[1] = 0 ;
1128 
1129 #ifdef DEBUG
1130 	if ( debug ) {
1131 		printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1132 	}
1133 #endif
1134 
1135 	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1136 		refclock_report ( peer, CEVNT_FAULT ) ;
1137 	}
1138 
1139 }
1140 
1141 /**************************************************************************************************/
1142 
1143 static void
1144 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1145 {
1146 
1147     /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1148 
1149 }
1150 
1151 #else
1152 int refclock_jjy_bs ;
1153 #endif /* REFCLOCK */
1154