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