xref: /freebsd/contrib/ntp/ntpd/refclock_jjy.c (revision 3157ba21)
1 /*
2  * refclock_jjy - clock driver for JJY receivers
3  */
4 
5 /**********************************************************************/
6 /*                                                                    */
7 /*  Copyright (C) 2001-2004, Takao Abe.  All rights reserved.         */
8 /*                                                                    */
9 /*  Permission to use, copy, modify, and distribute this software     */
10 /*  and its documentation for any purpose is hereby granted           */
11 /*  without fee, provided that the following conditions are met:      */
12 /*                                                                    */
13 /*  One retains the entire copyright notice properly, and both the    */
14 /*  copyright notice and this license. in the documentation and/or    */
15 /*  other materials provided with the distribution.                   */
16 /*                                                                    */
17 /*  This software and the name of the author must not be used to      */
18 /*  endorse or promote products derived from this software without    */
19 /*  prior written permission.                                         */
20 /*                                                                    */
21 /*  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED    */
22 /*  WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE        */
23 /*  IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A          */
24 /*  PARTICULAR PURPOSE.                                               */
25 /*  IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT,  */
26 /*  INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   */
27 /*  ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE        */
28 /*  GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS      */
29 /*  INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,     */
30 /*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING        */
31 /*  NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF    */
32 /*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
33 /*                                                                    */
34 /*  This driver is developed in my private time, and is opened as     */
35 /*  voluntary contributions for the NTP.                              */
36 /*  The manufacturer of the JJY receiver has not participated in      */
37 /*  a development of this driver.                                     */
38 /*  The manufacturer does not warrant anything about this driver,     */
39 /*  and is not liable for anything about this driver.                 */
40 /*                                                                    */
41 /**********************************************************************/
42 /*                                                                    */
43 /*  Author     Takao Abe                                              */
44 /*  Email      abetakao@bea.hi-ho.ne.jp                               */
45 /*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/                   */
46 /*                                                                    */
47 /**********************************************************************/
48 /*                                                                    */
49 /*  History                                                           */
50 /*                                                                    */
51 /*  2001/07/15                                                        */
52 /*    [New]    Support the Tristate Ltd. JJY receiver                 */
53 /*                                                                    */
54 /*  2001/08/04                                                        */
55 /*    [Change] Log to clockstats even if bad reply                    */
56 /*    [Fix]    PRECISION = (-3) (about 100 ms)                        */
57 /*    [Add]    Support the C-DEX Co.Ltd. JJY receiver                 */
58 /*                                                                    */
59 /*  2001/12/04                                                        */
60 /*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
61 /*                                                                    */
62 /*  2002/07/12                                                        */
63 /*    [Fix]    Portability for FreeBSD ( patched by the user )        */
64 /*                                                                    */
65 /*  2004/10/31                                                        */
66 /*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
67 /*             JJY-01 ( Firmware version 2.01 )                       */
68 /*             Thanks to Andy Taki for testing under FreeBSD          */
69 /*                                                                    */
70 /*  2004/11/28                                                        */
71 /*    [Add]    Support the Echo Keisokuki LT-2000 receiver            */
72 /*                                                                    */
73 /*  2006/11/04                                                        */
74 /*    [Fix]    C-DEX JST2000                                          */
75 /*             Thanks to Hideo Kuramatsu for the patch                */
76 /*                                                                    */
77 /*  2009/04/05                                                        */
78 /*    [Add]    Support the CITIZEN T.I.C JJY-200 receiver             */
79 /*                                                                    */
80 /**********************************************************************/
81 
82 #ifdef HAVE_CONFIG_H
83 #include <config.h>
84 #endif
85 
86 #if defined(REFCLOCK) && defined(CLOCK_JJY)
87 
88 #include <stdio.h>
89 #include <ctype.h>
90 #include <string.h>
91 #include <sys/time.h>
92 #include <time.h>
93 
94 #include "ntpd.h"
95 #include "ntp_io.h"
96 #include "ntp_tty.h"
97 #include "ntp_refclock.h"
98 #include "ntp_calendar.h"
99 #include "ntp_stdlib.h"
100 
101 /**********************************************************************/
102 /*                                                                    */
103 /*  The Tristate Ltd. JJY receiver JJY01                              */
104 /*                                                                    */
105 /*  Command        Response                 Remarks                   */
106 /*  ------------   ----------------------   ---------------------     */
107 /*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>                             */
108 /*  time<CR><LF>   HH:MM:SS<CR><LF>                                   */
109 /*  stim<CR><LF>   HH:MM:SS<CR><LF>         Reply at just second      */
110 /*                                                                    */
111 /*  During synchronization after a receiver is turned on,             */
112 /*  It replies the past time from 2000/01/01 00:00:00.                */
113 /*  The function "refclock_process" checks the time and tells         */
114 /*  as an insanity time.                                              */
115 /*                                                                    */
116 /**********************************************************************/
117 /*                                                                    */
118 /*  The C-DEX Co. Ltd. JJY receiver JST2000                           */
119 /*                                                                    */
120 /*  Command        Response                 Remarks                   */
121 /*  ------------   ----------------------   ---------------------     */
122 /*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>                          */
123 /*                                                                    */
124 /**********************************************************************/
125 /*                                                                    */
126 /*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000                   */
127 /*                                                                    */
128 /*  Command        Response                 Remarks                   */
129 /*  ------------   ----------------------   ---------------------     */
130 /*  #                                       Mode 1 (Request&Send)     */
131 /*  T              YYMMDDWHHMMSS<BCC1><BCC2><CR>                      */
132 /*  C                                       Mode 2 (Continuous)       */
133 /*                 YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>              */
134 /*                 <SUB>                    Second signal             */
135 /*                                                                    */
136 /**********************************************************************/
137 /*                                                                    */
138 /*  The CITIZEN T.I.C CO., LTD. JJY receiver JJY200                   */
139 /*                                                                    */
140 /*  Command        Response                 Remarks                   */
141 /*  ------------   ----------------------   ---------------------     */
142 /*                 'XX YY/MM/DD W HH:MM:SS<CR>                        */
143 /*                                          XX: OK|NG|ER              */
144 /*                                          W:  0(Monday)-6(Sunday)   */
145 /*                                                                    */
146 /**********************************************************************/
147 
148 /*
149  * Interface definitions
150  */
151 #define	DEVICE  	"/dev/jjy%d"    /* device name and unit */
152 #define	SPEED232	B9600           /* uart speed (9600 baud) */
153 #define	SPEED232_TRISTATE_JJY01         B9600   /* UART speed (9600 baud) */
154 #define	SPEED232_CDEX_JST2000           B9600   /* UART speed (9600 baud) */
155 #define	SPEED232_ECHOKEISOKUKI_LT2000   B9600   /* UART speed (9600 baud) */
156 #define	SPEED232_CITIZENTIC_JJY200      B4800   /* UART speed (4800 baud) */
157 #define	REFID   	"JJY"           /* reference ID */
158 #define	DESCRIPTION	"JJY Receiver"
159 #define	PRECISION	(-3)           /* precision assumed (about 100 ms) */
160 
161 /*
162  * JJY unit control structure
163  */
164 struct jjyunit {
165 	char	unittype ;          /* UNITTYPE_XXXXXXXXXX */
166     short   operationmode ;     /* Echo Keisokuki LT-2000 : 1 or 2 */
167 	short	version ;
168 	short	linediscipline ;	/* LDISC_CLK or LDISC_RAW */
169     char    bPollFlag ;         /* Set by jjy_pool and Reset by jjy_receive */
170 	int 	linecount ;
171 	int 	lineerror ;
172 	int 	year, month, day, hour, minute, second, msecond ;
173 /* LDISC_RAW only */
174 #define	MAX_LINECOUNT	8
175 #define	MAX_RAWBUF   	64
176 	int 	lineexpect ;
177 	int 	charexpect [ MAX_LINECOUNT ] ;
178 	int 	charcount ;
179 	char	rawbuf [ MAX_RAWBUF ] ;
180 };
181 
182 #define	UNITTYPE_TRISTATE_JJY01	1
183 #define	UNITTYPE_CDEX_JST2000  	2
184 #define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
185 #define	UNITTYPE_CITIZENTIC_JJY200  	4
186 
187 /*
188  * Function prototypes
189  */
190 static	int 	jjy_start                   P((int, struct peer *));
191 static	void	jjy_shutdown                P((int, struct peer *));
192 static	void	jjy_poll                    P((int, struct peer *));
193 static	void	jjy_poll_tristate_jjy01     P((int, struct peer *));
194 static	void	jjy_poll_cdex_jst2000       P((int, struct peer *));
195 static	void	jjy_poll_echokeisokuki_lt2000    P((int, struct peer *));
196 static  void    jjy_poll_citizentic_jjy200          P((int, struct peer *));
197 static	void	jjy_receive                 P((struct recvbuf *));
198 static	int 	jjy_receive_tristate_jjy01  P((struct recvbuf *));
199 static	int 	jjy_receive_cdex_jst2000    P((struct recvbuf *));
200 static	int 	jjy_receive_echokeisokuki_lt2000 P((struct recvbuf *));
201 static  int     jjy_receive_citizentic_jjy200       P((struct recvbuf *));
202 
203 /*
204  * Transfer vector
205  */
206 struct	refclock refclock_jjy = {
207 	jjy_start,      /* start up driver */
208 	jjy_shutdown,   /* shutdown driver */
209 	jjy_poll,       /* transmit poll message */
210 	noentry,        /* not used */
211 	noentry,        /* not used */
212 	noentry,        /* not used */
213 	NOFLAGS         /* not used */
214 };
215 
216 /*
217  * Start up driver return code
218  */
219 #define	RC_START_SUCCESS	1
220 #define	RC_START_ERROR  	0
221 
222 /*
223  * Local constants definition
224  */
225 
226 #define	MAX_LOGTEXT	64
227 
228 
229 /**************************************************************************************************/
230 /*  jjy_start - open the devices and initialize data for processing                               */
231 /**************************************************************************************************/
232 static int
233 jjy_start ( int unit, struct peer *peer )
234 {
235 
236 	struct jjyunit      *up ;
237 	struct refclockproc *pp ;
238 	int 	fd ;
239 	char	*pDeviceName ;
240 	short	iDiscipline ;
241 	int 	iSpeed232 ;
242 
243 #ifdef DEBUG
244 	if ( debug ) {
245 		printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttl ) ;
246 		printf ( DEVICE, unit ) ;
247 		printf ( "\n" ) ;
248 	}
249 #endif
250 	/*
251 	 * Open serial port
252 	 */
253 	if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
254 		return RC_START_ERROR ;
255 	}
256 	sprintf ( pDeviceName, DEVICE, unit ) ;
257 
258 	/*
259 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
260 	 */
261 	switch ( peer->ttl ) {
262 	case 0 :
263     case 1 :
264         iDiscipline = LDISC_CLK ;
265         iSpeed232   = SPEED232_TRISTATE_JJY01 ;
266         break ;
267     case 2 :
268         iDiscipline = LDISC_RAW ;
269         iSpeed232   = SPEED232_CDEX_JST2000   ;
270         break ;
271     case 3 :
272         iDiscipline = LDISC_CLK ;
273         iSpeed232   = SPEED232_ECHOKEISOKUKI_LT2000 ;
274         break ;
275     case 4 :
276         iDiscipline = LDISC_CLK ;
277         iSpeed232   = SPEED232_CITIZENTIC_JJY200 ;
278         break ;
279 	default :
280 		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
281 		          ntoa(&peer->srcadr), peer->ttl ) ;
282 		free ( (void*) pDeviceName ) ;
283 		return RC_START_ERROR ;
284 	}
285 
286 	if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) {
287 		free ( (void*) pDeviceName ) ;
288 		return RC_START_ERROR ;
289 	}
290 	free ( (void*) pDeviceName ) ;
291 
292 	/*
293 	 * Allocate and initialize unit structure
294 	 */
295 	if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
296 		close ( fd ) ;
297 		return RC_START_ERROR ;
298 	}
299 
300 	memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
301 	up->linediscipline = iDiscipline ;
302 
303 	/*
304 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
305 	 */
306 	switch ( peer->ttl ) {
307 	case 0 :
308 		/*
309 		 * The mode 0 is a default clock type at this time.
310 		 * But this will be change to auto-detect mode in the future.
311 		 */
312 	case 1 :
313 		up->unittype = UNITTYPE_TRISTATE_JJY01 ;
314 		up->version  = 100 ;
315 		up->lineexpect = 2 ;
316 		up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
317 		up->charexpect[1] =  8 ; /* HH:MM:SS<CR><LF> */
318 		break ;
319 	case 2 :
320 		up->unittype = UNITTYPE_CDEX_JST2000 ;
321 		up->lineexpect = 1 ;
322 		up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
323 		break ;
324 	case 3 :
325 		up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
326 		up->operationmode = 2 ;  /* Mode 2 : Continuous mode */
327 		up->lineexpect = 1 ;
328         switch ( up->operationmode ) {
329         case 1 :
330 			up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
331 			break ;
332 		case 2 :
333 			up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
334 			break ;
335 		}
336 		break ;
337     case 4 :
338         up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
339         up->lineexpect = 1 ;
340         up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
341         break ;
342 	default :
343 		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
344 		          ntoa(&peer->srcadr), peer->ttl ) ;
345 		close ( fd ) ;
346 		free ( (void*) up ) ;
347 		return RC_START_ERROR ;
348 	}
349 
350 	pp = peer->procptr ;
351 	pp->unitptr       = (caddr_t) up ;
352 	pp->io.clock_recv = jjy_receive ;
353 	pp->io.srcclock   = (caddr_t) peer ;
354 	pp->io.datalen    = 0 ;
355 	pp->io.fd         = fd ;
356 	if ( ! io_addclock(&pp->io) ) {
357 		close ( fd ) ;
358 		free ( (void*) up ) ;
359 		return RC_START_ERROR ;
360 	}
361 
362 	/*
363 	 * Initialize miscellaneous variables
364 	 */
365 	peer->precision = PRECISION ;
366 	peer->burst     = 1 ;
367 	pp->clockdesc   = DESCRIPTION ;
368 	memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
369 
370 	return RC_START_SUCCESS ;
371 
372 }
373 
374 
375 /**************************************************************************************************/
376 /*  jjy_shutdown - shutdown the clock                                                             */
377 /**************************************************************************************************/
378 static void
379 jjy_shutdown ( int unit, struct peer *peer )
380 {
381 
382 	struct jjyunit      *up;
383 	struct refclockproc *pp;
384 
385 	pp = peer->procptr ;
386 	up = (struct jjyunit *) pp->unitptr ;
387 	io_closeclock ( &pp->io ) ;
388 	free ( (void*) up ) ;
389 
390 }
391 
392 
393 /**************************************************************************************************/
394 /*  jjy_receive - receive data from the serial interface                                          */
395 /**************************************************************************************************/
396 static void
397 jjy_receive ( struct recvbuf *rbufp )
398 {
399 
400 	struct jjyunit      *up ;
401 	struct refclockproc *pp ;
402 	struct peer         *peer;
403 
404 	l_fp	tRecvTimestamp;		/* arrival timestamp */
405 	int 	rc ;
406 	char	sLogText [ MAX_LOGTEXT ] ;
407 	int 	i, bCntrlChar ;
408 
409 	/*
410 	 * Initialize pointers and read the timecode and timestamp
411 	 */
412 	peer = (struct peer *) rbufp->recv_srcclock ;
413 	pp = peer->procptr ;
414 	up = (struct jjyunit *) pp->unitptr ;
415 
416 	/*
417 	 * Get next input line
418 	 */
419 	pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
420 
421 	if ( up->linediscipline == LDISC_RAW ) {
422 		/*
423 		 * The reply with <STX> and <ETX> may give a blank line
424 		 */
425 		if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
426 		/*
427 		 * Copy received charaters to temporary buffer
428 		 */
429 		for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
430 			up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
431 		}
432 		while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
433 			for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ;
434 			up->charcount -- ;
435 		}
436 		bCntrlChar = 0 ;
437 		for ( i = 0 ; i < up->charcount ; i ++ ) {
438 			if ( up->rawbuf[i] < ' ' ) {
439 				bCntrlChar = 1 ;
440 				break ;
441 			}
442 		}
443 		if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
444 			if ( bCntrlChar == 0  &&  up->charcount < up->charexpect[up->linecount] ) return ;
445 		}
446 		up->rawbuf[up->charcount] = 0 ;
447 	} else {
448 		/*
449 		 * The reply with <CR><LF> gives a blank line
450 		 */
451 		if ( pp->lencode == 0 ) return ;
452 	}
453 	/*
454 	 * We get down to business
455 	 */
456 
457 	pp->lastrec = tRecvTimestamp ;
458 
459 	up->linecount ++ ;
460 
461 	if ( up->lineerror != 0 ) return ;
462 
463 	switch ( up->unittype ) {
464 
465 	case UNITTYPE_TRISTATE_JJY01 :
466 		rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
467 		break ;
468 
469 	case UNITTYPE_CDEX_JST2000 :
470 		rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
471 		break ;
472 
473 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
474 		rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
475 		break ;
476 
477     case UNITTYPE_CITIZENTIC_JJY200 :
478         rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
479         break ;
480 
481 	default :
482 		rc = 0 ;
483 		break ;
484 
485 	}
486 
487 	if ( up->linediscipline == LDISC_RAW ) {
488 		if ( up->linecount <= up->lineexpect  &&  up->charcount > up->charexpect[up->linecount-1] ) {
489 			for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) {
490 				up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
491 			}
492 			up->charcount -= up->charexpect[up->linecount-1] ;
493 		} else {
494 			up->charcount = 0 ;
495 		}
496 	}
497 
498 	if ( rc == 0 ) return ;
499 
500     up->bPollFlag = 0 ;
501 
502 	if ( up->lineerror != 0 ) {
503 		refclock_report ( peer, CEVNT_BADREPLY ) ;
504 		strcpy  ( sLogText, "BAD REPLY [" ) ;
505 		if ( up->linediscipline == LDISC_RAW ) {
506 			strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
507 		} else {
508 			strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
509 		}
510 		sLogText[MAX_LOGTEXT-1] = 0 ;
511 		if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
512 		record_clock_stats ( &peer->srcadr, sLogText ) ;
513 		return ;
514 	}
515 
516 	pp->year   = up->year ;
517 	pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
518 	pp->hour   = up->hour ;
519 	pp->minute = up->minute ;
520 	pp->second = up->second ;
521 	pp->nsec   = up->msecond * 1000000;
522 
523 	/*
524 	 * JST to UTC
525 	 */
526 	pp->hour -= 9 ;
527 	if ( pp->hour < 0 ) {
528 		pp->hour += 24 ;
529 		pp->day -- ;
530 		if ( pp->day < 1 ) {
531 			pp->year -- ;
532 			pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
533 		}
534 	}
535 #ifdef DEBUG
536 	if ( debug ) {
537 		printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST   ",
538 		          up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
539 		printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
540 		          pp->year, pp->day, pp->hour, pp->minute, pp->second, (int)(pp->nsec/100000000) ) ;
541 	}
542 #endif
543 
544 	/*
545 	 * Process the new sample in the median filter and determine the
546 	 * timecode timestamp.
547 	 */
548 
549 	sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
550 	          up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
551 	record_clock_stats ( &peer->srcadr, sLogText ) ;
552 
553 	if ( ! refclock_process ( pp ) ) {
554 		refclock_report(peer, CEVNT_BADTIME);
555 		return ;
556 	}
557 
558 	pp->lastref = pp->lastrec;
559 	refclock_receive(peer);
560 
561 }
562 
563 /**************************************************************************************************/
564 
565 static int
566 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
567 {
568 
569 	static	char	*sFunctionName = "jjy_receive_tristate_jjy01" ;
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", sFunctionName, 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", sFunctionName, 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", sFunctionName ) ;
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", sFunctionName ) ;
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", sFunctionName, 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", sFunctionName, 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 	static	char	*sFunctionName = "jjy_receive_cdex_jst2000" ;
704 
705 	struct jjyunit      *up ;
706 	struct refclockproc *pp ;
707 	struct peer         *peer;
708 
709 	char	*pBuf ;
710 	int 	iLen ;
711 	int 	rc ;
712 
713 	/*
714 	 * Initialize pointers and read the timecode and timestamp
715 	 */
716 	peer = (struct peer *) rbufp->recv_srcclock ;
717 	pp = peer->procptr ;
718 	up = (struct jjyunit *) pp->unitptr ;
719 
720 	if ( up->linediscipline == LDISC_RAW ) {
721 		pBuf = up->rawbuf ;
722 		iLen = up->charcount ;
723 	} else {
724 	    pBuf = pp->a_lastcode ;
725 	    iLen = pp->lencode ;
726 	}
727 
728 	switch ( up->linecount ) {
729 
730 	case 1 : /* JYYMMDD HHMMSSS */
731 
732 		if ( iLen != 15 ) {
733 #ifdef DEBUG
734 	        if ( debug >= 2 ) {
735 		        printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
736 	        }
737 #endif
738 			up->lineerror = 1 ;
739 			break ;
740 		}
741 		rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
742 		              &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
743 		if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
744 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
745 #ifdef DEBUG
746 	        if ( debug >= 2 ) {
747 		        printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName,
748 						 rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ;
749 	        }
750 #endif
751 			up->lineerror = 1 ;
752 			break ;
753 		}
754 		up->year    += 2000 ;
755 		up->msecond *= 100 ;
756 		break ;
757 
758 	default : /*  Unexpected reply */
759 
760 		up->lineerror = 1 ;
761 		break ;
762 
763 	}
764 
765 	return 1 ;
766 
767 }
768 
769 /**************************************************************************************************/
770 
771 static int
772 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
773 {
774 
775 	static	char	*sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
776 
777 	struct jjyunit      *up ;
778 	struct refclockproc *pp ;
779 	struct peer         *peer;
780 
781 	char	*pBuf ;
782 	int 	iLen ;
783 	int 	rc ;
784     int     i, ibcc, ibcc1, ibcc2 ;
785 
786 	/*
787 	 * Initialize pointers and read the timecode and timestamp
788 	 */
789 	peer = (struct peer *) rbufp->recv_srcclock ;
790 	pp = peer->procptr ;
791 	up = (struct jjyunit *) pp->unitptr ;
792 
793 	if ( up->linediscipline == LDISC_RAW ) {
794 		pBuf = up->rawbuf ;
795 		iLen = up->charcount ;
796 	} else {
797 	    pBuf = pp->a_lastcode ;
798 	    iLen = pp->lencode ;
799 	}
800 
801 	switch ( up->linecount ) {
802 
803 	case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
804 
805 		if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) {
806 #ifdef DEBUG
807 	        if ( debug >= 2 ) {
808 		        printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
809 	        }
810 #endif
811 			if ( up->operationmode == 1 ) {
812 #ifdef DEBUG
813 				if ( debug ) {
814 					printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
815 				}
816 #endif
817 				if ( write ( pp->io.fd, "#",1 ) != 1  ) {
818 					refclock_report ( peer, CEVNT_FAULT ) ;
819 				}
820 			}
821 			up->lineerror = 1 ;
822 			break ;
823 		}
824 
825 		if ( up->operationmode == 1 ) {
826 
827         	for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ;
828         	ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
829         	ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
830         	if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
831 #ifdef DEBUG
832 	        	if ( debug >= 2 ) {
833 		        	printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ;
834 	        	}
835 #endif
836 				up->lineerror = 1 ;
837 				break ;
838 			}
839 
840         }
841 
842 		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
843                       &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ;
844 		if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
845 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
846 #ifdef DEBUG
847 	        if ( debug >= 2 ) {
848 		        printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName,
849 						 rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
850 	        }
851 #endif
852 			up->lineerror = 1 ;
853 			break ;
854 		}
855 
856 		up->year += 2000 ;
857 
858 		if ( up->operationmode == 2 ) {
859 
860 			/* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
861 			up->msecond = 500 ;
862 			pp->second -- ;
863 			if ( pp->second < 0 ) {
864 				pp->second = 59 ;
865 				pp->minute -- ;
866 				if ( pp->minute < 0 ) {
867 					pp->minute = 59 ;
868 					pp->hour -- ;
869 					if ( pp->hour < 0 ) {
870 						pp->hour = 23 ;
871 						pp->day -- ;
872 						if ( pp->day < 1 ) {
873 							pp->year -- ;
874 							pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
875 						}
876 					}
877 				}
878 			}
879 
880 			/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
881 #ifdef DEBUG
882 			if ( debug ) {
883 				printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
884 			}
885 #endif
886 			if ( write ( pp->io.fd, "#",1 ) != 1  ) {
887 				refclock_report ( peer, CEVNT_FAULT ) ;
888 			}
889 
890 		}
891 
892 		break ;
893 
894 	default : /*  Unexpected reply */
895 
896 #ifdef DEBUG
897 		if ( debug ) {
898 			printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
899 		}
900 #endif
901 		if ( write ( pp->io.fd, "#",1 ) != 1  ) {
902 			refclock_report ( peer, CEVNT_FAULT ) ;
903 		}
904 
905 		up->lineerror = 1 ;
906 		break ;
907 
908 	}
909 
910 	return 1 ;
911 
912 }
913 
914 /**************************************************************************************************/
915 
916 static int
917 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
918 {
919 
920     static  char    *sFunctionName = "jjy_receive_citizentic_jjy200" ;
921 
922     struct jjyunit      *up ;
923     struct refclockproc *pp ;
924     struct peer         *peer;
925 
926     char    *pBuf ;
927     int     iLen ;
928     int     rc ;
929     char    cApostrophe, sStatus[3] ;
930     int     iWeekday ;
931 
932     /*
933      * Initialize pointers and read the timecode and timestamp
934      */
935     peer = (struct peer *) rbufp->recv_srcclock ;
936     pp = peer->procptr ;
937     up = (struct jjyunit *) pp->unitptr ;
938 
939     if ( up->linediscipline == LDISC_RAW ) {
940         pBuf = up->rawbuf ;
941         iLen = up->charcount ;
942     } else {
943         pBuf = pp->a_lastcode ;
944         iLen = pp->lencode ;
945     }
946 
947     /*
948      * JJY-200 sends a timestamp every second.
949      * So, a timestamp is ignored unless it is right after polled.
950      */
951     if ( ! up->bPollFlag ) return 0 ;
952 
953     switch ( up->linecount ) {
954 
955     case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
956 
957         if ( iLen != 23 ) {
958 #ifdef DEBUG
959             if ( debug >= 2 ) {
960                 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
961             }
962 #endif
963             up->lineerror = 1 ;
964             break ;
965         }
966 
967         rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
968                       &cApostrophe, sStatus,
969                       &up->year, &up->month, &up->day, &iWeekday, &up->hour, &up->minute, &up->second ) ;
970         sStatus[2] = 0 ;
971         if ( rc != 9 || cApostrophe != '\'' || strcmp( sStatus, "OK" ) != 0
972           || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
973           || iWeekday > 6
974           || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
975 #ifdef DEBUG
976             if ( debug >= 2 ) {
977                 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", sFunctionName,
978                          rc, cApostrophe, sStatus, up->year, up->month, up->day, iWeekday, up->hour, up->minute, up->second ) ;
979             }
980 #endif
981             up->lineerror = 1 ;
982             break ;
983         }
984 
985         up->year += 2000 ;
986         up->msecond = 0 ;
987 
988         break ;
989 
990     default : /* Unexpected reply */
991 
992         up->lineerror = 1 ;
993         break ;
994 
995     }
996 
997     return 1 ;
998 
999 }
1000 
1001 /**************************************************************************************************/
1002 /*  jjy_poll - called by the transmit procedure                                                   */
1003 /**************************************************************************************************/
1004 static void
1005 jjy_poll ( int unit, struct peer *peer )
1006 {
1007 
1008 	struct jjyunit      *up;
1009 	struct refclockproc *pp;
1010 
1011 	pp = peer->procptr;
1012 	up = (struct jjyunit *) pp->unitptr ;
1013 
1014 	if ( pp->polls > 0  &&  up->linecount == 0 ) {
1015 		/*
1016 		 * No reply for last command
1017 		 */
1018 		refclock_report ( peer, CEVNT_TIMEOUT ) ;
1019 	}
1020 
1021 #ifdef DEBUG
1022 	if ( debug ) {
1023 		printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1024 	}
1025 #endif
1026 
1027 	pp->polls ++ ;
1028 
1029     up->bPollFlag = 1 ;
1030 	up->linecount = 0 ;
1031 	up->lineerror = 0 ;
1032 	up->charcount = 0 ;
1033 
1034 	switch ( up->unittype ) {
1035 
1036 	case UNITTYPE_TRISTATE_JJY01 :
1037 		jjy_poll_tristate_jjy01  ( unit, peer ) ;
1038 		break ;
1039 
1040 	case UNITTYPE_CDEX_JST2000 :
1041 		jjy_poll_cdex_jst2000 ( unit, peer ) ;
1042 		break ;
1043 
1044 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1045 		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1046 		break ;
1047 
1048     case UNITTYPE_CITIZENTIC_JJY200 :
1049         jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1050         break ;
1051 
1052 	default :
1053 		break ;
1054 
1055 	}
1056 
1057 }
1058 
1059 /**************************************************************************************************/
1060 
1061 static void
1062 jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1063 {
1064 
1065 	struct refclockproc *pp;
1066 
1067 	pp = peer->procptr;
1068 
1069 	/*
1070 	 * Send "date<CR><LF>" command
1071 	 */
1072 
1073 #ifdef DEBUG
1074 	if ( debug ) {
1075 		printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
1076 	}
1077 #endif
1078 
1079 	if ( write ( pp->io.fd, "date\r\n",6 ) != 6  ) {
1080 		refclock_report ( peer, CEVNT_FAULT ) ;
1081 	}
1082 
1083 }
1084 
1085 /**************************************************************************************************/
1086 
1087 static void
1088 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1089 {
1090 
1091 	struct refclockproc *pp;
1092 
1093 	pp = peer->procptr;
1094 
1095 	/*
1096 	 * Send "<ENQ>1J<ETX>" command
1097 	 */
1098 
1099 #ifdef DEBUG
1100 	if ( debug ) {
1101 		printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1102 	}
1103 #endif
1104 
1105 	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1106 		refclock_report ( peer, CEVNT_FAULT ) ;
1107 	}
1108 
1109 }
1110 
1111 /**************************************************************************************************/
1112 
1113 static void
1114 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1115 {
1116 
1117 	struct jjyunit      *up;
1118 	struct refclockproc *pp;
1119 
1120 	char	sCmd[2] ;
1121 
1122 	pp = peer->procptr;
1123 	up = (struct jjyunit *) pp->unitptr ;
1124 
1125 	/*
1126 	 * Send "T" or "C" command
1127 	 */
1128 
1129 	switch ( up->operationmode ) {
1130 	case 1 : sCmd[0] = 'T' ; break ;
1131 	case 2 : sCmd[0] = 'C' ; break ;
1132 	}
1133 	sCmd[1] = 0 ;
1134 
1135 #ifdef DEBUG
1136 	if ( debug ) {
1137 		printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1138 	}
1139 #endif
1140 
1141 	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1142 		refclock_report ( peer, CEVNT_FAULT ) ;
1143 	}
1144 
1145 }
1146 
1147 /**************************************************************************************************/
1148 
1149 static void
1150 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1151 {
1152 
1153     /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1154 
1155 }
1156 
1157 #else
1158 int refclock_jjy_bs ;
1159 #endif /* REFCLOCK */
1160