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