1106163Sroberto/*
2106163Sroberto * refclock_jjy - clock driver for JJY receivers
3106163Sroberto */
4106163Sroberto
5106163Sroberto/**********************************************************************/
6280849Scy/*								      */
7362716Scy/*  Copyright (C) 2001-2020, Takao Abe.  All rights reserved.	      */
8280849Scy/*								      */
9106163Sroberto/*  Permission to use, copy, modify, and distribute this software     */
10280849Scy/*  and its documentation for any purpose is hereby granted	      */
11106163Sroberto/*  without fee, provided that the following conditions are met:      */
12280849Scy/*								      */
13106163Sroberto/*  One retains the entire copyright notice properly, and both the    */
14106163Sroberto/*  copyright notice and this license. in the documentation and/or    */
15280849Scy/*  other materials provided with the distribution.		      */
16280849Scy/*								      */
17106163Sroberto/*  This software and the name of the author must not be used to      */
18106163Sroberto/*  endorse or promote products derived from this software without    */
19280849Scy/*  prior written permission.					      */
20280849Scy/*								      */
21106163Sroberto/*  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED    */
22280849Scy/*  WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE	      */
23280849Scy/*  IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A	      */
24280849Scy/*  PARTICULAR PURPOSE.						      */
25106163Sroberto/*  IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT,  */
26106163Sroberto/*  INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   */
27280849Scy/*  ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE	      */
28106163Sroberto/*  GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS      */
29106163Sroberto/*  INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,     */
30280849Scy/*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING	      */
31106163Sroberto/*  NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF    */
32106163Sroberto/*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
33280849Scy/*								      */
34106163Sroberto/*  This driver is developed in my private time, and is opened as     */
35280849Scy/*  voluntary contributions for the NTP.			      */
36106163Sroberto/*  The manufacturer of the JJY receiver has not participated in      */
37280849Scy/*  a development of this driver.				      */
38106163Sroberto/*  The manufacturer does not warrant anything about this driver,     */
39280849Scy/*  and is not liable for anything about this driver.		      */
40280849Scy/*								      */
41106163Sroberto/**********************************************************************/
42280849Scy/*								      */
43280849Scy/*  Author     Takao Abe					      */
44280849Scy/*  Email      takao_abe@xurb.jp				      */
45280849Scy/*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/		      */
46280849Scy/*								      */
47280849Scy/*  The email address abetakao@bea.hi-ho.ne.jp is never read	      */
48280849Scy/*  from 2010, because a few filtering rule are provided by the	      */
49280849Scy/*  "hi-ho.ne.jp", and lots of spam mail are reached.		      */
50280849Scy/*  New email address for supporting the refclock_jjy is	      */
51280849Scy/*  takao_abe@xurb.jp						      */
52280849Scy/*								      */
53106163Sroberto/**********************************************************************/
54280849Scy/*								      */
55280849Scy/*  History							      */
56280849Scy/*								      */
57280849Scy/*  2001/07/15							      */
58280849Scy/*    [New]    Support the Tristate Ltd. JJY receiver		      */
59280849Scy/*								      */
60280849Scy/*  2001/08/04							      */
61280849Scy/*    [Change] Log to clockstats even if bad reply		      */
62280849Scy/*    [Fix]    PRECISION = (-3) (about 100 ms)			      */
63280849Scy/*    [Add]    Support the C-DEX Co.Ltd. JJY receiver		      */
64280849Scy/*								      */
65280849Scy/*  2001/12/04							      */
66106163Sroberto/*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
67280849Scy/*								      */
68280849Scy/*  2002/07/12							      */
69280849Scy/*    [Fix]    Portability for FreeBSD ( patched by the user )	      */
70280849Scy/*								      */
71280849Scy/*  2004/10/31							      */
72182007Sroberto/*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
73280849Scy/*	       JJY-01 ( Firmware version 2.01 )			      */
74280849Scy/*	       Thanks to Andy Taki for testing under FreeBSD	      */
75280849Scy/*								      */
76280849Scy/*  2004/11/28							      */
77280849Scy/*    [Add]    Support the Echo Keisokuki LT-2000 receiver	      */
78280849Scy/*								      */
79280849Scy/*  2006/11/04							      */
80280849Scy/*    [Fix]    C-DEX JST2000					      */
81280849Scy/*	       Thanks to Hideo Kuramatsu for the patch		      */
82280849Scy/*								      */
83280849Scy/*  2009/04/05							      */
84280849Scy/*    [Add]    Support the CITIZEN T.I.C JJY-200 receiver	      */
85280849Scy/*								      */
86280849Scy/*  2010/11/20							      */
87280849Scy/*    [Change] Bug 1618 ( Harmless )				      */
88280849Scy/*	       Code clean up ( Remove unreachable codes ) in	      */
89280849Scy/*	       jjy_start()					      */
90280849Scy/*    [Change] Change clockstats format of the Tristate JJY01/02      */
91280849Scy/*	       Issues more command to get the status of the receiver  */
92280849Scy/*	       when "fudge 127.127.40.X flag1 1" is specified	      */
93280849Scy/*	       ( DATE,STIM -> DCST,STUS,DATE,STIM )		      */
94280849Scy/*								      */
95280849Scy/*  2011/04/30							      */
96280849Scy/*    [Add]    Support the Tristate Ltd. TS-GPSclock-01		      */
97280849Scy/*								      */
98285169Scy/*  2015/03/29							      */
99285169Scy/*    [Add]    Support the Telephone JJY			      */
100285169Scy/*    [Change] Split the start up routine into each JJY receivers.    */
101285169Scy/*             Change raw data internal bufferring process            */
102285169Scy/*             Change over midnight handling of TS-JJY01 and TS-GPS01 */
103285169Scy/*             to put DATE command between before and after TIME's.   */
104285169Scy/*             Unify the writing clockstats of all JJY receivers.     */
105285169Scy/*								      */
106285169Scy/*  2015/05/15							      */
107285169Scy/*    [Add]    Support the SEIKO TIME SYSTEMS TDC-300		      */
108285169Scy/*								      */
109309007Sdelphij/*  2016/05/08							      */
110309007Sdelphij/*    [Fix]    C-DEX JST2000                                          */
111309007Sdelphij/*             Thanks to Mr. Kuramatsu for the report and the patch.  */
112309007Sdelphij/*								      */
113330106Sdelphij/*  2017/04/30							      */
114330106Sdelphij/*    [Change] Avoid a wrong report of the coverity static analysis   */
115330106Sdelphij/*             tool. ( The code is harmless and has no bug. )	      */
116330106Sdelphij/*             teljjy_conn_send()				      */
117330106Sdelphij/*								      */
118362716Scy/*  2020/01/19							      */
119362716Scy/*    [Change] Handling TS-JJY01/02 status of the the STUS reply.     */
120362716Scy/*             Time synchronization can be skipped by the settings of */
121362716Scy/*             the flag2 when the status of the reply is UNADJUSTED.  */
122362716Scy/*    [Change] Quiet compilation for the GCC 9.2.0.                   */
123362716Scy/*    [Fix]    Correct typos in comment lines                         */
124362716Scy/*								      */
125106163Sroberto/**********************************************************************/
126106163Sroberto
127106163Sroberto#ifdef HAVE_CONFIG_H
128106163Sroberto#include <config.h>
129106163Sroberto#endif
130106163Sroberto
131106163Sroberto#if defined(REFCLOCK) && defined(CLOCK_JJY)
132106163Sroberto
133106163Sroberto#include <stdio.h>
134106163Sroberto#include <ctype.h>
135106163Sroberto#include <string.h>
136106163Sroberto#include <sys/time.h>
137106163Sroberto#include <time.h>
138106163Sroberto
139106163Sroberto#include "ntpd.h"
140106163Sroberto#include "ntp_io.h"
141106163Sroberto#include "ntp_tty.h"
142106163Sroberto#include "ntp_refclock.h"
143106163Sroberto#include "ntp_calendar.h"
144106163Sroberto#include "ntp_stdlib.h"
145106163Sroberto
146106163Sroberto/**********************************************************************/
147106163Sroberto
148106163Sroberto/*
149106163Sroberto * Interface definitions
150106163Sroberto */
151280849Scy#define	DEVICE  	"/dev/jjy%d"	/* device name and unit */
152280849Scy#define	SPEED232_TRISTATE_JJY01		B9600   /* UART speed (9600 baud) */
153280849Scy#define	SPEED232_CDEX_JST2000		B9600   /* UART speed (9600 baud) */
154280849Scy#define	SPEED232_ECHOKEISOKUKI_LT2000	B9600   /* UART speed (9600 baud) */
155280849Scy#define	SPEED232_CITIZENTIC_JJY200	B4800   /* UART speed (4800 baud) */
156280849Scy#define	SPEED232_TRISTATE_GPSCLOCK01	B38400  /* USB  speed (38400 baud) */
157285169Scy#define	SPEED232_SEIKO_TIMESYS_TDC_300	B2400   /* UART speed (2400 baud) */
158285169Scy#define	SPEED232_TELEPHONE		B2400   /* UART speed (4800 baud) */
159280849Scy#define	REFID   	"JJY"		/* reference ID */
160106163Sroberto#define	DESCRIPTION	"JJY Receiver"
161280849Scy#define	PRECISION	(-3)		/* precision assumed (about 100 ms) */
162106163Sroberto
163106163Sroberto/*
164106163Sroberto * JJY unit control structure
165106163Sroberto */
166285169Scy
167285169Scystruct jjyRawDataBreak {
168294554Sdelphij	const char *	pString ;
169294554Sdelphij	int 		iLength ;
170285169Scy} ;
171285169Scy
172285169Scy#define	MAX_TIMESTAMP	6
173285169Scy#define	MAX_RAWBUF   	100
174285169Scy#define	MAX_LOOPBACK	5
175285169Scy
176106163Srobertostruct jjyunit {
177285169Scy/* Set up by the function "jjy_start_xxxxxxxx" */
178280849Scy	char	unittype ;	    /* UNITTYPE_XXXXXXXXXX */
179285169Scy	short   operationmode ;	    /* Echo Keisokuki LT-2000 */
180285169Scy	int 	linespeed ;         /* SPEED232_XXXXXXXXXX */
181280849Scy	short	linediscipline ;    /* LDISC_CLK or LDISC_RAW */
182285169Scy/* Receiving data */
183285169Scy	char	bInitError ;        /* Set by jjy_start if any error during initialization */
184285169Scy	short	iProcessState ;     /* JJY_PROCESS_STATE_XXXXXX */
185285169Scy	char	bReceiveFlag ;      /* Set and reset by jjy_receive */
186285169Scy	char	bLineError ;	    /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/
187285169Scy	short	iCommandSeq ;       /* 0:Idle  Non-Zero:Issued */
188285169Scy	short	iReceiveSeq ;
189285169Scy	int 	iLineCount ;
190106163Sroberto	int 	year, month, day, hour, minute, second, msecond ;
191285169Scy	int 	leapsecond ;
192285169Scy	int 	iTimestampCount ;   /* TS-JJY01, TS-GPS01, Telephone-JJY */
193285169Scy	int 	iTimestamp [ MAX_TIMESTAMP ] ;  /* Serial second ( 0 - 86399 ) */
194106163Sroberto/* LDISC_RAW only */
195285169Scy	char	sRawBuf [ MAX_RAWBUF ] ;
196285169Scy	int 	iRawBufLen ;
197285169Scy	struct	jjyRawDataBreak *pRawBreak ;
198285169Scy	char	bWaitBreakString ;
199285169Scy	char	sLineBuf [ MAX_RAWBUF ] ;
200285169Scy	int 	iLineBufLen ;
201285169Scy	char	sTextBuf [ MAX_RAWBUF ] ;
202285169Scy	int 	iTextBufLen ;
203285169Scy	char	bSkipCntrlCharOnly ;
204362716Scy/* TS-JJY01, TS-JJY02 */
205362716Scy	time_t	tLastAdjustedTimestamp ;
206362716Scy	char	bStusReplyAdjusted ;
207362716Scy	char	bStusReplyAdjustedAtLeastOnce ;
208285169Scy/* Telephone JJY auto measurement of the loopback delay */
209285169Scy	char	bLoopbackMode ;
210285169Scy	short	iLoopbackCount ;
211285169Scy	struct	timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ;
212285169Scy	char	bLoopbackTimeout[MAX_LOOPBACK] ;
213285169Scy	short	iLoopbackValidCount ;
214285169Scy/* Telephone JJY timer */
215285169Scy	short	iTeljjySilentTimer ;
216285169Scy	short	iTeljjyStateTimer ;
217285169Scy/* Telephone JJY control finite state machine */
218285169Scy	short	iClockState ;
219285169Scy	short	iClockEvent ;
220285169Scy	short	iClockCommandSeq ;
221285169Scy/* Modem timer */
222285169Scy	short	iModemSilentCount ;
223285169Scy	short	iModemSilentTimer ;
224285169Scy	short	iModemStateTimer ;
225285169Scy/* Modem control finite state machine */
226285169Scy	short	iModemState ;
227285169Scy	short	iModemEvent ;
228285169Scy	short	iModemCommandSeq ;
229106163Sroberto};
230106163Sroberto
231280849Scy#define	UNITTYPE_TRISTATE_JJY01		1
232280849Scy#define	UNITTYPE_CDEX_JST2000		2
233182007Sroberto#define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
234200576Sroberto#define	UNITTYPE_CITIZENTIC_JJY200  	4
235280849Scy#define	UNITTYPE_TRISTATE_GPSCLOCK01	5
236285169Scy#define	UNITTYPE_SEIKO_TIMESYS_TDC_300	6
237285169Scy#define	UNITTYPE_TELEPHONE		100
238106163Sroberto
239285169Scy#define	JJY_PROCESS_STATE_IDLE   	0
240285169Scy#define	JJY_PROCESS_STATE_POLL   	1
241285169Scy#define	JJY_PROCESS_STATE_RECEIVE	2
242285169Scy#define	JJY_PROCESS_STATE_DONE   	3
243285169Scy#define	JJY_PROCESS_STATE_ERROR  	4
244285169Scy
245285169Scy/**********************************************************************/
246285169Scy
247106163Sroberto/*
248285169Scy *  Function calling structure
249285169Scy *
250285169Scy *  jjy_start
251285169Scy *   |--  jjy_start_tristate_jjy01
252285169Scy *   |--  jjy_start_cdex_jst2000
253285169Scy *   |--  jjy_start_echokeisokuki_lt2000
254285169Scy *   |--  jjy_start_citizentic_jjy200
255285169Scy *   |--  jjy_start_tristate_gpsclock01
256285169Scy *   |--  jjy_start_seiko_tsys_tdc_300
257285169Scy *   |--  jjy_start_telephone
258285169Scy *
259285169Scy *  jjy_shutdown
260285169Scy *
261285169Scy *  jjy_poll
262285169Scy *   |--  jjy_poll_tristate_jjy01
263285169Scy *   |--  jjy_poll_cdex_jst2000
264285169Scy *   |--  jjy_poll_echokeisokuki_lt2000
265285169Scy *   |--  jjy_poll_citizentic_jjy200
266285169Scy *   |--  jjy_poll_tristate_gpsclock01
267285169Scy *   |--  jjy_poll_seiko_tsys_tdc_300
268285169Scy *   |--  jjy_poll_telephone
269285169Scy *         |--  teljjy_control
270285169Scy *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
271285169Scy *                     |--  modem_connect
272285169Scy *                           |--  modem_control
273285169Scy *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
274285169Scy *
275285169Scy *  jjy_receive
276285169Scy *   |
277285169Scy *   |--  jjy_receive_tristate_jjy01
278285169Scy *   |     |--  jjy_synctime
279285169Scy *   |--  jjy_receive_cdex_jst2000
280285169Scy *   |     |--  jjy_synctime
281285169Scy *   |--  jjy_receive_echokeisokuki_lt2000
282285169Scy *   |     |--  jjy_synctime
283285169Scy *   |--  jjy_receive_citizentic_jjy200
284285169Scy *   |     |--  jjy_synctime
285285169Scy *   |--  jjy_receive_tristate_gpsclock01
286285169Scy *   |     |--  jjy_synctime
287285169Scy *   |--  jjy_receive_seiko_tsys_tdc_300
288285169Scy *   |     |--  jjy_synctime
289285169Scy *   |--  jjy_receive_telephone
290285169Scy *         |--  modem_receive
291285169Scy *         |     |--  modem_control
292285169Scy *         |           |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
293285169Scy *         |--  teljjy_control
294285169Scy *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
295285169Scy *                     |--  jjy_synctime
296285169Scy *                     |--  modem_disconnect
297285169Scy *                           |--  modem_control
298285169Scy *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
299285169Scy *
300285169Scy *  jjy_timer
301285169Scy *   |--  jjy_timer_telephone
302285169Scy *         |--  modem_timer
303285169Scy *         |     |--  modem_control
304285169Scy *         |           |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
305285169Scy *         |--  teljjy_control
306285169Scy *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
307285169Scy *                     |--  modem_disconnect
308285169Scy *                           |--  modem_control
309285169Scy *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
310285169Scy *
311106163Sroberto * Function prototypes
312106163Sroberto */
313285169Scy
314280849Scystatic	int 	jjy_start			(int, struct peer *);
315285169Scystatic	int 	jjy_start_tristate_jjy01	(int, struct peer *, struct jjyunit *);
316285169Scystatic	int 	jjy_start_cdex_jst2000		(int, struct peer *, struct jjyunit *);
317285169Scystatic	int 	jjy_start_echokeisokuki_lt2000	(int, struct peer *, struct jjyunit *);
318285169Scystatic	int 	jjy_start_citizentic_jjy200	(int, struct peer *, struct jjyunit *);
319285169Scystatic	int 	jjy_start_tristate_gpsclock01	(int, struct peer *, struct jjyunit *);
320285169Scystatic	int 	jjy_start_seiko_tsys_tdc_300	(int, struct peer *, struct jjyunit *);
321285169Scystatic	int 	jjy_start_telephone		(int, struct peer *, struct jjyunit *);
322285169Scy
323280849Scystatic	void	jjy_shutdown			(int, struct peer *);
324106163Sroberto
325280849Scystatic	void	jjy_poll		    	(int, struct peer *);
326280849Scystatic	void	jjy_poll_tristate_jjy01	    	(int, struct peer *);
327280849Scystatic	void	jjy_poll_cdex_jst2000	    	(int, struct peer *);
328280849Scystatic	void	jjy_poll_echokeisokuki_lt2000	(int, struct peer *);
329280849Scystatic	void	jjy_poll_citizentic_jjy200	(int, struct peer *);
330280849Scystatic	void	jjy_poll_tristate_gpsclock01	(int, struct peer *);
331285169Scystatic	void	jjy_poll_seiko_tsys_tdc_300	(int, struct peer *);
332285169Scystatic	void	jjy_poll_telephone		(int, struct peer *);
333280849Scy
334280849Scystatic	void	jjy_receive			(struct recvbuf *);
335285169Scystatic	int 	jjy_receive_tristate_jjy01	(struct recvbuf *);
336285169Scystatic	int 	jjy_receive_cdex_jst2000	(struct recvbuf *);
337285169Scystatic	int 	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
338285169Scystatic  int 	jjy_receive_citizentic_jjy200	(struct recvbuf *);
339285169Scystatic	int 	jjy_receive_tristate_gpsclock01	(struct recvbuf *);
340285169Scystatic	int 	jjy_receive_seiko_tsys_tdc_300	(struct recvbuf *);
341285169Scystatic	int 	jjy_receive_telephone		(struct recvbuf *);
342280849Scy
343285169Scystatic	void	jjy_timer			(int, struct peer *);
344285169Scystatic	void	jjy_timer_telephone		(int, struct peer *);
345280849Scy
346285169Scystatic	void	jjy_synctime			( struct peer *, struct refclockproc *, struct jjyunit * ) ;
347285169Scystatic	void	jjy_write_clockstats		( struct peer *, int, const char* ) ;
348285169Scy
349285169Scystatic	int 	getRawDataBreakPosition		( struct jjyunit *, int ) ;
350285169Scy
351285169Scystatic	short	getModemState			( struct jjyunit * ) ;
352285169Scystatic	int 	isModemStateConnect		( short ) ;
353285169Scystatic	int 	isModemStateDisconnect		( short ) ;
354285169Scystatic	int 	isModemStateTimerOn		( struct jjyunit * ) ;
355285169Scystatic	void	modem_connect			( int, struct peer * ) ;
356285169Scystatic	void	modem_disconnect		( int, struct peer * ) ;
357285169Scystatic	int 	modem_receive			( struct recvbuf * ) ;
358285169Scystatic	void	modem_timer			( int, struct peer * );
359285169Scy
360285169Scystatic	void	printableString ( char*, int, const char*, int ) ;
361285169Scy
362106163Sroberto/*
363106163Sroberto * Transfer vector
364106163Sroberto */
365106163Srobertostruct	refclock refclock_jjy = {
366280849Scy	jjy_start,	/* start up driver */
367280849Scy	jjy_shutdown,	/* shutdown driver */
368280849Scy	jjy_poll,	/* transmit poll message */
369280849Scy	noentry,	/* not used */
370280849Scy	noentry,	/* not used */
371280849Scy	noentry,	/* not used */
372285169Scy	jjy_timer	/* 1 second interval timer */
373106163Sroberto};
374106163Sroberto
375106163Sroberto/*
376106163Sroberto * Start up driver return code
377106163Sroberto */
378106163Sroberto#define	RC_START_SUCCESS	1
379280849Scy#define	RC_START_ERROR		0
380106163Sroberto
381106163Sroberto/*
382106163Sroberto * Local constants definition
383106163Sroberto */
384106163Sroberto
385362716Scy#define	MAX_LOGTEXT	200
386106163Sroberto
387285169Scy#ifndef	TRUE
388285169Scy#define	TRUE	(0==0)
389285169Scy#endif
390285169Scy#ifndef	FALSE
391285169Scy#define	FALSE	(!TRUE)
392285169Scy#endif
393106163Sroberto
394285169Scy/* Local constants definition for the return code of the jjy_receive_xxxxxxxx */
395280849Scy
396285169Scy#define	JJY_RECEIVE_DONE	0
397285169Scy#define	JJY_RECEIVE_SKIP	1
398285169Scy#define	JJY_RECEIVE_UNPROCESS	2
399285169Scy#define	JJY_RECEIVE_WAIT	3
400285169Scy#define	JJY_RECEIVE_ERROR	4
401280849Scy
402285169Scy/* Local constants definition for the 2nd parameter of the jjy_write_clockstats */
403280849Scy
404285169Scy#define	JJY_CLOCKSTATS_MARK_NONE	0
405285169Scy#define	JJY_CLOCKSTATS_MARK_JJY 	1
406285169Scy#define	JJY_CLOCKSTATS_MARK_SEND	2
407285169Scy#define	JJY_CLOCKSTATS_MARK_RECEIVE	3
408285169Scy#define	JJY_CLOCKSTATS_MARK_INFORMATION	4
409285169Scy#define	JJY_CLOCKSTATS_MARK_ATTENTION	5
410285169Scy#define	JJY_CLOCKSTATS_MARK_WARNING	6
411285169Scy#define	JJY_CLOCKSTATS_MARK_ERROR	7
412330106Sdelphij#define	JJY_CLOCKSTATS_MARK_BUG 	8
413280849Scy
414285169Scy/* Local constants definition for the clockstats messages */
415280849Scy
416285169Scy#define	JJY_CLOCKSTATS_MESSAGE_ECHOBACK         	"* Echoback"
417285169Scy#define	JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY     	"* Ignore replay : [%s]"
418285169Scy#define	JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2  	"* Over midnight : timestamp=%d, %d"
419285169Scy#define	JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3  	"* Over midnight : timestamp=%d, %d, %d"
420285169Scy#define	JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE 	"* Unsure timestamp : %s"
421285169Scy#define	JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY   	"* Loopback delay : %d.%03d mSec."
422285169Scy#define	JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST     	"* Delay adjustment : %d mSec. ( valid=%hd/%d )"
423285169Scy#define	JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST   	"* Delay adjustment : None ( valid=%hd/%d )"
424362716Scy#define	JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED  	"* Skip time synchronization : STUS is 'UNADJUSTED' for %.0lf %s"
425280849Scy
426285169Scy#define	JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY     	"# Unexpected reply : [%s]"
427285169Scy#define	JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH     	"# Invalid length : length=%d"
428285169Scy#define	JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY     	"# Too many reply : count=%d"
429285169Scy#define	JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY      	"# Invalid reply : [%s]"
430285169Scy#define	JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2       	"# Slow reply : timestamp=%d, %d"
431285169Scy#define	JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3       	"# Slow reply : timestamp=%d, %d, %d"
432285169Scy#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE	"# Invalid date : rc=%d year=%d month=%d day=%d"
433285169Scy#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME	"# Invalid time : rc=%d hour=%d minute=%d second=%d"
434285169Scy#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME	"# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d"
435285169Scy#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP	"# Invalid leap : leapsecond=[%s]"
436285169Scy#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS	"# Invalid status : status=[%s]"
437280849Scy
438285169Scy/* Debug print macro */
439280849Scy
440285169Scy#ifdef	DEBUG
441285169Scy#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 ) ; } }
442285169Scy#else
443285169Scy#define	DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)
444285169Scy#endif
445280849Scy
446106163Sroberto/**************************************************************************************************/
447106163Sroberto/*  jjy_start - open the devices and initialize data for processing                               */
448106163Sroberto/**************************************************************************************************/
449106163Srobertostatic int
450106163Srobertojjy_start ( int unit, struct peer *peer )
451106163Sroberto{
452106163Sroberto
453285169Scy	struct	refclockproc *pp ;
454285169Scy	struct	jjyunit      *up ;
455285169Scy	int 	rc ;
456106163Sroberto	int 	fd ;
457285169Scy	char	sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ;
458106163Sroberto
459106163Sroberto#ifdef DEBUG
460106163Sroberto	if ( debug ) {
461285169Scy		printf( "refclock_jjy.c : jjy_start : %s  mode=%d  dev=%s  unit=%d\n",
462285169Scy			 ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ;
463106163Sroberto	}
464106163Sroberto#endif
465280849Scy
466285169Scy	/* Allocate memory for the unit structure */
467285169Scy	up = emalloc( sizeof(*up) ) ;
468285169Scy	if ( up == NULL ) {
469285169Scy		msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ;
470285169Scy		return RC_START_ERROR ;
471285169Scy	}
472285169Scy	memset ( up, 0, sizeof(*up) ) ;
473106163Sroberto
474285169Scy	up->bInitError = FALSE ;
475285169Scy	up->iProcessState = JJY_PROCESS_STATE_IDLE ;
476285169Scy	up->bReceiveFlag = FALSE ;
477285169Scy	up->iCommandSeq = 0 ;
478285169Scy	up->iLineCount = 0 ;
479285169Scy	up->iTimestampCount = 0 ;
480285169Scy	up->bWaitBreakString = FALSE ;
481285169Scy	up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ;
482285169Scy	up->bSkipCntrlCharOnly = TRUE ;
483285169Scy
484285169Scy	/* Set up the device name */
485285169Scy	snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ;
486285169Scy
487285169Scy	snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ;
488285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
489285169Scy
490106163Sroberto	/*
491132451Sroberto	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
492106163Sroberto	 */
493132451Sroberto	switch ( peer->ttl ) {
494106163Sroberto	case 0 :
495280849Scy	case 1 :
496285169Scy		rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ;
497280849Scy		break ;
498280849Scy	case 2 :
499285169Scy		rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ;
500280849Scy		break ;
501280849Scy	case 3 :
502285169Scy		rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ;
503280849Scy		break ;
504280849Scy	case 4 :
505285169Scy		rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ;
506280849Scy		break ;
507280849Scy	case 5 :
508285169Scy		rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ;
509280849Scy		break ;
510285169Scy	case 6 :
511285169Scy		rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ;
512285169Scy		break ;
513285169Scy	case 100 :
514285169Scy		rc = jjy_start_telephone ( unit, peer, up ) ;
515285169Scy		break ;
516106163Sroberto	default :
517285169Scy		if ( 101 <= peer->ttl && peer->ttl <= 180 ) {
518285169Scy			rc = jjy_start_telephone ( unit, peer, up ) ;
519285169Scy		} else {
520285169Scy			msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
521285169Scy				  ntoa(&peer->srcadr), peer->ttl ) ;
522285169Scy			free ( (void*) up ) ;
523285169Scy		return RC_START_ERROR ;
524285169Scy		}
525285169Scy	}
526285169Scy
527285169Scy	if ( rc != 0 ) {
528285169Scy		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error",
529280849Scy			  ntoa(&peer->srcadr), peer->ttl ) ;
530285169Scy		free ( (void*) up ) ;
531106163Sroberto		return RC_START_ERROR ;
532106163Sroberto	}
533106163Sroberto
534285169Scy	/* Open the device */
535285169Scy	fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ;
536280849Scy	if ( fd <= 0 ) {
537285169Scy		free ( (void*) up ) ;
538106163Sroberto		return RC_START_ERROR ;
539106163Sroberto	}
540106163Sroberto
541106163Sroberto	/*
542285169Scy	 * Initialize variables
543106163Sroberto	 */
544285169Scy	pp = peer->procptr ;
545106163Sroberto
546285169Scy	pp->clockdesc	= DESCRIPTION ;
547280849Scy	pp->unitptr       = up ;
548106163Sroberto	pp->io.clock_recv = jjy_receive ;
549280849Scy	pp->io.srcclock   = peer ;
550280849Scy	pp->io.datalen	  = 0 ;
551280849Scy	pp->io.fd	  = fd ;
552106163Sroberto	if ( ! io_addclock(&pp->io) ) {
553106163Sroberto		close ( fd ) ;
554280849Scy		pp->io.fd = -1 ;
555280849Scy		free ( up ) ;
556280849Scy		pp->unitptr = NULL ;
557106163Sroberto		return RC_START_ERROR ;
558106163Sroberto	}
559285169Scy	memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ;
560106163Sroberto
561106163Sroberto	peer->precision = PRECISION ;
562106163Sroberto
563285169Scy	snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ;
564285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
565285169Scy
566106163Sroberto	return RC_START_SUCCESS ;
567106163Sroberto
568106163Sroberto}
569106163Sroberto
570106163Sroberto/**************************************************************************************************/
571106163Sroberto/*  jjy_shutdown - shutdown the clock                                                             */
572106163Sroberto/**************************************************************************************************/
573106163Srobertostatic void
574106163Srobertojjy_shutdown ( int unit, struct peer *peer )
575106163Sroberto{
576106163Sroberto
577280849Scy	struct jjyunit	    *up;
578106163Sroberto	struct refclockproc *pp;
579106163Sroberto
580285169Scy	char	sLog [ 60 ] ;
581285169Scy
582106163Sroberto	pp = peer->procptr ;
583280849Scy	up = pp->unitptr ;
584285169Scy	if ( -1 != pp->io.fd ) {
585280849Scy		io_closeclock ( &pp->io ) ;
586285169Scy	}
587285169Scy	if ( NULL != up ) {
588280849Scy		free ( up ) ;
589285169Scy	}
590106163Sroberto
591285169Scy	snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ;
592285169Scy	record_clock_stats( &peer->srcadr, sLog ) ;
593285169Scy
594106163Sroberto}
595106163Sroberto
596106163Sroberto/**************************************************************************************************/
597106163Sroberto/*  jjy_receive - receive data from the serial interface                                          */
598106163Sroberto/**************************************************************************************************/
599106163Srobertostatic void
600106163Srobertojjy_receive ( struct recvbuf *rbufp )
601106163Sroberto{
602285169Scy#ifdef DEBUG
603285169Scy	static const char *sFunctionName = "jjy_receive" ;
604285169Scy#endif
605106163Sroberto
606280849Scy	struct jjyunit	    *up ;
607106163Sroberto	struct refclockproc *pp ;
608280849Scy	struct peer	    *peer;
609106163Sroberto
610106163Sroberto	l_fp	tRecvTimestamp;		/* arrival timestamp */
611106163Sroberto	int 	rc ;
612285169Scy	char	*pBuf, sLogText [ MAX_LOGTEXT ] ;
613316068Sdelphij	size_t 	iLen, iCopyLen ;
614285169Scy	int 	i, j, iReadRawBuf, iBreakPosition ;
615106163Sroberto
616106163Sroberto	/*
617106163Sroberto	 * Initialize pointers and read the timecode and timestamp
618106163Sroberto	 */
619280849Scy	peer = rbufp->recv_peer ;
620106163Sroberto	pp = peer->procptr ;
621280849Scy	up = pp->unitptr ;
622106163Sroberto
623106163Sroberto	/*
624106163Sroberto	 * Get next input line
625106163Sroberto	 */
626285169Scy	if ( up->linediscipline == LDISC_RAW ) {
627106163Sroberto
628285169Scy		pp->lencode  = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ;
629285169Scy		/* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions  (OVERRUN)" */
630285169Scy		/* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */
631285169Scy		/* To avoid its claim, pass the value BMAX-1. */
632285169Scy
633106163Sroberto		/*
634362716Scy		 * Append received characters to temporary buffer
635106163Sroberto		 */
636280849Scy		for ( i = 0 ;
637285169Scy		      i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ;
638285169Scy		      i ++ , up->iRawBufLen ++ ) {
639285169Scy			up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ;
640106163Sroberto		}
641285169Scy		up->sRawBuf[up->iRawBufLen] = 0 ;
642285169Scy
643285169Scy
644285169Scy	} else {
645285169Scy
646285169Scy		pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
647285169Scy
648285169Scy	}
649285169Scy#ifdef DEBUG
650285169Scy	printf( "\nrefclock_jjy.c : %s : Len=%d  ", sFunctionName, pp->lencode ) ;
651285169Scy	for ( i = 0 ; i < pp->lencode ; i ++ ) {
652294554Sdelphij		if ( iscntrl( (u_char)(pp->a_lastcode[i] & 0x7F) ) ) {
653285169Scy			printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ;
654285169Scy		} else {
655285169Scy			printf( "%c", pp->a_lastcode[i] ) ;
656106163Sroberto		}
657285169Scy	}
658285169Scy	printf( "\n" ) ;
659285169Scy#endif
660285169Scy
661285169Scy	/*
662285169Scy	 * The reply with <CR><LF> gives a blank line
663285169Scy	 */
664285169Scy
665285169Scy	if ( pp->lencode == 0 ) return ;
666285169Scy
667285169Scy	/*
668285169Scy	 * Receiving data is not expected
669285169Scy	 */
670285169Scy
671285169Scy	if ( up->iProcessState == JJY_PROCESS_STATE_IDLE
672285169Scy	  || up->iProcessState == JJY_PROCESS_STATE_DONE
673285169Scy	  || up->iProcessState == JJY_PROCESS_STATE_ERROR ) {
674285169Scy		/* Discard received data */
675285169Scy		up->iRawBufLen = 0 ;
676285169Scy#ifdef DEBUG
677285169Scy		if ( debug ) {
678285169Scy			printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ;
679106163Sroberto		}
680285169Scy#endif
681285169Scy		return ;
682106163Sroberto	}
683285169Scy
684106163Sroberto	/*
685106163Sroberto	 * We get down to business
686106163Sroberto	 */
687106163Sroberto
688285169Scy	pp->lastrec = tRecvTimestamp ;
689285169Scy
690285169Scy	up->iLineCount ++ ;
691285169Scy
692285169Scy	up->iProcessState = JJY_PROCESS_STATE_RECEIVE ;
693285169Scy	up->bReceiveFlag = TRUE ;
694285169Scy
695285169Scy	iReadRawBuf = 0 ;
696285169Scy	iBreakPosition = up->iRawBufLen - 1 ;
697285169Scy	for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) {
698285169Scy
699285169Scy		if ( up->linediscipline == LDISC_RAW ) {
700285169Scy
701285169Scy			if ( up->bWaitBreakString ) {
702285169Scy				iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ;
703285169Scy				if ( iBreakPosition == -1 ) {
704285169Scy					/* Break string have not come yet */
705285169Scy					if ( up->iRawBufLen < MAX_RAWBUF - 2
706285169Scy					  || iReadRawBuf > 0 ) {
707285169Scy						/* Temporary buffer is not full */
708285169Scy						break ;
709285169Scy					} else {
710285169Scy						/* Temporary buffer is full */
711285169Scy						iBreakPosition = up->iRawBufLen - 1 ;
712285169Scy					}
713285169Scy				}
714285169Scy			} else {
715285169Scy				iBreakPosition = up->iRawBufLen - 1 ;
716285169Scy			}
717285169Scy
718362716Scy			/* Copy characters from temporary buffer to process buffer */
719285169Scy			up->iLineBufLen = up->iTextBufLen = 0 ;
720285169Scy			for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) {
721285169Scy
722285169Scy				/* Copy all characters */
723285169Scy				up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ;
724285169Scy				up->iLineBufLen ++ ;
725285169Scy
726285169Scy				/* Copy printable characters */
727294554Sdelphij				if ( ! iscntrl( (u_char)up->sRawBuf[i] ) ) {
728285169Scy					up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ;
729285169Scy					up->iTextBufLen ++ ;
730285169Scy				}
731285169Scy
732285169Scy			}
733285169Scy			up->sLineBuf[up->iLineBufLen] = 0 ;
734285169Scy			up->sTextBuf[up->iTextBufLen] = 0 ;
735280849Scy#ifdef DEBUG
736285169Scy			printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n",
737285169Scy				 sFunctionName, up->iLineBufLen, up->iTextBufLen ) ;
738285169Scy#endif
739285169Scy
740285169Scy			if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) {
741285169Scy#ifdef DEBUG
742285169Scy				printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n",
743285169Scy					 sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ;
744285169Scy#endif
745285169Scy				if ( iBreakPosition + 1 < up->iRawBufLen ) {
746285169Scy					iReadRawBuf = iBreakPosition + 1 ;
747285169Scy					continue ;
748285169Scy				} else {
749285169Scy					break ;
750285169Scy				}
751285169Scy
752285169Scy			}
753285169Scy
754285169Scy		}
755285169Scy
756280849Scy		if ( up->linediscipline == LDISC_RAW ) {
757285169Scy			pBuf = up->sLineBuf ;
758285169Scy			iLen = up->iLineBufLen ;
759280849Scy		} else {
760285169Scy			pBuf = pp->a_lastcode ;
761285169Scy			iLen = pp->lencode ;
762280849Scy		}
763285169Scy
764285169Scy		iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ;
765316068Sdelphij		memcpy( sLogText, pBuf, iCopyLen ) ;
766316068Sdelphij		sLogText[iCopyLen] = '\0' ;
767285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ;
768285169Scy
769285169Scy		switch ( up->unittype ) {
770285169Scy
771285169Scy		case UNITTYPE_TRISTATE_JJY01 :
772285169Scy			rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
773285169Scy			break ;
774285169Scy
775285169Scy		case UNITTYPE_CDEX_JST2000 :
776285169Scy			rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
777285169Scy			break ;
778285169Scy
779285169Scy		case UNITTYPE_ECHOKEISOKUKI_LT2000 :
780285169Scy			rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
781285169Scy			break ;
782285169Scy
783285169Scy		case UNITTYPE_CITIZENTIC_JJY200 :
784285169Scy			rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
785285169Scy			break ;
786285169Scy
787285169Scy		case UNITTYPE_TRISTATE_GPSCLOCK01 :
788285169Scy			rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
789285169Scy			break ;
790285169Scy
791285169Scy		case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
792285169Scy			rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ;
793285169Scy			break ;
794285169Scy
795285169Scy		case UNITTYPE_TELEPHONE :
796285169Scy			rc = jjy_receive_telephone ( rbufp ) ;
797285169Scy			break ;
798285169Scy
799285169Scy		default :
800285169Scy			rc = JJY_RECEIVE_ERROR ;
801285169Scy			break ;
802285169Scy
803285169Scy		}
804285169Scy
805285169Scy		switch ( rc ) {
806285169Scy		case JJY_RECEIVE_DONE :
807285169Scy		case JJY_RECEIVE_SKIP :
808285169Scy			up->iProcessState = JJY_PROCESS_STATE_DONE ;
809285169Scy			break ;
810285169Scy		case JJY_RECEIVE_ERROR :
811285169Scy			up->iProcessState = JJY_PROCESS_STATE_ERROR ;
812285169Scy			break ;
813285169Scy		default :
814285169Scy			break ;
815285169Scy		}
816285169Scy
817285169Scy		if ( up->linediscipline == LDISC_RAW ) {
818285169Scy			if ( rc == JJY_RECEIVE_UNPROCESS ) {
819285169Scy				break ;
820285169Scy			}
821285169Scy			iReadRawBuf = iBreakPosition + 1 ;
822285169Scy			if ( iReadRawBuf >= up->iRawBufLen ) {
823285169Scy				/* Processed all received data */
824285169Scy				break ;
825285169Scy			}
826285169Scy		}
827285169Scy
828285169Scy		if ( up->linediscipline == LDISC_CLK ) {
829285169Scy			break ;
830285169Scy		}
831285169Scy
832280849Scy	}
833285169Scy
834285169Scy	if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) {
835285169Scy		for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) {
836285169Scy			up->sRawBuf[i] = up->sRawBuf[j] ;
837285169Scy		}
838285169Scy		up->iRawBufLen -= iReadRawBuf ;
839285169Scy		if ( up->iRawBufLen < 0 ) {
840285169Scy			up->iRawBufLen = 0 ;
841285169Scy		}
842285169Scy	}
843285169Scy
844285169Scy	up->bReceiveFlag = FALSE ;
845285169Scy
846285169Scy}
847285169Scy
848285169Scy/**************************************************************************************************/
849285169Scy
850285169Scystatic int
851285169ScygetRawDataBreakPosition ( struct jjyunit *up, int iStart )
852285169Scy{
853285169Scy
854285169Scy	int 	i, j ;
855285169Scy
856285169Scy	if ( iStart >= up->iRawBufLen ) {
857285169Scy#ifdef DEBUG
858285169Scy		printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
859280849Scy#endif
860285169Scy		return -1 ;
861285169Scy	}
862280849Scy
863285169Scy	for ( i = iStart ; i < up->iRawBufLen ; i ++ ) {
864106163Sroberto
865285169Scy		for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) {
866106163Sroberto
867285169Scy			if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) {
868106163Sroberto
869285169Scy				if ( strncmp( up->sRawBuf + i,
870285169Scy					up->pRawBreak[j].pString,
871285169Scy					up->pRawBreak[j].iLength ) == 0 ) {
872285169Scy
873285169Scy#ifdef DEBUG
874285169Scy					printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n",
875285169Scy						iStart, i + up->pRawBreak[j].iLength - 1 ) ;
876285169Scy#endif
877285169Scy					return i + up->pRawBreak[j].iLength - 1 ;
878285169Scy
879285169Scy				}
880285169Scy			}
881285169Scy		}
882285169Scy	}
883285169Scy
884285169Scy#ifdef DEBUG
885285169Scy	printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
886285169Scy#endif
887285169Scy	return -1 ;
888285169Scy
889285169Scy}
890285169Scy
891285169Scy/**************************************************************************************************/
892285169Scy/*  jjy_poll - called by the transmit procedure                                                   */
893285169Scy/**************************************************************************************************/
894285169Scystatic void
895285169Scyjjy_poll ( int unit, struct peer *peer )
896285169Scy{
897285169Scy
898285169Scy	char	sLog [ 40 ], sReach [ 9 ] ;
899285169Scy
900285169Scy	struct jjyunit      *up;
901285169Scy	struct refclockproc *pp;
902285169Scy
903285169Scy	pp = peer->procptr;
904285169Scy	up = pp->unitptr ;
905285169Scy
906285169Scy	if ( up->bInitError ) {
907285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ;
908285169Scy		return ;
909285169Scy	}
910285169Scy
911285169Scy	if ( pp->polls > 0  &&  up->iLineCount == 0 ) {
912285169Scy		/*
913285169Scy		 * No reply for last command
914285169Scy		 */
915285169Scy		refclock_report ( peer, CEVNT_TIMEOUT ) ;
916285169Scy	}
917285169Scy
918285169Scy	pp->polls ++ ;
919285169Scy
920285169Scy	sReach[0] = peer->reach & 0x80 ? '1' : '0' ;
921285169Scy	sReach[1] = peer->reach & 0x40 ? '1' : '0' ;
922285169Scy	sReach[2] = peer->reach & 0x20 ? '1' : '0' ;
923285169Scy	sReach[3] = peer->reach & 0x10 ? '1' : '0' ;
924285169Scy	sReach[4] = peer->reach & 0x08 ? '1' : '0' ;
925285169Scy	sReach[5] = peer->reach & 0x04 ? '1' : '0' ;
926285169Scy	sReach[6] = peer->reach & 0x02 ? '1' : '0' ;
927285169Scy	sReach[7] = 0 ; /* This poll */
928285169Scy	sReach[8] = 0 ;
929285169Scy
930285169Scy	snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ;
931285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
932285169Scy
933285169Scy	up->iProcessState = JJY_PROCESS_STATE_POLL ;
934285169Scy	up->iCommandSeq = 0 ;
935285169Scy	up->iReceiveSeq = 0 ;
936285169Scy	up->iLineCount = 0 ;
937285169Scy	up->bLineError = FALSE ;
938285169Scy	up->iRawBufLen = 0 ;
939285169Scy
940106163Sroberto	switch ( up->unittype ) {
941362716Scy
942106163Sroberto	case UNITTYPE_TRISTATE_JJY01 :
943285169Scy		jjy_poll_tristate_jjy01  ( unit, peer ) ;
944106163Sroberto		break ;
945106163Sroberto
946106163Sroberto	case UNITTYPE_CDEX_JST2000 :
947285169Scy		jjy_poll_cdex_jst2000 ( unit, peer ) ;
948106163Sroberto		break ;
949106163Sroberto
950182007Sroberto	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
951285169Scy		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
952182007Sroberto		break ;
953182007Sroberto
954280849Scy	case UNITTYPE_CITIZENTIC_JJY200 :
955285169Scy		jjy_poll_citizentic_jjy200 ( unit, peer ) ;
956280849Scy		break ;
957200576Sroberto
958280849Scy	case UNITTYPE_TRISTATE_GPSCLOCK01 :
959285169Scy		jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
960280849Scy		break ;
961280849Scy
962285169Scy	case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
963285169Scy		jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ;
964285169Scy		break ;
965285169Scy
966285169Scy	case UNITTYPE_TELEPHONE :
967285169Scy		jjy_poll_telephone ( unit, peer ) ;
968285169Scy		break ;
969285169Scy
970106163Sroberto	default :
971106163Sroberto		break ;
972106163Sroberto
973106163Sroberto	}
974106163Sroberto
975285169Scy}
976106163Sroberto
977285169Scy/**************************************************************************************************/
978285169Scy/*  jjy_timer - called at one-second intervals                                                    */
979285169Scy/**************************************************************************************************/
980285169Scystatic void
981285169Scyjjy_timer ( int unit, struct peer *peer )
982285169Scy{
983285169Scy
984285169Scy	struct	refclockproc *pp ;
985285169Scy	struct	jjyunit      *up ;
986285169Scy
987285169Scy#ifdef DEBUG
988285169Scy	if ( debug ) {
989285169Scy		printf ( "refclock_jjy.c : jjy_timer\n" ) ;
990280849Scy	}
991285169Scy#endif
992106163Sroberto
993285169Scy	pp = peer->procptr ;
994285169Scy	up = pp->unitptr ;
995200576Sroberto
996285169Scy	if ( up->bReceiveFlag ) {
997285169Scy#ifdef DEBUG
998285169Scy		if ( debug ) {
999285169Scy			printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ;
1000106163Sroberto		}
1001285169Scy#endif
1002106163Sroberto		return ;
1003106163Sroberto	}
1004106163Sroberto
1005285169Scy	switch ( up->unittype ) {
1006362716Scy
1007285169Scy	case UNITTYPE_TELEPHONE :
1008285169Scy		jjy_timer_telephone ( unit, peer ) ;
1009285169Scy		break ;
1010285169Scy
1011285169Scy	default :
1012285169Scy		break ;
1013285169Scy
1014285169Scy	}
1015285169Scy
1016285169Scy}
1017285169Scy
1018285169Scy/**************************************************************************************************/
1019285169Scy/*  jjy_synctime                                                                                  */
1020285169Scy/**************************************************************************************************/
1021285169Scystatic void
1022285169Scyjjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
1023285169Scy{
1024285169Scy
1025285169Scy	char	sLog [ 80 ], cStatus ;
1026285169Scy	const char	*pStatus ;
1027285169Scy
1028106163Sroberto	pp->year   = up->year ;
1029285169Scy	pp->day    = ymd2yd( up->year, up->month, up->day ) ;
1030106163Sroberto	pp->hour   = up->hour ;
1031106163Sroberto	pp->minute = up->minute ;
1032106163Sroberto	pp->second = up->second ;
1033285169Scy	pp->nsec   = up->msecond * 1000000 ;
1034106163Sroberto
1035362716Scy	/*
1036362716Scy	 * JST to UTC
1037106163Sroberto	 */
1038106163Sroberto	pp->hour -= 9 ;
1039106163Sroberto	if ( pp->hour < 0 ) {
1040106163Sroberto		pp->hour += 24 ;
1041106163Sroberto		pp->day -- ;
1042106163Sroberto		if ( pp->day < 1 ) {
1043106163Sroberto			pp->year -- ;
1044285169Scy			pp->day  = ymd2yd( pp->year, 12, 31 ) ;
1045106163Sroberto		}
1046106163Sroberto	}
1047106163Sroberto
1048106163Sroberto	/*
1049106163Sroberto	 * Process the new sample in the median filter and determine the
1050106163Sroberto	 * timecode timestamp.
1051106163Sroberto	 */
1052182007Sroberto
1053285169Scy	if ( ! refclock_process( pp ) ) {
1054285169Scy		refclock_report( peer, CEVNT_BADTIME ) ;
1055285169Scy		return ;
1056285169Scy	}
1057285169Scy
1058285169Scy	pp->lastref = pp->lastrec ;
1059285169Scy
1060285169Scy	refclock_receive( peer ) ;
1061285169Scy
1062285169Scy	/*
1063285169Scy	 * Write into the clockstats file
1064285169Scy	 */
1065285169Scy	snprintf ( sLog, sizeof(sLog),
1066285169Scy		   "%04d/%02d/%02d %02d:%02d:%02d.%03d JST   ( %04d/%03d %02d:%02d:%02d.%03d UTC )",
1067280849Scy		   up->year, up->month, up->day,
1068285169Scy		   up->hour, up->minute, up->second, up->msecond,
1069285169Scy		   pp->year, pp->day, pp->hour, pp->minute, pp->second,
1070285169Scy		   (int)(pp->nsec/1000000) ) ;
1071285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
1072182007Sroberto
1073285169Scy	cStatus = ' ' ;
1074285169Scy	pStatus = "" ;
1075285169Scy
1076285169Scy	switch ( peer->status ) {
1077285169Scy	case 0 : cStatus = ' ' ; pStatus = "Reject"    ; break ;
1078285169Scy	case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ;
1079285169Scy	case 2 : cStatus = '.' ; pStatus = "Excess"    ; break ;
1080285169Scy	case 3 : cStatus = '-' ; pStatus = "Outlier"   ; break ;
1081285169Scy	case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ;
1082285169Scy	case 5 : cStatus = '#' ; pStatus = "Selected"  ; break ;
1083285169Scy	case 6 : cStatus = '*' ; pStatus = "Sys.Peer"  ; break ;
1084285169Scy	case 7 : cStatus = 'o' ; pStatus = "PPS.Peer"  ; break ;
1085362716Scy	default : break ;
1086106163Sroberto	}
1087106163Sroberto
1088285169Scy	snprintf ( sLog, sizeof(sLog),
1089285169Scy		   "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.",
1090285169Scy		    peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ;
1091285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1092182007Sroberto
1093106163Sroberto}
1094106163Sroberto
1095285169Scy/*################################################################################################*/
1096285169Scy/*################################################################################################*/
1097285169Scy/*##												##*/
1098285169Scy/*##    The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02					##*/
1099285169Scy/*##												##*/
1100285169Scy/*##    server  127.127.40.X  mode 1								##*/
1101285169Scy/*##												##*/
1102285169Scy/*################################################################################################*/
1103285169Scy/*################################################################################################*/
1104285169Scy/*                                                                                                */
1105285169Scy/*  Command               Response                                  Remarks                       */
1106285169Scy/*  --------------------  ----------------------------------------  ----------------------------  */
1107285169Scy/*  dcst<CR><LF>          VALID<CR><LF> or INVALID<CR><LF>                                        */
1108285169Scy/*  stus<CR><LF>          ADJUSTED<CR><LF> or UNADJUSTED<CR><LF>                                  */
1109285169Scy/*  date<CR><LF>          YYYY/MM/DD XXX<CR><LF>                    XXX is the day of the week    */
1110285169Scy/*  time<CR><LF>          HH:MM:SS<CR><LF>                          Not used by this driver       */
1111285169Scy/*  stim<CR><LF>          HH:MM:SS<CR><LF>                          Reply at just second          */
1112285169Scy/*                                                                                                */
1113285169Scy/*################################################################################################*/
1114285169Scy
1115285169Scy#define	TS_JJY01_COMMAND_NUMBER_DATE	1
1116285169Scy#define	TS_JJY01_COMMAND_NUMBER_TIME	2
1117285169Scy#define	TS_JJY01_COMMAND_NUMBER_STIM	3
1118285169Scy#define	TS_JJY01_COMMAND_NUMBER_STUS	4
1119285169Scy#define	TS_JJY01_COMMAND_NUMBER_DCST	5
1120285169Scy
1121285169Scy#define	TS_JJY01_REPLY_DATE     	"yyyy/mm/dd www"
1122285169Scy#define	TS_JJY01_REPLY_STIM     	"hh:mm:ss"
1123285169Scy#define	TS_JJY01_REPLY_STUS_ADJUSTED	"adjusted"
1124285169Scy#define	TS_JJY01_REPLY_STUS_UNADJUSTED	"unadjusted"
1125285169Scy#define	TS_JJY01_REPLY_DCST_VALID	"valid"
1126285169Scy#define	TS_JJY01_REPLY_DCST_INVALID	"invalid"
1127285169Scy
1128285169Scy#define	TS_JJY01_REPLY_LENGTH_DATE           	14	/* Length without <CR><LF> */
1129285169Scy#define	TS_JJY01_REPLY_LENGTH_TIME           	8	/* Length without <CR><LF> */
1130285169Scy#define	TS_JJY01_REPLY_LENGTH_STIM           	8	/* Length without <CR><LF> */
1131285169Scy#define	TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED  	8	/* Length without <CR><LF> */
1132285169Scy#define	TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED	10	/* Length without <CR><LF> */
1133285169Scy#define	TS_JJY01_REPLY_LENGTH_DCST_VALID     	5	/* Length without <CR><LF> */
1134285169Scy#define	TS_JJY01_REPLY_LENGTH_DCST_INVALID   	7	/* Length without <CR><LF> */
1135285169Scy
1136285169Scystatic  struct
1137285169Scy{
1138285169Scy	const char	commandNumber ;
1139285169Scy	const char	*command ;
1140285169Scy	int	commandLength ;
1141285169Scy	int	iExpectedReplyLength [ 2 ] ;
1142285169Scy} tristate_jjy01_command_sequence[] =
1143285169Scy{
1144285169Scy	{ 0, NULL, 0, { 0, 0 } }, /* Idle */
1145285169Scy	{ TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID   , TS_JJY01_REPLY_LENGTH_DCST_INVALID } },
1146285169Scy	{ TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } },
1147285169Scy	{ TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME         , TS_JJY01_REPLY_LENGTH_TIME } },
1148285169Scy	{ TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE         , TS_JJY01_REPLY_LENGTH_DATE } },
1149285169Scy	{ TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM         , TS_JJY01_REPLY_LENGTH_STIM } },
1150285169Scy	/* End of command */
1151285169Scy	{ 0, NULL, 0, { 0, 0 } }
1152285169Scy} ;
1153285169Scy
1154106163Sroberto/**************************************************************************************************/
1155106163Sroberto
1156106163Srobertostatic int
1157285169Scyjjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up )
1158285169Scy{
1159285169Scy
1160285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ;
1161285169Scy
1162285169Scy	up->unittype  = UNITTYPE_TRISTATE_JJY01 ;
1163285169Scy	up->linespeed = SPEED232_TRISTATE_JJY01 ;
1164285169Scy	up->linediscipline = LDISC_CLK ;
1165285169Scy
1166362716Scy	time( &(up->tLastAdjustedTimestamp) ) ;
1167362716Scy	up->bStusReplyAdjustedAtLeastOnce = FALSE ;
1168362716Scy
1169285169Scy	return 0 ;
1170285169Scy
1171285169Scy}
1172285169Scy
1173285169Scy/**************************************************************************************************/
1174285169Scy
1175285169Scystatic int
1176106163Srobertojjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
1177106163Sroberto{
1178280849Scy	struct jjyunit	    *up ;
1179106163Sroberto	struct refclockproc *pp ;
1180280849Scy	struct peer	    *peer;
1181106163Sroberto
1182362716Scy	char *	pBuf ;
1183362716Scy	char	sLog [ MAX_LOGTEXT ] ;
1184362716Scy	int 	iLen ;
1185362716Scy	int 	rc ;
1186362716Scy	time_t	now ;
1187362716Scy	double	fSeconds ;
1188106163Sroberto
1189294554Sdelphij	const char *	pCmd ;
1190294554Sdelphij	int 		iCmdLen ;
1191280849Scy
1192285169Scy	/* Initialize pointers  */
1193285169Scy
1194280849Scy	peer = rbufp->recv_peer ;
1195106163Sroberto	pp = peer->procptr ;
1196280849Scy	up = pp->unitptr ;
1197106163Sroberto
1198106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
1199285169Scy		pBuf = up->sTextBuf ;
1200285169Scy		iLen = up->iTextBufLen ;
1201106163Sroberto	} else {
1202280849Scy		pBuf = pp->a_lastcode ;
1203280849Scy		iLen = pp->lencode ;
1204106163Sroberto	}
1205106163Sroberto
1206285169Scy	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
1207106163Sroberto
1208285169Scy	/* Check expected reply */
1209106163Sroberto
1210285169Scy	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1211285169Scy		/* Command sequence has not been started, or has been completed */
1212285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1213285169Scy			  pBuf ) ;
1214285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1215285169Scy		up->bLineError = TRUE ;
1216285169Scy		return JJY_RECEIVE_ERROR ;
1217285169Scy	}
1218280849Scy
1219285169Scy	/* Check reply length */
1220182007Sroberto
1221285169Scy	if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
1222285169Scy	  && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
1223285169Scy		/* Unexpected reply length */
1224285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1225285169Scy			  iLen ) ;
1226285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1227285169Scy		up->bLineError = TRUE ;
1228285169Scy		return JJY_RECEIVE_ERROR ;
1229285169Scy	}
1230182007Sroberto
1231285169Scy	/* Parse reply */
1232182007Sroberto
1233285169Scy	switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
1234182007Sroberto
1235285169Scy	case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
1236285169Scy
1237285169Scy		rc = sscanf ( pBuf, "%4d/%2d/%2d",
1238285169Scy			      &up->year, &up->month, &up->day ) ;
1239285169Scy
1240285169Scy		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
1241285169Scy		  || up->month < 1 || 12 < up->month
1242285169Scy		  || up->day < 1 || 31 < up->day ) {
1243285169Scy			/* Invalid date */
1244285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
1245285169Scy				  rc, up->year, up->month, up->day ) ;
1246285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1247285169Scy			up->bLineError = TRUE ;
1248285169Scy			return JJY_RECEIVE_ERROR ;
1249285169Scy		}
1250285169Scy
1251280849Scy		break ;
1252106163Sroberto
1253280849Scy	case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1254280849Scy	case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
1255106163Sroberto
1256285169Scy		if ( up->iTimestampCount >= 2 ) {
1257285169Scy			/* Too many time reply */
1258285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
1259285169Scy				  up->iTimestampCount ) ;
1260285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1261285169Scy			up->bLineError = TRUE ;
1262285169Scy			return JJY_RECEIVE_ERROR ;
1263106163Sroberto		}
1264280849Scy
1265285169Scy		rc = sscanf ( pBuf, "%2d:%2d:%2d",
1266285169Scy			      &up->hour, &up->minute, &up->second ) ;
1267285169Scy
1268280849Scy		if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
1269280849Scy		     up->second > 60 ) {
1270285169Scy			/* Invalid time */
1271285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
1272285169Scy				  rc, up->hour, up->minute, up->second ) ;
1273285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1274285169Scy			up->bLineError = TRUE ;
1275285169Scy			return JJY_RECEIVE_ERROR ;
1276106163Sroberto		}
1277280849Scy
1278285169Scy		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
1279285169Scy
1280285169Scy		up->iTimestampCount++ ;
1281285169Scy
1282106163Sroberto		up->msecond = 0 ;
1283285169Scy
1284106163Sroberto		break ;
1285106163Sroberto
1286280849Scy	case TS_JJY01_COMMAND_NUMBER_STUS :
1287280849Scy
1288285169Scy		if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
1289362716Scy			     TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0 ) {
1290362716Scy			/* STUS reply : adjusted */
1291362716Scy			up->bStusReplyAdjusted = TRUE ;
1292362716Scy			up->bStusReplyAdjustedAtLeastOnce = TRUE ;
1293362716Scy			time( &(up->tLastAdjustedTimestamp) ) ;
1294362716Scy		} else if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
1295362716Scy			             TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
1296362716Scy			/* STUS reply : unadjusted */
1297362716Scy			up->bStusReplyAdjusted = FALSE ;
1298280849Scy		} else {
1299362716Scy			/* Bad reply */
1300285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1301285169Scy				  pBuf ) ;
1302285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1303285169Scy			up->bLineError = TRUE ;
1304285169Scy			return JJY_RECEIVE_ERROR ;
1305280849Scy		}
1306280849Scy
1307280849Scy		break ;
1308280849Scy
1309280849Scy	case TS_JJY01_COMMAND_NUMBER_DCST :
1310280849Scy
1311285169Scy		if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
1312362716Scy			      TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
1313285169Scy		  || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
1314362716Scy			      TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
1315362716Scy			/* Valid reply */
1316280849Scy		} else {
1317362716Scy			/* Bad reply */
1318285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1319285169Scy				  pBuf ) ;
1320285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1321285169Scy			up->bLineError = TRUE ;
1322285169Scy			return JJY_RECEIVE_ERROR ;
1323280849Scy		}
1324280849Scy
1325280849Scy		break ;
1326280849Scy
1327362716Scy	default : /* Unexpected reply */
1328106163Sroberto
1329285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1330285169Scy			  pBuf ) ;
1331285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1332285169Scy		up->bLineError = TRUE ;
1333285169Scy		return JJY_RECEIVE_ERROR ;
1334106163Sroberto
1335106163Sroberto	}
1336106163Sroberto
1337285169Scy	if ( up->iTimestampCount == 2 ) {
1338285169Scy		/* Process date and time */
1339106163Sroberto
1340362716Scy		time( &now ) ;
1341362716Scy		fSeconds = difftime( now, up->tLastAdjustedTimestamp ) ;
1342362716Scy
1343362716Scy		if ( ( pp->sloppyclockflag & CLK_FLAG2 ) != 0
1344362716Scy		  && ( ! up->bStusReplyAdjusted )
1345362716Scy		  && ( fSeconds >= ( pp->fudgetime2 * 3600 ) || ( ! up->bStusReplyAdjustedAtLeastOnce ) ) ) {
1346362716Scy			/* STUS is not ADJUSTED */
1347362716Scy			if ( fSeconds < 60 ) {
1348362716Scy				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds, "seconds" ) ;
1349362716Scy			} else if ( fSeconds < 3600 ) {
1350362716Scy				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 60, "minutes" ) ;
1351362716Scy			} else if ( fSeconds < 86400 ) {
1352362716Scy				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 3600, "hours" ) ;
1353362716Scy			} else {
1354362716Scy				snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 86400, "days" ) ;
1355362716Scy			}
1356362716Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1357362716Scy			return JJY_RECEIVE_SKIP ;
1358362716Scy		} else if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
1359362716Scy		         && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
1360362716Scy			/* 3 commands (time,date,stim) was executed in two seconds */
1361285169Scy			jjy_synctime( peer, pp, up ) ;
1362285169Scy			return JJY_RECEIVE_DONE ;
1363285169Scy		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
1364285169Scy			/* Over midnight, and date is unsure */
1365285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
1366285169Scy				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1367285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1368285169Scy			return JJY_RECEIVE_SKIP ;
1369285169Scy		} else {
1370285169Scy			/* Slow reply */
1371285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
1372285169Scy				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1373285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1374285169Scy			up->bLineError = TRUE ;
1375285169Scy			return JJY_RECEIVE_ERROR ;
1376285169Scy		}
1377280849Scy
1378280849Scy	}
1379280849Scy
1380285169Scy	/* Issue next command */
1381285169Scy
1382285169Scy	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
1383285169Scy		up->iCommandSeq ++ ;
1384280849Scy	}
1385280849Scy
1386285169Scy	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1387280849Scy		/* Command sequence completed */
1388285169Scy		return JJY_RECEIVE_DONE ;
1389280849Scy	}
1390280849Scy
1391285169Scy	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1392285169Scy	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1393285169Scy	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1394285169Scy		refclock_report ( peer, CEVNT_FAULT ) ;
1395285169Scy	}
1396280849Scy
1397285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1398285169Scy
1399285169Scy	return JJY_RECEIVE_WAIT ;
1400285169Scy
1401285169Scy}
1402285169Scy
1403285169Scy/**************************************************************************************************/
1404285169Scy
1405285169Scystatic void
1406285169Scyjjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1407285169Scy{
1408280849Scy#ifdef DEBUG
1409285169Scy	static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1410285169Scy#endif
1411285169Scy
1412285169Scy	struct refclockproc *pp ;
1413285169Scy	struct jjyunit	    *up ;
1414285169Scy
1415294554Sdelphij	const char *	pCmd ;
1416294554Sdelphij	int 		iCmdLen ;
1417285169Scy
1418285169Scy	pp = peer->procptr;
1419285169Scy	up = pp->unitptr ;
1420285169Scy
1421285169Scy	up->bLineError = FALSE ;
1422285169Scy	up->iTimestampCount = 0 ;
1423285169Scy
1424285169Scy	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1425285169Scy		/* Skip "dcst" and "stus" commands */
1426285169Scy		up->iCommandSeq = 2 ;
1427285169Scy		up->iLineCount = 2 ;
1428285169Scy	}
1429285169Scy
1430362716Scy	up->bStusReplyAdjusted = FALSE ;
1431362716Scy
1432285169Scy#ifdef DEBUG
1433280849Scy	if ( debug ) {
1434285169Scy		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
1435285169Scy			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1436285169Scy			up->iLineCount ) ;
1437280849Scy	}
1438280849Scy#endif
1439280849Scy
1440285169Scy	/*
1441285169Scy	 * Send a first command
1442285169Scy	 */
1443285169Scy
1444285169Scy	up->iCommandSeq ++ ;
1445285169Scy
1446285169Scy	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1447285169Scy	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1448280849Scy	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1449280849Scy		refclock_report ( peer, CEVNT_FAULT ) ;
1450280849Scy	}
1451280849Scy
1452285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1453285169Scy
1454285169Scy}
1455285169Scy
1456285169Scy/*################################################################################################*/
1457285169Scy/*################################################################################################*/
1458285169Scy/*##												##*/
1459285169Scy/*##    The C-DEX Co. Ltd. JJY receiver JST2000							##*/
1460285169Scy/*##												##*/
1461285169Scy/*##    server  127.127.40.X  mode 2								##*/
1462285169Scy/*##												##*/
1463285169Scy/*################################################################################################*/
1464285169Scy/*################################################################################################*/
1465285169Scy/*                                                                                                */
1466285169Scy/*  Command               Response                                  Remarks                       */
1467285169Scy/*  --------------------  ----------------------------------------  ----------------------------  */
1468362716Scy/*  <ENQ>1J<ETX>          <STX>JYYMMDDWHHMMSSS<ETX>                 J is a fixed character        */
1469285169Scy/*                                                                                                */
1470285169Scy/*################################################################################################*/
1471285169Scy
1472285169Scystatic struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
1473285169Scy{
1474285169Scy	{ "\x03", 1 }, { NULL, 0 }
1475285169Scy} ;
1476285169Scy
1477285169Scy/**************************************************************************************************/
1478285169Scy
1479285169Scystatic int
1480285169Scyjjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
1481285169Scy{
1482285169Scy
1483285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
1484285169Scy
1485285169Scy	up->unittype  = UNITTYPE_CDEX_JST2000 ;
1486285169Scy	up->linespeed = SPEED232_CDEX_JST2000 ;
1487285169Scy	up->linediscipline = LDISC_RAW ;
1488285169Scy
1489285169Scy	up->pRawBreak = cdex_jst2000_raw_break ;
1490285169Scy	up->bWaitBreakString = TRUE ;
1491285169Scy
1492285169Scy	up->bSkipCntrlCharOnly = FALSE ;
1493285169Scy
1494280849Scy	return 0 ;
1495280849Scy
1496106163Sroberto}
1497106163Sroberto
1498106163Sroberto/**************************************************************************************************/
1499106163Sroberto
1500106163Srobertostatic int
1501106163Srobertojjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
1502106163Sroberto{
1503106163Sroberto
1504106163Sroberto	struct jjyunit      *up ;
1505106163Sroberto	struct refclockproc *pp ;
1506285169Scy	struct peer         *peer ;
1507106163Sroberto
1508362716Scy	char	*pBuf, sLog [ MAX_LOGTEXT ] ;
1509106163Sroberto	int 	iLen ;
1510106163Sroberto	int 	rc ;
1511106163Sroberto
1512285169Scy	/* Initialize pointers */
1513285169Scy
1514280849Scy	peer = rbufp->recv_peer ;
1515106163Sroberto	pp = peer->procptr ;
1516280849Scy	up = pp->unitptr ;
1517106163Sroberto
1518106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
1519285169Scy		pBuf = up->sTextBuf ;
1520285169Scy		iLen = up->iTextBufLen ;
1521106163Sroberto	} else {
1522280849Scy		pBuf = pp->a_lastcode ;
1523280849Scy		iLen = pp->lencode ;
1524106163Sroberto	}
1525106163Sroberto
1526285169Scy	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
1527106163Sroberto
1528285169Scy	/* Check expected reply */
1529106163Sroberto
1530285169Scy	if ( up->iCommandSeq != 1 ) {
1531285169Scy		/* Command sequence has not been started, or has been completed */
1532285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1533285169Scy			  pBuf ) ;
1534285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1535285169Scy		up->bLineError = TRUE ;
1536285169Scy		return JJY_RECEIVE_ERROR ;
1537285169Scy	}
1538106163Sroberto
1539285169Scy	/* Wait until ETX comes */
1540106163Sroberto
1541285169Scy	if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
1542285169Scy		return JJY_RECEIVE_UNPROCESS ;
1543285169Scy	}
1544106163Sroberto
1545285169Scy	/* Check reply length */
1546285169Scy
1547285169Scy	if ( iLen != 15 ) {
1548285169Scy		/* Unexpected reply length */
1549285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1550285169Scy			  iLen ) ;
1551285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1552285169Scy		up->bLineError = TRUE ;
1553285169Scy		return JJY_RECEIVE_ERROR ;
1554106163Sroberto	}
1555106163Sroberto
1556309007Sdelphij	/* JYYMMDDWHHMMSSS */
1557106163Sroberto
1558309007Sdelphij	rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
1559285169Scy		      &up->year, &up->month, &up->day,
1560285169Scy		      &up->hour, &up->minute, &up->second,
1561285169Scy		      &up->msecond ) ;
1562285169Scy
1563285169Scy	if ( rc != 7 || up->month < 1 || up->month > 12 ||
1564285169Scy	     up->day < 1 || up->day > 31 || up->hour > 23 ||
1565285169Scy	     up->minute > 59 || up->second > 60 ) {
1566285169Scy		/* Invalid date and time */
1567285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1568285169Scy			  rc, up->year, up->month, up->day,
1569285169Scy			  up->hour, up->minute, up->second ) ;
1570285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1571285169Scy		up->bLineError = TRUE ;
1572285169Scy		return JJY_RECEIVE_ERROR ;
1573285169Scy	}
1574285169Scy
1575285169Scy	up->year    += 2000 ;
1576285169Scy	up->msecond *= 100 ;
1577285169Scy
1578285169Scy	jjy_synctime( peer, pp, up ) ;
1579285169Scy
1580285169Scy	return JJY_RECEIVE_DONE ;
1581285169Scy
1582106163Sroberto}
1583106163Sroberto
1584106163Sroberto/**************************************************************************************************/
1585182007Sroberto
1586285169Scystatic void
1587285169Scyjjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1588285169Scy{
1589285169Scy
1590285169Scy	struct refclockproc *pp ;
1591285169Scy	struct jjyunit      *up ;
1592285169Scy
1593285169Scy	pp = peer->procptr ;
1594285169Scy	up = pp->unitptr ;
1595285169Scy
1596285169Scy	up->bLineError = FALSE ;
1597285169Scy	up->iRawBufLen = 0 ;
1598285169Scy	up->iLineBufLen = 0 ;
1599285169Scy	up->iTextBufLen = 0 ;
1600285169Scy
1601285169Scy	/*
1602285169Scy	 * Send "<ENQ>1J<ETX>" command
1603285169Scy	 */
1604285169Scy
1605285169Scy	up->iCommandSeq ++ ;
1606285169Scy
1607285169Scy	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1608285169Scy		refclock_report ( peer, CEVNT_FAULT ) ;
1609285169Scy	}
1610285169Scy
1611285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
1612285169Scy
1613285169Scy}
1614285169Scy
1615285169Scy/*################################################################################################*/
1616285169Scy/*################################################################################################*/
1617285169Scy/*##												##*/
1618285169Scy/*##    The Echo Keisokuki Co. Ltd. JJY receiver LT2000						##*/
1619285169Scy/*##												##*/
1620285169Scy/*##    server  127.127.40.X  mode 3								##*/
1621285169Scy/*##												##*/
1622285169Scy/*################################################################################################*/
1623285169Scy/*################################################################################################*/
1624285169Scy/*                                                                                                */
1625285169Scy/*  Command               Response                                  Remarks                       */
1626285169Scy/*  --------------------  ----------------------------------------  ----------------------------  */
1627285169Scy/*  #                                                               Mode 1 ( Request & Send )     */
1628285169Scy/*  T                     YYMMDDWHHMMSS<BCC1><BCC2><CR>                                           */
1629285169Scy/*  C                                                               Mode 2 ( Continuous )         */
1630285169Scy/*                        YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>     0.5 sec before time stamp     */
1631285169Scy/*                        <SUB>                                     Second signal                 */
1632285169Scy/*                                                                                                */
1633285169Scy/*################################################################################################*/
1634285169Scy
1635285169Scy#define	ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND		1
1636285169Scy#define	ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS		2
1637285169Scy#define	ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS	3
1638285169Scy
1639285169Scy#define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND 	"#"
1640285169Scy#define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME 	"T"
1641285169Scy#define	ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS 	"C"
1642285169Scy
1643285169Scy/**************************************************************************************************/
1644285169Scy
1645182007Srobertostatic int
1646285169Scyjjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
1647285169Scy{
1648285169Scy
1649285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
1650285169Scy
1651285169Scy	up->unittype  = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
1652285169Scy	up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
1653285169Scy	up->linediscipline = LDISC_CLK ;
1654285169Scy
1655285169Scy	up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
1656285169Scy
1657285169Scy	return 0 ;
1658285169Scy
1659285169Scy}
1660285169Scy
1661285169Scy/**************************************************************************************************/
1662285169Scy
1663285169Scystatic int
1664182007Srobertojjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1665182007Sroberto{
1666182007Sroberto
1667182007Sroberto	struct jjyunit      *up ;
1668182007Sroberto	struct refclockproc *pp ;
1669280849Scy	struct peer	    *peer;
1670182007Sroberto
1671285169Scy	char	*pBuf, sLog [ 100 ], sErr [ 60 ] ;
1672182007Sroberto	int 	iLen ;
1673182007Sroberto	int 	rc ;
1674280849Scy	int	i, ibcc, ibcc1, ibcc2 ;
1675182007Sroberto
1676285169Scy	/* Initialize pointers */
1677285169Scy
1678280849Scy	peer = rbufp->recv_peer ;
1679182007Sroberto	pp = peer->procptr ;
1680280849Scy	up = pp->unitptr ;
1681182007Sroberto
1682182007Sroberto	if ( up->linediscipline == LDISC_RAW ) {
1683285169Scy		pBuf = up->sTextBuf ;
1684285169Scy		iLen = up->iTextBufLen ;
1685182007Sroberto	} else {
1686280849Scy		pBuf = pp->a_lastcode ;
1687280849Scy		iLen = pp->lencode ;
1688182007Sroberto	}
1689182007Sroberto
1690285169Scy	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
1691182007Sroberto
1692285169Scy	/* Check reply length */
1693182007Sroberto
1694285169Scy	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1695285169Scy	       && iLen != 15 )
1696285169Scy	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1697285169Scy	       && iLen != 17 )
1698285169Scy	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1699285169Scy	       && iLen != 17 ) ) {
1700285169Scy		/* Unexpected reply length */
1701285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1702285169Scy			  iLen ) ;
1703285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1704285169Scy		up->bLineError = TRUE ;
1705285169Scy		return JJY_RECEIVE_ERROR ;
1706285169Scy	}
1707182007Sroberto
1708285169Scy	if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
1709285169Scy		/* YYMMDDWHHMMSS<BCC1><BCC2> */
1710182007Sroberto
1711285169Scy		for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
1712285169Scy			ibcc ^= pBuf[i] ;
1713285169Scy		}
1714182007Sroberto
1715285169Scy		ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1716285169Scy		ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
1717285169Scy		if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1718285169Scy			snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
1719285169Scy				  pBuf[13] & 0xFF, pBuf[14] & 0xFF,
1720285169Scy				  ibcc1, ibcc2 ) ;
1721285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1722285169Scy				  sErr ) ;
1723285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1724285169Scy			up->bLineError = TRUE ;
1725285169Scy			return JJY_RECEIVE_ERROR ;
1726280849Scy		}
1727182007Sroberto
1728285169Scy	}
1729285169Scy
1730285169Scy	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1731285169Scy	       && iLen == 15 )
1732285169Scy	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1733285169Scy	       && iLen == 17 )
1734285169Scy	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1735285169Scy	       && iLen == 17 ) ) {
1736285169Scy		/* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1737285169Scy
1738182007Sroberto		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1739280849Scy			      &up->year, &up->month, &up->day,
1740280849Scy			      &up->hour, &up->minute, &up->second ) ;
1741285169Scy
1742285169Scy		if ( rc != 6 || up->month < 1 || up->month > 12
1743285169Scy		  || up->day < 1 || up->day > 31
1744285169Scy		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1745285169Scy			/* Invalid date and time */
1746285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1747285169Scy				  rc, up->year, up->month, up->day,
1748285169Scy				  up->hour, up->minute, up->second ) ;
1749285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1750285169Scy			up->bLineError = TRUE ;
1751285169Scy			return JJY_RECEIVE_ERROR ;
1752182007Sroberto		}
1753182007Sroberto
1754182007Sroberto		up->year += 2000 ;
1755182007Sroberto
1756285169Scy		if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1757285169Scy		  || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1758285169Scy			/* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
1759182007Sroberto
1760182007Sroberto			up->msecond = 500 ;
1761285169Scy			up->second -- ;
1762285169Scy			if ( up->second < 0 ) {
1763285169Scy				up->second = 59 ;
1764285169Scy				up->minute -- ;
1765285169Scy				if ( up->minute < 0 ) {
1766285169Scy					up->minute = 59 ;
1767285169Scy					up->hour -- ;
1768285169Scy					if ( up->hour < 0 ) {
1769285169Scy						up->hour = 23 ;
1770285169Scy						up->day -- ;
1771285169Scy						if ( up->day < 1 ) {
1772285169Scy							up->month -- ;
1773285169Scy							if ( up->month < 1 ) {
1774285169Scy								up->month = 12 ;
1775285169Scy								up->year -- ;
1776285169Scy							}
1777182007Sroberto						}
1778182007Sroberto					}
1779182007Sroberto				}
1780182007Sroberto			}
1781182007Sroberto
1782182007Sroberto		}
1783182007Sroberto
1784285169Scy		jjy_synctime( peer, pp, up ) ;
1785182007Sroberto
1786182007Sroberto
1787285169Scy	}
1788285169Scy
1789285169Scy	if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1790285169Scy		/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1791285169Scy
1792285169Scy		iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1793285169Scy		if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen  ) {
1794182007Sroberto			refclock_report ( peer, CEVNT_FAULT ) ;
1795182007Sroberto		}
1796182007Sroberto
1797285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1798285169Scy
1799285169Scy	}
1800285169Scy
1801285169Scy	return JJY_RECEIVE_DONE ;
1802285169Scy
1803285169Scy}
1804285169Scy
1805285169Scy/**************************************************************************************************/
1806285169Scy
1807285169Scystatic void
1808285169Scyjjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1809285169Scy{
1810285169Scy
1811285169Scy	struct refclockproc *pp ;
1812285169Scy	struct jjyunit      *up ;
1813285169Scy
1814285169Scy	char	sCmd[2] ;
1815285169Scy
1816285169Scy	pp = peer->procptr ;
1817285169Scy	up = pp->unitptr ;
1818285169Scy
1819285169Scy	up->bLineError = FALSE ;
1820285169Scy
1821285169Scy	/*
1822285169Scy	 * Send "T" or "C" command
1823285169Scy	 */
1824285169Scy
1825285169Scy	switch ( up->operationmode ) {
1826285169Scy	case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
1827285169Scy		sCmd[0] = 'T' ;
1828182007Sroberto		break ;
1829285169Scy	case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
1830285169Scy	case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
1831285169Scy		sCmd[0] = 'C' ;
1832285169Scy		break ;
1833285169Scy	}
1834285169Scy	sCmd[1] = 0 ;
1835182007Sroberto
1836285169Scy	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1837285169Scy		refclock_report ( peer, CEVNT_FAULT ) ;
1838182007Sroberto	}
1839182007Sroberto
1840285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
1841182007Sroberto
1842182007Sroberto}
1843182007Sroberto
1844285169Scy/*################################################################################################*/
1845285169Scy/*################################################################################################*/
1846285169Scy/*##												##*/
1847285169Scy/*##    The CITIZEN T.I.C CO., LTD. JJY receiver JJY200						##*/
1848285169Scy/*##												##*/
1849285169Scy/*##    server  127.127.40.X  mode 4								##*/
1850285169Scy/*##												##*/
1851285169Scy/*################################################################################################*/
1852285169Scy/*################################################################################################*/
1853285169Scy/*                                                                                                */
1854285169Scy/*  Command               Response                                  Remarks                       */
1855285169Scy/*  --------------------  ----------------------------------------  ----------------------------  */
1856285169Scy/*                        'XX YY/MM/DD W HH:MM:SS<CR>               XX:OK|NG|ER  W:0(Mon)-6(Sun)  */
1857285169Scy/*                                                                                                */
1858285169Scy/*################################################################################################*/
1859285169Scy
1860285169Scystatic int
1861285169Scyjjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
1862285169Scy{
1863285169Scy
1864285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
1865285169Scy
1866285169Scy	up->unittype  = UNITTYPE_CITIZENTIC_JJY200 ;
1867285169Scy	up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
1868285169Scy	up->linediscipline = LDISC_CLK ;
1869285169Scy
1870285169Scy	return 0 ;
1871285169Scy
1872285169Scy}
1873285169Scy
1874182007Sroberto/**************************************************************************************************/
1875200576Sroberto
1876200576Srobertostatic int
1877200576Srobertojjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1878200576Sroberto{
1879200576Sroberto
1880280849Scy	struct jjyunit		*up ;
1881280849Scy	struct refclockproc	*pp ;
1882280849Scy	struct peer		*peer;
1883200576Sroberto
1884285169Scy	char	*pBuf, sLog [ 100 ], sMsg [ 16 ] ;
1885280849Scy	int	iLen ;
1886280849Scy	int	rc ;
1887280849Scy	char	cApostrophe, sStatus[3] ;
1888280849Scy	int	iWeekday ;
1889200576Sroberto
1890285169Scy	/* Initialize pointers */
1891285169Scy
1892280849Scy	peer = rbufp->recv_peer ;
1893280849Scy	pp = peer->procptr ;
1894280849Scy	up = pp->unitptr ;
1895200576Sroberto
1896280849Scy	if ( up->linediscipline == LDISC_RAW ) {
1897285169Scy		pBuf = up->sTextBuf ;
1898285169Scy		iLen = up->iTextBufLen ;
1899280849Scy	} else {
1900280849Scy		pBuf = pp->a_lastcode ;
1901280849Scy		iLen = pp->lencode ;
1902280849Scy	}
1903200576Sroberto
1904285169Scy	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
1905285169Scy
1906280849Scy	/*
1907285169Scy	 * JJY-200 sends a timestamp every second.
1908285169Scy	 * So, a timestamp is ignored unless it is right after polled.
1909285169Scy	 */
1910200576Sroberto
1911285169Scy	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
1912285169Scy		return JJY_RECEIVE_SKIP ;
1913285169Scy	}
1914200576Sroberto
1915285169Scy	/* Check reply length */
1916200576Sroberto
1917285169Scy	if ( iLen != 23 ) {
1918285169Scy		/* Unexpected reply length */
1919285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1920285169Scy			  iLen ) ;
1921285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1922285169Scy		up->bLineError = TRUE ;
1923285169Scy		return JJY_RECEIVE_ERROR ;
1924285169Scy	}
1925200576Sroberto
1926285169Scy	/* 'XX YY/MM/DD W HH:MM:SS<CR> */
1927200576Sroberto
1928285169Scy	rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1929285169Scy		      &cApostrophe, sStatus,
1930285169Scy		      &up->year, &up->month, &up->day, &iWeekday,
1931285169Scy		      &up->hour, &up->minute, &up->second ) ;
1932285169Scy	sStatus[2] = 0 ;
1933280849Scy
1934285169Scy	if ( rc != 9 || cApostrophe != '\''
1935285169Scy	  || ( strcmp( sStatus, "OK" ) != 0
1936285169Scy	    && strcmp( sStatus, "NG" ) != 0
1937285169Scy	    && strcmp( sStatus, "ER" ) != 0 )
1938285169Scy	  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
1939285169Scy	  || iWeekday > 6
1940285169Scy	  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1941285169Scy		/* Invalid date and time */
1942285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1943285169Scy			  rc, up->year, up->month, up->day,
1944285169Scy			  up->hour, up->minute, up->second ) ;
1945285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1946285169Scy		up->bLineError = TRUE ;
1947285169Scy		return JJY_RECEIVE_ERROR ;
1948285169Scy	} else if ( strcmp( sStatus, "NG" ) == 0
1949285169Scy		 || strcmp( sStatus, "ER" ) == 0 ) {
1950285169Scy		/* Timestamp is unsure */
1951285169Scy		snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
1952285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
1953285169Scy			  sMsg ) ;
1954285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
1955285169Scy		return JJY_RECEIVE_SKIP ;
1956285169Scy	}
1957280849Scy
1958285169Scy	up->year += 2000 ;
1959285169Scy	up->msecond = 0 ;
1960280849Scy
1961285169Scy	jjy_synctime( peer, pp, up ) ;
1962280849Scy
1963285169Scy	return JJY_RECEIVE_DONE ;
1964280849Scy
1965285169Scy}
1966280849Scy
1967285169Scy/**************************************************************************************************/
1968285169Scy
1969285169Scystatic void
1970285169Scyjjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1971285169Scy{
1972285169Scy
1973285169Scy	struct refclockproc *pp ;
1974285169Scy	struct jjyunit	    *up ;
1975285169Scy
1976285169Scy	pp = peer->procptr ;
1977285169Scy	up = pp->unitptr ;
1978285169Scy
1979285169Scy	up->bLineError = FALSE ;
1980285169Scy
1981280849Scy}
1982280849Scy
1983285169Scy/*################################################################################################*/
1984285169Scy/*################################################################################################*/
1985285169Scy/*##												##*/
1986285169Scy/*##    The Tristate Ltd. GPS clock TS-GPS01							##*/
1987285169Scy/*##												##*/
1988285169Scy/*##    server  127.127.40.X  mode 5								##*/
1989285169Scy/*##												##*/
1990285169Scy/*################################################################################################*/
1991285169Scy/*################################################################################################*/
1992285169Scy/*                                                                                                */
1993362716Scy/*  This clock has NMEA mode and command/response mode.                                           */
1994362716Scy/*  When this jjy driver are used, set to command/response mode of this clock                     */
1995285169Scy/*  by the onboard switch SW4, and make sure the LED-Y is tured on.                               */
1996285169Scy/*  Other than this JJY driver, the refclock driver type 20, generic NMEA driver,                 */
1997285169Scy/*  works with the NMEA mode of this clock.                                                       */
1998285169Scy/*                                                                                                */
1999285169Scy/*  Command               Response                                  Remarks                       */
2000285169Scy/*  --------------------  ----------------------------------------  ----------------------------  */
2001285169Scy/*  stus<CR><LF>          *R|*G|*U|+U<CR><LF>                                                     */
2002285169Scy/*  date<CR><LF>          YY/MM/DD<CR><LF>                                                        */
2003285169Scy/*  time<CR><LF>          HH:MM:SS<CR><LF>                                                        */
2004285169Scy/*                                                                                                */
2005285169Scy/*################################################################################################*/
2006285169Scy
2007285169Scy#define	TS_GPS01_COMMAND_NUMBER_DATE	1
2008285169Scy#define	TS_GPS01_COMMAND_NUMBER_TIME	2
2009285169Scy#define	TS_GPS01_COMMAND_NUMBER_STUS	4
2010285169Scy
2011285169Scy#define	TS_GPS01_REPLY_DATE		"yyyy/mm/dd"
2012285169Scy#define	TS_GPS01_REPLY_TIME		"hh:mm:ss"
2013285169Scy#define	TS_GPS01_REPLY_STUS_RTC		"*R"
2014285169Scy#define	TS_GPS01_REPLY_STUS_GPS		"*G"
2015285169Scy#define	TS_GPS01_REPLY_STUS_UTC		"*U"
2016285169Scy#define	TS_GPS01_REPLY_STUS_PPS		"+U"
2017285169Scy
2018285169Scy#define	TS_GPS01_REPLY_LENGTH_DATE	    10	/* Length without <CR><LF> */
2019285169Scy#define	TS_GPS01_REPLY_LENGTH_TIME	    8	/* Length without <CR><LF> */
2020285169Scy#define	TS_GPS01_REPLY_LENGTH_STUS	    2	/* Length without <CR><LF> */
2021285169Scy
2022285169Scystatic  struct
2023285169Scy{
2024285169Scy	char	commandNumber ;
2025285169Scy	const char	*command ;
2026285169Scy	int	commandLength ;
2027285169Scy	int	iExpectedReplyLength ;
2028285169Scy} tristate_gps01_command_sequence[] =
2029285169Scy{
2030285169Scy	{ 0, NULL, 0, 0 }, /* Idle */
2031285169Scy	{ TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
2032285169Scy	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
2033285169Scy	{ TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
2034285169Scy	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
2035285169Scy	/* End of command */
2036285169Scy	{ 0, NULL, 0, 0 }
2037285169Scy} ;
2038285169Scy
2039280849Scy/**************************************************************************************************/
2040280849Scy
2041280849Scystatic int
2042285169Scyjjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
2043285169Scy{
2044285169Scy
2045285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
2046285169Scy
2047285169Scy	up->unittype  = UNITTYPE_TRISTATE_GPSCLOCK01 ;
2048285169Scy	up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
2049285169Scy	up->linediscipline = LDISC_CLK ;
2050285169Scy
2051285169Scy	return 0 ;
2052285169Scy
2053285169Scy}
2054285169Scy
2055285169Scy/**************************************************************************************************/
2056285169Scy
2057285169Scystatic int
2058280849Scyjjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
2059280849Scy{
2060200576Sroberto#ifdef DEBUG
2061280849Scy	static	const char	*sFunctionName = "jjy_receive_tristate_gpsclock01" ;
2062200576Sroberto#endif
2063200576Sroberto
2064280849Scy	struct jjyunit	    *up ;
2065280849Scy	struct refclockproc *pp ;
2066280849Scy	struct peer	    *peer;
2067200576Sroberto
2068294554Sdelphij	char *		pBuf ;
2069362716Scy	char		sLog [ MAX_LOGTEXT ] ;
2070294554Sdelphij	int 		iLen ;
2071294554Sdelphij	int 		rc ;
2072200576Sroberto
2073294554Sdelphij	const char *	pCmd ;
2074294554Sdelphij	int 		iCmdLen ;
2075200576Sroberto
2076285169Scy	/* Initialize pointers */
2077285169Scy
2078280849Scy	peer = rbufp->recv_peer ;
2079280849Scy	pp = peer->procptr ;
2080280849Scy	up = pp->unitptr ;
2081200576Sroberto
2082280849Scy	if ( up->linediscipline == LDISC_RAW ) {
2083285169Scy		pBuf = up->sTextBuf ;
2084285169Scy		iLen = up->iTextBufLen ;
2085280849Scy	} else {
2086280849Scy		pBuf = pp->a_lastcode ;
2087280849Scy		iLen = pp->lencode ;
2088280849Scy	}
2089280849Scy
2090285169Scy	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
2091285169Scy
2092285169Scy	/* Ignore NMEA data stream */
2093285169Scy
2094280849Scy	if ( iLen > 5
2095280849Scy	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2096280849Scy#ifdef DEBUG
2097280849Scy		if ( debug ) {
2098280849Scy			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2099280849Scy				sFunctionName, pBuf ) ;
2100280849Scy		}
2101280849Scy#endif
2102285169Scy		return JJY_RECEIVE_WAIT ;
2103280849Scy	}
2104280849Scy
2105280849Scy	/*
2106280849Scy	 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
2107280849Scy	 */
2108280849Scy	if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2109285169Scy		return JJY_RECEIVE_WAIT ;
2110280849Scy	} else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2111280849Scy		pBuf += 5 ;
2112280849Scy		iLen -= 5 ;
2113280849Scy	}
2114280849Scy
2115280849Scy	/*
2116280849Scy	 * Ignore NMEA data stream after command prompt
2117280849Scy	 */
2118280849Scy	if ( iLen > 5
2119280849Scy	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2120280849Scy#ifdef DEBUG
2121280849Scy		if ( debug ) {
2122280849Scy			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2123280849Scy				sFunctionName, pBuf ) ;
2124280849Scy		}
2125280849Scy#endif
2126285169Scy		return JJY_RECEIVE_WAIT ;
2127280849Scy	}
2128280849Scy
2129285169Scy	/* Check expected reply */
2130280849Scy
2131285169Scy	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2132285169Scy		/* Command sequence has not been started, or has been completed */
2133285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2134285169Scy			  pBuf ) ;
2135285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2136285169Scy		up->bLineError = TRUE ;
2137285169Scy		return JJY_RECEIVE_ERROR ;
2138285169Scy	}
2139280849Scy
2140285169Scy	/* Check reply length */
2141280849Scy
2142285169Scy	if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
2143285169Scy		/* Unexpected reply length */
2144285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2145285169Scy			  iLen ) ;
2146285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2147285169Scy		up->bLineError = TRUE ;
2148285169Scy		return JJY_RECEIVE_ERROR ;
2149285169Scy	}
2150285169Scy
2151285169Scy	/* Parse reply */
2152285169Scy
2153285169Scy	switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
2154285169Scy
2155285169Scy	case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
2156285169Scy
2157280849Scy		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
2158285169Scy
2159285169Scy		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
2160285169Scy		  || up->month < 1 || 12 < up->month
2161285169Scy		  || up->day < 1 || 31 < up->day ) {
2162285169Scy			/* Invalid date */
2163285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
2164285169Scy				  rc, up->year, up->month, up->day ) ;
2165285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2166285169Scy			up->bLineError = TRUE ;
2167285169Scy			return JJY_RECEIVE_ERROR ;
2168280849Scy		}
2169280849Scy
2170280849Scy		break ;
2171280849Scy
2172285169Scy	case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
2173280849Scy
2174285169Scy		if ( up->iTimestampCount >= 2 ) {
2175285169Scy			/* Too many time reply */
2176285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
2177285169Scy				  up->iTimestampCount ) ;
2178285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2179285169Scy			up->bLineError = TRUE ;
2180285169Scy			return JJY_RECEIVE_ERROR ;
2181280849Scy		}
2182280849Scy
2183285169Scy		rc = sscanf ( pBuf, "%2d:%2d:%2d",
2184285169Scy			      &up->hour, &up->minute, &up->second ) ;
2185285169Scy
2186285169Scy		if ( rc != 3
2187285169Scy		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2188285169Scy			/* Invalid time */
2189285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2190285169Scy				  rc, up->hour, up->minute, up->second ) ;
2191285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2192285169Scy			up->bLineError = TRUE ;
2193285169Scy			return JJY_RECEIVE_ERROR ;
2194280849Scy		}
2195280849Scy
2196285169Scy		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
2197285169Scy
2198285169Scy		up->iTimestampCount++ ;
2199285169Scy
2200280849Scy		up->msecond = 0 ;
2201280849Scy
2202280849Scy		break ;
2203280849Scy
2204285169Scy	case TS_GPS01_COMMAND_NUMBER_STUS :
2205280849Scy
2206285169Scy		if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2207285169Scy		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2208285169Scy		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2209285169Scy		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
2210280849Scy			/* Good */
2211280849Scy		} else {
2212285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2213285169Scy				  pBuf ) ;
2214285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2215285169Scy			up->bLineError = TRUE ;
2216285169Scy			return JJY_RECEIVE_ERROR ;
2217280849Scy		}
2218280849Scy
2219280849Scy		break ;
2220280849Scy
2221280849Scy	default : /*  Unexpected reply */
2222280849Scy
2223285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2224285169Scy			  pBuf ) ;
2225285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2226285169Scy		up->bLineError = TRUE ;
2227285169Scy		return JJY_RECEIVE_ERROR ;
2228280849Scy
2229280849Scy	}
2230280849Scy
2231285169Scy	if ( up->iTimestampCount == 2 ) {
2232285169Scy		/* Process date and time */
2233280849Scy
2234285169Scy		if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
2235285169Scy		  && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
2236362716Scy			/* 3 commands (time,date,stim) was executed in two seconds */
2237285169Scy			jjy_synctime( peer, pp, up ) ;
2238285169Scy			return JJY_RECEIVE_DONE ;
2239285169Scy		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
2240285169Scy			/* Over midnight, and date is unsure */
2241285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
2242285169Scy				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2243285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
2244285169Scy			return JJY_RECEIVE_SKIP ;
2245285169Scy		} else {
2246285169Scy			/* Slow reply */
2247285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
2248285169Scy				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2249285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2250285169Scy			up->bLineError = TRUE ;
2251285169Scy			return JJY_RECEIVE_ERROR ;
2252285169Scy		}
2253280849Scy
2254285169Scy	}
2255280849Scy
2256285169Scy	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2257285169Scy		/* Command sequence completed */
2258285169Scy		jjy_synctime( peer, pp, up ) ;
2259285169Scy		return JJY_RECEIVE_DONE ;
2260280849Scy	}
2261280849Scy
2262285169Scy	/* Issue next command */
2263285169Scy
2264285169Scy	if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
2265285169Scy		up->iCommandSeq ++ ;
2266280849Scy	}
2267280849Scy
2268285169Scy	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2269280849Scy		/* Command sequence completed */
2270285169Scy		up->iProcessState = JJY_PROCESS_STATE_DONE ;
2271285169Scy		return JJY_RECEIVE_DONE ;
2272280849Scy	}
2273280849Scy
2274285169Scy	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2275285169Scy	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2276285169Scy	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2277285169Scy		refclock_report ( peer, CEVNT_FAULT ) ;
2278285169Scy	}
2279280849Scy
2280285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2281285169Scy
2282285169Scy	return JJY_RECEIVE_WAIT ;
2283285169Scy
2284285169Scy}
2285285169Scy
2286285169Scy/**************************************************************************************************/
2287285169Scy
2288285169Scystatic void
2289285169Scyjjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
2290285169Scy{
2291280849Scy#ifdef DEBUG
2292285169Scy	static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
2293285169Scy#endif
2294285169Scy
2295285169Scy	struct refclockproc *pp ;
2296285169Scy	struct jjyunit	    *up ;
2297285169Scy
2298294554Sdelphij	const char *	pCmd ;
2299294554Sdelphij	int		iCmdLen ;
2300285169Scy
2301285169Scy	pp = peer->procptr ;
2302285169Scy	up = pp->unitptr ;
2303285169Scy
2304285169Scy	up->iTimestampCount = 0 ;
2305285169Scy
2306285169Scy	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
2307285169Scy		/* Skip "stus" command */
2308285169Scy		up->iCommandSeq = 1 ;
2309285169Scy		up->iLineCount = 1 ;
2310285169Scy	}
2311285169Scy
2312285169Scy#ifdef DEBUG
2313280849Scy	if ( debug ) {
2314285169Scy		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
2315285169Scy			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
2316285169Scy			up->iLineCount ) ;
2317280849Scy	}
2318280849Scy#endif
2319280849Scy
2320285169Scy	/*
2321285169Scy	 * Send a first command
2322285169Scy	 */
2323285169Scy
2324285169Scy	up->iCommandSeq ++ ;
2325285169Scy
2326285169Scy	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2327285169Scy	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2328280849Scy	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2329280849Scy		refclock_report ( peer, CEVNT_FAULT ) ;
2330280849Scy	}
2331280849Scy
2332285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2333285169Scy
2334285169Scy}
2335285169Scy
2336285169Scy/*################################################################################################*/
2337285169Scy/*################################################################################################*/
2338285169Scy/*##												##*/
2339285169Scy/*##    The SEIKO TIME SYSTEMS TDC-300								##*/
2340285169Scy/*##												##*/
2341285169Scy/*##    server  127.127.40.X  mode 6								##*/
2342285169Scy/*##												##*/
2343285169Scy/*################################################################################################*/
2344285169Scy/*################################################################################################*/
2345285169Scy/*                                                                                                */
2346285169Scy/*  Type                  Response                                  Remarks                       */
2347285169Scy/*  --------------------  ----------------------------------------  ----------------------------  */
2348285169Scy/*  Type 1                <STX>HH:MM:SS<ETX>                                                      */
2349285169Scy/*  Type 2                <STX>YYMMDDHHMMSSWLSCU<ETX>               W:0(Sun)-6(Sat)               */
2350285169Scy/*  Type 3                <STX>YYMMDDWHHMMSS<ETX>                   W:0(Sun)-6(Sat)               */
2351285169Scy/*                        <STX><xE5><ETX>                           5 to 10 mSec. before second   */
2352285169Scy/*                                                                                                */
2353285169Scy/*################################################################################################*/
2354285169Scy
2355285169Scystatic struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
2356285169Scy{
2357285169Scy	{ "\x03", 1 }, { NULL, 0 }
2358285169Scy} ;
2359285169Scy
2360285169Scy/**************************************************************************************************/
2361285169Scy
2362285169Scystatic int
2363285169Scyjjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
2364285169Scy{
2365285169Scy
2366285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
2367285169Scy
2368285169Scy	up->unittype  = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
2369285169Scy	up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
2370285169Scy	up->linediscipline = LDISC_RAW ;
2371285169Scy
2372285169Scy	up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
2373285169Scy	up->bWaitBreakString = TRUE ;
2374285169Scy
2375285169Scy	up->bSkipCntrlCharOnly = FALSE ;
2376285169Scy
2377280849Scy	return 0 ;
2378280849Scy
2379200576Sroberto}
2380200576Sroberto
2381200576Sroberto/**************************************************************************************************/
2382285169Scy
2383285169Scystatic int
2384285169Scyjjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
2385106163Sroberto{
2386106163Sroberto
2387285169Scy	struct peer		*peer;
2388285169Scy	struct refclockproc	*pp ;
2389285169Scy	struct jjyunit		*up ;
2390106163Sroberto
2391362716Scy	char	*pBuf, sLog [ MAX_LOGTEXT ] ;
2392285169Scy	int	iLen, i ;
2393285169Scy	int	rc, iWeekday ;
2394285169Scy	time_t	now ;
2395285169Scy	struct	tm	*pTime ;
2396285169Scy
2397285169Scy	/* Initialize pointers */
2398285169Scy
2399285169Scy	peer = rbufp->recv_peer ;
2400285169Scy	pp = peer->procptr ;
2401280849Scy	up = pp->unitptr ;
2402106163Sroberto
2403285169Scy	if ( up->linediscipline == LDISC_RAW ) {
2404285169Scy		pBuf = up->sTextBuf ;
2405285169Scy		iLen = up->iTextBufLen ;
2406285169Scy	} else {
2407285169Scy		pBuf = pp->a_lastcode ;
2408285169Scy		iLen = pp->lencode ;
2409106163Sroberto	}
2410106163Sroberto
2411285169Scy	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
2412285169Scy
2413285169Scy	/*
2414285169Scy	 * TDC-300 sends a timestamp every second.
2415285169Scy	 * So, a timestamp is ignored unless it is right after polled.
2416285169Scy	 */
2417285169Scy
2418285169Scy	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
2419285169Scy		return JJY_RECEIVE_SKIP ;
2420106163Sroberto	}
2421106163Sroberto
2422285169Scy	/* Process timestamp */
2423106163Sroberto
2424285169Scy	up->iReceiveSeq ++ ;
2425106163Sroberto
2426285169Scy	switch ( iLen ) {
2427106163Sroberto
2428285169Scy	case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
2429106163Sroberto
2430285169Scy		for ( i = 0 ; i < iLen ; i ++ ) {
2431285169Scy			pBuf[i] &= 0x7F ;
2432285169Scy		}
2433182007Sroberto
2434285169Scy		rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
2435285169Scy		      &up->hour, &up->minute, &up->second ) ;
2436285169Scy
2437285169Scy		if ( rc != 3
2438285169Scy		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2439285169Scy			/* Invalid time */
2440285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2441285169Scy				  rc, up->hour, up->minute, up->second ) ;
2442285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2443285169Scy			up->bLineError = TRUE ;
2444285169Scy			return JJY_RECEIVE_ERROR ;
2445285169Scy		} else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
2446285169Scy			/* Uncertainty date guard */
2447285169Scy			return JJY_RECEIVE_WAIT ;
2448285169Scy		}
2449285169Scy
2450285169Scy		time( &now ) ;
2451285169Scy		pTime = localtime( &now ) ;
2452285169Scy		up->year  = pTime->tm_year ;
2453285169Scy		up->month = pTime->tm_mon + 1 ;
2454285169Scy		up->day   = pTime->tm_mday ;
2455285169Scy
2456280849Scy		break ;
2457200576Sroberto
2458285169Scy	case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
2459285169Scy
2460285169Scy		for ( i = 0 ; i < iLen ; i ++ ) {
2461285169Scy			pBuf[i] &= 0x7F ;
2462285169Scy		}
2463285169Scy
2464285169Scy		rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
2465285169Scy		      &up->year, &up->month, &up->day,
2466285169Scy		      &up->hour, &up->minute, &up->second, &iWeekday ) ;
2467285169Scy
2468285169Scy		if ( rc != 7
2469285169Scy		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2470285169Scy		  || iWeekday > 6
2471285169Scy		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2472285169Scy			/* Invalid date and time */
2473285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2474285169Scy				  rc, up->year, up->month, up->day,
2475285169Scy				  up->hour, up->minute, up->second ) ;
2476285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2477285169Scy			up->bLineError = TRUE ;
2478285169Scy			return JJY_RECEIVE_ERROR ;
2479285169Scy		}
2480285169Scy
2481280849Scy		break ;
2482280849Scy
2483285169Scy	case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
2484285169Scy
2485285169Scy		rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
2486285169Scy		      &up->year, &up->month, &up->day, &iWeekday,
2487285169Scy		      &up->hour, &up->minute, &up->second ) ;
2488285169Scy
2489285169Scy		if ( rc != 7
2490285169Scy		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2491285169Scy		  || iWeekday > 6
2492285169Scy		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2493285169Scy			/* Invalid date and time */
2494285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2495285169Scy				  rc, up->year, up->month, up->day,
2496285169Scy				  up->hour, up->minute, up->second ) ;
2497285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2498285169Scy			up->bLineError = TRUE ;
2499285169Scy			return JJY_RECEIVE_ERROR ;
2500285169Scy		}
2501285169Scy
2502285169Scy		return JJY_RECEIVE_WAIT ;
2503285169Scy
2504285169Scy	case 1 : /* Type 3 : <STX><xE5><ETX> */
2505285169Scy
2506285169Scy		if ( ( *pBuf & 0xFF ) != 0xE5 ) {
2507285169Scy			/* Invalid second signal */
2508285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2509285169Scy				  up->sLineBuf ) ;
2510285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2511285169Scy			up->bLineError = TRUE ;
2512285169Scy			return JJY_RECEIVE_ERROR ;
2513285169Scy		} else if ( up->iReceiveSeq == 1 ) {
2514285169Scy			/* Wait for next timestamp */
2515285169Scy			up->iReceiveSeq -- ;
2516285169Scy			return JJY_RECEIVE_WAIT ;
2517285169Scy		} else if ( up->iReceiveSeq >= 3 ) {
2518285169Scy			/* Unexpected second signal */
2519285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2520285169Scy				  up->sLineBuf ) ;
2521285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2522285169Scy			up->bLineError = TRUE ;
2523285169Scy			return JJY_RECEIVE_ERROR ;
2524285169Scy		}
2525285169Scy
2526106163Sroberto		break ;
2527106163Sroberto
2528285169Scy	default : /* Unexpected reply length */
2529285169Scy
2530285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2531285169Scy			  iLen ) ;
2532285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2533285169Scy		up->bLineError = TRUE ;
2534285169Scy		return JJY_RECEIVE_ERROR ;
2535285169Scy
2536106163Sroberto	}
2537106163Sroberto
2538285169Scy	up->year += 2000 ;
2539285169Scy	up->msecond = 0 ;
2540285169Scy
2541285169Scy	jjy_synctime( peer, pp, up ) ;
2542285169Scy
2543285169Scy	return JJY_RECEIVE_DONE ;
2544285169Scy
2545106163Sroberto}
2546106163Sroberto
2547106163Sroberto/**************************************************************************************************/
2548106163Sroberto
2549106163Srobertostatic void
2550285169Scyjjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
2551106163Sroberto{
2552285169Scy
2553285169Scy	struct refclockproc *pp ;
2554285169Scy	struct jjyunit	    *up ;
2555285169Scy
2556285169Scy	pp = peer->procptr ;
2557285169Scy	up = pp->unitptr ;
2558285169Scy
2559285169Scy	up->bLineError = FALSE ;
2560285169Scy
2561285169Scy}
2562285169Scy
2563285169Scy/*################################################################################################*/
2564285169Scy/*################################################################################################*/
2565285169Scy/*##												##*/
2566285169Scy/*##    Telephone JJY										##*/
2567285169Scy/*##												##*/
2568285169Scy/*##    server  127.127.40.X  mode 100 to 180							##*/
2569285169Scy/*##												##*/
2570285169Scy/*################################################################################################*/
2571285169Scy/*################################################################################################*/
2572285169Scy/*                                                                                                */
2573285169Scy/*  Prompt                Command               Response              Remarks                     */
2574285169Scy/*  --------------------  --------------------  --------------------  --------------------------  */
2575285169Scy/*  Name<SP>?<SP>         TJJY<CR>              Welcome messages      TJJY is a guest user ID     */
2576285169Scy/*  >                     4DATE<CR>             YYYYMMDD<CR>                                      */
2577285169Scy/*  >                     LEAPSEC<CR>           XX<CR>                One of <SP>0, +1, -1        */
2578285169Scy/*  >                     TIME<CR>              HHMMSS<CR>            3 times on second           */
2579285169Scy/*  >                     BYE<CR>               Sayounara messages                                */
2580285169Scy/*                                                                                                */
2581285169Scy/*################################################################################################*/
2582285169Scy
2583285169Scystatic struct jjyRawDataBreak teljjy_raw_break [ ] =
2584285169Scy{
2585285169Scy	{ "\r\n", 2 },
2586285169Scy	{ "\r"  , 1 },
2587285169Scy	{ "\n"  , 1 },
2588285169Scy	{ "Name ? ", 7 },
2589285169Scy	{ ">"   , 1 },
2590285169Scy	{ "+++" , 3 },
2591285169Scy	{ NULL  , 0 }
2592285169Scy} ;
2593285169Scy
2594285169Scy#define	TELJJY_STATE_IDLE	0
2595285169Scy#define	TELJJY_STATE_DAILOUT	1
2596285169Scy#define	TELJJY_STATE_LOGIN	2
2597285169Scy#define	TELJJY_STATE_CONNECT	3
2598285169Scy#define	TELJJY_STATE_BYE	4
2599285169Scy
2600285169Scy#define	TELJJY_EVENT_NULL	0
2601285169Scy#define	TELJJY_EVENT_START	1
2602285169Scy#define	TELJJY_EVENT_CONNECT	2
2603285169Scy#define	TELJJY_EVENT_DISCONNECT	3
2604285169Scy#define	TELJJY_EVENT_COMMAND	4
2605285169Scy#define	TELJJY_EVENT_LOGIN	5	/* Posted by the jjy_receive_telephone */
2606285169Scy#define	TELJJY_EVENT_PROMPT	6	/* Posted by the jjy_receive_telephone */
2607285169Scy#define	TELJJY_EVENT_DATA	7	/* Posted by the jjy_receive_telephone */
2608285169Scy#define	TELJJY_EVENT_ERROR	8	/* Posted by the jjy_receive_telephone */
2609285169Scy#define	TELJJY_EVENT_SILENT	9	/* Posted by the jjy_timer_telephone */
2610285169Scy#define	TELJJY_EVENT_TIMEOUT	10	/* Posted by the jjy_timer_telephone */
2611285169Scy
2612285169Scystatic	void 	teljjy_control		( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2613285169Scy
2614285169Scystatic	int 	teljjy_idle_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2615285169Scystatic	int 	teljjy_idle_dialout	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2616285169Scystatic	int 	teljjy_dial_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2617285169Scystatic	int 	teljjy_dial_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2618285169Scystatic	int 	teljjy_dial_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2619285169Scystatic	int 	teljjy_login_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2620285169Scystatic	int 	teljjy_login_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2621285169Scystatic	int 	teljjy_login_conn	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2622285169Scystatic	int 	teljjy_login_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2623285169Scystatic	int 	teljjy_login_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2624285169Scystatic	int 	teljjy_login_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2625285169Scystatic	int 	teljjy_conn_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2626285169Scystatic	int 	teljjy_conn_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2627285169Scystatic	int 	teljjy_conn_send	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2628285169Scystatic	int 	teljjy_conn_data	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2629285169Scystatic	int 	teljjy_conn_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2630285169Scystatic	int 	teljjy_conn_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2631285169Scystatic	int 	teljjy_bye_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2632285169Scystatic	int 	teljjy_bye_disc 	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2633285169Scystatic	int 	teljjy_bye_modem	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2634285169Scy
2635294554Sdelphijstatic int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) =
2636285169Scy{               	/*STATE_IDLE           STATE_DAILOUT       STATE_LOGIN           STATE_CONNECT       STATE_BYE        */
2637285169Scy/* NULL       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2638285169Scy/* START      */	{ teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2639285169Scy/* CONNECT    */	{ teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2640285169Scy/* DISCONNECT */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_disc  , teljjy_conn_disc  , teljjy_bye_disc   },
2641285169Scy/* COMMAND    */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem  },
2642285169Scy/* LOGIN      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
2643285169Scy/* PROMPT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn  , teljjy_conn_send  , teljjy_bye_ignore },
2644285169Scy/* DATA       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data  , teljjy_bye_ignore },
2645285169Scy/* ERROR      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
2646285169Scy/* SILENT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
2647285169Scy/* TIMEOUT    */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem  }
2648285169Scy} ;
2649285169Scy
2650285169Scystatic short iTeljjyNextState [ ] [ 5 ] =
2651285169Scy{               	/*STATE_IDLE            STATE_DAILOUT         STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2652285169Scy/* NULL       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2653285169Scy/* START      */	{ TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2654285169Scy/* CONNECT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_LOGIN  , TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2655285169Scy/* DISCONNECT */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE },
2656285169Scy/* COMMAND    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2657285169Scy/* LOGIN      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2658285169Scy/* PROMPT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2659285169Scy/* DATA       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2660285169Scy/* ERROR      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2661285169Scy/* SILENT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2662285169Scy/* TIMEOUT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  }
2663285169Scy} ;
2664285169Scy
2665285169Scystatic short iTeljjyPostEvent [ ] [ 5 ] =
2666285169Scy{               	/*STATE_IDLE         STATE_DAILOUT      STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2667285169Scy/* NULL       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2668285169Scy/* START      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2669285169Scy/* CONNECT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2670285169Scy/* DISCONNECT */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2671285169Scy/* COMMAND    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2672285169Scy/* LOGIN      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2673285169Scy/* PROMPT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2674285169Scy/* DATA       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2675285169Scy/* ERROR      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2676285169Scy/* SILENT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2677285169Scy/* TIMEOUT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
2678285169Scy} ;
2679285169Scy
2680285169Scystatic short iTeljjySilentTimeout [ 5 ] = { 0,   0, 10,  5,  0 } ;
2681285169Scystatic short iTeljjyStateTimeout  [ 5 ] = { 0, 120, 60, 60, 40 } ;
2682285169Scy
2683285169Scy#define	TELJJY_STAY_CLOCK_STATE  	0
2684285169Scy#define	TELJJY_CHANGE_CLOCK_STATE	1
2685285169Scy
2686285169Scy/* Command and replay */
2687285169Scy
2688285169Scy#define	TELJJY_REPLY_NONE	0
2689285169Scy#define	TELJJY_REPLY_4DATE	1
2690285169Scy#define	TELJJY_REPLY_TIME	2
2691285169Scy#define	TELJJY_REPLY_LEAPSEC	3
2692285169Scy#define	TELJJY_REPLY_LOOP	4
2693285169Scy#define	TELJJY_REPLY_PROMPT	5
2694285169Scy#define	TELJJY_REPLY_LOOPBACK	6
2695285169Scy#define	TELJJY_REPLY_COM	7
2696285169Scy
2697285169Scy#define	TELJJY_COMMAND_START_SKIP_LOOPBACK	7
2698285169Scy
2699285169Scystatic  struct
2700285169Scy{
2701285169Scy	const char	*command ;
2702285169Scy	int	commandLength ;
2703285169Scy	int	iEchobackReplyLength ;
2704285169Scy	int	iExpectedReplyType   ;
2705285169Scy	int	iExpectedReplyLength ;
2706285169Scy} teljjy_command_sequence[] =
2707285169Scy{
2708285169Scy	{ NULL, 0, 0, 0, 0 }, /* Idle */
2709285169Scy	{ "LOOP\r"   , 5, 4, TELJJY_REPLY_LOOP    , 0 }, /* Getting into loopback mode */
2710285169Scy	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2711285169Scy	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2712285169Scy	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2713285169Scy	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2714285169Scy	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2715285169Scy	{ "COM\r"    , 4, 3, TELJJY_REPLY_COM     , 0 }, /* Exit from loopback mode */
2716285169Scy	/* TELJJY_COMMAND_START_SKIP_LOOPBACK */
2717285169Scy	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2718285169Scy	{ "4DATE\r"  , 6, 5, TELJJY_REPLY_4DATE   , 8 },
2719285169Scy	{ "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
2720285169Scy	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2721285169Scy	{ "BYE\r"    , 4, 3, TELJJY_REPLY_NONE    , 0 },
2722285169Scy	/* End of command */
2723285169Scy	{ NULL, 0, 0, 0, 0 }
2724285169Scy} ;
2725285169Scy
2726285169Scy#define	TELJJY_LOOPBACK_DELAY_THRESHOLD		700 /* Milli second */
2727285169Scy
2728285169Scy#ifdef	DEBUG
2729285169Scy#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 ) ; } }
2730285169Scy#else
2731285169Scy#define	DEBUG_TELJJY_PRINTF(sFunc)
2732285169Scy#endif
2733285169Scy
2734285169Scy/**************************************************************************************************/
2735285169Scy
2736285169Scystatic int
2737285169Scyjjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
2738285169Scy{
2739285169Scy
2740285169Scy	char	sLog [ 80 ], sFirstThreeDigits [ 4 ] ;
2741316068Sdelphij	int	iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
2742316068Sdelphij	size_t  i ;
2743316068Sdelphij	size_t	iFirstThreeDigitsCount ;
2744285169Scy
2745285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
2746285169Scy
2747285169Scy	up->unittype  = UNITTYPE_TELEPHONE ;
2748285169Scy	up->linespeed = SPEED232_TELEPHONE ;
2749285169Scy	up->linediscipline = LDISC_RAW ;
2750285169Scy
2751285169Scy	up->pRawBreak = teljjy_raw_break ;
2752285169Scy	up->bWaitBreakString = TRUE ;
2753285169Scy
2754285169Scy	up->bSkipCntrlCharOnly = TRUE ;
2755285169Scy
2756285169Scy	up->iClockState = TELJJY_STATE_IDLE ;
2757285169Scy	up->iClockEvent = TELJJY_EVENT_NULL ;
2758285169Scy
2759285169Scy	/* Check the telephone number */
2760285169Scy
2761285169Scy	if ( sys_phone[0] == NULL ) {
2762285169Scy		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
2763285169Scy		up->bInitError = TRUE ;
2764285169Scy		return 1 ;
2765285169Scy	}
2766285169Scy
2767285169Scy	if ( sys_phone[1] != NULL ) {
2768285169Scy		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
2769285169Scy		up->bInitError = TRUE ;
2770285169Scy		return 1 ;
2771285169Scy	}
2772285169Scy
2773285169Scy	iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
2774285169Scy	for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
2775294554Sdelphij		if ( isdigit( (u_char)sys_phone[0][i] ) ) {
2776285169Scy			if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
2777294554Sdelphij				sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ;
2778285169Scy			}
2779285169Scy			iNumberOfDigitsOfPhoneNumber ++ ;
2780294554Sdelphij		} else if ( sys_phone[0][i] == ',' ) {
2781285169Scy			iCommaCount ++ ;
2782285169Scy			if ( iCommaCount > 1 ) {
2783285169Scy				msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
2784285169Scy				up->bInitError = TRUE ;
2785285169Scy				return 1 ;
2786285169Scy			}
2787285169Scy			iFirstThreeDigitsCount = 0 ;
2788285169Scy			iCommaPosition = i ;
2789294554Sdelphij		} else if ( sys_phone[0][i] != '-' ) {
2790285169Scy			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
2791285169Scy			up->bInitError = TRUE ;
2792285169Scy			return 1 ;
2793285169Scy		}
2794285169Scy	}
2795285169Scy	sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
2796285169Scy
2797285169Scy	if ( iCommaCount == 1 ) {
2798285169Scy		if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
2799285169Scy			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
2800285169Scy			up->bInitError = TRUE ;
2801285169Scy			return 1 ;
2802285169Scy		}
2803285169Scy	}
2804285169Scy
2805285169Scy	if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
2806285169Scy		/* Too short or too long */
2807285169Scy		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
2808285169Scy		up->bInitError = TRUE ;
2809285169Scy		return 1 ;
2810285169Scy	}
2811285169Scy
2812285169Scy	if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
2813285169Scy	  || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
2814285169Scy	  || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
2815285169Scy	  || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
2816285169Scy	  || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
2817285169Scy	  || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
2818285169Scy	  || ( sFirstThreeDigits[0] == '0' &&  sFirstThreeDigits[2] == '0' ) ) {
2819285169Scy		/* Not allowed because of emergency numbers or special service numbers */
2820285169Scy		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
2821285169Scy		up->bInitError = TRUE ;
2822285169Scy		return 1 ;
2823285169Scy	}
2824285169Scy
2825285169Scy	snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
2826285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2827285169Scy
2828285169Scy	if ( peer->minpoll < 8 ) {
2829285169Scy		/* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
2830285169Scy		int oldminpoll = peer->minpoll ;
2831285169Scy		peer->minpoll = 8 ;
2832285169Scy		if ( peer->ppoll < peer->minpoll ) {
2833285169Scy			peer->ppoll = peer->minpoll ;
2834285169Scy		}
2835285169Scy		if ( peer->maxpoll < peer->minpoll ) {
2836285169Scy			peer->maxpoll = peer->minpoll ;
2837285169Scy		}
2838285169Scy		snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
2839285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2840285169Scy	}
2841285169Scy
2842285169Scy	return 0 ;
2843285169Scy
2844285169Scy}
2845285169Scy
2846285169Scy/**************************************************************************************************/
2847285169Scy
2848285169Scystatic int
2849285169Scyjjy_receive_telephone ( struct recvbuf *rbufp )
2850285169Scy{
2851280849Scy#ifdef DEBUG
2852285169Scy	static	const char	*sFunctionName = "jjy_receive_telephone" ;
2853280849Scy#endif
2854106163Sroberto
2855285169Scy	struct	peer         *peer;
2856285169Scy	struct	refclockproc *pp ;
2857285169Scy	struct	jjyunit      *up ;
2858285169Scy	char	*pBuf ;
2859285169Scy	int	iLen ;
2860285169Scy	short	iPreviousModemState ;
2861106163Sroberto
2862285169Scy	peer = rbufp->recv_peer ;
2863285169Scy	pp = peer->procptr ;
2864285169Scy	up = pp->unitptr ;
2865280849Scy
2866285169Scy	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2867285169Scy
2868285169Scy	if ( up->iClockState == TELJJY_STATE_IDLE
2869285169Scy	  || up->iClockState == TELJJY_STATE_DAILOUT
2870285169Scy	  || up->iClockState == TELJJY_STATE_BYE ) {
2871285169Scy
2872285169Scy		iPreviousModemState = getModemState( up ) ;
2873285169Scy
2874285169Scy		modem_receive ( rbufp ) ;
2875285169Scy
2876285169Scy		if ( iPreviousModemState != up->iModemState ) {
2877285169Scy			/* Modem state is changed just now. */
2878285169Scy			if ( isModemStateDisconnect( up->iModemState ) ) {
2879285169Scy				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2880285169Scy				teljjy_control ( peer, pp, up ) ;
2881285169Scy			} else if ( isModemStateConnect( up->iModemState ) ) {
2882285169Scy				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2883285169Scy				teljjy_control ( peer, pp, up ) ;
2884285169Scy			}
2885285169Scy		}
2886285169Scy
2887285169Scy		return JJY_RECEIVE_WAIT ;
2888285169Scy
2889285169Scy	}
2890285169Scy
2891285169Scy	if ( up->linediscipline == LDISC_RAW ) {
2892285169Scy		pBuf = up->sTextBuf ;
2893285169Scy		iLen = up->iTextBufLen ;
2894285169Scy	} else {
2895285169Scy		pBuf = pp->a_lastcode ;
2896285169Scy		iLen = pp->lencode ;
2897285169Scy	}
2898285169Scy
2899285169Scy	up->iTeljjySilentTimer = 0 ;
2900285169Scy	if      ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN  ; }
2901285169Scy	else if ( iLen == 1 && strncmp( pBuf, ">"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
2902285169Scy	else if ( iLen >= 1 && strncmp( pBuf, "?"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR  ; }
2903285169Scy	else                                                        { up->iClockEvent = TELJJY_EVENT_DATA   ; }
2904285169Scy
2905285169Scy	teljjy_control ( peer, pp, up ) ;
2906285169Scy
2907285169Scy	return JJY_RECEIVE_WAIT ;
2908285169Scy
2909285169Scy}
2910285169Scy
2911285169Scy/**************************************************************************************************/
2912285169Scy
2913285169Scystatic void
2914285169Scyjjy_poll_telephone ( int unit, struct peer *peer )
2915285169Scy{
2916285169Scy#ifdef DEBUG
2917285169Scy	static const char *sFunctionName = "jjy_poll_telephone" ;
2918285169Scy#endif
2919285169Scy
2920285169Scy	struct	refclockproc *pp ;
2921285169Scy	struct	jjyunit      *up ;
2922285169Scy
2923285169Scy	pp = peer->procptr ;
2924280849Scy	up = pp->unitptr ;
2925106163Sroberto
2926285169Scy	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2927285169Scy
2928285169Scy	if ( up->iClockState == TELJJY_STATE_IDLE ) {
2929285169Scy		up->iRawBufLen = 0 ;
2930285169Scy		up->iLineBufLen = 0 ;
2931285169Scy		up->iTextBufLen = 0 ;
2932280849Scy	}
2933280849Scy
2934285169Scy	up->iClockEvent = TELJJY_EVENT_START ;
2935285169Scy	teljjy_control ( peer, pp, up ) ;
2936285169Scy
2937285169Scy}
2938285169Scy
2939285169Scy/**************************************************************************************************/
2940285169Scy
2941285169Scystatic void
2942285169Scyjjy_timer_telephone ( int unit, struct peer *peer )
2943285169Scy{
2944280849Scy#ifdef DEBUG
2945285169Scy	static const char *sFunctionName = "jjy_timer_telephone" ;
2946280849Scy#endif
2947280849Scy
2948285169Scy	struct	refclockproc *pp ;
2949285169Scy	struct	jjyunit      *up ;
2950285169Scy	short	iPreviousModemState ;
2951106163Sroberto
2952285169Scy	pp = peer->procptr ;
2953285169Scy	up = pp->unitptr ;
2954285169Scy
2955285169Scy	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2956285169Scy
2957285169Scy	if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
2958285169Scy		up->iTeljjySilentTimer++ ;
2959285169Scy		if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
2960285169Scy			up->iClockEvent = TELJJY_EVENT_SILENT ;
2961285169Scy			teljjy_control ( peer, pp, up ) ;
2962285169Scy		}
2963285169Scy	}
2964285169Scy
2965285169Scy	if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
2966285169Scy		up->iTeljjyStateTimer++ ;
2967285169Scy		if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
2968285169Scy			up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
2969285169Scy			teljjy_control ( peer, pp, up ) ;
2970285169Scy		}
2971285169Scy	}
2972285169Scy
2973285169Scy	if ( isModemStateTimerOn( up ) ) {
2974285169Scy
2975285169Scy		iPreviousModemState = getModemState( up ) ;
2976285169Scy
2977285169Scy		modem_timer ( unit, peer ) ;
2978285169Scy
2979285169Scy		if ( iPreviousModemState != up->iModemState ) {
2980285169Scy			/* Modem state is changed just now. */
2981285169Scy			if ( isModemStateDisconnect( up->iModemState ) ) {
2982285169Scy				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2983285169Scy				teljjy_control ( peer, pp, up ) ;
2984285169Scy			} else if ( isModemStateConnect( up->iModemState ) ) {
2985285169Scy				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2986285169Scy				teljjy_control ( peer, pp, up ) ;
2987285169Scy			}
2988285169Scy		}
2989285169Scy
2990285169Scy	}
2991285169Scy
2992285169Scy}
2993285169Scy
2994285169Scy/**************************************************************************************************/
2995285169Scy
2996285169Scystatic void
2997285169Scyteljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
2998285169Scy{
2999285169Scy
3000285169Scy	int	i, rc ;
3001285169Scy	short	iPostEvent = TELJJY_EVENT_NULL ;
3002285169Scy
3003285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
3004285169Scy
3005285169Scy	rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
3006285169Scy
3007285169Scy	if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
3008285169Scy		iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
3009182007Sroberto#ifdef DEBUG
3010285169Scy		if ( debug ) {
3011285169Scy			printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd  iPostEvent=%hd\n",
3012285169Scy				up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
3013285169Scy		}
3014182007Sroberto#endif
3015285169Scy		up->iTeljjySilentTimer = 0 ;
3016285169Scy		if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
3017285169Scy			/* Telephone JJY state is changing now */
3018285169Scy			up->iTeljjyStateTimer = 0 ;
3019285169Scy			up->bLineError = FALSE ;
3020285169Scy			up->iClockCommandSeq = 0 ;
3021285169Scy			up->iTimestampCount = 0 ;
3022285169Scy			up->iLoopbackCount = 0 ;
3023285169Scy			for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3024285169Scy				up->bLoopbackTimeout[i] = FALSE ;
3025285169Scy			}
3026285169Scy			if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
3027285169Scy				/* Telephone JJY state is changing to IDLE just now */
3028285169Scy				up->iProcessState = JJY_PROCESS_STATE_DONE ;
3029285169Scy			}
3030285169Scy		}
3031285169Scy		up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
3032182007Sroberto
3033106163Sroberto	}
3034106163Sroberto
3035285169Scy	if ( iPostEvent != TELJJY_EVENT_NULL ) {
3036285169Scy		up->iClockEvent = iPostEvent ;
3037285169Scy		teljjy_control ( peer, pp, up ) ;
3038285169Scy	}
3039285169Scy
3040285169Scy	up->iClockEvent = TELJJY_EVENT_NULL ;
3041285169Scy
3042182007Sroberto}
3043182007Sroberto
3044182007Sroberto/**************************************************************************************************/
3045182007Sroberto
3046182007Srobertostatic void
3047285169Scyteljjy_setDelay ( struct peer *peer, struct jjyunit *up )
3048182007Sroberto{
3049182007Sroberto
3050285169Scy	char	sLog [ 60 ] ;
3051285169Scy	int	milliSecond, microSecond ;
3052182007Sroberto
3053285169Scy	gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
3054182007Sroberto
3055285169Scy	up->delayTime[up->iLoopbackCount].tv_sec  -= up->sendTime[up->iLoopbackCount].tv_sec ;
3056285169Scy	up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
3057285169Scy	if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
3058285169Scy		up->delayTime[up->iLoopbackCount].tv_sec -- ;
3059285169Scy		up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
3060285169Scy	}
3061106163Sroberto
3062285169Scy	milliSecond  = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
3063285169Scy	microSecond  = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
3064285169Scy	milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
3065285169Scy
3066285169Scy	snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
3067285169Scy		  milliSecond, microSecond ) ;
3068285169Scy
3069285169Scy	if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
3070285169Scy		/* Delay > 700 mS */
3071285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3072285169Scy	} else {
3073285169Scy		/* Delay <= 700 mS */
3074285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3075285169Scy	}
3076285169Scy
3077285169Scy}
3078285169Scy
3079285169Scy/**************************************************************************************************/
3080285169Scy
3081285169Scystatic int
3082285169Scyteljjy_getDelay ( struct peer *peer, struct jjyunit *up )
3083285169Scy{
3084285169Scy
3085285169Scy	struct	timeval maxTime, minTime, averTime ;
3086285169Scy	int	i ;
3087285169Scy	int	minIndex = 0, maxIndex = 0, iAverCount = 0 ;
3088285169Scy	int	iThresholdSecond, iThresholdMicroSecond ;
3089285169Scy	int	iPercent ;
3090285169Scy
3091285169Scy	minTime.tv_sec = minTime.tv_usec = 0 ;
3092285169Scy	maxTime.tv_sec = maxTime.tv_usec = 0 ;
3093285169Scy
3094285169Scy	iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
3095285169Scy	iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
3096285169Scy
3097285169Scy	up->iLoopbackValidCount = 0 ;
3098285169Scy
3099285169Scy	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3100285169Scy		if ( up->bLoopbackTimeout[i]
3101285169Scy		  || up->delayTime[i].tv_sec  > iThresholdSecond
3102285169Scy		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3103285169Scy		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3104285169Scy			continue ;
3105285169Scy		}
3106285169Scy		if ( up->iLoopbackValidCount == 0 ) {
3107285169Scy			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3108285169Scy			minTime.tv_usec = up->delayTime[i].tv_usec ;
3109285169Scy			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3110285169Scy			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3111285169Scy			minIndex = maxIndex = i ;
3112285169Scy		} else if ( minTime.tv_sec  > up->delayTime[i].tv_sec
3113285169Scy		       || ( minTime.tv_sec == up->delayTime[i].tv_sec
3114285169Scy		         && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
3115285169Scy			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3116285169Scy			minTime.tv_usec = up->delayTime[i].tv_usec ;
3117285169Scy			minIndex = i ;
3118285169Scy		} else if ( maxTime.tv_sec  < up->delayTime[i].tv_sec
3119285169Scy		       || ( maxTime.tv_sec == up->delayTime[i].tv_sec
3120285169Scy		         && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
3121285169Scy			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3122285169Scy			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3123285169Scy			maxIndex = i ;
3124285169Scy		}
3125285169Scy		up->iLoopbackValidCount ++ ;
3126285169Scy	}
3127285169Scy
3128285169Scy	if ( up->iLoopbackValidCount < 2 ) {
3129285169Scy		return -1 ;
3130285169Scy	}
3131285169Scy
3132285169Scy	averTime.tv_usec = 0;
3133285169Scy
3134285169Scy	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3135285169Scy		if ( up->bLoopbackTimeout[i]
3136285169Scy		  || up->delayTime[i].tv_sec  > iThresholdSecond
3137285169Scy		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3138285169Scy		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3139285169Scy			continue ;
3140285169Scy		}
3141285169Scy		if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
3142285169Scy			continue ;
3143285169Scy		}
3144285169Scy		if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
3145285169Scy			continue ;
3146285169Scy		}
3147285169Scy		averTime.tv_usec += up->delayTime[i].tv_usec ;
3148285169Scy		iAverCount ++ ;
3149285169Scy	}
3150285169Scy
3151285169Scy	if ( iAverCount == 0 ) {
3152285169Scy		/* This is never happened. */
3153285169Scy		/* Previous for-if-for blocks assure iAverCount > 0. */
3154285169Scy		/* This code avoids a claim by the coverity scan tool. */
3155285169Scy		return -1 ;
3156285169Scy	}
3157285169Scy
3158285169Scy	/* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
3159285169Scy
3160285169Scy	iPercent = ( peer->ttl - 100 ) ;
3161285169Scy
3162285169Scy	/* Average delay time in milli second */
3163285169Scy
3164285169Scy	return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
3165285169Scy
3166285169Scy}
3167285169Scy
3168285169Scy/******************************/
3169285169Scystatic int
3170285169Scyteljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3171285169Scy{
3172285169Scy
3173285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
3174285169Scy
3175285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3176285169Scy
3177285169Scy}
3178285169Scy
3179285169Scy/******************************/
3180285169Scystatic int
3181285169Scyteljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3182285169Scy{
3183285169Scy
3184285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
3185285169Scy
3186285169Scy	modem_connect ( peer->refclkunit, peer ) ;
3187285169Scy
3188285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3189285169Scy
3190285169Scy}
3191285169Scy
3192285169Scy/******************************/
3193285169Scystatic int
3194285169Scyteljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3195285169Scy{
3196285169Scy
3197285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
3198285169Scy
3199285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3200285169Scy
3201285169Scy}
3202285169Scy
3203285169Scy/******************************/
3204285169Scystatic int
3205285169Scyteljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3206285169Scy{
3207285169Scy
3208285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
3209285169Scy
3210285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3211285169Scy
3212285169Scy}
3213285169Scy
3214285169Scy/******************************/
3215285169Scystatic int
3216285169Scyteljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3217285169Scy{
3218285169Scy
3219285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
3220285169Scy
3221285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3222285169Scy
3223285169Scy}
3224285169Scy
3225285169Scy/******************************/
3226285169Scystatic int
3227285169Scyteljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3228285169Scy{
3229285169Scy
3230285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
3231285169Scy
3232285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3233285169Scy
3234285169Scy}
3235285169Scy
3236285169Scy/******************************/
3237285169Scystatic int
3238285169Scyteljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3239285169Scy{
3240285169Scy
3241285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
3242285169Scy
3243285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3244285169Scy
3245285169Scy}
3246285169Scy
3247285169Scy/******************************/
3248285169Scystatic int
3249285169Scyteljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3250285169Scy{
3251285169Scy
3252285169Scy	int	i ;
3253285169Scy
3254285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
3255285169Scy
3256285169Scy	up->bLineError = FALSE ;
3257285169Scy	up->iClockCommandSeq = 0 ;
3258285169Scy	up->iTimestampCount = 0 ;
3259285169Scy	up->iLoopbackCount = 0 ;
3260285169Scy	for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3261285169Scy		up->bLoopbackTimeout[i] = FALSE ;
3262285169Scy	}
3263285169Scy
3264285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3265285169Scy
3266285169Scy}
3267285169Scy
3268285169Scy/******************************/
3269285169Scystatic int
3270285169Scyteljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3271285169Scy{
3272285169Scy
3273294554Sdelphij	const char *	pCmd ;
3274294554Sdelphij	int		iCmdLen ;
3275285169Scy
3276285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
3277285169Scy
3278285169Scy	/* Send a guest user ID */
3279285169Scy	pCmd = "TJJY\r" ;
3280285169Scy
3281285169Scy	/* Send login ID */
3282285169Scy	iCmdLen = strlen( pCmd ) ;
3283285169Scy	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
3284285169Scy		refclock_report( peer, CEVNT_FAULT ) ;
3285285169Scy	}
3286285169Scy
3287285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3288285169Scy
3289285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3290285169Scy
3291285169Scy}
3292285169Scy
3293285169Scy/******************************/
3294285169Scystatic int
3295285169Scyteljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3296285169Scy{
3297285169Scy
3298285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
3299285169Scy
3300285169Scy	if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
3301285169Scy		refclock_report( peer, CEVNT_FAULT ) ;
3302285169Scy	}
3303285169Scy
3304285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
3305285169Scy
3306285169Scy	up->iTeljjySilentTimer = 0 ;
3307285169Scy
3308285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3309285169Scy
3310285169Scy}
3311285169Scy
3312285169Scy/******************************/
3313285169Scystatic int
3314285169Scyteljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3315285169Scy{
3316285169Scy
3317285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
3318285169Scy
3319285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3320285169Scy
3321285169Scy}
3322285169Scy
3323285169Scy/******************************/
3324285169Scystatic int
3325285169Scyteljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3326285169Scy{
3327285169Scy
3328285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
3329285169Scy
3330285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3331285169Scy
3332285169Scy}
3333285169Scy
3334285169Scy/******************************/
3335285169Scystatic int
3336285169Scyteljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3337285169Scy{
3338285169Scy
3339285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
3340285169Scy
3341285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3342285169Scy
3343285169Scy}
3344285169Scy
3345285169Scy/******************************/
3346285169Scystatic int
3347285169Scyteljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3348285169Scy{
3349285169Scy
3350294554Sdelphij	const char *	pCmd ;
3351294554Sdelphij	int		i, iLen, iNextClockState ;
3352330106Sdelphij	char	sLog [ 120 ] ;
3353285169Scy
3354285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
3355285169Scy
3356285169Scy	if ( up->iClockCommandSeq > 0
3357285169Scy	  && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
3358285169Scy		/* Command sequence has been completed */
3359285169Scy	  	return TELJJY_CHANGE_CLOCK_STATE ;
3360285169Scy	}
3361285169Scy
3362285169Scy	if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
3363285169Scy		/* Skip loopback */
3364285169Scy
3365285169Scy		up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
3366285169Scy
3367285169Scy	} else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
3368285169Scy		/* Loopback start */
3369285169Scy
3370285169Scy		up->iLoopbackCount = 0 ;
3371285169Scy		for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3372285169Scy			up->bLoopbackTimeout[i] = FALSE ;
3373285169Scy		}
3374285169Scy
3375285169Scy	} else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
3376285169Scy		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3377285169Scy		 && up->iLoopbackCount < MAX_LOOPBACK ) {
3378285169Scy		/* Loopback character comes */
3379182007Sroberto#ifdef DEBUG
3380285169Scy		if ( debug ) {
3381330106Sdelphij			printf( "refclock_jjy.c : teljjy_conn_send : iClockCommandSeq=%d iLoopbackCount=%d\n",
3382330106Sdelphij				 up->iClockCommandSeq, up->iLoopbackCount ) ;
3383285169Scy		}
3384285169Scy#endif
3385285169Scy
3386285169Scy		teljjy_setDelay( peer, up ) ;
3387285169Scy
3388285169Scy		up->iLoopbackCount ++ ;
3389285169Scy
3390106163Sroberto	}
3391285169Scy
3392285169Scy	up->iClockCommandSeq++ ;
3393285169Scy
3394285169Scy	pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
3395285169Scy	iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
3396285169Scy
3397285169Scy	if ( pCmd != NULL ) {
3398285169Scy
3399285169Scy		if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
3400285169Scy			refclock_report( peer, CEVNT_FAULT ) ;
3401285169Scy		}
3402285169Scy
3403285169Scy		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3404285169Scy			/* Loopback character and timestamp */
3405330106Sdelphij			if ( up->iLoopbackCount < MAX_LOOPBACK ) {
3406330106Sdelphij				gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
3407330106Sdelphij				up->bLoopbackMode = TRUE ;
3408330106Sdelphij			} else {
3409330106Sdelphij				/* This else-block is never come. */
3410330106Sdelphij				/* This code avoid wrong report of the coverity static analysis scan tool. */
3411330106Sdelphij				snprintf( sLog, sizeof(sLog)-1, "refclock_jjy.c ; teljjy_conn_send ; iClockCommandSeq=%d iLoopbackCount=%d MAX_LOOPBACK=%d",
3412330106Sdelphij					  up->iClockCommandSeq, up->iLoopbackCount, MAX_LOOPBACK ) ;
3413330106Sdelphij				jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_BUG, sLog ) ;
3414330106Sdelphij				msyslog ( LOG_ERR, "%s", sLog ) ;
3415330106Sdelphij				up->bLoopbackMode = FALSE ;
3416330106Sdelphij			}
3417285169Scy		} else {
3418285169Scy			/* Regular command */
3419285169Scy			up->bLoopbackMode = FALSE ;
3420285169Scy		}
3421285169Scy
3422285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3423285169Scy
3424285169Scy		if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
3425285169Scy			/* Last command of the command sequence */
3426285169Scy			iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3427285169Scy		} else {
3428285169Scy			/* More commands to be issued */
3429285169Scy			iNextClockState = TELJJY_STAY_CLOCK_STATE ;
3430285169Scy		}
3431285169Scy
3432285169Scy	} else {
3433285169Scy
3434285169Scy		iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3435285169Scy
3436285169Scy	}
3437285169Scy
3438285169Scy	return iNextClockState ;
3439285169Scy
3440285169Scy}
3441285169Scy
3442285169Scy/******************************/
3443285169Scystatic int
3444285169Scyteljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3445285169Scy{
3446285169Scy
3447285169Scy	char	*pBuf ;
3448285169Scy	int	iLen, rc ;
3449362716Scy	char	sLog [ MAX_LOGTEXT ] ;
3450285169Scy	char	bAdjustment ;
3451285169Scy
3452285169Scy
3453285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
3454285169Scy
3455285169Scy	if ( up->linediscipline == LDISC_RAW ) {
3456285169Scy		pBuf = up->sTextBuf ;
3457285169Scy		iLen = up->iTextBufLen ;
3458285169Scy	} else {
3459285169Scy		pBuf = pp->a_lastcode ;
3460285169Scy		iLen = pp->lencode ;
3461285169Scy	}
3462285169Scy
3463285169Scy	if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3464285169Scy	  && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3465285169Scy	  && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
3466285169Scy	  && up->iLoopbackCount < MAX_LOOPBACK ) {
3467285169Scy		/* Loopback */
3468285169Scy
3469285169Scy		teljjy_setDelay( peer, up ) ;
3470285169Scy
3471285169Scy		up->iLoopbackCount ++ ;
3472285169Scy
3473285169Scy	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3474285169Scy	    && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
3475285169Scy		/* Maybe echoback */
3476285169Scy
3477285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
3478285169Scy
3479285169Scy	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3480285169Scy		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
3481285169Scy		/* 4DATE<CR> -> YYYYMMDD<CR> */
3482285169Scy
3483285169Scy		rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
3484285169Scy
3485285169Scy		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
3486285169Scy		  || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
3487285169Scy			/* Invalid date */
3488285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
3489285169Scy				  rc, up->year, up->month, up->day ) ;
3490285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3491285169Scy			up->bLineError = TRUE ;
3492285169Scy		}
3493285169Scy
3494285169Scy	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3495285169Scy		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
3496285169Scy	         && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
3497285169Scy		/* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
3498285169Scy
3499285169Scy		rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
3500285169Scy
3501285169Scy		if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
3502285169Scy			/* Invalid leap second */
3503285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
3504285169Scy				  pBuf ) ;
3505285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3506285169Scy			up->bLineError = TRUE ;
3507285169Scy		}
3508285169Scy
3509285169Scy	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3510285169Scy		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
3511285169Scy		/* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
3512285169Scy
3513285169Scy		rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
3514285169Scy
3515285169Scy		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
3516285169Scy			/* Invalid time */
3517285169Scy			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
3518285169Scy				  rc, up->hour, up->minute, up->second ) ;
3519285169Scy			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3520285169Scy			up->bLineError = TRUE ;
3521285169Scy		}
3522285169Scy		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
3523285169Scy
3524285169Scy		up->iTimestampCount++ ;
3525285169Scy
3526285169Scy		if ( up->iTimestampCount == 6 && ! up->bLineError ) {
3527285169Scy#if DEBUG
3528285169Scy			printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
3529285169Scy				up->bLineError,
3530285169Scy				up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
3531182007Sroberto#endif
3532285169Scy			bAdjustment = TRUE ;
3533106163Sroberto
3534285169Scy			if ( peer->ttl == 100 ) {
3535285169Scy				/* mode=100 */
3536285169Scy				up->msecond = 0 ;
3537285169Scy			} else {
3538285169Scy				/* mode=101 to 110 */
3539285169Scy				up->msecond = teljjy_getDelay( peer, up ) ;
3540285169Scy				if (up->msecond < 0 ) {
3541285169Scy					up->msecond = 0 ;
3542285169Scy					bAdjustment = FALSE ;
3543285169Scy				}
3544285169Scy			}
3545285169Scy
3546285169Scy			if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
3547285169Scy			  &&   up->iTimestamp[2]        <= up->iTimestamp[3]
3548285169Scy			  && ( up->iTimestamp[3] +  1 ) == up->iTimestamp[4]
3549285169Scy			  && ( up->iTimestamp[4] +  1 ) == up->iTimestamp[5] ) {
3550285169Scy				/* Non over midnight */
3551285169Scy
3552285169Scy				jjy_synctime( peer, pp, up ) ;
3553285169Scy
3554285169Scy				if ( peer->ttl != 100 ) {
3555285169Scy					if ( bAdjustment ) {
3556285169Scy						snprintf( sLog, sizeof(sLog),
3557285169Scy							  JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
3558285169Scy							  up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3559285169Scy						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3560285169Scy					} else {
3561285169Scy						snprintf( sLog, sizeof(sLog),
3562285169Scy							  JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
3563285169Scy							   up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3564285169Scy						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3565285169Scy					}
3566285169Scy				}
3567285169Scy
3568285169Scy			}
3569285169Scy		}
3570285169Scy
3571285169Scy	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
3572285169Scy		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3573285169Scy		/* Loopback noise ( Unexpected replay ) */
3574285169Scy
3575285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
3576285169Scy			  pBuf ) ;
3577285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3578285169Scy
3579285169Scy	} else {
3580285169Scy
3581285169Scy		up->bLineError = TRUE ;
3582285169Scy
3583285169Scy		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
3584285169Scy			  pBuf ) ;
3585285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3586285169Scy
3587182007Sroberto	}
3588182007Sroberto
3589285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3590285169Scy
3591106163Sroberto}
3592106163Sroberto
3593285169Scy/******************************/
3594285169Scystatic int
3595285169Scyteljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3596285169Scy{
3597285169Scy
3598294554Sdelphij	const char *	pCmd ;
3599285169Scy
3600285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
3601285169Scy
3602285169Scy	if ( up->iClockCommandSeq >= 1
3603285169Scy	  && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
3604285169Scy		/* Loopback */
3605285169Scy#ifdef DEBUG
3606285169Scy		if ( debug ) {
3607285169Scy			printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
3608285169Scy		}
3609285169Scy#endif
3610285169Scy		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3611285169Scy			up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
3612285169Scy		}
3613285169Scy		up->iTeljjySilentTimer = 0 ;
3614285169Scy		return teljjy_conn_send( peer, pp, up ) ;
3615285169Scy	} else {
3616285169Scy		pCmd = "\r" ;
3617285169Scy	}
3618285169Scy
3619285169Scy	if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
3620285169Scy		refclock_report( peer, CEVNT_FAULT ) ;
3621285169Scy	}
3622285169Scy
3623285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3624285169Scy
3625285169Scy	up->iTeljjySilentTimer = 0 ;
3626285169Scy
3627285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3628285169Scy
3629285169Scy}
3630285169Scy
3631285169Scy/******************************/
3632285169Scystatic int
3633285169Scyteljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3634285169Scy{
3635285169Scy
3636285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
3637285169Scy
3638285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3639285169Scy
3640285169Scy}
3641285169Scy
3642285169Scy/******************************/
3643285169Scystatic int
3644285169Scyteljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3645285169Scy{
3646285169Scy
3647285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
3648285169Scy
3649285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3650285169Scy
3651285169Scy}
3652285169Scy
3653285169Scy/******************************/
3654285169Scystatic int
3655285169Scyteljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3656285169Scy{
3657285169Scy
3658285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
3659285169Scy
3660285169Scy	return TELJJY_CHANGE_CLOCK_STATE ;
3661285169Scy
3662285169Scy}
3663285169Scy
3664285169Scy/******************************/
3665285169Scystatic int
3666285169Scyteljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3667285169Scy{
3668285169Scy
3669285169Scy	DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
3670285169Scy
3671285169Scy	modem_disconnect ( peer->refclkunit, peer ) ;
3672285169Scy
3673285169Scy	return TELJJY_STAY_CLOCK_STATE ;
3674285169Scy
3675285169Scy}
3676285169Scy
3677285169Scy/*################################################################################################*/
3678285169Scy/*################################################################################################*/
3679285169Scy/*##												##*/
3680285169Scy/*##    Modem control finite state machine							##*/
3681285169Scy/*##												##*/
3682285169Scy/*################################################################################################*/
3683285169Scy/*################################################################################################*/
3684285169Scy
3685285169Scy/* struct jjyunit.iModemState */
3686285169Scy
3687285169Scy#define	MODEM_STATE_DISCONNECT		0
3688285169Scy#define	MODEM_STATE_INITIALIZE		1
3689285169Scy#define	MODEM_STATE_DAILING		2
3690285169Scy#define	MODEM_STATE_CONNECT		3
3691285169Scy#define	MODEM_STATE_ESCAPE		4
3692285169Scy
3693285169Scy/* struct jjyunit.iModemEvent */
3694285169Scy
3695285169Scy#define MODEM_EVENT_NULL		0
3696285169Scy#define	MODEM_EVENT_INITIALIZE		1
3697285169Scy#define	MODEM_EVENT_DIALOUT		2
3698285169Scy#define	MODEM_EVENT_DISCONNECT		3
3699285169Scy#define	MODEM_EVENT_RESP_OK		4
3700285169Scy#define	MODEM_EVENT_RESP_CONNECT	5
3701285169Scy#define	MODEM_EVENT_RESP_RING		6
3702285169Scy#define	MODEM_EVENT_RESP_NO_CARRIER	7
3703285169Scy#define	MODEM_EVENT_RESP_ERROR		8
3704285169Scy#define	MODEM_EVENT_RESP_CONNECT_X	9
3705285169Scy#define	MODEM_EVENT_RESP_NO_DAILTONE	10
3706285169Scy#define	MODEM_EVENT_RESP_BUSY		11
3707285169Scy#define	MODEM_EVENT_RESP_NO_ANSWER	12
3708285169Scy#define	MODEM_EVENT_RESP_UNKNOWN	13
3709285169Scy#define	MODEM_EVENT_SILENT		14
3710285169Scy#define	MODEM_EVENT_TIMEOUT		15
3711285169Scy
3712285169Scy/* Function prototypes */
3713285169Scy
3714285169Scystatic	void	modem_control		( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3715285169Scy
3716285169Scystatic	int 	modem_disc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3717285169Scystatic	int 	modem_disc_init  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3718285169Scystatic	int 	modem_init_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3719285169Scystatic	int 	modem_init_start 	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3720285169Scystatic	int 	modem_init_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3721285169Scystatic	int 	modem_init_resp00	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3722285169Scystatic	int 	modem_init_resp04	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3723285169Scystatic	int 	modem_dial_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3724285169Scystatic	int 	modem_dial_dialout	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3725285169Scystatic	int 	modem_dial_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3726285169Scystatic	int 	modem_dial_connect	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3727285169Scystatic	int 	modem_dial_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3728285169Scystatic	int 	modem_conn_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3729285169Scystatic	int 	modem_conn_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3730285169Scystatic	int 	modem_esc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3731285169Scystatic	int 	modem_esc_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3732285169Scystatic	int 	modem_esc_data  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3733285169Scystatic	int 	modem_esc_silent	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3734285169Scystatic	int 	modem_esc_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3735285169Scy
3736294554Sdelphijstatic int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) =
3737285169Scy{                         	/*STATE_DISCONNECT   STATE_INITIALIZE   STATE_DAILING       STATE_CONNECT      STATE_ESCAPE     */
3738285169Scy/* NULL                 */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3739285169Scy/* INITIALIZE           */	{ modem_disc_init  , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3740285169Scy/* DIALOUT              */	{ modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
3741285169Scy/* DISCONNECT           */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_escape },
3742285169Scy/* RESP: 0: OK          */	{ modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3743285169Scy/* RESP: 1: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3744285169Scy/* RESP: 2: RING        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3745285169Scy/* RESP: 3: NO CARRIER  */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3746285169Scy/* RESP: 4: ERROR       */	{ modem_disc_ignore, modem_init_resp04, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3747285169Scy/* RESP: 5: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3748285169Scy/* RESP: 6: NO DAILTONE */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3749285169Scy/* RESP: 7: BUSY        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3750285169Scy/* RESP: 8: NO ANSWER   */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3751285169Scy/* RESP: 9: UNKNOWN     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3752285169Scy/* SILENT               */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
3753285169Scy/* TIMEOUT              */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_disc   }
3754285169Scy} ;
3755285169Scy
3756285169Scystatic short iModemNextState [ ] [ 5 ] =
3757285169Scy{                         	/*STATE_DISCONNECT        STATE_INITIALIZE        STATE_DAILING        STATE_CONNECT        STATE_ESCAPE           */
3758285169Scy/* NULL                 */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3759285169Scy/* INITIALIZE           */	{ MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3760285169Scy/* DIALOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3761285169Scy/* DISCONNECT           */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE     },
3762285169Scy/* RESP: 0: OK          */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3763285169Scy/* RESP: 1: CONNECT     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3764285169Scy/* RESP: 2: RING        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3765285169Scy/* RESP: 3: NO CARRIER  */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3766285169Scy/* RESP: 4: ERROR       */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3767285169Scy/* RESP: 5: CONNECT X   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3768285169Scy/* RESP: 6: NO DAILTONE */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3769285169Scy/* RESP: 7: BUSY        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3770285169Scy/* RESP: 8: NO ANSWER   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3771285169Scy/* RESP: 9: UNKNOWN     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3772285169Scy/* SILENT               */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
3773285169Scy/* TIMEOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
3774285169Scy} ;
3775285169Scy
3776285169Scystatic short iModemPostEvent [ ] [ 5 ] =
3777285169Scy{                         	/*STATE_DISCONNECT        STATE_INITIALIZE     STATE_DAILING           STATE_CONNECT           STATE_ESCAPE     */
3778285169Scy/* NULL                 */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3779285169Scy/* INITIALIZE           */	{ MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3780285169Scy/* DIALOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3781285169Scy/* DISCONNECT           */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
3782285169Scy/* RESP: 0: OK          */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3783285169Scy/* RESP: 1: CONNECT     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3784285169Scy/* RESP: 2: RING        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3785285169Scy/* RESP: 3: NO CARRIER  */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3786285169Scy/* RESP: 4: ERROR       */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3787285169Scy/* RESP: 5: CONNECT X   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3788285169Scy/* RESP: 6: NO DAILTONE */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3789285169Scy/* RESP: 7: BUSY        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3790285169Scy/* RESP: 8: NO ANSWER   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3791285169Scy/* RESP: 9: UNKNOWN     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3792285169Scy/* SILENT               */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3793285169Scy/* TIMEOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
3794285169Scy} ;
3795285169Scy
3796285169Scystatic short iModemSilentTimeout [ 5 ] = { 0,  0,  0, 0,  5 } ;
3797285169Scystatic short iModemStateTimeout  [ 5 ] = { 0, 20, 90, 0, 20 } ;
3798285169Scy
3799285169Scy#define	STAY_MODEM_STATE	0
3800285169Scy#define	CHANGE_MODEM_STATE	1
3801285169Scy
3802285169Scy#ifdef	DEBUG
3803285169Scy#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 ) ; } }
3804285169Scy#else
3805285169Scy#define	DEBUG_MODEM_PRINTF(sFunc)
3806285169Scy#endif
3807285169Scy
3808106163Sroberto/**************************************************************************************************/
3809106163Sroberto
3810285169Scystatic short
3811285169ScygetModemState ( struct jjyunit *up )
3812285169Scy{
3813285169Scy	return up->iModemState ;
3814285169Scy}
3815285169Scy
3816285169Scy/**************************************************************************************************/
3817285169Scy
3818285169Scystatic int
3819285169ScyisModemStateConnect ( short iCheckState )
3820285169Scy{
3821285169Scy	return ( iCheckState == MODEM_STATE_CONNECT ) ;
3822285169Scy}
3823285169Scy
3824285169Scy/**************************************************************************************************/
3825285169Scy
3826285169Scystatic int
3827285169ScyisModemStateDisconnect ( short iCheckState )
3828285169Scy{
3829285169Scy	return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
3830285169Scy}
3831285169Scy
3832285169Scy/**************************************************************************************************/
3833285169Scy
3834285169Scystatic int
3835285169ScyisModemStateTimerOn ( struct jjyunit *up )
3836285169Scy{
3837285169Scy	return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
3838285169Scy}
3839285169Scy
3840285169Scy/**************************************************************************************************/
3841285169Scy
3842106163Srobertostatic void
3843285169Scymodem_connect ( int unit, struct peer *peer )
3844106163Sroberto{
3845285169Scy	struct	refclockproc	*pp;
3846285169Scy	struct	jjyunit 	*up;
3847106163Sroberto
3848285169Scy	pp = peer->procptr ;
3849285169Scy	up = pp->unitptr ;
3850106163Sroberto
3851285169Scy	DEBUG_MODEM_PRINTF( "modem_connect" ) ;
3852182007Sroberto
3853285169Scy	up->iModemEvent = MODEM_EVENT_INITIALIZE ;
3854285169Scy
3855285169Scy	modem_control ( peer, pp, up ) ;
3856285169Scy
3857285169Scy}
3858285169Scy
3859285169Scy/**************************************************************************************************/
3860285169Scy
3861285169Scystatic void
3862285169Scymodem_disconnect ( int unit, struct peer *peer )
3863285169Scy{
3864285169Scy	struct	refclockproc	*pp;
3865285169Scy	struct	jjyunit 	*up;
3866285169Scy
3867285169Scy	pp = peer->procptr ;
3868280849Scy	up = pp->unitptr ;
3869106163Sroberto
3870285169Scy	DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
3871106163Sroberto
3872285169Scy	up->iModemEvent = MODEM_EVENT_DISCONNECT ;
3873285169Scy
3874285169Scy	modem_control ( peer, pp, up ) ;
3875285169Scy
3876285169Scy}
3877285169Scy
3878285169Scy/**************************************************************************************************/
3879285169Scy
3880285169Scystatic int
3881285169Scymodem_receive ( struct recvbuf *rbufp )
3882285169Scy{
3883285169Scy
3884285169Scy	struct	peer		*peer;
3885285169Scy	struct	jjyunit		*up;
3886285169Scy	struct	refclockproc	*pp;
3887285169Scy	char	*pBuf ;
3888316068Sdelphij	size_t	iLen ;
3889285169Scy
3890285169Scy#ifdef DEBUG
3891285169Scy	static const char *sFunctionName = "modem_receive" ;
3892285169Scy#endif
3893285169Scy
3894285169Scy	peer = rbufp->recv_peer ;
3895285169Scy	pp = peer->procptr ;
3896285169Scy	up = pp->unitptr ;
3897285169Scy
3898285169Scy	DEBUG_MODEM_PRINTF( sFunctionName ) ;
3899285169Scy
3900285169Scy	if ( up->linediscipline == LDISC_RAW ) {
3901285169Scy		pBuf = up->sTextBuf ;
3902285169Scy		iLen = up->iTextBufLen ;
3903285169Scy	} else {
3904285169Scy		pBuf = pp->a_lastcode ;
3905285169Scy		iLen = pp->lencode ;
3906182007Sroberto	}
3907182007Sroberto
3908285169Scy	if      ( iLen ==  2 && strncmp( pBuf, "OK"         ,  2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK          ; }
3909285169Scy	else if ( iLen ==  7 && strncmp( pBuf, "CONNECT"    ,  7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT     ; }
3910285169Scy	else if ( iLen ==  4 && strncmp( pBuf, "RING"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING        ; }
3911285169Scy	else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER  ; }
3912285169Scy	else if ( iLen ==  5 && strncmp( pBuf, "ERROR"      ,  5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR       ; }
3913285169Scy	else if ( iLen >=  8 && strncmp( pBuf, "CONNECT "   ,  8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X   ; }
3914285169Scy	else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
3915285169Scy	else if ( iLen ==  4 && strncmp( pBuf, "BUSY"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY        ; }
3916285169Scy	else if ( iLen ==  9 && strncmp( pBuf, "NO ANSWER"  ,  9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER   ; }
3917285169Scy	else                                                              { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN     ; }
3918285169Scy
3919182007Sroberto#ifdef DEBUG
3920182007Sroberto	if ( debug ) {
3921285169Scy		char	sResp [ 40 ] ;
3922316068Sdelphij		size_t	iCopyLen ;
3923285169Scy		iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3924285169Scy		strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3925285169Scy		sResp[iCopyLen] = 0 ;
3926316068Sdelphij		printf ( "refclock_jjy.c : modem_receive : iLen=%zu pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
3927182007Sroberto	}
3928182007Sroberto#endif
3929285169Scy	modem_control ( peer, pp, up ) ;
3930182007Sroberto
3931285169Scy	return 0 ;
3932106163Sroberto
3933106163Sroberto}
3934106163Sroberto
3935200576Sroberto/**************************************************************************************************/
3936200576Sroberto
3937200576Srobertostatic void
3938285169Scymodem_timer ( int unit, struct peer *peer )
3939200576Sroberto{
3940200576Sroberto
3941285169Scy	struct	refclockproc *pp ;
3942285169Scy	struct	jjyunit      *up ;
3943200576Sroberto
3944285169Scy	pp = peer->procptr ;
3945285169Scy	up = pp->unitptr ;
3946285169Scy
3947285169Scy	DEBUG_MODEM_PRINTF( "modem_timer" ) ;
3948285169Scy
3949285169Scy	if ( iModemSilentTimeout[up->iModemState] != 0 ) {
3950285169Scy		up->iModemSilentTimer++ ;
3951285169Scy		if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
3952285169Scy			up->iModemEvent = MODEM_EVENT_SILENT ;
3953285169Scy			modem_control ( peer, pp, up ) ;
3954285169Scy		}
3955285169Scy	}
3956285169Scy
3957285169Scy	if ( iModemStateTimeout[up->iModemState] != 0 ) {
3958285169Scy		up->iModemStateTimer++ ;
3959285169Scy		if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
3960285169Scy			up->iModemEvent = MODEM_EVENT_TIMEOUT ;
3961285169Scy			modem_control ( peer, pp, up ) ;
3962285169Scy		}
3963285169Scy	}
3964285169Scy
3965200576Sroberto}
3966200576Sroberto
3967280849Scy/**************************************************************************************************/
3968280849Scy
3969280849Scystatic void
3970285169Scymodem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3971280849Scy{
3972285169Scy
3973285169Scy	int	rc ;
3974285169Scy	short	iPostEvent = MODEM_EVENT_NULL ;
3975285169Scy
3976285169Scy	DEBUG_MODEM_PRINTF( "modem_control" ) ;
3977285169Scy
3978285169Scy	rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
3979285169Scy
3980285169Scy	if ( rc == CHANGE_MODEM_STATE ) {
3981285169Scy		iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
3982280849Scy#ifdef DEBUG
3983285169Scy		if ( debug ) {
3984285169Scy			printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d  iPostEvent=%d\n",
3985285169Scy				 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
3986285169Scy		}
3987280849Scy#endif
3988280849Scy
3989285169Scy		if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
3990285169Scy			up->iModemSilentCount = 0 ;
3991285169Scy			up->iModemStateTimer = 0 ;
3992285169Scy			up->iModemCommandSeq = 0 ;
3993285169Scy		}
3994280849Scy
3995285169Scy		up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
3996285169Scy	}
3997280849Scy
3998285169Scy	if ( iPostEvent != MODEM_EVENT_NULL ) {
3999285169Scy		up->iModemEvent = iPostEvent ;
4000285169Scy		modem_control ( peer, pp, up ) ;
4001285169Scy	}
4002280849Scy
4003285169Scy	up->iModemEvent = MODEM_EVENT_NULL ;
4004285169Scy
4005285169Scy}
4006285169Scy
4007285169Scy/******************************/
4008285169Scystatic int
4009285169Scymodem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4010285169Scy{
4011285169Scy
4012285169Scy	DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
4013285169Scy
4014285169Scy	return STAY_MODEM_STATE ;
4015285169Scy
4016285169Scy}
4017285169Scy
4018285169Scy/******************************/
4019285169Scystatic int
4020285169Scymodem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4021285169Scy{
4022285169Scy
4023285169Scy	DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
4024285169Scy
4025285169Scy	return CHANGE_MODEM_STATE ;
4026285169Scy
4027285169Scy}
4028285169Scy
4029285169Scy/******************************/
4030285169Scystatic int
4031285169Scymodem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4032285169Scy{
4033285169Scy
4034285169Scy	DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
4035285169Scy
4036285169Scy	return STAY_MODEM_STATE ;
4037285169Scy
4038285169Scy}
4039285169Scy
4040285169Scy/******************************/
4041285169Scystatic int
4042285169Scymodem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4043285169Scy{
4044285169Scy
4045285169Scy	DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
4046285169Scy
4047285169Scy	up->iModemCommandSeq = 0 ;
4048285169Scy
4049285169Scy#ifdef DEBUG
4050285169Scy	if ( debug ) {
4051285169Scy		printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
4052285169Scy	}
4053285169Scy#endif
4054285169Scy
4055285169Scy	return modem_init_resp00( peer, pp, up ) ;
4056285169Scy
4057285169Scy}
4058285169Scy
4059285169Scy/******************************/
4060285169Scystatic int
4061285169Scymodem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4062285169Scy{
4063285169Scy
4064294554Sdelphij	const char *	pCmd ;
4065294554Sdelphij	char		cBuf [ 46 ] ;
4066294554Sdelphij	int		iCmdLen ;
4067294554Sdelphij	int		iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
4068294554Sdelphij	int		iNextModemState = STAY_MODEM_STATE ;
4069285169Scy
4070285169Scy	DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
4071285169Scy
4072285169Scy	up->iModemCommandSeq++ ;
4073285169Scy
4074285169Scy	switch ( up->iModemCommandSeq ) {
4075285169Scy
4076285169Scy	case 1 :
4077285169Scy		/* En = Echoback      0:Off      1:On   */
4078285169Scy		/* Qn = Result codes  0:On       1:Off  */
4079285169Scy		/* Vn = Result codes  0:Numeric  1:Text */
4080285169Scy		pCmd = "ATE0Q0V1\r\n" ;
4081285169Scy		break ;
4082285169Scy
4083285169Scy	case 2 :
4084285169Scy		/* Mn = Speaker switch  0:Off  1:On until remote carrier detected  2:On */
4085285169Scy		if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
4086285169Scy			/* fudge 127.127.40.n flag3 0 */
4087285169Scy			iSpeakerSwitch = 0 ;
4088285169Scy		} else {
4089285169Scy			/* fudge 127.127.40.n flag3 1 */
4090285169Scy			iSpeakerSwitch = 2 ;
4091285169Scy		}
4092285169Scy
4093285169Scy		/* Ln = Speaker volume  0:Very low  1:Low  2:Middle  3:High */
4094285169Scy		if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
4095285169Scy			/* fudge 127.127.40.n flag4 0 */
4096285169Scy			iSpeakerVolume = 1 ;
4097285169Scy		} else {
4098285169Scy			/* fudge 127.127.40.n flag4 1 */
4099285169Scy			iSpeakerVolume = 2 ;
4100285169Scy		}
4101285169Scy
4102285169Scy		pCmd = cBuf ;
4103294554Sdelphij		snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
4104285169Scy		break ;
4105285169Scy
4106285169Scy	case 3 :
4107285169Scy		/* &Kn = Flow control  4:XON/XOFF */
4108285169Scy		pCmd = "AT&K4\r\n" ;
4109285169Scy		break ;
4110285169Scy
4111285169Scy	case 4 :
4112285169Scy		/* +MS = Protocol  V22B:1200,2400bps�iV.22bis) */
4113285169Scy		pCmd = "AT+MS=V22B\r\n" ;
4114285169Scy		break ;
4115285169Scy
4116285169Scy	case 5 :
4117285169Scy		/* %Cn = Data compression  0:No data compression */
4118285169Scy		pCmd = "AT%C0\r\n" ;
4119285169Scy		break ;
4120285169Scy
4121285169Scy	case 6 :
4122285169Scy		/* \Nn = Error correction  0:Normal mode  1:Direct mode  2:V42,MNP  3:V42,MNP,Normal */
4123285169Scy		if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
4124285169Scy			/* fudge 127.127.40.n flag2 0 */
4125285169Scy			iErrorCorrection = 0 ;
4126285169Scy		} else {
4127285169Scy			/* fudge 127.127.40.n flag2 1 */
4128285169Scy			iErrorCorrection = 3 ;
4129285169Scy		}
4130285169Scy
4131285169Scy		pCmd = cBuf ;
4132294554Sdelphij		snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
4133285169Scy		break ;
4134285169Scy
4135285169Scy	case 7 :
4136285169Scy		/* Hn = Hook  0:Hook-On ( Disconnect )  1:Hook-Off ( Connect ) */
4137285169Scy		pCmd = "ATH1\r\n" ;
4138285169Scy		break ;
4139285169Scy
4140285169Scy	case 8 :
4141285169Scy		/* Initialize completion */
4142285169Scy		pCmd = NULL ;
4143285169Scy		iNextModemState = CHANGE_MODEM_STATE ;
4144285169Scy		break ;
4145285169Scy
4146285169Scy	default :
4147285169Scy		pCmd = NULL ;
4148285169Scy		break ;
4149285169Scy
4150285169Scy	}
4151285169Scy
4152285169Scy	if ( pCmd != NULL ) {
4153285169Scy
4154285169Scy		iCmdLen = strlen( pCmd ) ;
4155285169Scy		if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4156285169Scy			refclock_report( peer, CEVNT_FAULT ) ;
4157285169Scy		}
4158285169Scy
4159285169Scy		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4160285169Scy
4161285169Scy	}
4162285169Scy
4163285169Scy	return iNextModemState ;
4164285169Scy
4165285169Scy}
4166285169Scy
4167285169Scy/******************************/
4168285169Scystatic int
4169285169Scymodem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4170285169Scy{
4171285169Scy
4172285169Scy	DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
4173285169Scy
4174285169Scy	return modem_init_resp00( peer, pp, up ) ;
4175285169Scy
4176285169Scy}
4177285169Scy
4178285169Scy/******************************/
4179285169Scystatic int
4180285169Scymodem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4181285169Scy{
4182285169Scy
4183285169Scy	DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
4184285169Scy#ifdef DEBUG
4185285169Scy	if ( debug ) {
4186285169Scy		printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
4187285169Scy	}
4188285169Scy#endif
4189285169Scy
4190285169Scy	return CHANGE_MODEM_STATE ;
4191285169Scy
4192285169Scy}
4193285169Scy
4194285169Scy/******************************/
4195285169Scystatic int
4196285169Scymodem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4197285169Scy{
4198285169Scy
4199285169Scy	DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
4200285169Scy
4201285169Scy	return STAY_MODEM_STATE ;
4202285169Scy
4203285169Scy}
4204285169Scy
4205285169Scy/******************************/
4206285169Scystatic int
4207285169Scymodem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4208285169Scy{
4209285169Scy
4210285169Scy	char	sCmd [ 46 ] ;
4211285169Scy	int	iCmdLen ;
4212285169Scy	char	cToneOrPulse ;
4213285169Scy
4214285169Scy	DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
4215285169Scy
4216285169Scy	/* Tone or Pulse */
4217280849Scy	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
4218285169Scy		/* fudge 127.127.40.n flag1 0 */
4219285169Scy		cToneOrPulse = 'T' ;
4220285169Scy	} else {
4221285169Scy		/* fudge 127.127.40.n flag1 1 */
4222285169Scy		cToneOrPulse = 'P' ;
4223280849Scy	}
4224280849Scy
4225285169Scy	/* Connect ( Dial number ) */
4226285169Scy	snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
4227285169Scy
4228285169Scy	/* Send command */
4229285169Scy	iCmdLen = strlen( sCmd ) ;
4230285169Scy	if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
4231285169Scy		refclock_report( peer, CEVNT_FAULT ) ;
4232285169Scy	}
4233285169Scy
4234285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
4235285169Scy
4236285169Scy	return STAY_MODEM_STATE ;
4237285169Scy
4238285169Scy}
4239285169Scy
4240285169Scy/******************************/
4241285169Scystatic int
4242285169Scymodem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4243285169Scy{
4244285169Scy
4245285169Scy	DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
4246280849Scy#ifdef DEBUG
4247280849Scy	if ( debug ) {
4248285169Scy		printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
4249280849Scy	}
4250280849Scy#endif
4251280849Scy
4252285169Scy	return modem_conn_escape( peer, pp, up ) ;
4253280849Scy
4254285169Scy}
4255285169Scy
4256285169Scy/******************************/
4257285169Scystatic int
4258285169Scymodem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4259285169Scy{
4260285169Scy
4261285169Scy	DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
4262285169Scy
4263285169Scy	return CHANGE_MODEM_STATE ;
4264285169Scy
4265285169Scy}
4266285169Scy
4267285169Scy/******************************/
4268285169Scystatic int
4269285169Scymodem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4270285169Scy{
4271285169Scy
4272285169Scy	DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
4273280849Scy#ifdef DEBUG
4274280849Scy	if ( debug ) {
4275285169Scy		printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
4276280849Scy	}
4277280849Scy#endif
4278280849Scy
4279285169Scy	modem_esc_disc( peer, pp, up ) ;
4280285169Scy
4281285169Scy	return CHANGE_MODEM_STATE ;
4282285169Scy
4283285169Scy}
4284285169Scy
4285285169Scy/******************************/
4286285169Scystatic int
4287285169Scymodem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4288285169Scy{
4289285169Scy
4290285169Scy	DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
4291285169Scy
4292285169Scy	return STAY_MODEM_STATE ;
4293285169Scy
4294285169Scy}
4295285169Scy
4296285169Scy/******************************/
4297285169Scystatic int
4298285169Scymodem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4299285169Scy{
4300285169Scy
4301285169Scy	DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
4302285169Scy
4303285169Scy	return CHANGE_MODEM_STATE ;
4304285169Scy
4305285169Scy}
4306285169Scy
4307285169Scy/******************************/
4308285169Scystatic int
4309285169Scymodem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4310285169Scy{
4311285169Scy
4312285169Scy	DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
4313285169Scy
4314285169Scy	return STAY_MODEM_STATE ;
4315285169Scy
4316285169Scy}
4317285169Scy
4318285169Scy/******************************/
4319285169Scystatic int
4320285169Scymodem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4321285169Scy{
4322285169Scy
4323294554Sdelphij	const char *	pCmd ;
4324294554Sdelphij	int		iCmdLen ;
4325285169Scy
4326285169Scy	DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
4327285169Scy
4328285169Scy	/* Escape command ( Go to command mode ) */
4329285169Scy	pCmd = "+++" ;
4330285169Scy
4331285169Scy	/* Send command */
4332285169Scy	iCmdLen = strlen( pCmd ) ;
4333285169Scy	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4334285169Scy		refclock_report( peer, CEVNT_FAULT ) ;
4335280849Scy	}
4336280849Scy
4337285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4338285169Scy
4339285169Scy	return STAY_MODEM_STATE ;
4340285169Scy
4341280849Scy}
4342280849Scy
4343285169Scy/******************************/
4344285169Scystatic int
4345285169Scymodem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4346285169Scy{
4347280849Scy
4348285169Scy	DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
4349285169Scy
4350285169Scy	up->iModemSilentTimer = 0 ;
4351285169Scy
4352285169Scy	return STAY_MODEM_STATE ;
4353285169Scy
4354285169Scy}
4355285169Scy
4356285169Scy/******************************/
4357285169Scystatic int
4358285169Scymodem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4359285169Scy{
4360285169Scy
4361285169Scy	DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
4362285169Scy
4363285169Scy	up->iModemSilentCount ++ ;
4364285169Scy
4365285169Scy	if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
4366285169Scy#ifdef DEBUG
4367285169Scy		if ( debug ) {
4368285169Scy			printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
4369285169Scy		}
4370285169Scy#endif
4371285169Scy		modem_esc_escape( peer, pp, up ) ;
4372285169Scy		up->iModemSilentTimer = 0 ;
4373285169Scy		return STAY_MODEM_STATE ;
4374285169Scy	}
4375285169Scy
4376285169Scy#ifdef DEBUG
4377285169Scy	if ( debug ) {
4378285169Scy		printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
4379285169Scy	}
4380285169Scy#endif
4381285169Scy	return modem_esc_disc( peer, pp, up ) ;
4382285169Scy
4383285169Scy}
4384285169Scy/******************************/
4385285169Scystatic int
4386285169Scymodem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4387285169Scy{
4388285169Scy
4389294554Sdelphij	const char *	pCmd ;
4390294554Sdelphij	int		iCmdLen ;
4391285169Scy
4392285169Scy	DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
4393285169Scy
4394285169Scy	/* Disconnect */
4395285169Scy	pCmd = "ATH0\r\n" ;
4396285169Scy
4397285169Scy	/* Send command */
4398285169Scy	iCmdLen = strlen( pCmd ) ;
4399285169Scy	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4400285169Scy		refclock_report( peer, CEVNT_FAULT ) ;
4401285169Scy	}
4402285169Scy
4403285169Scy	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4404285169Scy
4405285169Scy	return CHANGE_MODEM_STATE ;
4406285169Scy
4407285169Scy}
4408285169Scy
4409285169Scy/*################################################################################################*/
4410285169Scy/*################################################################################################*/
4411285169Scy/*##												##*/
4412285169Scy/*##    jjy_write_clockstats									##*/
4413285169Scy/*##												##*/
4414285169Scy/*################################################################################################*/
4415285169Scy/*################################################################################################*/
4416285169Scy
4417280849Scystatic void
4418285169Scyjjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
4419280849Scy{
4420285169Scy
4421294554Sdelphij	char		sLog [ 100 ] ;
4422294554Sdelphij	const char *	pMark ;
4423294554Sdelphij	int 		iMarkLen, iDataLen ;
4424285169Scy
4425285169Scy	switch ( iMark ) {
4426285169Scy	case JJY_CLOCKSTATS_MARK_JJY :
4427285169Scy		pMark = "JJY " ;
4428285169Scy		break ;
4429285169Scy	case JJY_CLOCKSTATS_MARK_SEND :
4430285169Scy		pMark = "--> " ;
4431285169Scy		break ;
4432285169Scy	case JJY_CLOCKSTATS_MARK_RECEIVE :
4433285169Scy		pMark = "<-- " ;
4434285169Scy		break ;
4435285169Scy	case JJY_CLOCKSTATS_MARK_INFORMATION :
4436285169Scy		pMark = "--- " ;
4437285169Scy		break ;
4438285169Scy	case JJY_CLOCKSTATS_MARK_ATTENTION :
4439285169Scy		pMark = "=== " ;
4440285169Scy		break ;
4441285169Scy	case JJY_CLOCKSTATS_MARK_WARNING :
4442285169Scy		pMark = "-W- " ;
4443285169Scy		break ;
4444285169Scy	case JJY_CLOCKSTATS_MARK_ERROR :
4445285169Scy		pMark = "-X- " ;
4446285169Scy		break ;
4447330106Sdelphij	case JJY_CLOCKSTATS_MARK_BUG :
4448330106Sdelphij		pMark = "!!! " ;
4449330106Sdelphij		break ;
4450285169Scy	default :
4451285169Scy		pMark = "" ;
4452285169Scy		break ;
4453285169Scy	}
4454285169Scy
4455285169Scy	iDataLen = strlen( pData ) ;
4456285169Scy	iMarkLen = strlen( pMark ) ;
4457285169Scy	strcpy( sLog, pMark ) ; /* Harmless because of enough length */
4458285169Scy	printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
4459285169Scy
4460285169Scy#ifdef DEBUG
4461285169Scy	if ( debug ) {
4462285169Scy		printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
4463285169Scy	}
4464285169Scy#endif
4465285169Scy	record_clock_stats( &peer->srcadr, sLog ) ;
4466285169Scy
4467285169Scy}
4468285169Scy
4469285169Scy/*################################################################################################*/
4470285169Scy/*################################################################################################*/
4471285169Scy/*##												##*/
4472285169Scy/*##    printableString										##*/
4473285169Scy/*##												##*/
4474285169Scy/*################################################################################################*/
4475285169Scy/*################################################################################################*/
4476285169Scy
4477285169Scystatic void
4478285169ScyprintableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
4479285169Scy{
4480280849Scy	const char	*printableControlChar[] = {
4481280849Scy			"<NUL>", "<SOH>", "<STX>", "<ETX>",
4482280849Scy			"<EOT>", "<ENQ>", "<ACK>", "<BEL>",
4483280849Scy			"<BS>" , "<HT>" , "<LF>" , "<VT>" ,
4484280849Scy			"<FF>" , "<CR>" , "<SO>" , "<SI>" ,
4485280849Scy			"<DLE>", "<DC1>", "<DC2>", "<DC3>",
4486280849Scy			"<DC4>", "<NAK>", "<SYN>", "<ETB>",
4487280849Scy			"<CAN>", "<EM>" , "<SUB>", "<ESC>",
4488280849Scy			"<FS>" , "<GS>" , "<RS>" , "<US>" ,
4489280849Scy			" " } ;
4490280849Scy
4491280849Scy	size_t	i, j, n ;
4492280849Scy	size_t	InputLen;
4493280849Scy	size_t	OutputLen;
4494280849Scy
4495280849Scy	InputLen = (size_t)iInputLen;
4496280849Scy	OutputLen = (size_t)iOutputLen;
4497280849Scy	for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
4498280849Scy		if ( isprint( (unsigned char)sInput[i] ) ) {
4499280849Scy			n = 1 ;
4500280849Scy			if ( j + 1 >= OutputLen )
4501280849Scy				break ;
4502280849Scy			sOutput[j] = sInput[i] ;
4503280849Scy		} else if ( ( sInput[i] & 0xFF ) <
4504280849Scy			    COUNTOF(printableControlChar) ) {
4505280849Scy			n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
4506280849Scy			if ( j + n + 1 >= OutputLen )
4507280849Scy				break ;
4508280849Scy			strlcpy( sOutput + j,
4509280849Scy				 printableControlChar[sInput[i] & 0xFF],
4510280849Scy				 OutputLen - j ) ;
4511280849Scy		} else {
4512280849Scy			n = 5 ;
4513280849Scy			if ( j + n + 1 >= OutputLen )
4514280849Scy				break ;
4515280849Scy			snprintf( sOutput + j, OutputLen - j, "<x%X>",
4516280849Scy				  sInput[i] & 0xFF ) ;
4517280849Scy		}
4518280849Scy		j += n ;
4519280849Scy	}
4520280849Scy
4521280849Scy	sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
4522280849Scy
4523280849Scy}
4524280849Scy
4525280849Scy/**************************************************************************************************/
4526280849Scy
4527106163Sroberto#else
4528106163Srobertoint refclock_jjy_bs ;
4529106163Sroberto#endif /* REFCLOCK */
4530