xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_jjy.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /*	$NetBSD: refclock_jjy.c,v 1.16 2022/10/09 21:41:03 christos Exp $	*/
2 
3 /*
4  * refclock_jjy - clock driver for JJY receivers
5  */
6 
7 /**********************************************************************/
8 /*								      */
9 /*  Copyright (C) 2001-2020, 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 /*  2015/03/29							      */
101 /*    [Add]    Support the Telephone JJY			      */
102 /*    [Change] Split the start up routine into each JJY receivers.    */
103 /*             Change raw data internal bufferring process            */
104 /*             Change over midnight handling of TS-JJY01 and TS-GPS01 */
105 /*             to put DATE command between before and after TIME's.   */
106 /*             Unify the writing clockstats of all JJY receivers.     */
107 /*								      */
108 /*  2015/05/15							      */
109 /*    [Add]    Support the SEIKO TIME SYSTEMS TDC-300		      */
110 /*								      */
111 /*  2016/05/08							      */
112 /*    [Fix]    C-DEX JST2000                                          */
113 /*             Thanks to Mr. Kuramatsu for the report and the patch.  */
114 /*								      */
115 /*  2017/04/30							      */
116 /*    [Change] Avoid a wrong report of the coverity static analysis   */
117 /*             tool. ( The code is harmless and has no bug. )	      */
118 /*             teljjy_conn_send()				      */
119 /*								      */
120 /*  2020/01/19							      */
121 /*    [Change] Handling TS-JJY01/02 status of the the STUS reply.     */
122 /*             Time synchronization can be skipped by the settings of */
123 /*             the flag2 when the status of the reply is UNADJUSTED.  */
124 /*    [Change] Quiet compilation for the GCC 9.2.0.                   */
125 /*    [Fix]    Correct typos in comment lines                         */
126 /*								      */
127 /**********************************************************************/
128 
129 #ifdef HAVE_CONFIG_H
130 #include <config.h>
131 #endif
132 
133 #if defined(REFCLOCK) && defined(CLOCK_JJY)
134 
135 #include <stdio.h>
136 #include <ctype.h>
137 #include <string.h>
138 #include <sys/time.h>
139 #include <time.h>
140 
141 #include "ntpd.h"
142 #include "ntp_io.h"
143 #include "ntp_tty.h"
144 #include "ntp_refclock.h"
145 #include "ntp_calendar.h"
146 #include "ntp_stdlib.h"
147 
148 /**********************************************************************/
149 
150 /*
151  * Interface definitions
152  */
153 #define	DEVICE  	"/dev/jjy%d"	/* device name and unit */
154 #define	SPEED232_TRISTATE_JJY01		B9600   /* UART speed (9600 baud) */
155 #define	SPEED232_CDEX_JST2000		B9600   /* UART speed (9600 baud) */
156 #define	SPEED232_ECHOKEISOKUKI_LT2000	B9600   /* UART speed (9600 baud) */
157 #define	SPEED232_CITIZENTIC_JJY200	B4800   /* UART speed (4800 baud) */
158 #define	SPEED232_TRISTATE_GPSCLOCK01	B38400  /* USB  speed (38400 baud) */
159 #define	SPEED232_SEIKO_TIMESYS_TDC_300	B2400   /* UART speed (2400 baud) */
160 #define	SPEED232_TELEPHONE		B2400   /* UART speed (4800 baud) */
161 #define	REFID   	"JJY"		/* reference ID */
162 #define	DESCRIPTION	"JJY Receiver"
163 #define	PRECISION	(-3)		/* precision assumed (about 100 ms) */
164 
165 /*
166  * JJY unit control structure
167  */
168 
169 struct jjyRawDataBreak {
170 	const char *	pString ;
171 	int 		iLength ;
172 } ;
173 
174 #define	MAX_TIMESTAMP	6
175 #define	MAX_RAWBUF   	100
176 #define	MAX_LOOPBACK	5
177 
178 struct jjyunit {
179 /* Set up by the function "jjy_start_xxxxxxxx" */
180 	char	unittype ;	    /* UNITTYPE_XXXXXXXXXX */
181 	short   operationmode ;	    /* Echo Keisokuki LT-2000 */
182 	int 	linespeed ;         /* SPEED232_XXXXXXXXXX */
183 	short	linediscipline ;    /* LDISC_CLK or LDISC_RAW */
184 /* Receiving data */
185 	char	bInitError ;        /* Set by jjy_start if any error during initialization */
186 	short	iProcessState ;     /* JJY_PROCESS_STATE_XXXXXX */
187 	char	bReceiveFlag ;      /* Set and reset by jjy_receive */
188 	char	bLineError ;	    /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/
189 	short	iCommandSeq ;       /* 0:Idle  Non-Zero:Issued */
190 	short	iReceiveSeq ;
191 	int 	iLineCount ;
192 	int 	year, month, day, hour, minute, second, msecond ;
193 	int 	leapsecond ;
194 	int 	iTimestampCount ;   /* TS-JJY01, TS-GPS01, Telephone-JJY */
195 	int 	iTimestamp [ MAX_TIMESTAMP ] ;  /* Serial second ( 0 - 86399 ) */
196 /* LDISC_RAW only */
197 	char	sRawBuf [ MAX_RAWBUF ] ;
198 	int 	iRawBufLen ;
199 	struct	jjyRawDataBreak *pRawBreak ;
200 	char	bWaitBreakString ;
201 	char	sLineBuf [ MAX_RAWBUF ] ;
202 	int 	iLineBufLen ;
203 	char	sTextBuf [ MAX_RAWBUF ] ;
204 	int 	iTextBufLen ;
205 	char	bSkipCntrlCharOnly ;
206 /* TS-JJY01, TS-JJY02 */
207 	time_t	tLastAdjustedTimestamp ;
208 	char	bStusReplyAdjusted ;
209 	char	bStusReplyAdjustedAtLeastOnce ;
210 /* Telephone JJY auto measurement of the loopback delay */
211 	char	bLoopbackMode ;
212 	short	iLoopbackCount ;
213 	struct	timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ;
214 	char	bLoopbackTimeout[MAX_LOOPBACK] ;
215 	short	iLoopbackValidCount ;
216 /* Telephone JJY timer */
217 	short	iTeljjySilentTimer ;
218 	short	iTeljjyStateTimer ;
219 /* Telephone JJY control finite state machine */
220 	short	iClockState ;
221 	short	iClockEvent ;
222 	short	iClockCommandSeq ;
223 /* Modem timer */
224 	short	iModemSilentCount ;
225 	short	iModemSilentTimer ;
226 	short	iModemStateTimer ;
227 /* Modem control finite state machine */
228 	short	iModemState ;
229 	short	iModemEvent ;
230 	short	iModemCommandSeq ;
231 };
232 
233 #define	UNITTYPE_TRISTATE_JJY01		1
234 #define	UNITTYPE_CDEX_JST2000		2
235 #define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
236 #define	UNITTYPE_CITIZENTIC_JJY200  	4
237 #define	UNITTYPE_TRISTATE_GPSCLOCK01	5
238 #define	UNITTYPE_SEIKO_TIMESYS_TDC_300	6
239 #define	UNITTYPE_TELEPHONE		100
240 
241 #define	JJY_PROCESS_STATE_IDLE   	0
242 #define	JJY_PROCESS_STATE_POLL   	1
243 #define	JJY_PROCESS_STATE_RECEIVE	2
244 #define	JJY_PROCESS_STATE_DONE   	3
245 #define	JJY_PROCESS_STATE_ERROR  	4
246 
247 /**********************************************************************/
248 
249 /*
250  *  Function calling structure
251  *
252  *  jjy_start
253  *   |--  jjy_start_tristate_jjy01
254  *   |--  jjy_start_cdex_jst2000
255  *   |--  jjy_start_echokeisokuki_lt2000
256  *   |--  jjy_start_citizentic_jjy200
257  *   |--  jjy_start_tristate_gpsclock01
258  *   |--  jjy_start_seiko_tsys_tdc_300
259  *   |--  jjy_start_telephone
260  *
261  *  jjy_shutdown
262  *
263  *  jjy_poll
264  *   |--  jjy_poll_tristate_jjy01
265  *   |--  jjy_poll_cdex_jst2000
266  *   |--  jjy_poll_echokeisokuki_lt2000
267  *   |--  jjy_poll_citizentic_jjy200
268  *   |--  jjy_poll_tristate_gpsclock01
269  *   |--  jjy_poll_seiko_tsys_tdc_300
270  *   |--  jjy_poll_telephone
271  *         |--  teljjy_control
272  *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
273  *                     |--  modem_connect
274  *                           |--  modem_control
275  *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
276  *
277  *  jjy_receive
278  *   |
279  *   |--  jjy_receive_tristate_jjy01
280  *   |     |--  jjy_synctime
281  *   |--  jjy_receive_cdex_jst2000
282  *   |     |--  jjy_synctime
283  *   |--  jjy_receive_echokeisokuki_lt2000
284  *   |     |--  jjy_synctime
285  *   |--  jjy_receive_citizentic_jjy200
286  *   |     |--  jjy_synctime
287  *   |--  jjy_receive_tristate_gpsclock01
288  *   |     |--  jjy_synctime
289  *   |--  jjy_receive_seiko_tsys_tdc_300
290  *   |     |--  jjy_synctime
291  *   |--  jjy_receive_telephone
292  *         |--  modem_receive
293  *         |     |--  modem_control
294  *         |           |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
295  *         |--  teljjy_control
296  *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
297  *                     |--  jjy_synctime
298  *                     |--  modem_disconnect
299  *                           |--  modem_control
300  *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
301  *
302  *  jjy_timer
303  *   |--  jjy_timer_telephone
304  *         |--  modem_timer
305  *         |     |--  modem_control
306  *         |           |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
307  *         |--  teljjy_control
308  *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
309  *                     |--  modem_disconnect
310  *                           |--  modem_control
311  *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
312  *
313  * Function prototypes
314  */
315 
316 static	int 	jjy_start			(int, struct peer *);
317 static	int 	jjy_start_tristate_jjy01	(int, struct peer *, struct jjyunit *);
318 static	int 	jjy_start_cdex_jst2000		(int, struct peer *, struct jjyunit *);
319 static	int 	jjy_start_echokeisokuki_lt2000	(int, struct peer *, struct jjyunit *);
320 static	int 	jjy_start_citizentic_jjy200	(int, struct peer *, struct jjyunit *);
321 static	int 	jjy_start_tristate_gpsclock01	(int, struct peer *, struct jjyunit *);
322 static	int 	jjy_start_seiko_tsys_tdc_300	(int, struct peer *, struct jjyunit *);
323 static	int 	jjy_start_telephone		(int, struct peer *, struct jjyunit *);
324 
325 static	void	jjy_shutdown			(int, struct peer *);
326 
327 static	void	jjy_poll		    	(int, struct peer *);
328 static	void	jjy_poll_tristate_jjy01	    	(int, struct peer *);
329 static	void	jjy_poll_cdex_jst2000	    	(int, struct peer *);
330 static	void	jjy_poll_echokeisokuki_lt2000	(int, struct peer *);
331 static	void	jjy_poll_citizentic_jjy200	(int, struct peer *);
332 static	void	jjy_poll_tristate_gpsclock01	(int, struct peer *);
333 static	void	jjy_poll_seiko_tsys_tdc_300	(int, struct peer *);
334 static	void	jjy_poll_telephone		(int, struct peer *);
335 
336 static	void	jjy_receive			(struct recvbuf *);
337 static	int 	jjy_receive_tristate_jjy01	(struct recvbuf *);
338 static	int 	jjy_receive_cdex_jst2000	(struct recvbuf *);
339 static	int 	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
340 static  int 	jjy_receive_citizentic_jjy200	(struct recvbuf *);
341 static	int 	jjy_receive_tristate_gpsclock01	(struct recvbuf *);
342 static	int 	jjy_receive_seiko_tsys_tdc_300	(struct recvbuf *);
343 static	int 	jjy_receive_telephone		(struct recvbuf *);
344 
345 static	void	jjy_timer			(int, struct peer *);
346 static	void	jjy_timer_telephone		(int, struct peer *);
347 
348 static	void	jjy_synctime			( struct peer *, struct refclockproc *, struct jjyunit * ) ;
349 static	void	jjy_write_clockstats		( struct peer *, int, const char* ) ;
350 
351 static	int 	getRawDataBreakPosition		( struct jjyunit *, int ) ;
352 
353 static	short	getModemState			( struct jjyunit * ) ;
354 static	int 	isModemStateConnect		( short ) ;
355 static	int 	isModemStateDisconnect		( short ) ;
356 static	int 	isModemStateTimerOn		( struct jjyunit * ) ;
357 static	void	modem_connect			( int, struct peer * ) ;
358 static	void	modem_disconnect		( int, struct peer * ) ;
359 static	int 	modem_receive			( struct recvbuf * ) ;
360 static	void	modem_timer			( int, struct peer * );
361 
362 static	void	printableString ( char*, int, const char*, int ) ;
363 
364 /*
365  * Transfer vector
366  */
367 struct	refclock refclock_jjy = {
368 	jjy_start,	/* start up driver */
369 	jjy_shutdown,	/* shutdown driver */
370 	jjy_poll,	/* transmit poll message */
371 	noentry,	/* not used */
372 	noentry,	/* not used */
373 	noentry,	/* not used */
374 	jjy_timer	/* 1 second interval timer */
375 };
376 
377 /*
378  * Start up driver return code
379  */
380 #define	RC_START_SUCCESS	1
381 #define	RC_START_ERROR		0
382 
383 /*
384  * Local constants definition
385  */
386 
387 #define	MAX_LOGTEXT	200
388 
389 #ifndef	TRUE
390 #define	TRUE	(0==0)
391 #endif
392 #ifndef	FALSE
393 #define	FALSE	(!TRUE)
394 #endif
395 
396 /* Local constants definition for the return code of the jjy_receive_xxxxxxxx */
397 
398 #define	JJY_RECEIVE_DONE	0
399 #define	JJY_RECEIVE_SKIP	1
400 #define	JJY_RECEIVE_UNPROCESS	2
401 #define	JJY_RECEIVE_WAIT	3
402 #define	JJY_RECEIVE_ERROR	4
403 
404 /* Local constants definition for the 2nd parameter of the jjy_write_clockstats */
405 
406 #define	JJY_CLOCKSTATS_MARK_NONE	0
407 #define	JJY_CLOCKSTATS_MARK_JJY 	1
408 #define	JJY_CLOCKSTATS_MARK_SEND	2
409 #define	JJY_CLOCKSTATS_MARK_RECEIVE	3
410 #define	JJY_CLOCKSTATS_MARK_INFORMATION	4
411 #define	JJY_CLOCKSTATS_MARK_ATTENTION	5
412 #define	JJY_CLOCKSTATS_MARK_WARNING	6
413 #define	JJY_CLOCKSTATS_MARK_ERROR	7
414 #define	JJY_CLOCKSTATS_MARK_BUG 	8
415 
416 /* Local constants definition for the clockstats messages */
417 
418 #define	JJY_CLOCKSTATS_MESSAGE_ECHOBACK         	"* Echoback"
419 #define	JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY     	"* Ignore replay : [%s]"
420 #define	JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2  	"* Over midnight : timestamp=%d, %d"
421 #define	JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3  	"* Over midnight : timestamp=%d, %d, %d"
422 #define	JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE 	"* Unsure timestamp : %s"
423 #define	JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY   	"* Loopback delay : %d.%03d mSec."
424 #define	JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST     	"* Delay adjustment : %d mSec. ( valid=%hd/%d )"
425 #define	JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST   	"* Delay adjustment : None ( valid=%hd/%d )"
426 #define	JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED  	"* Skip time synchronization : STUS is 'UNADJUSTED' for %.0lf %s"
427 
428 #define	JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY     	"# Unexpected reply : [%s]"
429 #define	JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH     	"# Invalid length : length=%d"
430 #define	JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY     	"# Too many reply : count=%d"
431 #define	JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY      	"# Invalid reply : [%s]"
432 #define	JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2       	"# Slow reply : timestamp=%d, %d"
433 #define	JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3       	"# Slow reply : timestamp=%d, %d, %d"
434 #define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE	"# Invalid date : rc=%d year=%d month=%d day=%d"
435 #define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME	"# Invalid time : rc=%d hour=%d minute=%d second=%d"
436 #define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME	"# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d"
437 #define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP	"# Invalid leap : leapsecond=[%s]"
438 #define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS	"# Invalid status : status=[%s]"
439 
440 /* Debug print macro */
441 
442 #ifdef	DEBUG
443 #define	DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)	{ if ( debug ) { printf ( "refclock_jjy.c : %s : iProcessState=%d bLineError=%d iCommandSeq=%d iLineCount=%d iTimestampCount=%d iLen=%d\n", sFunc, up->iProcessState, up->bLineError, up->iCommandSeq, up->iLineCount, up->iTimestampCount, iLen ) ; } }
444 #else
445 #define	DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)
446 #endif
447 
448 /**************************************************************************************************/
449 /*  jjy_start - open the devices and initialize data for processing                               */
450 /**************************************************************************************************/
451 static int
452 jjy_start ( int unit, struct peer *peer )
453 {
454 
455 	struct	refclockproc *pp ;
456 	struct	jjyunit      *up ;
457 	int 	rc ;
458 	int 	fd ;
459 	char	sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ;
460 
461 #ifdef DEBUG
462 	if ( debug ) {
463 		printf( "refclock_jjy.c : jjy_start : %s  mode=%d  dev=%s  unit=%d\n",
464 			 ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ;
465 	}
466 #endif
467 
468 	/* Allocate memory for the unit structure */
469 	up = emalloc( sizeof(*up) ) ;
470 	if ( up == NULL ) {
471 		msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ;
472 		return RC_START_ERROR ;
473 	}
474 	memset ( up, 0, sizeof(*up) ) ;
475 
476 	up->bInitError = FALSE ;
477 	up->iProcessState = JJY_PROCESS_STATE_IDLE ;
478 	up->bReceiveFlag = FALSE ;
479 	up->iCommandSeq = 0 ;
480 	up->iLineCount = 0 ;
481 	up->iTimestampCount = 0 ;
482 	up->bWaitBreakString = FALSE ;
483 	up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ;
484 	up->bSkipCntrlCharOnly = TRUE ;
485 
486 	/* Set up the device name */
487 	snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ;
488 
489 	snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ;
490 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
491 
492 	/*
493 	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
494 	 */
495 	switch ( peer->ttl ) {
496 	case 0 :
497 	case 1 :
498 		rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ;
499 		break ;
500 	case 2 :
501 		rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ;
502 		break ;
503 	case 3 :
504 		rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ;
505 		break ;
506 	case 4 :
507 		rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ;
508 		break ;
509 	case 5 :
510 		rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ;
511 		break ;
512 	case 6 :
513 		rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ;
514 		break ;
515 	case 100 :
516 		rc = jjy_start_telephone ( unit, peer, up ) ;
517 		break ;
518 	default :
519 		if ( 101 <= peer->ttl && peer->ttl <= 180 ) {
520 			rc = jjy_start_telephone ( unit, peer, up ) ;
521 		} else {
522 			msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
523 				  ntoa(&peer->srcadr), peer->ttl ) ;
524 			free ( (void*) up ) ;
525 		return RC_START_ERROR ;
526 		}
527 	}
528 
529 	if ( rc != 0 ) {
530 		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error",
531 			  ntoa(&peer->srcadr), peer->ttl ) ;
532 		free ( (void*) up ) ;
533 		return RC_START_ERROR ;
534 	}
535 
536 	/* Open the device */
537 	fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ;
538 	if ( fd <= 0 ) {
539 		free ( (void*) up ) ;
540 		return RC_START_ERROR ;
541 	}
542 
543 	/*
544 	 * Initialize variables
545 	 */
546 	pp = peer->procptr ;
547 
548 	pp->clockdesc	= DESCRIPTION ;
549 	pp->unitptr       = up ;
550 	pp->io.clock_recv = jjy_receive ;
551 	pp->io.srcclock   = peer ;
552 	pp->io.datalen	  = 0 ;
553 	pp->io.fd	  = fd ;
554 	if ( ! io_addclock(&pp->io) ) {
555 		close ( fd ) ;
556 		pp->io.fd = -1 ;
557 		free ( up ) ;
558 		pp->unitptr = NULL ;
559 		return RC_START_ERROR ;
560 	}
561 	memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ;
562 
563 	peer->precision = PRECISION ;
564 
565 	snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ;
566 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
567 
568 	return RC_START_SUCCESS ;
569 
570 }
571 
572 /**************************************************************************************************/
573 /*  jjy_shutdown - shutdown the clock                                                             */
574 /**************************************************************************************************/
575 static void
576 jjy_shutdown ( int unit, struct peer *peer )
577 {
578 
579 	struct jjyunit	    *up;
580 	struct refclockproc *pp;
581 
582 	char	sLog [ 60 ] ;
583 
584 	pp = peer->procptr ;
585 	up = pp->unitptr ;
586 	if ( -1 != pp->io.fd ) {
587 		io_closeclock ( &pp->io ) ;
588 	}
589 	if ( NULL != up ) {
590 		free ( up ) ;
591 	}
592 
593 	snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ;
594 	record_clock_stats( &peer->srcadr, sLog ) ;
595 
596 }
597 
598 /**************************************************************************************************/
599 /*  jjy_receive - receive data from the serial interface                                          */
600 /**************************************************************************************************/
601 static void
602 jjy_receive ( struct recvbuf *rbufp )
603 {
604 #ifdef DEBUG
605 	static const char *sFunctionName = "jjy_receive" ;
606 #endif
607 
608 	struct jjyunit	    *up ;
609 	struct refclockproc *pp ;
610 	struct peer	    *peer;
611 
612 	l_fp	tRecvTimestamp;		/* arrival timestamp */
613 	int 	rc ;
614 	char	*pBuf, sLogText [ MAX_LOGTEXT ] ;
615 	size_t 	iLen, iCopyLen ;
616 	int 	i, j, iReadRawBuf, iBreakPosition ;
617 
618 	/*
619 	 * Initialize pointers and read the timecode and timestamp
620 	 */
621 	peer = rbufp->recv_peer ;
622 	pp = peer->procptr ;
623 	up = pp->unitptr ;
624 
625 	/*
626 	 * Get next input line
627 	 */
628 	if ( up->linediscipline == LDISC_RAW ) {
629 
630 		pp->lencode  = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ;
631 		/* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions  (OVERRUN)" */
632 		/* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */
633 		/* To avoid its claim, pass the value BMAX-1. */
634 
635 		/*
636 		 * Append received characters to temporary buffer
637 		 */
638 		for ( i = 0 ;
639 		      i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ;
640 		      i ++ , up->iRawBufLen ++ ) {
641 			up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ;
642 		}
643 		up->sRawBuf[up->iRawBufLen] = 0 ;
644 
645 
646 	} else {
647 
648 		pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
649 
650 	}
651 #ifdef DEBUG
652 	printf( "\nrefclock_jjy.c : %s : Len=%d  ", sFunctionName, pp->lencode ) ;
653 	for ( i = 0 ; i < pp->lencode ; i ++ ) {
654 		if ( iscntrl( (u_char)(pp->a_lastcode[i] & 0x7F) ) ) {
655 			printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ;
656 		} else {
657 			printf( "%c", pp->a_lastcode[i] ) ;
658 		}
659 	}
660 	printf( "\n" ) ;
661 #endif
662 
663 	/*
664 	 * The reply with <CR><LF> gives a blank line
665 	 */
666 
667 	if ( pp->lencode == 0 ) return ;
668 
669 	/*
670 	 * Receiving data is not expected
671 	 */
672 
673 	if ( up->iProcessState == JJY_PROCESS_STATE_IDLE
674 	  || up->iProcessState == JJY_PROCESS_STATE_DONE
675 	  || up->iProcessState == JJY_PROCESS_STATE_ERROR ) {
676 		/* Discard received data */
677 		up->iRawBufLen = 0 ;
678 #ifdef DEBUG
679 		if ( debug ) {
680 			printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ;
681 		}
682 #endif
683 		return ;
684 	}
685 
686 	/*
687 	 * We get down to business
688 	 */
689 
690 	pp->lastrec = tRecvTimestamp ;
691 
692 	up->iLineCount ++ ;
693 
694 	up->iProcessState = JJY_PROCESS_STATE_RECEIVE ;
695 	up->bReceiveFlag = TRUE ;
696 
697 	iReadRawBuf = 0 ;
698 	iBreakPosition = up->iRawBufLen - 1 ;
699 	for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) {
700 
701 		if ( up->linediscipline == LDISC_RAW ) {
702 
703 			if ( up->bWaitBreakString ) {
704 				iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ;
705 				if ( iBreakPosition == -1 ) {
706 					/* Break string have not come yet */
707 					if ( up->iRawBufLen < MAX_RAWBUF - 2
708 					  || iReadRawBuf > 0 ) {
709 						/* Temporary buffer is not full */
710 						break ;
711 					} else {
712 						/* Temporary buffer is full */
713 						iBreakPosition = up->iRawBufLen - 1 ;
714 					}
715 				}
716 			} else {
717 				iBreakPosition = up->iRawBufLen - 1 ;
718 			}
719 
720 			/* Copy characters from temporary buffer to process buffer */
721 			up->iLineBufLen = up->iTextBufLen = 0 ;
722 			for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) {
723 
724 				/* Copy all characters */
725 				up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ;
726 				up->iLineBufLen ++ ;
727 
728 				/* Copy printable characters */
729 				if ( ! iscntrl( (u_char)up->sRawBuf[i] ) ) {
730 					up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ;
731 					up->iTextBufLen ++ ;
732 				}
733 
734 			}
735 			up->sLineBuf[up->iLineBufLen] = 0 ;
736 			up->sTextBuf[up->iTextBufLen] = 0 ;
737 #ifdef DEBUG
738 			printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n",
739 				 sFunctionName, up->iLineBufLen, up->iTextBufLen ) ;
740 #endif
741 
742 			if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) {
743 #ifdef DEBUG
744 				printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n",
745 					 sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ;
746 #endif
747 				if ( iBreakPosition + 1 < up->iRawBufLen ) {
748 					iReadRawBuf = iBreakPosition + 1 ;
749 					continue ;
750 				} else {
751 					break ;
752 				}
753 
754 			}
755 
756 		}
757 
758 		if ( up->linediscipline == LDISC_RAW ) {
759 			pBuf = up->sLineBuf ;
760 			iLen = up->iLineBufLen ;
761 		} else {
762 			pBuf = pp->a_lastcode ;
763 			iLen = pp->lencode ;
764 		}
765 
766 		iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ;
767 		memcpy( sLogText, pBuf, iCopyLen ) ;
768 		sLogText[iCopyLen] = '\0' ;
769 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ;
770 
771 		switch ( up->unittype ) {
772 
773 		case UNITTYPE_TRISTATE_JJY01 :
774 			rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
775 			break ;
776 
777 		case UNITTYPE_CDEX_JST2000 :
778 			rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
779 			break ;
780 
781 		case UNITTYPE_ECHOKEISOKUKI_LT2000 :
782 			rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
783 			break ;
784 
785 		case UNITTYPE_CITIZENTIC_JJY200 :
786 			rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
787 			break ;
788 
789 		case UNITTYPE_TRISTATE_GPSCLOCK01 :
790 			rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
791 			break ;
792 
793 		case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
794 			rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ;
795 			break ;
796 
797 		case UNITTYPE_TELEPHONE :
798 			rc = jjy_receive_telephone ( rbufp ) ;
799 			break ;
800 
801 		default :
802 			rc = JJY_RECEIVE_ERROR ;
803 			break ;
804 
805 		}
806 
807 		switch ( rc ) {
808 		case JJY_RECEIVE_DONE :
809 		case JJY_RECEIVE_SKIP :
810 			up->iProcessState = JJY_PROCESS_STATE_DONE ;
811 			break ;
812 		case JJY_RECEIVE_ERROR :
813 			up->iProcessState = JJY_PROCESS_STATE_ERROR ;
814 			break ;
815 		default :
816 			break ;
817 		}
818 
819 		if ( up->linediscipline == LDISC_RAW ) {
820 			if ( rc == JJY_RECEIVE_UNPROCESS ) {
821 				break ;
822 			}
823 			iReadRawBuf = iBreakPosition + 1 ;
824 			if ( iReadRawBuf >= up->iRawBufLen ) {
825 				/* Processed all received data */
826 				break ;
827 			}
828 		}
829 
830 		if ( up->linediscipline == LDISC_CLK ) {
831 			break ;
832 		}
833 
834 	}
835 
836 	if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) {
837 		for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) {
838 			up->sRawBuf[i] = up->sRawBuf[j] ;
839 		}
840 		up->iRawBufLen -= iReadRawBuf ;
841 		if ( up->iRawBufLen < 0 ) {
842 			up->iRawBufLen = 0 ;
843 		}
844 	}
845 
846 	up->bReceiveFlag = FALSE ;
847 
848 }
849 
850 /**************************************************************************************************/
851 
852 static int
853 getRawDataBreakPosition ( struct jjyunit *up, int iStart )
854 {
855 
856 	int 	i, j ;
857 
858 	if ( iStart >= up->iRawBufLen ) {
859 #ifdef DEBUG
860 		printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
861 #endif
862 		return -1 ;
863 	}
864 
865 	for ( i = iStart ; i < up->iRawBufLen ; i ++ ) {
866 
867 		for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) {
868 
869 			if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) {
870 
871 				if ( strncmp( up->sRawBuf + i,
872 					up->pRawBreak[j].pString,
873 					up->pRawBreak[j].iLength ) == 0 ) {
874 
875 #ifdef DEBUG
876 					printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n",
877 						iStart, i + up->pRawBreak[j].iLength - 1 ) ;
878 #endif
879 					return i + up->pRawBreak[j].iLength - 1 ;
880 
881 				}
882 			}
883 		}
884 	}
885 
886 #ifdef DEBUG
887 	printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
888 #endif
889 	return -1 ;
890 
891 }
892 
893 /**************************************************************************************************/
894 /*  jjy_poll - called by the transmit procedure                                                   */
895 /**************************************************************************************************/
896 static void
897 jjy_poll ( int unit, struct peer *peer )
898 {
899 
900 	char	sLog [ 40 ], sReach [ 9 ] ;
901 
902 	struct jjyunit      *up;
903 	struct refclockproc *pp;
904 
905 	pp = peer->procptr;
906 	up = pp->unitptr ;
907 
908 	if ( up->bInitError ) {
909 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ;
910 		return ;
911 	}
912 
913 	if ( pp->polls > 0  &&  up->iLineCount == 0 ) {
914 		/*
915 		 * No reply for last command
916 		 */
917 		refclock_report ( peer, CEVNT_TIMEOUT ) ;
918 	}
919 
920 	pp->polls ++ ;
921 
922 	sReach[0] = peer->reach & 0x80 ? '1' : '0' ;
923 	sReach[1] = peer->reach & 0x40 ? '1' : '0' ;
924 	sReach[2] = peer->reach & 0x20 ? '1' : '0' ;
925 	sReach[3] = peer->reach & 0x10 ? '1' : '0' ;
926 	sReach[4] = peer->reach & 0x08 ? '1' : '0' ;
927 	sReach[5] = peer->reach & 0x04 ? '1' : '0' ;
928 	sReach[6] = peer->reach & 0x02 ? '1' : '0' ;
929 	sReach[7] = 0 ; /* This poll */
930 	sReach[8] = 0 ;
931 
932 	snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ;
933 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
934 
935 	up->iProcessState = JJY_PROCESS_STATE_POLL ;
936 	up->iCommandSeq = 0 ;
937 	up->iReceiveSeq = 0 ;
938 	up->iLineCount = 0 ;
939 	up->bLineError = FALSE ;
940 	up->iRawBufLen = 0 ;
941 
942 	switch ( up->unittype ) {
943 
944 	case UNITTYPE_TRISTATE_JJY01 :
945 		jjy_poll_tristate_jjy01  ( unit, peer ) ;
946 		break ;
947 
948 	case UNITTYPE_CDEX_JST2000 :
949 		jjy_poll_cdex_jst2000 ( unit, peer ) ;
950 		break ;
951 
952 	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
953 		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
954 		break ;
955 
956 	case UNITTYPE_CITIZENTIC_JJY200 :
957 		jjy_poll_citizentic_jjy200 ( unit, peer ) ;
958 		break ;
959 
960 	case UNITTYPE_TRISTATE_GPSCLOCK01 :
961 		jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
962 		break ;
963 
964 	case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
965 		jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ;
966 		break ;
967 
968 	case UNITTYPE_TELEPHONE :
969 		jjy_poll_telephone ( unit, peer ) ;
970 		break ;
971 
972 	default :
973 		break ;
974 
975 	}
976 
977 }
978 
979 /**************************************************************************************************/
980 /*  jjy_timer - called at one-second intervals                                                    */
981 /**************************************************************************************************/
982 static void
983 jjy_timer ( int unit, struct peer *peer )
984 {
985 
986 	struct	refclockproc *pp ;
987 	struct	jjyunit      *up ;
988 
989 #ifdef DEBUG
990 	if ( debug ) {
991 		printf ( "refclock_jjy.c : jjy_timer\n" ) ;
992 	}
993 #endif
994 
995 	pp = peer->procptr ;
996 	up = pp->unitptr ;
997 
998 	if ( up->bReceiveFlag ) {
999 #ifdef DEBUG
1000 		if ( debug ) {
1001 			printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ;
1002 		}
1003 #endif
1004 		return ;
1005 	}
1006 
1007 	switch ( up->unittype ) {
1008 
1009 	case UNITTYPE_TELEPHONE :
1010 		jjy_timer_telephone ( unit, peer ) ;
1011 		break ;
1012 
1013 	default :
1014 		break ;
1015 
1016 	}
1017 
1018 }
1019 
1020 /**************************************************************************************************/
1021 /*  jjy_synctime                                                                                  */
1022 /**************************************************************************************************/
1023 static void
1024 jjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
1025 {
1026 
1027 	char	sLog [ 192 ], cStatus ;
1028 	const char	*pStatus ;
1029 
1030 	pp->year   = up->year ;
1031 	pp->day    = ymd2yd( up->year, up->month, up->day ) ;
1032 	pp->hour   = up->hour ;
1033 	pp->minute = up->minute ;
1034 	pp->second = up->second ;
1035 	pp->nsec   = up->msecond * 1000000 ;
1036 
1037 	/*
1038 	 * JST to UTC
1039 	 */
1040 	pp->hour -= 9 ;
1041 	if ( pp->hour < 0 ) {
1042 		pp->hour += 24 ;
1043 		pp->day -- ;
1044 		if ( pp->day < 1 ) {
1045 			pp->year -- ;
1046 			pp->day  = ymd2yd( pp->year, 12, 31 ) ;
1047 		}
1048 	}
1049 
1050 	/*
1051 	 * Process the new sample in the median filter and determine the
1052 	 * timecode timestamp.
1053 	 */
1054 
1055 	if ( ! refclock_process( pp ) ) {
1056 		refclock_report( peer, CEVNT_BADTIME ) ;
1057 		return ;
1058 	}
1059 
1060 	pp->lastref = pp->lastrec ;
1061 
1062 	refclock_receive( peer ) ;
1063 
1064 	/*
1065 	 * Write into the clockstats file
1066 	 */
1067 	snprintf ( sLog, sizeof(sLog),
1068 		   "%04d/%02d/%02d %02d:%02d:%02d.%03d JST   ( %04d/%03d %02d:%02d:%02d.%03d UTC )",
1069 		   up->year, up->month, up->day,
1070 		   up->hour, up->minute, up->second, up->msecond,
1071 		   pp->year, pp->day, pp->hour, pp->minute, pp->second,
1072 		   (int)(pp->nsec/1000000) ) ;
1073 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
1074 
1075 	cStatus = ' ' ;
1076 	pStatus = "" ;
1077 
1078 	switch ( peer->status ) {
1079 	case 0 : cStatus = ' ' ; pStatus = "Reject"    ; break ;
1080 	case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ;
1081 	case 2 : cStatus = '.' ; pStatus = "Excess"    ; break ;
1082 	case 3 : cStatus = '-' ; pStatus = "Outlier"   ; break ;
1083 	case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ;
1084 	case 5 : cStatus = '#' ; pStatus = "Selected"  ; break ;
1085 	case 6 : cStatus = '*' ; pStatus = "Sys.Peer"  ; break ;
1086 	case 7 : cStatus = 'o' ; pStatus = "PPS.Peer"  ; break ;
1087 	default : break ;
1088 	}
1089 
1090 	snprintf ( sLog, sizeof(sLog),
1091 		   "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.",
1092 		    peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ;
1093 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1094 
1095 }
1096 
1097 /*################################################################################################*/
1098 /*################################################################################################*/
1099 /*##												##*/
1100 /*##    The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02					##*/
1101 /*##												##*/
1102 /*##    server  127.127.40.X  mode 1								##*/
1103 /*##												##*/
1104 /*################################################################################################*/
1105 /*################################################################################################*/
1106 /*                                                                                                */
1107 /*  Command               Response                                  Remarks                       */
1108 /*  --------------------  ----------------------------------------  ----------------------------  */
1109 /*  dcst<CR><LF>          VALID<CR><LF> or INVALID<CR><LF>                                        */
1110 /*  stus<CR><LF>          ADJUSTED<CR><LF> or UNADJUSTED<CR><LF>                                  */
1111 /*  date<CR><LF>          YYYY/MM/DD XXX<CR><LF>                    XXX is the day of the week    */
1112 /*  time<CR><LF>          HH:MM:SS<CR><LF>                          Not used by this driver       */
1113 /*  stim<CR><LF>          HH:MM:SS<CR><LF>                          Reply at just second          */
1114 /*                                                                                                */
1115 /*################################################################################################*/
1116 
1117 #define	TS_JJY01_COMMAND_NUMBER_DATE	1
1118 #define	TS_JJY01_COMMAND_NUMBER_TIME	2
1119 #define	TS_JJY01_COMMAND_NUMBER_STIM	3
1120 #define	TS_JJY01_COMMAND_NUMBER_STUS	4
1121 #define	TS_JJY01_COMMAND_NUMBER_DCST	5
1122 
1123 #define	TS_JJY01_REPLY_DATE     	"yyyy/mm/dd www"
1124 #define	TS_JJY01_REPLY_STIM     	"hh:mm:ss"
1125 #define	TS_JJY01_REPLY_STUS_ADJUSTED	"adjusted"
1126 #define	TS_JJY01_REPLY_STUS_UNADJUSTED	"unadjusted"
1127 #define	TS_JJY01_REPLY_DCST_VALID	"valid"
1128 #define	TS_JJY01_REPLY_DCST_INVALID	"invalid"
1129 
1130 #define	TS_JJY01_REPLY_LENGTH_DATE           	14	/* Length without <CR><LF> */
1131 #define	TS_JJY01_REPLY_LENGTH_TIME           	8	/* Length without <CR><LF> */
1132 #define	TS_JJY01_REPLY_LENGTH_STIM           	8	/* Length without <CR><LF> */
1133 #define	TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED  	8	/* Length without <CR><LF> */
1134 #define	TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED	10	/* Length without <CR><LF> */
1135 #define	TS_JJY01_REPLY_LENGTH_DCST_VALID     	5	/* Length without <CR><LF> */
1136 #define	TS_JJY01_REPLY_LENGTH_DCST_INVALID   	7	/* Length without <CR><LF> */
1137 
1138 static  struct
1139 {
1140 	const char	commandNumber ;
1141 	const char	*command ;
1142 	int	commandLength ;
1143 	int	iExpectedReplyLength [ 2 ] ;
1144 } tristate_jjy01_command_sequence[] =
1145 {
1146 	{ 0, NULL, 0, { 0, 0 } }, /* Idle */
1147 	{ TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID   , TS_JJY01_REPLY_LENGTH_DCST_INVALID } },
1148 	{ TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } },
1149 	{ TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME         , TS_JJY01_REPLY_LENGTH_TIME } },
1150 	{ TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE         , TS_JJY01_REPLY_LENGTH_DATE } },
1151 	{ TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM         , TS_JJY01_REPLY_LENGTH_STIM } },
1152 	/* End of command */
1153 	{ 0, NULL, 0, { 0, 0 } }
1154 } ;
1155 
1156 /**************************************************************************************************/
1157 
1158 static int
1159 jjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up )
1160 {
1161 
1162 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ;
1163 
1164 	up->unittype  = UNITTYPE_TRISTATE_JJY01 ;
1165 	up->linespeed = SPEED232_TRISTATE_JJY01 ;
1166 	up->linediscipline = LDISC_CLK ;
1167 
1168 	time( &(up->tLastAdjustedTimestamp) ) ;
1169 	up->bStusReplyAdjustedAtLeastOnce = FALSE ;
1170 
1171 	return 0 ;
1172 
1173 }
1174 
1175 /**************************************************************************************************/
1176 
1177 static int
1178 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
1179 {
1180 	struct jjyunit	    *up ;
1181 	struct refclockproc *pp ;
1182 	struct peer	    *peer;
1183 
1184 	char *	pBuf ;
1185 	char	sLog [ MAX_LOGTEXT ] ;
1186 	int 	iLen ;
1187 	int 	rc ;
1188 	time_t	now ;
1189 	double	fSeconds ;
1190 
1191 	const char *	pCmd ;
1192 	int 		iCmdLen ;
1193 
1194 	/* Initialize pointers  */
1195 
1196 	peer = rbufp->recv_peer ;
1197 	pp = peer->procptr ;
1198 	up = pp->unitptr ;
1199 
1200 	if ( up->linediscipline == LDISC_RAW ) {
1201 		pBuf = up->sTextBuf ;
1202 		iLen = up->iTextBufLen ;
1203 	} else {
1204 		pBuf = pp->a_lastcode ;
1205 		iLen = pp->lencode ;
1206 	}
1207 
1208 	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
1209 
1210 	/* Check expected reply */
1211 
1212 	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1213 		/* Command sequence has not been started, or has been completed */
1214 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1215 			  pBuf ) ;
1216 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1217 		up->bLineError = TRUE ;
1218 		return JJY_RECEIVE_ERROR ;
1219 	}
1220 
1221 	/* Check reply length */
1222 
1223 	if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
1224 	  && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
1225 		/* Unexpected reply length */
1226 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1227 			  iLen ) ;
1228 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1229 		up->bLineError = TRUE ;
1230 		return JJY_RECEIVE_ERROR ;
1231 	}
1232 
1233 	/* Parse reply */
1234 
1235 	switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
1236 
1237 	case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
1238 
1239 		rc = sscanf ( pBuf, "%4d/%2d/%2d",
1240 			      &up->year, &up->month, &up->day ) ;
1241 
1242 		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
1243 		  || up->month < 1 || 12 < up->month
1244 		  || up->day < 1 || 31 < up->day ) {
1245 			/* Invalid date */
1246 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
1247 				  rc, up->year, up->month, up->day ) ;
1248 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1249 			up->bLineError = TRUE ;
1250 			return JJY_RECEIVE_ERROR ;
1251 		}
1252 
1253 		break ;
1254 
1255 	case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1256 	case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
1257 
1258 		if ( up->iTimestampCount >= 2 ) {
1259 			/* Too many time reply */
1260 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
1261 				  up->iTimestampCount ) ;
1262 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1263 			up->bLineError = TRUE ;
1264 			return JJY_RECEIVE_ERROR ;
1265 		}
1266 
1267 		rc = sscanf ( pBuf, "%2d:%2d:%2d",
1268 			      &up->hour, &up->minute, &up->second ) ;
1269 
1270 		if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
1271 		     up->second > 60 ) {
1272 			/* Invalid time */
1273 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
1274 				  rc, up->hour, up->minute, up->second ) ;
1275 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1276 			up->bLineError = TRUE ;
1277 			return JJY_RECEIVE_ERROR ;
1278 		}
1279 
1280 		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
1281 
1282 		up->iTimestampCount++ ;
1283 
1284 		up->msecond = 0 ;
1285 
1286 		break ;
1287 
1288 	case TS_JJY01_COMMAND_NUMBER_STUS :
1289 
1290 		if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
1291 			     TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0 ) {
1292 			/* STUS reply : adjusted */
1293 			up->bStusReplyAdjusted = TRUE ;
1294 			up->bStusReplyAdjustedAtLeastOnce = TRUE ;
1295 			time( &(up->tLastAdjustedTimestamp) ) ;
1296 		} else if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
1297 			             TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
1298 			/* STUS reply : unadjusted */
1299 			up->bStusReplyAdjusted = FALSE ;
1300 		} else {
1301 			/* Bad reply */
1302 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1303 				  pBuf ) ;
1304 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1305 			up->bLineError = TRUE ;
1306 			return JJY_RECEIVE_ERROR ;
1307 		}
1308 
1309 		break ;
1310 
1311 	case TS_JJY01_COMMAND_NUMBER_DCST :
1312 
1313 		if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
1314 			      TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
1315 		  || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
1316 			      TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
1317 			/* Valid reply */
1318 		} else {
1319 			/* Bad reply */
1320 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1321 				  pBuf ) ;
1322 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1323 			up->bLineError = TRUE ;
1324 			return JJY_RECEIVE_ERROR ;
1325 		}
1326 
1327 		break ;
1328 
1329 	default : /* Unexpected reply */
1330 
1331 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1332 			  pBuf ) ;
1333 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1334 		up->bLineError = TRUE ;
1335 		return JJY_RECEIVE_ERROR ;
1336 
1337 	}
1338 
1339 	if ( up->iTimestampCount == 2 ) {
1340 		/* Process date and time */
1341 
1342 		time( &now ) ;
1343 		fSeconds = difftime( now, up->tLastAdjustedTimestamp ) ;
1344 
1345 		if ( ( pp->sloppyclockflag & CLK_FLAG2 ) != 0
1346 		  && ( ! up->bStusReplyAdjusted )
1347 		  && ( fSeconds >= ( pp->fudgetime2 * 3600 ) || ( ! up->bStusReplyAdjustedAtLeastOnce ) ) ) {
1348 			/* STUS is not ADJUSTED */
1349 			if ( fSeconds < 60 ) {
1350 				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds, "seconds" ) ;
1351 			} else if ( fSeconds < 3600 ) {
1352 				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 60, "minutes" ) ;
1353 			} else if ( fSeconds < 86400 ) {
1354 				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 3600, "hours" ) ;
1355 			} else {
1356 				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 86400, "days" ) ;
1357 			}
1358 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1359 			return JJY_RECEIVE_SKIP ;
1360 		} else if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
1361 		         && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
1362 			/* 3 commands (time,date,stim) was executed in two seconds */
1363 			jjy_synctime( peer, pp, up ) ;
1364 			return JJY_RECEIVE_DONE ;
1365 		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
1366 			/* Over midnight, and date is unsure */
1367 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
1368 				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1369 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1370 			return JJY_RECEIVE_SKIP ;
1371 		} else {
1372 			/* Slow reply */
1373 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
1374 				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1375 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1376 			up->bLineError = TRUE ;
1377 			return JJY_RECEIVE_ERROR ;
1378 		}
1379 
1380 	}
1381 
1382 	/* Issue next command */
1383 
1384 	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
1385 		up->iCommandSeq ++ ;
1386 	}
1387 
1388 	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1389 		/* Command sequence completed */
1390 		return JJY_RECEIVE_DONE ;
1391 	}
1392 
1393 	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1394 	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1395 	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1396 		refclock_report ( peer, CEVNT_FAULT ) ;
1397 	}
1398 
1399 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1400 
1401 	return JJY_RECEIVE_WAIT ;
1402 
1403 }
1404 
1405 /**************************************************************************************************/
1406 
1407 static void
1408 jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1409 {
1410 #ifdef DEBUG
1411 	static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1412 #endif
1413 
1414 	struct refclockproc *pp ;
1415 	struct jjyunit	    *up ;
1416 
1417 	const char *	pCmd ;
1418 	int 		iCmdLen ;
1419 
1420 	pp = peer->procptr;
1421 	up = pp->unitptr ;
1422 
1423 	up->bLineError = FALSE ;
1424 	up->iTimestampCount = 0 ;
1425 
1426 	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1427 		/* Skip "dcst" and "stus" commands */
1428 		up->iCommandSeq = 2 ;
1429 		up->iLineCount = 2 ;
1430 	}
1431 
1432 	up->bStusReplyAdjusted = FALSE ;
1433 
1434 #ifdef DEBUG
1435 	if ( debug ) {
1436 		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
1437 			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1438 			up->iLineCount ) ;
1439 	}
1440 #endif
1441 
1442 	/*
1443 	 * Send a first command
1444 	 */
1445 
1446 	up->iCommandSeq ++ ;
1447 
1448 	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1449 	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1450 	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1451 		refclock_report ( peer, CEVNT_FAULT ) ;
1452 	}
1453 
1454 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1455 
1456 }
1457 
1458 /*################################################################################################*/
1459 /*################################################################################################*/
1460 /*##												##*/
1461 /*##    The C-DEX Co. Ltd. JJY receiver JST2000							##*/
1462 /*##												##*/
1463 /*##    server  127.127.40.X  mode 2								##*/
1464 /*##												##*/
1465 /*################################################################################################*/
1466 /*################################################################################################*/
1467 /*                                                                                                */
1468 /*  Command               Response                                  Remarks                       */
1469 /*  --------------------  ----------------------------------------  ----------------------------  */
1470 /*  <ENQ>1J<ETX>          <STX>JYYMMDDWHHMMSSS<ETX>                 J is a fixed character        */
1471 /*                                                                                                */
1472 /*################################################################################################*/
1473 
1474 static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
1475 {
1476 	{ "\x03", 1 }, { NULL, 0 }
1477 } ;
1478 
1479 /**************************************************************************************************/
1480 
1481 static int
1482 jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
1483 {
1484 
1485 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
1486 
1487 	up->unittype  = UNITTYPE_CDEX_JST2000 ;
1488 	up->linespeed = SPEED232_CDEX_JST2000 ;
1489 	up->linediscipline = LDISC_RAW ;
1490 
1491 	up->pRawBreak = cdex_jst2000_raw_break ;
1492 	up->bWaitBreakString = TRUE ;
1493 
1494 	up->bSkipCntrlCharOnly = FALSE ;
1495 
1496 	return 0 ;
1497 
1498 }
1499 
1500 /**************************************************************************************************/
1501 
1502 static int
1503 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
1504 {
1505 
1506 	struct jjyunit      *up ;
1507 	struct refclockproc *pp ;
1508 	struct peer         *peer ;
1509 
1510 	char	*pBuf, sLog [ MAX_LOGTEXT ] ;
1511 	int 	iLen ;
1512 	int 	rc ;
1513 
1514 	/* Initialize pointers */
1515 
1516 	peer = rbufp->recv_peer ;
1517 	pp = peer->procptr ;
1518 	up = pp->unitptr ;
1519 
1520 	if ( up->linediscipline == LDISC_RAW ) {
1521 		pBuf = up->sTextBuf ;
1522 		iLen = up->iTextBufLen ;
1523 	} else {
1524 		pBuf = pp->a_lastcode ;
1525 		iLen = pp->lencode ;
1526 	}
1527 
1528 	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
1529 
1530 	/* Check expected reply */
1531 
1532 	if ( up->iCommandSeq != 1 ) {
1533 		/* Command sequence has not been started, or has been completed */
1534 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1535 			  pBuf ) ;
1536 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1537 		up->bLineError = TRUE ;
1538 		return JJY_RECEIVE_ERROR ;
1539 	}
1540 
1541 	/* Wait until ETX comes */
1542 
1543 	if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
1544 		return JJY_RECEIVE_UNPROCESS ;
1545 	}
1546 
1547 	/* Check reply length */
1548 
1549 	if ( iLen != 15 ) {
1550 		/* Unexpected reply length */
1551 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1552 			  iLen ) ;
1553 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1554 		up->bLineError = TRUE ;
1555 		return JJY_RECEIVE_ERROR ;
1556 	}
1557 
1558 	/* JYYMMDDWHHMMSSS */
1559 
1560 	rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
1561 		      &up->year, &up->month, &up->day,
1562 		      &up->hour, &up->minute, &up->second,
1563 		      &up->msecond ) ;
1564 
1565 	if ( rc != 7 || up->month < 1 || up->month > 12 ||
1566 	     up->day < 1 || up->day > 31 || up->hour > 23 ||
1567 	     up->minute > 59 || up->second > 60 ) {
1568 		/* Invalid date and time */
1569 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1570 			  rc, up->year, up->month, up->day,
1571 			  up->hour, up->minute, up->second ) ;
1572 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1573 		up->bLineError = TRUE ;
1574 		return JJY_RECEIVE_ERROR ;
1575 	}
1576 
1577 	up->year    += 2000 ;
1578 	up->msecond *= 100 ;
1579 
1580 	jjy_synctime( peer, pp, up ) ;
1581 
1582 	return JJY_RECEIVE_DONE ;
1583 
1584 }
1585 
1586 /**************************************************************************************************/
1587 
1588 static void
1589 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1590 {
1591 
1592 	struct refclockproc *pp ;
1593 	struct jjyunit      *up ;
1594 
1595 	pp = peer->procptr ;
1596 	up = pp->unitptr ;
1597 
1598 	up->bLineError = FALSE ;
1599 	up->iRawBufLen = 0 ;
1600 	up->iLineBufLen = 0 ;
1601 	up->iTextBufLen = 0 ;
1602 
1603 	/*
1604 	 * Send "<ENQ>1J<ETX>" command
1605 	 */
1606 
1607 	up->iCommandSeq ++ ;
1608 
1609 	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1610 		refclock_report ( peer, CEVNT_FAULT ) ;
1611 	}
1612 
1613 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
1614 
1615 }
1616 
1617 /*################################################################################################*/
1618 /*################################################################################################*/
1619 /*##												##*/
1620 /*##    The Echo Keisokuki Co. Ltd. JJY receiver LT2000						##*/
1621 /*##												##*/
1622 /*##    server  127.127.40.X  mode 3								##*/
1623 /*##												##*/
1624 /*################################################################################################*/
1625 /*################################################################################################*/
1626 /*                                                                                                */
1627 /*  Command               Response                                  Remarks                       */
1628 /*  --------------------  ----------------------------------------  ----------------------------  */
1629 /*  #                                                               Mode 1 ( Request & Send )     */
1630 /*  T                     YYMMDDWHHMMSS<BCC1><BCC2><CR>                                           */
1631 /*  C                                                               Mode 2 ( Continuous )         */
1632 /*                        YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>     0.5 sec before time stamp     */
1633 /*                        <SUB>                                     Second signal                 */
1634 /*                                                                                                */
1635 /*################################################################################################*/
1636 
1637 #define	ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND		1
1638 #define	ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS		2
1639 #define	ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS	3
1640 
1641 #define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND 	"#"
1642 #define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME 	"T"
1643 #define	ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS 	"C"
1644 
1645 /**************************************************************************************************/
1646 
1647 static int
1648 jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
1649 {
1650 
1651 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
1652 
1653 	up->unittype  = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
1654 	up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
1655 	up->linediscipline = LDISC_CLK ;
1656 
1657 	up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
1658 
1659 	return 0 ;
1660 
1661 }
1662 
1663 /**************************************************************************************************/
1664 
1665 static int
1666 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1667 {
1668 
1669 	struct jjyunit      *up ;
1670 	struct refclockproc *pp ;
1671 	struct peer	    *peer;
1672 
1673 	char	*pBuf, sLog [ 100 ], sErr [ 60 ] ;
1674 	int 	iLen ;
1675 	int 	rc ;
1676 	int	i, ibcc, ibcc1, ibcc2 ;
1677 
1678 	/* Initialize pointers */
1679 
1680 	peer = rbufp->recv_peer ;
1681 	pp = peer->procptr ;
1682 	up = pp->unitptr ;
1683 
1684 	if ( up->linediscipline == LDISC_RAW ) {
1685 		pBuf = up->sTextBuf ;
1686 		iLen = up->iTextBufLen ;
1687 	} else {
1688 		pBuf = pp->a_lastcode ;
1689 		iLen = pp->lencode ;
1690 	}
1691 
1692 	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
1693 
1694 	/* Check reply length */
1695 
1696 	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1697 	       && iLen != 15 )
1698 	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1699 	       && iLen != 17 )
1700 	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1701 	       && iLen != 17 ) ) {
1702 		/* Unexpected reply length */
1703 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1704 			  iLen ) ;
1705 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1706 		up->bLineError = TRUE ;
1707 		return JJY_RECEIVE_ERROR ;
1708 	}
1709 
1710 	if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
1711 		/* YYMMDDWHHMMSS<BCC1><BCC2> */
1712 
1713 		for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
1714 			ibcc ^= pBuf[i] ;
1715 		}
1716 
1717 		ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1718 		ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
1719 		if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1720 			snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
1721 				  pBuf[13] & 0xFF, pBuf[14] & 0xFF,
1722 				  ibcc1, ibcc2 ) ;
1723 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1724 				  sErr ) ;
1725 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1726 			up->bLineError = TRUE ;
1727 			return JJY_RECEIVE_ERROR ;
1728 		}
1729 
1730 	}
1731 
1732 	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1733 	       && iLen == 15 )
1734 	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1735 	       && iLen == 17 )
1736 	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1737 	       && iLen == 17 ) ) {
1738 		/* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1739 
1740 		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1741 			      &up->year, &up->month, &up->day,
1742 			      &up->hour, &up->minute, &up->second ) ;
1743 
1744 		if ( rc != 6 || up->month < 1 || up->month > 12
1745 		  || up->day < 1 || up->day > 31
1746 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1747 			/* Invalid date and time */
1748 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1749 				  rc, up->year, up->month, up->day,
1750 				  up->hour, up->minute, up->second ) ;
1751 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1752 			up->bLineError = TRUE ;
1753 			return JJY_RECEIVE_ERROR ;
1754 		}
1755 
1756 		up->year += 2000 ;
1757 
1758 		if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1759 		  || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1760 			/* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
1761 
1762 			up->msecond = 500 ;
1763 			up->second -- ;
1764 			if ( up->second < 0 ) {
1765 				up->second = 59 ;
1766 				up->minute -- ;
1767 				if ( up->minute < 0 ) {
1768 					up->minute = 59 ;
1769 					up->hour -- ;
1770 					if ( up->hour < 0 ) {
1771 						up->hour = 23 ;
1772 						up->day -- ;
1773 						if ( up->day < 1 ) {
1774 							up->month -- ;
1775 							if ( up->month < 1 ) {
1776 								up->month = 12 ;
1777 								up->year -- ;
1778 							}
1779 						}
1780 					}
1781 				}
1782 			}
1783 
1784 		}
1785 
1786 		jjy_synctime( peer, pp, up ) ;
1787 
1788 
1789 	}
1790 
1791 	if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1792 		/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1793 
1794 		iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1795 		if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen  ) {
1796 			refclock_report ( peer, CEVNT_FAULT ) ;
1797 		}
1798 
1799 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1800 
1801 	}
1802 
1803 	return JJY_RECEIVE_DONE ;
1804 
1805 }
1806 
1807 /**************************************************************************************************/
1808 
1809 static void
1810 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1811 {
1812 
1813 	struct refclockproc *pp ;
1814 	struct jjyunit      *up ;
1815 
1816 	char	sCmd[2] ;
1817 
1818 	pp = peer->procptr ;
1819 	up = pp->unitptr ;
1820 
1821 	up->bLineError = FALSE ;
1822 
1823 	/*
1824 	 * Send "T" or "C" command
1825 	 */
1826 
1827 	switch ( up->operationmode ) {
1828 	case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
1829 		sCmd[0] = 'T' ;
1830 		break ;
1831 	case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
1832 	case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
1833 		sCmd[0] = 'C' ;
1834 		break ;
1835 	}
1836 	sCmd[1] = 0 ;
1837 
1838 	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1839 		refclock_report ( peer, CEVNT_FAULT ) ;
1840 	}
1841 
1842 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
1843 
1844 }
1845 
1846 /*################################################################################################*/
1847 /*################################################################################################*/
1848 /*##												##*/
1849 /*##    The CITIZEN T.I.C CO., LTD. JJY receiver JJY200						##*/
1850 /*##												##*/
1851 /*##    server  127.127.40.X  mode 4								##*/
1852 /*##												##*/
1853 /*################################################################################################*/
1854 /*################################################################################################*/
1855 /*                                                                                                */
1856 /*  Command               Response                                  Remarks                       */
1857 /*  --------------------  ----------------------------------------  ----------------------------  */
1858 /*                        'XX YY/MM/DD W HH:MM:SS<CR>               XX:OK|NG|ER  W:0(Mon)-6(Sun)  */
1859 /*                                                                                                */
1860 /*################################################################################################*/
1861 
1862 static int
1863 jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
1864 {
1865 
1866 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
1867 
1868 	up->unittype  = UNITTYPE_CITIZENTIC_JJY200 ;
1869 	up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
1870 	up->linediscipline = LDISC_CLK ;
1871 
1872 	return 0 ;
1873 
1874 }
1875 
1876 /**************************************************************************************************/
1877 
1878 static int
1879 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1880 {
1881 
1882 	struct jjyunit		*up ;
1883 	struct refclockproc	*pp ;
1884 	struct peer		*peer;
1885 
1886 	char	*pBuf, sLog [ 100 ], sMsg [ 16 ] ;
1887 	int	iLen ;
1888 	int	rc ;
1889 	char	cApostrophe, sStatus[3] ;
1890 	int	iWeekday ;
1891 
1892 	/* Initialize pointers */
1893 
1894 	peer = rbufp->recv_peer ;
1895 	pp = peer->procptr ;
1896 	up = pp->unitptr ;
1897 
1898 	if ( up->linediscipline == LDISC_RAW ) {
1899 		pBuf = up->sTextBuf ;
1900 		iLen = up->iTextBufLen ;
1901 	} else {
1902 		pBuf = pp->a_lastcode ;
1903 		iLen = pp->lencode ;
1904 	}
1905 
1906 	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
1907 
1908 	/*
1909 	 * JJY-200 sends a timestamp every second.
1910 	 * So, a timestamp is ignored unless it is right after polled.
1911 	 */
1912 
1913 	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
1914 		return JJY_RECEIVE_SKIP ;
1915 	}
1916 
1917 	/* Check reply length */
1918 
1919 	if ( iLen != 23 ) {
1920 		/* Unexpected reply length */
1921 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1922 			  iLen ) ;
1923 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1924 		up->bLineError = TRUE ;
1925 		return JJY_RECEIVE_ERROR ;
1926 	}
1927 
1928 	/* 'XX YY/MM/DD W HH:MM:SS<CR> */
1929 
1930 	rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1931 		      &cApostrophe, sStatus,
1932 		      &up->year, &up->month, &up->day, &iWeekday,
1933 		      &up->hour, &up->minute, &up->second ) ;
1934 	sStatus[2] = 0 ;
1935 
1936 	if ( rc != 9 || cApostrophe != '\''
1937 	  || ( strcmp( sStatus, "OK" ) != 0
1938 	    && strcmp( sStatus, "NG" ) != 0
1939 	    && strcmp( sStatus, "ER" ) != 0 )
1940 	  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
1941 	  || iWeekday > 6
1942 	  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1943 		/* Invalid date and time */
1944 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1945 			  rc, up->year, up->month, up->day,
1946 			  up->hour, up->minute, up->second ) ;
1947 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1948 		up->bLineError = TRUE ;
1949 		return JJY_RECEIVE_ERROR ;
1950 	} else if ( strcmp( sStatus, "NG" ) == 0
1951 		 || strcmp( sStatus, "ER" ) == 0 ) {
1952 		/* Timestamp is unsure */
1953 		snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
1954 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
1955 			  sMsg ) ;
1956 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
1957 		return JJY_RECEIVE_SKIP ;
1958 	}
1959 
1960 	up->year += 2000 ;
1961 	up->msecond = 0 ;
1962 
1963 	jjy_synctime( peer, pp, up ) ;
1964 
1965 	return JJY_RECEIVE_DONE ;
1966 
1967 }
1968 
1969 /**************************************************************************************************/
1970 
1971 static void
1972 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1973 {
1974 
1975 	struct refclockproc *pp ;
1976 	struct jjyunit	    *up ;
1977 
1978 	pp = peer->procptr ;
1979 	up = pp->unitptr ;
1980 
1981 	up->bLineError = FALSE ;
1982 
1983 }
1984 
1985 /*################################################################################################*/
1986 /*################################################################################################*/
1987 /*##												##*/
1988 /*##    The Tristate Ltd. GPS clock TS-GPS01							##*/
1989 /*##												##*/
1990 /*##    server  127.127.40.X  mode 5								##*/
1991 /*##												##*/
1992 /*################################################################################################*/
1993 /*################################################################################################*/
1994 /*                                                                                                */
1995 /*  This clock has NMEA mode and command/response mode.                                           */
1996 /*  When this jjy driver are used, set to command/response mode of this clock                     */
1997 /*  by the onboard switch SW4, and make sure the LED-Y is tured on.                               */
1998 /*  Other than this JJY driver, the refclock driver type 20, generic NMEA driver,                 */
1999 /*  works with the NMEA mode of this clock.                                                       */
2000 /*                                                                                                */
2001 /*  Command               Response                                  Remarks                       */
2002 /*  --------------------  ----------------------------------------  ----------------------------  */
2003 /*  stus<CR><LF>          *R|*G|*U|+U<CR><LF>                                                     */
2004 /*  date<CR><LF>          YY/MM/DD<CR><LF>                                                        */
2005 /*  time<CR><LF>          HH:MM:SS<CR><LF>                                                        */
2006 /*                                                                                                */
2007 /*################################################################################################*/
2008 
2009 #define	TS_GPS01_COMMAND_NUMBER_DATE	1
2010 #define	TS_GPS01_COMMAND_NUMBER_TIME	2
2011 #define	TS_GPS01_COMMAND_NUMBER_STUS	4
2012 
2013 #define	TS_GPS01_REPLY_DATE		"yyyy/mm/dd"
2014 #define	TS_GPS01_REPLY_TIME		"hh:mm:ss"
2015 #define	TS_GPS01_REPLY_STUS_RTC		"*R"
2016 #define	TS_GPS01_REPLY_STUS_GPS		"*G"
2017 #define	TS_GPS01_REPLY_STUS_UTC		"*U"
2018 #define	TS_GPS01_REPLY_STUS_PPS		"+U"
2019 
2020 #define	TS_GPS01_REPLY_LENGTH_DATE	    10	/* Length without <CR><LF> */
2021 #define	TS_GPS01_REPLY_LENGTH_TIME	    8	/* Length without <CR><LF> */
2022 #define	TS_GPS01_REPLY_LENGTH_STUS	    2	/* Length without <CR><LF> */
2023 
2024 static  struct
2025 {
2026 	char	commandNumber ;
2027 	const char	*command ;
2028 	int	commandLength ;
2029 	int	iExpectedReplyLength ;
2030 } tristate_gps01_command_sequence[] =
2031 {
2032 	{ 0, NULL, 0, 0 }, /* Idle */
2033 	{ TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
2034 	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
2035 	{ TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
2036 	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
2037 	/* End of command */
2038 	{ 0, NULL, 0, 0 }
2039 } ;
2040 
2041 /**************************************************************************************************/
2042 
2043 static int
2044 jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
2045 {
2046 
2047 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
2048 
2049 	up->unittype  = UNITTYPE_TRISTATE_GPSCLOCK01 ;
2050 	up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
2051 	up->linediscipline = LDISC_CLK ;
2052 
2053 	return 0 ;
2054 
2055 }
2056 
2057 /**************************************************************************************************/
2058 
2059 static int
2060 jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
2061 {
2062 #ifdef DEBUG
2063 	static	const char	*sFunctionName = "jjy_receive_tristate_gpsclock01" ;
2064 #endif
2065 
2066 	struct jjyunit	    *up ;
2067 	struct refclockproc *pp ;
2068 	struct peer	    *peer;
2069 
2070 	char *		pBuf ;
2071 	char		sLog [ MAX_LOGTEXT ] ;
2072 	int 		iLen ;
2073 	int 		rc ;
2074 
2075 	const char *	pCmd ;
2076 	int 		iCmdLen ;
2077 
2078 	/* Initialize pointers */
2079 
2080 	peer = rbufp->recv_peer ;
2081 	pp = peer->procptr ;
2082 	up = pp->unitptr ;
2083 
2084 	if ( up->linediscipline == LDISC_RAW ) {
2085 		pBuf = up->sTextBuf ;
2086 		iLen = up->iTextBufLen ;
2087 	} else {
2088 		pBuf = pp->a_lastcode ;
2089 		iLen = pp->lencode ;
2090 	}
2091 
2092 	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
2093 
2094 	/* Ignore NMEA data stream */
2095 
2096 	if ( iLen > 5
2097 	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2098 #ifdef DEBUG
2099 		if ( debug ) {
2100 			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2101 				sFunctionName, pBuf ) ;
2102 		}
2103 #endif
2104 		return JJY_RECEIVE_WAIT ;
2105 	}
2106 
2107 	/*
2108 	 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
2109 	 */
2110 	if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2111 		return JJY_RECEIVE_WAIT ;
2112 	} else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2113 		pBuf += 5 ;
2114 		iLen -= 5 ;
2115 	}
2116 
2117 	/*
2118 	 * Ignore NMEA data stream after command prompt
2119 	 */
2120 	if ( iLen > 5
2121 	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2122 #ifdef DEBUG
2123 		if ( debug ) {
2124 			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2125 				sFunctionName, pBuf ) ;
2126 		}
2127 #endif
2128 		return JJY_RECEIVE_WAIT ;
2129 	}
2130 
2131 	/* Check expected reply */
2132 
2133 	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2134 		/* Command sequence has not been started, or has been completed */
2135 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2136 			  pBuf ) ;
2137 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2138 		up->bLineError = TRUE ;
2139 		return JJY_RECEIVE_ERROR ;
2140 	}
2141 
2142 	/* Check reply length */
2143 
2144 	if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
2145 		/* Unexpected reply length */
2146 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2147 			  iLen ) ;
2148 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2149 		up->bLineError = TRUE ;
2150 		return JJY_RECEIVE_ERROR ;
2151 	}
2152 
2153 	/* Parse reply */
2154 
2155 	switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
2156 
2157 	case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
2158 
2159 		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
2160 
2161 		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
2162 		  || up->month < 1 || 12 < up->month
2163 		  || up->day < 1 || 31 < up->day ) {
2164 			/* Invalid date */
2165 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
2166 				  rc, up->year, up->month, up->day ) ;
2167 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2168 			up->bLineError = TRUE ;
2169 			return JJY_RECEIVE_ERROR ;
2170 		}
2171 
2172 		break ;
2173 
2174 	case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
2175 
2176 		if ( up->iTimestampCount >= 2 ) {
2177 			/* Too many time reply */
2178 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
2179 				  up->iTimestampCount ) ;
2180 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2181 			up->bLineError = TRUE ;
2182 			return JJY_RECEIVE_ERROR ;
2183 		}
2184 
2185 		rc = sscanf ( pBuf, "%2d:%2d:%2d",
2186 			      &up->hour, &up->minute, &up->second ) ;
2187 
2188 		if ( rc != 3
2189 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2190 			/* Invalid time */
2191 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2192 				  rc, up->hour, up->minute, up->second ) ;
2193 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2194 			up->bLineError = TRUE ;
2195 			return JJY_RECEIVE_ERROR ;
2196 		}
2197 
2198 		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
2199 
2200 		up->iTimestampCount++ ;
2201 
2202 		up->msecond = 0 ;
2203 
2204 		break ;
2205 
2206 	case TS_GPS01_COMMAND_NUMBER_STUS :
2207 
2208 		if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2209 		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2210 		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2211 		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
2212 			/* Good */
2213 		} else {
2214 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2215 				  pBuf ) ;
2216 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2217 			up->bLineError = TRUE ;
2218 			return JJY_RECEIVE_ERROR ;
2219 		}
2220 
2221 		break ;
2222 
2223 	default : /*  Unexpected reply */
2224 
2225 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2226 			  pBuf ) ;
2227 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2228 		up->bLineError = TRUE ;
2229 		return JJY_RECEIVE_ERROR ;
2230 
2231 	}
2232 
2233 	if ( up->iTimestampCount == 2 ) {
2234 		/* Process date and time */
2235 
2236 		if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
2237 		  && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
2238 			/* 3 commands (time,date,stim) was executed in two seconds */
2239 			jjy_synctime( peer, pp, up ) ;
2240 			return JJY_RECEIVE_DONE ;
2241 		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
2242 			/* Over midnight, and date is unsure */
2243 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
2244 				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2245 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
2246 			return JJY_RECEIVE_SKIP ;
2247 		} else {
2248 			/* Slow reply */
2249 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
2250 				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2251 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2252 			up->bLineError = TRUE ;
2253 			return JJY_RECEIVE_ERROR ;
2254 		}
2255 
2256 	}
2257 
2258 	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2259 		/* Command sequence completed */
2260 		jjy_synctime( peer, pp, up ) ;
2261 		return JJY_RECEIVE_DONE ;
2262 	}
2263 
2264 	/* Issue next command */
2265 
2266 	if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
2267 		up->iCommandSeq ++ ;
2268 	}
2269 
2270 	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2271 		/* Command sequence completed */
2272 		up->iProcessState = JJY_PROCESS_STATE_DONE ;
2273 		return JJY_RECEIVE_DONE ;
2274 	}
2275 
2276 	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2277 	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2278 	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2279 		refclock_report ( peer, CEVNT_FAULT ) ;
2280 	}
2281 
2282 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2283 
2284 	return JJY_RECEIVE_WAIT ;
2285 
2286 }
2287 
2288 /**************************************************************************************************/
2289 
2290 static void
2291 jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
2292 {
2293 #ifdef DEBUG
2294 	static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
2295 #endif
2296 
2297 	struct refclockproc *pp ;
2298 	struct jjyunit	    *up ;
2299 
2300 	const char *	pCmd ;
2301 	int		iCmdLen ;
2302 
2303 	pp = peer->procptr ;
2304 	up = pp->unitptr ;
2305 
2306 	up->iTimestampCount = 0 ;
2307 
2308 	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
2309 		/* Skip "stus" command */
2310 		up->iCommandSeq = 1 ;
2311 		up->iLineCount = 1 ;
2312 	}
2313 
2314 #ifdef DEBUG
2315 	if ( debug ) {
2316 		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
2317 			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
2318 			up->iLineCount ) ;
2319 	}
2320 #endif
2321 
2322 	/*
2323 	 * Send a first command
2324 	 */
2325 
2326 	up->iCommandSeq ++ ;
2327 
2328 	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2329 	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2330 	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2331 		refclock_report ( peer, CEVNT_FAULT ) ;
2332 	}
2333 
2334 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2335 
2336 }
2337 
2338 /*################################################################################################*/
2339 /*################################################################################################*/
2340 /*##												##*/
2341 /*##    The SEIKO TIME SYSTEMS TDC-300								##*/
2342 /*##												##*/
2343 /*##    server  127.127.40.X  mode 6								##*/
2344 /*##												##*/
2345 /*################################################################################################*/
2346 /*################################################################################################*/
2347 /*                                                                                                */
2348 /*  Type                  Response                                  Remarks                       */
2349 /*  --------------------  ----------------------------------------  ----------------------------  */
2350 /*  Type 1                <STX>HH:MM:SS<ETX>                                                      */
2351 /*  Type 2                <STX>YYMMDDHHMMSSWLSCU<ETX>               W:0(Sun)-6(Sat)               */
2352 /*  Type 3                <STX>YYMMDDWHHMMSS<ETX>                   W:0(Sun)-6(Sat)               */
2353 /*                        <STX><xE5><ETX>                           5 to 10 mSec. before second   */
2354 /*                                                                                                */
2355 /*################################################################################################*/
2356 
2357 static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
2358 {
2359 	{ "\x03", 1 }, { NULL, 0 }
2360 } ;
2361 
2362 /**************************************************************************************************/
2363 
2364 static int
2365 jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
2366 {
2367 
2368 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
2369 
2370 	up->unittype  = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
2371 	up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
2372 	up->linediscipline = LDISC_RAW ;
2373 
2374 	up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
2375 	up->bWaitBreakString = TRUE ;
2376 
2377 	up->bSkipCntrlCharOnly = FALSE ;
2378 
2379 	return 0 ;
2380 
2381 }
2382 
2383 /**************************************************************************************************/
2384 
2385 static int
2386 jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
2387 {
2388 
2389 	struct peer		*peer;
2390 	struct refclockproc	*pp ;
2391 	struct jjyunit		*up ;
2392 
2393 	char	*pBuf, sLog [ MAX_LOGTEXT ] ;
2394 	int	iLen, i ;
2395 	int	rc, iWeekday ;
2396 	time_t	now ;
2397 	struct	tm	*pTime ;
2398 
2399 	/* Initialize pointers */
2400 
2401 	peer = rbufp->recv_peer ;
2402 	pp = peer->procptr ;
2403 	up = pp->unitptr ;
2404 
2405 	if ( up->linediscipline == LDISC_RAW ) {
2406 		pBuf = up->sTextBuf ;
2407 		iLen = up->iTextBufLen ;
2408 	} else {
2409 		pBuf = pp->a_lastcode ;
2410 		iLen = pp->lencode ;
2411 	}
2412 
2413 	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
2414 
2415 	/*
2416 	 * TDC-300 sends a timestamp every second.
2417 	 * So, a timestamp is ignored unless it is right after polled.
2418 	 */
2419 
2420 	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
2421 		return JJY_RECEIVE_SKIP ;
2422 	}
2423 
2424 	/* Process timestamp */
2425 
2426 	up->iReceiveSeq ++ ;
2427 
2428 	switch ( iLen ) {
2429 
2430 	case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
2431 
2432 		for ( i = 0 ; i < iLen ; i ++ ) {
2433 			pBuf[i] &= 0x7F ;
2434 		}
2435 
2436 		rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
2437 		      &up->hour, &up->minute, &up->second ) ;
2438 
2439 		if ( rc != 3
2440 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2441 			/* Invalid time */
2442 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2443 				  rc, up->hour, up->minute, up->second ) ;
2444 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2445 			up->bLineError = TRUE ;
2446 			return JJY_RECEIVE_ERROR ;
2447 		} else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
2448 			/* Uncertainty date guard */
2449 			return JJY_RECEIVE_WAIT ;
2450 		}
2451 
2452 		time( &now ) ;
2453 		pTime = localtime( &now ) ;
2454 		up->year  = pTime->tm_year ;
2455 		up->month = pTime->tm_mon + 1 ;
2456 		up->day   = pTime->tm_mday ;
2457 
2458 		break ;
2459 
2460 	case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
2461 
2462 		for ( i = 0 ; i < iLen ; i ++ ) {
2463 			pBuf[i] &= 0x7F ;
2464 		}
2465 
2466 		rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
2467 		      &up->year, &up->month, &up->day,
2468 		      &up->hour, &up->minute, &up->second, &iWeekday ) ;
2469 
2470 		if ( rc != 7
2471 		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2472 		  || iWeekday > 6
2473 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2474 			/* Invalid date and time */
2475 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2476 				  rc, up->year, up->month, up->day,
2477 				  up->hour, up->minute, up->second ) ;
2478 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2479 			up->bLineError = TRUE ;
2480 			return JJY_RECEIVE_ERROR ;
2481 		}
2482 
2483 		break ;
2484 
2485 	case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
2486 
2487 		rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
2488 		      &up->year, &up->month, &up->day, &iWeekday,
2489 		      &up->hour, &up->minute, &up->second ) ;
2490 
2491 		if ( rc != 7
2492 		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2493 		  || iWeekday > 6
2494 		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2495 			/* Invalid date and time */
2496 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2497 				  rc, up->year, up->month, up->day,
2498 				  up->hour, up->minute, up->second ) ;
2499 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2500 			up->bLineError = TRUE ;
2501 			return JJY_RECEIVE_ERROR ;
2502 		}
2503 
2504 		return JJY_RECEIVE_WAIT ;
2505 
2506 	case 1 : /* Type 3 : <STX><xE5><ETX> */
2507 
2508 		if ( ( *pBuf & 0xFF ) != 0xE5 ) {
2509 			/* Invalid second signal */
2510 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2511 				  up->sLineBuf ) ;
2512 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2513 			up->bLineError = TRUE ;
2514 			return JJY_RECEIVE_ERROR ;
2515 		} else if ( up->iReceiveSeq == 1 ) {
2516 			/* Wait for next timestamp */
2517 			up->iReceiveSeq -- ;
2518 			return JJY_RECEIVE_WAIT ;
2519 		} else if ( up->iReceiveSeq >= 3 ) {
2520 			/* Unexpected second signal */
2521 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2522 				  up->sLineBuf ) ;
2523 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2524 			up->bLineError = TRUE ;
2525 			return JJY_RECEIVE_ERROR ;
2526 		}
2527 
2528 		break ;
2529 
2530 	default : /* Unexpected reply length */
2531 
2532 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2533 			  iLen ) ;
2534 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2535 		up->bLineError = TRUE ;
2536 		return JJY_RECEIVE_ERROR ;
2537 
2538 	}
2539 
2540 	up->year += 2000 ;
2541 	up->msecond = 0 ;
2542 
2543 	jjy_synctime( peer, pp, up ) ;
2544 
2545 	return JJY_RECEIVE_DONE ;
2546 
2547 }
2548 
2549 /**************************************************************************************************/
2550 
2551 static void
2552 jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
2553 {
2554 
2555 	struct refclockproc *pp ;
2556 	struct jjyunit	    *up ;
2557 
2558 	pp = peer->procptr ;
2559 	up = pp->unitptr ;
2560 
2561 	up->bLineError = FALSE ;
2562 
2563 }
2564 
2565 /*################################################################################################*/
2566 /*################################################################################################*/
2567 /*##												##*/
2568 /*##    Telephone JJY										##*/
2569 /*##												##*/
2570 /*##    server  127.127.40.X  mode 100 to 180							##*/
2571 /*##												##*/
2572 /*################################################################################################*/
2573 /*################################################################################################*/
2574 /*                                                                                                */
2575 /*  Prompt                Command               Response              Remarks                     */
2576 /*  --------------------  --------------------  --------------------  --------------------------  */
2577 /*  Name<SP>?<SP>         TJJY<CR>              Welcome messages      TJJY is a guest user ID     */
2578 /*  >                     4DATE<CR>             YYYYMMDD<CR>                                      */
2579 /*  >                     LEAPSEC<CR>           XX<CR>                One of <SP>0, +1, -1        */
2580 /*  >                     TIME<CR>              HHMMSS<CR>            3 times on second           */
2581 /*  >                     BYE<CR>               Sayounara messages                                */
2582 /*                                                                                                */
2583 /*################################################################################################*/
2584 
2585 static struct jjyRawDataBreak teljjy_raw_break [ ] =
2586 {
2587 	{ "\r\n", 2 },
2588 	{ "\r"  , 1 },
2589 	{ "\n"  , 1 },
2590 	{ "Name ? ", 7 },
2591 	{ ">"   , 1 },
2592 	{ "+++" , 3 },
2593 	{ NULL  , 0 }
2594 } ;
2595 
2596 #define	TELJJY_STATE_IDLE	0
2597 #define	TELJJY_STATE_DAILOUT	1
2598 #define	TELJJY_STATE_LOGIN	2
2599 #define	TELJJY_STATE_CONNECT	3
2600 #define	TELJJY_STATE_BYE	4
2601 
2602 #define	TELJJY_EVENT_NULL	0
2603 #define	TELJJY_EVENT_START	1
2604 #define	TELJJY_EVENT_CONNECT	2
2605 #define	TELJJY_EVENT_DISCONNECT	3
2606 #define	TELJJY_EVENT_COMMAND	4
2607 #define	TELJJY_EVENT_LOGIN	5	/* Posted by the jjy_receive_telephone */
2608 #define	TELJJY_EVENT_PROMPT	6	/* Posted by the jjy_receive_telephone */
2609 #define	TELJJY_EVENT_DATA	7	/* Posted by the jjy_receive_telephone */
2610 #define	TELJJY_EVENT_ERROR	8	/* Posted by the jjy_receive_telephone */
2611 #define	TELJJY_EVENT_SILENT	9	/* Posted by the jjy_timer_telephone */
2612 #define	TELJJY_EVENT_TIMEOUT	10	/* Posted by the jjy_timer_telephone */
2613 
2614 static	void 	teljjy_control		( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2615 
2616 static	int 	teljjy_idle_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2617 static	int 	teljjy_idle_dialout	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2618 static	int 	teljjy_dial_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2619 static	int 	teljjy_dial_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2620 static	int 	teljjy_dial_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2621 static	int 	teljjy_login_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2622 static	int 	teljjy_login_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2623 static	int 	teljjy_login_conn	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2624 static	int 	teljjy_login_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2625 static	int 	teljjy_login_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2626 static	int 	teljjy_login_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2627 static	int 	teljjy_conn_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2628 static	int 	teljjy_conn_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2629 static	int 	teljjy_conn_send	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2630 static	int 	teljjy_conn_data	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2631 static	int 	teljjy_conn_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2632 static	int 	teljjy_conn_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2633 static	int 	teljjy_bye_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2634 static	int 	teljjy_bye_disc 	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2635 static	int 	teljjy_bye_modem	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2636 
2637 static int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) =
2638 {               	/*STATE_IDLE           STATE_DAILOUT       STATE_LOGIN           STATE_CONNECT       STATE_BYE        */
2639 /* NULL       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2640 /* START      */	{ teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2641 /* CONNECT    */	{ teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2642 /* DISCONNECT */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_disc  , teljjy_conn_disc  , teljjy_bye_disc   },
2643 /* COMMAND    */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem  },
2644 /* LOGIN      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
2645 /* PROMPT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn  , teljjy_conn_send  , teljjy_bye_ignore },
2646 /* DATA       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data  , teljjy_bye_ignore },
2647 /* ERROR      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
2648 /* SILENT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
2649 /* TIMEOUT    */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem  }
2650 } ;
2651 
2652 static short iTeljjyNextState [ ] [ 5 ] =
2653 {               	/*STATE_IDLE            STATE_DAILOUT         STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2654 /* NULL       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2655 /* START      */	{ TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2656 /* CONNECT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_LOGIN  , TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2657 /* DISCONNECT */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE },
2658 /* COMMAND    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2659 /* LOGIN      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2660 /* PROMPT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2661 /* DATA       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2662 /* ERROR      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2663 /* SILENT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2664 /* TIMEOUT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  }
2665 } ;
2666 
2667 static short iTeljjyPostEvent [ ] [ 5 ] =
2668 {               	/*STATE_IDLE         STATE_DAILOUT      STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2669 /* NULL       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2670 /* START      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2671 /* CONNECT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2672 /* DISCONNECT */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2673 /* COMMAND    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2674 /* LOGIN      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2675 /* PROMPT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2676 /* DATA       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2677 /* ERROR      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2678 /* SILENT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2679 /* TIMEOUT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
2680 } ;
2681 
2682 static short iTeljjySilentTimeout [ 5 ] = { 0,   0, 10,  5,  0 } ;
2683 static short iTeljjyStateTimeout  [ 5 ] = { 0, 120, 60, 60, 40 } ;
2684 
2685 #define	TELJJY_STAY_CLOCK_STATE  	0
2686 #define	TELJJY_CHANGE_CLOCK_STATE	1
2687 
2688 /* Command and replay */
2689 
2690 #define	TELJJY_REPLY_NONE	0
2691 #define	TELJJY_REPLY_4DATE	1
2692 #define	TELJJY_REPLY_TIME	2
2693 #define	TELJJY_REPLY_LEAPSEC	3
2694 #define	TELJJY_REPLY_LOOP	4
2695 #define	TELJJY_REPLY_PROMPT	5
2696 #define	TELJJY_REPLY_LOOPBACK	6
2697 #define	TELJJY_REPLY_COM	7
2698 
2699 #define	TELJJY_COMMAND_START_SKIP_LOOPBACK	7
2700 
2701 static  struct
2702 {
2703 	const char	*command ;
2704 	int	commandLength ;
2705 	int	iEchobackReplyLength ;
2706 	int	iExpectedReplyType   ;
2707 	int	iExpectedReplyLength ;
2708 } teljjy_command_sequence[] =
2709 {
2710 	{ NULL, 0, 0, 0, 0 }, /* Idle */
2711 	{ "LOOP\r"   , 5, 4, TELJJY_REPLY_LOOP    , 0 }, /* Getting into loopback mode */
2712 	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2713 	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2714 	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2715 	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2716 	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2717 	{ "COM\r"    , 4, 3, TELJJY_REPLY_COM     , 0 }, /* Exit from loopback mode */
2718 	/* TELJJY_COMMAND_START_SKIP_LOOPBACK */
2719 	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2720 	{ "4DATE\r"  , 6, 5, TELJJY_REPLY_4DATE   , 8 },
2721 	{ "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
2722 	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2723 	{ "BYE\r"    , 4, 3, TELJJY_REPLY_NONE    , 0 },
2724 	/* End of command */
2725 	{ NULL, 0, 0, 0, 0 }
2726 } ;
2727 
2728 #define	TELJJY_LOOPBACK_DELAY_THRESHOLD		700 /* Milli second */
2729 
2730 #ifdef	DEBUG
2731 #define	DEBUG_TELJJY_PRINTF(sFunc)	{ if ( debug ) { printf ( "refclock_jjy.c : %s : iClockState=%d iClockEvent=%d iTeljjySilentTimer=%d iTeljjyStateTimer=%d iClockCommandSeq=%d\n", sFunc, up->iClockState, up->iClockEvent, up->iTeljjySilentTimer, up->iTeljjyStateTimer, up->iClockCommandSeq ) ; } }
2732 #else
2733 #define	DEBUG_TELJJY_PRINTF(sFunc)
2734 #endif
2735 
2736 /**************************************************************************************************/
2737 
2738 static int
2739 jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
2740 {
2741 
2742 	char	sLog [ 192 ], sFirstThreeDigits [ 4 ] ;
2743 	int	iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
2744 	size_t  i ;
2745 	size_t	iFirstThreeDigitsCount ;
2746 
2747 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
2748 
2749 	up->unittype  = UNITTYPE_TELEPHONE ;
2750 	up->linespeed = SPEED232_TELEPHONE ;
2751 	up->linediscipline = LDISC_RAW ;
2752 
2753 	up->pRawBreak = teljjy_raw_break ;
2754 	up->bWaitBreakString = TRUE ;
2755 
2756 	up->bSkipCntrlCharOnly = TRUE ;
2757 
2758 	up->iClockState = TELJJY_STATE_IDLE ;
2759 	up->iClockEvent = TELJJY_EVENT_NULL ;
2760 
2761 	/* Check the telephone number */
2762 
2763 	if ( sys_phone[0] == NULL ) {
2764 		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
2765 		up->bInitError = TRUE ;
2766 		return 1 ;
2767 	}
2768 
2769 	if ( sys_phone[1] != NULL ) {
2770 		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
2771 		up->bInitError = TRUE ;
2772 		return 1 ;
2773 	}
2774 
2775 	iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
2776 	for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
2777 		if ( isdigit( (u_char)sys_phone[0][i] ) ) {
2778 			if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
2779 				sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ;
2780 			}
2781 			iNumberOfDigitsOfPhoneNumber ++ ;
2782 		} else if ( sys_phone[0][i] == ',' ) {
2783 			iCommaCount ++ ;
2784 			if ( iCommaCount > 1 ) {
2785 				msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
2786 				up->bInitError = TRUE ;
2787 				return 1 ;
2788 			}
2789 			iFirstThreeDigitsCount = 0 ;
2790 			iCommaPosition = i ;
2791 		} else if ( sys_phone[0][i] != '-' ) {
2792 			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
2793 			up->bInitError = TRUE ;
2794 			return 1 ;
2795 		}
2796 	}
2797 	sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
2798 
2799 	if ( iCommaCount == 1 ) {
2800 		if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
2801 			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
2802 			up->bInitError = TRUE ;
2803 			return 1 ;
2804 		}
2805 	}
2806 
2807 	if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
2808 		/* Too short or too long */
2809 		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
2810 		up->bInitError = TRUE ;
2811 		return 1 ;
2812 	}
2813 
2814 	if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
2815 	  || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
2816 	  || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
2817 	  || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
2818 	  || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
2819 	  || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
2820 	  || ( sFirstThreeDigits[0] == '0' &&  sFirstThreeDigits[2] == '0' ) ) {
2821 		/* Not allowed because of emergency numbers or special service numbers */
2822 		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
2823 		up->bInitError = TRUE ;
2824 		return 1 ;
2825 	}
2826 
2827 	snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
2828 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2829 
2830 	if ( peer->minpoll < 8 ) {
2831 		/* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
2832 		int oldminpoll = peer->minpoll ;
2833 		peer->minpoll = 8 ;
2834 		if ( peer->ppoll < peer->minpoll ) {
2835 			peer->ppoll = peer->minpoll ;
2836 		}
2837 		if ( peer->maxpoll < peer->minpoll ) {
2838 			peer->maxpoll = peer->minpoll ;
2839 		}
2840 		snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
2841 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2842 	}
2843 
2844 	return 0 ;
2845 
2846 }
2847 
2848 /**************************************************************************************************/
2849 
2850 static int
2851 jjy_receive_telephone ( struct recvbuf *rbufp )
2852 {
2853 #ifdef DEBUG
2854 	static	const char	*sFunctionName = "jjy_receive_telephone" ;
2855 #endif
2856 
2857 	struct	peer         *peer;
2858 	struct	refclockproc *pp ;
2859 	struct	jjyunit      *up ;
2860 	char	*pBuf ;
2861 	int	iLen ;
2862 	short	iPreviousModemState ;
2863 
2864 	peer = rbufp->recv_peer ;
2865 	pp = peer->procptr ;
2866 	up = pp->unitptr ;
2867 
2868 	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2869 
2870 	if ( up->iClockState == TELJJY_STATE_IDLE
2871 	  || up->iClockState == TELJJY_STATE_DAILOUT
2872 	  || up->iClockState == TELJJY_STATE_BYE ) {
2873 
2874 		iPreviousModemState = getModemState( up ) ;
2875 
2876 		modem_receive ( rbufp ) ;
2877 
2878 		if ( iPreviousModemState != up->iModemState ) {
2879 			/* Modem state is changed just now. */
2880 			if ( isModemStateDisconnect( up->iModemState ) ) {
2881 				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2882 				teljjy_control ( peer, pp, up ) ;
2883 			} else if ( isModemStateConnect( up->iModemState ) ) {
2884 				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2885 				teljjy_control ( peer, pp, up ) ;
2886 			}
2887 		}
2888 
2889 		return JJY_RECEIVE_WAIT ;
2890 
2891 	}
2892 
2893 	if ( up->linediscipline == LDISC_RAW ) {
2894 		pBuf = up->sTextBuf ;
2895 		iLen = up->iTextBufLen ;
2896 	} else {
2897 		pBuf = pp->a_lastcode ;
2898 		iLen = pp->lencode ;
2899 	}
2900 
2901 	up->iTeljjySilentTimer = 0 ;
2902 	if      ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN  ; }
2903 	else if ( iLen == 1 && strncmp( pBuf, ">"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
2904 	else if ( iLen >= 1 && strncmp( pBuf, "?"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR  ; }
2905 	else                                                        { up->iClockEvent = TELJJY_EVENT_DATA   ; }
2906 
2907 	teljjy_control ( peer, pp, up ) ;
2908 
2909 	return JJY_RECEIVE_WAIT ;
2910 
2911 }
2912 
2913 /**************************************************************************************************/
2914 
2915 static void
2916 jjy_poll_telephone ( int unit, struct peer *peer )
2917 {
2918 #ifdef DEBUG
2919 	static const char *sFunctionName = "jjy_poll_telephone" ;
2920 #endif
2921 
2922 	struct	refclockproc *pp ;
2923 	struct	jjyunit      *up ;
2924 
2925 	pp = peer->procptr ;
2926 	up = pp->unitptr ;
2927 
2928 	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2929 
2930 	if ( up->iClockState == TELJJY_STATE_IDLE ) {
2931 		up->iRawBufLen = 0 ;
2932 		up->iLineBufLen = 0 ;
2933 		up->iTextBufLen = 0 ;
2934 	}
2935 
2936 	up->iClockEvent = TELJJY_EVENT_START ;
2937 	teljjy_control ( peer, pp, up ) ;
2938 
2939 }
2940 
2941 /**************************************************************************************************/
2942 
2943 static void
2944 jjy_timer_telephone ( int unit, struct peer *peer )
2945 {
2946 #ifdef DEBUG
2947 	static const char *sFunctionName = "jjy_timer_telephone" ;
2948 #endif
2949 
2950 	struct	refclockproc *pp ;
2951 	struct	jjyunit      *up ;
2952 	short	iPreviousModemState ;
2953 
2954 	pp = peer->procptr ;
2955 	up = pp->unitptr ;
2956 
2957 	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2958 
2959 	if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
2960 		up->iTeljjySilentTimer++ ;
2961 		if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
2962 			up->iClockEvent = TELJJY_EVENT_SILENT ;
2963 			teljjy_control ( peer, pp, up ) ;
2964 		}
2965 	}
2966 
2967 	if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
2968 		up->iTeljjyStateTimer++ ;
2969 		if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
2970 			up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
2971 			teljjy_control ( peer, pp, up ) ;
2972 		}
2973 	}
2974 
2975 	if ( isModemStateTimerOn( up ) ) {
2976 
2977 		iPreviousModemState = getModemState( up ) ;
2978 
2979 		modem_timer ( unit, peer ) ;
2980 
2981 		if ( iPreviousModemState != up->iModemState ) {
2982 			/* Modem state is changed just now. */
2983 			if ( isModemStateDisconnect( up->iModemState ) ) {
2984 				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2985 				teljjy_control ( peer, pp, up ) ;
2986 			} else if ( isModemStateConnect( up->iModemState ) ) {
2987 				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2988 				teljjy_control ( peer, pp, up ) ;
2989 			}
2990 		}
2991 
2992 	}
2993 
2994 }
2995 
2996 /**************************************************************************************************/
2997 
2998 static void
2999 teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3000 {
3001 
3002 	int	i, rc ;
3003 	short	iPostEvent = TELJJY_EVENT_NULL ;
3004 
3005 	DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
3006 
3007 	rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
3008 
3009 	if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
3010 		iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
3011 #ifdef DEBUG
3012 		if ( debug ) {
3013 			printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd  iPostEvent=%hd\n",
3014 				up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
3015 		}
3016 #endif
3017 		up->iTeljjySilentTimer = 0 ;
3018 		if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
3019 			/* Telephone JJY state is changing now */
3020 			up->iTeljjyStateTimer = 0 ;
3021 			up->bLineError = FALSE ;
3022 			up->iClockCommandSeq = 0 ;
3023 			up->iTimestampCount = 0 ;
3024 			up->iLoopbackCount = 0 ;
3025 			for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3026 				up->bLoopbackTimeout[i] = FALSE ;
3027 			}
3028 			if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
3029 				/* Telephone JJY state is changing to IDLE just now */
3030 				up->iProcessState = JJY_PROCESS_STATE_DONE ;
3031 			}
3032 		}
3033 		up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
3034 
3035 	}
3036 
3037 	if ( iPostEvent != TELJJY_EVENT_NULL ) {
3038 		up->iClockEvent = iPostEvent ;
3039 		teljjy_control ( peer, pp, up ) ;
3040 	}
3041 
3042 	up->iClockEvent = TELJJY_EVENT_NULL ;
3043 
3044 }
3045 
3046 /**************************************************************************************************/
3047 
3048 static void
3049 teljjy_setDelay ( struct peer *peer, struct jjyunit *up )
3050 {
3051 
3052 	char	sLog [ 60 ] ;
3053 	int	milliSecond, microSecond ;
3054 
3055 	gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
3056 
3057 	up->delayTime[up->iLoopbackCount].tv_sec  -= up->sendTime[up->iLoopbackCount].tv_sec ;
3058 	up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
3059 	if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
3060 		up->delayTime[up->iLoopbackCount].tv_sec -- ;
3061 		up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
3062 	}
3063 
3064 	milliSecond  = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
3065 	microSecond  = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
3066 	milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
3067 
3068 	snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
3069 		  milliSecond, microSecond ) ;
3070 
3071 	if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
3072 		/* Delay > 700 mS */
3073 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3074 	} else {
3075 		/* Delay <= 700 mS */
3076 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3077 	}
3078 
3079 }
3080 
3081 /**************************************************************************************************/
3082 
3083 static int
3084 teljjy_getDelay ( struct peer *peer, struct jjyunit *up )
3085 {
3086 
3087 	struct	timeval maxTime, minTime, averTime ;
3088 	int	i ;
3089 	int	minIndex = 0, maxIndex = 0, iAverCount = 0 ;
3090 	int	iThresholdSecond, iThresholdMicroSecond ;
3091 	int	iPercent ;
3092 
3093 	minTime.tv_sec = minTime.tv_usec = 0 ;
3094 	maxTime.tv_sec = maxTime.tv_usec = 0 ;
3095 
3096 	iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
3097 	iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
3098 
3099 	up->iLoopbackValidCount = 0 ;
3100 
3101 	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3102 		if ( up->bLoopbackTimeout[i]
3103 		  || up->delayTime[i].tv_sec  > iThresholdSecond
3104 		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3105 		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3106 			continue ;
3107 		}
3108 		if ( up->iLoopbackValidCount == 0 ) {
3109 			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3110 			minTime.tv_usec = up->delayTime[i].tv_usec ;
3111 			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3112 			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3113 			minIndex = maxIndex = i ;
3114 		} else if ( minTime.tv_sec  > up->delayTime[i].tv_sec
3115 		       || ( minTime.tv_sec == up->delayTime[i].tv_sec
3116 		         && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
3117 			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3118 			minTime.tv_usec = up->delayTime[i].tv_usec ;
3119 			minIndex = i ;
3120 		} else if ( maxTime.tv_sec  < up->delayTime[i].tv_sec
3121 		       || ( maxTime.tv_sec == up->delayTime[i].tv_sec
3122 		         && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
3123 			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3124 			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3125 			maxIndex = i ;
3126 		}
3127 		up->iLoopbackValidCount ++ ;
3128 	}
3129 
3130 	if ( up->iLoopbackValidCount < 2 ) {
3131 		return -1 ;
3132 	}
3133 
3134 	averTime.tv_usec = 0;
3135 
3136 	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3137 		if ( up->bLoopbackTimeout[i]
3138 		  || up->delayTime[i].tv_sec  > iThresholdSecond
3139 		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3140 		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3141 			continue ;
3142 		}
3143 		if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
3144 			continue ;
3145 		}
3146 		if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
3147 			continue ;
3148 		}
3149 		averTime.tv_usec += up->delayTime[i].tv_usec ;
3150 		iAverCount ++ ;
3151 	}
3152 
3153 	if ( iAverCount == 0 ) {
3154 		/* This is never happened. */
3155 		/* Previous for-if-for blocks assure iAverCount > 0. */
3156 		/* This code avoids a claim by the coverity scan tool. */
3157 		return -1 ;
3158 	}
3159 
3160 	/* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
3161 
3162 	iPercent = ( peer->ttl - 100 ) ;
3163 
3164 	/* Average delay time in milli second */
3165 
3166 	return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
3167 
3168 }
3169 
3170 /******************************/
3171 static int
3172 teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3173 {
3174 
3175 	DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
3176 
3177 	return TELJJY_STAY_CLOCK_STATE ;
3178 
3179 }
3180 
3181 /******************************/
3182 static int
3183 teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3184 {
3185 
3186 	DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
3187 
3188 	modem_connect ( peer->refclkunit, peer ) ;
3189 
3190 	return TELJJY_CHANGE_CLOCK_STATE ;
3191 
3192 }
3193 
3194 /******************************/
3195 static int
3196 teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3197 {
3198 
3199 	DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
3200 
3201 	return TELJJY_STAY_CLOCK_STATE ;
3202 
3203 }
3204 
3205 /******************************/
3206 static int
3207 teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3208 {
3209 
3210 	DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
3211 
3212 	return TELJJY_CHANGE_CLOCK_STATE ;
3213 
3214 }
3215 
3216 /******************************/
3217 static int
3218 teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3219 {
3220 
3221 	DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
3222 
3223 	return TELJJY_CHANGE_CLOCK_STATE ;
3224 
3225 }
3226 
3227 /******************************/
3228 static int
3229 teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3230 {
3231 
3232 	DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
3233 
3234 	return TELJJY_STAY_CLOCK_STATE ;
3235 
3236 }
3237 
3238 /******************************/
3239 static int
3240 teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3241 {
3242 
3243 	DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
3244 
3245 	return TELJJY_CHANGE_CLOCK_STATE ;
3246 
3247 }
3248 
3249 /******************************/
3250 static int
3251 teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3252 {
3253 
3254 	int	i ;
3255 
3256 	DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
3257 
3258 	up->bLineError = FALSE ;
3259 	up->iClockCommandSeq = 0 ;
3260 	up->iTimestampCount = 0 ;
3261 	up->iLoopbackCount = 0 ;
3262 	for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3263 		up->bLoopbackTimeout[i] = FALSE ;
3264 	}
3265 
3266 	return TELJJY_CHANGE_CLOCK_STATE ;
3267 
3268 }
3269 
3270 /******************************/
3271 static int
3272 teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3273 {
3274 
3275 	const char *	pCmd ;
3276 	int		iCmdLen ;
3277 
3278 	DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
3279 
3280 	/* Send a guest user ID */
3281 	pCmd = "TJJY\r" ;
3282 
3283 	/* Send login ID */
3284 	iCmdLen = strlen( pCmd ) ;
3285 	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
3286 		refclock_report( peer, CEVNT_FAULT ) ;
3287 	}
3288 
3289 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3290 
3291 	return TELJJY_STAY_CLOCK_STATE ;
3292 
3293 }
3294 
3295 /******************************/
3296 static int
3297 teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3298 {
3299 
3300 	DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
3301 
3302 	if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
3303 		refclock_report( peer, CEVNT_FAULT ) ;
3304 	}
3305 
3306 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
3307 
3308 	up->iTeljjySilentTimer = 0 ;
3309 
3310 	return TELJJY_CHANGE_CLOCK_STATE ;
3311 
3312 }
3313 
3314 /******************************/
3315 static int
3316 teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3317 {
3318 
3319 	DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
3320 
3321 	return TELJJY_CHANGE_CLOCK_STATE ;
3322 
3323 }
3324 
3325 /******************************/
3326 static int
3327 teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3328 {
3329 
3330 	DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
3331 
3332 	return TELJJY_STAY_CLOCK_STATE ;
3333 
3334 }
3335 
3336 /******************************/
3337 static int
3338 teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3339 {
3340 
3341 	DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
3342 
3343 	return TELJJY_CHANGE_CLOCK_STATE ;
3344 
3345 }
3346 
3347 /******************************/
3348 static int
3349 teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3350 {
3351 
3352 	const char *	pCmd ;
3353 	int		i, iLen, iNextClockState ;
3354 	char	sLog [ 120 ] ;
3355 
3356 	DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
3357 
3358 	if ( up->iClockCommandSeq > 0
3359 	  && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
3360 		/* Command sequence has been completed */
3361 	  	return TELJJY_CHANGE_CLOCK_STATE ;
3362 	}
3363 
3364 	if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
3365 		/* Skip loopback */
3366 
3367 		up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
3368 
3369 	} else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
3370 		/* Loopback start */
3371 
3372 		up->iLoopbackCount = 0 ;
3373 		for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3374 			up->bLoopbackTimeout[i] = FALSE ;
3375 		}
3376 
3377 	} else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
3378 		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3379 		 && up->iLoopbackCount < MAX_LOOPBACK ) {
3380 		/* Loopback character comes */
3381 #ifdef DEBUG
3382 		if ( debug ) {
3383 			printf( "refclock_jjy.c : teljjy_conn_send : iClockCommandSeq=%d iLoopbackCount=%d\n",
3384 				 up->iClockCommandSeq, up->iLoopbackCount ) ;
3385 		}
3386 #endif
3387 
3388 		teljjy_setDelay( peer, up ) ;
3389 
3390 		up->iLoopbackCount ++ ;
3391 
3392 	}
3393 
3394 	up->iClockCommandSeq++ ;
3395 
3396 	pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
3397 	iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
3398 
3399 	if ( pCmd != NULL ) {
3400 
3401 		if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
3402 			refclock_report( peer, CEVNT_FAULT ) ;
3403 		}
3404 
3405 		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3406 			/* Loopback character and timestamp */
3407 			if ( up->iLoopbackCount < MAX_LOOPBACK ) {
3408 				gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
3409 				up->bLoopbackMode = TRUE ;
3410 			} else {
3411 				/* This else-block is never come. */
3412 				/* This code avoid wrong report of the coverity static analysis scan tool. */
3413 				snprintf( sLog, sizeof(sLog)-1, "refclock_jjy.c ; teljjy_conn_send ; iClockCommandSeq=%d iLoopbackCount=%d MAX_LOOPBACK=%d",
3414 					  up->iClockCommandSeq, up->iLoopbackCount, MAX_LOOPBACK ) ;
3415 				jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_BUG, sLog ) ;
3416 				msyslog ( LOG_ERR, "%s", sLog ) ;
3417 				up->bLoopbackMode = FALSE ;
3418 			}
3419 		} else {
3420 			/* Regular command */
3421 			up->bLoopbackMode = FALSE ;
3422 		}
3423 
3424 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3425 
3426 		if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
3427 			/* Last command of the command sequence */
3428 			iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3429 		} else {
3430 			/* More commands to be issued */
3431 			iNextClockState = TELJJY_STAY_CLOCK_STATE ;
3432 		}
3433 
3434 	} else {
3435 
3436 		iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3437 
3438 	}
3439 
3440 	return iNextClockState ;
3441 
3442 }
3443 
3444 /******************************/
3445 static int
3446 teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3447 {
3448 
3449 	char	*pBuf ;
3450 	int	iLen, rc ;
3451 	char	sLog [ MAX_LOGTEXT ] ;
3452 	char	bAdjustment ;
3453 
3454 
3455 	DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
3456 
3457 	if ( up->linediscipline == LDISC_RAW ) {
3458 		pBuf = up->sTextBuf ;
3459 		iLen = up->iTextBufLen ;
3460 	} else {
3461 		pBuf = pp->a_lastcode ;
3462 		iLen = pp->lencode ;
3463 	}
3464 
3465 	if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3466 	  && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3467 	  && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
3468 	  && up->iLoopbackCount < MAX_LOOPBACK ) {
3469 		/* Loopback */
3470 
3471 		teljjy_setDelay( peer, up ) ;
3472 
3473 		up->iLoopbackCount ++ ;
3474 
3475 	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3476 	    && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
3477 		/* Maybe echoback */
3478 
3479 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
3480 
3481 	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3482 		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
3483 		/* 4DATE<CR> -> YYYYMMDD<CR> */
3484 
3485 		rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
3486 
3487 		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
3488 		  || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
3489 			/* Invalid date */
3490 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
3491 				  rc, up->year, up->month, up->day ) ;
3492 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3493 			up->bLineError = TRUE ;
3494 		}
3495 
3496 	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3497 		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
3498 	         && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
3499 		/* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
3500 
3501 		rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
3502 
3503 		if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
3504 			/* Invalid leap second */
3505 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
3506 				  pBuf ) ;
3507 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3508 			up->bLineError = TRUE ;
3509 		}
3510 
3511 	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3512 		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
3513 		/* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
3514 
3515 		rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
3516 
3517 		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
3518 			/* Invalid time */
3519 			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
3520 				  rc, up->hour, up->minute, up->second ) ;
3521 			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3522 			up->bLineError = TRUE ;
3523 		}
3524 		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
3525 
3526 		up->iTimestampCount++ ;
3527 
3528 		if ( up->iTimestampCount == 6 && ! up->bLineError ) {
3529 #if DEBUG
3530 			printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
3531 				up->bLineError,
3532 				up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
3533 #endif
3534 			bAdjustment = TRUE ;
3535 
3536 			if ( peer->ttl == 100 ) {
3537 				/* mode=100 */
3538 				up->msecond = 0 ;
3539 			} else {
3540 				/* mode=101 to 110 */
3541 				up->msecond = teljjy_getDelay( peer, up ) ;
3542 				if (up->msecond < 0 ) {
3543 					up->msecond = 0 ;
3544 					bAdjustment = FALSE ;
3545 				}
3546 			}
3547 
3548 			if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
3549 			  &&   up->iTimestamp[2]        <= up->iTimestamp[3]
3550 			  && ( up->iTimestamp[3] +  1 ) == up->iTimestamp[4]
3551 			  && ( up->iTimestamp[4] +  1 ) == up->iTimestamp[5] ) {
3552 				/* Non over midnight */
3553 
3554 				jjy_synctime( peer, pp, up ) ;
3555 
3556 				if ( peer->ttl != 100 ) {
3557 					if ( bAdjustment ) {
3558 						snprintf( sLog, sizeof(sLog),
3559 							  JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
3560 							  up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3561 						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3562 					} else {
3563 						snprintf( sLog, sizeof(sLog),
3564 							  JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
3565 							   up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3566 						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3567 					}
3568 				}
3569 
3570 			}
3571 		}
3572 
3573 	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
3574 		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3575 		/* Loopback noise ( Unexpected replay ) */
3576 
3577 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
3578 			  pBuf ) ;
3579 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3580 
3581 	} else {
3582 
3583 		up->bLineError = TRUE ;
3584 
3585 		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
3586 			  pBuf ) ;
3587 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3588 
3589 	}
3590 
3591 	return TELJJY_STAY_CLOCK_STATE ;
3592 
3593 }
3594 
3595 /******************************/
3596 static int
3597 teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3598 {
3599 
3600 	const char *	pCmd ;
3601 
3602 	DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
3603 
3604 	if ( up->iClockCommandSeq >= 1
3605 	  && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
3606 		/* Loopback */
3607 #ifdef DEBUG
3608 		if ( debug ) {
3609 			printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
3610 		}
3611 #endif
3612 		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3613 			up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
3614 		}
3615 		up->iTeljjySilentTimer = 0 ;
3616 		return teljjy_conn_send( peer, pp, up ) ;
3617 	} else {
3618 		pCmd = "\r" ;
3619 	}
3620 
3621 	if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
3622 		refclock_report( peer, CEVNT_FAULT ) ;
3623 	}
3624 
3625 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3626 
3627 	up->iTeljjySilentTimer = 0 ;
3628 
3629 	return TELJJY_STAY_CLOCK_STATE ;
3630 
3631 }
3632 
3633 /******************************/
3634 static int
3635 teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3636 {
3637 
3638 	DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
3639 
3640 	return TELJJY_CHANGE_CLOCK_STATE ;
3641 
3642 }
3643 
3644 /******************************/
3645 static int
3646 teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3647 {
3648 
3649 	DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
3650 
3651 	return TELJJY_STAY_CLOCK_STATE ;
3652 
3653 }
3654 
3655 /******************************/
3656 static int
3657 teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3658 {
3659 
3660 	DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
3661 
3662 	return TELJJY_CHANGE_CLOCK_STATE ;
3663 
3664 }
3665 
3666 /******************************/
3667 static int
3668 teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3669 {
3670 
3671 	DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
3672 
3673 	modem_disconnect ( peer->refclkunit, peer ) ;
3674 
3675 	return TELJJY_STAY_CLOCK_STATE ;
3676 
3677 }
3678 
3679 /*################################################################################################*/
3680 /*################################################################################################*/
3681 /*##												##*/
3682 /*##    Modem control finite state machine							##*/
3683 /*##												##*/
3684 /*################################################################################################*/
3685 /*################################################################################################*/
3686 
3687 /* struct jjyunit.iModemState */
3688 
3689 #define	MODEM_STATE_DISCONNECT		0
3690 #define	MODEM_STATE_INITIALIZE		1
3691 #define	MODEM_STATE_DAILING		2
3692 #define	MODEM_STATE_CONNECT		3
3693 #define	MODEM_STATE_ESCAPE		4
3694 
3695 /* struct jjyunit.iModemEvent */
3696 
3697 #define MODEM_EVENT_NULL		0
3698 #define	MODEM_EVENT_INITIALIZE		1
3699 #define	MODEM_EVENT_DIALOUT		2
3700 #define	MODEM_EVENT_DISCONNECT		3
3701 #define	MODEM_EVENT_RESP_OK		4
3702 #define	MODEM_EVENT_RESP_CONNECT	5
3703 #define	MODEM_EVENT_RESP_RING		6
3704 #define	MODEM_EVENT_RESP_NO_CARRIER	7
3705 #define	MODEM_EVENT_RESP_ERROR		8
3706 #define	MODEM_EVENT_RESP_CONNECT_X	9
3707 #define	MODEM_EVENT_RESP_NO_DAILTONE	10
3708 #define	MODEM_EVENT_RESP_BUSY		11
3709 #define	MODEM_EVENT_RESP_NO_ANSWER	12
3710 #define	MODEM_EVENT_RESP_UNKNOWN	13
3711 #define	MODEM_EVENT_SILENT		14
3712 #define	MODEM_EVENT_TIMEOUT		15
3713 
3714 /* Function prototypes */
3715 
3716 static	void	modem_control		( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3717 
3718 static	int 	modem_disc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3719 static	int 	modem_disc_init  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3720 static	int 	modem_init_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3721 static	int 	modem_init_start 	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3722 static	int 	modem_init_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3723 static	int 	modem_init_resp00	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3724 static	int 	modem_init_resp04	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3725 static	int 	modem_dial_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3726 static	int 	modem_dial_dialout	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3727 static	int 	modem_dial_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3728 static	int 	modem_dial_connect	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3729 static	int 	modem_dial_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3730 static	int 	modem_conn_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3731 static	int 	modem_conn_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3732 static	int 	modem_esc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3733 static	int 	modem_esc_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3734 static	int 	modem_esc_data  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3735 static	int 	modem_esc_silent	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3736 static	int 	modem_esc_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3737 
3738 static int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) =
3739 {                         	/*STATE_DISCONNECT   STATE_INITIALIZE   STATE_DAILING       STATE_CONNECT      STATE_ESCAPE     */
3740 /* NULL                 */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3741 /* INITIALIZE           */	{ modem_disc_init  , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3742 /* DIALOUT              */	{ modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
3743 /* DISCONNECT           */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_escape },
3744 /* RESP: 0: OK          */	{ modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3745 /* RESP: 1: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3746 /* RESP: 2: RING        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3747 /* RESP: 3: NO CARRIER  */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3748 /* RESP: 4: ERROR       */	{ modem_disc_ignore, modem_init_resp04, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3749 /* RESP: 5: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3750 /* RESP: 6: NO DAILTONE */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3751 /* RESP: 7: BUSY        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3752 /* RESP: 8: NO ANSWER   */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3753 /* RESP: 9: UNKNOWN     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3754 /* SILENT               */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
3755 /* TIMEOUT              */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_disc   }
3756 } ;
3757 
3758 static short iModemNextState [ ] [ 5 ] =
3759 {                         	/*STATE_DISCONNECT        STATE_INITIALIZE        STATE_DAILING        STATE_CONNECT        STATE_ESCAPE           */
3760 /* NULL                 */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3761 /* INITIALIZE           */	{ MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3762 /* DIALOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3763 /* DISCONNECT           */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE     },
3764 /* RESP: 0: OK          */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3765 /* RESP: 1: CONNECT     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3766 /* RESP: 2: RING        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3767 /* RESP: 3: NO CARRIER  */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3768 /* RESP: 4: ERROR       */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3769 /* RESP: 5: CONNECT X   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3770 /* RESP: 6: NO DAILTONE */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3771 /* RESP: 7: BUSY        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3772 /* RESP: 8: NO ANSWER   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3773 /* RESP: 9: UNKNOWN     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3774 /* SILENT               */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
3775 /* TIMEOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
3776 } ;
3777 
3778 static short iModemPostEvent [ ] [ 5 ] =
3779 {                         	/*STATE_DISCONNECT        STATE_INITIALIZE     STATE_DAILING           STATE_CONNECT           STATE_ESCAPE     */
3780 /* NULL                 */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3781 /* INITIALIZE           */	{ MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3782 /* DIALOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3783 /* DISCONNECT           */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
3784 /* RESP: 0: OK          */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3785 /* RESP: 1: CONNECT     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3786 /* RESP: 2: RING        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3787 /* RESP: 3: NO CARRIER  */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3788 /* RESP: 4: ERROR       */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3789 /* RESP: 5: CONNECT X   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3790 /* RESP: 6: NO DAILTONE */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3791 /* RESP: 7: BUSY        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3792 /* RESP: 8: NO ANSWER   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3793 /* RESP: 9: UNKNOWN     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3794 /* SILENT               */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3795 /* TIMEOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
3796 } ;
3797 
3798 static short iModemSilentTimeout [ 5 ] = { 0,  0,  0, 0,  5 } ;
3799 static short iModemStateTimeout  [ 5 ] = { 0, 20, 90, 0, 20 } ;
3800 
3801 #define	STAY_MODEM_STATE	0
3802 #define	CHANGE_MODEM_STATE	1
3803 
3804 #ifdef	DEBUG
3805 #define	DEBUG_MODEM_PRINTF(sFunc)	{ if ( debug ) { printf ( "refclock_jjy.c : %s : iModemState=%d iModemEvent=%d iModemSilentTimer=%d iModemStateTimer=%d\n", sFunc, up->iModemState, up->iModemEvent, up->iModemSilentTimer, up->iModemStateTimer ) ; } }
3806 #else
3807 #define	DEBUG_MODEM_PRINTF(sFunc)
3808 #endif
3809 
3810 /**************************************************************************************************/
3811 
3812 static short
3813 getModemState ( struct jjyunit *up )
3814 {
3815 	return up->iModemState ;
3816 }
3817 
3818 /**************************************************************************************************/
3819 
3820 static int
3821 isModemStateConnect ( short iCheckState )
3822 {
3823 	return ( iCheckState == MODEM_STATE_CONNECT ) ;
3824 }
3825 
3826 /**************************************************************************************************/
3827 
3828 static int
3829 isModemStateDisconnect ( short iCheckState )
3830 {
3831 	return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
3832 }
3833 
3834 /**************************************************************************************************/
3835 
3836 static int
3837 isModemStateTimerOn ( struct jjyunit *up )
3838 {
3839 	return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
3840 }
3841 
3842 /**************************************************************************************************/
3843 
3844 static void
3845 modem_connect ( int unit, struct peer *peer )
3846 {
3847 	struct	refclockproc	*pp;
3848 	struct	jjyunit 	*up;
3849 
3850 	pp = peer->procptr ;
3851 	up = pp->unitptr ;
3852 
3853 	DEBUG_MODEM_PRINTF( "modem_connect" ) ;
3854 
3855 	up->iModemEvent = MODEM_EVENT_INITIALIZE ;
3856 
3857 	modem_control ( peer, pp, up ) ;
3858 
3859 }
3860 
3861 /**************************************************************************************************/
3862 
3863 static void
3864 modem_disconnect ( int unit, struct peer *peer )
3865 {
3866 	struct	refclockproc	*pp;
3867 	struct	jjyunit 	*up;
3868 
3869 	pp = peer->procptr ;
3870 	up = pp->unitptr ;
3871 
3872 	DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
3873 
3874 	up->iModemEvent = MODEM_EVENT_DISCONNECT ;
3875 
3876 	modem_control ( peer, pp, up ) ;
3877 
3878 }
3879 
3880 /**************************************************************************************************/
3881 
3882 static int
3883 modem_receive ( struct recvbuf *rbufp )
3884 {
3885 
3886 	struct	peer		*peer;
3887 	struct	jjyunit		*up;
3888 	struct	refclockproc	*pp;
3889 	char	*pBuf ;
3890 	size_t	iLen ;
3891 
3892 #ifdef DEBUG
3893 	static const char *sFunctionName = "modem_receive" ;
3894 #endif
3895 
3896 	peer = rbufp->recv_peer ;
3897 	pp = peer->procptr ;
3898 	up = pp->unitptr ;
3899 
3900 	DEBUG_MODEM_PRINTF( sFunctionName ) ;
3901 
3902 	if ( up->linediscipline == LDISC_RAW ) {
3903 		pBuf = up->sTextBuf ;
3904 		iLen = up->iTextBufLen ;
3905 	} else {
3906 		pBuf = pp->a_lastcode ;
3907 		iLen = pp->lencode ;
3908 	}
3909 
3910 	if      ( iLen ==  2 && strncmp( pBuf, "OK"         ,  2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK          ; }
3911 	else if ( iLen ==  7 && strncmp( pBuf, "CONNECT"    ,  7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT     ; }
3912 	else if ( iLen ==  4 && strncmp( pBuf, "RING"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING        ; }
3913 	else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER  ; }
3914 	else if ( iLen ==  5 && strncmp( pBuf, "ERROR"      ,  5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR       ; }
3915 	else if ( iLen >=  8 && strncmp( pBuf, "CONNECT "   ,  8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X   ; }
3916 	else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
3917 	else if ( iLen ==  4 && strncmp( pBuf, "BUSY"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY        ; }
3918 	else if ( iLen ==  9 && strncmp( pBuf, "NO ANSWER"  ,  9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER   ; }
3919 	else                                                              { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN     ; }
3920 
3921 #ifdef DEBUG
3922 	if ( debug ) {
3923 		char	sResp [ 40 ] ;
3924 		size_t	iCopyLen ;
3925 		iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3926 		strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3927 		sResp[iCopyLen] = 0 ;
3928 		printf ( "refclock_jjy.c : modem_receive : iLen=%zu pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
3929 	}
3930 #endif
3931 	modem_control ( peer, pp, up ) ;
3932 
3933 	return 0 ;
3934 
3935 }
3936 
3937 /**************************************************************************************************/
3938 
3939 static void
3940 modem_timer ( int unit, struct peer *peer )
3941 {
3942 
3943 	struct	refclockproc *pp ;
3944 	struct	jjyunit      *up ;
3945 
3946 	pp = peer->procptr ;
3947 	up = pp->unitptr ;
3948 
3949 	DEBUG_MODEM_PRINTF( "modem_timer" ) ;
3950 
3951 	if ( iModemSilentTimeout[up->iModemState] != 0 ) {
3952 		up->iModemSilentTimer++ ;
3953 		if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
3954 			up->iModemEvent = MODEM_EVENT_SILENT ;
3955 			modem_control ( peer, pp, up ) ;
3956 		}
3957 	}
3958 
3959 	if ( iModemStateTimeout[up->iModemState] != 0 ) {
3960 		up->iModemStateTimer++ ;
3961 		if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
3962 			up->iModemEvent = MODEM_EVENT_TIMEOUT ;
3963 			modem_control ( peer, pp, up ) ;
3964 		}
3965 	}
3966 
3967 }
3968 
3969 /**************************************************************************************************/
3970 
3971 static void
3972 modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3973 {
3974 
3975 	int	rc ;
3976 	short	iPostEvent = MODEM_EVENT_NULL ;
3977 
3978 	DEBUG_MODEM_PRINTF( "modem_control" ) ;
3979 
3980 	rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
3981 
3982 	if ( rc == CHANGE_MODEM_STATE ) {
3983 		iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
3984 #ifdef DEBUG
3985 		if ( debug ) {
3986 			printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d  iPostEvent=%d\n",
3987 				 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
3988 		}
3989 #endif
3990 
3991 		if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
3992 			up->iModemSilentCount = 0 ;
3993 			up->iModemStateTimer = 0 ;
3994 			up->iModemCommandSeq = 0 ;
3995 		}
3996 
3997 		up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
3998 	}
3999 
4000 	if ( iPostEvent != MODEM_EVENT_NULL ) {
4001 		up->iModemEvent = iPostEvent ;
4002 		modem_control ( peer, pp, up ) ;
4003 	}
4004 
4005 	up->iModemEvent = MODEM_EVENT_NULL ;
4006 
4007 }
4008 
4009 /******************************/
4010 static int
4011 modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4012 {
4013 
4014 	DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
4015 
4016 	return STAY_MODEM_STATE ;
4017 
4018 }
4019 
4020 /******************************/
4021 static int
4022 modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4023 {
4024 
4025 	DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
4026 
4027 	return CHANGE_MODEM_STATE ;
4028 
4029 }
4030 
4031 /******************************/
4032 static int
4033 modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4034 {
4035 
4036 	DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
4037 
4038 	return STAY_MODEM_STATE ;
4039 
4040 }
4041 
4042 /******************************/
4043 static int
4044 modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4045 {
4046 
4047 	DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
4048 
4049 	up->iModemCommandSeq = 0 ;
4050 
4051 #ifdef DEBUG
4052 	if ( debug ) {
4053 		printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
4054 	}
4055 #endif
4056 
4057 	return modem_init_resp00( peer, pp, up ) ;
4058 
4059 }
4060 
4061 /******************************/
4062 static int
4063 modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4064 {
4065 
4066 	const char *	pCmd ;
4067 	char		cBuf [ 46 ] ;
4068 	int		iCmdLen ;
4069 	int		iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
4070 	int		iNextModemState = STAY_MODEM_STATE ;
4071 
4072 	DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
4073 
4074 	up->iModemCommandSeq++ ;
4075 
4076 	switch ( up->iModemCommandSeq ) {
4077 
4078 	case 1 :
4079 		/* En = Echoback      0:Off      1:On   */
4080 		/* Qn = Result codes  0:On       1:Off  */
4081 		/* Vn = Result codes  0:Numeric  1:Text */
4082 		pCmd = "ATE0Q0V1\r\n" ;
4083 		break ;
4084 
4085 	case 2 :
4086 		/* Mn = Speaker switch  0:Off  1:On until remote carrier detected  2:On */
4087 		if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
4088 			/* fudge 127.127.40.n flag3 0 */
4089 			iSpeakerSwitch = 0 ;
4090 		} else {
4091 			/* fudge 127.127.40.n flag3 1 */
4092 			iSpeakerSwitch = 2 ;
4093 		}
4094 
4095 		/* Ln = Speaker volume  0:Very low  1:Low  2:Middle  3:High */
4096 		if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
4097 			/* fudge 127.127.40.n flag4 0 */
4098 			iSpeakerVolume = 1 ;
4099 		} else {
4100 			/* fudge 127.127.40.n flag4 1 */
4101 			iSpeakerVolume = 2 ;
4102 		}
4103 
4104 		pCmd = cBuf ;
4105 		snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
4106 		break ;
4107 
4108 	case 3 :
4109 		/* &Kn = Flow control  4:XON/XOFF */
4110 		pCmd = "AT&K4\r\n" ;
4111 		break ;
4112 
4113 	case 4 :
4114 		/* +MS = Protocol  V22B:1200,2400bps�iV.22bis) */
4115 		pCmd = "AT+MS=V22B\r\n" ;
4116 		break ;
4117 
4118 	case 5 :
4119 		/* %Cn = Data compression  0:No data compression */
4120 		pCmd = "AT%C0\r\n" ;
4121 		break ;
4122 
4123 	case 6 :
4124 		/* \Nn = Error correction  0:Normal mode  1:Direct mode  2:V42,MNP  3:V42,MNP,Normal */
4125 		if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
4126 			/* fudge 127.127.40.n flag2 0 */
4127 			iErrorCorrection = 0 ;
4128 		} else {
4129 			/* fudge 127.127.40.n flag2 1 */
4130 			iErrorCorrection = 3 ;
4131 		}
4132 
4133 		pCmd = cBuf ;
4134 		snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
4135 		break ;
4136 
4137 	case 7 :
4138 		/* Hn = Hook  0:Hook-On ( Disconnect )  1:Hook-Off ( Connect ) */
4139 		pCmd = "ATH1\r\n" ;
4140 		break ;
4141 
4142 	case 8 :
4143 		/* Initialize completion */
4144 		pCmd = NULL ;
4145 		iNextModemState = CHANGE_MODEM_STATE ;
4146 		break ;
4147 
4148 	default :
4149 		pCmd = NULL ;
4150 		break ;
4151 
4152 	}
4153 
4154 	if ( pCmd != NULL ) {
4155 
4156 		iCmdLen = strlen( pCmd ) ;
4157 		if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4158 			refclock_report( peer, CEVNT_FAULT ) ;
4159 		}
4160 
4161 		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4162 
4163 	}
4164 
4165 	return iNextModemState ;
4166 
4167 }
4168 
4169 /******************************/
4170 static int
4171 modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4172 {
4173 
4174 	DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
4175 
4176 	return modem_init_resp00( peer, pp, up ) ;
4177 
4178 }
4179 
4180 /******************************/
4181 static int
4182 modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4183 {
4184 
4185 	DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
4186 #ifdef DEBUG
4187 	if ( debug ) {
4188 		printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
4189 	}
4190 #endif
4191 
4192 	return CHANGE_MODEM_STATE ;
4193 
4194 }
4195 
4196 /******************************/
4197 static int
4198 modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4199 {
4200 
4201 	DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
4202 
4203 	return STAY_MODEM_STATE ;
4204 
4205 }
4206 
4207 /******************************/
4208 static int
4209 modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4210 {
4211 
4212 	char	sCmd [ 46 ] ;
4213 	int	iCmdLen ;
4214 	char	cToneOrPulse ;
4215 
4216 	DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
4217 
4218 	/* Tone or Pulse */
4219 	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
4220 		/* fudge 127.127.40.n flag1 0 */
4221 		cToneOrPulse = 'T' ;
4222 	} else {
4223 		/* fudge 127.127.40.n flag1 1 */
4224 		cToneOrPulse = 'P' ;
4225 	}
4226 
4227 	/* Connect ( Dial number ) */
4228 	snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
4229 
4230 	/* Send command */
4231 	iCmdLen = strlen( sCmd ) ;
4232 	if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
4233 		refclock_report( peer, CEVNT_FAULT ) ;
4234 	}
4235 
4236 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
4237 
4238 	return STAY_MODEM_STATE ;
4239 
4240 }
4241 
4242 /******************************/
4243 static int
4244 modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4245 {
4246 
4247 	DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
4248 #ifdef DEBUG
4249 	if ( debug ) {
4250 		printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
4251 	}
4252 #endif
4253 
4254 	return modem_conn_escape( peer, pp, up ) ;
4255 
4256 }
4257 
4258 /******************************/
4259 static int
4260 modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4261 {
4262 
4263 	DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
4264 
4265 	return CHANGE_MODEM_STATE ;
4266 
4267 }
4268 
4269 /******************************/
4270 static int
4271 modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4272 {
4273 
4274 	DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
4275 #ifdef DEBUG
4276 	if ( debug ) {
4277 		printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
4278 	}
4279 #endif
4280 
4281 	modem_esc_disc( peer, pp, up ) ;
4282 
4283 	return CHANGE_MODEM_STATE ;
4284 
4285 }
4286 
4287 /******************************/
4288 static int
4289 modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4290 {
4291 
4292 	DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
4293 
4294 	return STAY_MODEM_STATE ;
4295 
4296 }
4297 
4298 /******************************/
4299 static int
4300 modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4301 {
4302 
4303 	DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
4304 
4305 	return CHANGE_MODEM_STATE ;
4306 
4307 }
4308 
4309 /******************************/
4310 static int
4311 modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4312 {
4313 
4314 	DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
4315 
4316 	return STAY_MODEM_STATE ;
4317 
4318 }
4319 
4320 /******************************/
4321 static int
4322 modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4323 {
4324 
4325 	const char *	pCmd ;
4326 	int		iCmdLen ;
4327 
4328 	DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
4329 
4330 	/* Escape command ( Go to command mode ) */
4331 	pCmd = "+++" ;
4332 
4333 	/* Send command */
4334 	iCmdLen = strlen( pCmd ) ;
4335 	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4336 		refclock_report( peer, CEVNT_FAULT ) ;
4337 	}
4338 
4339 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4340 
4341 	return STAY_MODEM_STATE ;
4342 
4343 }
4344 
4345 /******************************/
4346 static int
4347 modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4348 {
4349 
4350 	DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
4351 
4352 	up->iModemSilentTimer = 0 ;
4353 
4354 	return STAY_MODEM_STATE ;
4355 
4356 }
4357 
4358 /******************************/
4359 static int
4360 modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4361 {
4362 
4363 	DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
4364 
4365 	up->iModemSilentCount ++ ;
4366 
4367 	if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
4368 #ifdef DEBUG
4369 		if ( debug ) {
4370 			printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
4371 		}
4372 #endif
4373 		modem_esc_escape( peer, pp, up ) ;
4374 		up->iModemSilentTimer = 0 ;
4375 		return STAY_MODEM_STATE ;
4376 	}
4377 
4378 #ifdef DEBUG
4379 	if ( debug ) {
4380 		printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
4381 	}
4382 #endif
4383 	return modem_esc_disc( peer, pp, up ) ;
4384 
4385 }
4386 /******************************/
4387 static int
4388 modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4389 {
4390 
4391 	const char *	pCmd ;
4392 	int		iCmdLen ;
4393 
4394 	DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
4395 
4396 	/* Disconnect */
4397 	pCmd = "ATH0\r\n" ;
4398 
4399 	/* Send command */
4400 	iCmdLen = strlen( pCmd ) ;
4401 	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4402 		refclock_report( peer, CEVNT_FAULT ) ;
4403 	}
4404 
4405 	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4406 
4407 	return CHANGE_MODEM_STATE ;
4408 
4409 }
4410 
4411 /*################################################################################################*/
4412 /*################################################################################################*/
4413 /*##												##*/
4414 /*##    jjy_write_clockstats									##*/
4415 /*##												##*/
4416 /*################################################################################################*/
4417 /*################################################################################################*/
4418 
4419 static void
4420 jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
4421 {
4422 
4423 	char		sLog [ 100 ] ;
4424 	const char *	pMark ;
4425 	int 		iMarkLen, iDataLen ;
4426 
4427 	switch ( iMark ) {
4428 	case JJY_CLOCKSTATS_MARK_JJY :
4429 		pMark = "JJY " ;
4430 		break ;
4431 	case JJY_CLOCKSTATS_MARK_SEND :
4432 		pMark = "--> " ;
4433 		break ;
4434 	case JJY_CLOCKSTATS_MARK_RECEIVE :
4435 		pMark = "<-- " ;
4436 		break ;
4437 	case JJY_CLOCKSTATS_MARK_INFORMATION :
4438 		pMark = "--- " ;
4439 		break ;
4440 	case JJY_CLOCKSTATS_MARK_ATTENTION :
4441 		pMark = "=== " ;
4442 		break ;
4443 	case JJY_CLOCKSTATS_MARK_WARNING :
4444 		pMark = "-W- " ;
4445 		break ;
4446 	case JJY_CLOCKSTATS_MARK_ERROR :
4447 		pMark = "-X- " ;
4448 		break ;
4449 	case JJY_CLOCKSTATS_MARK_BUG :
4450 		pMark = "!!! " ;
4451 		break ;
4452 	default :
4453 		pMark = "" ;
4454 		break ;
4455 	}
4456 
4457 	iDataLen = strlen( pData ) ;
4458 	iMarkLen = strlen( pMark ) ;
4459 	strcpy( sLog, pMark ) ; /* Harmless because of enough length */
4460 	printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
4461 
4462 #ifdef DEBUG
4463 	if ( debug ) {
4464 		printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
4465 	}
4466 #endif
4467 	record_clock_stats( &peer->srcadr, sLog ) ;
4468 
4469 }
4470 
4471 /*################################################################################################*/
4472 /*################################################################################################*/
4473 /*##												##*/
4474 /*##    printableString										##*/
4475 /*##												##*/
4476 /*################################################################################################*/
4477 /*################################################################################################*/
4478 
4479 static void
4480 printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
4481 {
4482 	const char	*printableControlChar[] = {
4483 			"<NUL>", "<SOH>", "<STX>", "<ETX>",
4484 			"<EOT>", "<ENQ>", "<ACK>", "<BEL>",
4485 			"<BS>" , "<HT>" , "<LF>" , "<VT>" ,
4486 			"<FF>" , "<CR>" , "<SO>" , "<SI>" ,
4487 			"<DLE>", "<DC1>", "<DC2>", "<DC3>",
4488 			"<DC4>", "<NAK>", "<SYN>", "<ETB>",
4489 			"<CAN>", "<EM>" , "<SUB>", "<ESC>",
4490 			"<FS>" , "<GS>" , "<RS>" , "<US>" ,
4491 			" " } ;
4492 
4493 	size_t	i, j, n ;
4494 	size_t	InputLen;
4495 	size_t	OutputLen;
4496 
4497 	InputLen = (size_t)iInputLen;
4498 	OutputLen = (size_t)iOutputLen;
4499 	for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
4500 		if ( isprint( (unsigned char)sInput[i] ) ) {
4501 			n = 1 ;
4502 			if ( j + 1 >= OutputLen )
4503 				break ;
4504 			sOutput[j] = sInput[i] ;
4505 		} else if ( ( sInput[i] & 0xFF ) <
4506 			    COUNTOF(printableControlChar) ) {
4507 			n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
4508 			if ( j + n + 1 >= OutputLen )
4509 				break ;
4510 			strlcpy( sOutput + j,
4511 				 printableControlChar[sInput[i] & 0xFF],
4512 				 OutputLen - j ) ;
4513 		} else {
4514 			n = 5 ;
4515 			if ( j + n + 1 >= OutputLen )
4516 				break ;
4517 			snprintf( sOutput + j, OutputLen - j, "<x%X>",
4518 				  sInput[i] & 0xFF ) ;
4519 		}
4520 		j += n ;
4521 	}
4522 
4523 	sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
4524 
4525 }
4526 
4527 /**************************************************************************************************/
4528 
4529 #else
4530 int refclock_jjy_bs ;
4531 #endif /* REFCLOCK */
4532