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