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