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 */
164struct 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 */
190static	int 	jjy_start                   (int, struct peer *);
191static	void	jjy_shutdown                (int, struct peer *);
192static	void	jjy_poll                    (int, struct peer *);
193static	void	jjy_poll_tristate_jjy01     (int, struct peer *);
194static	void	jjy_poll_cdex_jst2000       (int, struct peer *);
195static	void	jjy_poll_echokeisokuki_lt2000    (int, struct peer *);
196static  void    jjy_poll_citizentic_jjy200          (int, struct peer *);
197static	void	jjy_receive                 (struct recvbuf *);
198static	int 	jjy_receive_tristate_jjy01  (struct recvbuf *);
199static	int 	jjy_receive_cdex_jst2000    (struct recvbuf *);
200static	int 	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
201static  int     jjy_receive_citizentic_jjy200 (struct recvbuf *);
202
203/*
204 * Transfer vector
205 */
206struct	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/**************************************************************************************************/
232static int
233jjy_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/**************************************************************************************************/
378static void
379jjy_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/**************************************************************************************************/
396static void
397jjy_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
565static int
566jjy_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
699static int
700jjy_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
771static int
772jjy_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
916static int
917jjy_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/**************************************************************************************************/
1004static void
1005jjy_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
1061static void
1062jjy_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
1087static void
1088jjy_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
1113static void
1114jjy_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
1149static void
1150jjy_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
1158int refclock_jjy_bs ;
1159#endif /* REFCLOCK */
1160