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