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