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