refclock_jjy.c revision 182007
1189251Ssam/*
2189251Ssam * refclock_jjy - clock driver for JJY receivers
3189251Ssam */
4189251Ssam
5189251Ssam/**********************************************************************/
6189251Ssam/*                                                                    */
7189251Ssam/*  Copyright (C) 2001-2004, Takao Abe.  All rights reserved.         */
8189251Ssam/*                                                                    */
9189251Ssam/*  Permission to use, copy, modify, and distribute this software     */
10189251Ssam/*  and its documentation for any purpose is hereby granted           */
11189251Ssam/*  without fee, provided that the following conditions are met:      */
12189251Ssam/*                                                                    */
13189251Ssam/*  One retains the entire copyright notice properly, and both the    */
14189251Ssam/*  copyright notice and this license. in the documentation and/or    */
15189251Ssam/*  other materials provided with the distribution.                   */
16189251Ssam/*                                                                    */
17189251Ssam/*  This software and the name of the author must not be used to      */
18189251Ssam/*  endorse or promote products derived from this software without    */
19189251Ssam/*  prior written permission.                                         */
20189251Ssam/*                                                                    */
21189251Ssam/*  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED    */
22189251Ssam/*  WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE        */
23189251Ssam/*  IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A          */
24189251Ssam/*  PARTICULAR PURPOSE.                                               */
25189251Ssam/*  IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT,  */
26189251Ssam/*  INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   */
27189251Ssam/*  ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE        */
28189251Ssam/*  GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS      */
29189251Ssam/*  INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,     */
30189251Ssam/*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING        */
31189251Ssam/*  NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF    */
32189251Ssam/*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
33189251Ssam/*                                                                    */
34189251Ssam/*  This driver is developed in my private time, and is opened as     */
35189251Ssam/*  voluntary contributions for the NTP.                              */
36189251Ssam/*  The manufacturer of the JJY receiver has not participated in      */
37189251Ssam/*  a development of this driver.                                     */
38189251Ssam/*  The manufacturer does not warrant anything about this driver,     */
39189251Ssam/*  and is not liable for anything about this driver.                 */
40189251Ssam/*                                                                    */
41189251Ssam/**********************************************************************/
42189251Ssam/*                                                                    */
43189251Ssam/*  Author     Takao Abe                                              */
44189251Ssam/*  Email      abetakao@bea.hi-ho.ne.jp                               */
45189251Ssam/*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/                   */
46189251Ssam/*                                                                    */
47189251Ssam/**********************************************************************/
48189251Ssam/*                                                                    */
49189251Ssam/*  History                                                           */
50189251Ssam/*                                                                    */
51189251Ssam/*  2001/07/15                                                        */
52189251Ssam/*    [New]    Support the Tristate Ltd. JJY receiver                 */
53189251Ssam/*                                                                    */
54189251Ssam/*  2001/08/04                                                        */
55189251Ssam/*    [Change] Log to clockstats even if bad reply                    */
56189251Ssam/*    [Fix]    PRECISION = (-3) (about 100 ms)                        */
57189251Ssam/*    [Add]    Support the C-DEX Co.Ltd. JJY receiver                 */
58189251Ssam/*                                                                    */
59189251Ssam/*  2001/12/04                                                        */
60189251Ssam/*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
61189251Ssam/*                                                                    */
62189251Ssam/*  2002/07/12                                                        */
63189251Ssam/*    [Fix]    Portability for FreeBSD ( patched by the user )        */
64189251Ssam/*                                                                    */
65189251Ssam/*  2004/10/31                                                        */
66189251Ssam/*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
67189251Ssam/*             JJY-01 ( Firmware version 2.01 )                       */
68189251Ssam/*             Thanks to Andy Taki for testing under FreeBSD          */
69189251Ssam/*                                                                    */
70189251Ssam/*  2004/11/28                                                        */
71189251Ssam/*    [Add]    Support the Echo Keisokuki LT-2000 receiver            */
72189251Ssam/*                                                                    */
73189251Ssam/*  2006/11/04                                                        */
74189251Ssam/*    [Fix]    C-DEX JST2000                                          */
75189251Ssam/*             Thanks to Hideo Kuramatsu for the patch                */
76189251Ssam/*                                                                    */
77189251Ssam/**********************************************************************/
78189251Ssam
79189251Ssam#ifdef HAVE_CONFIG_H
80189251Ssam#include <config.h>
81189251Ssam#endif
82189251Ssam
83189251Ssam#if defined(REFCLOCK) && defined(CLOCK_JJY)
84189251Ssam
85189251Ssam#include <stdio.h>
86189251Ssam#include <ctype.h>
87189251Ssam#include <string.h>
88189251Ssam#include <sys/time.h>
89189251Ssam#include <time.h>
90189251Ssam
91189251Ssam#include "ntpd.h"
92189251Ssam#include "ntp_io.h"
93189251Ssam#include "ntp_tty.h"
94189251Ssam#include "ntp_refclock.h"
95189251Ssam#include "ntp_calendar.h"
96189251Ssam#include "ntp_stdlib.h"
97189251Ssam
98189251Ssam/**********************************************************************/
99189251Ssam/*                                                                    */
100189251Ssam/*  The Tristate Ltd. JJY receiver JJY01                              */
101189251Ssam/*                                                                    */
102189251Ssam/*  Command        Response                 Remarks                   */
103189251Ssam/*  ------------   ----------------------   ---------------------     */
104189251Ssam/*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>                             */
105189251Ssam/*  time<CR><LF>   HH:MM:SS<CR><LF>                                   */
106189251Ssam/*  stim<CR><LF>   HH:MM:SS<CR><LF>         Reply at just second      */
107189251Ssam/*                                                                    */
108189251Ssam/*  During synchronization after a receiver is turned on,             */
109189251Ssam/*  It replies the past time from 2000/01/01 00:00:00.                */
110189251Ssam/*  The function "refclock_process" checks the time and tells         */
111189251Ssam/*  as an insanity time.                                              */
112189251Ssam/*                                                                    */
113189251Ssam/**********************************************************************/
114189251Ssam/*                                                                    */
115189251Ssam/*  The C-DEX Co. Ltd. JJY receiver JST2000                           */
116189251Ssam/*                                                                    */
117189251Ssam/*  Command        Response                 Remarks                   */
118189251Ssam/*  ------------   ----------------------   ---------------------     */
119189251Ssam/*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>                          */
120189251Ssam/*                                                                    */
121189251Ssam/**********************************************************************/
122189251Ssam/*                                                                    */
123189251Ssam/*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000                   */
124189251Ssam/*                                                                    */
125189251Ssam/*  Command        Response                 Remarks                   */
126189251Ssam/*  ------------   ----------------------   ---------------------     */
127189251Ssam/*  #                                       Mode 1 (Request&Send)     */
128189251Ssam/*  T              YYMMDDWHHMMSS<BCC1><BCC2><CR>                      */
129189251Ssam/*  C                                       Mode 2 (Continuous)       */
130189251Ssam/*                 YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>              */
131189251Ssam/*                 <SUB>                    Second signal             */
132189251Ssam/*                                                                    */
133189251Ssam/**********************************************************************/
134189251Ssam
135189251Ssam/*
136189251Ssam * Interface definitions
137189251Ssam */
138189251Ssam#define	DEVICE  	"/dev/jjy%d"    /* device name and unit */
139189251Ssam#define	SPEED232	B9600           /* uart speed (9600 baud) */
140189251Ssam#define	REFID   	"JJY"           /* reference ID */
141189251Ssam#define	DESCRIPTION	"JJY Receiver"
142189251Ssam#define	PRECISION	(-3)           /* precision assumed (about 100 ms) */
143189251Ssam
144189251Ssam/*
145189251Ssam * JJY unit control structure
146189251Ssam */
147189251Ssamstruct jjyunit {
148189251Ssam	char	unittype ;          /* UNITTYPE_XXXXXXXXXX */
149189251Ssam    short   operationmode ;     /* Echo Keisokuki LT-2000 : 1 or 2 */
150189251Ssam	short	version ;
151189251Ssam	short	linediscipline ;	/* LDISC_CLK or LDISC_RAW */
152189251Ssam	int 	linecount ;
153189251Ssam	int 	lineerror ;
154189251Ssam	int 	year, month, day, hour, minute, second, msecond ;
155189251Ssam/* LDISC_RAW only */
156189251Ssam#define	MAX_LINECOUNT	8
157189251Ssam#define	MAX_RAWBUF   	64
158189251Ssam	int 	lineexpect ;
159189251Ssam	int 	charexpect [ MAX_LINECOUNT ] ;
160189251Ssam	int 	charcount ;
161189251Ssam	char	rawbuf [ MAX_RAWBUF ] ;
162189251Ssam};
163189251Ssam
164189251Ssam#define	UNITTYPE_TRISTATE_JJY01	1
165189251Ssam#define	UNITTYPE_CDEX_JST2000  	2
166189251Ssam#define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
167189251Ssam
168189251Ssam/*
169189251Ssam * Function prototypes
170189251Ssam */
171189251Ssamstatic	int 	jjy_start                   P((int, struct peer *));
172189251Ssamstatic	void	jjy_shutdown                P((int, struct peer *));
173189251Ssamstatic	void	jjy_poll                    P((int, struct peer *));
174189251Ssamstatic	void	jjy_poll_tristate_jjy01     P((int, struct peer *));
175189251Ssamstatic	void	jjy_poll_cdex_jst2000       P((int, struct peer *));
176189251Ssamstatic	void	jjy_poll_echokeisokuki_lt2000    P((int, struct peer *));
177189251Ssamstatic	void	jjy_receive                 P((struct recvbuf *));
178189251Ssamstatic	int 	jjy_receive_tristate_jjy01  P((struct recvbuf *));
179189251Ssamstatic	int 	jjy_receive_cdex_jst2000    P((struct recvbuf *));
180189251Ssamstatic	int 	jjy_receive_echokeisokuki_lt2000 P((struct recvbuf *));
181189251Ssam
182189251Ssam/*
183189251Ssam * Transfer vector
184189251Ssam */
185189251Ssamstruct	refclock refclock_jjy = {
186209158Srpaulo	jjy_start,      /* start up driver */
187209158Srpaulo	jjy_shutdown,   /* shutdown driver */
188189251Ssam	jjy_poll,       /* transmit poll message */
189189251Ssam	noentry,        /* not used */
190189251Ssam	noentry,        /* not used */
191189251Ssam	noentry,        /* not used */
192189251Ssam	NOFLAGS         /* not used */
193189251Ssam};
194189251Ssam
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/**************************************************************************************************/
211static int
212jjy_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/**************************************************************************************************/
338static void
339jjy_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/**************************************************************************************************/
356static void
357jjy_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
519static int
520jjy_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
653static int
654jjy_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
725static int
726jjy_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/**************************************************************************************************/
871static void
872jjy_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
923static void
924jjy_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
949static void
950jjy_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
975static void
976jjy_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
1010int refclock_jjy_bs ;
1011#endif /* REFCLOCK */
1012