refclock_jjy.c revision 1.5
1/*	$NetBSD: refclock_jjy.c,v 1.5 2013/12/28 03:20:14 christos Exp $	*/
2
3/*
4 * refclock_jjy - clock driver for JJY receivers
5 */
6
7/**********************************************************************/
8/*								      */
9/*  Copyright (C) 2001-2011, 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      takao_abe@xurb.jp				      */
47/*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/		      */
48/*								      */
49/*  The email address abetakao@bea.hi-ho.ne.jp is never read	      */
50/*  from 2010, because a few filtering rule are provided by the	      */
51/*  "hi-ho.ne.jp", and lots of spam mail are reached.		      */
52/*  New email address for supporting the refclock_jjy is	      */
53/*  takao_abe@xurb.jp						      */
54/*								      */
55/**********************************************************************/
56/*								      */
57/*  History							      */
58/*								      */
59/*  2001/07/15							      */
60/*    [New]    Support the Tristate Ltd. JJY receiver		      */
61/*								      */
62/*  2001/08/04							      */
63/*    [Change] Log to clockstats even if bad reply		      */
64/*    [Fix]    PRECISION = (-3) (about 100 ms)			      */
65/*    [Add]    Support the C-DEX Co.Ltd. JJY receiver		      */
66/*								      */
67/*  2001/12/04							      */
68/*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
69/*								      */
70/*  2002/07/12							      */
71/*    [Fix]    Portability for FreeBSD ( patched by the user )	      */
72/*								      */
73/*  2004/10/31							      */
74/*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
75/*	       JJY-01 ( Firmware version 2.01 )			      */
76/*	       Thanks to Andy Taki for testing under FreeBSD	      */
77/*								      */
78/*  2004/11/28							      */
79/*    [Add]    Support the Echo Keisokuki LT-2000 receiver	      */
80/*								      */
81/*  2006/11/04							      */
82/*    [Fix]    C-DEX JST2000					      */
83/*	       Thanks to Hideo Kuramatsu for the patch		      */
84/*								      */
85/*  2009/04/05							      */
86/*    [Add]    Support the CITIZEN T.I.C JJY-200 receiver	      */
87/*								      */
88/*  2010/11/20							      */
89/*    [Change] Bug 1618 ( Harmless )				      */
90/*	       Code clean up ( Remove unreachable codes ) in	      */
91/*	       jjy_start()					      */
92/*    [Change] Change clockstats format of the Tristate JJY01/02      */
93/*	       Issues more command to get the status of the receiver  */
94/*	       when "fudge 127.127.40.X flag1 1" is specified	      */
95/*	       ( DATE,STIM -> DCST,STUS,DATE,STIM )		      */
96/*								      */
97/*  2011/04/30							      */
98/*    [Add]    Support the Tristate Ltd. TS-GPSclock-01		      */
99/*								      */
100/**********************************************************************/
101
102#ifdef HAVE_CONFIG_H
103#include <config.h>
104#endif
105
106#if defined(REFCLOCK) && defined(CLOCK_JJY)
107
108#include <stdio.h>
109#include <ctype.h>
110#include <string.h>
111#include <sys/time.h>
112#include <time.h>
113
114#include "ntpd.h"
115#include "ntp_io.h"
116#include "ntp_tty.h"
117#include "ntp_refclock.h"
118#include "ntp_calendar.h"
119#include "ntp_stdlib.h"
120
121/**********************************************************************/
122/*								      */
123/*  The Tristate Ltd. JJY receiver JJY01			      */
124/*								      */
125/*  Command	   Response		    Remarks		      */
126/*  ------------   ----------------------   ---------------------     */
127/*  dcst<CR><LF>   VALID|INVALID<CR><LF>			      */
128/*  stus<CR><LF>   ADJUSTED|UNADJUSTED<CR><LF>			      */
129/*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>			      */
130/*  time<CR><LF>   HH:MM:SS<CR><LF>	    Not used by this driver   */
131/*  stim<CR><LF>   HH:MM:SS<CR><LF>	    Reply at just second      */
132/*								      */
133/*  During synchronization after a receiver is turned on,	      */
134/*  It replies the past time from 2000/01/01 00:00:00.		      */
135/*  The function "refclock_process" checks the time and tells	      */
136/*  as an insanity time.					      */
137/*								      */
138/**********************************************************************/
139/*								      */
140/*  The C-DEX Co. Ltd. JJY receiver JST2000			      */
141/*								      */
142/*  Command	   Response		    Remarks		      */
143/*  ------------   ----------------------   ---------------------     */
144/*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>			      */
145/*								      */
146/**********************************************************************/
147/*								      */
148/*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000		      */
149/*								      */
150/*  Command        Response		    Remarks		      */
151/*  ------------   ----------------------   ---------------------     */
152/*  #					    Mode 1 (Request&Send)     */
153/*  T		   YYMMDDWHHMMSS<BCC1><BCC2><CR>		      */
154/*  C					    Mode 2 (Continuous)	      */
155/*		   YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>	      */
156/*		   <SUB>		    Second signal	      */
157/*								      */
158/**********************************************************************/
159/*								      */
160/*  The CITIZEN T.I.C CO., LTD. JJY receiver JJY200		      */
161/*								      */
162/*  Command	   Response		    Remarks		      */
163/*  ------------   ----------------------   ---------------------     */
164/*		   'XX YY/MM/DD W HH:MM:SS<CR>			      */
165/*					    XX: OK|NG|ER	      */
166/*					    W:  0(Monday)-6(Sunday)   */
167/*								      */
168/**********************************************************************/
169/*								      */
170/*  The Tristate Ltd. GPS clock TS-GPSCLOCK-01			      */
171/*								      */
172/*  This clock has NMEA mode and command/respose mode.		      */
173/*  When this jjy driver are used, set to command/respose mode        */
174/*  of this clock by the onboard switch SW4, and make sure the        */
175/*  LED-Y is tured on.						      */
176/*  Other than this JJY driver, the refclock driver type 20,	      */
177/*  generic NMEA driver, works with the NMEA mode of this clock.      */
178/*								      */
179/*  Command	   Response		    Remarks		      */
180/*  ------------   ----------------------   ---------------------     */
181/*  stus<CR><LF>   *R|*G|*U|+U<CR><LF>				      */
182/*  date<CR><LF>   YY/MM/DD<CR><LF>				      */
183/*  time<CR><LF>   HH:MM:SS<CR><LF>				      */
184/*								      */
185/**********************************************************************/
186
187/*
188 * Interface definitions
189 */
190#define	DEVICE  	"/dev/jjy%d"	/* device name and unit */
191#define	SPEED232	B9600		/* uart speed (9600 baud) */
192#define	SPEED232_TRISTATE_JJY01		B9600   /* UART speed (9600 baud) */
193#define	SPEED232_CDEX_JST2000		B9600   /* UART speed (9600 baud) */
194#define	SPEED232_ECHOKEISOKUKI_LT2000	B9600   /* UART speed (9600 baud) */
195#define	SPEED232_CITIZENTIC_JJY200	B4800   /* UART speed (4800 baud) */
196#define	SPEED232_TRISTATE_GPSCLOCK01	B38400  /* USB  speed (38400 baud) */
197#define	REFID   	"JJY"		/* reference ID */
198#define	DESCRIPTION	"JJY Receiver"
199#define	PRECISION	(-3)		/* precision assumed (about 100 ms) */
200
201/*
202 * JJY unit control structure
203 */
204struct jjyunit {
205	char	unittype ;	    /* UNITTYPE_XXXXXXXXXX */
206	short   operationmode ;	    /* Echo Keisokuki LT-2000 : 1 or 2 */
207	short	version ;
208	short	linediscipline ;    /* LDISC_CLK or LDISC_RAW */
209	char    bPollFlag ;	    /* Set by jjy_pool and Reset by jjy_receive */
210	int 	linecount ;
211	int 	lineerror ;
212	int 	year, month, day, hour, minute, second, msecond ;
213/* LDISC_RAW only */
214#define	MAX_LINECOUNT	8
215#define	MAX_RAWBUF   	64
216	int 	lineexpect ;
217	int 	charexpect [ MAX_LINECOUNT ] ;
218	int 	charcount ;
219	char	rawbuf [ MAX_RAWBUF ] ;
220};
221
222#define	UNITTYPE_TRISTATE_JJY01		1
223#define	UNITTYPE_CDEX_JST2000		2
224#define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
225#define	UNITTYPE_CITIZENTIC_JJY200  	4
226#define	UNITTYPE_TRISTATE_GPSCLOCK01	5
227
228/*
229 * Function prototypes
230 */
231
232static	int 	jjy_start			(int, struct peer *);
233static	void	jjy_shutdown			(int, struct peer *);
234
235static	void	jjy_poll		    	(int, struct peer *);
236static	void	jjy_poll_tristate_jjy01	    	(int, struct peer *);
237static	void	jjy_poll_cdex_jst2000	    	(int, struct peer *);
238static	void	jjy_poll_echokeisokuki_lt2000	(int, struct peer *);
239static	void	jjy_poll_citizentic_jjy200	(int, struct peer *);
240static	void	jjy_poll_tristate_gpsclock01	(int, struct peer *);
241
242static	void	jjy_receive			(struct recvbuf *);
243static	int	jjy_receive_tristate_jjy01	(struct recvbuf *);
244static	int	jjy_receive_cdex_jst2000	(struct recvbuf *);
245static	int	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
246static  int	jjy_receive_citizentic_jjy200	(struct recvbuf *);
247static	int	jjy_receive_tristate_gpsclock01	(struct recvbuf *);
248
249static	void	printableString ( char*, int, char*, int ) ;
250
251/*
252 * Transfer vector
253 */
254struct	refclock refclock_jjy = {
255	jjy_start,	/* start up driver */
256	jjy_shutdown,	/* shutdown driver */
257	jjy_poll,	/* transmit poll message */
258	noentry,	/* not used */
259	noentry,	/* not used */
260	noentry,	/* not used */
261	NOFLAGS		/* not used */
262};
263
264/*
265 * Start up driver return code
266 */
267#define	RC_START_SUCCESS	1
268#define	RC_START_ERROR		0
269
270/*
271 * Local constants definition
272 */
273
274#define	MAX_LOGTEXT	64
275
276/*
277 * Tristate JJY01/JJY02 constants definition
278 */
279
280#define	TS_JJY01_COMMAND_NUMBER_DATE	1
281#define	TS_JJY01_COMMAND_NUMBER_TIME	2
282#define	TS_JJY01_COMMAND_NUMBER_STIM	3
283#define	TS_JJY01_COMMAND_NUMBER_STUS	4
284#define	TS_JJY01_COMMAND_NUMBER_DCST	5
285
286#define	TS_JJY01_REPLY_DATE		"yyyy/mm/dd www\r\n"
287#define	TS_JJY01_REPLY_STIM		"hh:mm:ss\r\n"
288#define	TS_JJY01_REPLY_STUS_YES		"adjusted\r\n"
289#define	TS_JJY01_REPLY_STUS_NO		"unadjusted\r\n"
290#define	TS_JJY01_REPLY_DCST_VALID	"valid\r\n"
291#define	TS_JJY01_REPLY_DCST_INVALID	"invalid\r\n"
292
293#define	TS_JJY01_REPLY_LENGTH_DATE	    14	/* Length without <CR><LF> */
294#define	TS_JJY01_REPLY_LENGTH_STIM	    8	/* Length without <CR><LF> */
295#define	TS_JJY01_REPLY_LENGTH_STUS_YES	    8	/* Length without <CR><LF> */
296#define	TS_JJY01_REPLY_LENGTH_STUS_NO	    10	/* Length without <CR><LF> */
297#define	TS_JJY01_REPLY_LENGTH_DCST_VALID    5	/* Length without <CR><LF> */
298#define	TS_JJY01_REPLY_LENGTH_DCST_INVALID  7	/* Length without <CR><LF> */
299
300static  struct
301{
302	const char	commandNumber ;
303	const char	*commandLog ;
304	const char	*command ;
305	int	commandLength ;
306} tristate_jjy01_command_sequence[] =
307{
308	/* dcst<CR><LF> -> VALID<CR><LF> or INVALID<CR><LF> */
309	{ TS_JJY01_COMMAND_NUMBER_DCST, "dcst", "dcst\r\n", 6 },
310	/* stus<CR><LF> -> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
311	{ TS_JJY01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
312	/* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
313	{ TS_JJY01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
314	/* stim<CR><LF> -> HH:MM:SS<CR><LF> */
315	{ TS_JJY01_COMMAND_NUMBER_STIM, "stim", "stim\r\n", 6 },
316	/* End of command */
317	{ 0, NULL, NULL, 0 }
318} ;
319
320/*
321 * Tristate TS-GPSCLOCK01 constants definition
322 */
323
324#define	TS_GPSCLOCK01_COMMAND_NUMBER_DATE	1
325#define	TS_GPSCLOCK01_COMMAND_NUMBER_TIME	2
326#define	TS_GPSCLOCK01_COMMAND_NUMBER_STUS	4
327
328#define	TS_GPSCLOCK01_REPLY_DATE		"yyyy/mm/dd\r\n"
329#define	TS_GPSCLOCK01_REPLY_TIME		"hh:mm:ss\r\n"
330#define	TS_GPSCLOCK01_REPLY_STUS_RTC		"*R\r\n"
331#define	TS_GPSCLOCK01_REPLY_STUS_GPS		"*G\r\n"
332#define	TS_GPSCLOCK01_REPLY_STUS_UTC		"*U\r\n"
333#define	TS_GPSCLOCK01_REPLY_STUS_PPS		"+U\r\n"
334
335#define	TS_GPSCLOCK01_REPLY_LENGTH_DATE	    10	/* Length without <CR><LF> */
336#define	TS_GPSCLOCK01_REPLY_LENGTH_TIME	    8	/* Length without <CR><LF> */
337#define	TS_GPSCLOCK01_REPLY_LENGTH_STUS	    2	/* Length without <CR><LF> */
338
339static  struct
340{
341	char	commandNumber ;
342	const char	*commandLog ;
343	const char	*command ;
344	int	commandLength ;
345} tristate_gpsclock01_command_sequence[] =
346{
347	/* stus<CR><LF> -> *R<CR><LF> or *G<CR><LF> or *U<CR><LF> or +U<CR><LF> */
348	{ TS_GPSCLOCK01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
349	/* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
350	{ TS_GPSCLOCK01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
351	/* time<CR><LF> -> HH:MM:SS<CR><LF> */
352	{ TS_GPSCLOCK01_COMMAND_NUMBER_TIME, "time", "time\r\n", 6 },
353	/* End of command */
354	{ 0, NULL, NULL, 0 }
355} ;
356
357/**************************************************************************************************/
358/*  jjy_start - open the devices and initialize data for processing                               */
359/**************************************************************************************************/
360static int
361jjy_start ( int unit, struct peer *peer )
362{
363
364	struct jjyunit	    *up ;
365	struct refclockproc *pp ;
366	int 	fd ;
367	char	*pDeviceName ;
368	short	iDiscipline ;
369	int 	iSpeed232 ;
370
371	char	sLogText [ MAX_LOGTEXT ] , sDevText [ MAX_LOGTEXT ] ;
372
373#ifdef DEBUG
374	if ( debug ) {
375		printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttl ) ;
376		printf ( DEVICE, unit ) ;
377		printf ( "\n" ) ;
378	}
379#endif
380	snprintf ( sDevText, sizeof(sDevText), DEVICE, unit ) ;
381	snprintf ( sLogText, sizeof(sLogText), "*Initialze*  %s  mode=%d", sDevText, peer->ttl ) ;
382	record_clock_stats ( &peer->srcadr, sLogText ) ;
383
384	/*
385	 * Open serial port
386	 */
387	pDeviceName = emalloc ( strlen(DEVICE) + 10 );
388	snprintf ( pDeviceName, strlen(DEVICE) + 10, DEVICE, unit ) ;
389
390	/*
391	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
392	 */
393	switch ( peer->ttl ) {
394	case 0 :
395	case 1 :
396		iDiscipline = LDISC_CLK ;
397		iSpeed232   = SPEED232_TRISTATE_JJY01 ;
398		break ;
399	case 2 :
400		iDiscipline = LDISC_RAW ;
401		iSpeed232   = SPEED232_CDEX_JST2000   ;
402		break ;
403	case 3 :
404		iDiscipline = LDISC_CLK ;
405		iSpeed232   = SPEED232_ECHOKEISOKUKI_LT2000 ;
406		break ;
407	case 4 :
408		iDiscipline = LDISC_CLK ;
409		iSpeed232   = SPEED232_CITIZENTIC_JJY200 ;
410		break ;
411	case 5 :
412		iDiscipline = LDISC_CLK ;
413		iSpeed232   = SPEED232_TRISTATE_GPSCLOCK01 ;
414		break ;
415	default :
416		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
417			  ntoa(&peer->srcadr), peer->ttl ) ;
418		free ( (void*) pDeviceName ) ;
419		return RC_START_ERROR ;
420	}
421
422	fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ;
423	if ( fd <= 0 ) {
424		free ( (void*) pDeviceName ) ;
425		return RC_START_ERROR ;
426	}
427	free ( (void*) pDeviceName ) ;
428
429	/*
430	 * Allocate and initialize unit structure
431	 */
432	up = emalloc (sizeof(*up));
433	memset ( up, 0, sizeof(*up) ) ;
434	up->linediscipline = iDiscipline ;
435
436	/*
437	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
438	 */
439	switch ( peer->ttl ) {
440	case 0 :
441		/*
442		 * The mode 0 is a default clock type at this time.
443		 * But this will be change to auto-detect mode in the future.
444		 */
445	case 1 :
446		up->unittype = UNITTYPE_TRISTATE_JJY01 ;
447		up->version  = 100 ;
448		/* 2010/11/20 */
449		/* Command sequence is defined by the struct tristate_jjy01_command_sequence, */
450		/* and the following 3 lines are not used in the mode LDISC_CLK. */
451		/* up->lineexpect = 2 ; */
452		/* up->charexpect[0] = 14 ; */ /* YYYY/MM/DD WWW<CR><LF> */
453		/* up->charexpect[1] =  8 ; */ /* HH:MM:SS<CR><LF> */
454		break ;
455	case 2 :
456		up->unittype = UNITTYPE_CDEX_JST2000 ;
457		up->lineexpect = 1 ;
458		up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
459		break ;
460	case 3 :
461		up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
462		up->operationmode = 2 ;  /* Mode 2 : Continuous mode */
463		up->lineexpect = 1 ;
464		switch ( up->operationmode ) {
465		case 1 :
466			up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
467			break ;
468		case 2 :
469			up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
470			break ;
471		}
472		break ;
473	case 4 :
474		up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
475		up->lineexpect = 1 ;
476		up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
477		break ;
478	case 5 :
479		up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
480		break ;
481
482	/* 2010/11/20 */
483	/* The "default:" section of this switch block is never executed,     */
484	/* because the former switch block traps the same "default:" case.    */
485	/* This "default:" section codes are removed to avoid spending time   */
486	/* in the future looking, though the codes are functionally harmless. */
487
488	}
489
490	pp = peer->procptr ;
491	pp->unitptr       = up ;
492	pp->io.clock_recv = jjy_receive ;
493	pp->io.srcclock   = peer ;
494	pp->io.datalen	  = 0 ;
495	pp->io.fd	  = fd ;
496	if ( ! io_addclock(&pp->io) ) {
497		close ( fd ) ;
498		pp->io.fd = -1 ;
499		free ( up ) ;
500		pp->unitptr = NULL ;
501		return RC_START_ERROR ;
502	}
503
504	/*
505	 * Initialize miscellaneous variables
506	 */
507	peer->precision = PRECISION ;
508	pp->clockdesc	= DESCRIPTION ;
509	memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
510
511	return RC_START_SUCCESS ;
512
513}
514
515
516/**************************************************************************************************/
517/*  jjy_shutdown - shutdown the clock                                                             */
518/**************************************************************************************************/
519static void
520jjy_shutdown ( int unit, struct peer *peer )
521{
522
523	struct jjyunit	    *up;
524	struct refclockproc *pp;
525
526	pp = peer->procptr ;
527	up = pp->unitptr ;
528	if ( -1 != pp->io.fd )
529		io_closeclock ( &pp->io ) ;
530	if ( NULL != up )
531		free ( up ) ;
532
533}
534
535
536/**************************************************************************************************/
537/*  jjy_receive - receive data from the serial interface                                          */
538/**************************************************************************************************/
539static void
540jjy_receive ( struct recvbuf *rbufp )
541{
542
543	struct jjyunit	    *up ;
544	struct refclockproc *pp ;
545	struct peer	    *peer;
546
547	l_fp	tRecvTimestamp;		/* arrival timestamp */
548	int 	rc ;
549	char	sLogText [ MAX_LOGTEXT ] ;
550	int 	i, bCntrlChar ;
551
552	/*
553	 * Initialize pointers and read the timecode and timestamp
554	 */
555	peer = rbufp->recv_peer ;
556	pp = peer->procptr ;
557	up = pp->unitptr ;
558
559	/*
560	 * Get next input line
561	 */
562	pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
563
564	if ( up->linediscipline == LDISC_RAW ) {
565		/*
566		 * The reply with <STX> and <ETX> may give a blank line
567		 */
568		if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
569		/*
570		 * Copy received charaters to temporary buffer
571		 */
572		for ( i = 0 ;
573		      i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ;
574		      i ++ , up->charcount ++ ) {
575			up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
576		}
577		while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
578			for ( i = 0 ; i < up->charcount - 1 ; i ++ )
579				up->rawbuf[i] = up->rawbuf[i+1] ;
580			up->charcount -- ;
581		}
582		bCntrlChar = 0 ;
583		for ( i = 0 ; i < up->charcount ; i ++ ) {
584			if ( up->rawbuf[i] < ' ' ) {
585				bCntrlChar = 1 ;
586				break ;
587			}
588		}
589		if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
590			if ( bCntrlChar == 0  &&
591			     up->charcount < up->charexpect[up->linecount] )
592				return ;
593		}
594		up->rawbuf[up->charcount] = 0 ;
595	} else {
596		/*
597		 * The reply with <CR><LF> gives a blank line
598		 */
599		if ( pp->lencode == 0 ) return ;
600	}
601	/*
602	 * We get down to business
603	 */
604
605#ifdef DEBUG
606	if ( debug ) {
607		if ( up->linediscipline == LDISC_RAW ) {
608			printableString( sLogText, MAX_LOGTEXT, up->rawbuf, up->charcount ) ;
609		} else {
610			printableString( sLogText, MAX_LOGTEXT, pp->a_lastcode, pp->lencode ) ;
611		}
612		printf ( "jjy_receive (refclock_jjy.c) : [%s]\n", sLogText ) ;
613	}
614#endif
615
616	pp->lastrec = tRecvTimestamp ;
617
618	up->linecount ++ ;
619
620	if ( up->lineerror != 0 ) return ;
621
622	switch ( up->unittype ) {
623
624	case UNITTYPE_TRISTATE_JJY01 :
625		rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
626		break ;
627
628	case UNITTYPE_CDEX_JST2000 :
629		rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
630		break ;
631
632	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
633		rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
634		break ;
635
636	case UNITTYPE_CITIZENTIC_JJY200 :
637		rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
638		break ;
639
640	case UNITTYPE_TRISTATE_GPSCLOCK01 :
641		rc = jjy_receive_tristate_gpsclock01  ( rbufp ) ;
642		break ;
643
644	default :
645		rc = 0 ;
646		break ;
647
648	}
649
650	if ( up->linediscipline == LDISC_RAW ) {
651		if ( up->linecount <= up->lineexpect  &&
652		     up->charcount > up->charexpect[up->linecount-1] ) {
653			for ( i = 0 ;
654			      i < up->charcount - up->charexpect[up->linecount-1] ;
655			      i ++ ) {
656				up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
657			}
658			up->charcount -= up->charexpect[up->linecount-1] ;
659		} else {
660			up->charcount = 0 ;
661		}
662	}
663
664	if ( rc == 0 ) {
665		return ;
666	}
667
668	up->bPollFlag = 0 ;
669
670	if ( up->lineerror != 0 ) {
671		refclock_report ( peer, CEVNT_BADREPLY ) ;
672		strlcpy  ( sLogText, "BAD REPLY [",
673			   sizeof( sLogText ) ) ;
674		if ( up->linediscipline == LDISC_RAW ) {
675			strlcat ( sLogText, up->rawbuf,
676				  sizeof( sLogText ) ) ;
677		} else {
678			strlcat ( sLogText, pp->a_lastcode,
679				  sizeof( sLogText ) ) ;
680		}
681		sLogText[MAX_LOGTEXT-1] = 0 ;
682		if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 )
683			strlcat ( sLogText, "]",
684				  sizeof( sLogText ) ) ;
685		record_clock_stats ( &peer->srcadr, sLogText ) ;
686		return ;
687	}
688
689	pp->year   = up->year ;
690	pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
691	pp->hour   = up->hour ;
692	pp->minute = up->minute ;
693	pp->second = up->second ;
694	pp->nsec   = up->msecond * 1000000;
695
696	/*
697	 * JST to UTC
698	 */
699	pp->hour -= 9 ;
700	if ( pp->hour < 0 ) {
701		pp->hour += 24 ;
702		pp->day -- ;
703		if ( pp->day < 1 ) {
704			pp->year -- ;
705			pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
706		}
707	}
708#ifdef DEBUG
709	if ( debug ) {
710		printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST   ",
711			  up->year, up->month, up->day, up->hour,
712			  up->minute, up->second, up->msecond/100 ) ;
713		printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
714			  pp->year, pp->day, pp->hour, pp->minute,
715			  pp->second, (int)(pp->nsec/100000000) ) ;
716	}
717#endif
718
719	/*
720	 * Process the new sample in the median filter and determine the
721	 * timecode timestamp.
722	 */
723
724	snprintf ( sLogText, sizeof(sLogText),
725		   "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
726		   up->year, up->month, up->day,
727		   up->hour, up->minute, up->second, up->msecond/100 ) ;
728	record_clock_stats ( &peer->srcadr, sLogText ) ;
729
730	if ( ! refclock_process ( pp ) ) {
731		refclock_report(peer, CEVNT_BADTIME);
732		return ;
733	}
734
735	pp->lastref = pp->lastrec;
736	refclock_receive(peer);
737
738}
739
740/**************************************************************************************************/
741
742static int
743jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
744{
745#ifdef DEBUG
746	static	const char	*sFunctionName = "jjy_receive_tristate_jjy01" ;
747#endif
748
749	struct jjyunit	    *up ;
750	struct refclockproc *pp ;
751	struct peer	    *peer;
752
753	char	*pBuf ;
754	int 	iLen ;
755	int 	rc ;
756
757	int 	bOverMidnight = 0 ;
758
759	char	sLogText [ MAX_LOGTEXT ], sReplyText  [ MAX_LOGTEXT ] ;
760
761	const char *pCmd ;
762	int 	iCmdLen ;
763
764	/*
765	 * Initialize pointers and read the timecode and timestamp
766	 */
767	peer = rbufp->recv_peer ;
768	pp = peer->procptr ;
769	up = pp->unitptr ;
770
771	if ( up->linediscipline == LDISC_RAW ) {
772		pBuf = up->rawbuf ;
773		iLen = up->charcount ;
774	} else {
775		pBuf = pp->a_lastcode ;
776		iLen = pp->lencode ;
777	}
778
779	switch ( tristate_jjy01_command_sequence[up->linecount-1].commandNumber ) {
780
781	case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
782
783		if ( iLen != TS_JJY01_REPLY_LENGTH_DATE ) {
784			up->lineerror = 1 ;
785			break ;
786		}
787
788		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year,
789			      &up->month, &up->day ) ;
790		if ( rc != 3 || up->year < 2000 || up->month < 1 ||
791		     up->month > 12 || up->day < 1 || up->day > 31 ) {
792			up->lineerror = 1 ;
793			break ;
794		}
795
796		/*** Start of modification on 2004/10/31 ***/
797		/*
798		 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
799		 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
800		 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
801		 * so this driver issues the second command "stim" after the reply of the first command "date".
802		 */
803
804		/*** 2010/11/20 ***/
805		/*
806		 * Codes of a next command issue are moved to the end of this function.
807		 */
808
809		/*** End of modification ***/
810
811		break ;
812
813	case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
814	case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
815
816		if ( iLen != TS_JJY01_REPLY_LENGTH_STIM ) {
817			up->lineerror = 1 ;
818			break ;
819		}
820
821		rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour,
822			      &up->minute, &up->second ) ;
823		if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
824		     up->second > 60 ) {
825			up->lineerror = 1 ;
826			break ;
827		}
828
829		up->msecond = 0 ;
830		if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
831			/*
832			 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver separately,
833			 * and the JJY receiver replies a date and time separately.
834			 * Just after midnight transitions, we ignore this time.
835			 */
836			bOverMidnight = 1 ;
837		}
838		break ;
839
840	case TS_JJY01_COMMAND_NUMBER_STUS :
841
842		if ( ( iLen == TS_JJY01_REPLY_LENGTH_STUS_YES
843		    && strncmp( pBuf, TS_JJY01_REPLY_STUS_YES,
844				TS_JJY01_REPLY_LENGTH_STUS_YES ) == 0 )
845		  || ( iLen == TS_JJY01_REPLY_LENGTH_STUS_NO
846		    && strncmp( pBuf, TS_JJY01_REPLY_STUS_NO,
847				TS_JJY01_REPLY_LENGTH_STUS_NO ) == 0 ) ) {
848			/* Good */
849		} else {
850			up->lineerror = 1 ;
851			break ;
852		}
853
854		break ;
855
856	case TS_JJY01_COMMAND_NUMBER_DCST :
857
858		if ( ( iLen == TS_JJY01_REPLY_LENGTH_DCST_VALID
859		    && strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
860				TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 )
861		  || ( iLen == TS_JJY01_REPLY_LENGTH_DCST_INVALID
862		    && strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
863				TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) ) {
864			/* Good */
865		} else {
866			up->lineerror = 1 ;
867			break ;
868		}
869
870		break ;
871
872	default : /*  Unexpected reply */
873
874		up->lineerror = 1 ;
875		break ;
876
877	}
878
879	/* Clockstats Log */
880
881	printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
882	snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
883		   up->linecount,
884		   tristate_jjy01_command_sequence[up->linecount-1].commandLog,
885		   ( up->lineerror == 0 )
886			? ( ( bOverMidnight == 0 )
887				? 'O'
888				: 'S' )
889			: 'X',
890		   sReplyText ) ;
891	record_clock_stats ( &peer->srcadr, sLogText ) ;
892
893	/* Check before issue next command */
894
895	if ( up->lineerror != 0 ) {
896		/* Do not issue next command */
897		return 0 ;
898	}
899
900	if ( bOverMidnight != 0 ) {
901		/* Do not issue next command */
902		return 0 ;
903	}
904
905	if ( tristate_jjy01_command_sequence[up->linecount].command == NULL ) {
906		/* Command sequence completed */
907		return 1 ;
908	}
909
910	/* Issue next command */
911
912#ifdef DEBUG
913	if ( debug ) {
914		printf ( "%s (refclock_jjy.c) : send '%s'\n",
915			sFunctionName, tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
916	}
917#endif
918
919	pCmd =  tristate_jjy01_command_sequence[up->linecount].command ;
920	iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
921	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
922		refclock_report ( peer, CEVNT_FAULT ) ;
923	}
924
925	return 0 ;
926
927}
928
929/**************************************************************************************************/
930
931static int
932jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
933{
934#ifdef DEBUG
935	static	const char	*sFunctionName = "jjy_receive_cdex_jst2000" ;
936#endif
937
938	struct jjyunit      *up ;
939	struct refclockproc *pp ;
940	struct peer         *peer;
941
942	char	*pBuf ;
943	int 	iLen ;
944	int 	rc ;
945
946	/*
947	 * Initialize pointers and read the timecode and timestamp
948	 */
949	peer = rbufp->recv_peer ;
950	pp = peer->procptr ;
951	up = pp->unitptr ;
952
953	if ( up->linediscipline == LDISC_RAW ) {
954		pBuf = up->rawbuf ;
955		iLen = up->charcount ;
956	} else {
957		pBuf = pp->a_lastcode ;
958		iLen = pp->lencode ;
959	}
960
961	switch ( up->linecount ) {
962
963	case 1 : /* JYYMMDD HHMMSSS */
964
965		if ( iLen != 15 ) {
966#ifdef DEBUG
967			if ( debug >= 2 ) {
968				printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
969					 sFunctionName, iLen ) ;
970			}
971#endif
972			up->lineerror = 1 ;
973			break ;
974		}
975		rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
976			      &up->year, &up->month, &up->day,
977			      &up->hour, &up->minute, &up->second,
978			      &up->msecond ) ;
979		if ( rc != 7 || up->month < 1 || up->month > 12 ||
980		     up->day < 1 || up->day > 31 || up->hour > 23 ||
981		     up->minute > 59 || up->second > 60 ) {
982#ifdef DEBUG
983			if ( debug >= 2 ) {
984				printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n",
985					 sFunctionName, rc, up->year,
986					 up->month, up->day, up->hour,
987					 up->minute, up->second,
988					 up->msecond ) ;
989			}
990#endif
991			up->lineerror = 1 ;
992			break ;
993		}
994		up->year    += 2000 ;
995		up->msecond *= 100 ;
996		break ;
997
998	default : /*  Unexpected reply */
999
1000		up->lineerror = 1 ;
1001		break ;
1002
1003	}
1004
1005	return 1 ;
1006
1007}
1008
1009/**************************************************************************************************/
1010
1011static int
1012jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1013{
1014#ifdef DEBUG
1015	static	const char	*sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
1016#endif
1017
1018	struct jjyunit      *up ;
1019	struct refclockproc *pp ;
1020	struct peer	    *peer;
1021
1022	char	*pBuf ;
1023	int 	iLen ;
1024	int 	rc ;
1025	int	i, ibcc, ibcc1, ibcc2 ;
1026
1027	/*
1028	 * Initialize pointers and read the timecode and timestamp
1029	 */
1030	peer = rbufp->recv_peer ;
1031	pp = peer->procptr ;
1032	up = pp->unitptr ;
1033
1034	if ( up->linediscipline == LDISC_RAW ) {
1035		pBuf = up->rawbuf ;
1036		iLen = up->charcount ;
1037	} else {
1038		pBuf = pp->a_lastcode ;
1039		iLen = pp->lencode ;
1040	}
1041
1042	switch ( up->linecount ) {
1043
1044	case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1045
1046		if ( ( up->operationmode == 1 && iLen != 15 ) ||
1047		     ( up->operationmode == 2 && iLen != 17 ) ) {
1048#ifdef DEBUG
1049			if ( debug >= 2 ) {
1050				printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
1051					 sFunctionName, iLen ) ;
1052			}
1053#endif
1054			if ( up->operationmode == 1 ) {
1055#ifdef DEBUG
1056				if ( debug ) {
1057					printf ( "%s (refclock_jjy.c) : send '#'\n", __func__ ) ;
1058				}
1059#endif
1060				if ( write ( pp->io.fd, "#",1 ) != 1  ) {
1061					refclock_report ( peer, CEVNT_FAULT ) ;
1062				}
1063			}
1064			up->lineerror = 1 ;
1065			break ;
1066		}
1067
1068		if ( up->operationmode == 1 ) {
1069
1070			for ( i = ibcc = 0 ; i < 13 ; i ++ )
1071				ibcc ^= pBuf[i] ;
1072			ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1073			ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
1074			if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1075#ifdef DEBUG
1076				if ( debug >= 2 ) {
1077					printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n",
1078						 sFunctionName,
1079						 pBuf[13] & 0xFF,
1080						 pBuf[14] & 0xFF,
1081						 ibcc1, ibcc2 ) ;
1082				}
1083#endif
1084				up->lineerror = 1 ;
1085				break ;
1086			}
1087
1088		}
1089
1090		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1091			      &up->year, &up->month, &up->day,
1092			      &up->hour, &up->minute, &up->second ) ;
1093		if ( rc != 6 || up->month < 1 || up->month > 12 ||
1094		     up->day < 1 || up->day > 31 || up->hour > 23 ||
1095		     up->minute > 59 || up->second > 60 ) {
1096#ifdef DEBUG
1097			if ( debug >= 2 ) {
1098				printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n",
1099					 sFunctionName, rc, up->year,
1100					 up->month, up->day, up->hour,
1101					 up->minute, up->second ) ;
1102			}
1103#endif
1104			up->lineerror = 1 ;
1105			break ;
1106		}
1107
1108		up->year += 2000 ;
1109
1110		if ( up->operationmode == 2 ) {
1111
1112			/* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
1113			up->msecond = 500 ;
1114			pp->second -- ;
1115			if ( pp->second < 0 ) {
1116				pp->second = 59 ;
1117				pp->minute -- ;
1118				if ( pp->minute < 0 ) {
1119					pp->minute = 59 ;
1120					pp->hour -- ;
1121					if ( pp->hour < 0 ) {
1122						pp->hour = 23 ;
1123						pp->day -- ;
1124						if ( pp->day < 1 ) {
1125							pp->year -- ;
1126							pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
1127						}
1128					}
1129				}
1130			}
1131
1132			/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1133#ifdef DEBUG
1134			if ( debug ) {
1135				printf ( "%s (refclock_jjy.c) : send '#'\n",
1136					 sFunctionName ) ;
1137			}
1138#endif
1139			if ( write ( pp->io.fd, "#",1 ) != 1  ) {
1140				refclock_report ( peer, CEVNT_FAULT ) ;
1141			}
1142
1143		}
1144
1145		break ;
1146
1147	default : /*  Unexpected reply */
1148
1149#ifdef DEBUG
1150		if ( debug ) {
1151			printf ( "%s (refclock_jjy.c) : send '#'\n",
1152				 sFunctionName ) ;
1153		}
1154#endif
1155		if ( write ( pp->io.fd, "#",1 ) != 1  ) {
1156			refclock_report ( peer, CEVNT_FAULT ) ;
1157		}
1158
1159		up->lineerror = 1 ;
1160		break ;
1161
1162	}
1163
1164	return 1 ;
1165
1166}
1167
1168/**************************************************************************************************/
1169
1170static int
1171jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1172{
1173#ifdef DEBUG
1174	static const char *sFunctionName = "jjy_receive_citizentic_jjy200" ;
1175#endif
1176
1177	struct jjyunit		*up ;
1178	struct refclockproc	*pp ;
1179	struct peer		*peer;
1180
1181	char	*pBuf ;
1182	int	iLen ;
1183	int	rc ;
1184	char	cApostrophe, sStatus[3] ;
1185	int	iWeekday ;
1186
1187	/*
1188	* Initialize pointers and read the timecode and timestamp
1189	*/
1190	peer = rbufp->recv_peer ;
1191	pp = peer->procptr ;
1192	up = pp->unitptr ;
1193
1194	if ( up->linediscipline == LDISC_RAW ) {
1195		pBuf = up->rawbuf ;
1196		iLen = up->charcount ;
1197	} else {
1198		pBuf = pp->a_lastcode ;
1199		iLen = pp->lencode ;
1200	}
1201
1202	/*
1203	* JJY-200 sends a timestamp every second.
1204	* So, a timestamp is ignored unless it is right after polled.
1205	*/
1206	if ( ! up->bPollFlag )
1207		return 0 ;
1208
1209	switch ( up->linecount ) {
1210
1211	case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
1212
1213		if ( iLen != 23 ) {
1214#ifdef DEBUG
1215			if ( debug >= 2 ) {
1216				printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
1217					 sFunctionName, iLen ) ;
1218			}
1219#endif
1220			up->lineerror = 1 ;
1221			break ;
1222		}
1223
1224		rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1225			      &cApostrophe, sStatus, &up->year,
1226			      &up->month, &up->day, &iWeekday,
1227			      &up->hour, &up->minute, &up->second ) ;
1228		sStatus[2] = 0 ;
1229		if ( rc != 9 || cApostrophe != '\'' ||
1230		     strcmp( sStatus, "OK" ) != 0 || up->month < 1 ||
1231		     up->month > 12 || up->day < 1 || up->day > 31 ||
1232		     iWeekday > 6 || up->hour > 23 || up->minute > 59 ||
1233		     up->second > 60 ) {
1234#ifdef DEBUG
1235			if ( debug >= 2 ) {
1236				printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n",
1237					 sFunctionName, rc, cApostrophe,
1238					 sStatus, up->year, up->month,
1239					 up->day, iWeekday, up->hour,
1240					 up->minute, up->second ) ;
1241			}
1242#endif
1243			up->lineerror = 1 ;
1244			break ;
1245		}
1246
1247		up->year += 2000 ;
1248		up->msecond = 0 ;
1249
1250		break ;
1251
1252	default : /* Unexpected reply */
1253
1254		up->lineerror = 1 ;
1255		break ;
1256
1257	}
1258
1259	return 1 ;
1260
1261}
1262
1263/**************************************************************************************************/
1264
1265static int
1266jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
1267{
1268#ifdef DEBUG
1269	static	const char	*sFunctionName = "jjy_receive_tristate_gpsclock01" ;
1270#endif
1271
1272	struct jjyunit	    *up ;
1273	struct refclockproc *pp ;
1274	struct peer	    *peer;
1275
1276	char	*pBuf ;
1277	int 	iLen ;
1278	int 	rc ;
1279
1280	int 	bOverMidnight = 0 ;
1281
1282	char	sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ;
1283
1284	const char	*pCmd ;
1285	int 	iCmdLen ;
1286
1287	/*
1288	 * Initialize pointers and read the timecode and timestamp
1289	 */
1290	peer = rbufp->recv_peer ;
1291	pp = peer->procptr ;
1292	up = pp->unitptr ;
1293
1294	if ( up->linediscipline == LDISC_RAW ) {
1295		pBuf = up->rawbuf ;
1296		iLen = up->charcount ;
1297	} else {
1298		pBuf = pp->a_lastcode ;
1299		iLen = pp->lencode ;
1300	}
1301
1302	/*
1303	 * Ignore NMEA data stream
1304	 */
1305	if ( iLen > 5
1306	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
1307#ifdef DEBUG
1308		if ( debug ) {
1309			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
1310				sFunctionName, pBuf ) ;
1311		}
1312#endif
1313		return 0 ;
1314	}
1315
1316	/*
1317	 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
1318	 */
1319	if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
1320		return 0 ;
1321	} else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
1322		pBuf += 5 ;
1323		iLen -= 5 ;
1324	}
1325
1326	/*
1327	 * Ignore NMEA data stream after command prompt
1328	 */
1329	if ( iLen > 5
1330	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
1331#ifdef DEBUG
1332		if ( debug ) {
1333			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
1334				sFunctionName, pBuf ) ;
1335		}
1336#endif
1337		return 0 ;
1338	}
1339
1340	switch ( tristate_gpsclock01_command_sequence[up->linecount-1].commandNumber ) {
1341
1342	case TS_GPSCLOCK01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
1343
1344		if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_DATE ) {
1345			up->lineerror = 1 ;
1346			break ;
1347		}
1348
1349		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
1350		if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 ||
1351		     up->day < 1 || up->day > 31 ) {
1352			up->lineerror = 1 ;
1353			break ;
1354		}
1355
1356		break ;
1357
1358	case TS_GPSCLOCK01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1359
1360		if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_TIME ) {
1361			up->lineerror = 1 ;
1362			break ;
1363		}
1364
1365		rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
1366		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1367			up->lineerror = 1 ;
1368			break ;
1369		}
1370
1371		up->msecond = 0 ;
1372
1373		if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
1374			/*
1375			 * The command "date" and "time" were sent to the JJY receiver separately,
1376			 * and the JJY receiver replies a date and time separately.
1377			 * Just after midnight transitions, we ignore this time.
1378			 */
1379			bOverMidnight = 1 ;
1380		}
1381
1382		break ;
1383
1384	case TS_GPSCLOCK01_COMMAND_NUMBER_STUS :
1385
1386		if ( iLen == TS_GPSCLOCK01_REPLY_LENGTH_STUS
1387		  && ( strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_RTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1388		    || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_GPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1389		    || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_UTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1390		    || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_PPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 ) ) {
1391			/* Good */
1392		} else {
1393			up->lineerror = 1 ;
1394			break ;
1395		}
1396
1397		break ;
1398
1399	default : /*  Unexpected reply */
1400
1401		up->lineerror = 1 ;
1402		break ;
1403
1404	}
1405
1406	/* Clockstats Log */
1407
1408	printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
1409	snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
1410		   up->linecount,
1411		   tristate_gpsclock01_command_sequence[up->linecount-1].commandLog,
1412		   ( up->lineerror == 0 )
1413			? ( ( bOverMidnight == 0 )
1414				? 'O'
1415				: 'S' )
1416			: 'X',
1417		   sReplyText ) ;
1418	record_clock_stats ( &peer->srcadr, sLogText ) ;
1419
1420	/* Check before issue next command */
1421
1422	if ( up->lineerror != 0 ) {
1423		/* Do not issue next command */
1424		return 0 ;
1425	}
1426
1427	if ( bOverMidnight != 0 ) {
1428		/* Do not issue next command */
1429		return 0 ;
1430	}
1431
1432	if ( tristate_gpsclock01_command_sequence[up->linecount].command == NULL ) {
1433		/* Command sequence completed */
1434		return 1 ;
1435	}
1436
1437	/* Issue next command */
1438
1439#ifdef DEBUG
1440	if ( debug ) {
1441		printf ( "%s (refclock_jjy.c) : send '%s'\n",
1442			sFunctionName, tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
1443	}
1444#endif
1445
1446	pCmd =  tristate_gpsclock01_command_sequence[up->linecount].command ;
1447	iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
1448	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1449		refclock_report ( peer, CEVNT_FAULT ) ;
1450	}
1451
1452	return 0 ;
1453
1454}
1455
1456/**************************************************************************************************/
1457/*  jjy_poll - called by the transmit procedure                                                   */
1458/**************************************************************************************************/
1459static void
1460jjy_poll ( int unit, struct peer *peer )
1461{
1462
1463	struct jjyunit      *up;
1464	struct refclockproc *pp;
1465
1466	pp = peer->procptr;
1467	up = pp->unitptr ;
1468
1469	if ( pp->polls > 0  &&  up->linecount == 0 ) {
1470		/*
1471		 * No reply for last command
1472		 */
1473		refclock_report ( peer, CEVNT_TIMEOUT ) ;
1474	}
1475
1476#ifdef DEBUG
1477	if ( debug ) {
1478		printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1479	}
1480#endif
1481
1482	pp->polls ++ ;
1483
1484	up->bPollFlag = 1 ;
1485	up->linecount = 0 ;
1486	up->lineerror = 0 ;
1487	up->charcount = 0 ;
1488
1489	switch ( up->unittype ) {
1490
1491	case UNITTYPE_TRISTATE_JJY01 :
1492		jjy_poll_tristate_jjy01  ( unit, peer ) ;
1493		break ;
1494
1495	case UNITTYPE_CDEX_JST2000 :
1496		jjy_poll_cdex_jst2000 ( unit, peer ) ;
1497		break ;
1498
1499	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1500		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1501		break ;
1502
1503	case UNITTYPE_CITIZENTIC_JJY200 :
1504		jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1505		break ;
1506
1507	case UNITTYPE_TRISTATE_GPSCLOCK01 :
1508		jjy_poll_tristate_gpsclock01  ( unit, peer ) ;
1509		break ;
1510
1511	default :
1512		break ;
1513
1514	}
1515
1516}
1517
1518/**************************************************************************************************/
1519
1520static void
1521jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1522{
1523#ifdef DEBUG
1524	static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1525#endif
1526
1527	struct jjyunit	    *up;
1528	struct refclockproc *pp;
1529
1530	const char *pCmd ;
1531	int 	iCmdLen ;
1532
1533	pp = peer->procptr;
1534	up = pp->unitptr ;
1535
1536	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1537		up->linecount = 2 ;
1538	}
1539
1540#ifdef DEBUG
1541	if ( debug ) {
1542		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
1543			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1544			up->linecount ) ;
1545	}
1546#endif
1547
1548	/*
1549	 * Send a first command
1550	 */
1551
1552#ifdef DEBUG
1553	if ( debug ) {
1554		printf ( "%s (refclock_jjy.c) : send '%s'\n",
1555			 sFunctionName,
1556			 tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
1557	}
1558#endif
1559
1560	pCmd =  tristate_jjy01_command_sequence[up->linecount].command ;
1561	iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
1562	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1563		refclock_report ( peer, CEVNT_FAULT ) ;
1564	}
1565
1566}
1567
1568/**************************************************************************************************/
1569
1570static void
1571jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1572{
1573
1574	struct refclockproc *pp;
1575
1576	pp = peer->procptr;
1577
1578	/*
1579	 * Send "<ENQ>1J<ETX>" command
1580	 */
1581
1582#ifdef DEBUG
1583	if ( debug ) {
1584		printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1585	}
1586#endif
1587
1588	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1589		refclock_report ( peer, CEVNT_FAULT ) ;
1590	}
1591
1592}
1593
1594/**************************************************************************************************/
1595
1596static void
1597jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1598{
1599
1600	struct jjyunit      *up;
1601	struct refclockproc *pp;
1602
1603	char	sCmd[2] ;
1604
1605	pp = peer->procptr;
1606	up = pp->unitptr ;
1607
1608	/*
1609	 * Send "T" or "C" command
1610	 */
1611
1612	switch ( up->operationmode ) {
1613	case 1 : sCmd[0] = 'T' ; break ;
1614	case 2 : sCmd[0] = 'C' ; break ;
1615	}
1616	sCmd[1] = 0 ;
1617
1618#ifdef DEBUG
1619	if ( debug ) {
1620		printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1621	}
1622#endif
1623
1624	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1625		refclock_report ( peer, CEVNT_FAULT ) ;
1626	}
1627
1628}
1629
1630/**************************************************************************************************/
1631
1632static void
1633jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1634{
1635
1636	/* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1637
1638}
1639
1640/**************************************************************************************************/
1641
1642static void
1643jjy_poll_tristate_gpsclock01  ( int unit, struct peer *peer )
1644{
1645#ifdef DEBUG
1646	static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
1647#endif
1648
1649	struct jjyunit	    *up;
1650	struct refclockproc *pp;
1651
1652	const char	*pCmd ;
1653	int 	iCmdLen ;
1654
1655	pp = peer->procptr;
1656	up = pp->unitptr ;
1657
1658	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1659		up->linecount = 1 ;
1660	}
1661
1662#ifdef DEBUG
1663	if ( debug ) {
1664		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
1665			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1666			up->linecount ) ;
1667	}
1668#endif
1669
1670	/*
1671	 * Send a first command
1672	 */
1673
1674#ifdef DEBUG
1675	if ( debug ) {
1676		printf ( "%s (refclock_jjy.c) : send '%s'\n",
1677			 sFunctionName,
1678			 tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
1679	}
1680#endif
1681
1682	pCmd =  tristate_gpsclock01_command_sequence[up->linecount].command ;
1683	iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
1684	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1685		refclock_report ( peer, CEVNT_FAULT ) ;
1686	}
1687
1688}
1689
1690/**************************************************************************************************/
1691
1692static void
1693printableString ( char *sOutput, int iOutputLen, char *sInput, int iInputLen )
1694{
1695	const char	*printableControlChar[] = {
1696			"<NUL>", "<SOH>", "<STX>", "<ETX>",
1697			"<EOT>", "<ENQ>", "<ACK>", "<BEL>",
1698			"<BS>" , "<HT>" , "<LF>" , "<VT>" ,
1699			"<FF>" , "<CR>" , "<SO>" , "<SI>" ,
1700			"<DLE>", "<DC1>", "<DC2>", "<DC3>",
1701			"<DC4>", "<NAK>", "<SYN>", "<ETB>",
1702			"<CAN>", "<EM>" , "<SUB>", "<ESC>",
1703			"<FS>" , "<GS>" , "<RS>" , "<US>" ,
1704			" " } ;
1705
1706	size_t	i, j, n ;
1707	size_t	InputLen;
1708	size_t	OutputLen;
1709
1710	InputLen = (size_t)iInputLen;
1711	OutputLen = (size_t)iOutputLen;
1712	for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
1713		if ( isprint( (unsigned char)sInput[i] ) ) {
1714			n = 1 ;
1715			if ( j + 1 >= OutputLen )
1716				break ;
1717			sOutput[j] = sInput[i] ;
1718		} else if ( ( sInput[i] & 0xFF ) <
1719			    COUNTOF(printableControlChar) ) {
1720			n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
1721			if ( j + n + 1 >= OutputLen )
1722				break ;
1723			strlcpy( sOutput + j,
1724				 printableControlChar[sInput[i] & 0xFF],
1725				 OutputLen - j ) ;
1726		} else {
1727			n = 5 ;
1728			if ( j + n + 1 >= OutputLen )
1729				break ;
1730			snprintf( sOutput + j, OutputLen - j, "<x%X>",
1731				  sInput[i] & 0xFF ) ;
1732		}
1733		j += n ;
1734	}
1735
1736	sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
1737
1738}
1739
1740/**************************************************************************************************/
1741
1742#else
1743int refclock_jjy_bs ;
1744#endif /* REFCLOCK */
1745