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