xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_jjy.c (revision bbde328be4e75ea9ad02e9715ea13ca54b797ada)
1 /*	$NetBSD: refclock_jjy.c,v 1.1.1.1 2009/12/13 16:55:50 kardel 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 	static	char	*sFunctionName = "jjy_receive_tristate_jjy01" ;
572 
573 	struct jjyunit      *up ;
574 	struct refclockproc *pp ;
575 	struct peer         *peer;
576 
577 	char	*pBuf ;
578 	int 	iLen ;
579 	int 	rc ;
580 
581 	/*
582 	 * Initialize pointers and read the timecode and timestamp
583 	 */
584 	peer = (struct peer *) rbufp->recv_srcclock ;
585 	pp = peer->procptr ;
586 	up = (struct jjyunit *) pp->unitptr ;
587 
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 ;
594 	}
595 
596 	switch ( up->linecount ) {
597 
598 	case 1 : /* YYYY/MM/DD WWW */
599 
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 ) ;
604 	        }
605 #endif
606 			up->lineerror = 1 ;
607 			break ;
608 		}
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 ) ;
614 	        }
615 #endif
616 			up->lineerror = 1 ;
617 			break ;
618 		}
619 
620 		/*** Start of modification on 2004/10/31 */
621 		/*
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".
626 		 */
627 
628 		/*
629 		 * Send "stim<CR><LF>" or "time<CR><LF>" command
630 		 */
631 
632 
633 		if ( up->version >= 100 ) {
634 #ifdef DEBUG
635 			if ( debug ) {
636 				printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName ) ;
637 			}
638 #endif
639 			if ( write ( pp->io.fd, "stim\r\n",6 ) != 6  ) {
640 				refclock_report ( peer, CEVNT_FAULT ) ;
641 			}
642 		} else {
643 #ifdef DEBUG
644 			if ( debug ) {
645 				printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName ) ;
646 			}
647 #endif
648 			if ( write ( pp->io.fd, "time\r\n",6 ) != 6  ) {
649 				refclock_report ( peer, CEVNT_FAULT ) ;
650 			}
651 		}
652 		/*** End of modification ***/
653 
654 		return 0 ;
655 
656 	case 2 : /* HH:MM:SS */
657 
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 ) ;
662 	        }
663 #endif
664 			up->lineerror = 1 ;
665 			break ;
666 		}
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 ) ;
672 	        }
673 #endif
674 			up->lineerror = 1 ;
675 			break ;
676 		}
677 		up->msecond = 0 ;
678 		if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
679 			/*
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.
683 			 */
684 			return 0 ;
685 		}
686 		break ;
687 
688 	default : /*  Unexpected reply */
689 
690 		up->lineerror = 1 ;
691 		break ;
692 
693 	}
694 
695 	return 1 ;
696 
697 }
698 
699 /**************************************************************************************************/
700 
701 static int
702 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
703 {
704 
705 	static	char	*sFunctionName = "jjy_receive_cdex_jst2000" ;
706 
707 	struct jjyunit      *up ;
708 	struct refclockproc *pp ;
709 	struct peer         *peer;
710 
711 	char	*pBuf ;
712 	int 	iLen ;
713 	int 	rc ;
714 
715 	/*
716 	 * Initialize pointers and read the timecode and timestamp
717 	 */
718 	peer = (struct peer *) rbufp->recv_srcclock ;
719 	pp = peer->procptr ;
720 	up = (struct jjyunit *) pp->unitptr ;
721 
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 ;
728 	}
729 
730 	switch ( up->linecount ) {
731 
732 	case 1 : /* JYYMMDD HHMMSSS */
733 
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 ) ;
738 	        }
739 #endif
740 			up->lineerror = 1 ;
741 			break ;
742 		}
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 ) ;
751 	        }
752 #endif
753 			up->lineerror = 1 ;
754 			break ;
755 		}
756 		up->year    += 2000 ;
757 		up->msecond *= 100 ;
758 		break ;
759 
760 	default : /*  Unexpected reply */
761 
762 		up->lineerror = 1 ;
763 		break ;
764 
765 	}
766 
767 	return 1 ;
768 
769 }
770 
771 /**************************************************************************************************/
772 
773 static int
774 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
775 {
776 
777 	static	char	*sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
778 
779 	struct jjyunit      *up ;
780 	struct refclockproc *pp ;
781 	struct peer         *peer;
782 
783 	char	*pBuf ;
784 	int 	iLen ;
785 	int 	rc ;
786     int     i, ibcc, ibcc1, ibcc2 ;
787 
788 	/*
789 	 * Initialize pointers and read the timecode and timestamp
790 	 */
791 	peer = (struct peer *) rbufp->recv_srcclock ;
792 	pp = peer->procptr ;
793 	up = (struct jjyunit *) pp->unitptr ;
794 
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 ;
801 	}
802 
803 	switch ( up->linecount ) {
804 
805 	case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
806 
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 ) ;
811 	        }
812 #endif
813 			if ( up->operationmode == 1 ) {
814 #ifdef DEBUG
815 				if ( debug ) {
816 					printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
817 				}
818 #endif
819 				if ( write ( pp->io.fd, "#",1 ) != 1  ) {
820 					refclock_report ( peer, CEVNT_FAULT ) ;
821 				}
822 			}
823 			up->lineerror = 1 ;
824 			break ;
825 		}
826 
827 		if ( up->operationmode == 1 ) {
828 
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 ) ;
836 	        	}
837 #endif
838 				up->lineerror = 1 ;
839 				break ;
840 			}
841 
842         }
843 
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 ) ;
852 	        }
853 #endif
854 			up->lineerror = 1 ;
855 			break ;
856 		}
857 
858 		up->year += 2000 ;
859 
860 		if ( up->operationmode == 2 ) {
861 
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 ) ;
877 						}
878 					}
879 				}
880 			}
881 
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 ) ;
886 			}
887 #endif
888 			if ( write ( pp->io.fd, "#",1 ) != 1  ) {
889 				refclock_report ( peer, CEVNT_FAULT ) ;
890 			}
891 
892 		}
893 
894 		break ;
895 
896 	default : /*  Unexpected reply */
897 
898 #ifdef DEBUG
899 		if ( debug ) {
900 			printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
901 		}
902 #endif
903 		if ( write ( pp->io.fd, "#",1 ) != 1  ) {
904 			refclock_report ( peer, CEVNT_FAULT ) ;
905 		}
906 
907 		up->lineerror = 1 ;
908 		break ;
909 
910 	}
911 
912 	return 1 ;
913 
914 }
915 
916 /**************************************************************************************************/
917 
918 static int
919 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
920 {
921 
922     static  char    *sFunctionName = "jjy_receive_citizentic_jjy200" ;
923 
924     struct jjyunit      *up ;
925     struct refclockproc *pp ;
926     struct peer         *peer;
927 
928     char    *pBuf ;
929     int     iLen ;
930     int     rc ;
931     char    cApostrophe, sStatus[3] ;
932     int     iWeekday ;
933 
934     /*
935      * Initialize pointers and read the timecode and timestamp
936      */
937     peer = (struct peer *) rbufp->recv_srcclock ;
938     pp = peer->procptr ;
939     up = (struct jjyunit *) pp->unitptr ;
940 
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 ;
947     }
948 
949     /*
950      * JJY-200 sends a timestamp every second.
951      * So, a timestamp is ignored unless it is right after polled.
952      */
953     if ( ! up->bPollFlag ) return 0 ;
954 
955     switch ( up->linecount ) {
956 
957     case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
958 
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 ) ;
963             }
964 #endif
965             up->lineerror = 1 ;
966             break ;
967         }
968 
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 ) ;
981             }
982 #endif
983             up->lineerror = 1 ;
984             break ;
985         }
986 
987         up->year += 2000 ;
988         up->msecond = 0 ;
989 
990         break ;
991 
992     default : /* Unexpected reply */
993 
994         up->lineerror = 1 ;
995         break ;
996 
997     }
998 
999     return 1 ;
1000 
1001 }
1002 
1003 /**************************************************************************************************/
1004 /*  jjy_poll - called by the transmit procedure                                                   */
1005 /**************************************************************************************************/
1006 static void
1007 jjy_poll ( int unit, struct peer *peer )
1008 {
1009 
1010 	struct jjyunit      *up;
1011 	struct refclockproc *pp;
1012 
1013 	pp = peer->procptr;
1014 	up = (struct jjyunit *) pp->unitptr ;
1015 
1016 	if ( pp->polls > 0  &&  up->linecount == 0 ) {
1017 		/*
1018 		 * No reply for last command
1019 		 */
1020 		refclock_report ( peer, CEVNT_TIMEOUT ) ;
1021 	}
1022 
1023 #ifdef DEBUG
1024 	if ( debug ) {
1025 		printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1026 	}
1027 #endif
1028 
1029 	pp->polls ++ ;
1030 
1031     up->bPollFlag = 1 ;
1032 	up->linecount = 0 ;
1033 	up->lineerror = 0 ;
1034 	up->charcount = 0 ;
1035 
1036 	switch ( up->unittype ) {
1037 
1038 	case UNITTYPE_TRISTATE_JJY01 :
1039 		jjy_poll_tristate_jjy01  ( unit, peer ) ;
1040 		break ;
1041 
1042 	case UNITTYPE_CDEX_JST2000 :
1043 		jjy_poll_cdex_jst2000 ( unit, peer ) ;
1044 		break ;
1045 
1046 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1047 		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1048 		break ;
1049 
1050     case UNITTYPE_CITIZENTIC_JJY200 :
1051         jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1052         break ;
1053 
1054 	default :
1055 		break ;
1056 
1057 	}
1058 
1059 }
1060 
1061 /**************************************************************************************************/
1062 
1063 static void
1064 jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1065 {
1066 
1067 	struct refclockproc *pp;
1068 
1069 	pp = peer->procptr;
1070 
1071 	/*
1072 	 * Send "date<CR><LF>" command
1073 	 */
1074 
1075 #ifdef DEBUG
1076 	if ( debug ) {
1077 		printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
1078 	}
1079 #endif
1080 
1081 	if ( write ( pp->io.fd, "date\r\n",6 ) != 6  ) {
1082 		refclock_report ( peer, CEVNT_FAULT ) ;
1083 	}
1084 
1085 }
1086 
1087 /**************************************************************************************************/
1088 
1089 static void
1090 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1091 {
1092 
1093 	struct refclockproc *pp;
1094 
1095 	pp = peer->procptr;
1096 
1097 	/*
1098 	 * Send "<ENQ>1J<ETX>" command
1099 	 */
1100 
1101 #ifdef DEBUG
1102 	if ( debug ) {
1103 		printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1104 	}
1105 #endif
1106 
1107 	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1108 		refclock_report ( peer, CEVNT_FAULT ) ;
1109 	}
1110 
1111 }
1112 
1113 /**************************************************************************************************/
1114 
1115 static void
1116 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1117 {
1118 
1119 	struct jjyunit      *up;
1120 	struct refclockproc *pp;
1121 
1122 	char	sCmd[2] ;
1123 
1124 	pp = peer->procptr;
1125 	up = (struct jjyunit *) pp->unitptr ;
1126 
1127 	/*
1128 	 * Send "T" or "C" command
1129 	 */
1130 
1131 	switch ( up->operationmode ) {
1132 	case 1 : sCmd[0] = 'T' ; break ;
1133 	case 2 : sCmd[0] = 'C' ; break ;
1134 	}
1135 	sCmd[1] = 0 ;
1136 
1137 #ifdef DEBUG
1138 	if ( debug ) {
1139 		printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1140 	}
1141 #endif
1142 
1143 	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1144 		refclock_report ( peer, CEVNT_FAULT ) ;
1145 	}
1146 
1147 }
1148 
1149 /**************************************************************************************************/
1150 
1151 static void
1152 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1153 {
1154 
1155     /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1156 
1157 }
1158 
1159 #else
1160 int refclock_jjy_bs ;
1161 #endif /* REFCLOCK */
1162