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