xref: /freebsd/contrib/ntp/ntpd/refclock_jjy.c (revision 566a751354a439384a12dd3f4b43ff3b55ddf9a8)
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 /**********************************************************************/
78 
79 #ifdef HAVE_CONFIG_H
80 #include <config.h>
81 #endif
82 
83 #if defined(REFCLOCK) && defined(CLOCK_JJY)
84 
85 #include <stdio.h>
86 #include <ctype.h>
87 #include <string.h>
88 #include <sys/time.h>
89 #include <time.h>
90 
91 #include "ntpd.h"
92 #include "ntp_io.h"
93 #include "ntp_tty.h"
94 #include "ntp_refclock.h"
95 #include "ntp_calendar.h"
96 #include "ntp_stdlib.h"
97 
98 /**********************************************************************/
99 /*                                                                    */
100 /*  The Tristate Ltd. JJY receiver JJY01                              */
101 /*                                                                    */
102 /*  Command        Response                 Remarks                   */
103 /*  ------------   ----------------------   ---------------------     */
104 /*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>                             */
105 /*  time<CR><LF>   HH:MM:SS<CR><LF>                                   */
106 /*  stim<CR><LF>   HH:MM:SS<CR><LF>         Reply at just second      */
107 /*                                                                    */
108 /*  During synchronization after a receiver is turned on,             */
109 /*  It replies the past time from 2000/01/01 00:00:00.                */
110 /*  The function "refclock_process" checks the time and tells         */
111 /*  as an insanity time.                                              */
112 /*                                                                    */
113 /**********************************************************************/
114 /*                                                                    */
115 /*  The C-DEX Co. Ltd. JJY receiver JST2000                           */
116 /*                                                                    */
117 /*  Command        Response                 Remarks                   */
118 /*  ------------   ----------------------   ---------------------     */
119 /*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>                          */
120 /*                                                                    */
121 /**********************************************************************/
122 /*                                                                    */
123 /*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000                   */
124 /*                                                                    */
125 /*  Command        Response                 Remarks                   */
126 /*  ------------   ----------------------   ---------------------     */
127 /*  #                                       Mode 1 (Request&Send)     */
128 /*  T              YYMMDDWHHMMSS<BCC1><BCC2><CR>                      */
129 /*  C                                       Mode 2 (Continuous)       */
130 /*                 YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>              */
131 /*                 <SUB>                    Second signal             */
132 /*                                                                    */
133 /**********************************************************************/
134 
135 /*
136  * Interface definitions
137  */
138 #define	DEVICE  	"/dev/jjy%d"    /* device name and unit */
139 #define	SPEED232	B9600           /* uart speed (9600 baud) */
140 #define	REFID   	"JJY"           /* reference ID */
141 #define	DESCRIPTION	"JJY Receiver"
142 #define	PRECISION	(-3)           /* precision assumed (about 100 ms) */
143 
144 /*
145  * JJY unit control structure
146  */
147 struct jjyunit {
148 	char	unittype ;          /* UNITTYPE_XXXXXXXXXX */
149     short   operationmode ;     /* Echo Keisokuki LT-2000 : 1 or 2 */
150 	short	version ;
151 	short	linediscipline ;	/* LDISC_CLK or LDISC_RAW */
152 	int 	linecount ;
153 	int 	lineerror ;
154 	int 	year, month, day, hour, minute, second, msecond ;
155 /* LDISC_RAW only */
156 #define	MAX_LINECOUNT	8
157 #define	MAX_RAWBUF   	64
158 	int 	lineexpect ;
159 	int 	charexpect [ MAX_LINECOUNT ] ;
160 	int 	charcount ;
161 	char	rawbuf [ MAX_RAWBUF ] ;
162 };
163 
164 #define	UNITTYPE_TRISTATE_JJY01	1
165 #define	UNITTYPE_CDEX_JST2000  	2
166 #define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
167 
168 /*
169  * Function prototypes
170  */
171 static	int 	jjy_start                   P((int, struct peer *));
172 static	void	jjy_shutdown                P((int, struct peer *));
173 static	void	jjy_poll                    P((int, struct peer *));
174 static	void	jjy_poll_tristate_jjy01     P((int, struct peer *));
175 static	void	jjy_poll_cdex_jst2000       P((int, struct peer *));
176 static	void	jjy_poll_echokeisokuki_lt2000    P((int, struct peer *));
177 static	void	jjy_receive                 P((struct recvbuf *));
178 static	int 	jjy_receive_tristate_jjy01  P((struct recvbuf *));
179 static	int 	jjy_receive_cdex_jst2000    P((struct recvbuf *));
180 static	int 	jjy_receive_echokeisokuki_lt2000 P((struct recvbuf *));
181 
182 /*
183  * Transfer vector
184  */
185 struct	refclock refclock_jjy = {
186 	jjy_start,      /* start up driver */
187 	jjy_shutdown,   /* shutdown driver */
188 	jjy_poll,       /* transmit poll message */
189 	noentry,        /* not used */
190 	noentry,        /* not used */
191 	noentry,        /* not used */
192 	NOFLAGS         /* not used */
193 };
194 
195 /*
196  * Start up driver return code
197  */
198 #define	RC_START_SUCCESS	1
199 #define	RC_START_ERROR  	0
200 
201 /*
202  * Local constants definition
203  */
204 
205 #define	MAX_LOGTEXT	64
206 
207 
208 /**************************************************************************************************/
209 /*  jjy_start - open the devices and initialize data for processing                               */
210 /**************************************************************************************************/
211 static int
212 jjy_start ( int unit, struct peer *peer )
213 {
214 
215 	struct jjyunit      *up ;
216 	struct refclockproc *pp ;
217 	int 	fd ;
218 	char	*pDeviceName ;
219 	short	iDiscipline ;
220 
221 #ifdef DEBUG
222 	if ( debug ) {
223 		printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttl ) ;
224 		printf ( DEVICE, unit ) ;
225 		printf ( "\n" ) ;
226 	}
227 #endif
228 	/*
229 	 * Open serial port
230 	 */
231 	if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
232 		return RC_START_ERROR ;
233 	}
234 	sprintf ( pDeviceName, DEVICE, unit ) ;
235 
236 	/*
237 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
238 	 */
239 	switch ( peer->ttl ) {
240 	case 0 :
241 	case 1 : iDiscipline = LDISC_CLK ; break ;
242 	case 2 : iDiscipline = LDISC_RAW ; break ;
243 	case 3 : iDiscipline = LDISC_CLK ; break ;
244 	default :
245 		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
246 		          ntoa(&peer->srcadr), peer->ttl ) ;
247 		free ( (void*) pDeviceName ) ;
248 		return RC_START_ERROR ;
249 	}
250 
251 	if ( ! ( fd = refclock_open ( pDeviceName, SPEED232, iDiscipline ) ) ) {
252 		free ( (void*) pDeviceName ) ;
253 		return RC_START_ERROR ;
254 	}
255 	free ( (void*) pDeviceName ) ;
256 
257 	/*
258 	 * Allocate and initialize unit structure
259 	 */
260 	if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
261 		close ( fd ) ;
262 		return RC_START_ERROR ;
263 	}
264 
265 	memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
266 	up->linediscipline = iDiscipline ;
267 
268 	/*
269 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
270 	 */
271 	switch ( peer->ttl ) {
272 	case 0 :
273 		/*
274 		 * The mode 0 is a default clock type at this time.
275 		 * But this will be change to auto-detect mode in the future.
276 		 */
277 	case 1 :
278 		up->unittype = UNITTYPE_TRISTATE_JJY01 ;
279 		up->version  = 100 ;
280 		up->lineexpect = 2 ;
281 		up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
282 		up->charexpect[1] =  8 ; /* HH:MM:SS<CR><LF> */
283 		break ;
284 	case 2 :
285 		up->unittype = UNITTYPE_CDEX_JST2000 ;
286 		up->lineexpect = 1 ;
287 		up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
288 		break ;
289 	case 3 :
290 		up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
291 		up->operationmode = 2 ;  /* Mode 2 : Continuous mode */
292 		up->lineexpect = 1 ;
293         switch ( up->operationmode ) {
294         case 1 :
295 			up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
296 			break ;
297 		case 2 :
298 			up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
299 			break ;
300 		}
301 		break ;
302 	default :
303 		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
304 		          ntoa(&peer->srcadr), peer->ttl ) ;
305 		close ( fd ) ;
306 		free ( (void*) up ) ;
307 		return RC_START_ERROR ;
308 	}
309 
310 	pp = peer->procptr ;
311 	pp->unitptr       = (caddr_t) up ;
312 	pp->io.clock_recv = jjy_receive ;
313 	pp->io.srcclock   = (caddr_t) peer ;
314 	pp->io.datalen    = 0 ;
315 	pp->io.fd         = fd ;
316 	if ( ! io_addclock(&pp->io) ) {
317 		close ( fd ) ;
318 		free ( (void*) up ) ;
319 		return RC_START_ERROR ;
320 	}
321 
322 	/*
323 	 * Initialize miscellaneous variables
324 	 */
325 	peer->precision = PRECISION ;
326 	peer->burst     = 1 ;
327 	pp->clockdesc   = DESCRIPTION ;
328 	memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
329 
330 	return RC_START_SUCCESS ;
331 
332 }
333 
334 
335 /**************************************************************************************************/
336 /*  jjy_shutdown - shutdown the clock                                                             */
337 /**************************************************************************************************/
338 static void
339 jjy_shutdown ( int unit, struct peer *peer )
340 {
341 
342 	struct jjyunit      *up;
343 	struct refclockproc *pp;
344 
345 	pp = peer->procptr ;
346 	up = (struct jjyunit *) pp->unitptr ;
347 	io_closeclock ( &pp->io ) ;
348 	free ( (void*) up ) ;
349 
350 }
351 
352 
353 /**************************************************************************************************/
354 /*  jjy_receive - receive data from the serial interface                                          */
355 /**************************************************************************************************/
356 static void
357 jjy_receive ( struct recvbuf *rbufp )
358 {
359 
360 	struct jjyunit      *up ;
361 	struct refclockproc *pp ;
362 	struct peer         *peer;
363 
364 	l_fp	tRecvTimestamp;		/* arrival timestamp */
365 	int 	rc ;
366 	char	sLogText [ MAX_LOGTEXT ] ;
367 	int 	i, bCntrlChar ;
368 
369 	/*
370 	 * Initialize pointers and read the timecode and timestamp
371 	 */
372 	peer = (struct peer *) rbufp->recv_srcclock ;
373 	pp = peer->procptr ;
374 	up = (struct jjyunit *) pp->unitptr ;
375 
376 	/*
377 	 * Get next input line
378 	 */
379 	pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
380 
381 	if ( up->linediscipline == LDISC_RAW ) {
382 		/*
383 		 * The reply with <STX> and <ETX> may give a blank line
384 		 */
385 		if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
386 		/*
387 		 * Copy received charaters to temporary buffer
388 		 */
389 		for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
390 			up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
391 		}
392 		while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
393 			for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ;
394 			up->charcount -- ;
395 		}
396 		bCntrlChar = 0 ;
397 		for ( i = 0 ; i < up->charcount ; i ++ ) {
398 			if ( up->rawbuf[i] < ' ' ) {
399 				bCntrlChar = 1 ;
400 				break ;
401 			}
402 		}
403 		if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
404 			if ( bCntrlChar == 0  &&  up->charcount < up->charexpect[up->linecount] ) return ;
405 		}
406 		up->rawbuf[up->charcount] = 0 ;
407 	} else {
408 		/*
409 		 * The reply with <CR><LF> gives a blank line
410 		 */
411 		if ( pp->lencode == 0 ) return ;
412 	}
413 	/*
414 	 * We get down to business
415 	 */
416 
417 	pp->lastrec = tRecvTimestamp ;
418 
419 	up->linecount ++ ;
420 
421 	if ( up->lineerror != 0 ) return ;
422 
423 	switch ( up->unittype ) {
424 
425 	case UNITTYPE_TRISTATE_JJY01 :
426 		rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
427 		break ;
428 
429 	case UNITTYPE_CDEX_JST2000 :
430 		rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
431 		break ;
432 
433 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
434 		rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
435 		break ;
436 
437 	default :
438 		rc = 0 ;
439 		break ;
440 
441 	}
442 
443 	if ( up->linediscipline == LDISC_RAW ) {
444 		if ( up->linecount <= up->lineexpect  &&  up->charcount > up->charexpect[up->linecount-1] ) {
445 			for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) {
446 				up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
447 			}
448 			up->charcount -= up->charexpect[up->linecount-1] ;
449 		} else {
450 			up->charcount = 0 ;
451 		}
452 	}
453 
454 	if ( rc == 0 ) return ;
455 
456 	if ( up->lineerror != 0 ) {
457 		refclock_report ( peer, CEVNT_BADREPLY ) ;
458 		strcpy  ( sLogText, "BAD REPLY [" ) ;
459 		if ( up->linediscipline == LDISC_RAW ) {
460 			strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
461 		} else {
462 			strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
463 		}
464 		sLogText[MAX_LOGTEXT-1] = 0 ;
465 		if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
466 		record_clock_stats ( &peer->srcadr, sLogText ) ;
467 		return ;
468 	}
469 
470 	pp->year   = up->year ;
471 	pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
472 	pp->hour   = up->hour ;
473 	pp->minute = up->minute ;
474 	pp->second = up->second ;
475 	pp->nsec   = up->msecond * 1000000;
476 
477 	/*
478 	 * JST to UTC
479 	 */
480 	pp->hour -= 9 ;
481 	if ( pp->hour < 0 ) {
482 		pp->hour += 24 ;
483 		pp->day -- ;
484 		if ( pp->day < 1 ) {
485 			pp->year -- ;
486 			pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
487 		}
488 	}
489 #ifdef DEBUG
490 	if ( debug ) {
491 		printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST   ",
492 		          up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
493 		printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
494 		          pp->year, pp->day, pp->hour, pp->minute, pp->second, (int)(pp->nsec/100000000) ) ;
495 	}
496 #endif
497 
498 	/*
499 	 * Process the new sample in the median filter and determine the
500 	 * timecode timestamp.
501 	 */
502 
503 	sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
504 	          up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
505 	record_clock_stats ( &peer->srcadr, sLogText ) ;
506 
507 	if ( ! refclock_process ( pp ) ) {
508 		refclock_report(peer, CEVNT_BADTIME);
509 		return ;
510 	}
511 
512 	pp->lastref = pp->lastrec;
513 	refclock_receive(peer);
514 
515 }
516 
517 /**************************************************************************************************/
518 
519 static int
520 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
521 {
522 
523 	static	char	*sFunctionName = "jjy_receive_tristate_jjy01" ;
524 
525 	struct jjyunit      *up ;
526 	struct refclockproc *pp ;
527 	struct peer         *peer;
528 
529 	char	*pBuf ;
530 	int 	iLen ;
531 	int 	rc ;
532 
533 	/*
534 	 * Initialize pointers and read the timecode and timestamp
535 	 */
536 	peer = (struct peer *) rbufp->recv_srcclock ;
537 	pp = peer->procptr ;
538 	up = (struct jjyunit *) pp->unitptr ;
539 
540 	if ( up->linediscipline == LDISC_RAW ) {
541 		pBuf = up->rawbuf ;
542 		iLen = up->charcount ;
543 	} else {
544 	    pBuf = pp->a_lastcode ;
545 	    iLen = pp->lencode ;
546 	}
547 
548 	switch ( up->linecount ) {
549 
550 	case 1 : /* YYYY/MM/DD WWW */
551 
552 		if ( iLen != 14 ) {
553 #ifdef DEBUG
554 	        if ( debug >= 2 ) {
555 		        printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d  iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
556 	        }
557 #endif
558 			up->lineerror = 1 ;
559 			break ;
560 		}
561 		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
562 		if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
563 #ifdef DEBUG
564 	        if ( debug >= 2 ) {
565 		        printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
566 	        }
567 #endif
568 			up->lineerror = 1 ;
569 			break ;
570 		}
571 
572 		/*** Start of modification on 2004/10/31 */
573 		/*
574 		 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
575 		 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
576 		 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
577 		 * so this driver issues the second command "stim" after the reply of the first command "date".
578 		 */
579 
580 		/*
581 		 * Send "stim<CR><LF>" or "time<CR><LF>" command
582 		 */
583 
584 
585 		if ( up->version >= 100 ) {
586 #ifdef DEBUG
587 			if ( debug ) {
588 				printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName ) ;
589 			}
590 #endif
591 			if ( write ( pp->io.fd, "stim\r\n",6 ) != 6  ) {
592 				refclock_report ( peer, CEVNT_FAULT ) ;
593 			}
594 		} else {
595 #ifdef DEBUG
596 			if ( debug ) {
597 				printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName ) ;
598 			}
599 #endif
600 			if ( write ( pp->io.fd, "time\r\n",6 ) != 6  ) {
601 				refclock_report ( peer, CEVNT_FAULT ) ;
602 			}
603 		}
604 		/*** End of modification ***/
605 
606 		return 0 ;
607 
608 	case 2 : /* HH:MM:SS */
609 
610 		if ( iLen != 8 ) {
611 #ifdef DEBUG
612 	        if ( debug >= 2 ) {
613 		        printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d  iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
614 	        }
615 #endif
616 			up->lineerror = 1 ;
617 			break ;
618 		}
619 		rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
620 		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
621 #ifdef DEBUG
622 	        if ( debug >= 2 ) {
623 		        printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
624 	        }
625 #endif
626 			up->lineerror = 1 ;
627 			break ;
628 		}
629 		up->msecond = 0 ;
630 		if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
631 			/*
632 			 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
633 			 * But the JJY receiver replies a date and time separately.
634 			 * Just after midnight transitions, we ignore this time.
635 			 */
636 			return 0 ;
637 		}
638 		break ;
639 
640 	default : /*  Unexpected reply */
641 
642 		up->lineerror = 1 ;
643 		break ;
644 
645 	}
646 
647 	return 1 ;
648 
649 }
650 
651 /**************************************************************************************************/
652 
653 static int
654 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
655 {
656 
657 	static	char	*sFunctionName = "jjy_receive_cdex_jst2000" ;
658 
659 	struct jjyunit      *up ;
660 	struct refclockproc *pp ;
661 	struct peer         *peer;
662 
663 	char	*pBuf ;
664 	int 	iLen ;
665 	int 	rc ;
666 
667 	/*
668 	 * Initialize pointers and read the timecode and timestamp
669 	 */
670 	peer = (struct peer *) rbufp->recv_srcclock ;
671 	pp = peer->procptr ;
672 	up = (struct jjyunit *) pp->unitptr ;
673 
674 	if ( up->linediscipline == LDISC_RAW ) {
675 		pBuf = up->rawbuf ;
676 		iLen = up->charcount ;
677 	} else {
678 	    pBuf = pp->a_lastcode ;
679 	    iLen = pp->lencode ;
680 	}
681 
682 	switch ( up->linecount ) {
683 
684 	case 1 : /* JYYMMDD HHMMSSS */
685 
686 		if ( iLen != 15 ) {
687 #ifdef DEBUG
688 	        if ( debug >= 2 ) {
689 		        printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
690 	        }
691 #endif
692 			up->lineerror = 1 ;
693 			break ;
694 		}
695 		rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
696 		              &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
697 		if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
698 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
699 #ifdef DEBUG
700 	        if ( debug >= 2 ) {
701 		        printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName,
702 						 rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ;
703 	        }
704 #endif
705 			up->lineerror = 1 ;
706 			break ;
707 		}
708 		up->year    += 2000 ;
709 		up->msecond *= 100 ;
710 		break ;
711 
712 	default : /*  Unexpected reply */
713 
714 		up->lineerror = 1 ;
715 		break ;
716 
717 	}
718 
719 	return 1 ;
720 
721 }
722 
723 /**************************************************************************************************/
724 
725 static int
726 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
727 {
728 
729 	static	char	*sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
730 
731 	struct jjyunit      *up ;
732 	struct refclockproc *pp ;
733 	struct peer         *peer;
734 
735 	char	*pBuf ;
736 	int 	iLen ;
737 	int 	rc ;
738     int     i, ibcc, ibcc1, ibcc2 ;
739 
740 	/*
741 	 * Initialize pointers and read the timecode and timestamp
742 	 */
743 	peer = (struct peer *) rbufp->recv_srcclock ;
744 	pp = peer->procptr ;
745 	up = (struct jjyunit *) pp->unitptr ;
746 
747 	if ( up->linediscipline == LDISC_RAW ) {
748 		pBuf = up->rawbuf ;
749 		iLen = up->charcount ;
750 	} else {
751 	    pBuf = pp->a_lastcode ;
752 	    iLen = pp->lencode ;
753 	}
754 
755 	switch ( up->linecount ) {
756 
757 	case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
758 
759 		if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) {
760 #ifdef DEBUG
761 	        if ( debug >= 2 ) {
762 		        printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
763 	        }
764 #endif
765 			if ( up->operationmode == 1 ) {
766 #ifdef DEBUG
767 				if ( debug ) {
768 					printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
769 				}
770 #endif
771 				if ( write ( pp->io.fd, "#",1 ) != 1  ) {
772 					refclock_report ( peer, CEVNT_FAULT ) ;
773 				}
774 			}
775 			up->lineerror = 1 ;
776 			break ;
777 		}
778 
779 		if ( up->operationmode == 1 ) {
780 
781         	for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ;
782         	ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
783         	ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
784         	if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
785 #ifdef DEBUG
786 	        	if ( debug >= 2 ) {
787 		        	printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ;
788 	        	}
789 #endif
790 				up->lineerror = 1 ;
791 				break ;
792 			}
793 
794         }
795 
796 		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
797                       &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ;
798 		if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
799 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
800 #ifdef DEBUG
801 	        if ( debug >= 2 ) {
802 		        printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName,
803 						 rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
804 	        }
805 #endif
806 			up->lineerror = 1 ;
807 			break ;
808 		}
809 
810 		up->year += 2000 ;
811 
812 		if ( up->operationmode == 2 ) {
813 
814 			/* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
815 			up->msecond = 500 ;
816 			pp->second -- ;
817 			if ( pp->second < 0 ) {
818 				pp->second = 59 ;
819 				pp->minute -- ;
820 				if ( pp->minute < 0 ) {
821 					pp->minute = 59 ;
822 					pp->hour -- ;
823 					if ( pp->hour < 0 ) {
824 						pp->hour = 23 ;
825 						pp->day -- ;
826 						if ( pp->day < 1 ) {
827 							pp->year -- ;
828 							pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
829 						}
830 					}
831 				}
832 			}
833 
834 			/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
835 #ifdef DEBUG
836 			if ( debug ) {
837 				printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
838 			}
839 #endif
840 			if ( write ( pp->io.fd, "#",1 ) != 1  ) {
841 				refclock_report ( peer, CEVNT_FAULT ) ;
842 			}
843 
844 		}
845 
846 		break ;
847 
848 	default : /*  Unexpected reply */
849 
850 #ifdef DEBUG
851 		if ( debug ) {
852 			printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
853 		}
854 #endif
855 		if ( write ( pp->io.fd, "#",1 ) != 1  ) {
856 			refclock_report ( peer, CEVNT_FAULT ) ;
857 		}
858 
859 		up->lineerror = 1 ;
860 		break ;
861 
862 	}
863 
864 	return 1 ;
865 
866 }
867 
868 /**************************************************************************************************/
869 /*  jjy_poll - called by the transmit procedure                                                   */
870 /**************************************************************************************************/
871 static void
872 jjy_poll ( int unit, struct peer *peer )
873 {
874 
875 	struct jjyunit      *up;
876 	struct refclockproc *pp;
877 
878 	pp = peer->procptr;
879 	up = (struct jjyunit *) pp->unitptr ;
880 
881 	if ( pp->polls > 0  &&  up->linecount == 0 ) {
882 		/*
883 		 * No reply for last command
884 		 */
885 		refclock_report ( peer, CEVNT_TIMEOUT ) ;
886 	}
887 
888 #ifdef DEBUG
889 	if ( debug ) {
890 		printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
891 	}
892 #endif
893 
894 	pp->polls ++ ;
895 
896 	up->linecount = 0 ;
897 	up->lineerror = 0 ;
898 	up->charcount = 0 ;
899 
900 	switch ( up->unittype ) {
901 
902 	case UNITTYPE_TRISTATE_JJY01 :
903 		jjy_poll_tristate_jjy01  ( unit, peer ) ;
904 		break ;
905 
906 	case UNITTYPE_CDEX_JST2000 :
907 		jjy_poll_cdex_jst2000 ( unit, peer ) ;
908 		break ;
909 
910 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
911 		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
912 		break ;
913 
914 	default :
915 		break ;
916 
917 	}
918 
919 }
920 
921 /**************************************************************************************************/
922 
923 static void
924 jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
925 {
926 
927 	struct refclockproc *pp;
928 
929 	pp = peer->procptr;
930 
931 	/*
932 	 * Send "date<CR><LF>" command
933 	 */
934 
935 #ifdef DEBUG
936 	if ( debug ) {
937 		printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
938 	}
939 #endif
940 
941 	if ( write ( pp->io.fd, "date\r\n",6 ) != 6  ) {
942 		refclock_report ( peer, CEVNT_FAULT ) ;
943 	}
944 
945 }
946 
947 /**************************************************************************************************/
948 
949 static void
950 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
951 {
952 
953 	struct refclockproc *pp;
954 
955 	pp = peer->procptr;
956 
957 	/*
958 	 * Send "<ENQ>1J<ETX>" command
959 	 */
960 
961 #ifdef DEBUG
962 	if ( debug ) {
963 		printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
964 	}
965 #endif
966 
967 	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
968 		refclock_report ( peer, CEVNT_FAULT ) ;
969 	}
970 
971 }
972 
973 /**************************************************************************************************/
974 
975 static void
976 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
977 {
978 
979 	struct jjyunit      *up;
980 	struct refclockproc *pp;
981 
982 	char	sCmd[2] ;
983 
984 	pp = peer->procptr;
985 	up = (struct jjyunit *) pp->unitptr ;
986 
987 	/*
988 	 * Send "T" or "C" command
989 	 */
990 
991 	switch ( up->operationmode ) {
992 	case 1 : sCmd[0] = 'T' ; break ;
993 	case 2 : sCmd[0] = 'C' ; break ;
994 	}
995 	sCmd[1] = 0 ;
996 
997 #ifdef DEBUG
998 	if ( debug ) {
999 		printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1000 	}
1001 #endif
1002 
1003 	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1004 		refclock_report ( peer, CEVNT_FAULT ) ;
1005 	}
1006 
1007 }
1008 
1009 #else
1010 int refclock_jjy_bs ;
1011 #endif /* REFCLOCK */
1012