xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_jjy.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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  */
204 struct 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 
232 static	int 	jjy_start			(int, struct peer *);
233 static	void	jjy_shutdown			(int, struct peer *);
234 
235 static	void	jjy_poll		    	(int, struct peer *);
236 static	void	jjy_poll_tristate_jjy01	    	(int, struct peer *);
237 static	void	jjy_poll_cdex_jst2000	    	(int, struct peer *);
238 static	void	jjy_poll_echokeisokuki_lt2000	(int, struct peer *);
239 static	void	jjy_poll_citizentic_jjy200	(int, struct peer *);
240 static	void	jjy_poll_tristate_gpsclock01	(int, struct peer *);
241 
242 static	void	jjy_receive			(struct recvbuf *);
243 static	int	jjy_receive_tristate_jjy01	(struct recvbuf *);
244 static	int	jjy_receive_cdex_jst2000	(struct recvbuf *);
245 static	int	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
246 static  int	jjy_receive_citizentic_jjy200	(struct recvbuf *);
247 static	int	jjy_receive_tristate_gpsclock01	(struct recvbuf *);
248 
249 static	void	printableString ( char*, int, char*, int ) ;
250 
251 /*
252  * Transfer vector
253  */
254 struct	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 
300 static  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 
339 static  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 /**************************************************************************************************/
360 static int
361 jjy_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 /**************************************************************************************************/
519 static void
520 jjy_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 /**************************************************************************************************/
539 static void
540 jjy_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 
742 static int
743 jjy_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 
931 static int
932 jjy_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 
1011 static int
1012 jjy_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 
1170 static int
1171 jjy_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 
1265 static int
1266 jjy_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 /**************************************************************************************************/
1459 static void
1460 jjy_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 
1520 static void
1521 jjy_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 
1570 static void
1571 jjy_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 
1596 static void
1597 jjy_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 
1632 static void
1633 jjy_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 
1642 static void
1643 jjy_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 
1692 static void
1693 printableString ( 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
1743 int refclock_jjy_bs ;
1744 #endif /* REFCLOCK */
1745