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