xref: /freebsd/contrib/ntp/ntpd/refclock_jjy.c (revision a466cc55)
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 
167 struct 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 
176 struct 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 
314 static	int 	jjy_start			(int, struct peer *);
315 static	int 	jjy_start_tristate_jjy01	(int, struct peer *, struct jjyunit *);
316 static	int 	jjy_start_cdex_jst2000		(int, struct peer *, struct jjyunit *);
317 static	int 	jjy_start_echokeisokuki_lt2000	(int, struct peer *, struct jjyunit *);
318 static	int 	jjy_start_citizentic_jjy200	(int, struct peer *, struct jjyunit *);
319 static	int 	jjy_start_tristate_gpsclock01	(int, struct peer *, struct jjyunit *);
320 static	int 	jjy_start_seiko_tsys_tdc_300	(int, struct peer *, struct jjyunit *);
321 static	int 	jjy_start_telephone		(int, struct peer *, struct jjyunit *);
322 
323 static	void	jjy_shutdown			(int, struct peer *);
324 
325 static	void	jjy_poll		    	(int, struct peer *);
326 static	void	jjy_poll_tristate_jjy01	    	(int, struct peer *);
327 static	void	jjy_poll_cdex_jst2000	    	(int, struct peer *);
328 static	void	jjy_poll_echokeisokuki_lt2000	(int, struct peer *);
329 static	void	jjy_poll_citizentic_jjy200	(int, struct peer *);
330 static	void	jjy_poll_tristate_gpsclock01	(int, struct peer *);
331 static	void	jjy_poll_seiko_tsys_tdc_300	(int, struct peer *);
332 static	void	jjy_poll_telephone		(int, struct peer *);
333 
334 static	void	jjy_receive			(struct recvbuf *);
335 static	int 	jjy_receive_tristate_jjy01	(struct recvbuf *);
336 static	int 	jjy_receive_cdex_jst2000	(struct recvbuf *);
337 static	int 	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
338 static  int 	jjy_receive_citizentic_jjy200	(struct recvbuf *);
339 static	int 	jjy_receive_tristate_gpsclock01	(struct recvbuf *);
340 static	int 	jjy_receive_seiko_tsys_tdc_300	(struct recvbuf *);
341 static	int 	jjy_receive_telephone		(struct recvbuf *);
342 
343 static	void	jjy_timer			(int, struct peer *);
344 static	void	jjy_timer_telephone		(int, struct peer *);
345 
346 static	void	jjy_synctime			( struct peer *, struct refclockproc *, struct jjyunit * ) ;
347 static	void	jjy_write_clockstats		( struct peer *, int, const char* ) ;
348 
349 static	int 	getRawDataBreakPosition		( struct jjyunit *, int ) ;
350 
351 static	short	getModemState			( struct jjyunit * ) ;
352 static	int 	isModemStateConnect		( short ) ;
353 static	int 	isModemStateDisconnect		( short ) ;
354 static	int 	isModemStateTimerOn		( struct jjyunit * ) ;
355 static	void	modem_connect			( int, struct peer * ) ;
356 static	void	modem_disconnect		( int, struct peer * ) ;
357 static	int 	modem_receive			( struct recvbuf * ) ;
358 static	void	modem_timer			( int, struct peer * );
359 
360 static	void	printableString ( char*, int, const char*, int ) ;
361 
362 /*
363  * Transfer vector
364  */
365 struct	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 /**************************************************************************************************/
449 static int
jjy_start(int unit,struct peer * peer)450 jjy_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 /**************************************************************************************************/
573 static void
jjy_shutdown(int unit,struct peer * peer)574 jjy_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 /**************************************************************************************************/
599 static void
jjy_receive(struct recvbuf * rbufp)600 jjy_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 
850 static int
getRawDataBreakPosition(struct jjyunit * up,int iStart)851 getRawDataBreakPosition ( 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 /**************************************************************************************************/
894 static void
jjy_poll(int unit,struct peer * peer)895 jjy_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 /**************************************************************************************************/
980 static void
jjy_timer(int unit,struct peer * peer)981 jjy_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 /**************************************************************************************************/
1021 static void
jjy_synctime(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)1022 jjy_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 
1136 static  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 
1156 static int
jjy_start_tristate_jjy01(int unit,struct peer * peer,struct jjyunit * up)1157 jjy_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 
1175 static int
jjy_receive_tristate_jjy01(struct recvbuf * rbufp)1176 jjy_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 
1405 static void
jjy_poll_tristate_jjy01(int unit,struct peer * peer)1406 jjy_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 
1472 static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
1473 {
1474 	{ "\x03", 1 }, { NULL, 0 }
1475 } ;
1476 
1477 /**************************************************************************************************/
1478 
1479 static int
jjy_start_cdex_jst2000(int unit,struct peer * peer,struct jjyunit * up)1480 jjy_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 
1500 static int
jjy_receive_cdex_jst2000(struct recvbuf * rbufp)1501 jjy_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 
1586 static void
jjy_poll_cdex_jst2000(int unit,struct peer * peer)1587 jjy_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 
1645 static int
jjy_start_echokeisokuki_lt2000(int unit,struct peer * peer,struct jjyunit * up)1646 jjy_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 
1663 static int
jjy_receive_echokeisokuki_lt2000(struct recvbuf * rbufp)1664 jjy_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 
1807 static void
jjy_poll_echokeisokuki_lt2000(int unit,struct peer * peer)1808 jjy_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 
1860 static int
jjy_start_citizentic_jjy200(int unit,struct peer * peer,struct jjyunit * up)1861 jjy_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 
1876 static int
jjy_receive_citizentic_jjy200(struct recvbuf * rbufp)1877 jjy_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 
1969 static void
jjy_poll_citizentic_jjy200(int unit,struct peer * peer)1970 jjy_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 
2022 static  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 
2041 static int
jjy_start_tristate_gpsclock01(int unit,struct peer * peer,struct jjyunit * up)2042 jjy_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 
2057 static int
jjy_receive_tristate_gpsclock01(struct recvbuf * rbufp)2058 jjy_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 
2288 static void
jjy_poll_tristate_gpsclock01(int unit,struct peer * peer)2289 jjy_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 
2355 static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
2356 {
2357 	{ "\x03", 1 }, { NULL, 0 }
2358 } ;
2359 
2360 /**************************************************************************************************/
2361 
2362 static int
jjy_start_seiko_tsys_tdc_300(int unit,struct peer * peer,struct jjyunit * up)2363 jjy_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 
2383 static int
jjy_receive_seiko_tsys_tdc_300(struct recvbuf * rbufp)2384 jjy_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 
2549 static void
jjy_poll_seiko_tsys_tdc_300(int unit,struct peer * peer)2550 jjy_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 
2583 static 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 
2612 static	void 	teljjy_control		( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2613 
2614 static	int 	teljjy_idle_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2615 static	int 	teljjy_idle_dialout	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2616 static	int 	teljjy_dial_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2617 static	int 	teljjy_dial_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2618 static	int 	teljjy_dial_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2619 static	int 	teljjy_login_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2620 static	int 	teljjy_login_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2621 static	int 	teljjy_login_conn	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2622 static	int 	teljjy_login_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2623 static	int 	teljjy_login_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2624 static	int 	teljjy_login_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2625 static	int 	teljjy_conn_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2626 static	int 	teljjy_conn_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2627 static	int 	teljjy_conn_send	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2628 static	int 	teljjy_conn_data	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2629 static	int 	teljjy_conn_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2630 static	int 	teljjy_conn_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2631 static	int 	teljjy_bye_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2632 static	int 	teljjy_bye_disc 	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2633 static	int 	teljjy_bye_modem	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2634 
2635 static 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 
2650 static 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 
2665 static 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 
2680 static short iTeljjySilentTimeout [ 5 ] = { 0,   0, 10,  5,  0 } ;
2681 static 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 
2699 static  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 
2736 static int
jjy_start_telephone(int unit,struct peer * peer,struct jjyunit * up)2737 jjy_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 
2848 static int
jjy_receive_telephone(struct recvbuf * rbufp)2849 jjy_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 
2913 static void
jjy_poll_telephone(int unit,struct peer * peer)2914 jjy_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 
2941 static void
jjy_timer_telephone(int unit,struct peer * peer)2942 jjy_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 
2996 static void
teljjy_control(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)2997 teljjy_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 
3046 static void
teljjy_setDelay(struct peer * peer,struct jjyunit * up)3047 teljjy_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 
3081 static int
teljjy_getDelay(struct peer * peer,struct jjyunit * up)3082 teljjy_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 /******************************/
3169 static int
teljjy_idle_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3170 teljjy_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 /******************************/
3180 static int
teljjy_idle_dialout(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3181 teljjy_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 /******************************/
3193 static int
teljjy_dial_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3194 teljjy_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 /******************************/
3204 static int
teljjy_dial_login(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3205 teljjy_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 /******************************/
3215 static int
teljjy_dial_disc(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3216 teljjy_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 /******************************/
3226 static int
teljjy_login_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3227 teljjy_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 /******************************/
3237 static int
teljjy_login_disc(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3238 teljjy_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 /******************************/
3248 static int
teljjy_login_conn(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3249 teljjy_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 /******************************/
3269 static int
teljjy_login_login(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3270 teljjy_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 /******************************/
3294 static int
teljjy_login_silent(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3295 teljjy_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 /******************************/
3313 static int
teljjy_login_error(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3314 teljjy_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 /******************************/
3324 static int
teljjy_conn_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3325 teljjy_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 /******************************/
3335 static int
teljjy_conn_disc(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3336 teljjy_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 /******************************/
3346 static int
teljjy_conn_send(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3347 teljjy_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 /******************************/
3443 static int
teljjy_conn_data(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3444 teljjy_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 /******************************/
3594 static int
teljjy_conn_silent(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3595 teljjy_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 /******************************/
3632 static int
teljjy_conn_error(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3633 teljjy_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 /******************************/
3643 static int
teljjy_bye_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3644 teljjy_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 /******************************/
3654 static int
teljjy_bye_disc(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3655 teljjy_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 /******************************/
3665 static int
teljjy_bye_modem(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3666 teljjy_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 
3714 static	void	modem_control		( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3715 
3716 static	int 	modem_disc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3717 static	int 	modem_disc_init  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3718 static	int 	modem_init_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3719 static	int 	modem_init_start 	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3720 static	int 	modem_init_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3721 static	int 	modem_init_resp00	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3722 static	int 	modem_init_resp04	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3723 static	int 	modem_dial_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3724 static	int 	modem_dial_dialout	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3725 static	int 	modem_dial_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3726 static	int 	modem_dial_connect	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3727 static	int 	modem_dial_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3728 static	int 	modem_conn_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3729 static	int 	modem_conn_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3730 static	int 	modem_esc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3731 static	int 	modem_esc_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3732 static	int 	modem_esc_data  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3733 static	int 	modem_esc_silent	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3734 static	int 	modem_esc_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3735 
3736 static 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 
3756 static 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 
3776 static 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 
3796 static short iModemSilentTimeout [ 5 ] = { 0,  0,  0, 0,  5 } ;
3797 static 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 
3810 static short
getModemState(struct jjyunit * up)3811 getModemState ( struct jjyunit *up )
3812 {
3813 	return up->iModemState ;
3814 }
3815 
3816 /**************************************************************************************************/
3817 
3818 static int
isModemStateConnect(short iCheckState)3819 isModemStateConnect ( short iCheckState )
3820 {
3821 	return ( iCheckState == MODEM_STATE_CONNECT ) ;
3822 }
3823 
3824 /**************************************************************************************************/
3825 
3826 static int
isModemStateDisconnect(short iCheckState)3827 isModemStateDisconnect ( short iCheckState )
3828 {
3829 	return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
3830 }
3831 
3832 /**************************************************************************************************/
3833 
3834 static int
isModemStateTimerOn(struct jjyunit * up)3835 isModemStateTimerOn ( struct jjyunit *up )
3836 {
3837 	return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
3838 }
3839 
3840 /**************************************************************************************************/
3841 
3842 static void
modem_connect(int unit,struct peer * peer)3843 modem_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 
3861 static void
modem_disconnect(int unit,struct peer * peer)3862 modem_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 
3880 static int
modem_receive(struct recvbuf * rbufp)3881 modem_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 
3937 static void
modem_timer(int unit,struct peer * peer)3938 modem_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 
3969 static void
modem_control(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)3970 modem_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 /******************************/
4008 static int
modem_disc_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4009 modem_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 /******************************/
4019 static int
modem_disc_init(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4020 modem_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 /******************************/
4030 static int
modem_init_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4031 modem_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 /******************************/
4041 static int
modem_init_start(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4042 modem_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 /******************************/
4060 static int
modem_init_resp00(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4061 modem_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 /******************************/
4168 static int
modem_init_resp04(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4169 modem_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 /******************************/
4179 static int
modem_init_disc(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4180 modem_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 /******************************/
4195 static int
modem_dial_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4196 modem_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 /******************************/
4206 static int
modem_dial_dialout(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4207 modem_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 /******************************/
4241 static int
modem_dial_escape(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4242 modem_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 /******************************/
4257 static int
modem_dial_connect(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4258 modem_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 /******************************/
4268 static int
modem_dial_disc(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4269 modem_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 /******************************/
4286 static int
modem_conn_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4287 modem_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 /******************************/
4297 static int
modem_conn_escape(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4298 modem_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 /******************************/
4308 static int
modem_esc_ignore(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4309 modem_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 /******************************/
4319 static int
modem_esc_escape(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4320 modem_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 /******************************/
4344 static int
modem_esc_data(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4345 modem_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 /******************************/
4357 static int
modem_esc_silent(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4358 modem_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 /******************************/
4385 static int
modem_esc_disc(struct peer * peer,struct refclockproc * pp,struct jjyunit * up)4386 modem_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 
4417 static void
jjy_write_clockstats(struct peer * peer,int iMark,const char * pData)4418 jjy_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 
4477 static void
printableString(char * sOutput,int iOutputLen,const char * sInput,int iInputLen)4478 printableString ( 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
4528 int refclock_jjy_bs ;
4529 #endif /* REFCLOCK */
4530