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