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