refclock_jjy.c revision 290001
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	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( 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( 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, sLog [ 100 ] ;
1158	int 	iLen ;
1159	int 	rc ;
1160
1161	const char *pCmd ;
1162	int 	iCmdLen ;
1163
1164	/* Initialize pointers  */
1165
1166	peer = rbufp->recv_peer ;
1167	pp = peer->procptr ;
1168	up = pp->unitptr ;
1169
1170	if ( up->linediscipline == LDISC_RAW ) {
1171		pBuf = up->sTextBuf ;
1172		iLen = up->iTextBufLen ;
1173	} else {
1174		pBuf = pp->a_lastcode ;
1175		iLen = pp->lencode ;
1176	}
1177
1178	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
1179
1180	/* Check expected reply */
1181
1182	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1183		/* Command sequence has not been started, or has been completed */
1184		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1185			  pBuf ) ;
1186		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1187		up->bLineError = TRUE ;
1188		return JJY_RECEIVE_ERROR ;
1189	}
1190
1191	/* Check reply length */
1192
1193	if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
1194	  && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
1195		/* Unexpected reply length */
1196		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1197			  iLen ) ;
1198		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1199		up->bLineError = TRUE ;
1200		return JJY_RECEIVE_ERROR ;
1201	}
1202
1203	/* Parse reply */
1204
1205	switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
1206
1207	case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
1208
1209		rc = sscanf ( pBuf, "%4d/%2d/%2d",
1210			      &up->year, &up->month, &up->day ) ;
1211
1212		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
1213		  || up->month < 1 || 12 < up->month
1214		  || up->day < 1 || 31 < up->day ) {
1215			/* Invalid date */
1216			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
1217				  rc, up->year, up->month, up->day ) ;
1218			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1219			up->bLineError = TRUE ;
1220			return JJY_RECEIVE_ERROR ;
1221		}
1222
1223		break ;
1224
1225	case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1226	case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
1227
1228		if ( up->iTimestampCount >= 2 ) {
1229			/* Too many time reply */
1230			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
1231				  up->iTimestampCount ) ;
1232			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1233			up->bLineError = TRUE ;
1234			return JJY_RECEIVE_ERROR ;
1235		}
1236
1237		rc = sscanf ( pBuf, "%2d:%2d:%2d",
1238			      &up->hour, &up->minute, &up->second ) ;
1239
1240		if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
1241		     up->second > 60 ) {
1242			/* Invalid time */
1243			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
1244				  rc, up->hour, up->minute, up->second ) ;
1245			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1246			up->bLineError = TRUE ;
1247			return JJY_RECEIVE_ERROR ;
1248		}
1249
1250		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
1251
1252		up->iTimestampCount++ ;
1253
1254		up->msecond = 0 ;
1255
1256		break ;
1257
1258	case TS_JJY01_COMMAND_NUMBER_STUS :
1259
1260		if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
1261			     TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0
1262		  || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
1263			     TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
1264			/* Good */
1265		} else {
1266			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1267				  pBuf ) ;
1268			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1269			up->bLineError = TRUE ;
1270			return JJY_RECEIVE_ERROR ;
1271		}
1272
1273		break ;
1274
1275	case TS_JJY01_COMMAND_NUMBER_DCST :
1276
1277		if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
1278			     TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
1279		  || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
1280			     TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
1281			/* Good */
1282		} else {
1283			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1284				  pBuf ) ;
1285			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1286			up->bLineError = TRUE ;
1287			return JJY_RECEIVE_ERROR ;
1288		}
1289
1290		break ;
1291
1292	default : /*  Unexpected reply */
1293
1294		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1295			  pBuf ) ;
1296		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1297		up->bLineError = TRUE ;
1298		return JJY_RECEIVE_ERROR ;
1299
1300	}
1301
1302	if ( up->iTimestampCount == 2 ) {
1303		/* Process date and time */
1304
1305		if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
1306		  && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
1307			/* 3 commands (time,date,stim) was excuted in two seconds */
1308			jjy_synctime( peer, pp, up ) ;
1309			return JJY_RECEIVE_DONE ;
1310		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
1311			/* Over midnight, and date is unsure */
1312			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
1313				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1314			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1315			return JJY_RECEIVE_SKIP ;
1316		} else {
1317			/* Slow reply */
1318			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
1319				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1320			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1321			up->bLineError = TRUE ;
1322			return JJY_RECEIVE_ERROR ;
1323		}
1324
1325	}
1326
1327	/* Issue next command */
1328
1329	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
1330		up->iCommandSeq ++ ;
1331	}
1332
1333	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1334		/* Command sequence completed */
1335		return JJY_RECEIVE_DONE ;
1336	}
1337
1338	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1339	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1340	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1341		refclock_report ( peer, CEVNT_FAULT ) ;
1342	}
1343
1344	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1345
1346	return JJY_RECEIVE_WAIT ;
1347
1348}
1349
1350/**************************************************************************************************/
1351
1352static void
1353jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1354{
1355#ifdef DEBUG
1356	static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1357#endif
1358
1359	struct refclockproc *pp ;
1360	struct jjyunit	    *up ;
1361
1362	const char *pCmd ;
1363	int 	iCmdLen ;
1364
1365	pp = peer->procptr;
1366	up = pp->unitptr ;
1367
1368	up->bLineError = FALSE ;
1369	up->iTimestampCount = 0 ;
1370
1371	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1372		/* Skip "dcst" and "stus" commands */
1373		up->iCommandSeq = 2 ;
1374		up->iLineCount = 2 ;
1375	}
1376
1377#ifdef DEBUG
1378	if ( debug ) {
1379		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
1380			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1381			up->iLineCount ) ;
1382	}
1383#endif
1384
1385	/*
1386	 * Send a first command
1387	 */
1388
1389	up->iCommandSeq ++ ;
1390
1391	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1392	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1393	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1394		refclock_report ( peer, CEVNT_FAULT ) ;
1395	}
1396
1397	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1398
1399}
1400
1401/*################################################################################################*/
1402/*################################################################################################*/
1403/*##												##*/
1404/*##    The C-DEX Co. Ltd. JJY receiver JST2000							##*/
1405/*##												##*/
1406/*##    server  127.127.40.X  mode 2								##*/
1407/*##												##*/
1408/*################################################################################################*/
1409/*################################################################################################*/
1410/*                                                                                                */
1411/*  Command               Response                                  Remarks                       */
1412/*  --------------------  ----------------------------------------  ----------------------------  */
1413/*  <ENQ>1J<ETX>          <STX>JYYMMDD HHMMSSS<ETX>                 J is a fixed character        */
1414/*                                                                                                */
1415/*################################################################################################*/
1416
1417static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
1418{
1419	{ "\x03", 1 }, { NULL, 0 }
1420} ;
1421
1422/**************************************************************************************************/
1423
1424static int
1425jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
1426{
1427
1428	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
1429
1430	up->unittype  = UNITTYPE_CDEX_JST2000 ;
1431	up->linespeed = SPEED232_CDEX_JST2000 ;
1432	up->linediscipline = LDISC_RAW ;
1433
1434	up->pRawBreak = cdex_jst2000_raw_break ;
1435	up->bWaitBreakString = TRUE ;
1436
1437	up->bSkipCntrlCharOnly = FALSE ;
1438
1439	return 0 ;
1440
1441}
1442
1443/**************************************************************************************************/
1444
1445static int
1446jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
1447{
1448
1449	struct jjyunit      *up ;
1450	struct refclockproc *pp ;
1451	struct peer         *peer ;
1452
1453	char	*pBuf, sLog [ 100 ] ;
1454	int 	iLen ;
1455	int 	rc ;
1456
1457	/* Initialize pointers */
1458
1459	peer = rbufp->recv_peer ;
1460	pp = peer->procptr ;
1461	up = pp->unitptr ;
1462
1463	if ( up->linediscipline == LDISC_RAW ) {
1464		pBuf = up->sTextBuf ;
1465		iLen = up->iTextBufLen ;
1466	} else {
1467		pBuf = pp->a_lastcode ;
1468		iLen = pp->lencode ;
1469	}
1470
1471	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
1472
1473	/* Check expected reply */
1474
1475	if ( up->iCommandSeq != 1 ) {
1476		/* Command sequence has not been started, or has been completed */
1477		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1478			  pBuf ) ;
1479		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1480		up->bLineError = TRUE ;
1481		return JJY_RECEIVE_ERROR ;
1482	}
1483
1484	/* Wait until ETX comes */
1485
1486	if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
1487		return JJY_RECEIVE_UNPROCESS ;
1488	}
1489
1490	/* Check reply length */
1491
1492	if ( iLen != 15 ) {
1493		/* Unexpected reply length */
1494		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1495			  iLen ) ;
1496		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1497		up->bLineError = TRUE ;
1498		return JJY_RECEIVE_ERROR ;
1499	}
1500
1501	/* JYYMMDD HHMMSSS */
1502
1503	rc = sscanf ( pBuf, "J%2d%2d%2d %2d%2d%2d%1d",
1504		      &up->year, &up->month, &up->day,
1505		      &up->hour, &up->minute, &up->second,
1506		      &up->msecond ) ;
1507
1508	if ( rc != 7 || up->month < 1 || up->month > 12 ||
1509	     up->day < 1 || up->day > 31 || up->hour > 23 ||
1510	     up->minute > 59 || up->second > 60 ) {
1511		/* Invalid date and time */
1512		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1513			  rc, up->year, up->month, up->day,
1514			  up->hour, up->minute, up->second ) ;
1515		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1516		up->bLineError = TRUE ;
1517		return JJY_RECEIVE_ERROR ;
1518	}
1519
1520	up->year    += 2000 ;
1521	up->msecond *= 100 ;
1522
1523	jjy_synctime( peer, pp, up ) ;
1524
1525	return JJY_RECEIVE_DONE ;
1526
1527}
1528
1529/**************************************************************************************************/
1530
1531static void
1532jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1533{
1534
1535	struct refclockproc *pp ;
1536	struct jjyunit      *up ;
1537
1538	pp = peer->procptr ;
1539	up = pp->unitptr ;
1540
1541	up->bLineError = FALSE ;
1542	up->iRawBufLen = 0 ;
1543	up->iLineBufLen = 0 ;
1544	up->iTextBufLen = 0 ;
1545
1546	/*
1547	 * Send "<ENQ>1J<ETX>" command
1548	 */
1549
1550	up->iCommandSeq ++ ;
1551
1552	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1553		refclock_report ( peer, CEVNT_FAULT ) ;
1554	}
1555
1556	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
1557
1558}
1559
1560/*################################################################################################*/
1561/*################################################################################################*/
1562/*##												##*/
1563/*##    The Echo Keisokuki Co. Ltd. JJY receiver LT2000						##*/
1564/*##												##*/
1565/*##    server  127.127.40.X  mode 3								##*/
1566/*##												##*/
1567/*################################################################################################*/
1568/*################################################################################################*/
1569/*                                                                                                */
1570/*  Command               Response                                  Remarks                       */
1571/*  --------------------  ----------------------------------------  ----------------------------  */
1572/*  #                                                               Mode 1 ( Request & Send )     */
1573/*  T                     YYMMDDWHHMMSS<BCC1><BCC2><CR>                                           */
1574/*  C                                                               Mode 2 ( Continuous )         */
1575/*                        YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>     0.5 sec before time stamp     */
1576/*                        <SUB>                                     Second signal                 */
1577/*                                                                                                */
1578/*################################################################################################*/
1579
1580#define	ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND		1
1581#define	ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS		2
1582#define	ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS	3
1583
1584#define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND 	"#"
1585#define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME 	"T"
1586#define	ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS 	"C"
1587
1588/**************************************************************************************************/
1589
1590static int
1591jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
1592{
1593
1594	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
1595
1596	up->unittype  = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
1597	up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
1598	up->linediscipline = LDISC_CLK ;
1599
1600	up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
1601
1602	return 0 ;
1603
1604}
1605
1606/**************************************************************************************************/
1607
1608static int
1609jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1610{
1611
1612	struct jjyunit      *up ;
1613	struct refclockproc *pp ;
1614	struct peer	    *peer;
1615
1616	char	*pBuf, sLog [ 100 ], sErr [ 60 ] ;
1617	int 	iLen ;
1618	int 	rc ;
1619	int	i, ibcc, ibcc1, ibcc2 ;
1620
1621	/* Initialize pointers */
1622
1623	peer = rbufp->recv_peer ;
1624	pp = peer->procptr ;
1625	up = pp->unitptr ;
1626
1627	if ( up->linediscipline == LDISC_RAW ) {
1628		pBuf = up->sTextBuf ;
1629		iLen = up->iTextBufLen ;
1630	} else {
1631		pBuf = pp->a_lastcode ;
1632		iLen = pp->lencode ;
1633	}
1634
1635	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
1636
1637	/* Check reply length */
1638
1639	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1640	       && iLen != 15 )
1641	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1642	       && iLen != 17 )
1643	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1644	       && iLen != 17 ) ) {
1645		/* Unexpected reply length */
1646		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1647			  iLen ) ;
1648			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1649		up->bLineError = TRUE ;
1650		return JJY_RECEIVE_ERROR ;
1651	}
1652
1653	if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
1654		/* YYMMDDWHHMMSS<BCC1><BCC2> */
1655
1656		for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
1657			ibcc ^= pBuf[i] ;
1658		}
1659
1660		ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1661		ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
1662		if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1663			snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
1664				  pBuf[13] & 0xFF, pBuf[14] & 0xFF,
1665				  ibcc1, ibcc2 ) ;
1666			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1667				  sErr ) ;
1668			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1669			up->bLineError = TRUE ;
1670			return JJY_RECEIVE_ERROR ;
1671		}
1672
1673	}
1674
1675	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1676	       && iLen == 15 )
1677	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1678	       && iLen == 17 )
1679	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1680	       && iLen == 17 ) ) {
1681		/* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1682
1683		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1684			      &up->year, &up->month, &up->day,
1685			      &up->hour, &up->minute, &up->second ) ;
1686
1687		if ( rc != 6 || up->month < 1 || up->month > 12
1688		  || up->day < 1 || up->day > 31
1689		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1690			/* Invalid date and time */
1691			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1692				  rc, up->year, up->month, up->day,
1693				  up->hour, up->minute, up->second ) ;
1694			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1695			up->bLineError = TRUE ;
1696			return JJY_RECEIVE_ERROR ;
1697		}
1698
1699		up->year += 2000 ;
1700
1701		if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1702		  || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1703			/* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
1704
1705			up->msecond = 500 ;
1706			up->second -- ;
1707			if ( up->second < 0 ) {
1708				up->second = 59 ;
1709				up->minute -- ;
1710				if ( up->minute < 0 ) {
1711					up->minute = 59 ;
1712					up->hour -- ;
1713					if ( up->hour < 0 ) {
1714						up->hour = 23 ;
1715						up->day -- ;
1716						if ( up->day < 1 ) {
1717							up->month -- ;
1718							if ( up->month < 1 ) {
1719								up->month = 12 ;
1720								up->year -- ;
1721							}
1722						}
1723					}
1724				}
1725			}
1726
1727		}
1728
1729		jjy_synctime( peer, pp, up ) ;
1730
1731
1732	}
1733
1734	if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1735		/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1736
1737		iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1738		if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen  ) {
1739			refclock_report ( peer, CEVNT_FAULT ) ;
1740		}
1741
1742		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1743
1744	}
1745
1746	return JJY_RECEIVE_DONE ;
1747
1748}
1749
1750/**************************************************************************************************/
1751
1752static void
1753jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1754{
1755
1756	struct refclockproc *pp ;
1757	struct jjyunit      *up ;
1758
1759	char	sCmd[2] ;
1760
1761	pp = peer->procptr ;
1762	up = pp->unitptr ;
1763
1764	up->bLineError = FALSE ;
1765
1766	/*
1767	 * Send "T" or "C" command
1768	 */
1769
1770	switch ( up->operationmode ) {
1771	case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
1772		sCmd[0] = 'T' ;
1773		break ;
1774	case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
1775	case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
1776		sCmd[0] = 'C' ;
1777		break ;
1778	}
1779	sCmd[1] = 0 ;
1780
1781	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1782		refclock_report ( peer, CEVNT_FAULT ) ;
1783	}
1784
1785	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
1786
1787}
1788
1789/*################################################################################################*/
1790/*################################################################################################*/
1791/*##												##*/
1792/*##    The CITIZEN T.I.C CO., LTD. JJY receiver JJY200						##*/
1793/*##												##*/
1794/*##    server  127.127.40.X  mode 4								##*/
1795/*##												##*/
1796/*################################################################################################*/
1797/*################################################################################################*/
1798/*                                                                                                */
1799/*  Command               Response                                  Remarks                       */
1800/*  --------------------  ----------------------------------------  ----------------------------  */
1801/*                        'XX YY/MM/DD W HH:MM:SS<CR>               XX:OK|NG|ER  W:0(Mon)-6(Sun)  */
1802/*                                                                                                */
1803/*################################################################################################*/
1804
1805static int
1806jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
1807{
1808
1809	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
1810
1811	up->unittype  = UNITTYPE_CITIZENTIC_JJY200 ;
1812	up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
1813	up->linediscipline = LDISC_CLK ;
1814
1815	return 0 ;
1816
1817}
1818
1819/**************************************************************************************************/
1820
1821static int
1822jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1823{
1824
1825	struct jjyunit		*up ;
1826	struct refclockproc	*pp ;
1827	struct peer		*peer;
1828
1829	char	*pBuf, sLog [ 100 ], sMsg [ 16 ] ;
1830	int	iLen ;
1831	int	rc ;
1832	char	cApostrophe, sStatus[3] ;
1833	int	iWeekday ;
1834
1835	/* Initialize pointers */
1836
1837	peer = rbufp->recv_peer ;
1838	pp = peer->procptr ;
1839	up = pp->unitptr ;
1840
1841	if ( up->linediscipline == LDISC_RAW ) {
1842		pBuf = up->sTextBuf ;
1843		iLen = up->iTextBufLen ;
1844	} else {
1845		pBuf = pp->a_lastcode ;
1846		iLen = pp->lencode ;
1847	}
1848
1849	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
1850
1851	/*
1852	 * JJY-200 sends a timestamp every second.
1853	 * So, a timestamp is ignored unless it is right after polled.
1854	 */
1855
1856	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
1857		return JJY_RECEIVE_SKIP ;
1858	}
1859
1860	/* Check reply length */
1861
1862	if ( iLen != 23 ) {
1863		/* Unexpected reply length */
1864		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1865			  iLen ) ;
1866		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1867		up->bLineError = TRUE ;
1868		return JJY_RECEIVE_ERROR ;
1869	}
1870
1871	/* 'XX YY/MM/DD W HH:MM:SS<CR> */
1872
1873	rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1874		      &cApostrophe, sStatus,
1875		      &up->year, &up->month, &up->day, &iWeekday,
1876		      &up->hour, &up->minute, &up->second ) ;
1877	sStatus[2] = 0 ;
1878
1879	if ( rc != 9 || cApostrophe != '\''
1880	  || ( strcmp( sStatus, "OK" ) != 0
1881	    && strcmp( sStatus, "NG" ) != 0
1882	    && strcmp( sStatus, "ER" ) != 0 )
1883	  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
1884	  || iWeekday > 6
1885	  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1886		/* Invalid date and time */
1887		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1888			  rc, up->year, up->month, up->day,
1889			  up->hour, up->minute, up->second ) ;
1890		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1891		up->bLineError = TRUE ;
1892		return JJY_RECEIVE_ERROR ;
1893	} else if ( strcmp( sStatus, "NG" ) == 0
1894		 || strcmp( sStatus, "ER" ) == 0 ) {
1895		/* Timestamp is unsure */
1896		snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
1897		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
1898			  sMsg ) ;
1899		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
1900		return JJY_RECEIVE_SKIP ;
1901	}
1902
1903	up->year += 2000 ;
1904	up->msecond = 0 ;
1905
1906	jjy_synctime( peer, pp, up ) ;
1907
1908	return JJY_RECEIVE_DONE ;
1909
1910}
1911
1912/**************************************************************************************************/
1913
1914static void
1915jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1916{
1917
1918	struct refclockproc *pp ;
1919	struct jjyunit	    *up ;
1920
1921	pp = peer->procptr ;
1922	up = pp->unitptr ;
1923
1924	up->bLineError = FALSE ;
1925
1926}
1927
1928/*################################################################################################*/
1929/*################################################################################################*/
1930/*##												##*/
1931/*##    The Tristate Ltd. GPS clock TS-GPS01							##*/
1932/*##												##*/
1933/*##    server  127.127.40.X  mode 5								##*/
1934/*##												##*/
1935/*################################################################################################*/
1936/*################################################################################################*/
1937/*                                                                                                */
1938/*  This clock has NMEA mode and command/respose mode.                                            */
1939/*  When this jjy driver are used, set to command/respose mode of this clock                      */
1940/*  by the onboard switch SW4, and make sure the LED-Y is tured on.                               */
1941/*  Other than this JJY driver, the refclock driver type 20, generic NMEA driver,                 */
1942/*  works with the NMEA mode of this clock.                                                       */
1943/*                                                                                                */
1944/*  Command               Response                                  Remarks                       */
1945/*  --------------------  ----------------------------------------  ----------------------------  */
1946/*  stus<CR><LF>          *R|*G|*U|+U<CR><LF>                                                     */
1947/*  date<CR><LF>          YY/MM/DD<CR><LF>                                                        */
1948/*  time<CR><LF>          HH:MM:SS<CR><LF>                                                        */
1949/*                                                                                                */
1950/*################################################################################################*/
1951
1952#define	TS_GPS01_COMMAND_NUMBER_DATE	1
1953#define	TS_GPS01_COMMAND_NUMBER_TIME	2
1954#define	TS_GPS01_COMMAND_NUMBER_STUS	4
1955
1956#define	TS_GPS01_REPLY_DATE		"yyyy/mm/dd"
1957#define	TS_GPS01_REPLY_TIME		"hh:mm:ss"
1958#define	TS_GPS01_REPLY_STUS_RTC		"*R"
1959#define	TS_GPS01_REPLY_STUS_GPS		"*G"
1960#define	TS_GPS01_REPLY_STUS_UTC		"*U"
1961#define	TS_GPS01_REPLY_STUS_PPS		"+U"
1962
1963#define	TS_GPS01_REPLY_LENGTH_DATE	    10	/* Length without <CR><LF> */
1964#define	TS_GPS01_REPLY_LENGTH_TIME	    8	/* Length without <CR><LF> */
1965#define	TS_GPS01_REPLY_LENGTH_STUS	    2	/* Length without <CR><LF> */
1966
1967static  struct
1968{
1969	char	commandNumber ;
1970	const char	*command ;
1971	int	commandLength ;
1972	int	iExpectedReplyLength ;
1973} tristate_gps01_command_sequence[] =
1974{
1975	{ 0, NULL, 0, 0 }, /* Idle */
1976	{ TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
1977	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1978	{ TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
1979	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1980	/* End of command */
1981	{ 0, NULL, 0, 0 }
1982} ;
1983
1984/**************************************************************************************************/
1985
1986static int
1987jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
1988{
1989
1990	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
1991
1992	up->unittype  = UNITTYPE_TRISTATE_GPSCLOCK01 ;
1993	up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
1994	up->linediscipline = LDISC_CLK ;
1995
1996	return 0 ;
1997
1998}
1999
2000/**************************************************************************************************/
2001
2002static int
2003jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
2004{
2005#ifdef DEBUG
2006	static	const char	*sFunctionName = "jjy_receive_tristate_gpsclock01" ;
2007#endif
2008
2009	struct jjyunit	    *up ;
2010	struct refclockproc *pp ;
2011	struct peer	    *peer;
2012
2013	char	*pBuf, sLog [ 100 ] ;
2014	int 	iLen ;
2015	int 	rc ;
2016
2017	const char	*pCmd ;
2018	int 	iCmdLen ;
2019
2020	/* Initialize pointers */
2021
2022	peer = rbufp->recv_peer ;
2023	pp = peer->procptr ;
2024	up = pp->unitptr ;
2025
2026	if ( up->linediscipline == LDISC_RAW ) {
2027		pBuf = up->sTextBuf ;
2028		iLen = up->iTextBufLen ;
2029	} else {
2030		pBuf = pp->a_lastcode ;
2031		iLen = pp->lencode ;
2032	}
2033
2034	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
2035
2036	/* Ignore NMEA data stream */
2037
2038	if ( iLen > 5
2039	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2040#ifdef DEBUG
2041		if ( debug ) {
2042			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2043				sFunctionName, pBuf ) ;
2044		}
2045#endif
2046		return JJY_RECEIVE_WAIT ;
2047	}
2048
2049	/*
2050	 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
2051	 */
2052	if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2053		return JJY_RECEIVE_WAIT ;
2054	} else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2055		pBuf += 5 ;
2056		iLen -= 5 ;
2057	}
2058
2059	/*
2060	 * Ignore NMEA data stream after command prompt
2061	 */
2062	if ( iLen > 5
2063	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2064#ifdef DEBUG
2065		if ( debug ) {
2066			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2067				sFunctionName, pBuf ) ;
2068		}
2069#endif
2070		return JJY_RECEIVE_WAIT ;
2071	}
2072
2073	/* Check expected reply */
2074
2075	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2076		/* Command sequence has not been started, or has been completed */
2077		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2078			  pBuf ) ;
2079		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2080		up->bLineError = TRUE ;
2081		return JJY_RECEIVE_ERROR ;
2082	}
2083
2084	/* Check reply length */
2085
2086	if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
2087		/* Unexpected reply length */
2088		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2089			  iLen ) ;
2090		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2091		up->bLineError = TRUE ;
2092		return JJY_RECEIVE_ERROR ;
2093	}
2094
2095	/* Parse reply */
2096
2097	switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
2098
2099	case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
2100
2101		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
2102
2103		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
2104		  || up->month < 1 || 12 < up->month
2105		  || up->day < 1 || 31 < up->day ) {
2106			/* Invalid date */
2107			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
2108				  rc, up->year, up->month, up->day ) ;
2109			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2110			up->bLineError = TRUE ;
2111			return JJY_RECEIVE_ERROR ;
2112		}
2113
2114		break ;
2115
2116	case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
2117
2118		if ( up->iTimestampCount >= 2 ) {
2119			/* Too many time reply */
2120			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
2121				  up->iTimestampCount ) ;
2122			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2123			up->bLineError = TRUE ;
2124			return JJY_RECEIVE_ERROR ;
2125		}
2126
2127		rc = sscanf ( pBuf, "%2d:%2d:%2d",
2128			      &up->hour, &up->minute, &up->second ) ;
2129
2130		if ( rc != 3
2131		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2132			/* Invalid time */
2133			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2134				  rc, up->hour, up->minute, up->second ) ;
2135			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2136			up->bLineError = TRUE ;
2137			return JJY_RECEIVE_ERROR ;
2138		}
2139
2140		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
2141
2142		up->iTimestampCount++ ;
2143
2144		up->msecond = 0 ;
2145
2146		break ;
2147
2148	case TS_GPS01_COMMAND_NUMBER_STUS :
2149
2150		if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2151		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2152		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2153		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
2154			/* Good */
2155		} else {
2156			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2157				  pBuf ) ;
2158			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2159			up->bLineError = TRUE ;
2160			return JJY_RECEIVE_ERROR ;
2161		}
2162
2163		break ;
2164
2165	default : /*  Unexpected reply */
2166
2167		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2168			  pBuf ) ;
2169		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2170		up->bLineError = TRUE ;
2171		return JJY_RECEIVE_ERROR ;
2172
2173	}
2174
2175	if ( up->iTimestampCount == 2 ) {
2176		/* Process date and time */
2177
2178		if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
2179		  && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
2180			/* 3 commands (time,date,stim) was excuted in two seconds */
2181			jjy_synctime( peer, pp, up ) ;
2182			return JJY_RECEIVE_DONE ;
2183		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
2184			/* Over midnight, and date is unsure */
2185			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
2186				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2187			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
2188			return JJY_RECEIVE_SKIP ;
2189		} else {
2190			/* Slow reply */
2191			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
2192				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2193			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2194			up->bLineError = TRUE ;
2195			return JJY_RECEIVE_ERROR ;
2196		}
2197
2198	}
2199
2200	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2201		/* Command sequence completed */
2202		jjy_synctime( peer, pp, up ) ;
2203		return JJY_RECEIVE_DONE ;
2204	}
2205
2206	/* Issue next command */
2207
2208	if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
2209		up->iCommandSeq ++ ;
2210	}
2211
2212	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2213		/* Command sequence completed */
2214		up->iProcessState = JJY_PROCESS_STATE_DONE ;
2215		return JJY_RECEIVE_DONE ;
2216	}
2217
2218	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2219	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2220	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2221		refclock_report ( peer, CEVNT_FAULT ) ;
2222	}
2223
2224	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2225
2226	return JJY_RECEIVE_WAIT ;
2227
2228}
2229
2230/**************************************************************************************************/
2231
2232static void
2233jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
2234{
2235#ifdef DEBUG
2236	static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
2237#endif
2238
2239	struct refclockproc *pp ;
2240	struct jjyunit	    *up ;
2241
2242	const char	*pCmd ;
2243	int 	iCmdLen ;
2244
2245	pp = peer->procptr ;
2246	up = pp->unitptr ;
2247
2248	up->iTimestampCount = 0 ;
2249
2250	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
2251		/* Skip "stus" command */
2252		up->iCommandSeq = 1 ;
2253		up->iLineCount = 1 ;
2254	}
2255
2256#ifdef DEBUG
2257	if ( debug ) {
2258		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
2259			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
2260			up->iLineCount ) ;
2261	}
2262#endif
2263
2264	/*
2265	 * Send a first command
2266	 */
2267
2268	up->iCommandSeq ++ ;
2269
2270	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2271	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2272	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2273		refclock_report ( peer, CEVNT_FAULT ) ;
2274	}
2275
2276	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2277
2278}
2279
2280/*################################################################################################*/
2281/*################################################################################################*/
2282/*##												##*/
2283/*##    The SEIKO TIME SYSTEMS TDC-300								##*/
2284/*##												##*/
2285/*##    server  127.127.40.X  mode 6								##*/
2286/*##												##*/
2287/*################################################################################################*/
2288/*################################################################################################*/
2289/*                                                                                                */
2290/*  Type                  Response                                  Remarks                       */
2291/*  --------------------  ----------------------------------------  ----------------------------  */
2292/*  Type 1                <STX>HH:MM:SS<ETX>                                                      */
2293/*  Type 2                <STX>YYMMDDHHMMSSWLSCU<ETX>               W:0(Sun)-6(Sat)               */
2294/*  Type 3                <STX>YYMMDDWHHMMSS<ETX>                   W:0(Sun)-6(Sat)               */
2295/*                        <STX><xE5><ETX>                           5 to 10 mSec. before second   */
2296/*                                                                                                */
2297/*################################################################################################*/
2298
2299static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
2300{
2301	{ "\x03", 1 }, { NULL, 0 }
2302} ;
2303
2304/**************************************************************************************************/
2305
2306static int
2307jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
2308{
2309
2310	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
2311
2312	up->unittype  = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
2313	up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
2314	up->linediscipline = LDISC_RAW ;
2315
2316	up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
2317	up->bWaitBreakString = TRUE ;
2318
2319	up->bSkipCntrlCharOnly = FALSE ;
2320
2321	return 0 ;
2322
2323}
2324
2325/**************************************************************************************************/
2326
2327static int
2328jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
2329{
2330
2331	struct peer		*peer;
2332	struct refclockproc	*pp ;
2333	struct jjyunit		*up ;
2334
2335	char	*pBuf, sLog [ 100 ] ;
2336	int	iLen, i ;
2337	int	rc, iWeekday ;
2338	time_t	now ;
2339	struct	tm	*pTime ;
2340
2341	/* Initialize pointers */
2342
2343	peer = rbufp->recv_peer ;
2344	pp = peer->procptr ;
2345	up = pp->unitptr ;
2346
2347	if ( up->linediscipline == LDISC_RAW ) {
2348		pBuf = up->sTextBuf ;
2349		iLen = up->iTextBufLen ;
2350	} else {
2351		pBuf = pp->a_lastcode ;
2352		iLen = pp->lencode ;
2353	}
2354
2355	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
2356
2357	/*
2358	 * TDC-300 sends a timestamp every second.
2359	 * So, a timestamp is ignored unless it is right after polled.
2360	 */
2361
2362	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
2363		return JJY_RECEIVE_SKIP ;
2364	}
2365
2366	/* Process timestamp */
2367
2368	up->iReceiveSeq ++ ;
2369
2370	switch ( iLen ) {
2371
2372	case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
2373
2374		for ( i = 0 ; i < iLen ; i ++ ) {
2375			pBuf[i] &= 0x7F ;
2376		}
2377
2378		rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
2379		      &up->hour, &up->minute, &up->second ) ;
2380
2381		if ( rc != 3
2382		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2383			/* Invalid time */
2384			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2385				  rc, up->hour, up->minute, up->second ) ;
2386			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2387			up->bLineError = TRUE ;
2388			return JJY_RECEIVE_ERROR ;
2389		} else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
2390			/* Uncertainty date guard */
2391			return JJY_RECEIVE_WAIT ;
2392		}
2393
2394		time( &now ) ;
2395		pTime = localtime( &now ) ;
2396		up->year  = pTime->tm_year ;
2397		up->month = pTime->tm_mon + 1 ;
2398		up->day   = pTime->tm_mday ;
2399
2400		break ;
2401
2402	case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
2403
2404		for ( i = 0 ; i < iLen ; i ++ ) {
2405			pBuf[i] &= 0x7F ;
2406		}
2407
2408		rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
2409		      &up->year, &up->month, &up->day,
2410		      &up->hour, &up->minute, &up->second, &iWeekday ) ;
2411
2412		if ( rc != 7
2413		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2414		  || iWeekday > 6
2415		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2416			/* Invalid date and time */
2417			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2418				  rc, up->year, up->month, up->day,
2419				  up->hour, up->minute, up->second ) ;
2420			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2421			up->bLineError = TRUE ;
2422			return JJY_RECEIVE_ERROR ;
2423		}
2424
2425		break ;
2426
2427	case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
2428
2429		rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
2430		      &up->year, &up->month, &up->day, &iWeekday,
2431		      &up->hour, &up->minute, &up->second ) ;
2432
2433		if ( rc != 7
2434		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2435		  || iWeekday > 6
2436		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2437			/* Invalid date and time */
2438			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2439				  rc, up->year, up->month, up->day,
2440				  up->hour, up->minute, up->second ) ;
2441			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2442			up->bLineError = TRUE ;
2443			return JJY_RECEIVE_ERROR ;
2444		}
2445
2446		return JJY_RECEIVE_WAIT ;
2447
2448	case 1 : /* Type 3 : <STX><xE5><ETX> */
2449
2450		if ( ( *pBuf & 0xFF ) != 0xE5 ) {
2451			/* Invalid second signal */
2452			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2453				  up->sLineBuf ) ;
2454			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2455			up->bLineError = TRUE ;
2456			return JJY_RECEIVE_ERROR ;
2457		} else if ( up->iReceiveSeq == 1 ) {
2458			/* Wait for next timestamp */
2459			up->iReceiveSeq -- ;
2460			return JJY_RECEIVE_WAIT ;
2461		} else if ( up->iReceiveSeq >= 3 ) {
2462			/* Unexpected second signal */
2463			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2464				  up->sLineBuf ) ;
2465			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2466			up->bLineError = TRUE ;
2467			return JJY_RECEIVE_ERROR ;
2468		}
2469
2470		break ;
2471
2472	default : /* Unexpected reply length */
2473
2474		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2475			  iLen ) ;
2476		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2477		up->bLineError = TRUE ;
2478		return JJY_RECEIVE_ERROR ;
2479
2480	}
2481
2482	up->year += 2000 ;
2483	up->msecond = 0 ;
2484
2485	jjy_synctime( peer, pp, up ) ;
2486
2487	return JJY_RECEIVE_DONE ;
2488
2489}
2490
2491/**************************************************************************************************/
2492
2493static void
2494jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
2495{
2496
2497	struct refclockproc *pp ;
2498	struct jjyunit	    *up ;
2499
2500	pp = peer->procptr ;
2501	up = pp->unitptr ;
2502
2503	up->bLineError = FALSE ;
2504
2505}
2506
2507/*################################################################################################*/
2508/*################################################################################################*/
2509/*##												##*/
2510/*##    Telephone JJY										##*/
2511/*##												##*/
2512/*##    server  127.127.40.X  mode 100 to 180							##*/
2513/*##												##*/
2514/*################################################################################################*/
2515/*################################################################################################*/
2516/*                                                                                                */
2517/*  Prompt                Command               Response              Remarks                     */
2518/*  --------------------  --------------------  --------------------  --------------------------  */
2519/*  Name<SP>?<SP>         TJJY<CR>              Welcome messages      TJJY is a guest user ID     */
2520/*  >                     4DATE<CR>             YYYYMMDD<CR>                                      */
2521/*  >                     LEAPSEC<CR>           XX<CR>                One of <SP>0, +1, -1        */
2522/*  >                     TIME<CR>              HHMMSS<CR>            3 times on second           */
2523/*  >                     BYE<CR>               Sayounara messages                                */
2524/*                                                                                                */
2525/*################################################################################################*/
2526
2527static struct jjyRawDataBreak teljjy_raw_break [ ] =
2528{
2529	{ "\r\n", 2 },
2530	{ "\r"  , 1 },
2531	{ "\n"  , 1 },
2532	{ "Name ? ", 7 },
2533	{ ">"   , 1 },
2534	{ "+++" , 3 },
2535	{ NULL  , 0 }
2536} ;
2537
2538#define	TELJJY_STATE_IDLE	0
2539#define	TELJJY_STATE_DAILOUT	1
2540#define	TELJJY_STATE_LOGIN	2
2541#define	TELJJY_STATE_CONNECT	3
2542#define	TELJJY_STATE_BYE	4
2543
2544#define	TELJJY_EVENT_NULL	0
2545#define	TELJJY_EVENT_START	1
2546#define	TELJJY_EVENT_CONNECT	2
2547#define	TELJJY_EVENT_DISCONNECT	3
2548#define	TELJJY_EVENT_COMMAND	4
2549#define	TELJJY_EVENT_LOGIN	5	/* Posted by the jjy_receive_telephone */
2550#define	TELJJY_EVENT_PROMPT	6	/* Posted by the jjy_receive_telephone */
2551#define	TELJJY_EVENT_DATA	7	/* Posted by the jjy_receive_telephone */
2552#define	TELJJY_EVENT_ERROR	8	/* Posted by the jjy_receive_telephone */
2553#define	TELJJY_EVENT_SILENT	9	/* Posted by the jjy_timer_telephone */
2554#define	TELJJY_EVENT_TIMEOUT	10	/* Posted by the jjy_timer_telephone */
2555
2556static	void 	teljjy_control		( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2557
2558static	int 	teljjy_idle_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2559static	int 	teljjy_idle_dialout	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2560static	int 	teljjy_dial_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2561static	int 	teljjy_dial_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2562static	int 	teljjy_dial_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2563static	int 	teljjy_login_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2564static	int 	teljjy_login_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2565static	int 	teljjy_login_conn	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2566static	int 	teljjy_login_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2567static	int 	teljjy_login_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2568static	int 	teljjy_login_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2569static	int 	teljjy_conn_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2570static	int 	teljjy_conn_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2571static	int 	teljjy_conn_send	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2572static	int 	teljjy_conn_data	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2573static	int 	teljjy_conn_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2574static	int 	teljjy_conn_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2575static	int 	teljjy_bye_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2576static	int 	teljjy_bye_disc 	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2577static	int 	teljjy_bye_modem	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2578
2579static int ( *pTeljjyHandler [ ] [ 5 ] ) ( ) =
2580{               	/*STATE_IDLE           STATE_DAILOUT       STATE_LOGIN           STATE_CONNECT       STATE_BYE        */
2581/* NULL       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2582/* START      */	{ teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2583/* CONNECT    */	{ teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2584/* DISCONNECT */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_disc  , teljjy_conn_disc  , teljjy_bye_disc   },
2585/* COMMAND    */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem  },
2586/* LOGIN      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
2587/* PROMPT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn  , teljjy_conn_send  , teljjy_bye_ignore },
2588/* DATA       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data  , teljjy_bye_ignore },
2589/* ERROR      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
2590/* SILENT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
2591/* TIMEOUT    */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem  }
2592} ;
2593
2594static short iTeljjyNextState [ ] [ 5 ] =
2595{               	/*STATE_IDLE            STATE_DAILOUT         STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2596/* NULL       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2597/* START      */	{ TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2598/* CONNECT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_LOGIN  , TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2599/* DISCONNECT */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE },
2600/* COMMAND    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2601/* LOGIN      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2602/* PROMPT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2603/* DATA       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2604/* ERROR      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2605/* SILENT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2606/* TIMEOUT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  }
2607} ;
2608
2609static short iTeljjyPostEvent [ ] [ 5 ] =
2610{               	/*STATE_IDLE         STATE_DAILOUT      STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2611/* NULL       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2612/* START      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2613/* CONNECT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2614/* DISCONNECT */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2615/* COMMAND    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2616/* LOGIN      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2617/* PROMPT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2618/* DATA       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2619/* ERROR      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2620/* SILENT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2621/* TIMEOUT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
2622} ;
2623
2624static short iTeljjySilentTimeout [ 5 ] = { 0,   0, 10,  5,  0 } ;
2625static short iTeljjyStateTimeout  [ 5 ] = { 0, 120, 60, 60, 40 } ;
2626
2627#define	TELJJY_STAY_CLOCK_STATE  	0
2628#define	TELJJY_CHANGE_CLOCK_STATE	1
2629
2630/* Command and replay */
2631
2632#define	TELJJY_REPLY_NONE	0
2633#define	TELJJY_REPLY_4DATE	1
2634#define	TELJJY_REPLY_TIME	2
2635#define	TELJJY_REPLY_LEAPSEC	3
2636#define	TELJJY_REPLY_LOOP	4
2637#define	TELJJY_REPLY_PROMPT	5
2638#define	TELJJY_REPLY_LOOPBACK	6
2639#define	TELJJY_REPLY_COM	7
2640
2641#define	TELJJY_COMMAND_START_SKIP_LOOPBACK	7
2642
2643static  struct
2644{
2645	const char	*command ;
2646	int	commandLength ;
2647	int	iEchobackReplyLength ;
2648	int	iExpectedReplyType   ;
2649	int	iExpectedReplyLength ;
2650} teljjy_command_sequence[] =
2651{
2652	{ NULL, 0, 0, 0, 0 }, /* Idle */
2653	{ "LOOP\r"   , 5, 4, TELJJY_REPLY_LOOP    , 0 }, /* Getting into loopback mode */
2654	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2655	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
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	{ "COM\r"    , 4, 3, TELJJY_REPLY_COM     , 0 }, /* Exit from loopback mode */
2660	/* TELJJY_COMMAND_START_SKIP_LOOPBACK */
2661	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2662	{ "4DATE\r"  , 6, 5, TELJJY_REPLY_4DATE   , 8 },
2663	{ "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
2664	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2665	{ "BYE\r"    , 4, 3, TELJJY_REPLY_NONE    , 0 },
2666	/* End of command */
2667	{ NULL, 0, 0, 0, 0 }
2668} ;
2669
2670#define	TELJJY_LOOPBACK_DELAY_THRESHOLD		700 /* Milli second */
2671
2672#ifdef	DEBUG
2673#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 ) ; } }
2674#else
2675#define	DEBUG_TELJJY_PRINTF(sFunc)
2676#endif
2677
2678/**************************************************************************************************/
2679
2680static int
2681jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
2682{
2683
2684	char	sLog [ 80 ], sFirstThreeDigits [ 4 ] ;
2685	int	i, iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
2686	int	iFirstThreeDigitsCount ;
2687
2688	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
2689
2690	up->unittype  = UNITTYPE_TELEPHONE ;
2691	up->linespeed = SPEED232_TELEPHONE ;
2692	up->linediscipline = LDISC_RAW ;
2693
2694	up->pRawBreak = teljjy_raw_break ;
2695	up->bWaitBreakString = TRUE ;
2696
2697	up->bSkipCntrlCharOnly = TRUE ;
2698
2699	up->iClockState = TELJJY_STATE_IDLE ;
2700	up->iClockEvent = TELJJY_EVENT_NULL ;
2701
2702	/* Check the telephone number */
2703
2704	if ( sys_phone[0] == NULL ) {
2705		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
2706		up->bInitError = TRUE ;
2707		return 1 ;
2708	}
2709
2710	if ( sys_phone[1] != NULL ) {
2711		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
2712		up->bInitError = TRUE ;
2713		return 1 ;
2714	}
2715
2716	iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
2717	for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
2718		if ( isdigit( *(sys_phone[0]+i) ) ) {
2719			if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
2720				sFirstThreeDigits[iFirstThreeDigitsCount++] = *(sys_phone[0]+i) ;
2721			}
2722			iNumberOfDigitsOfPhoneNumber ++ ;
2723		} else if ( *(sys_phone[0]+i) == ',' ) {
2724			iCommaCount ++ ;
2725			if ( iCommaCount > 1 ) {
2726				msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
2727				up->bInitError = TRUE ;
2728				return 1 ;
2729			}
2730			iFirstThreeDigitsCount = 0 ;
2731			iCommaPosition = i ;
2732		} else if ( *(sys_phone[0]+i) != '-' ) {
2733			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
2734			up->bInitError = TRUE ;
2735			return 1 ;
2736		}
2737	}
2738	sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
2739
2740	if ( iCommaCount == 1 ) {
2741		if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
2742			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
2743			up->bInitError = TRUE ;
2744			return 1 ;
2745		}
2746	}
2747
2748	if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
2749		/* Too short or too long */
2750		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
2751		up->bInitError = TRUE ;
2752		return 1 ;
2753	}
2754
2755	if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
2756	  || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
2757	  || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
2758	  || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
2759	  || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
2760	  || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
2761	  || ( sFirstThreeDigits[0] == '0' &&  sFirstThreeDigits[2] == '0' ) ) {
2762		/* Not allowed because of emergency numbers or special service numbers */
2763		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
2764		up->bInitError = TRUE ;
2765		return 1 ;
2766	}
2767
2768	snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
2769	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2770
2771	if ( peer->minpoll < 8 ) {
2772		/* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
2773		int oldminpoll = peer->minpoll ;
2774		peer->minpoll = 8 ;
2775		if ( peer->ppoll < peer->minpoll ) {
2776			peer->ppoll = peer->minpoll ;
2777		}
2778		if ( peer->maxpoll < peer->minpoll ) {
2779			peer->maxpoll = peer->minpoll ;
2780		}
2781		snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
2782		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2783	}
2784
2785	return 0 ;
2786
2787}
2788
2789/**************************************************************************************************/
2790
2791static int
2792jjy_receive_telephone ( struct recvbuf *rbufp )
2793{
2794#ifdef DEBUG
2795	static	const char	*sFunctionName = "jjy_receive_telephone" ;
2796#endif
2797
2798	struct	peer         *peer;
2799	struct	refclockproc *pp ;
2800	struct	jjyunit      *up ;
2801	char	*pBuf ;
2802	int	iLen ;
2803	short	iPreviousModemState ;
2804
2805	peer = rbufp->recv_peer ;
2806	pp = peer->procptr ;
2807	up = pp->unitptr ;
2808
2809	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2810
2811	if ( up->iClockState == TELJJY_STATE_IDLE
2812	  || up->iClockState == TELJJY_STATE_DAILOUT
2813	  || up->iClockState == TELJJY_STATE_BYE ) {
2814
2815		iPreviousModemState = getModemState( up ) ;
2816
2817		modem_receive ( rbufp ) ;
2818
2819		if ( iPreviousModemState != up->iModemState ) {
2820			/* Modem state is changed just now. */
2821			if ( isModemStateDisconnect( up->iModemState ) ) {
2822				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2823				teljjy_control ( peer, pp, up ) ;
2824			} else if ( isModemStateConnect( up->iModemState ) ) {
2825				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2826				teljjy_control ( peer, pp, up ) ;
2827			}
2828		}
2829
2830		return JJY_RECEIVE_WAIT ;
2831
2832	}
2833
2834	if ( up->linediscipline == LDISC_RAW ) {
2835		pBuf = up->sTextBuf ;
2836		iLen = up->iTextBufLen ;
2837	} else {
2838		pBuf = pp->a_lastcode ;
2839		iLen = pp->lencode ;
2840	}
2841
2842	up->iTeljjySilentTimer = 0 ;
2843	if      ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN  ; }
2844	else if ( iLen == 1 && strncmp( pBuf, ">"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
2845	else if ( iLen >= 1 && strncmp( pBuf, "?"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR  ; }
2846	else                                                        { up->iClockEvent = TELJJY_EVENT_DATA   ; }
2847
2848	teljjy_control ( peer, pp, up ) ;
2849
2850	return JJY_RECEIVE_WAIT ;
2851
2852}
2853
2854/**************************************************************************************************/
2855
2856static void
2857jjy_poll_telephone ( int unit, struct peer *peer )
2858{
2859#ifdef DEBUG
2860	static const char *sFunctionName = "jjy_poll_telephone" ;
2861#endif
2862
2863	struct	refclockproc *pp ;
2864	struct	jjyunit      *up ;
2865
2866	pp = peer->procptr ;
2867	up = pp->unitptr ;
2868
2869	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2870
2871	if ( up->iClockState == TELJJY_STATE_IDLE ) {
2872		up->iRawBufLen = 0 ;
2873		up->iLineBufLen = 0 ;
2874		up->iTextBufLen = 0 ;
2875	}
2876
2877	up->iClockEvent = TELJJY_EVENT_START ;
2878	teljjy_control ( peer, pp, up ) ;
2879
2880}
2881
2882/**************************************************************************************************/
2883
2884static void
2885jjy_timer_telephone ( int unit, struct peer *peer )
2886{
2887#ifdef DEBUG
2888	static const char *sFunctionName = "jjy_timer_telephone" ;
2889#endif
2890
2891	struct	refclockproc *pp ;
2892	struct	jjyunit      *up ;
2893	short	iPreviousModemState ;
2894
2895	pp = peer->procptr ;
2896	up = pp->unitptr ;
2897
2898	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2899
2900	if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
2901		up->iTeljjySilentTimer++ ;
2902		if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
2903			up->iClockEvent = TELJJY_EVENT_SILENT ;
2904			teljjy_control ( peer, pp, up ) ;
2905		}
2906	}
2907
2908	if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
2909		up->iTeljjyStateTimer++ ;
2910		if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
2911			up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
2912			teljjy_control ( peer, pp, up ) ;
2913		}
2914	}
2915
2916	if ( isModemStateTimerOn( up ) ) {
2917
2918		iPreviousModemState = getModemState( up ) ;
2919
2920		modem_timer ( unit, peer ) ;
2921
2922		if ( iPreviousModemState != up->iModemState ) {
2923			/* Modem state is changed just now. */
2924			if ( isModemStateDisconnect( up->iModemState ) ) {
2925				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2926				teljjy_control ( peer, pp, up ) ;
2927			} else if ( isModemStateConnect( up->iModemState ) ) {
2928				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2929				teljjy_control ( peer, pp, up ) ;
2930			}
2931		}
2932
2933	}
2934
2935}
2936
2937/**************************************************************************************************/
2938
2939static void
2940teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
2941{
2942
2943	int	i, rc ;
2944	short	iPostEvent = TELJJY_EVENT_NULL ;
2945
2946	DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
2947
2948	rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
2949
2950	if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
2951		iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
2952#ifdef DEBUG
2953		if ( debug ) {
2954			printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd  iPostEvent=%hd\n",
2955				up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
2956		}
2957#endif
2958		up->iTeljjySilentTimer = 0 ;
2959		if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
2960			/* Telephone JJY state is changing now */
2961			up->iTeljjyStateTimer = 0 ;
2962			up->bLineError = FALSE ;
2963			up->iClockCommandSeq = 0 ;
2964			up->iTimestampCount = 0 ;
2965			up->iLoopbackCount = 0 ;
2966			for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
2967				up->bLoopbackTimeout[i] = FALSE ;
2968			}
2969			if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
2970				/* Telephone JJY state is changing to IDLE just now */
2971				up->iProcessState = JJY_PROCESS_STATE_DONE ;
2972			}
2973		}
2974		up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
2975
2976	}
2977
2978	if ( iPostEvent != TELJJY_EVENT_NULL ) {
2979		up->iClockEvent = iPostEvent ;
2980		teljjy_control ( peer, pp, up ) ;
2981	}
2982
2983	up->iClockEvent = TELJJY_EVENT_NULL ;
2984
2985}
2986
2987/**************************************************************************************************/
2988
2989static void
2990teljjy_setDelay ( struct peer *peer, struct jjyunit *up )
2991{
2992
2993	char	sLog [ 60 ] ;
2994	int	milliSecond, microSecond ;
2995
2996	gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
2997
2998	up->delayTime[up->iLoopbackCount].tv_sec  -= up->sendTime[up->iLoopbackCount].tv_sec ;
2999	up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
3000	if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
3001		up->delayTime[up->iLoopbackCount].tv_sec -- ;
3002		up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
3003	}
3004
3005	milliSecond  = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
3006	microSecond  = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
3007	milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
3008
3009	snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
3010		  milliSecond, microSecond ) ;
3011
3012	if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
3013		/* Delay > 700 mS */
3014		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3015	} else {
3016		/* Delay <= 700 mS */
3017		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3018	}
3019
3020}
3021
3022/**************************************************************************************************/
3023
3024static int
3025teljjy_getDelay ( struct peer *peer, struct jjyunit *up )
3026{
3027
3028	struct	timeval maxTime, minTime, averTime ;
3029	int	i ;
3030	int	minIndex = 0, maxIndex = 0, iAverCount = 0 ;
3031	int	iThresholdSecond, iThresholdMicroSecond ;
3032	int	iPercent ;
3033
3034	minTime.tv_sec = minTime.tv_usec = 0 ;
3035	maxTime.tv_sec = maxTime.tv_usec = 0 ;
3036
3037	iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
3038	iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
3039
3040	up->iLoopbackValidCount = 0 ;
3041
3042	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3043		if ( up->bLoopbackTimeout[i]
3044		  || up->delayTime[i].tv_sec  > iThresholdSecond
3045		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3046		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3047			continue ;
3048		}
3049		if ( up->iLoopbackValidCount == 0 ) {
3050			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3051			minTime.tv_usec = up->delayTime[i].tv_usec ;
3052			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3053			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3054			minIndex = maxIndex = i ;
3055		} else if ( minTime.tv_sec  > up->delayTime[i].tv_sec
3056		       || ( minTime.tv_sec == up->delayTime[i].tv_sec
3057		         && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
3058			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3059			minTime.tv_usec = up->delayTime[i].tv_usec ;
3060			minIndex = i ;
3061		} else if ( maxTime.tv_sec  < up->delayTime[i].tv_sec
3062		       || ( maxTime.tv_sec == up->delayTime[i].tv_sec
3063		         && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
3064			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3065			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3066			maxIndex = i ;
3067		}
3068		up->iLoopbackValidCount ++ ;
3069	}
3070
3071	if ( up->iLoopbackValidCount < 2 ) {
3072		return -1 ;
3073	}
3074
3075	averTime.tv_usec = 0;
3076
3077	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3078		if ( up->bLoopbackTimeout[i]
3079		  || up->delayTime[i].tv_sec  > iThresholdSecond
3080		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3081		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3082			continue ;
3083		}
3084		if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
3085			continue ;
3086		}
3087		if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
3088			continue ;
3089		}
3090		averTime.tv_usec += up->delayTime[i].tv_usec ;
3091		iAverCount ++ ;
3092	}
3093
3094	if ( iAverCount == 0 ) {
3095		/* This is never happened. */
3096		/* Previous for-if-for blocks assure iAverCount > 0. */
3097		/* This code avoids a claim by the coverity scan tool. */
3098		return -1 ;
3099	}
3100
3101	/* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
3102
3103	iPercent = ( peer->ttl - 100 ) ;
3104
3105	/* Average delay time in milli second */
3106
3107	return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
3108
3109}
3110
3111/******************************/
3112static int
3113teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3114{
3115
3116	DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
3117
3118	return TELJJY_STAY_CLOCK_STATE ;
3119
3120}
3121
3122/******************************/
3123static int
3124teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3125{
3126
3127	DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
3128
3129	modem_connect ( peer->refclkunit, peer ) ;
3130
3131	return TELJJY_CHANGE_CLOCK_STATE ;
3132
3133}
3134
3135/******************************/
3136static int
3137teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3138{
3139
3140	DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
3141
3142	return TELJJY_STAY_CLOCK_STATE ;
3143
3144}
3145
3146/******************************/
3147static int
3148teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3149{
3150
3151	DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
3152
3153	return TELJJY_CHANGE_CLOCK_STATE ;
3154
3155}
3156
3157/******************************/
3158static int
3159teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3160{
3161
3162	DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
3163
3164	return TELJJY_CHANGE_CLOCK_STATE ;
3165
3166}
3167
3168/******************************/
3169static int
3170teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3171{
3172
3173	DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
3174
3175	return TELJJY_STAY_CLOCK_STATE ;
3176
3177}
3178
3179/******************************/
3180static int
3181teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3182{
3183
3184	DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
3185
3186	return TELJJY_CHANGE_CLOCK_STATE ;
3187
3188}
3189
3190/******************************/
3191static int
3192teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3193{
3194
3195	int	i ;
3196
3197	DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
3198
3199	up->bLineError = FALSE ;
3200	up->iClockCommandSeq = 0 ;
3201	up->iTimestampCount = 0 ;
3202	up->iLoopbackCount = 0 ;
3203	for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3204		up->bLoopbackTimeout[i] = FALSE ;
3205	}
3206
3207	return TELJJY_CHANGE_CLOCK_STATE ;
3208
3209}
3210
3211/******************************/
3212static int
3213teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3214{
3215
3216	char	*pCmd ;
3217	int	iCmdLen ;
3218
3219	DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
3220
3221	/* Send a guest user ID */
3222	pCmd = "TJJY\r" ;
3223
3224	/* Send login ID */
3225	iCmdLen = strlen( pCmd ) ;
3226	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
3227		refclock_report( peer, CEVNT_FAULT ) ;
3228	}
3229
3230	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3231
3232	return TELJJY_STAY_CLOCK_STATE ;
3233
3234}
3235
3236/******************************/
3237static int
3238teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3239{
3240
3241	DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
3242
3243	if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
3244		refclock_report( peer, CEVNT_FAULT ) ;
3245	}
3246
3247	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
3248
3249	up->iTeljjySilentTimer = 0 ;
3250
3251	return TELJJY_CHANGE_CLOCK_STATE ;
3252
3253}
3254
3255/******************************/
3256static int
3257teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3258{
3259
3260	DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
3261
3262	return TELJJY_CHANGE_CLOCK_STATE ;
3263
3264}
3265
3266/******************************/
3267static int
3268teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3269{
3270
3271	DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
3272
3273	return TELJJY_STAY_CLOCK_STATE ;
3274
3275}
3276
3277/******************************/
3278static int
3279teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3280{
3281
3282	DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
3283
3284	return TELJJY_CHANGE_CLOCK_STATE ;
3285
3286}
3287
3288/******************************/
3289static int
3290teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3291{
3292
3293	const char	*pCmd ;
3294	int	i, iLen, iNextClockState ;
3295
3296	DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
3297
3298	if ( up->iClockCommandSeq > 0
3299	  && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
3300		/* Command sequence has been completed */
3301	  	return TELJJY_CHANGE_CLOCK_STATE ;
3302	}
3303
3304	if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
3305		/* Skip loopback */
3306
3307		up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
3308
3309	} else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
3310		/* Loopback start */
3311
3312		up->iLoopbackCount = 0 ;
3313		for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3314			up->bLoopbackTimeout[i] = FALSE ;
3315		}
3316
3317	} else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
3318		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3319		 && up->iLoopbackCount < MAX_LOOPBACK ) {
3320		/* Loopback character comes */
3321#ifdef DEBUG
3322		if ( debug ) {
3323			printf( "refclock_jjy.c : teljjy_conn_send : iLoopbackCount=%d\n",
3324				 up->iLoopbackCount ) ;
3325		}
3326#endif
3327
3328		teljjy_setDelay( peer, up ) ;
3329
3330		up->iLoopbackCount ++ ;
3331
3332	}
3333
3334	up->iClockCommandSeq++ ;
3335
3336	pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
3337	iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
3338
3339	if ( pCmd != NULL ) {
3340
3341		if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
3342			refclock_report( peer, CEVNT_FAULT ) ;
3343		}
3344
3345		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3346			/* Loopback character and timestamp */
3347			gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
3348			up->bLoopbackMode = TRUE ;
3349		} else {
3350			/* Regular command */
3351			up->bLoopbackMode = FALSE ;
3352		}
3353
3354		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3355
3356		if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
3357			/* Last command of the command sequence */
3358			iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3359		} else {
3360			/* More commands to be issued */
3361			iNextClockState = TELJJY_STAY_CLOCK_STATE ;
3362		}
3363
3364	} else {
3365
3366		iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3367
3368	}
3369
3370	return iNextClockState ;
3371
3372}
3373
3374/******************************/
3375static int
3376teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3377{
3378
3379	char	*pBuf ;
3380	int	iLen, rc ;
3381	char	sLog [ 80 ] ;
3382	char	bAdjustment ;
3383
3384
3385	DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
3386
3387	if ( up->linediscipline == LDISC_RAW ) {
3388		pBuf = up->sTextBuf ;
3389		iLen = up->iTextBufLen ;
3390	} else {
3391		pBuf = pp->a_lastcode ;
3392		iLen = pp->lencode ;
3393	}
3394
3395	if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3396	  && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3397	  && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
3398	  && up->iLoopbackCount < MAX_LOOPBACK ) {
3399		/* Loopback */
3400
3401		teljjy_setDelay( peer, up ) ;
3402
3403		up->iLoopbackCount ++ ;
3404
3405	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3406	    && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
3407		/* Maybe echoback */
3408
3409		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
3410
3411	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3412		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
3413		/* 4DATE<CR> -> YYYYMMDD<CR> */
3414
3415		rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
3416
3417		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
3418		  || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
3419			/* Invalid date */
3420			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
3421				  rc, up->year, up->month, up->day ) ;
3422			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3423			up->bLineError = TRUE ;
3424		}
3425
3426	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3427		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
3428	         && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
3429		/* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
3430
3431		rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
3432
3433		if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
3434			/* Invalid leap second */
3435			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
3436				  pBuf ) ;
3437			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3438			up->bLineError = TRUE ;
3439		}
3440
3441	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3442		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
3443		/* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
3444
3445		rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
3446
3447		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
3448			/* Invalid time */
3449			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
3450				  rc, up->hour, up->minute, up->second ) ;
3451			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3452			up->bLineError = TRUE ;
3453		}
3454		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
3455
3456		up->iTimestampCount++ ;
3457
3458		if ( up->iTimestampCount == 6 && ! up->bLineError ) {
3459#if DEBUG
3460			printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
3461				up->bLineError,
3462				up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
3463#endif
3464			bAdjustment = TRUE ;
3465
3466			if ( peer->ttl == 100 ) {
3467				/* mode=100 */
3468				up->msecond = 0 ;
3469			} else {
3470				/* mode=101 to 110 */
3471				up->msecond = teljjy_getDelay( peer, up ) ;
3472				if (up->msecond < 0 ) {
3473					up->msecond = 0 ;
3474					bAdjustment = FALSE ;
3475				}
3476			}
3477
3478			if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
3479			  &&   up->iTimestamp[2]        <= up->iTimestamp[3]
3480			  && ( up->iTimestamp[3] +  1 ) == up->iTimestamp[4]
3481			  && ( up->iTimestamp[4] +  1 ) == up->iTimestamp[5] ) {
3482				/* Non over midnight */
3483
3484				jjy_synctime( peer, pp, up ) ;
3485
3486				if ( peer->ttl != 100 ) {
3487					if ( bAdjustment ) {
3488						snprintf( sLog, sizeof(sLog),
3489							  JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
3490							  up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3491						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3492					} else {
3493						snprintf( sLog, sizeof(sLog),
3494							  JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
3495							   up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3496						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3497					}
3498				}
3499
3500			}
3501		}
3502
3503	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
3504		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3505		/* Loopback noise ( Unexpected replay ) */
3506
3507		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
3508			  pBuf ) ;
3509		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3510
3511	} else {
3512
3513		up->bLineError = TRUE ;
3514
3515		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
3516			  pBuf ) ;
3517		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3518
3519	}
3520
3521	return TELJJY_STAY_CLOCK_STATE ;
3522
3523}
3524
3525/******************************/
3526static int
3527teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3528{
3529
3530	const char	*pCmd ;
3531
3532	DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
3533
3534	if ( up->iClockCommandSeq >= 1
3535	  && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
3536		/* Loopback */
3537#ifdef DEBUG
3538		if ( debug ) {
3539			printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
3540		}
3541#endif
3542		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3543			up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
3544		}
3545		up->iTeljjySilentTimer = 0 ;
3546		return teljjy_conn_send( peer, pp, up ) ;
3547	} else {
3548		pCmd = "\r" ;
3549	}
3550
3551	if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
3552		refclock_report( peer, CEVNT_FAULT ) ;
3553	}
3554
3555	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3556
3557	up->iTeljjySilentTimer = 0 ;
3558
3559	return TELJJY_STAY_CLOCK_STATE ;
3560
3561}
3562
3563/******************************/
3564static int
3565teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3566{
3567
3568	DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
3569
3570	return TELJJY_CHANGE_CLOCK_STATE ;
3571
3572}
3573
3574/******************************/
3575static int
3576teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3577{
3578
3579	DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
3580
3581	return TELJJY_STAY_CLOCK_STATE ;
3582
3583}
3584
3585/******************************/
3586static int
3587teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3588{
3589
3590	DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
3591
3592	return TELJJY_CHANGE_CLOCK_STATE ;
3593
3594}
3595
3596/******************************/
3597static int
3598teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3599{
3600
3601	DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
3602
3603	modem_disconnect ( peer->refclkunit, peer ) ;
3604
3605	return TELJJY_STAY_CLOCK_STATE ;
3606
3607}
3608
3609/*################################################################################################*/
3610/*################################################################################################*/
3611/*##												##*/
3612/*##    Modem control finite state machine							##*/
3613/*##												##*/
3614/*################################################################################################*/
3615/*################################################################################################*/
3616
3617/* struct jjyunit.iModemState */
3618
3619#define	MODEM_STATE_DISCONNECT		0
3620#define	MODEM_STATE_INITIALIZE		1
3621#define	MODEM_STATE_DAILING		2
3622#define	MODEM_STATE_CONNECT		3
3623#define	MODEM_STATE_ESCAPE		4
3624
3625/* struct jjyunit.iModemEvent */
3626
3627#define MODEM_EVENT_NULL		0
3628#define	MODEM_EVENT_INITIALIZE		1
3629#define	MODEM_EVENT_DIALOUT		2
3630#define	MODEM_EVENT_DISCONNECT		3
3631#define	MODEM_EVENT_RESP_OK		4
3632#define	MODEM_EVENT_RESP_CONNECT	5
3633#define	MODEM_EVENT_RESP_RING		6
3634#define	MODEM_EVENT_RESP_NO_CARRIER	7
3635#define	MODEM_EVENT_RESP_ERROR		8
3636#define	MODEM_EVENT_RESP_CONNECT_X	9
3637#define	MODEM_EVENT_RESP_NO_DAILTONE	10
3638#define	MODEM_EVENT_RESP_BUSY		11
3639#define	MODEM_EVENT_RESP_NO_ANSWER	12
3640#define	MODEM_EVENT_RESP_UNKNOWN	13
3641#define	MODEM_EVENT_SILENT		14
3642#define	MODEM_EVENT_TIMEOUT		15
3643
3644/* Function prototypes */
3645
3646static	void	modem_control		( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3647
3648static	int 	modem_disc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3649static	int 	modem_disc_init  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3650static	int 	modem_init_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3651static	int 	modem_init_start 	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3652static	int 	modem_init_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3653static	int 	modem_init_resp00	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3654static	int 	modem_init_resp04	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3655static	int 	modem_dial_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3656static	int 	modem_dial_dialout	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3657static	int 	modem_dial_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3658static	int 	modem_dial_connect	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3659static	int 	modem_dial_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3660static	int 	modem_conn_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3661static	int 	modem_conn_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3662static	int 	modem_esc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3663static	int 	modem_esc_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3664static	int 	modem_esc_data  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3665static	int 	modem_esc_silent	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3666static	int 	modem_esc_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3667
3668static int ( *pModemHandler [ ] [ 5 ] ) ( ) =
3669{                         	/*STATE_DISCONNECT   STATE_INITIALIZE   STATE_DAILING       STATE_CONNECT      STATE_ESCAPE     */
3670/* NULL                 */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3671/* INITIALIZE           */	{ modem_disc_init  , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3672/* DIALOUT              */	{ modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
3673/* DISCONNECT           */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_escape },
3674/* RESP: 0: OK          */	{ modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3675/* RESP: 1: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3676/* RESP: 2: RING        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3677/* RESP: 3: NO CARRIER  */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3678/* RESP: 4: ERROR       */	{ modem_disc_ignore, modem_init_resp04, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3679/* RESP: 5: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3680/* RESP: 6: NO DAILTONE */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3681/* RESP: 7: BUSY        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3682/* RESP: 8: NO ANSWER   */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3683/* RESP: 9: UNKNOWN     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3684/* SILENT               */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
3685/* TIMEOUT              */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_disc   }
3686} ;
3687
3688static short iModemNextState [ ] [ 5 ] =
3689{                         	/*STATE_DISCONNECT        STATE_INITIALIZE        STATE_DAILING        STATE_CONNECT        STATE_ESCAPE           */
3690/* NULL                 */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3691/* INITIALIZE           */	{ MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3692/* DIALOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3693/* DISCONNECT           */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE     },
3694/* RESP: 0: OK          */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3695/* RESP: 1: CONNECT     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3696/* RESP: 2: RING        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3697/* RESP: 3: NO CARRIER  */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3698/* RESP: 4: ERROR       */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3699/* RESP: 5: CONNECT X   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3700/* RESP: 6: NO DAILTONE */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3701/* RESP: 7: BUSY        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3702/* RESP: 8: NO ANSWER   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3703/* RESP: 9: UNKNOWN     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3704/* SILENT               */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
3705/* TIMEOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
3706} ;
3707
3708static short iModemPostEvent [ ] [ 5 ] =
3709{                         	/*STATE_DISCONNECT        STATE_INITIALIZE     STATE_DAILING           STATE_CONNECT           STATE_ESCAPE     */
3710/* NULL                 */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3711/* INITIALIZE           */	{ MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3712/* DIALOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3713/* DISCONNECT           */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
3714/* RESP: 0: OK          */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3715/* RESP: 1: CONNECT     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3716/* RESP: 2: RING        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3717/* RESP: 3: NO CARRIER  */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3718/* RESP: 4: ERROR       */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3719/* RESP: 5: CONNECT X   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3720/* RESP: 6: NO DAILTONE */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3721/* RESP: 7: BUSY        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3722/* RESP: 8: NO ANSWER   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3723/* RESP: 9: UNKNOWN     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3724/* SILENT               */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3725/* TIMEOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
3726} ;
3727
3728static short iModemSilentTimeout [ 5 ] = { 0,  0,  0, 0,  5 } ;
3729static short iModemStateTimeout  [ 5 ] = { 0, 20, 90, 0, 20 } ;
3730
3731#define	STAY_MODEM_STATE	0
3732#define	CHANGE_MODEM_STATE	1
3733
3734#ifdef	DEBUG
3735#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 ) ; } }
3736#else
3737#define	DEBUG_MODEM_PRINTF(sFunc)
3738#endif
3739
3740/**************************************************************************************************/
3741
3742static short
3743getModemState ( struct jjyunit *up )
3744{
3745	return up->iModemState ;
3746}
3747
3748/**************************************************************************************************/
3749
3750static int
3751isModemStateConnect ( short iCheckState )
3752{
3753	return ( iCheckState == MODEM_STATE_CONNECT ) ;
3754}
3755
3756/**************************************************************************************************/
3757
3758static int
3759isModemStateDisconnect ( short iCheckState )
3760{
3761	return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
3762}
3763
3764/**************************************************************************************************/
3765
3766static int
3767isModemStateTimerOn ( struct jjyunit *up )
3768{
3769	return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
3770}
3771
3772/**************************************************************************************************/
3773
3774static void
3775modem_connect ( int unit, struct peer *peer )
3776{
3777	struct	refclockproc	*pp;
3778	struct	jjyunit 	*up;
3779
3780	pp = peer->procptr ;
3781	up = pp->unitptr ;
3782
3783	DEBUG_MODEM_PRINTF( "modem_connect" ) ;
3784
3785	up->iModemEvent = MODEM_EVENT_INITIALIZE ;
3786
3787	modem_control ( peer, pp, up ) ;
3788
3789}
3790
3791/**************************************************************************************************/
3792
3793static void
3794modem_disconnect ( int unit, struct peer *peer )
3795{
3796	struct	refclockproc	*pp;
3797	struct	jjyunit 	*up;
3798
3799	pp = peer->procptr ;
3800	up = pp->unitptr ;
3801
3802	DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
3803
3804	up->iModemEvent = MODEM_EVENT_DISCONNECT ;
3805
3806	modem_control ( peer, pp, up ) ;
3807
3808}
3809
3810/**************************************************************************************************/
3811
3812static int
3813modem_receive ( struct recvbuf *rbufp )
3814{
3815
3816	struct	peer		*peer;
3817	struct	jjyunit		*up;
3818	struct	refclockproc	*pp;
3819	char	*pBuf ;
3820	int	iLen ;
3821
3822#ifdef DEBUG
3823	static const char *sFunctionName = "modem_receive" ;
3824#endif
3825
3826	peer = rbufp->recv_peer ;
3827	pp = peer->procptr ;
3828	up = pp->unitptr ;
3829
3830	DEBUG_MODEM_PRINTF( sFunctionName ) ;
3831
3832	if ( up->linediscipline == LDISC_RAW ) {
3833		pBuf = up->sTextBuf ;
3834		iLen = up->iTextBufLen ;
3835	} else {
3836		pBuf = pp->a_lastcode ;
3837		iLen = pp->lencode ;
3838	}
3839
3840	if      ( iLen ==  2 && strncmp( pBuf, "OK"         ,  2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK          ; }
3841	else if ( iLen ==  7 && strncmp( pBuf, "CONNECT"    ,  7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT     ; }
3842	else if ( iLen ==  4 && strncmp( pBuf, "RING"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING        ; }
3843	else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER  ; }
3844	else if ( iLen ==  5 && strncmp( pBuf, "ERROR"      ,  5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR       ; }
3845	else if ( iLen >=  8 && strncmp( pBuf, "CONNECT "   ,  8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X   ; }
3846	else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
3847	else if ( iLen ==  4 && strncmp( pBuf, "BUSY"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY        ; }
3848	else if ( iLen ==  9 && strncmp( pBuf, "NO ANSWER"  ,  9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER   ; }
3849	else                                                              { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN     ; }
3850
3851#ifdef DEBUG
3852	if ( debug ) {
3853		char	sResp [ 40 ] ;
3854		int	iCopyLen ;
3855		iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3856		strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3857		sResp[iCopyLen] = 0 ;
3858		printf ( "refclock_jjy.c : modem_receive : iLen=%d pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
3859	}
3860#endif
3861	modem_control ( peer, pp, up ) ;
3862
3863	return 0 ;
3864
3865}
3866
3867/**************************************************************************************************/
3868
3869static void
3870modem_timer ( int unit, struct peer *peer )
3871{
3872
3873	struct	refclockproc *pp ;
3874	struct	jjyunit      *up ;
3875
3876	pp = peer->procptr ;
3877	up = pp->unitptr ;
3878
3879	DEBUG_MODEM_PRINTF( "modem_timer" ) ;
3880
3881	if ( iModemSilentTimeout[up->iModemState] != 0 ) {
3882		up->iModemSilentTimer++ ;
3883		if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
3884			up->iModemEvent = MODEM_EVENT_SILENT ;
3885			modem_control ( peer, pp, up ) ;
3886		}
3887	}
3888
3889	if ( iModemStateTimeout[up->iModemState] != 0 ) {
3890		up->iModemStateTimer++ ;
3891		if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
3892			up->iModemEvent = MODEM_EVENT_TIMEOUT ;
3893			modem_control ( peer, pp, up ) ;
3894		}
3895	}
3896
3897}
3898
3899/**************************************************************************************************/
3900
3901static void
3902modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3903{
3904
3905	int	rc ;
3906	short	iPostEvent = MODEM_EVENT_NULL ;
3907
3908	DEBUG_MODEM_PRINTF( "modem_control" ) ;
3909
3910	rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
3911
3912	if ( rc == CHANGE_MODEM_STATE ) {
3913		iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
3914#ifdef DEBUG
3915		if ( debug ) {
3916			printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d  iPostEvent=%d\n",
3917				 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
3918		}
3919#endif
3920
3921		if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
3922			up->iModemSilentCount = 0 ;
3923			up->iModemStateTimer = 0 ;
3924			up->iModemCommandSeq = 0 ;
3925		}
3926
3927		up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
3928	}
3929
3930	if ( iPostEvent != MODEM_EVENT_NULL ) {
3931		up->iModemEvent = iPostEvent ;
3932		modem_control ( peer, pp, up ) ;
3933	}
3934
3935	up->iModemEvent = MODEM_EVENT_NULL ;
3936
3937}
3938
3939/******************************/
3940static int
3941modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3942{
3943
3944	DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
3945
3946	return STAY_MODEM_STATE ;
3947
3948}
3949
3950/******************************/
3951static int
3952modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3953{
3954
3955	DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
3956
3957	return CHANGE_MODEM_STATE ;
3958
3959}
3960
3961/******************************/
3962static int
3963modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3964{
3965
3966	DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
3967
3968	return STAY_MODEM_STATE ;
3969
3970}
3971
3972/******************************/
3973static int
3974modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3975{
3976
3977	DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
3978
3979	up->iModemCommandSeq = 0 ;
3980
3981#ifdef DEBUG
3982	if ( debug ) {
3983		printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
3984	}
3985#endif
3986
3987	return modem_init_resp00( peer, pp, up ) ;
3988
3989}
3990
3991/******************************/
3992static int
3993modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3994{
3995
3996	char	*pCmd, cBuf [ 46 ] ;
3997	int	iCmdLen ;
3998	int	iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
3999	int	iNextModemState = STAY_MODEM_STATE ;
4000
4001	DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
4002
4003	up->iModemCommandSeq++ ;
4004
4005	switch ( up->iModemCommandSeq ) {
4006
4007	case 1 :
4008		/* En = Echoback      0:Off      1:On   */
4009		/* Qn = Result codes  0:On       1:Off  */
4010		/* Vn = Result codes  0:Numeric  1:Text */
4011		pCmd = "ATE0Q0V1\r\n" ;
4012		break ;
4013
4014	case 2 :
4015		/* Mn = Speaker switch  0:Off  1:On until remote carrier detected  2:On */
4016		if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
4017			/* fudge 127.127.40.n flag3 0 */
4018			iSpeakerSwitch = 0 ;
4019		} else {
4020			/* fudge 127.127.40.n flag3 1 */
4021			iSpeakerSwitch = 2 ;
4022		}
4023
4024		/* Ln = Speaker volume  0:Very low  1:Low  2:Middle  3:High */
4025		if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
4026			/* fudge 127.127.40.n flag4 0 */
4027			iSpeakerVolume = 1 ;
4028		} else {
4029			/* fudge 127.127.40.n flag4 1 */
4030			iSpeakerVolume = 2 ;
4031		}
4032
4033		pCmd = cBuf ;
4034		snprintf( pCmd, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
4035		break ;
4036
4037	case 3 :
4038		/* &Kn = Flow control  4:XON/XOFF */
4039		pCmd = "AT&K4\r\n" ;
4040		break ;
4041
4042	case 4 :
4043		/* +MS = Protocol  V22B:1200,2400bps�iV.22bis) */
4044		pCmd = "AT+MS=V22B\r\n" ;
4045		break ;
4046
4047	case 5 :
4048		/* %Cn = Data compression  0:No data compression */
4049		pCmd = "AT%C0\r\n" ;
4050		break ;
4051
4052	case 6 :
4053		/* \Nn = Error correction  0:Normal mode  1:Direct mode  2:V42,MNP  3:V42,MNP,Normal */
4054		if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
4055			/* fudge 127.127.40.n flag2 0 */
4056			iErrorCorrection = 0 ;
4057		} else {
4058			/* fudge 127.127.40.n flag2 1 */
4059			iErrorCorrection = 3 ;
4060		}
4061
4062		pCmd = cBuf ;
4063		snprintf( pCmd, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
4064		break ;
4065
4066	case 7 :
4067		/* Hn = Hook  0:Hook-On ( Disconnect )  1:Hook-Off ( Connect ) */
4068		pCmd = "ATH1\r\n" ;
4069		break ;
4070
4071	case 8 :
4072		/* Initialize completion */
4073		pCmd = NULL ;
4074		iNextModemState = CHANGE_MODEM_STATE ;
4075		break ;
4076
4077	default :
4078		pCmd = NULL ;
4079		break ;
4080
4081	}
4082
4083	if ( pCmd != NULL ) {
4084
4085		iCmdLen = strlen( pCmd ) ;
4086		if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4087			refclock_report( peer, CEVNT_FAULT ) ;
4088		}
4089
4090		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4091
4092	}
4093
4094	return iNextModemState ;
4095
4096}
4097
4098/******************************/
4099static int
4100modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4101{
4102
4103	DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
4104
4105	return modem_init_resp00( peer, pp, up ) ;
4106
4107}
4108
4109/******************************/
4110static int
4111modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4112{
4113
4114	DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
4115#ifdef DEBUG
4116	if ( debug ) {
4117		printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
4118	}
4119#endif
4120
4121	return CHANGE_MODEM_STATE ;
4122
4123}
4124
4125/******************************/
4126static int
4127modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4128{
4129
4130	DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
4131
4132	return STAY_MODEM_STATE ;
4133
4134}
4135
4136/******************************/
4137static int
4138modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4139{
4140
4141	char	sCmd [ 46 ] ;
4142	int	iCmdLen ;
4143	char	cToneOrPulse ;
4144
4145	DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
4146
4147	/* Tone or Pulse */
4148	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
4149		/* fudge 127.127.40.n flag1 0 */
4150		cToneOrPulse = 'T' ;
4151	} else {
4152		/* fudge 127.127.40.n flag1 1 */
4153		cToneOrPulse = 'P' ;
4154	}
4155
4156	/* Connect ( Dial number ) */
4157	snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
4158
4159	/* Send command */
4160	iCmdLen = strlen( sCmd ) ;
4161	if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
4162		refclock_report( peer, CEVNT_FAULT ) ;
4163	}
4164
4165	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
4166
4167	return STAY_MODEM_STATE ;
4168
4169}
4170
4171/******************************/
4172static int
4173modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4174{
4175
4176	DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
4177#ifdef DEBUG
4178	if ( debug ) {
4179		printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
4180	}
4181#endif
4182
4183	return modem_conn_escape( peer, pp, up ) ;
4184
4185}
4186
4187/******************************/
4188static int
4189modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4190{
4191
4192	DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
4193
4194	return CHANGE_MODEM_STATE ;
4195
4196}
4197
4198/******************************/
4199static int
4200modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4201{
4202
4203	DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
4204#ifdef DEBUG
4205	if ( debug ) {
4206		printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
4207	}
4208#endif
4209
4210	modem_esc_disc( peer, pp, up ) ;
4211
4212	return CHANGE_MODEM_STATE ;
4213
4214}
4215
4216/******************************/
4217static int
4218modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4219{
4220
4221	DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
4222
4223	return STAY_MODEM_STATE ;
4224
4225}
4226
4227/******************************/
4228static int
4229modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4230{
4231
4232	DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
4233
4234	return CHANGE_MODEM_STATE ;
4235
4236}
4237
4238/******************************/
4239static int
4240modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4241{
4242
4243	DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
4244
4245	return STAY_MODEM_STATE ;
4246
4247}
4248
4249/******************************/
4250static int
4251modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4252{
4253
4254	char	*pCmd ;
4255	int	iCmdLen ;
4256
4257	DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
4258
4259	/* Escape command ( Go to command mode ) */
4260	pCmd = "+++" ;
4261
4262	/* Send command */
4263	iCmdLen = strlen( pCmd ) ;
4264	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4265		refclock_report( peer, CEVNT_FAULT ) ;
4266	}
4267
4268	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4269
4270	return STAY_MODEM_STATE ;
4271
4272}
4273
4274/******************************/
4275static int
4276modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4277{
4278
4279	DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
4280
4281	up->iModemSilentTimer = 0 ;
4282
4283	return STAY_MODEM_STATE ;
4284
4285}
4286
4287/******************************/
4288static int
4289modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4290{
4291
4292	DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
4293
4294	up->iModemSilentCount ++ ;
4295
4296	if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
4297#ifdef DEBUG
4298		if ( debug ) {
4299			printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
4300		}
4301#endif
4302		modem_esc_escape( peer, pp, up ) ;
4303		up->iModemSilentTimer = 0 ;
4304		return STAY_MODEM_STATE ;
4305	}
4306
4307#ifdef DEBUG
4308	if ( debug ) {
4309		printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
4310	}
4311#endif
4312	return modem_esc_disc( peer, pp, up ) ;
4313
4314}
4315/******************************/
4316static int
4317modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4318{
4319
4320	char	*pCmd ;
4321	int	iCmdLen ;
4322
4323	DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
4324
4325	/* Disconnect */
4326	pCmd = "ATH0\r\n" ;
4327
4328	/* Send command */
4329	iCmdLen = strlen( pCmd ) ;
4330	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4331		refclock_report( peer, CEVNT_FAULT ) ;
4332	}
4333
4334	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4335
4336	return CHANGE_MODEM_STATE ;
4337
4338}
4339
4340/*################################################################################################*/
4341/*################################################################################################*/
4342/*##												##*/
4343/*##    jjy_write_clockstats									##*/
4344/*##												##*/
4345/*################################################################################################*/
4346/*################################################################################################*/
4347
4348static void
4349jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
4350{
4351
4352	char	sLog [ 100 ] ;
4353	char	*pMark ;
4354	int 	iMarkLen, iDataLen ;
4355
4356	switch ( iMark ) {
4357	case JJY_CLOCKSTATS_MARK_JJY :
4358		pMark = "JJY " ;
4359		break ;
4360	case JJY_CLOCKSTATS_MARK_SEND :
4361		pMark = "--> " ;
4362		break ;
4363	case JJY_CLOCKSTATS_MARK_RECEIVE :
4364		pMark = "<-- " ;
4365		break ;
4366	case JJY_CLOCKSTATS_MARK_INFORMATION :
4367		pMark = "--- " ;
4368		break ;
4369	case JJY_CLOCKSTATS_MARK_ATTENTION :
4370		pMark = "=== " ;
4371		break ;
4372	case JJY_CLOCKSTATS_MARK_WARNING :
4373		pMark = "-W- " ;
4374		break ;
4375	case JJY_CLOCKSTATS_MARK_ERROR :
4376		pMark = "-X- " ;
4377		break ;
4378	default :
4379		pMark = "" ;
4380		break ;
4381	}
4382
4383	iDataLen = strlen( pData ) ;
4384	iMarkLen = strlen( pMark ) ;
4385	strcpy( sLog, pMark ) ; /* Harmless because of enough length */
4386	printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
4387
4388#ifdef DEBUG
4389	if ( debug ) {
4390		printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
4391	}
4392#endif
4393	record_clock_stats( &peer->srcadr, sLog ) ;
4394
4395}
4396
4397/*################################################################################################*/
4398/*################################################################################################*/
4399/*##												##*/
4400/*##    printableString										##*/
4401/*##												##*/
4402/*################################################################################################*/
4403/*################################################################################################*/
4404
4405static void
4406printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
4407{
4408	const char	*printableControlChar[] = {
4409			"<NUL>", "<SOH>", "<STX>", "<ETX>",
4410			"<EOT>", "<ENQ>", "<ACK>", "<BEL>",
4411			"<BS>" , "<HT>" , "<LF>" , "<VT>" ,
4412			"<FF>" , "<CR>" , "<SO>" , "<SI>" ,
4413			"<DLE>", "<DC1>", "<DC2>", "<DC3>",
4414			"<DC4>", "<NAK>", "<SYN>", "<ETB>",
4415			"<CAN>", "<EM>" , "<SUB>", "<ESC>",
4416			"<FS>" , "<GS>" , "<RS>" , "<US>" ,
4417			" " } ;
4418
4419	size_t	i, j, n ;
4420	size_t	InputLen;
4421	size_t	OutputLen;
4422
4423	InputLen = (size_t)iInputLen;
4424	OutputLen = (size_t)iOutputLen;
4425	for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
4426		if ( isprint( (unsigned char)sInput[i] ) ) {
4427			n = 1 ;
4428			if ( j + 1 >= OutputLen )
4429				break ;
4430			sOutput[j] = sInput[i] ;
4431		} else if ( ( sInput[i] & 0xFF ) <
4432			    COUNTOF(printableControlChar) ) {
4433			n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
4434			if ( j + n + 1 >= OutputLen )
4435				break ;
4436			strlcpy( sOutput + j,
4437				 printableControlChar[sInput[i] & 0xFF],
4438				 OutputLen - j ) ;
4439		} else {
4440			n = 5 ;
4441			if ( j + n + 1 >= OutputLen )
4442				break ;
4443			snprintf( sOutput + j, OutputLen - j, "<x%X>",
4444				  sInput[i] & 0xFF ) ;
4445		}
4446		j += n ;
4447	}
4448
4449	sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
4450
4451}
4452
4453/**************************************************************************************************/
4454
4455#else
4456int refclock_jjy_bs ;
4457#endif /* REFCLOCK */
4458