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