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