1106163Sroberto/*
2106163Sroberto * refclock_jjy - clock driver for JJY receivers
3106163Sroberto */
4106163Sroberto
5106163Sroberto/**********************************************************************/
6285612Sdelphij/*								      */
7285612Sdelphij/*  Copyright (C) 2001-2015, Takao Abe.  All rights reserved.	      */
8285612Sdelphij/*								      */
9106163Sroberto/*  Permission to use, copy, modify, and distribute this software     */
10285612Sdelphij/*  and its documentation for any purpose is hereby granted	      */
11106163Sroberto/*  without fee, provided that the following conditions are met:      */
12285612Sdelphij/*								      */
13106163Sroberto/*  One retains the entire copyright notice properly, and both the    */
14106163Sroberto/*  copyright notice and this license. in the documentation and/or    */
15285612Sdelphij/*  other materials provided with the distribution.		      */
16285612Sdelphij/*								      */
17106163Sroberto/*  This software and the name of the author must not be used to      */
18106163Sroberto/*  endorse or promote products derived from this software without    */
19285612Sdelphij/*  prior written permission.					      */
20285612Sdelphij/*								      */
21106163Sroberto/*  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED    */
22285612Sdelphij/*  WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE	      */
23285612Sdelphij/*  IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A	      */
24285612Sdelphij/*  PARTICULAR PURPOSE.						      */
25106163Sroberto/*  IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT,  */
26106163Sroberto/*  INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   */
27285612Sdelphij/*  ( 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,     */
30285612Sdelphij/*  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. */
33285612Sdelphij/*								      */
34106163Sroberto/*  This driver is developed in my private time, and is opened as     */
35285612Sdelphij/*  voluntary contributions for the NTP.			      */
36106163Sroberto/*  The manufacturer of the JJY receiver has not participated in      */
37285612Sdelphij/*  a development of this driver.				      */
38106163Sroberto/*  The manufacturer does not warrant anything about this driver,     */
39285612Sdelphij/*  and is not liable for anything about this driver.		      */
40285612Sdelphij/*								      */
41106163Sroberto/**********************************************************************/
42285612Sdelphij/*								      */
43285612Sdelphij/*  Author     Takao Abe					      */
44285612Sdelphij/*  Email      takao_abe@xurb.jp				      */
45285612Sdelphij/*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/		      */
46285612Sdelphij/*								      */
47285612Sdelphij/*  The email address abetakao@bea.hi-ho.ne.jp is never read	      */
48285612Sdelphij/*  from 2010, because a few filtering rule are provided by the	      */
49285612Sdelphij/*  "hi-ho.ne.jp", and lots of spam mail are reached.		      */
50285612Sdelphij/*  New email address for supporting the refclock_jjy is	      */
51285612Sdelphij/*  takao_abe@xurb.jp						      */
52285612Sdelphij/*								      */
53106163Sroberto/**********************************************************************/
54285612Sdelphij/*								      */
55285612Sdelphij/*  History							      */
56285612Sdelphij/*								      */
57285612Sdelphij/*  2001/07/15							      */
58285612Sdelphij/*    [New]    Support the Tristate Ltd. JJY receiver		      */
59285612Sdelphij/*								      */
60285612Sdelphij/*  2001/08/04							      */
61285612Sdelphij/*    [Change] Log to clockstats even if bad reply		      */
62285612Sdelphij/*    [Fix]    PRECISION = (-3) (about 100 ms)			      */
63285612Sdelphij/*    [Add]    Support the C-DEX Co.Ltd. JJY receiver		      */
64285612Sdelphij/*								      */
65285612Sdelphij/*  2001/12/04							      */
66106163Sroberto/*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
67285612Sdelphij/*								      */
68285612Sdelphij/*  2002/07/12							      */
69285612Sdelphij/*    [Fix]    Portability for FreeBSD ( patched by the user )	      */
70285612Sdelphij/*								      */
71285612Sdelphij/*  2004/10/31							      */
72182007Sroberto/*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
73285612Sdelphij/*	       JJY-01 ( Firmware version 2.01 )			      */
74285612Sdelphij/*	       Thanks to Andy Taki for testing under FreeBSD	      */
75285612Sdelphij/*								      */
76285612Sdelphij/*  2004/11/28							      */
77285612Sdelphij/*    [Add]    Support the Echo Keisokuki LT-2000 receiver	      */
78285612Sdelphij/*								      */
79285612Sdelphij/*  2006/11/04							      */
80285612Sdelphij/*    [Fix]    C-DEX JST2000					      */
81285612Sdelphij/*	       Thanks to Hideo Kuramatsu for the patch		      */
82285612Sdelphij/*								      */
83285612Sdelphij/*  2009/04/05							      */
84285612Sdelphij/*    [Add]    Support the CITIZEN T.I.C JJY-200 receiver	      */
85285612Sdelphij/*								      */
86285612Sdelphij/*  2010/11/20							      */
87285612Sdelphij/*    [Change] Bug 1618 ( Harmless )				      */
88285612Sdelphij/*	       Code clean up ( Remove unreachable codes ) in	      */
89285612Sdelphij/*	       jjy_start()					      */
90285612Sdelphij/*    [Change] Change clockstats format of the Tristate JJY01/02      */
91285612Sdelphij/*	       Issues more command to get the status of the receiver  */
92285612Sdelphij/*	       when "fudge 127.127.40.X flag1 1" is specified	      */
93285612Sdelphij/*	       ( DATE,STIM -> DCST,STUS,DATE,STIM )		      */
94285612Sdelphij/*								      */
95285612Sdelphij/*  2011/04/30							      */
96285612Sdelphij/*    [Add]    Support the Tristate Ltd. TS-GPSclock-01		      */
97285612Sdelphij/*								      */
98285612Sdelphij/*  2015/03/29							      */
99285612Sdelphij/*    [Add]    Support the Telephone JJY			      */
100285612Sdelphij/*    [Change] Split the start up routine into each JJY receivers.    */
101285612Sdelphij/*             Change raw data internal bufferring process            */
102285612Sdelphij/*             Change over midnight handling of TS-JJY01 and TS-GPS01 */
103285612Sdelphij/*             to put DATE command between before and after TIME's.   */
104285612Sdelphij/*             Unify the writing clockstats of all JJY receivers.     */
105285612Sdelphij/*								      */
106285612Sdelphij/*  2015/05/15							      */
107285612Sdelphij/*    [Add]    Support the SEIKO TIME SYSTEMS TDC-300		      */
108285612Sdelphij/*								      */
109310419Sdelphij/*  2016/05/08							      */
110310419Sdelphij/*    [Fix]    C-DEX JST2000                                          */
111310419Sdelphij/*             Thanks to Mr. Kuramatsu for the report and the patch.  */
112310419Sdelphij/*								      */
113330567Sgordon/*  2017/04/30							      */
114330567Sgordon/*    [Change] Avoid a wrong report of the coverity static analysis   */
115330567Sgordon/*             tool. ( The code is harmless and has no bug. )	      */
116330567Sgordon/*             teljjy_conn_send()				      */
117330567Sgordon/*								      */
118106163Sroberto/**********************************************************************/
119106163Sroberto
120106163Sroberto#ifdef HAVE_CONFIG_H
121106163Sroberto#include <config.h>
122106163Sroberto#endif
123106163Sroberto
124106163Sroberto#if defined(REFCLOCK) && defined(CLOCK_JJY)
125106163Sroberto
126106163Sroberto#include <stdio.h>
127106163Sroberto#include <ctype.h>
128106163Sroberto#include <string.h>
129106163Sroberto#include <sys/time.h>
130106163Sroberto#include <time.h>
131106163Sroberto
132106163Sroberto#include "ntpd.h"
133106163Sroberto#include "ntp_io.h"
134106163Sroberto#include "ntp_tty.h"
135106163Sroberto#include "ntp_refclock.h"
136106163Sroberto#include "ntp_calendar.h"
137106163Sroberto#include "ntp_stdlib.h"
138106163Sroberto
139106163Sroberto/**********************************************************************/
140106163Sroberto
141106163Sroberto/*
142106163Sroberto * Interface definitions
143106163Sroberto */
144285612Sdelphij#define	DEVICE  	"/dev/jjy%d"	/* device name and unit */
145285612Sdelphij#define	SPEED232_TRISTATE_JJY01		B9600   /* UART speed (9600 baud) */
146285612Sdelphij#define	SPEED232_CDEX_JST2000		B9600   /* UART speed (9600 baud) */
147285612Sdelphij#define	SPEED232_ECHOKEISOKUKI_LT2000	B9600   /* UART speed (9600 baud) */
148285612Sdelphij#define	SPEED232_CITIZENTIC_JJY200	B4800   /* UART speed (4800 baud) */
149285612Sdelphij#define	SPEED232_TRISTATE_GPSCLOCK01	B38400  /* USB  speed (38400 baud) */
150285612Sdelphij#define	SPEED232_SEIKO_TIMESYS_TDC_300	B2400   /* UART speed (2400 baud) */
151285612Sdelphij#define	SPEED232_TELEPHONE		B2400   /* UART speed (4800 baud) */
152285612Sdelphij#define	REFID   	"JJY"		/* reference ID */
153106163Sroberto#define	DESCRIPTION	"JJY Receiver"
154285612Sdelphij#define	PRECISION	(-3)		/* precision assumed (about 100 ms) */
155106163Sroberto
156106163Sroberto/*
157106163Sroberto * JJY unit control structure
158106163Sroberto */
159285612Sdelphij
160285612Sdelphijstruct jjyRawDataBreak {
161294569Sdelphij	const char *	pString ;
162294569Sdelphij	int 		iLength ;
163285612Sdelphij} ;
164285612Sdelphij
165285612Sdelphij#define	MAX_TIMESTAMP	6
166285612Sdelphij#define	MAX_RAWBUF   	100
167285612Sdelphij#define	MAX_LOOPBACK	5
168285612Sdelphij
169106163Srobertostruct jjyunit {
170285612Sdelphij/* Set up by the function "jjy_start_xxxxxxxx" */
171285612Sdelphij	char	unittype ;	    /* UNITTYPE_XXXXXXXXXX */
172285612Sdelphij	short   operationmode ;	    /* Echo Keisokuki LT-2000 */
173285612Sdelphij	int 	linespeed ;         /* SPEED232_XXXXXXXXXX */
174285612Sdelphij	short	linediscipline ;    /* LDISC_CLK or LDISC_RAW */
175285612Sdelphij/* Receiving data */
176285612Sdelphij	char	bInitError ;        /* Set by jjy_start if any error during initialization */
177285612Sdelphij	short	iProcessState ;     /* JJY_PROCESS_STATE_XXXXXX */
178285612Sdelphij	char	bReceiveFlag ;      /* Set and reset by jjy_receive */
179285612Sdelphij	char	bLineError ;	    /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/
180285612Sdelphij	short	iCommandSeq ;       /* 0:Idle  Non-Zero:Issued */
181285612Sdelphij	short	iReceiveSeq ;
182285612Sdelphij	int 	iLineCount ;
183106163Sroberto	int 	year, month, day, hour, minute, second, msecond ;
184285612Sdelphij	int 	leapsecond ;
185285612Sdelphij	int 	iTimestampCount ;   /* TS-JJY01, TS-GPS01, Telephone-JJY */
186285612Sdelphij	int 	iTimestamp [ MAX_TIMESTAMP ] ;  /* Serial second ( 0 - 86399 ) */
187106163Sroberto/* LDISC_RAW only */
188285612Sdelphij	char	sRawBuf [ MAX_RAWBUF ] ;
189285612Sdelphij	int 	iRawBufLen ;
190285612Sdelphij	struct	jjyRawDataBreak *pRawBreak ;
191285612Sdelphij	char	bWaitBreakString ;
192285612Sdelphij	char	sLineBuf [ MAX_RAWBUF ] ;
193285612Sdelphij	int 	iLineBufLen ;
194285612Sdelphij	char	sTextBuf [ MAX_RAWBUF ] ;
195285612Sdelphij	int 	iTextBufLen ;
196285612Sdelphij	char	bSkipCntrlCharOnly ;
197285612Sdelphij/* Telephone JJY auto measurement of the loopback delay */
198285612Sdelphij	char	bLoopbackMode ;
199285612Sdelphij	short	iLoopbackCount ;
200285612Sdelphij	struct	timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ;
201285612Sdelphij	char	bLoopbackTimeout[MAX_LOOPBACK] ;
202285612Sdelphij	short	iLoopbackValidCount ;
203285612Sdelphij/* Telephone JJY timer */
204285612Sdelphij	short	iTeljjySilentTimer ;
205285612Sdelphij	short	iTeljjyStateTimer ;
206285612Sdelphij/* Telephone JJY control finite state machine */
207285612Sdelphij	short	iClockState ;
208285612Sdelphij	short	iClockEvent ;
209285612Sdelphij	short	iClockCommandSeq ;
210285612Sdelphij/* Modem timer */
211285612Sdelphij	short	iModemSilentCount ;
212285612Sdelphij	short	iModemSilentTimer ;
213285612Sdelphij	short	iModemStateTimer ;
214285612Sdelphij/* Modem control finite state machine */
215285612Sdelphij	short	iModemState ;
216285612Sdelphij	short	iModemEvent ;
217285612Sdelphij	short	iModemCommandSeq ;
218106163Sroberto};
219106163Sroberto
220285612Sdelphij#define	UNITTYPE_TRISTATE_JJY01		1
221285612Sdelphij#define	UNITTYPE_CDEX_JST2000		2
222182007Sroberto#define	UNITTYPE_ECHOKEISOKUKI_LT2000  	3
223200576Sroberto#define	UNITTYPE_CITIZENTIC_JJY200  	4
224285612Sdelphij#define	UNITTYPE_TRISTATE_GPSCLOCK01	5
225285612Sdelphij#define	UNITTYPE_SEIKO_TIMESYS_TDC_300	6
226285612Sdelphij#define	UNITTYPE_TELEPHONE		100
227106163Sroberto
228285612Sdelphij#define	JJY_PROCESS_STATE_IDLE   	0
229285612Sdelphij#define	JJY_PROCESS_STATE_POLL   	1
230285612Sdelphij#define	JJY_PROCESS_STATE_RECEIVE	2
231285612Sdelphij#define	JJY_PROCESS_STATE_DONE   	3
232285612Sdelphij#define	JJY_PROCESS_STATE_ERROR  	4
233285612Sdelphij
234285612Sdelphij/**********************************************************************/
235285612Sdelphij
236106163Sroberto/*
237285612Sdelphij *  Function calling structure
238285612Sdelphij *
239285612Sdelphij *  jjy_start
240285612Sdelphij *   |--  jjy_start_tristate_jjy01
241285612Sdelphij *   |--  jjy_start_cdex_jst2000
242285612Sdelphij *   |--  jjy_start_echokeisokuki_lt2000
243285612Sdelphij *   |--  jjy_start_citizentic_jjy200
244285612Sdelphij *   |--  jjy_start_tristate_gpsclock01
245285612Sdelphij *   |--  jjy_start_seiko_tsys_tdc_300
246285612Sdelphij *   |--  jjy_start_telephone
247285612Sdelphij *
248285612Sdelphij *  jjy_shutdown
249285612Sdelphij *
250285612Sdelphij *  jjy_poll
251285612Sdelphij *   |--  jjy_poll_tristate_jjy01
252285612Sdelphij *   |--  jjy_poll_cdex_jst2000
253285612Sdelphij *   |--  jjy_poll_echokeisokuki_lt2000
254285612Sdelphij *   |--  jjy_poll_citizentic_jjy200
255285612Sdelphij *   |--  jjy_poll_tristate_gpsclock01
256285612Sdelphij *   |--  jjy_poll_seiko_tsys_tdc_300
257285612Sdelphij *   |--  jjy_poll_telephone
258285612Sdelphij *         |--  teljjy_control
259285612Sdelphij *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
260285612Sdelphij *                     |--  modem_connect
261285612Sdelphij *                           |--  modem_control
262285612Sdelphij *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
263285612Sdelphij *
264285612Sdelphij *  jjy_receive
265285612Sdelphij *   |
266285612Sdelphij *   |--  jjy_receive_tristate_jjy01
267285612Sdelphij *   |     |--  jjy_synctime
268285612Sdelphij *   |--  jjy_receive_cdex_jst2000
269285612Sdelphij *   |     |--  jjy_synctime
270285612Sdelphij *   |--  jjy_receive_echokeisokuki_lt2000
271285612Sdelphij *   |     |--  jjy_synctime
272285612Sdelphij *   |--  jjy_receive_citizentic_jjy200
273285612Sdelphij *   |     |--  jjy_synctime
274285612Sdelphij *   |--  jjy_receive_tristate_gpsclock01
275285612Sdelphij *   |     |--  jjy_synctime
276285612Sdelphij *   |--  jjy_receive_seiko_tsys_tdc_300
277285612Sdelphij *   |     |--  jjy_synctime
278285612Sdelphij *   |--  jjy_receive_telephone
279285612Sdelphij *         |--  modem_receive
280285612Sdelphij *         |     |--  modem_control
281285612Sdelphij *         |           |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
282285612Sdelphij *         |--  teljjy_control
283285612Sdelphij *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
284285612Sdelphij *                     |--  jjy_synctime
285285612Sdelphij *                     |--  modem_disconnect
286285612Sdelphij *                           |--  modem_control
287285612Sdelphij *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
288285612Sdelphij *
289285612Sdelphij *  jjy_timer
290285612Sdelphij *   |--  jjy_timer_telephone
291285612Sdelphij *         |--  modem_timer
292285612Sdelphij *         |     |--  modem_control
293285612Sdelphij *         |           |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
294285612Sdelphij *         |--  teljjy_control
295285612Sdelphij *               |--  teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
296285612Sdelphij *                     |--  modem_disconnect
297285612Sdelphij *                           |--  modem_control
298285612Sdelphij *                                 |--  modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
299285612Sdelphij *
300106163Sroberto * Function prototypes
301106163Sroberto */
302106163Sroberto
303285612Sdelphijstatic	int 	jjy_start			(int, struct peer *);
304285612Sdelphijstatic	int 	jjy_start_tristate_jjy01	(int, struct peer *, struct jjyunit *);
305285612Sdelphijstatic	int 	jjy_start_cdex_jst2000		(int, struct peer *, struct jjyunit *);
306285612Sdelphijstatic	int 	jjy_start_echokeisokuki_lt2000	(int, struct peer *, struct jjyunit *);
307285612Sdelphijstatic	int 	jjy_start_citizentic_jjy200	(int, struct peer *, struct jjyunit *);
308285612Sdelphijstatic	int 	jjy_start_tristate_gpsclock01	(int, struct peer *, struct jjyunit *);
309285612Sdelphijstatic	int 	jjy_start_seiko_tsys_tdc_300	(int, struct peer *, struct jjyunit *);
310285612Sdelphijstatic	int 	jjy_start_telephone		(int, struct peer *, struct jjyunit *);
311285612Sdelphij
312285612Sdelphijstatic	void	jjy_shutdown			(int, struct peer *);
313285612Sdelphij
314285612Sdelphijstatic	void	jjy_poll		    	(int, struct peer *);
315285612Sdelphijstatic	void	jjy_poll_tristate_jjy01	    	(int, struct peer *);
316285612Sdelphijstatic	void	jjy_poll_cdex_jst2000	    	(int, struct peer *);
317285612Sdelphijstatic	void	jjy_poll_echokeisokuki_lt2000	(int, struct peer *);
318285612Sdelphijstatic	void	jjy_poll_citizentic_jjy200	(int, struct peer *);
319285612Sdelphijstatic	void	jjy_poll_tristate_gpsclock01	(int, struct peer *);
320285612Sdelphijstatic	void	jjy_poll_seiko_tsys_tdc_300	(int, struct peer *);
321285612Sdelphijstatic	void	jjy_poll_telephone		(int, struct peer *);
322285612Sdelphij
323285612Sdelphijstatic	void	jjy_receive			(struct recvbuf *);
324285612Sdelphijstatic	int 	jjy_receive_tristate_jjy01	(struct recvbuf *);
325285612Sdelphijstatic	int 	jjy_receive_cdex_jst2000	(struct recvbuf *);
326285612Sdelphijstatic	int 	jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
327285612Sdelphijstatic  int 	jjy_receive_citizentic_jjy200	(struct recvbuf *);
328285612Sdelphijstatic	int 	jjy_receive_tristate_gpsclock01	(struct recvbuf *);
329285612Sdelphijstatic	int 	jjy_receive_seiko_tsys_tdc_300	(struct recvbuf *);
330285612Sdelphijstatic	int 	jjy_receive_telephone		(struct recvbuf *);
331285612Sdelphij
332285612Sdelphijstatic	void	jjy_timer			(int, struct peer *);
333285612Sdelphijstatic	void	jjy_timer_telephone		(int, struct peer *);
334285612Sdelphij
335285612Sdelphijstatic	void	jjy_synctime			( struct peer *, struct refclockproc *, struct jjyunit * ) ;
336285612Sdelphijstatic	void	jjy_write_clockstats		( struct peer *, int, const char* ) ;
337285612Sdelphij
338285612Sdelphijstatic	int 	getRawDataBreakPosition		( struct jjyunit *, int ) ;
339285612Sdelphij
340285612Sdelphijstatic	short	getModemState			( struct jjyunit * ) ;
341285612Sdelphijstatic	int 	isModemStateConnect		( short ) ;
342285612Sdelphijstatic	int 	isModemStateDisconnect		( short ) ;
343285612Sdelphijstatic	int 	isModemStateTimerOn		( struct jjyunit * ) ;
344285612Sdelphijstatic	void	modem_connect			( int, struct peer * ) ;
345285612Sdelphijstatic	void	modem_disconnect		( int, struct peer * ) ;
346285612Sdelphijstatic	int 	modem_receive			( struct recvbuf * ) ;
347285612Sdelphijstatic	void	modem_timer			( int, struct peer * );
348285612Sdelphij
349285612Sdelphijstatic	void	printableString ( char*, int, const char*, int ) ;
350285612Sdelphij
351106163Sroberto/*
352106163Sroberto * Transfer vector
353106163Sroberto */
354106163Srobertostruct	refclock refclock_jjy = {
355285612Sdelphij	jjy_start,	/* start up driver */
356285612Sdelphij	jjy_shutdown,	/* shutdown driver */
357285612Sdelphij	jjy_poll,	/* transmit poll message */
358285612Sdelphij	noentry,	/* not used */
359285612Sdelphij	noentry,	/* not used */
360285612Sdelphij	noentry,	/* not used */
361285612Sdelphij	jjy_timer	/* 1 second interval timer */
362106163Sroberto};
363106163Sroberto
364106163Sroberto/*
365106163Sroberto * Start up driver return code
366106163Sroberto */
367106163Sroberto#define	RC_START_SUCCESS	1
368285612Sdelphij#define	RC_START_ERROR		0
369106163Sroberto
370106163Sroberto/*
371106163Sroberto * Local constants definition
372106163Sroberto */
373106163Sroberto
374285612Sdelphij#define	MAX_LOGTEXT	100
375106163Sroberto
376285612Sdelphij#ifndef	TRUE
377285612Sdelphij#define	TRUE	(0==0)
378285612Sdelphij#endif
379285612Sdelphij#ifndef	FALSE
380285612Sdelphij#define	FALSE	(!TRUE)
381285612Sdelphij#endif
382106163Sroberto
383285612Sdelphij/* Local constants definition for the return code of the jjy_receive_xxxxxxxx */
384285612Sdelphij
385285612Sdelphij#define	JJY_RECEIVE_DONE	0
386285612Sdelphij#define	JJY_RECEIVE_SKIP	1
387285612Sdelphij#define	JJY_RECEIVE_UNPROCESS	2
388285612Sdelphij#define	JJY_RECEIVE_WAIT	3
389285612Sdelphij#define	JJY_RECEIVE_ERROR	4
390285612Sdelphij
391285612Sdelphij/* Local constants definition for the 2nd parameter of the jjy_write_clockstats */
392285612Sdelphij
393285612Sdelphij#define	JJY_CLOCKSTATS_MARK_NONE	0
394285612Sdelphij#define	JJY_CLOCKSTATS_MARK_JJY 	1
395285612Sdelphij#define	JJY_CLOCKSTATS_MARK_SEND	2
396285612Sdelphij#define	JJY_CLOCKSTATS_MARK_RECEIVE	3
397285612Sdelphij#define	JJY_CLOCKSTATS_MARK_INFORMATION	4
398285612Sdelphij#define	JJY_CLOCKSTATS_MARK_ATTENTION	5
399285612Sdelphij#define	JJY_CLOCKSTATS_MARK_WARNING	6
400285612Sdelphij#define	JJY_CLOCKSTATS_MARK_ERROR	7
401330567Sgordon#define	JJY_CLOCKSTATS_MARK_BUG 	8
402285612Sdelphij
403285612Sdelphij/* Local constants definition for the clockstats messages */
404285612Sdelphij
405285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_ECHOBACK         	"* Echoback"
406285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY     	"* Ignore replay : [%s]"
407285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2  	"* Over midnight : timestamp=%d, %d"
408285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3  	"* Over midnight : timestamp=%d, %d, %d"
409285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE 	"* Unsure timestamp : %s"
410285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY   	"* Loopback delay : %d.%03d mSec."
411285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST     	"* Delay adjustment : %d mSec. ( valid=%hd/%d )"
412285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST   	"* Delay adjustment : None ( valid=%hd/%d )"
413285612Sdelphij
414285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY     	"# Unexpected reply : [%s]"
415285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH     	"# Invalid length : length=%d"
416285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY     	"# Too many reply : count=%d"
417285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY      	"# Invalid reply : [%s]"
418285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2       	"# Slow reply : timestamp=%d, %d"
419285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3       	"# Slow reply : timestamp=%d, %d, %d"
420285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE	"# Invalid date : rc=%d year=%d month=%d day=%d"
421285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME	"# Invalid time : rc=%d hour=%d minute=%d second=%d"
422285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME	"# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d"
423285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP	"# Invalid leap : leapsecond=[%s]"
424285612Sdelphij#define	JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS	"# Invalid status : status=[%s]"
425285612Sdelphij
426285612Sdelphij/* Debug print macro */
427285612Sdelphij
428285612Sdelphij#ifdef	DEBUG
429285612Sdelphij#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 ) ; } }
430285612Sdelphij#else
431285612Sdelphij#define	DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)
432285612Sdelphij#endif
433285612Sdelphij
434106163Sroberto/**************************************************************************************************/
435106163Sroberto/*  jjy_start - open the devices and initialize data for processing                               */
436106163Sroberto/**************************************************************************************************/
437106163Srobertostatic int
438106163Srobertojjy_start ( int unit, struct peer *peer )
439106163Sroberto{
440106163Sroberto
441285612Sdelphij	struct	refclockproc *pp ;
442285612Sdelphij	struct	jjyunit      *up ;
443285612Sdelphij	int 	rc ;
444106163Sroberto	int 	fd ;
445285612Sdelphij	char	sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ;
446106163Sroberto
447106163Sroberto#ifdef DEBUG
448106163Sroberto	if ( debug ) {
449285612Sdelphij		printf( "refclock_jjy.c : jjy_start : %s  mode=%d  dev=%s  unit=%d\n",
450285612Sdelphij			 ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ;
451106163Sroberto	}
452106163Sroberto#endif
453106163Sroberto
454285612Sdelphij	/* Allocate memory for the unit structure */
455285612Sdelphij	up = emalloc( sizeof(*up) ) ;
456285612Sdelphij	if ( up == NULL ) {
457285612Sdelphij		msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ;
458106163Sroberto		return RC_START_ERROR ;
459106163Sroberto	}
460285612Sdelphij	memset ( up, 0, sizeof(*up) ) ;
461106163Sroberto
462285612Sdelphij	up->bInitError = FALSE ;
463285612Sdelphij	up->iProcessState = JJY_PROCESS_STATE_IDLE ;
464285612Sdelphij	up->bReceiveFlag = FALSE ;
465285612Sdelphij	up->iCommandSeq = 0 ;
466285612Sdelphij	up->iLineCount = 0 ;
467285612Sdelphij	up->iTimestampCount = 0 ;
468285612Sdelphij	up->bWaitBreakString = FALSE ;
469285612Sdelphij	up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ;
470285612Sdelphij	up->bSkipCntrlCharOnly = TRUE ;
471106163Sroberto
472285612Sdelphij	/* Set up the device name */
473285612Sdelphij	snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ;
474106163Sroberto
475285612Sdelphij	snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ;
476285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
477106163Sroberto
478106163Sroberto	/*
479132451Sroberto	 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
480106163Sroberto	 */
481132451Sroberto	switch ( peer->ttl ) {
482106163Sroberto	case 0 :
483106163Sroberto	case 1 :
484285612Sdelphij		rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ;
485106163Sroberto		break ;
486106163Sroberto	case 2 :
487285612Sdelphij		rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ;
488106163Sroberto		break ;
489182007Sroberto	case 3 :
490285612Sdelphij		rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ;
491182007Sroberto		break ;
492285612Sdelphij	case 4 :
493285612Sdelphij		rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ;
494285612Sdelphij		break ;
495285612Sdelphij	case 5 :
496285612Sdelphij		rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ;
497285612Sdelphij		break ;
498285612Sdelphij	case 6 :
499285612Sdelphij		rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ;
500285612Sdelphij		break ;
501285612Sdelphij	case 100 :
502285612Sdelphij		rc = jjy_start_telephone ( unit, peer, up ) ;
503285612Sdelphij		break ;
504106163Sroberto	default :
505285612Sdelphij		if ( 101 <= peer->ttl && peer->ttl <= 180 ) {
506285612Sdelphij			rc = jjy_start_telephone ( unit, peer, up ) ;
507285612Sdelphij		} else {
508285612Sdelphij			msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
509285612Sdelphij				  ntoa(&peer->srcadr), peer->ttl ) ;
510285612Sdelphij			free ( (void*) up ) ;
511285612Sdelphij		return RC_START_ERROR ;
512285612Sdelphij		}
513285612Sdelphij	}
514285612Sdelphij
515285612Sdelphij	if ( rc != 0 ) {
516285612Sdelphij		msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error",
517285612Sdelphij			  ntoa(&peer->srcadr), peer->ttl ) ;
518106163Sroberto		free ( (void*) up ) ;
519106163Sroberto		return RC_START_ERROR ;
520106163Sroberto	}
521106163Sroberto
522285612Sdelphij	/* Open the device */
523285612Sdelphij	fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ;
524285612Sdelphij	if ( fd <= 0 ) {
525285612Sdelphij		free ( (void*) up ) ;
526285612Sdelphij		return RC_START_ERROR ;
527285612Sdelphij	}
528285612Sdelphij
529285612Sdelphij	/*
530285612Sdelphij	 * Initialize variables
531285612Sdelphij	 */
532106163Sroberto	pp = peer->procptr ;
533285612Sdelphij
534285612Sdelphij	pp->clockdesc	= DESCRIPTION ;
535285612Sdelphij	pp->unitptr       = up ;
536106163Sroberto	pp->io.clock_recv = jjy_receive ;
537285612Sdelphij	pp->io.srcclock   = peer ;
538285612Sdelphij	pp->io.datalen	  = 0 ;
539285612Sdelphij	pp->io.fd	  = fd ;
540106163Sroberto	if ( ! io_addclock(&pp->io) ) {
541106163Sroberto		close ( fd ) ;
542285612Sdelphij		pp->io.fd = -1 ;
543285612Sdelphij		free ( up ) ;
544285612Sdelphij		pp->unitptr = NULL ;
545106163Sroberto		return RC_START_ERROR ;
546106163Sroberto	}
547285612Sdelphij	memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ;
548106163Sroberto
549106163Sroberto	peer->precision = PRECISION ;
550106163Sroberto
551285612Sdelphij	snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ;
552285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
553285612Sdelphij
554106163Sroberto	return RC_START_SUCCESS ;
555106163Sroberto
556106163Sroberto}
557106163Sroberto
558106163Sroberto/**************************************************************************************************/
559106163Sroberto/*  jjy_shutdown - shutdown the clock                                                             */
560106163Sroberto/**************************************************************************************************/
561106163Srobertostatic void
562106163Srobertojjy_shutdown ( int unit, struct peer *peer )
563106163Sroberto{
564106163Sroberto
565285612Sdelphij	struct jjyunit	    *up;
566106163Sroberto	struct refclockproc *pp;
567106163Sroberto
568285612Sdelphij	char	sLog [ 60 ] ;
569285612Sdelphij
570106163Sroberto	pp = peer->procptr ;
571285612Sdelphij	up = pp->unitptr ;
572285612Sdelphij	if ( -1 != pp->io.fd ) {
573285612Sdelphij		io_closeclock ( &pp->io ) ;
574285612Sdelphij	}
575285612Sdelphij	if ( NULL != up ) {
576285612Sdelphij		free ( up ) ;
577285612Sdelphij	}
578106163Sroberto
579285612Sdelphij	snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ;
580285612Sdelphij	record_clock_stats( &peer->srcadr, sLog ) ;
581285612Sdelphij
582106163Sroberto}
583106163Sroberto
584106163Sroberto/**************************************************************************************************/
585106163Sroberto/*  jjy_receive - receive data from the serial interface                                          */
586106163Sroberto/**************************************************************************************************/
587106163Srobertostatic void
588106163Srobertojjy_receive ( struct recvbuf *rbufp )
589106163Sroberto{
590285612Sdelphij#ifdef DEBUG
591285612Sdelphij	static const char *sFunctionName = "jjy_receive" ;
592285612Sdelphij#endif
593106163Sroberto
594285612Sdelphij	struct jjyunit	    *up ;
595106163Sroberto	struct refclockproc *pp ;
596285612Sdelphij	struct peer	    *peer;
597106163Sroberto
598106163Sroberto	l_fp	tRecvTimestamp;		/* arrival timestamp */
599106163Sroberto	int 	rc ;
600285612Sdelphij	char	*pBuf, sLogText [ MAX_LOGTEXT ] ;
601316722Sdelphij	size_t 	iLen, iCopyLen ;
602285612Sdelphij	int 	i, j, iReadRawBuf, iBreakPosition ;
603106163Sroberto
604106163Sroberto	/*
605106163Sroberto	 * Initialize pointers and read the timecode and timestamp
606106163Sroberto	 */
607285612Sdelphij	peer = rbufp->recv_peer ;
608106163Sroberto	pp = peer->procptr ;
609285612Sdelphij	up = pp->unitptr ;
610106163Sroberto
611106163Sroberto	/*
612106163Sroberto	 * Get next input line
613106163Sroberto	 */
614285612Sdelphij	if ( up->linediscipline == LDISC_RAW ) {
615106163Sroberto
616285612Sdelphij		pp->lencode  = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ;
617285612Sdelphij		/* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions  (OVERRUN)" */
618285612Sdelphij		/* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */
619285612Sdelphij		/* To avoid its claim, pass the value BMAX-1. */
620285612Sdelphij
621106163Sroberto		/*
622285612Sdelphij		 * Append received charaters to temporary buffer
623106163Sroberto		 */
624285612Sdelphij		for ( i = 0 ;
625285612Sdelphij		      i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ;
626285612Sdelphij		      i ++ , up->iRawBufLen ++ ) {
627285612Sdelphij			up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ;
628106163Sroberto		}
629285612Sdelphij		up->sRawBuf[up->iRawBufLen] = 0 ;
630285612Sdelphij
631285612Sdelphij
632285612Sdelphij	} else {
633285612Sdelphij
634285612Sdelphij		pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
635285612Sdelphij
636285612Sdelphij	}
637285612Sdelphij#ifdef DEBUG
638285612Sdelphij	printf( "\nrefclock_jjy.c : %s : Len=%d  ", sFunctionName, pp->lencode ) ;
639285612Sdelphij	for ( i = 0 ; i < pp->lencode ; i ++ ) {
640294569Sdelphij		if ( iscntrl( (u_char)(pp->a_lastcode[i] & 0x7F) ) ) {
641285612Sdelphij			printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ;
642285612Sdelphij		} else {
643285612Sdelphij			printf( "%c", pp->a_lastcode[i] ) ;
644106163Sroberto		}
645285612Sdelphij	}
646285612Sdelphij	printf( "\n" ) ;
647285612Sdelphij#endif
648285612Sdelphij
649285612Sdelphij	/*
650285612Sdelphij	 * The reply with <CR><LF> gives a blank line
651285612Sdelphij	 */
652285612Sdelphij
653285612Sdelphij	if ( pp->lencode == 0 ) return ;
654285612Sdelphij
655285612Sdelphij	/*
656285612Sdelphij	 * Receiving data is not expected
657285612Sdelphij	 */
658285612Sdelphij
659285612Sdelphij	if ( up->iProcessState == JJY_PROCESS_STATE_IDLE
660285612Sdelphij	  || up->iProcessState == JJY_PROCESS_STATE_DONE
661285612Sdelphij	  || up->iProcessState == JJY_PROCESS_STATE_ERROR ) {
662285612Sdelphij		/* Discard received data */
663285612Sdelphij		up->iRawBufLen = 0 ;
664285612Sdelphij#ifdef DEBUG
665285612Sdelphij		if ( debug ) {
666285612Sdelphij			printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ;
667285612Sdelphij		}
668285612Sdelphij#endif
669285612Sdelphij		return ;
670285612Sdelphij	}
671285612Sdelphij
672285612Sdelphij	/*
673285612Sdelphij	 * We get down to business
674285612Sdelphij	 */
675285612Sdelphij
676285612Sdelphij	pp->lastrec = tRecvTimestamp ;
677285612Sdelphij
678285612Sdelphij	up->iLineCount ++ ;
679285612Sdelphij
680285612Sdelphij	up->iProcessState = JJY_PROCESS_STATE_RECEIVE ;
681285612Sdelphij	up->bReceiveFlag = TRUE ;
682285612Sdelphij
683285612Sdelphij	iReadRawBuf = 0 ;
684285612Sdelphij	iBreakPosition = up->iRawBufLen - 1 ;
685285612Sdelphij	for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) {
686285612Sdelphij
687285612Sdelphij		if ( up->linediscipline == LDISC_RAW ) {
688285612Sdelphij
689285612Sdelphij			if ( up->bWaitBreakString ) {
690285612Sdelphij				iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ;
691285612Sdelphij				if ( iBreakPosition == -1 ) {
692285612Sdelphij					/* Break string have not come yet */
693285612Sdelphij					if ( up->iRawBufLen < MAX_RAWBUF - 2
694285612Sdelphij					  || iReadRawBuf > 0 ) {
695285612Sdelphij						/* Temporary buffer is not full */
696285612Sdelphij						break ;
697285612Sdelphij					} else {
698285612Sdelphij						/* Temporary buffer is full */
699285612Sdelphij						iBreakPosition = up->iRawBufLen - 1 ;
700285612Sdelphij					}
701285612Sdelphij				}
702285612Sdelphij			} else {
703285612Sdelphij				iBreakPosition = up->iRawBufLen - 1 ;
704285612Sdelphij			}
705285612Sdelphij
706285612Sdelphij			/* Copy charaters from temporary buffer to process buffer */
707285612Sdelphij			up->iLineBufLen = up->iTextBufLen = 0 ;
708285612Sdelphij			for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) {
709285612Sdelphij
710285612Sdelphij				/* Copy all characters */
711285612Sdelphij				up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ;
712285612Sdelphij				up->iLineBufLen ++ ;
713285612Sdelphij
714285612Sdelphij				/* Copy printable characters */
715294569Sdelphij				if ( ! iscntrl( (u_char)up->sRawBuf[i] ) ) {
716285612Sdelphij					up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ;
717285612Sdelphij					up->iTextBufLen ++ ;
718285612Sdelphij				}
719285612Sdelphij
720285612Sdelphij			}
721285612Sdelphij			up->sLineBuf[up->iLineBufLen] = 0 ;
722285612Sdelphij			up->sTextBuf[up->iTextBufLen] = 0 ;
723285612Sdelphij#ifdef DEBUG
724285612Sdelphij			printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n",
725285612Sdelphij				 sFunctionName, up->iLineBufLen, up->iTextBufLen ) ;
726285612Sdelphij#endif
727285612Sdelphij
728285612Sdelphij			if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) {
729285612Sdelphij#ifdef DEBUG
730285612Sdelphij				printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n",
731285612Sdelphij					 sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ;
732285612Sdelphij#endif
733285612Sdelphij				if ( iBreakPosition + 1 < up->iRawBufLen ) {
734285612Sdelphij					iReadRawBuf = iBreakPosition + 1 ;
735285612Sdelphij					continue ;
736285612Sdelphij				} else {
737285612Sdelphij					break ;
738285612Sdelphij				}
739285612Sdelphij
740285612Sdelphij			}
741285612Sdelphij
742285612Sdelphij		}
743285612Sdelphij
744285612Sdelphij		if ( up->linediscipline == LDISC_RAW ) {
745285612Sdelphij			pBuf = up->sLineBuf ;
746285612Sdelphij			iLen = up->iLineBufLen ;
747285612Sdelphij		} else {
748285612Sdelphij			pBuf = pp->a_lastcode ;
749285612Sdelphij			iLen = pp->lencode ;
750285612Sdelphij		}
751285612Sdelphij
752285612Sdelphij		iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ;
753316722Sdelphij		memcpy( sLogText, pBuf, iCopyLen ) ;
754316722Sdelphij		sLogText[iCopyLen] = '\0' ;
755285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ;
756285612Sdelphij
757285612Sdelphij		switch ( up->unittype ) {
758285612Sdelphij
759285612Sdelphij		case UNITTYPE_TRISTATE_JJY01 :
760285612Sdelphij			rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
761285612Sdelphij			break ;
762285612Sdelphij
763285612Sdelphij		case UNITTYPE_CDEX_JST2000 :
764285612Sdelphij			rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
765285612Sdelphij			break ;
766285612Sdelphij
767285612Sdelphij		case UNITTYPE_ECHOKEISOKUKI_LT2000 :
768285612Sdelphij			rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
769285612Sdelphij			break ;
770285612Sdelphij
771285612Sdelphij		case UNITTYPE_CITIZENTIC_JJY200 :
772285612Sdelphij			rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
773285612Sdelphij			break ;
774285612Sdelphij
775285612Sdelphij		case UNITTYPE_TRISTATE_GPSCLOCK01 :
776285612Sdelphij			rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
777285612Sdelphij			break ;
778285612Sdelphij
779285612Sdelphij		case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
780285612Sdelphij			rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ;
781285612Sdelphij			break ;
782285612Sdelphij
783285612Sdelphij		case UNITTYPE_TELEPHONE :
784285612Sdelphij			rc = jjy_receive_telephone ( rbufp ) ;
785285612Sdelphij			break ;
786285612Sdelphij
787285612Sdelphij		default :
788285612Sdelphij			rc = JJY_RECEIVE_ERROR ;
789285612Sdelphij			break ;
790285612Sdelphij
791285612Sdelphij		}
792285612Sdelphij
793285612Sdelphij		switch ( rc ) {
794285612Sdelphij		case JJY_RECEIVE_DONE :
795285612Sdelphij		case JJY_RECEIVE_SKIP :
796285612Sdelphij			up->iProcessState = JJY_PROCESS_STATE_DONE ;
797285612Sdelphij			break ;
798285612Sdelphij		case JJY_RECEIVE_ERROR :
799285612Sdelphij			up->iProcessState = JJY_PROCESS_STATE_ERROR ;
800285612Sdelphij			break ;
801285612Sdelphij		default :
802285612Sdelphij			break ;
803285612Sdelphij		}
804285612Sdelphij
805285612Sdelphij		if ( up->linediscipline == LDISC_RAW ) {
806285612Sdelphij			if ( rc == JJY_RECEIVE_UNPROCESS ) {
807106163Sroberto				break ;
808106163Sroberto			}
809285612Sdelphij			iReadRawBuf = iBreakPosition + 1 ;
810285612Sdelphij			if ( iReadRawBuf >= up->iRawBufLen ) {
811285612Sdelphij				/* Processed all received data */
812285612Sdelphij				break ;
813285612Sdelphij			}
814106163Sroberto		}
815285612Sdelphij
816285612Sdelphij		if ( up->linediscipline == LDISC_CLK ) {
817285612Sdelphij			break ;
818106163Sroberto		}
819285612Sdelphij
820285612Sdelphij	}
821285612Sdelphij
822285612Sdelphij	if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) {
823285612Sdelphij		for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) {
824285612Sdelphij			up->sRawBuf[i] = up->sRawBuf[j] ;
825285612Sdelphij		}
826285612Sdelphij		up->iRawBufLen -= iReadRawBuf ;
827285612Sdelphij		if ( up->iRawBufLen < 0 ) {
828285612Sdelphij			up->iRawBufLen = 0 ;
829285612Sdelphij		}
830285612Sdelphij	}
831285612Sdelphij
832285612Sdelphij	up->bReceiveFlag = FALSE ;
833285612Sdelphij
834285612Sdelphij}
835285612Sdelphij
836285612Sdelphij/**************************************************************************************************/
837285612Sdelphij
838285612Sdelphijstatic int
839285612SdelphijgetRawDataBreakPosition ( struct jjyunit *up, int iStart )
840285612Sdelphij{
841285612Sdelphij
842285612Sdelphij	int 	i, j ;
843285612Sdelphij
844285612Sdelphij	if ( iStart >= up->iRawBufLen ) {
845285612Sdelphij#ifdef DEBUG
846285612Sdelphij		printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
847285612Sdelphij#endif
848285612Sdelphij		return -1 ;
849285612Sdelphij	}
850285612Sdelphij
851285612Sdelphij	for ( i = iStart ; i < up->iRawBufLen ; i ++ ) {
852285612Sdelphij
853285612Sdelphij		for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) {
854285612Sdelphij
855285612Sdelphij			if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) {
856285612Sdelphij
857285612Sdelphij				if ( strncmp( up->sRawBuf + i,
858285612Sdelphij					up->pRawBreak[j].pString,
859285612Sdelphij					up->pRawBreak[j].iLength ) == 0 ) {
860285612Sdelphij
861285612Sdelphij#ifdef DEBUG
862285612Sdelphij					printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n",
863285612Sdelphij						iStart, i + up->pRawBreak[j].iLength - 1 ) ;
864285612Sdelphij#endif
865285612Sdelphij					return i + up->pRawBreak[j].iLength - 1 ;
866285612Sdelphij
867285612Sdelphij				}
868285612Sdelphij			}
869285612Sdelphij		}
870285612Sdelphij	}
871285612Sdelphij
872285612Sdelphij#ifdef DEBUG
873285612Sdelphij	printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
874285612Sdelphij#endif
875285612Sdelphij	return -1 ;
876285612Sdelphij
877285612Sdelphij}
878285612Sdelphij
879285612Sdelphij/**************************************************************************************************/
880285612Sdelphij/*  jjy_poll - called by the transmit procedure                                                   */
881285612Sdelphij/**************************************************************************************************/
882285612Sdelphijstatic void
883285612Sdelphijjjy_poll ( int unit, struct peer *peer )
884285612Sdelphij{
885285612Sdelphij
886285612Sdelphij	char	sLog [ 40 ], sReach [ 9 ] ;
887285612Sdelphij
888285612Sdelphij	struct jjyunit      *up;
889285612Sdelphij	struct refclockproc *pp;
890285612Sdelphij
891285612Sdelphij	pp = peer->procptr;
892285612Sdelphij	up = pp->unitptr ;
893285612Sdelphij
894285612Sdelphij	if ( up->bInitError ) {
895285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ;
896285612Sdelphij		return ;
897285612Sdelphij	}
898285612Sdelphij
899285612Sdelphij	if ( pp->polls > 0  &&  up->iLineCount == 0 ) {
900106163Sroberto		/*
901285612Sdelphij		 * No reply for last command
902106163Sroberto		 */
903285612Sdelphij		refclock_report ( peer, CEVNT_TIMEOUT ) ;
904106163Sroberto	}
905106163Sroberto
906285612Sdelphij	pp->polls ++ ;
907106163Sroberto
908285612Sdelphij	sReach[0] = peer->reach & 0x80 ? '1' : '0' ;
909285612Sdelphij	sReach[1] = peer->reach & 0x40 ? '1' : '0' ;
910285612Sdelphij	sReach[2] = peer->reach & 0x20 ? '1' : '0' ;
911285612Sdelphij	sReach[3] = peer->reach & 0x10 ? '1' : '0' ;
912285612Sdelphij	sReach[4] = peer->reach & 0x08 ? '1' : '0' ;
913285612Sdelphij	sReach[5] = peer->reach & 0x04 ? '1' : '0' ;
914285612Sdelphij	sReach[6] = peer->reach & 0x02 ? '1' : '0' ;
915285612Sdelphij	sReach[7] = 0 ; /* This poll */
916285612Sdelphij	sReach[8] = 0 ;
917106163Sroberto
918285612Sdelphij	snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ;
919285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
920106163Sroberto
921285612Sdelphij	up->iProcessState = JJY_PROCESS_STATE_POLL ;
922285612Sdelphij	up->iCommandSeq = 0 ;
923285612Sdelphij	up->iReceiveSeq = 0 ;
924285612Sdelphij	up->iLineCount = 0 ;
925285612Sdelphij	up->bLineError = FALSE ;
926285612Sdelphij	up->iRawBufLen = 0 ;
927285612Sdelphij
928106163Sroberto	switch ( up->unittype ) {
929106163Sroberto
930106163Sroberto	case UNITTYPE_TRISTATE_JJY01 :
931285612Sdelphij		jjy_poll_tristate_jjy01  ( unit, peer ) ;
932106163Sroberto		break ;
933106163Sroberto
934106163Sroberto	case UNITTYPE_CDEX_JST2000 :
935285612Sdelphij		jjy_poll_cdex_jst2000 ( unit, peer ) ;
936106163Sroberto		break ;
937106163Sroberto
938182007Sroberto	case UNITTYPE_ECHOKEISOKUKI_LT2000 :
939285612Sdelphij		jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
940182007Sroberto		break ;
941182007Sroberto
942285612Sdelphij	case UNITTYPE_CITIZENTIC_JJY200 :
943285612Sdelphij		jjy_poll_citizentic_jjy200 ( unit, peer ) ;
944285612Sdelphij		break ;
945200576Sroberto
946285612Sdelphij	case UNITTYPE_TRISTATE_GPSCLOCK01 :
947285612Sdelphij		jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
948285612Sdelphij		break ;
949285612Sdelphij
950285612Sdelphij	case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
951285612Sdelphij		jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ;
952285612Sdelphij		break ;
953285612Sdelphij
954285612Sdelphij	case UNITTYPE_TELEPHONE :
955285612Sdelphij		jjy_poll_telephone ( unit, peer ) ;
956285612Sdelphij		break ;
957285612Sdelphij
958106163Sroberto	default :
959106163Sroberto		break ;
960106163Sroberto
961106163Sroberto	}
962106163Sroberto
963285612Sdelphij}
964285612Sdelphij
965285612Sdelphij/**************************************************************************************************/
966285612Sdelphij/*  jjy_timer - called at one-second intervals                                                    */
967285612Sdelphij/**************************************************************************************************/
968285612Sdelphijstatic void
969285612Sdelphijjjy_timer ( int unit, struct peer *peer )
970285612Sdelphij{
971285612Sdelphij
972285612Sdelphij	struct	refclockproc *pp ;
973285612Sdelphij	struct	jjyunit      *up ;
974285612Sdelphij
975285612Sdelphij#ifdef DEBUG
976285612Sdelphij	if ( debug ) {
977285612Sdelphij		printf ( "refclock_jjy.c : jjy_timer\n" ) ;
978106163Sroberto	}
979285612Sdelphij#endif
980106163Sroberto
981285612Sdelphij	pp = peer->procptr ;
982285612Sdelphij	up = pp->unitptr ;
983106163Sroberto
984285612Sdelphij	if ( up->bReceiveFlag ) {
985285612Sdelphij#ifdef DEBUG
986285612Sdelphij		if ( debug ) {
987285612Sdelphij			printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ;
988106163Sroberto		}
989285612Sdelphij#endif
990106163Sroberto		return ;
991106163Sroberto	}
992106163Sroberto
993285612Sdelphij	switch ( up->unittype ) {
994285612Sdelphij
995285612Sdelphij	case UNITTYPE_TELEPHONE :
996285612Sdelphij		jjy_timer_telephone ( unit, peer ) ;
997285612Sdelphij		break ;
998285612Sdelphij
999285612Sdelphij	default :
1000285612Sdelphij		break ;
1001285612Sdelphij
1002285612Sdelphij	}
1003285612Sdelphij
1004285612Sdelphij}
1005285612Sdelphij
1006285612Sdelphij/**************************************************************************************************/
1007285612Sdelphij/*  jjy_synctime                                                                                  */
1008285612Sdelphij/**************************************************************************************************/
1009285612Sdelphijstatic void
1010285612Sdelphijjjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
1011285612Sdelphij{
1012285612Sdelphij
1013285612Sdelphij	char	sLog [ 80 ], cStatus ;
1014285612Sdelphij	const char	*pStatus ;
1015285612Sdelphij
1016106163Sroberto	pp->year   = up->year ;
1017285612Sdelphij	pp->day    = ymd2yd( up->year, up->month, up->day ) ;
1018106163Sroberto	pp->hour   = up->hour ;
1019106163Sroberto	pp->minute = up->minute ;
1020106163Sroberto	pp->second = up->second ;
1021285612Sdelphij	pp->nsec   = up->msecond * 1000000 ;
1022106163Sroberto
1023106163Sroberto	/*
1024106163Sroberto	 * JST to UTC
1025106163Sroberto	 */
1026106163Sroberto	pp->hour -= 9 ;
1027106163Sroberto	if ( pp->hour < 0 ) {
1028106163Sroberto		pp->hour += 24 ;
1029106163Sroberto		pp->day -- ;
1030106163Sroberto		if ( pp->day < 1 ) {
1031106163Sroberto			pp->year -- ;
1032285612Sdelphij			pp->day  = ymd2yd( pp->year, 12, 31 ) ;
1033106163Sroberto		}
1034106163Sroberto	}
1035285612Sdelphij
1036285612Sdelphij	/*
1037285612Sdelphij	 * Process the new sample in the median filter and determine the
1038285612Sdelphij	 * timecode timestamp.
1039285612Sdelphij	 */
1040285612Sdelphij
1041285612Sdelphij	if ( ! refclock_process( pp ) ) {
1042285612Sdelphij		refclock_report( peer, CEVNT_BADTIME ) ;
1043285612Sdelphij		return ;
1044285612Sdelphij	}
1045285612Sdelphij
1046285612Sdelphij	pp->lastref = pp->lastrec ;
1047285612Sdelphij
1048285612Sdelphij	refclock_receive( peer ) ;
1049285612Sdelphij
1050285612Sdelphij	/*
1051285612Sdelphij	 * Write into the clockstats file
1052285612Sdelphij	 */
1053285612Sdelphij	snprintf ( sLog, sizeof(sLog),
1054285612Sdelphij		   "%04d/%02d/%02d %02d:%02d:%02d.%03d JST   ( %04d/%03d %02d:%02d:%02d.%03d UTC )",
1055285612Sdelphij		   up->year, up->month, up->day,
1056285612Sdelphij		   up->hour, up->minute, up->second, up->msecond,
1057285612Sdelphij		   pp->year, pp->day, pp->hour, pp->minute, pp->second,
1058285612Sdelphij		   (int)(pp->nsec/1000000) ) ;
1059285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
1060285612Sdelphij
1061285612Sdelphij	cStatus = ' ' ;
1062285612Sdelphij	pStatus = "" ;
1063285612Sdelphij
1064285612Sdelphij	switch ( peer->status ) {
1065285612Sdelphij	case 0 : cStatus = ' ' ; pStatus = "Reject"    ; break ;
1066285612Sdelphij	case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ;
1067285612Sdelphij	case 2 : cStatus = '.' ; pStatus = "Excess"    ; break ;
1068285612Sdelphij	case 3 : cStatus = '-' ; pStatus = "Outlier"   ; break ;
1069285612Sdelphij	case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ;
1070285612Sdelphij	case 5 : cStatus = '#' ; pStatus = "Selected"  ; break ;
1071285612Sdelphij	case 6 : cStatus = '*' ; pStatus = "Sys.Peer"  ; break ;
1072285612Sdelphij	case 7 : cStatus = 'o' ; pStatus = "PPS.Peer"  ; break ;
1073285612Sdelphij	default : break ;
1074285612Sdelphij	}
1075285612Sdelphij
1076285612Sdelphij	snprintf ( sLog, sizeof(sLog),
1077285612Sdelphij		   "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.",
1078285612Sdelphij		    peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ;
1079285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1080285612Sdelphij
1081285612Sdelphij}
1082285612Sdelphij
1083285612Sdelphij/*################################################################################################*/
1084285612Sdelphij/*################################################################################################*/
1085285612Sdelphij/*##												##*/
1086285612Sdelphij/*##    The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02					##*/
1087285612Sdelphij/*##												##*/
1088285612Sdelphij/*##    server  127.127.40.X  mode 1								##*/
1089285612Sdelphij/*##												##*/
1090285612Sdelphij/*################################################################################################*/
1091285612Sdelphij/*################################################################################################*/
1092285612Sdelphij/*                                                                                                */
1093285612Sdelphij/*  Command               Response                                  Remarks                       */
1094285612Sdelphij/*  --------------------  ----------------------------------------  ----------------------------  */
1095285612Sdelphij/*  dcst<CR><LF>          VALID<CR><LF> or INVALID<CR><LF>                                        */
1096285612Sdelphij/*  stus<CR><LF>          ADJUSTED<CR><LF> or UNADJUSTED<CR><LF>                                  */
1097285612Sdelphij/*  date<CR><LF>          YYYY/MM/DD XXX<CR><LF>                    XXX is the day of the week    */
1098285612Sdelphij/*  time<CR><LF>          HH:MM:SS<CR><LF>                          Not used by this driver       */
1099285612Sdelphij/*  stim<CR><LF>          HH:MM:SS<CR><LF>                          Reply at just second          */
1100285612Sdelphij/*                                                                                                */
1101285612Sdelphij/*################################################################################################*/
1102285612Sdelphij
1103285612Sdelphij#define	TS_JJY01_COMMAND_NUMBER_DATE	1
1104285612Sdelphij#define	TS_JJY01_COMMAND_NUMBER_TIME	2
1105285612Sdelphij#define	TS_JJY01_COMMAND_NUMBER_STIM	3
1106285612Sdelphij#define	TS_JJY01_COMMAND_NUMBER_STUS	4
1107285612Sdelphij#define	TS_JJY01_COMMAND_NUMBER_DCST	5
1108285612Sdelphij
1109285612Sdelphij#define	TS_JJY01_REPLY_DATE     	"yyyy/mm/dd www"
1110285612Sdelphij#define	TS_JJY01_REPLY_STIM     	"hh:mm:ss"
1111285612Sdelphij#define	TS_JJY01_REPLY_STUS_ADJUSTED	"adjusted"
1112285612Sdelphij#define	TS_JJY01_REPLY_STUS_UNADJUSTED	"unadjusted"
1113285612Sdelphij#define	TS_JJY01_REPLY_DCST_VALID	"valid"
1114285612Sdelphij#define	TS_JJY01_REPLY_DCST_INVALID	"invalid"
1115285612Sdelphij
1116285612Sdelphij#define	TS_JJY01_REPLY_LENGTH_DATE           	14	/* Length without <CR><LF> */
1117285612Sdelphij#define	TS_JJY01_REPLY_LENGTH_TIME           	8	/* Length without <CR><LF> */
1118285612Sdelphij#define	TS_JJY01_REPLY_LENGTH_STIM           	8	/* Length without <CR><LF> */
1119285612Sdelphij#define	TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED  	8	/* Length without <CR><LF> */
1120285612Sdelphij#define	TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED	10	/* Length without <CR><LF> */
1121285612Sdelphij#define	TS_JJY01_REPLY_LENGTH_DCST_VALID     	5	/* Length without <CR><LF> */
1122285612Sdelphij#define	TS_JJY01_REPLY_LENGTH_DCST_INVALID   	7	/* Length without <CR><LF> */
1123285612Sdelphij
1124285612Sdelphijstatic  struct
1125285612Sdelphij{
1126285612Sdelphij	const char	commandNumber ;
1127285612Sdelphij	const char	*command ;
1128285612Sdelphij	int	commandLength ;
1129285612Sdelphij	int	iExpectedReplyLength [ 2 ] ;
1130285612Sdelphij} tristate_jjy01_command_sequence[] =
1131285612Sdelphij{
1132285612Sdelphij	{ 0, NULL, 0, { 0, 0 } }, /* Idle */
1133285612Sdelphij	{ TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID   , TS_JJY01_REPLY_LENGTH_DCST_INVALID } },
1134285612Sdelphij	{ TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } },
1135285612Sdelphij	{ TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME         , TS_JJY01_REPLY_LENGTH_TIME } },
1136285612Sdelphij	{ TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE         , TS_JJY01_REPLY_LENGTH_DATE } },
1137285612Sdelphij	{ TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM         , TS_JJY01_REPLY_LENGTH_STIM } },
1138285612Sdelphij	/* End of command */
1139285612Sdelphij	{ 0, NULL, 0, { 0, 0 } }
1140285612Sdelphij} ;
1141285612Sdelphij
1142285612Sdelphij/**************************************************************************************************/
1143285612Sdelphij
1144285612Sdelphijstatic int
1145285612Sdelphijjjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up )
1146285612Sdelphij{
1147285612Sdelphij
1148285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ;
1149285612Sdelphij
1150285612Sdelphij	up->unittype  = UNITTYPE_TRISTATE_JJY01 ;
1151285612Sdelphij	up->linespeed = SPEED232_TRISTATE_JJY01 ;
1152285612Sdelphij	up->linediscipline = LDISC_CLK ;
1153285612Sdelphij
1154285612Sdelphij	return 0 ;
1155285612Sdelphij
1156285612Sdelphij}
1157285612Sdelphij
1158285612Sdelphij/**************************************************************************************************/
1159285612Sdelphij
1160285612Sdelphijstatic int
1161285612Sdelphijjjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
1162285612Sdelphij{
1163285612Sdelphij	struct jjyunit	    *up ;
1164285612Sdelphij	struct refclockproc *pp ;
1165285612Sdelphij	struct peer	    *peer;
1166285612Sdelphij
1167294569Sdelphij	char *		pBuf ;
1168294569Sdelphij	char		sLog [ 100 ] ;
1169294569Sdelphij	int 		iLen ;
1170294569Sdelphij	int 		rc ;
1171285612Sdelphij
1172294569Sdelphij	const char *	pCmd ;
1173294569Sdelphij	int 		iCmdLen ;
1174285612Sdelphij
1175285612Sdelphij	/* Initialize pointers  */
1176285612Sdelphij
1177285612Sdelphij	peer = rbufp->recv_peer ;
1178285612Sdelphij	pp = peer->procptr ;
1179285612Sdelphij	up = pp->unitptr ;
1180285612Sdelphij
1181285612Sdelphij	if ( up->linediscipline == LDISC_RAW ) {
1182285612Sdelphij		pBuf = up->sTextBuf ;
1183285612Sdelphij		iLen = up->iTextBufLen ;
1184285612Sdelphij	} else {
1185285612Sdelphij		pBuf = pp->a_lastcode ;
1186285612Sdelphij		iLen = pp->lencode ;
1187285612Sdelphij	}
1188285612Sdelphij
1189285612Sdelphij	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
1190285612Sdelphij
1191285612Sdelphij	/* Check expected reply */
1192285612Sdelphij
1193285612Sdelphij	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1194285612Sdelphij		/* Command sequence has not been started, or has been completed */
1195285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1196285612Sdelphij			  pBuf ) ;
1197285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1198285612Sdelphij		up->bLineError = TRUE ;
1199285612Sdelphij		return JJY_RECEIVE_ERROR ;
1200285612Sdelphij	}
1201285612Sdelphij
1202285612Sdelphij	/* Check reply length */
1203285612Sdelphij
1204285612Sdelphij	if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
1205285612Sdelphij	  && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
1206285612Sdelphij		/* Unexpected reply length */
1207285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1208285612Sdelphij			  iLen ) ;
1209285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1210285612Sdelphij		up->bLineError = TRUE ;
1211285612Sdelphij		return JJY_RECEIVE_ERROR ;
1212285612Sdelphij	}
1213285612Sdelphij
1214285612Sdelphij	/* Parse reply */
1215285612Sdelphij
1216285612Sdelphij	switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
1217285612Sdelphij
1218285612Sdelphij	case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
1219285612Sdelphij
1220285612Sdelphij		rc = sscanf ( pBuf, "%4d/%2d/%2d",
1221285612Sdelphij			      &up->year, &up->month, &up->day ) ;
1222285612Sdelphij
1223285612Sdelphij		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
1224285612Sdelphij		  || up->month < 1 || 12 < up->month
1225285612Sdelphij		  || up->day < 1 || 31 < up->day ) {
1226285612Sdelphij			/* Invalid date */
1227285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
1228285612Sdelphij				  rc, up->year, up->month, up->day ) ;
1229285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1230285612Sdelphij			up->bLineError = TRUE ;
1231285612Sdelphij			return JJY_RECEIVE_ERROR ;
1232285612Sdelphij		}
1233285612Sdelphij
1234285612Sdelphij		break ;
1235285612Sdelphij
1236285612Sdelphij	case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1237285612Sdelphij	case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
1238285612Sdelphij
1239285612Sdelphij		if ( up->iTimestampCount >= 2 ) {
1240285612Sdelphij			/* Too many time reply */
1241285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
1242285612Sdelphij				  up->iTimestampCount ) ;
1243285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1244285612Sdelphij			up->bLineError = TRUE ;
1245285612Sdelphij			return JJY_RECEIVE_ERROR ;
1246285612Sdelphij		}
1247285612Sdelphij
1248285612Sdelphij		rc = sscanf ( pBuf, "%2d:%2d:%2d",
1249285612Sdelphij			      &up->hour, &up->minute, &up->second ) ;
1250285612Sdelphij
1251285612Sdelphij		if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
1252285612Sdelphij		     up->second > 60 ) {
1253285612Sdelphij			/* Invalid time */
1254285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
1255285612Sdelphij				  rc, up->hour, up->minute, up->second ) ;
1256285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1257285612Sdelphij			up->bLineError = TRUE ;
1258285612Sdelphij			return JJY_RECEIVE_ERROR ;
1259285612Sdelphij		}
1260285612Sdelphij
1261285612Sdelphij		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
1262285612Sdelphij
1263285612Sdelphij		up->iTimestampCount++ ;
1264285612Sdelphij
1265285612Sdelphij		up->msecond = 0 ;
1266285612Sdelphij
1267285612Sdelphij		break ;
1268285612Sdelphij
1269285612Sdelphij	case TS_JJY01_COMMAND_NUMBER_STUS :
1270285612Sdelphij
1271285612Sdelphij		if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
1272285612Sdelphij			     TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0
1273285612Sdelphij		  || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
1274285612Sdelphij			     TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
1275285612Sdelphij			/* Good */
1276285612Sdelphij		} else {
1277285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1278285612Sdelphij				  pBuf ) ;
1279285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1280285612Sdelphij			up->bLineError = TRUE ;
1281285612Sdelphij			return JJY_RECEIVE_ERROR ;
1282285612Sdelphij		}
1283285612Sdelphij
1284285612Sdelphij		break ;
1285285612Sdelphij
1286285612Sdelphij	case TS_JJY01_COMMAND_NUMBER_DCST :
1287285612Sdelphij
1288285612Sdelphij		if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
1289285612Sdelphij			     TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
1290285612Sdelphij		  || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
1291285612Sdelphij			     TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
1292285612Sdelphij			/* Good */
1293285612Sdelphij		} else {
1294285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1295285612Sdelphij				  pBuf ) ;
1296285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1297285612Sdelphij			up->bLineError = TRUE ;
1298285612Sdelphij			return JJY_RECEIVE_ERROR ;
1299285612Sdelphij		}
1300285612Sdelphij
1301285612Sdelphij		break ;
1302285612Sdelphij
1303285612Sdelphij	default : /*  Unexpected reply */
1304285612Sdelphij
1305285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1306285612Sdelphij			  pBuf ) ;
1307285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1308285612Sdelphij		up->bLineError = TRUE ;
1309285612Sdelphij		return JJY_RECEIVE_ERROR ;
1310285612Sdelphij
1311285612Sdelphij	}
1312285612Sdelphij
1313285612Sdelphij	if ( up->iTimestampCount == 2 ) {
1314285612Sdelphij		/* Process date and time */
1315285612Sdelphij
1316285612Sdelphij		if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
1317285612Sdelphij		  && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
1318285612Sdelphij			/* 3 commands (time,date,stim) was excuted in two seconds */
1319285612Sdelphij			jjy_synctime( peer, pp, up ) ;
1320285612Sdelphij			return JJY_RECEIVE_DONE ;
1321285612Sdelphij		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
1322285612Sdelphij			/* Over midnight, and date is unsure */
1323285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
1324285612Sdelphij				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1325285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
1326285612Sdelphij			return JJY_RECEIVE_SKIP ;
1327285612Sdelphij		} else {
1328285612Sdelphij			/* Slow reply */
1329285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
1330285612Sdelphij				  up->iTimestamp[0], up->iTimestamp[1] ) ;
1331285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1332285612Sdelphij			up->bLineError = TRUE ;
1333285612Sdelphij			return JJY_RECEIVE_ERROR ;
1334285612Sdelphij		}
1335285612Sdelphij
1336285612Sdelphij	}
1337285612Sdelphij
1338285612Sdelphij	/* Issue next command */
1339285612Sdelphij
1340285612Sdelphij	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
1341285612Sdelphij		up->iCommandSeq ++ ;
1342285612Sdelphij	}
1343285612Sdelphij
1344285612Sdelphij	if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
1345285612Sdelphij		/* Command sequence completed */
1346285612Sdelphij		return JJY_RECEIVE_DONE ;
1347285612Sdelphij	}
1348285612Sdelphij
1349285612Sdelphij	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1350285612Sdelphij	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1351285612Sdelphij	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1352285612Sdelphij		refclock_report ( peer, CEVNT_FAULT ) ;
1353285612Sdelphij	}
1354285612Sdelphij
1355285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1356285612Sdelphij
1357285612Sdelphij	return JJY_RECEIVE_WAIT ;
1358285612Sdelphij
1359285612Sdelphij}
1360285612Sdelphij
1361285612Sdelphij/**************************************************************************************************/
1362285612Sdelphij
1363285612Sdelphijstatic void
1364285612Sdelphijjjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1365285612Sdelphij{
1366106163Sroberto#ifdef DEBUG
1367285612Sdelphij	static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1368285612Sdelphij#endif
1369285612Sdelphij
1370285612Sdelphij	struct refclockproc *pp ;
1371285612Sdelphij	struct jjyunit	    *up ;
1372285612Sdelphij
1373294569Sdelphij	const char *	pCmd ;
1374294569Sdelphij	int 		iCmdLen ;
1375285612Sdelphij
1376285612Sdelphij	pp = peer->procptr;
1377285612Sdelphij	up = pp->unitptr ;
1378285612Sdelphij
1379285612Sdelphij	up->bLineError = FALSE ;
1380285612Sdelphij	up->iTimestampCount = 0 ;
1381285612Sdelphij
1382285612Sdelphij	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1383285612Sdelphij		/* Skip "dcst" and "stus" commands */
1384285612Sdelphij		up->iCommandSeq = 2 ;
1385285612Sdelphij		up->iLineCount = 2 ;
1386285612Sdelphij	}
1387285612Sdelphij
1388285612Sdelphij#ifdef DEBUG
1389106163Sroberto	if ( debug ) {
1390285612Sdelphij		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
1391285612Sdelphij			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1392285612Sdelphij			up->iLineCount ) ;
1393106163Sroberto	}
1394106163Sroberto#endif
1395106163Sroberto
1396106163Sroberto	/*
1397285612Sdelphij	 * Send a first command
1398106163Sroberto	 */
1399182007Sroberto
1400285612Sdelphij	up->iCommandSeq ++ ;
1401182007Sroberto
1402285612Sdelphij	pCmd =  tristate_jjy01_command_sequence[up->iCommandSeq].command ;
1403285612Sdelphij	iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
1404285612Sdelphij	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1405285612Sdelphij		refclock_report ( peer, CEVNT_FAULT ) ;
1406106163Sroberto	}
1407106163Sroberto
1408285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
1409182007Sroberto
1410106163Sroberto}
1411106163Sroberto
1412285612Sdelphij/*################################################################################################*/
1413285612Sdelphij/*################################################################################################*/
1414285612Sdelphij/*##												##*/
1415285612Sdelphij/*##    The C-DEX Co. Ltd. JJY receiver JST2000							##*/
1416285612Sdelphij/*##												##*/
1417285612Sdelphij/*##    server  127.127.40.X  mode 2								##*/
1418285612Sdelphij/*##												##*/
1419285612Sdelphij/*################################################################################################*/
1420285612Sdelphij/*################################################################################################*/
1421285612Sdelphij/*                                                                                                */
1422285612Sdelphij/*  Command               Response                                  Remarks                       */
1423285612Sdelphij/*  --------------------  ----------------------------------------  ----------------------------  */
1424285612Sdelphij/*  <ENQ>1J<ETX>          <STX>JYYMMDD HHMMSSS<ETX>                 J is a fixed character        */
1425285612Sdelphij/*                                                                                                */
1426285612Sdelphij/*################################################################################################*/
1427285612Sdelphij
1428285612Sdelphijstatic struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
1429285612Sdelphij{
1430285612Sdelphij	{ "\x03", 1 }, { NULL, 0 }
1431285612Sdelphij} ;
1432285612Sdelphij
1433106163Sroberto/**************************************************************************************************/
1434106163Sroberto
1435106163Srobertostatic int
1436285612Sdelphijjjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
1437106163Sroberto{
1438106163Sroberto
1439285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
1440182007Sroberto
1441285612Sdelphij	up->unittype  = UNITTYPE_CDEX_JST2000 ;
1442285612Sdelphij	up->linespeed = SPEED232_CDEX_JST2000 ;
1443285612Sdelphij	up->linediscipline = LDISC_RAW ;
1444285612Sdelphij
1445285612Sdelphij	up->pRawBreak = cdex_jst2000_raw_break ;
1446285612Sdelphij	up->bWaitBreakString = TRUE ;
1447285612Sdelphij
1448285612Sdelphij	up->bSkipCntrlCharOnly = FALSE ;
1449285612Sdelphij
1450285612Sdelphij	return 0 ;
1451285612Sdelphij
1452285612Sdelphij}
1453285612Sdelphij
1454285612Sdelphij/**************************************************************************************************/
1455285612Sdelphij
1456285612Sdelphijstatic int
1457285612Sdelphijjjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
1458285612Sdelphij{
1459285612Sdelphij
1460106163Sroberto	struct jjyunit      *up ;
1461106163Sroberto	struct refclockproc *pp ;
1462285612Sdelphij	struct peer         *peer ;
1463106163Sroberto
1464285612Sdelphij	char	*pBuf, sLog [ 100 ] ;
1465106163Sroberto	int 	iLen ;
1466106163Sroberto	int 	rc ;
1467106163Sroberto
1468285612Sdelphij	/* Initialize pointers */
1469285612Sdelphij
1470285612Sdelphij	peer = rbufp->recv_peer ;
1471285612Sdelphij	pp = peer->procptr ;
1472285612Sdelphij	up = pp->unitptr ;
1473285612Sdelphij
1474285612Sdelphij	if ( up->linediscipline == LDISC_RAW ) {
1475285612Sdelphij		pBuf = up->sTextBuf ;
1476285612Sdelphij		iLen = up->iTextBufLen ;
1477285612Sdelphij	} else {
1478285612Sdelphij		pBuf = pp->a_lastcode ;
1479285612Sdelphij		iLen = pp->lencode ;
1480285612Sdelphij	}
1481285612Sdelphij
1482285612Sdelphij	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
1483285612Sdelphij
1484285612Sdelphij	/* Check expected reply */
1485285612Sdelphij
1486285612Sdelphij	if ( up->iCommandSeq != 1 ) {
1487285612Sdelphij		/* Command sequence has not been started, or has been completed */
1488285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
1489285612Sdelphij			  pBuf ) ;
1490285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1491285612Sdelphij		up->bLineError = TRUE ;
1492285612Sdelphij		return JJY_RECEIVE_ERROR ;
1493285612Sdelphij	}
1494285612Sdelphij
1495285612Sdelphij	/* Wait until ETX comes */
1496285612Sdelphij
1497285612Sdelphij	if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
1498285612Sdelphij		return JJY_RECEIVE_UNPROCESS ;
1499285612Sdelphij	}
1500285612Sdelphij
1501285612Sdelphij	/* Check reply length */
1502285612Sdelphij
1503285612Sdelphij	if ( iLen != 15 ) {
1504285612Sdelphij		/* Unexpected reply length */
1505285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1506285612Sdelphij			  iLen ) ;
1507285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1508285612Sdelphij		up->bLineError = TRUE ;
1509285612Sdelphij		return JJY_RECEIVE_ERROR ;
1510285612Sdelphij	}
1511285612Sdelphij
1512310419Sdelphij	/* JYYMMDDWHHMMSSS */
1513285612Sdelphij
1514310419Sdelphij	rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
1515285612Sdelphij		      &up->year, &up->month, &up->day,
1516285612Sdelphij		      &up->hour, &up->minute, &up->second,
1517285612Sdelphij		      &up->msecond ) ;
1518285612Sdelphij
1519285612Sdelphij	if ( rc != 7 || up->month < 1 || up->month > 12 ||
1520285612Sdelphij	     up->day < 1 || up->day > 31 || up->hour > 23 ||
1521285612Sdelphij	     up->minute > 59 || up->second > 60 ) {
1522285612Sdelphij		/* Invalid date and time */
1523285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1524285612Sdelphij			  rc, up->year, up->month, up->day,
1525285612Sdelphij			  up->hour, up->minute, up->second ) ;
1526285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1527285612Sdelphij		up->bLineError = TRUE ;
1528285612Sdelphij		return JJY_RECEIVE_ERROR ;
1529285612Sdelphij	}
1530285612Sdelphij
1531285612Sdelphij	up->year    += 2000 ;
1532285612Sdelphij	up->msecond *= 100 ;
1533285612Sdelphij
1534285612Sdelphij	jjy_synctime( peer, pp, up ) ;
1535285612Sdelphij
1536285612Sdelphij	return JJY_RECEIVE_DONE ;
1537285612Sdelphij
1538285612Sdelphij}
1539285612Sdelphij
1540285612Sdelphij/**************************************************************************************************/
1541285612Sdelphij
1542285612Sdelphijstatic void
1543285612Sdelphijjjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1544285612Sdelphij{
1545285612Sdelphij
1546285612Sdelphij	struct refclockproc *pp ;
1547285612Sdelphij	struct jjyunit      *up ;
1548285612Sdelphij
1549285612Sdelphij	pp = peer->procptr ;
1550285612Sdelphij	up = pp->unitptr ;
1551285612Sdelphij
1552285612Sdelphij	up->bLineError = FALSE ;
1553285612Sdelphij	up->iRawBufLen = 0 ;
1554285612Sdelphij	up->iLineBufLen = 0 ;
1555285612Sdelphij	up->iTextBufLen = 0 ;
1556285612Sdelphij
1557106163Sroberto	/*
1558285612Sdelphij	 * Send "<ENQ>1J<ETX>" command
1559106163Sroberto	 */
1560285612Sdelphij
1561285612Sdelphij	up->iCommandSeq ++ ;
1562285612Sdelphij
1563285612Sdelphij	if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1564285612Sdelphij		refclock_report ( peer, CEVNT_FAULT ) ;
1565285612Sdelphij	}
1566285612Sdelphij
1567285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
1568285612Sdelphij
1569285612Sdelphij}
1570285612Sdelphij
1571285612Sdelphij/*################################################################################################*/
1572285612Sdelphij/*################################################################################################*/
1573285612Sdelphij/*##												##*/
1574285612Sdelphij/*##    The Echo Keisokuki Co. Ltd. JJY receiver LT2000						##*/
1575285612Sdelphij/*##												##*/
1576285612Sdelphij/*##    server  127.127.40.X  mode 3								##*/
1577285612Sdelphij/*##												##*/
1578285612Sdelphij/*################################################################################################*/
1579285612Sdelphij/*################################################################################################*/
1580285612Sdelphij/*                                                                                                */
1581285612Sdelphij/*  Command               Response                                  Remarks                       */
1582285612Sdelphij/*  --------------------  ----------------------------------------  ----------------------------  */
1583285612Sdelphij/*  #                                                               Mode 1 ( Request & Send )     */
1584285612Sdelphij/*  T                     YYMMDDWHHMMSS<BCC1><BCC2><CR>                                           */
1585285612Sdelphij/*  C                                                               Mode 2 ( Continuous )         */
1586285612Sdelphij/*                        YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>     0.5 sec before time stamp     */
1587285612Sdelphij/*                        <SUB>                                     Second signal                 */
1588285612Sdelphij/*                                                                                                */
1589285612Sdelphij/*################################################################################################*/
1590285612Sdelphij
1591285612Sdelphij#define	ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND		1
1592285612Sdelphij#define	ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS		2
1593285612Sdelphij#define	ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS	3
1594285612Sdelphij
1595285612Sdelphij#define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND 	"#"
1596285612Sdelphij#define	ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME 	"T"
1597285612Sdelphij#define	ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS 	"C"
1598285612Sdelphij
1599285612Sdelphij/**************************************************************************************************/
1600285612Sdelphij
1601285612Sdelphijstatic int
1602285612Sdelphijjjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
1603285612Sdelphij{
1604285612Sdelphij
1605285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
1606285612Sdelphij
1607285612Sdelphij	up->unittype  = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
1608285612Sdelphij	up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
1609285612Sdelphij	up->linediscipline = LDISC_CLK ;
1610285612Sdelphij
1611285612Sdelphij	up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
1612285612Sdelphij
1613285612Sdelphij	return 0 ;
1614285612Sdelphij
1615285612Sdelphij}
1616285612Sdelphij
1617285612Sdelphij/**************************************************************************************************/
1618285612Sdelphij
1619285612Sdelphijstatic int
1620285612Sdelphijjjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1621285612Sdelphij{
1622285612Sdelphij
1623285612Sdelphij	struct jjyunit      *up ;
1624285612Sdelphij	struct refclockproc *pp ;
1625285612Sdelphij	struct peer	    *peer;
1626285612Sdelphij
1627285612Sdelphij	char	*pBuf, sLog [ 100 ], sErr [ 60 ] ;
1628285612Sdelphij	int 	iLen ;
1629285612Sdelphij	int 	rc ;
1630285612Sdelphij	int	i, ibcc, ibcc1, ibcc2 ;
1631285612Sdelphij
1632285612Sdelphij	/* Initialize pointers */
1633285612Sdelphij
1634285612Sdelphij	peer = rbufp->recv_peer ;
1635106163Sroberto	pp = peer->procptr ;
1636285612Sdelphij	up = pp->unitptr ;
1637106163Sroberto
1638106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
1639285612Sdelphij		pBuf = up->sTextBuf ;
1640285612Sdelphij		iLen = up->iTextBufLen ;
1641106163Sroberto	} else {
1642285612Sdelphij		pBuf = pp->a_lastcode ;
1643285612Sdelphij		iLen = pp->lencode ;
1644106163Sroberto	}
1645106163Sroberto
1646285612Sdelphij	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
1647106163Sroberto
1648285612Sdelphij	/* Check reply length */
1649106163Sroberto
1650285612Sdelphij	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1651285612Sdelphij	       && iLen != 15 )
1652285612Sdelphij	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1653285612Sdelphij	       && iLen != 17 )
1654285612Sdelphij	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1655285612Sdelphij	       && iLen != 17 ) ) {
1656285612Sdelphij		/* Unexpected reply length */
1657285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1658285612Sdelphij			  iLen ) ;
1659285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1660285612Sdelphij		up->bLineError = TRUE ;
1661285612Sdelphij		return JJY_RECEIVE_ERROR ;
1662285612Sdelphij	}
1663285612Sdelphij
1664285612Sdelphij	if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
1665285612Sdelphij		/* YYMMDDWHHMMSS<BCC1><BCC2> */
1666285612Sdelphij
1667285612Sdelphij		for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
1668285612Sdelphij			ibcc ^= pBuf[i] ;
1669106163Sroberto		}
1670285612Sdelphij
1671285612Sdelphij		ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1672285612Sdelphij		ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
1673285612Sdelphij		if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1674285612Sdelphij			snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
1675285612Sdelphij				  pBuf[13] & 0xFF, pBuf[14] & 0xFF,
1676285612Sdelphij				  ibcc1, ibcc2 ) ;
1677285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
1678285612Sdelphij				  sErr ) ;
1679285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1680285612Sdelphij			up->bLineError = TRUE ;
1681285612Sdelphij			return JJY_RECEIVE_ERROR ;
1682106163Sroberto		}
1683182007Sroberto
1684285612Sdelphij	}
1685182007Sroberto
1686285612Sdelphij	if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
1687285612Sdelphij	       && iLen == 15 )
1688285612Sdelphij	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1689285612Sdelphij	       && iLen == 17 )
1690285612Sdelphij	  || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
1691285612Sdelphij	       && iLen == 17 ) ) {
1692285612Sdelphij		/* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1693182007Sroberto
1694285612Sdelphij		rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1695285612Sdelphij			      &up->year, &up->month, &up->day,
1696285612Sdelphij			      &up->hour, &up->minute, &up->second ) ;
1697285612Sdelphij
1698285612Sdelphij		if ( rc != 6 || up->month < 1 || up->month > 12
1699285612Sdelphij		  || up->day < 1 || up->day > 31
1700285612Sdelphij		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1701285612Sdelphij			/* Invalid date and time */
1702285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1703285612Sdelphij				  rc, up->year, up->month, up->day,
1704285612Sdelphij				  up->hour, up->minute, up->second ) ;
1705285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1706285612Sdelphij			up->bLineError = TRUE ;
1707285612Sdelphij			return JJY_RECEIVE_ERROR ;
1708285612Sdelphij		}
1709285612Sdelphij
1710285612Sdelphij		up->year += 2000 ;
1711285612Sdelphij
1712285612Sdelphij		if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
1713285612Sdelphij		  || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1714285612Sdelphij			/* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
1715285612Sdelphij
1716285612Sdelphij			up->msecond = 500 ;
1717285612Sdelphij			up->second -- ;
1718285612Sdelphij			if ( up->second < 0 ) {
1719285612Sdelphij				up->second = 59 ;
1720285612Sdelphij				up->minute -- ;
1721285612Sdelphij				if ( up->minute < 0 ) {
1722285612Sdelphij					up->minute = 59 ;
1723285612Sdelphij					up->hour -- ;
1724285612Sdelphij					if ( up->hour < 0 ) {
1725285612Sdelphij						up->hour = 23 ;
1726285612Sdelphij						up->day -- ;
1727285612Sdelphij						if ( up->day < 1 ) {
1728285612Sdelphij							up->month -- ;
1729285612Sdelphij							if ( up->month < 1 ) {
1730285612Sdelphij								up->month = 12 ;
1731285612Sdelphij								up->year -- ;
1732285612Sdelphij							}
1733285612Sdelphij						}
1734285612Sdelphij					}
1735285612Sdelphij				}
1736182007Sroberto			}
1737285612Sdelphij
1738285612Sdelphij		}
1739285612Sdelphij
1740285612Sdelphij		jjy_synctime( peer, pp, up ) ;
1741285612Sdelphij
1742285612Sdelphij
1743285612Sdelphij	}
1744285612Sdelphij
1745285612Sdelphij	if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
1746285612Sdelphij		/* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1747285612Sdelphij
1748285612Sdelphij		iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1749285612Sdelphij		if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen  ) {
1750285612Sdelphij			refclock_report ( peer, CEVNT_FAULT ) ;
1751285612Sdelphij		}
1752285612Sdelphij
1753285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
1754285612Sdelphij
1755285612Sdelphij	}
1756285612Sdelphij
1757285612Sdelphij	return JJY_RECEIVE_DONE ;
1758285612Sdelphij
1759285612Sdelphij}
1760285612Sdelphij
1761285612Sdelphij/**************************************************************************************************/
1762285612Sdelphij
1763285612Sdelphijstatic void
1764285612Sdelphijjjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1765285612Sdelphij{
1766285612Sdelphij
1767285612Sdelphij	struct refclockproc *pp ;
1768285612Sdelphij	struct jjyunit      *up ;
1769285612Sdelphij
1770285612Sdelphij	char	sCmd[2] ;
1771285612Sdelphij
1772285612Sdelphij	pp = peer->procptr ;
1773285612Sdelphij	up = pp->unitptr ;
1774285612Sdelphij
1775285612Sdelphij	up->bLineError = FALSE ;
1776285612Sdelphij
1777285612Sdelphij	/*
1778285612Sdelphij	 * Send "T" or "C" command
1779285612Sdelphij	 */
1780285612Sdelphij
1781285612Sdelphij	switch ( up->operationmode ) {
1782285612Sdelphij	case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
1783285612Sdelphij		sCmd[0] = 'T' ;
1784285612Sdelphij		break ;
1785285612Sdelphij	case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
1786285612Sdelphij	case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
1787285612Sdelphij		sCmd[0] = 'C' ;
1788285612Sdelphij		break ;
1789285612Sdelphij	}
1790285612Sdelphij	sCmd[1] = 0 ;
1791285612Sdelphij
1792285612Sdelphij	if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1793285612Sdelphij		refclock_report ( peer, CEVNT_FAULT ) ;
1794285612Sdelphij	}
1795285612Sdelphij
1796285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
1797285612Sdelphij
1798285612Sdelphij}
1799285612Sdelphij
1800285612Sdelphij/*################################################################################################*/
1801285612Sdelphij/*################################################################################################*/
1802285612Sdelphij/*##												##*/
1803285612Sdelphij/*##    The CITIZEN T.I.C CO., LTD. JJY receiver JJY200						##*/
1804285612Sdelphij/*##												##*/
1805285612Sdelphij/*##    server  127.127.40.X  mode 4								##*/
1806285612Sdelphij/*##												##*/
1807285612Sdelphij/*################################################################################################*/
1808285612Sdelphij/*################################################################################################*/
1809285612Sdelphij/*                                                                                                */
1810285612Sdelphij/*  Command               Response                                  Remarks                       */
1811285612Sdelphij/*  --------------------  ----------------------------------------  ----------------------------  */
1812285612Sdelphij/*                        'XX YY/MM/DD W HH:MM:SS<CR>               XX:OK|NG|ER  W:0(Mon)-6(Sun)  */
1813285612Sdelphij/*                                                                                                */
1814285612Sdelphij/*################################################################################################*/
1815285612Sdelphij
1816285612Sdelphijstatic int
1817285612Sdelphijjjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
1818285612Sdelphij{
1819285612Sdelphij
1820285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
1821285612Sdelphij
1822285612Sdelphij	up->unittype  = UNITTYPE_CITIZENTIC_JJY200 ;
1823285612Sdelphij	up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
1824285612Sdelphij	up->linediscipline = LDISC_CLK ;
1825285612Sdelphij
1826285612Sdelphij	return 0 ;
1827285612Sdelphij
1828285612Sdelphij}
1829285612Sdelphij
1830285612Sdelphij/**************************************************************************************************/
1831285612Sdelphij
1832285612Sdelphijstatic int
1833285612Sdelphijjjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1834285612Sdelphij{
1835285612Sdelphij
1836285612Sdelphij	struct jjyunit		*up ;
1837285612Sdelphij	struct refclockproc	*pp ;
1838285612Sdelphij	struct peer		*peer;
1839285612Sdelphij
1840285612Sdelphij	char	*pBuf, sLog [ 100 ], sMsg [ 16 ] ;
1841285612Sdelphij	int	iLen ;
1842285612Sdelphij	int	rc ;
1843285612Sdelphij	char	cApostrophe, sStatus[3] ;
1844285612Sdelphij	int	iWeekday ;
1845285612Sdelphij
1846285612Sdelphij	/* Initialize pointers */
1847285612Sdelphij
1848285612Sdelphij	peer = rbufp->recv_peer ;
1849285612Sdelphij	pp = peer->procptr ;
1850285612Sdelphij	up = pp->unitptr ;
1851285612Sdelphij
1852285612Sdelphij	if ( up->linediscipline == LDISC_RAW ) {
1853285612Sdelphij		pBuf = up->sTextBuf ;
1854285612Sdelphij		iLen = up->iTextBufLen ;
1855285612Sdelphij	} else {
1856285612Sdelphij		pBuf = pp->a_lastcode ;
1857285612Sdelphij		iLen = pp->lencode ;
1858285612Sdelphij	}
1859285612Sdelphij
1860285612Sdelphij	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
1861285612Sdelphij
1862285612Sdelphij	/*
1863285612Sdelphij	 * JJY-200 sends a timestamp every second.
1864285612Sdelphij	 * So, a timestamp is ignored unless it is right after polled.
1865285612Sdelphij	 */
1866285612Sdelphij
1867285612Sdelphij	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
1868285612Sdelphij		return JJY_RECEIVE_SKIP ;
1869285612Sdelphij	}
1870285612Sdelphij
1871285612Sdelphij	/* Check reply length */
1872285612Sdelphij
1873285612Sdelphij	if ( iLen != 23 ) {
1874285612Sdelphij		/* Unexpected reply length */
1875285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
1876285612Sdelphij			  iLen ) ;
1877285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1878285612Sdelphij		up->bLineError = TRUE ;
1879285612Sdelphij		return JJY_RECEIVE_ERROR ;
1880285612Sdelphij	}
1881285612Sdelphij
1882285612Sdelphij	/* 'XX YY/MM/DD W HH:MM:SS<CR> */
1883285612Sdelphij
1884285612Sdelphij	rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1885285612Sdelphij		      &cApostrophe, sStatus,
1886285612Sdelphij		      &up->year, &up->month, &up->day, &iWeekday,
1887285612Sdelphij		      &up->hour, &up->minute, &up->second ) ;
1888285612Sdelphij	sStatus[2] = 0 ;
1889285612Sdelphij
1890285612Sdelphij	if ( rc != 9 || cApostrophe != '\''
1891285612Sdelphij	  || ( strcmp( sStatus, "OK" ) != 0
1892285612Sdelphij	    && strcmp( sStatus, "NG" ) != 0
1893285612Sdelphij	    && strcmp( sStatus, "ER" ) != 0 )
1894285612Sdelphij	  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
1895285612Sdelphij	  || iWeekday > 6
1896285612Sdelphij	  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1897285612Sdelphij		/* Invalid date and time */
1898285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
1899285612Sdelphij			  rc, up->year, up->month, up->day,
1900285612Sdelphij			  up->hour, up->minute, up->second ) ;
1901285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
1902285612Sdelphij		up->bLineError = TRUE ;
1903285612Sdelphij		return JJY_RECEIVE_ERROR ;
1904285612Sdelphij	} else if ( strcmp( sStatus, "NG" ) == 0
1905285612Sdelphij		 || strcmp( sStatus, "ER" ) == 0 ) {
1906285612Sdelphij		/* Timestamp is unsure */
1907285612Sdelphij		snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
1908285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
1909285612Sdelphij			  sMsg ) ;
1910285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
1911285612Sdelphij		return JJY_RECEIVE_SKIP ;
1912285612Sdelphij	}
1913285612Sdelphij
1914285612Sdelphij	up->year += 2000 ;
1915285612Sdelphij	up->msecond = 0 ;
1916285612Sdelphij
1917285612Sdelphij	jjy_synctime( peer, pp, up ) ;
1918285612Sdelphij
1919285612Sdelphij	return JJY_RECEIVE_DONE ;
1920285612Sdelphij
1921285612Sdelphij}
1922285612Sdelphij
1923285612Sdelphij/**************************************************************************************************/
1924285612Sdelphij
1925285612Sdelphijstatic void
1926285612Sdelphijjjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1927285612Sdelphij{
1928285612Sdelphij
1929285612Sdelphij	struct refclockproc *pp ;
1930285612Sdelphij	struct jjyunit	    *up ;
1931285612Sdelphij
1932285612Sdelphij	pp = peer->procptr ;
1933285612Sdelphij	up = pp->unitptr ;
1934285612Sdelphij
1935285612Sdelphij	up->bLineError = FALSE ;
1936285612Sdelphij
1937285612Sdelphij}
1938285612Sdelphij
1939285612Sdelphij/*################################################################################################*/
1940285612Sdelphij/*################################################################################################*/
1941285612Sdelphij/*##												##*/
1942285612Sdelphij/*##    The Tristate Ltd. GPS clock TS-GPS01							##*/
1943285612Sdelphij/*##												##*/
1944285612Sdelphij/*##    server  127.127.40.X  mode 5								##*/
1945285612Sdelphij/*##												##*/
1946285612Sdelphij/*################################################################################################*/
1947285612Sdelphij/*################################################################################################*/
1948285612Sdelphij/*                                                                                                */
1949285612Sdelphij/*  This clock has NMEA mode and command/respose mode.                                            */
1950285612Sdelphij/*  When this jjy driver are used, set to command/respose mode of this clock                      */
1951285612Sdelphij/*  by the onboard switch SW4, and make sure the LED-Y is tured on.                               */
1952285612Sdelphij/*  Other than this JJY driver, the refclock driver type 20, generic NMEA driver,                 */
1953285612Sdelphij/*  works with the NMEA mode of this clock.                                                       */
1954285612Sdelphij/*                                                                                                */
1955285612Sdelphij/*  Command               Response                                  Remarks                       */
1956285612Sdelphij/*  --------------------  ----------------------------------------  ----------------------------  */
1957285612Sdelphij/*  stus<CR><LF>          *R|*G|*U|+U<CR><LF>                                                     */
1958285612Sdelphij/*  date<CR><LF>          YY/MM/DD<CR><LF>                                                        */
1959285612Sdelphij/*  time<CR><LF>          HH:MM:SS<CR><LF>                                                        */
1960285612Sdelphij/*                                                                                                */
1961285612Sdelphij/*################################################################################################*/
1962285612Sdelphij
1963285612Sdelphij#define	TS_GPS01_COMMAND_NUMBER_DATE	1
1964285612Sdelphij#define	TS_GPS01_COMMAND_NUMBER_TIME	2
1965285612Sdelphij#define	TS_GPS01_COMMAND_NUMBER_STUS	4
1966285612Sdelphij
1967285612Sdelphij#define	TS_GPS01_REPLY_DATE		"yyyy/mm/dd"
1968285612Sdelphij#define	TS_GPS01_REPLY_TIME		"hh:mm:ss"
1969285612Sdelphij#define	TS_GPS01_REPLY_STUS_RTC		"*R"
1970285612Sdelphij#define	TS_GPS01_REPLY_STUS_GPS		"*G"
1971285612Sdelphij#define	TS_GPS01_REPLY_STUS_UTC		"*U"
1972285612Sdelphij#define	TS_GPS01_REPLY_STUS_PPS		"+U"
1973285612Sdelphij
1974285612Sdelphij#define	TS_GPS01_REPLY_LENGTH_DATE	    10	/* Length without <CR><LF> */
1975285612Sdelphij#define	TS_GPS01_REPLY_LENGTH_TIME	    8	/* Length without <CR><LF> */
1976285612Sdelphij#define	TS_GPS01_REPLY_LENGTH_STUS	    2	/* Length without <CR><LF> */
1977285612Sdelphij
1978285612Sdelphijstatic  struct
1979285612Sdelphij{
1980285612Sdelphij	char	commandNumber ;
1981285612Sdelphij	const char	*command ;
1982285612Sdelphij	int	commandLength ;
1983285612Sdelphij	int	iExpectedReplyLength ;
1984285612Sdelphij} tristate_gps01_command_sequence[] =
1985285612Sdelphij{
1986285612Sdelphij	{ 0, NULL, 0, 0 }, /* Idle */
1987285612Sdelphij	{ TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
1988285612Sdelphij	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1989285612Sdelphij	{ TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
1990285612Sdelphij	{ TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
1991285612Sdelphij	/* End of command */
1992285612Sdelphij	{ 0, NULL, 0, 0 }
1993285612Sdelphij} ;
1994285612Sdelphij
1995285612Sdelphij/**************************************************************************************************/
1996285612Sdelphij
1997285612Sdelphijstatic int
1998285612Sdelphijjjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
1999285612Sdelphij{
2000285612Sdelphij
2001285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
2002285612Sdelphij
2003285612Sdelphij	up->unittype  = UNITTYPE_TRISTATE_GPSCLOCK01 ;
2004285612Sdelphij	up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
2005285612Sdelphij	up->linediscipline = LDISC_CLK ;
2006285612Sdelphij
2007285612Sdelphij	return 0 ;
2008285612Sdelphij
2009285612Sdelphij}
2010285612Sdelphij
2011285612Sdelphij/**************************************************************************************************/
2012285612Sdelphij
2013285612Sdelphijstatic int
2014285612Sdelphijjjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
2015285612Sdelphij{
2016182007Sroberto#ifdef DEBUG
2017285612Sdelphij	static	const char	*sFunctionName = "jjy_receive_tristate_gpsclock01" ;
2018182007Sroberto#endif
2019182007Sroberto
2020285612Sdelphij	struct jjyunit	    *up ;
2021285612Sdelphij	struct refclockproc *pp ;
2022285612Sdelphij	struct peer	    *peer;
2023106163Sroberto
2024294569Sdelphij	char *		pBuf ;
2025294569Sdelphij	char		sLog [ 100 ] ;
2026294569Sdelphij	int 		iLen ;
2027294569Sdelphij	int 		rc ;
2028106163Sroberto
2029294569Sdelphij	const char *	pCmd ;
2030294569Sdelphij	int 		iCmdLen ;
2031285612Sdelphij
2032285612Sdelphij	/* Initialize pointers */
2033285612Sdelphij
2034285612Sdelphij	peer = rbufp->recv_peer ;
2035285612Sdelphij	pp = peer->procptr ;
2036285612Sdelphij	up = pp->unitptr ;
2037285612Sdelphij
2038285612Sdelphij	if ( up->linediscipline == LDISC_RAW ) {
2039285612Sdelphij		pBuf = up->sTextBuf ;
2040285612Sdelphij		iLen = up->iTextBufLen ;
2041285612Sdelphij	} else {
2042285612Sdelphij		pBuf = pp->a_lastcode ;
2043285612Sdelphij		iLen = pp->lencode ;
2044285612Sdelphij	}
2045285612Sdelphij
2046285612Sdelphij	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
2047285612Sdelphij
2048285612Sdelphij	/* Ignore NMEA data stream */
2049285612Sdelphij
2050285612Sdelphij	if ( iLen > 5
2051285612Sdelphij	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2052182007Sroberto#ifdef DEBUG
2053285612Sdelphij		if ( debug ) {
2054285612Sdelphij			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2055285612Sdelphij				sFunctionName, pBuf ) ;
2056285612Sdelphij		}
2057182007Sroberto#endif
2058285612Sdelphij		return JJY_RECEIVE_WAIT ;
2059285612Sdelphij	}
2060285612Sdelphij
2061285612Sdelphij	/*
2062285612Sdelphij	 * Skip command prompt '$Cmd>' from the TS-GPSclock-01
2063285612Sdelphij	 */
2064285612Sdelphij	if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2065285612Sdelphij		return JJY_RECEIVE_WAIT ;
2066285612Sdelphij	} else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
2067285612Sdelphij		pBuf += 5 ;
2068285612Sdelphij		iLen -= 5 ;
2069285612Sdelphij	}
2070285612Sdelphij
2071285612Sdelphij	/*
2072285612Sdelphij	 * Ignore NMEA data stream after command prompt
2073285612Sdelphij	 */
2074285612Sdelphij	if ( iLen > 5
2075285612Sdelphij	  && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
2076285612Sdelphij#ifdef DEBUG
2077285612Sdelphij		if ( debug ) {
2078285612Sdelphij			printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
2079285612Sdelphij				sFunctionName, pBuf ) ;
2080106163Sroberto		}
2081182007Sroberto#endif
2082285612Sdelphij		return JJY_RECEIVE_WAIT ;
2083285612Sdelphij	}
2084285612Sdelphij
2085285612Sdelphij	/* Check expected reply */
2086285612Sdelphij
2087285612Sdelphij	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2088285612Sdelphij		/* Command sequence has not been started, or has been completed */
2089285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2090285612Sdelphij			  pBuf ) ;
2091285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2092285612Sdelphij		up->bLineError = TRUE ;
2093285612Sdelphij		return JJY_RECEIVE_ERROR ;
2094285612Sdelphij	}
2095285612Sdelphij
2096285612Sdelphij	/* Check reply length */
2097285612Sdelphij
2098285612Sdelphij	if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
2099285612Sdelphij		/* Unexpected reply length */
2100285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2101285612Sdelphij			  iLen ) ;
2102285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2103285612Sdelphij		up->bLineError = TRUE ;
2104285612Sdelphij		return JJY_RECEIVE_ERROR ;
2105285612Sdelphij	}
2106285612Sdelphij
2107285612Sdelphij	/* Parse reply */
2108285612Sdelphij
2109285612Sdelphij	switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
2110285612Sdelphij
2111285612Sdelphij	case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
2112285612Sdelphij
2113285612Sdelphij		rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
2114285612Sdelphij
2115285612Sdelphij		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
2116285612Sdelphij		  || up->month < 1 || 12 < up->month
2117285612Sdelphij		  || up->day < 1 || 31 < up->day ) {
2118285612Sdelphij			/* Invalid date */
2119285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
2120285612Sdelphij				  rc, up->year, up->month, up->day ) ;
2121285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2122285612Sdelphij			up->bLineError = TRUE ;
2123285612Sdelphij			return JJY_RECEIVE_ERROR ;
2124106163Sroberto		}
2125285612Sdelphij
2126285612Sdelphij		break ;
2127285612Sdelphij
2128285612Sdelphij	case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
2129285612Sdelphij
2130285612Sdelphij		if ( up->iTimestampCount >= 2 ) {
2131285612Sdelphij			/* Too many time reply */
2132285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
2133285612Sdelphij				  up->iTimestampCount ) ;
2134285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2135285612Sdelphij			up->bLineError = TRUE ;
2136285612Sdelphij			return JJY_RECEIVE_ERROR ;
2137285612Sdelphij		}
2138285612Sdelphij
2139285612Sdelphij		rc = sscanf ( pBuf, "%2d:%2d:%2d",
2140285612Sdelphij			      &up->hour, &up->minute, &up->second ) ;
2141285612Sdelphij
2142285612Sdelphij		if ( rc != 3
2143285612Sdelphij		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2144285612Sdelphij			/* Invalid time */
2145285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2146285612Sdelphij				  rc, up->hour, up->minute, up->second ) ;
2147285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2148285612Sdelphij			up->bLineError = TRUE ;
2149285612Sdelphij			return JJY_RECEIVE_ERROR ;
2150285612Sdelphij		}
2151285612Sdelphij
2152285612Sdelphij		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
2153285612Sdelphij
2154285612Sdelphij		up->iTimestampCount++ ;
2155285612Sdelphij
2156106163Sroberto		up->msecond = 0 ;
2157285612Sdelphij
2158285612Sdelphij		break ;
2159285612Sdelphij
2160285612Sdelphij	case TS_GPS01_COMMAND_NUMBER_STUS :
2161285612Sdelphij
2162285612Sdelphij		if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2163285612Sdelphij		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2164285612Sdelphij		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
2165285612Sdelphij		  || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
2166285612Sdelphij			/* Good */
2167285612Sdelphij		} else {
2168285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2169285612Sdelphij				  pBuf ) ;
2170285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2171285612Sdelphij			up->bLineError = TRUE ;
2172285612Sdelphij			return JJY_RECEIVE_ERROR ;
2173106163Sroberto		}
2174285612Sdelphij
2175106163Sroberto		break ;
2176106163Sroberto
2177106163Sroberto	default : /*  Unexpected reply */
2178106163Sroberto
2179285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2180285612Sdelphij			  pBuf ) ;
2181285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2182285612Sdelphij		up->bLineError = TRUE ;
2183285612Sdelphij		return JJY_RECEIVE_ERROR ;
2184106163Sroberto
2185106163Sroberto	}
2186106163Sroberto
2187285612Sdelphij	if ( up->iTimestampCount == 2 ) {
2188285612Sdelphij		/* Process date and time */
2189106163Sroberto
2190285612Sdelphij		if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
2191285612Sdelphij		  && up->iTimestamp[0]     <= up->iTimestamp[1] ) {
2192285612Sdelphij			/* 3 commands (time,date,stim) was excuted in two seconds */
2193285612Sdelphij			jjy_synctime( peer, pp, up ) ;
2194285612Sdelphij			return JJY_RECEIVE_DONE ;
2195285612Sdelphij		} else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
2196285612Sdelphij			/* Over midnight, and date is unsure */
2197285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
2198285612Sdelphij				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2199285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
2200285612Sdelphij			return JJY_RECEIVE_SKIP ;
2201285612Sdelphij		} else {
2202285612Sdelphij			/* Slow reply */
2203285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
2204285612Sdelphij				  up->iTimestamp[0], up->iTimestamp[1] ) ;
2205285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2206285612Sdelphij			up->bLineError = TRUE ;
2207285612Sdelphij			return JJY_RECEIVE_ERROR ;
2208285612Sdelphij		}
2209285612Sdelphij
2210285612Sdelphij	}
2211285612Sdelphij
2212285612Sdelphij	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2213285612Sdelphij		/* Command sequence completed */
2214285612Sdelphij		jjy_synctime( peer, pp, up ) ;
2215285612Sdelphij		return JJY_RECEIVE_DONE ;
2216285612Sdelphij	}
2217285612Sdelphij
2218285612Sdelphij	/* Issue next command */
2219285612Sdelphij
2220285612Sdelphij	if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
2221285612Sdelphij		up->iCommandSeq ++ ;
2222285612Sdelphij	}
2223285612Sdelphij
2224285612Sdelphij	if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
2225285612Sdelphij		/* Command sequence completed */
2226285612Sdelphij		up->iProcessState = JJY_PROCESS_STATE_DONE ;
2227285612Sdelphij		return JJY_RECEIVE_DONE ;
2228285612Sdelphij	}
2229285612Sdelphij
2230285612Sdelphij	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2231285612Sdelphij	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2232285612Sdelphij	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2233285612Sdelphij		refclock_report ( peer, CEVNT_FAULT ) ;
2234285612Sdelphij	}
2235285612Sdelphij
2236285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2237285612Sdelphij
2238285612Sdelphij	return JJY_RECEIVE_WAIT ;
2239285612Sdelphij
2240106163Sroberto}
2241106163Sroberto
2242106163Sroberto/**************************************************************************************************/
2243106163Sroberto
2244285612Sdelphijstatic void
2245285612Sdelphijjjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
2246106163Sroberto{
2247285612Sdelphij#ifdef DEBUG
2248285612Sdelphij	static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
2249285612Sdelphij#endif
2250106163Sroberto
2251106163Sroberto	struct refclockproc *pp ;
2252285612Sdelphij	struct jjyunit	    *up ;
2253106163Sroberto
2254294569Sdelphij	const char *	pCmd ;
2255294569Sdelphij	int		iCmdLen ;
2256106163Sroberto
2257285612Sdelphij	pp = peer->procptr ;
2258285612Sdelphij	up = pp->unitptr ;
2259285612Sdelphij
2260285612Sdelphij	up->iTimestampCount = 0 ;
2261285612Sdelphij
2262285612Sdelphij	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
2263285612Sdelphij		/* Skip "stus" command */
2264285612Sdelphij		up->iCommandSeq = 1 ;
2265285612Sdelphij		up->iLineCount = 1 ;
2266285612Sdelphij	}
2267285612Sdelphij
2268285612Sdelphij#ifdef DEBUG
2269285612Sdelphij	if ( debug ) {
2270285612Sdelphij		printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
2271285612Sdelphij			sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
2272285612Sdelphij			up->iLineCount ) ;
2273285612Sdelphij	}
2274285612Sdelphij#endif
2275285612Sdelphij
2276106163Sroberto	/*
2277285612Sdelphij	 * Send a first command
2278106163Sroberto	 */
2279285612Sdelphij
2280285612Sdelphij	up->iCommandSeq ++ ;
2281285612Sdelphij
2282285612Sdelphij	pCmd =  tristate_gps01_command_sequence[up->iCommandSeq].command ;
2283285612Sdelphij	iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
2284285612Sdelphij	if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
2285285612Sdelphij		refclock_report ( peer, CEVNT_FAULT ) ;
2286285612Sdelphij	}
2287285612Sdelphij
2288285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
2289285612Sdelphij
2290285612Sdelphij}
2291285612Sdelphij
2292285612Sdelphij/*################################################################################################*/
2293285612Sdelphij/*################################################################################################*/
2294285612Sdelphij/*##												##*/
2295285612Sdelphij/*##    The SEIKO TIME SYSTEMS TDC-300								##*/
2296285612Sdelphij/*##												##*/
2297285612Sdelphij/*##    server  127.127.40.X  mode 6								##*/
2298285612Sdelphij/*##												##*/
2299285612Sdelphij/*################################################################################################*/
2300285612Sdelphij/*################################################################################################*/
2301285612Sdelphij/*                                                                                                */
2302285612Sdelphij/*  Type                  Response                                  Remarks                       */
2303285612Sdelphij/*  --------------------  ----------------------------------------  ----------------------------  */
2304285612Sdelphij/*  Type 1                <STX>HH:MM:SS<ETX>                                                      */
2305285612Sdelphij/*  Type 2                <STX>YYMMDDHHMMSSWLSCU<ETX>               W:0(Sun)-6(Sat)               */
2306285612Sdelphij/*  Type 3                <STX>YYMMDDWHHMMSS<ETX>                   W:0(Sun)-6(Sat)               */
2307285612Sdelphij/*                        <STX><xE5><ETX>                           5 to 10 mSec. before second   */
2308285612Sdelphij/*                                                                                                */
2309285612Sdelphij/*################################################################################################*/
2310285612Sdelphij
2311285612Sdelphijstatic struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
2312285612Sdelphij{
2313285612Sdelphij	{ "\x03", 1 }, { NULL, 0 }
2314285612Sdelphij} ;
2315285612Sdelphij
2316285612Sdelphij/**************************************************************************************************/
2317285612Sdelphij
2318285612Sdelphijstatic int
2319285612Sdelphijjjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
2320285612Sdelphij{
2321285612Sdelphij
2322285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
2323285612Sdelphij
2324285612Sdelphij	up->unittype  = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
2325285612Sdelphij	up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
2326285612Sdelphij	up->linediscipline = LDISC_RAW ;
2327285612Sdelphij
2328285612Sdelphij	up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
2329285612Sdelphij	up->bWaitBreakString = TRUE ;
2330285612Sdelphij
2331285612Sdelphij	up->bSkipCntrlCharOnly = FALSE ;
2332285612Sdelphij
2333285612Sdelphij	return 0 ;
2334285612Sdelphij
2335285612Sdelphij}
2336285612Sdelphij
2337285612Sdelphij/**************************************************************************************************/
2338285612Sdelphij
2339285612Sdelphijstatic int
2340285612Sdelphijjjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
2341285612Sdelphij{
2342285612Sdelphij
2343285612Sdelphij	struct peer		*peer;
2344285612Sdelphij	struct refclockproc	*pp ;
2345285612Sdelphij	struct jjyunit		*up ;
2346285612Sdelphij
2347285612Sdelphij	char	*pBuf, sLog [ 100 ] ;
2348285612Sdelphij	int	iLen, i ;
2349285612Sdelphij	int	rc, iWeekday ;
2350285612Sdelphij	time_t	now ;
2351285612Sdelphij	struct	tm	*pTime ;
2352285612Sdelphij
2353285612Sdelphij	/* Initialize pointers */
2354285612Sdelphij
2355285612Sdelphij	peer = rbufp->recv_peer ;
2356106163Sroberto	pp = peer->procptr ;
2357285612Sdelphij	up = pp->unitptr ;
2358106163Sroberto
2359106163Sroberto	if ( up->linediscipline == LDISC_RAW ) {
2360285612Sdelphij		pBuf = up->sTextBuf ;
2361285612Sdelphij		iLen = up->iTextBufLen ;
2362106163Sroberto	} else {
2363285612Sdelphij		pBuf = pp->a_lastcode ;
2364285612Sdelphij		iLen = pp->lencode ;
2365106163Sroberto	}
2366106163Sroberto
2367285612Sdelphij	DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
2368106163Sroberto
2369285612Sdelphij	/*
2370285612Sdelphij	 * TDC-300 sends a timestamp every second.
2371285612Sdelphij	 * So, a timestamp is ignored unless it is right after polled.
2372285612Sdelphij	 */
2373106163Sroberto
2374285612Sdelphij	if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
2375285612Sdelphij		return JJY_RECEIVE_SKIP ;
2376285612Sdelphij	}
2377285612Sdelphij
2378285612Sdelphij	/* Process timestamp */
2379285612Sdelphij
2380285612Sdelphij	up->iReceiveSeq ++ ;
2381285612Sdelphij
2382285612Sdelphij	switch ( iLen ) {
2383285612Sdelphij
2384285612Sdelphij	case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
2385285612Sdelphij
2386285612Sdelphij		for ( i = 0 ; i < iLen ; i ++ ) {
2387285612Sdelphij			pBuf[i] &= 0x7F ;
2388106163Sroberto		}
2389285612Sdelphij
2390285612Sdelphij		rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
2391285612Sdelphij		      &up->hour, &up->minute, &up->second ) ;
2392285612Sdelphij
2393285612Sdelphij		if ( rc != 3
2394106163Sroberto		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2395285612Sdelphij			/* Invalid time */
2396285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
2397285612Sdelphij				  rc, up->hour, up->minute, up->second ) ;
2398285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2399285612Sdelphij			up->bLineError = TRUE ;
2400285612Sdelphij			return JJY_RECEIVE_ERROR ;
2401285612Sdelphij		} else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
2402285612Sdelphij			/* Uncertainty date guard */
2403285612Sdelphij			return JJY_RECEIVE_WAIT ;
2404106163Sroberto		}
2405285612Sdelphij
2406285612Sdelphij		time( &now ) ;
2407285612Sdelphij		pTime = localtime( &now ) ;
2408285612Sdelphij		up->year  = pTime->tm_year ;
2409285612Sdelphij		up->month = pTime->tm_mon + 1 ;
2410285612Sdelphij		up->day   = pTime->tm_mday ;
2411285612Sdelphij
2412106163Sroberto		break ;
2413106163Sroberto
2414285612Sdelphij	case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
2415106163Sroberto
2416285612Sdelphij		for ( i = 0 ; i < iLen ; i ++ ) {
2417285612Sdelphij			pBuf[i] &= 0x7F ;
2418285612Sdelphij		}
2419285612Sdelphij
2420285612Sdelphij		rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
2421285612Sdelphij		      &up->year, &up->month, &up->day,
2422285612Sdelphij		      &up->hour, &up->minute, &up->second, &iWeekday ) ;
2423285612Sdelphij
2424285612Sdelphij		if ( rc != 7
2425285612Sdelphij		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2426285612Sdelphij		  || iWeekday > 6
2427285612Sdelphij		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2428285612Sdelphij			/* Invalid date and time */
2429285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2430285612Sdelphij				  rc, up->year, up->month, up->day,
2431285612Sdelphij				  up->hour, up->minute, up->second ) ;
2432285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2433285612Sdelphij			up->bLineError = TRUE ;
2434285612Sdelphij			return JJY_RECEIVE_ERROR ;
2435285612Sdelphij		}
2436285612Sdelphij
2437106163Sroberto		break ;
2438106163Sroberto
2439285612Sdelphij	case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
2440285612Sdelphij
2441285612Sdelphij		rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
2442285612Sdelphij		      &up->year, &up->month, &up->day, &iWeekday,
2443285612Sdelphij		      &up->hour, &up->minute, &up->second ) ;
2444285612Sdelphij
2445285612Sdelphij		if ( rc != 7
2446285612Sdelphij		  || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
2447285612Sdelphij		  || iWeekday > 6
2448285612Sdelphij		  || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
2449285612Sdelphij			/* Invalid date and time */
2450285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
2451285612Sdelphij				  rc, up->year, up->month, up->day,
2452285612Sdelphij				  up->hour, up->minute, up->second ) ;
2453285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2454285612Sdelphij			up->bLineError = TRUE ;
2455285612Sdelphij			return JJY_RECEIVE_ERROR ;
2456285612Sdelphij		}
2457285612Sdelphij
2458285612Sdelphij		return JJY_RECEIVE_WAIT ;
2459285612Sdelphij
2460285612Sdelphij	case 1 : /* Type 3 : <STX><xE5><ETX> */
2461285612Sdelphij
2462285612Sdelphij		if ( ( *pBuf & 0xFF ) != 0xE5 ) {
2463285612Sdelphij			/* Invalid second signal */
2464285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
2465285612Sdelphij				  up->sLineBuf ) ;
2466285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2467285612Sdelphij			up->bLineError = TRUE ;
2468285612Sdelphij			return JJY_RECEIVE_ERROR ;
2469285612Sdelphij		} else if ( up->iReceiveSeq == 1 ) {
2470285612Sdelphij			/* Wait for next timestamp */
2471285612Sdelphij			up->iReceiveSeq -- ;
2472285612Sdelphij			return JJY_RECEIVE_WAIT ;
2473285612Sdelphij		} else if ( up->iReceiveSeq >= 3 ) {
2474285612Sdelphij			/* Unexpected second signal */
2475285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
2476285612Sdelphij				  up->sLineBuf ) ;
2477285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2478285612Sdelphij			up->bLineError = TRUE ;
2479285612Sdelphij			return JJY_RECEIVE_ERROR ;
2480285612Sdelphij		}
2481285612Sdelphij
2482285612Sdelphij		break ;
2483285612Sdelphij
2484285612Sdelphij	default : /* Unexpected reply length */
2485285612Sdelphij
2486285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
2487285612Sdelphij			  iLen ) ;
2488285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
2489285612Sdelphij		up->bLineError = TRUE ;
2490285612Sdelphij		return JJY_RECEIVE_ERROR ;
2491285612Sdelphij
2492106163Sroberto	}
2493106163Sroberto
2494285612Sdelphij	up->year += 2000 ;
2495285612Sdelphij	up->msecond = 0 ;
2496106163Sroberto
2497285612Sdelphij	jjy_synctime( peer, pp, up ) ;
2498285612Sdelphij
2499285612Sdelphij	return JJY_RECEIVE_DONE ;
2500285612Sdelphij
2501106163Sroberto}
2502106163Sroberto
2503106163Sroberto/**************************************************************************************************/
2504182007Sroberto
2505285612Sdelphijstatic void
2506285612Sdelphijjjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
2507285612Sdelphij{
2508285612Sdelphij
2509285612Sdelphij	struct refclockproc *pp ;
2510285612Sdelphij	struct jjyunit	    *up ;
2511285612Sdelphij
2512285612Sdelphij	pp = peer->procptr ;
2513285612Sdelphij	up = pp->unitptr ;
2514285612Sdelphij
2515285612Sdelphij	up->bLineError = FALSE ;
2516285612Sdelphij
2517285612Sdelphij}
2518285612Sdelphij
2519285612Sdelphij/*################################################################################################*/
2520285612Sdelphij/*################################################################################################*/
2521285612Sdelphij/*##												##*/
2522285612Sdelphij/*##    Telephone JJY										##*/
2523285612Sdelphij/*##												##*/
2524285612Sdelphij/*##    server  127.127.40.X  mode 100 to 180							##*/
2525285612Sdelphij/*##												##*/
2526285612Sdelphij/*################################################################################################*/
2527285612Sdelphij/*################################################################################################*/
2528285612Sdelphij/*                                                                                                */
2529285612Sdelphij/*  Prompt                Command               Response              Remarks                     */
2530285612Sdelphij/*  --------------------  --------------------  --------------------  --------------------------  */
2531285612Sdelphij/*  Name<SP>?<SP>         TJJY<CR>              Welcome messages      TJJY is a guest user ID     */
2532285612Sdelphij/*  >                     4DATE<CR>             YYYYMMDD<CR>                                      */
2533285612Sdelphij/*  >                     LEAPSEC<CR>           XX<CR>                One of <SP>0, +1, -1        */
2534285612Sdelphij/*  >                     TIME<CR>              HHMMSS<CR>            3 times on second           */
2535285612Sdelphij/*  >                     BYE<CR>               Sayounara messages                                */
2536285612Sdelphij/*                                                                                                */
2537285612Sdelphij/*################################################################################################*/
2538285612Sdelphij
2539285612Sdelphijstatic struct jjyRawDataBreak teljjy_raw_break [ ] =
2540285612Sdelphij{
2541285612Sdelphij	{ "\r\n", 2 },
2542285612Sdelphij	{ "\r"  , 1 },
2543285612Sdelphij	{ "\n"  , 1 },
2544285612Sdelphij	{ "Name ? ", 7 },
2545285612Sdelphij	{ ">"   , 1 },
2546285612Sdelphij	{ "+++" , 3 },
2547285612Sdelphij	{ NULL  , 0 }
2548285612Sdelphij} ;
2549285612Sdelphij
2550285612Sdelphij#define	TELJJY_STATE_IDLE	0
2551285612Sdelphij#define	TELJJY_STATE_DAILOUT	1
2552285612Sdelphij#define	TELJJY_STATE_LOGIN	2
2553285612Sdelphij#define	TELJJY_STATE_CONNECT	3
2554285612Sdelphij#define	TELJJY_STATE_BYE	4
2555285612Sdelphij
2556285612Sdelphij#define	TELJJY_EVENT_NULL	0
2557285612Sdelphij#define	TELJJY_EVENT_START	1
2558285612Sdelphij#define	TELJJY_EVENT_CONNECT	2
2559285612Sdelphij#define	TELJJY_EVENT_DISCONNECT	3
2560285612Sdelphij#define	TELJJY_EVENT_COMMAND	4
2561285612Sdelphij#define	TELJJY_EVENT_LOGIN	5	/* Posted by the jjy_receive_telephone */
2562285612Sdelphij#define	TELJJY_EVENT_PROMPT	6	/* Posted by the jjy_receive_telephone */
2563285612Sdelphij#define	TELJJY_EVENT_DATA	7	/* Posted by the jjy_receive_telephone */
2564285612Sdelphij#define	TELJJY_EVENT_ERROR	8	/* Posted by the jjy_receive_telephone */
2565285612Sdelphij#define	TELJJY_EVENT_SILENT	9	/* Posted by the jjy_timer_telephone */
2566285612Sdelphij#define	TELJJY_EVENT_TIMEOUT	10	/* Posted by the jjy_timer_telephone */
2567285612Sdelphij
2568285612Sdelphijstatic	void 	teljjy_control		( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2569285612Sdelphij
2570285612Sdelphijstatic	int 	teljjy_idle_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2571285612Sdelphijstatic	int 	teljjy_idle_dialout	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2572285612Sdelphijstatic	int 	teljjy_dial_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2573285612Sdelphijstatic	int 	teljjy_dial_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2574285612Sdelphijstatic	int 	teljjy_dial_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2575285612Sdelphijstatic	int 	teljjy_login_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2576285612Sdelphijstatic	int 	teljjy_login_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2577285612Sdelphijstatic	int 	teljjy_login_conn	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2578285612Sdelphijstatic	int 	teljjy_login_login	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2579285612Sdelphijstatic	int 	teljjy_login_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2580285612Sdelphijstatic	int 	teljjy_login_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2581285612Sdelphijstatic	int 	teljjy_conn_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2582285612Sdelphijstatic	int 	teljjy_conn_disc	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2583285612Sdelphijstatic	int 	teljjy_conn_send	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2584285612Sdelphijstatic	int 	teljjy_conn_data	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2585285612Sdelphijstatic	int 	teljjy_conn_silent	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2586285612Sdelphijstatic	int 	teljjy_conn_error	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2587285612Sdelphijstatic	int 	teljjy_bye_ignore	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2588285612Sdelphijstatic	int 	teljjy_bye_disc 	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2589285612Sdelphijstatic	int 	teljjy_bye_modem	( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
2590285612Sdelphij
2591294569Sdelphijstatic int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) =
2592285612Sdelphij{               	/*STATE_IDLE           STATE_DAILOUT       STATE_LOGIN           STATE_CONNECT       STATE_BYE        */
2593285612Sdelphij/* NULL       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2594285612Sdelphij/* START      */	{ teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2595285612Sdelphij/* CONNECT    */	{ teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
2596285612Sdelphij/* DISCONNECT */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_disc  , teljjy_conn_disc  , teljjy_bye_disc   },
2597285612Sdelphij/* COMMAND    */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem  },
2598285612Sdelphij/* LOGIN      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
2599285612Sdelphij/* PROMPT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn  , teljjy_conn_send  , teljjy_bye_ignore },
2600285612Sdelphij/* DATA       */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data  , teljjy_bye_ignore },
2601285612Sdelphij/* ERROR      */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
2602285612Sdelphij/* SILENT     */	{ teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
2603285612Sdelphij/* TIMEOUT    */	{ teljjy_idle_ignore , teljjy_dial_disc  , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem  }
2604285612Sdelphij} ;
2605285612Sdelphij
2606285612Sdelphijstatic short iTeljjyNextState [ ] [ 5 ] =
2607285612Sdelphij{               	/*STATE_IDLE            STATE_DAILOUT         STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2608285612Sdelphij/* NULL       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2609285612Sdelphij/* START      */	{ TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2610285612Sdelphij/* CONNECT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_LOGIN  , TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2611285612Sdelphij/* DISCONNECT */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE },
2612285612Sdelphij/* COMMAND    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2613285612Sdelphij/* LOGIN      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2614285612Sdelphij/* PROMPT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2615285612Sdelphij/* DATA       */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2616285612Sdelphij/* ERROR      */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  },
2617285612Sdelphij/* SILENT     */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN  , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE  },
2618285612Sdelphij/* TIMEOUT    */	{ TELJJY_STATE_IDLE   , TELJJY_STATE_IDLE   , TELJJY_STATE_BYE    , TELJJY_STATE_BYE    , TELJJY_STATE_BYE  }
2619285612Sdelphij} ;
2620285612Sdelphij
2621285612Sdelphijstatic short iTeljjyPostEvent [ ] [ 5 ] =
2622285612Sdelphij{               	/*STATE_IDLE         STATE_DAILOUT      STATE_LOGIN           STATE_CONNECT         STATE_BYE         */
2623285612Sdelphij/* NULL       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2624285612Sdelphij/* START      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2625285612Sdelphij/* CONNECT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2626285612Sdelphij/* DISCONNECT */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2627285612Sdelphij/* COMMAND    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2628285612Sdelphij/* LOGIN      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2629285612Sdelphij/* PROMPT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2630285612Sdelphij/* DATA       */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2631285612Sdelphij/* ERROR      */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
2632285612Sdelphij/* SILENT     */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL   , TELJJY_EVENT_NULL },
2633285612Sdelphij/* TIMEOUT    */	{ TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
2634285612Sdelphij} ;
2635285612Sdelphij
2636285612Sdelphijstatic short iTeljjySilentTimeout [ 5 ] = { 0,   0, 10,  5,  0 } ;
2637285612Sdelphijstatic short iTeljjyStateTimeout  [ 5 ] = { 0, 120, 60, 60, 40 } ;
2638285612Sdelphij
2639285612Sdelphij#define	TELJJY_STAY_CLOCK_STATE  	0
2640285612Sdelphij#define	TELJJY_CHANGE_CLOCK_STATE	1
2641285612Sdelphij
2642285612Sdelphij/* Command and replay */
2643285612Sdelphij
2644285612Sdelphij#define	TELJJY_REPLY_NONE	0
2645285612Sdelphij#define	TELJJY_REPLY_4DATE	1
2646285612Sdelphij#define	TELJJY_REPLY_TIME	2
2647285612Sdelphij#define	TELJJY_REPLY_LEAPSEC	3
2648285612Sdelphij#define	TELJJY_REPLY_LOOP	4
2649285612Sdelphij#define	TELJJY_REPLY_PROMPT	5
2650285612Sdelphij#define	TELJJY_REPLY_LOOPBACK	6
2651285612Sdelphij#define	TELJJY_REPLY_COM	7
2652285612Sdelphij
2653285612Sdelphij#define	TELJJY_COMMAND_START_SKIP_LOOPBACK	7
2654285612Sdelphij
2655285612Sdelphijstatic  struct
2656285612Sdelphij{
2657285612Sdelphij	const char	*command ;
2658285612Sdelphij	int	commandLength ;
2659285612Sdelphij	int	iEchobackReplyLength ;
2660285612Sdelphij	int	iExpectedReplyType   ;
2661285612Sdelphij	int	iExpectedReplyLength ;
2662285612Sdelphij} teljjy_command_sequence[] =
2663285612Sdelphij{
2664285612Sdelphij	{ NULL, 0, 0, 0, 0 }, /* Idle */
2665285612Sdelphij	{ "LOOP\r"   , 5, 4, TELJJY_REPLY_LOOP    , 0 }, /* Getting into loopback mode */
2666285612Sdelphij	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2667285612Sdelphij	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2668285612Sdelphij	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2669285612Sdelphij	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2670285612Sdelphij	{ ">"        , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
2671285612Sdelphij	{ "COM\r"    , 4, 3, TELJJY_REPLY_COM     , 0 }, /* Exit from loopback mode */
2672285612Sdelphij	/* TELJJY_COMMAND_START_SKIP_LOOPBACK */
2673285612Sdelphij	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2674285612Sdelphij	{ "4DATE\r"  , 6, 5, TELJJY_REPLY_4DATE   , 8 },
2675285612Sdelphij	{ "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
2676285612Sdelphij	{ "TIME\r"   , 5, 4, TELJJY_REPLY_TIME    , 6 },
2677285612Sdelphij	{ "BYE\r"    , 4, 3, TELJJY_REPLY_NONE    , 0 },
2678285612Sdelphij	/* End of command */
2679285612Sdelphij	{ NULL, 0, 0, 0, 0 }
2680285612Sdelphij} ;
2681285612Sdelphij
2682285612Sdelphij#define	TELJJY_LOOPBACK_DELAY_THRESHOLD		700 /* Milli second */
2683285612Sdelphij
2684285612Sdelphij#ifdef	DEBUG
2685285612Sdelphij#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 ) ; } }
2686285612Sdelphij#else
2687285612Sdelphij#define	DEBUG_TELJJY_PRINTF(sFunc)
2688285612Sdelphij#endif
2689285612Sdelphij
2690285612Sdelphij/**************************************************************************************************/
2691285612Sdelphij
2692182007Srobertostatic int
2693285612Sdelphijjjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
2694182007Sroberto{
2695182007Sroberto
2696285612Sdelphij	char	sLog [ 80 ], sFirstThreeDigits [ 4 ] ;
2697316722Sdelphij	int	iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
2698316722Sdelphij	size_t  i ;
2699316722Sdelphij	size_t	iFirstThreeDigitsCount ;
2700182007Sroberto
2701285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
2702182007Sroberto
2703285612Sdelphij	up->unittype  = UNITTYPE_TELEPHONE ;
2704285612Sdelphij	up->linespeed = SPEED232_TELEPHONE ;
2705285612Sdelphij	up->linediscipline = LDISC_RAW ;
2706285612Sdelphij
2707285612Sdelphij	up->pRawBreak = teljjy_raw_break ;
2708285612Sdelphij	up->bWaitBreakString = TRUE ;
2709285612Sdelphij
2710285612Sdelphij	up->bSkipCntrlCharOnly = TRUE ;
2711285612Sdelphij
2712285612Sdelphij	up->iClockState = TELJJY_STATE_IDLE ;
2713285612Sdelphij	up->iClockEvent = TELJJY_EVENT_NULL ;
2714285612Sdelphij
2715285612Sdelphij	/* Check the telephone number */
2716285612Sdelphij
2717285612Sdelphij	if ( sys_phone[0] == NULL ) {
2718285612Sdelphij		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
2719285612Sdelphij		up->bInitError = TRUE ;
2720285612Sdelphij		return 1 ;
2721285612Sdelphij	}
2722285612Sdelphij
2723285612Sdelphij	if ( sys_phone[1] != NULL ) {
2724285612Sdelphij		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
2725285612Sdelphij		up->bInitError = TRUE ;
2726285612Sdelphij		return 1 ;
2727285612Sdelphij	}
2728285612Sdelphij
2729285612Sdelphij	iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
2730285612Sdelphij	for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
2731294569Sdelphij		if ( isdigit( (u_char)sys_phone[0][i] ) ) {
2732285612Sdelphij			if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
2733294569Sdelphij				sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ;
2734285612Sdelphij			}
2735285612Sdelphij			iNumberOfDigitsOfPhoneNumber ++ ;
2736294569Sdelphij		} else if ( sys_phone[0][i] == ',' ) {
2737285612Sdelphij			iCommaCount ++ ;
2738285612Sdelphij			if ( iCommaCount > 1 ) {
2739285612Sdelphij				msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
2740285612Sdelphij				up->bInitError = TRUE ;
2741285612Sdelphij				return 1 ;
2742285612Sdelphij			}
2743285612Sdelphij			iFirstThreeDigitsCount = 0 ;
2744285612Sdelphij			iCommaPosition = i ;
2745294569Sdelphij		} else if ( sys_phone[0][i] != '-' ) {
2746285612Sdelphij			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
2747285612Sdelphij			up->bInitError = TRUE ;
2748285612Sdelphij			return 1 ;
2749285612Sdelphij		}
2750285612Sdelphij	}
2751285612Sdelphij	sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
2752285612Sdelphij
2753285612Sdelphij	if ( iCommaCount == 1 ) {
2754285612Sdelphij		if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
2755285612Sdelphij			msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
2756285612Sdelphij			up->bInitError = TRUE ;
2757285612Sdelphij			return 1 ;
2758285612Sdelphij		}
2759285612Sdelphij	}
2760285612Sdelphij
2761285612Sdelphij	if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
2762285612Sdelphij		/* Too short or too long */
2763285612Sdelphij		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
2764285612Sdelphij		up->bInitError = TRUE ;
2765285612Sdelphij		return 1 ;
2766285612Sdelphij	}
2767285612Sdelphij
2768285612Sdelphij	if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
2769285612Sdelphij	  || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
2770285612Sdelphij	  || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
2771285612Sdelphij	  || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
2772285612Sdelphij	  || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
2773285612Sdelphij	  || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
2774285612Sdelphij	  || ( sFirstThreeDigits[0] == '0' &&  sFirstThreeDigits[2] == '0' ) ) {
2775285612Sdelphij		/* Not allowed because of emergency numbers or special service numbers */
2776285612Sdelphij		msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
2777285612Sdelphij		up->bInitError = TRUE ;
2778285612Sdelphij		return 1 ;
2779285612Sdelphij	}
2780285612Sdelphij
2781285612Sdelphij	snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
2782285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2783285612Sdelphij
2784285612Sdelphij	if ( peer->minpoll < 8 ) {
2785285612Sdelphij		/* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
2786285612Sdelphij		int oldminpoll = peer->minpoll ;
2787285612Sdelphij		peer->minpoll = 8 ;
2788285612Sdelphij		if ( peer->ppoll < peer->minpoll ) {
2789285612Sdelphij			peer->ppoll = peer->minpoll ;
2790285612Sdelphij		}
2791285612Sdelphij		if ( peer->maxpoll < peer->minpoll ) {
2792285612Sdelphij			peer->maxpoll = peer->minpoll ;
2793285612Sdelphij		}
2794285612Sdelphij		snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
2795285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
2796285612Sdelphij	}
2797285612Sdelphij
2798285612Sdelphij	return 0 ;
2799285612Sdelphij
2800285612Sdelphij}
2801285612Sdelphij
2802285612Sdelphij/**************************************************************************************************/
2803285612Sdelphij
2804285612Sdelphijstatic int
2805285612Sdelphijjjy_receive_telephone ( struct recvbuf *rbufp )
2806285612Sdelphij{
2807285612Sdelphij#ifdef DEBUG
2808285612Sdelphij	static	const char	*sFunctionName = "jjy_receive_telephone" ;
2809285612Sdelphij#endif
2810285612Sdelphij
2811285612Sdelphij	struct	peer         *peer;
2812285612Sdelphij	struct	refclockproc *pp ;
2813285612Sdelphij	struct	jjyunit      *up ;
2814182007Sroberto	char	*pBuf ;
2815285612Sdelphij	int	iLen ;
2816285612Sdelphij	short	iPreviousModemState ;
2817182007Sroberto
2818285612Sdelphij	peer = rbufp->recv_peer ;
2819182007Sroberto	pp = peer->procptr ;
2820285612Sdelphij	up = pp->unitptr ;
2821182007Sroberto
2822285612Sdelphij	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2823285612Sdelphij
2824285612Sdelphij	if ( up->iClockState == TELJJY_STATE_IDLE
2825285612Sdelphij	  || up->iClockState == TELJJY_STATE_DAILOUT
2826285612Sdelphij	  || up->iClockState == TELJJY_STATE_BYE ) {
2827285612Sdelphij
2828285612Sdelphij		iPreviousModemState = getModemState( up ) ;
2829285612Sdelphij
2830285612Sdelphij		modem_receive ( rbufp ) ;
2831285612Sdelphij
2832285612Sdelphij		if ( iPreviousModemState != up->iModemState ) {
2833285612Sdelphij			/* Modem state is changed just now. */
2834285612Sdelphij			if ( isModemStateDisconnect( up->iModemState ) ) {
2835285612Sdelphij				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2836285612Sdelphij				teljjy_control ( peer, pp, up ) ;
2837285612Sdelphij			} else if ( isModemStateConnect( up->iModemState ) ) {
2838285612Sdelphij				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2839285612Sdelphij				teljjy_control ( peer, pp, up ) ;
2840285612Sdelphij			}
2841285612Sdelphij		}
2842285612Sdelphij
2843285612Sdelphij		return JJY_RECEIVE_WAIT ;
2844285612Sdelphij
2845285612Sdelphij	}
2846285612Sdelphij
2847182007Sroberto	if ( up->linediscipline == LDISC_RAW ) {
2848285612Sdelphij		pBuf = up->sTextBuf ;
2849285612Sdelphij		iLen = up->iTextBufLen ;
2850182007Sroberto	} else {
2851285612Sdelphij		pBuf = pp->a_lastcode ;
2852285612Sdelphij		iLen = pp->lencode ;
2853182007Sroberto	}
2854182007Sroberto
2855285612Sdelphij	up->iTeljjySilentTimer = 0 ;
2856285612Sdelphij	if      ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN  ; }
2857285612Sdelphij	else if ( iLen == 1 && strncmp( pBuf, ">"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
2858285612Sdelphij	else if ( iLen >= 1 && strncmp( pBuf, "?"      , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR  ; }
2859285612Sdelphij	else                                                        { up->iClockEvent = TELJJY_EVENT_DATA   ; }
2860182007Sroberto
2861285612Sdelphij	teljjy_control ( peer, pp, up ) ;
2862182007Sroberto
2863285612Sdelphij	return JJY_RECEIVE_WAIT ;
2864285612Sdelphij
2865285612Sdelphij}
2866285612Sdelphij
2867285612Sdelphij/**************************************************************************************************/
2868285612Sdelphij
2869285612Sdelphijstatic void
2870285612Sdelphijjjy_poll_telephone ( int unit, struct peer *peer )
2871285612Sdelphij{
2872182007Sroberto#ifdef DEBUG
2873285612Sdelphij	static const char *sFunctionName = "jjy_poll_telephone" ;
2874182007Sroberto#endif
2875285612Sdelphij
2876285612Sdelphij	struct	refclockproc *pp ;
2877285612Sdelphij	struct	jjyunit      *up ;
2878285612Sdelphij
2879285612Sdelphij	pp = peer->procptr ;
2880285612Sdelphij	up = pp->unitptr ;
2881285612Sdelphij
2882285612Sdelphij	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2883285612Sdelphij
2884285612Sdelphij	if ( up->iClockState == TELJJY_STATE_IDLE ) {
2885285612Sdelphij		up->iRawBufLen = 0 ;
2886285612Sdelphij		up->iLineBufLen = 0 ;
2887285612Sdelphij		up->iTextBufLen = 0 ;
2888285612Sdelphij	}
2889285612Sdelphij
2890285612Sdelphij	up->iClockEvent = TELJJY_EVENT_START ;
2891285612Sdelphij	teljjy_control ( peer, pp, up ) ;
2892285612Sdelphij
2893285612Sdelphij}
2894285612Sdelphij
2895285612Sdelphij/**************************************************************************************************/
2896285612Sdelphij
2897285612Sdelphijstatic void
2898285612Sdelphijjjy_timer_telephone ( int unit, struct peer *peer )
2899285612Sdelphij{
2900182007Sroberto#ifdef DEBUG
2901285612Sdelphij	static const char *sFunctionName = "jjy_timer_telephone" ;
2902182007Sroberto#endif
2903285612Sdelphij
2904285612Sdelphij	struct	refclockproc *pp ;
2905285612Sdelphij	struct	jjyunit      *up ;
2906285612Sdelphij	short	iPreviousModemState ;
2907285612Sdelphij
2908285612Sdelphij	pp = peer->procptr ;
2909285612Sdelphij	up = pp->unitptr ;
2910285612Sdelphij
2911285612Sdelphij	DEBUG_TELJJY_PRINTF( sFunctionName ) ;
2912285612Sdelphij
2913285612Sdelphij	if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
2914285612Sdelphij		up->iTeljjySilentTimer++ ;
2915285612Sdelphij		if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
2916285612Sdelphij			up->iClockEvent = TELJJY_EVENT_SILENT ;
2917285612Sdelphij			teljjy_control ( peer, pp, up ) ;
2918285612Sdelphij		}
2919285612Sdelphij	}
2920285612Sdelphij
2921285612Sdelphij	if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
2922285612Sdelphij		up->iTeljjyStateTimer++ ;
2923285612Sdelphij		if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
2924285612Sdelphij			up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
2925285612Sdelphij			teljjy_control ( peer, pp, up ) ;
2926285612Sdelphij		}
2927285612Sdelphij	}
2928285612Sdelphij
2929285612Sdelphij	if ( isModemStateTimerOn( up ) ) {
2930285612Sdelphij
2931285612Sdelphij		iPreviousModemState = getModemState( up ) ;
2932285612Sdelphij
2933285612Sdelphij		modem_timer ( unit, peer ) ;
2934285612Sdelphij
2935285612Sdelphij		if ( iPreviousModemState != up->iModemState ) {
2936285612Sdelphij			/* Modem state is changed just now. */
2937285612Sdelphij			if ( isModemStateDisconnect( up->iModemState ) ) {
2938285612Sdelphij				up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
2939285612Sdelphij				teljjy_control ( peer, pp, up ) ;
2940285612Sdelphij			} else if ( isModemStateConnect( up->iModemState ) ) {
2941285612Sdelphij				up->iClockEvent = TELJJY_EVENT_CONNECT ;
2942285612Sdelphij				teljjy_control ( peer, pp, up ) ;
2943182007Sroberto			}
2944182007Sroberto		}
2945182007Sroberto
2946285612Sdelphij	}
2947182007Sroberto
2948285612Sdelphij}
2949285612Sdelphij
2950285612Sdelphij/**************************************************************************************************/
2951285612Sdelphij
2952285612Sdelphijstatic void
2953285612Sdelphijteljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
2954285612Sdelphij{
2955285612Sdelphij
2956285612Sdelphij	int	i, rc ;
2957285612Sdelphij	short	iPostEvent = TELJJY_EVENT_NULL ;
2958285612Sdelphij
2959285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
2960285612Sdelphij
2961285612Sdelphij	rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
2962285612Sdelphij
2963285612Sdelphij	if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
2964285612Sdelphij		iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
2965182007Sroberto#ifdef DEBUG
2966285612Sdelphij		if ( debug ) {
2967285612Sdelphij			printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd  iPostEvent=%hd\n",
2968285612Sdelphij				up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
2969285612Sdelphij		}
2970182007Sroberto#endif
2971285612Sdelphij		up->iTeljjySilentTimer = 0 ;
2972285612Sdelphij		if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
2973285612Sdelphij			/* Telephone JJY state is changing now */
2974285612Sdelphij			up->iTeljjyStateTimer = 0 ;
2975285612Sdelphij			up->bLineError = FALSE ;
2976285612Sdelphij			up->iClockCommandSeq = 0 ;
2977285612Sdelphij			up->iTimestampCount = 0 ;
2978285612Sdelphij			up->iLoopbackCount = 0 ;
2979285612Sdelphij			for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
2980285612Sdelphij				up->bLoopbackTimeout[i] = FALSE ;
2981182007Sroberto			}
2982285612Sdelphij			if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
2983285612Sdelphij				/* Telephone JJY state is changing to IDLE just now */
2984285612Sdelphij				up->iProcessState = JJY_PROCESS_STATE_DONE ;
2985285612Sdelphij			}
2986285612Sdelphij		}
2987285612Sdelphij		up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
2988182007Sroberto
2989285612Sdelphij	}
2990182007Sroberto
2991285612Sdelphij	if ( iPostEvent != TELJJY_EVENT_NULL ) {
2992285612Sdelphij		up->iClockEvent = iPostEvent ;
2993285612Sdelphij		teljjy_control ( peer, pp, up ) ;
2994285612Sdelphij	}
2995285612Sdelphij
2996285612Sdelphij	up->iClockEvent = TELJJY_EVENT_NULL ;
2997285612Sdelphij
2998285612Sdelphij}
2999285612Sdelphij
3000285612Sdelphij/**************************************************************************************************/
3001285612Sdelphij
3002285612Sdelphijstatic void
3003285612Sdelphijteljjy_setDelay ( struct peer *peer, struct jjyunit *up )
3004285612Sdelphij{
3005285612Sdelphij
3006285612Sdelphij	char	sLog [ 60 ] ;
3007285612Sdelphij	int	milliSecond, microSecond ;
3008285612Sdelphij
3009285612Sdelphij	gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
3010285612Sdelphij
3011285612Sdelphij	up->delayTime[up->iLoopbackCount].tv_sec  -= up->sendTime[up->iLoopbackCount].tv_sec ;
3012285612Sdelphij	up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
3013285612Sdelphij	if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
3014285612Sdelphij		up->delayTime[up->iLoopbackCount].tv_sec -- ;
3015285612Sdelphij		up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
3016285612Sdelphij	}
3017285612Sdelphij
3018285612Sdelphij	milliSecond  = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
3019285612Sdelphij	microSecond  = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
3020285612Sdelphij	milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
3021285612Sdelphij
3022285612Sdelphij	snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
3023285612Sdelphij		  milliSecond, microSecond ) ;
3024285612Sdelphij
3025285612Sdelphij	if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
3026285612Sdelphij		/* Delay > 700 mS */
3027285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3028285612Sdelphij	} else {
3029285612Sdelphij		/* Delay <= 700 mS */
3030285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3031285612Sdelphij	}
3032285612Sdelphij
3033285612Sdelphij}
3034285612Sdelphij
3035285612Sdelphij/**************************************************************************************************/
3036285612Sdelphij
3037285612Sdelphijstatic int
3038285612Sdelphijteljjy_getDelay ( struct peer *peer, struct jjyunit *up )
3039285612Sdelphij{
3040285612Sdelphij
3041285612Sdelphij	struct	timeval maxTime, minTime, averTime ;
3042285612Sdelphij	int	i ;
3043285612Sdelphij	int	minIndex = 0, maxIndex = 0, iAverCount = 0 ;
3044285612Sdelphij	int	iThresholdSecond, iThresholdMicroSecond ;
3045285612Sdelphij	int	iPercent ;
3046285612Sdelphij
3047285612Sdelphij	minTime.tv_sec = minTime.tv_usec = 0 ;
3048285612Sdelphij	maxTime.tv_sec = maxTime.tv_usec = 0 ;
3049285612Sdelphij
3050285612Sdelphij	iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
3051285612Sdelphij	iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
3052285612Sdelphij
3053285612Sdelphij	up->iLoopbackValidCount = 0 ;
3054285612Sdelphij
3055285612Sdelphij	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3056285612Sdelphij		if ( up->bLoopbackTimeout[i]
3057285612Sdelphij		  || up->delayTime[i].tv_sec  > iThresholdSecond
3058285612Sdelphij		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3059285612Sdelphij		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3060285612Sdelphij			continue ;
3061285612Sdelphij		}
3062285612Sdelphij		if ( up->iLoopbackValidCount == 0 ) {
3063285612Sdelphij			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3064285612Sdelphij			minTime.tv_usec = up->delayTime[i].tv_usec ;
3065285612Sdelphij			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3066285612Sdelphij			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3067285612Sdelphij			minIndex = maxIndex = i ;
3068285612Sdelphij		} else if ( minTime.tv_sec  > up->delayTime[i].tv_sec
3069285612Sdelphij		       || ( minTime.tv_sec == up->delayTime[i].tv_sec
3070285612Sdelphij		         && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
3071285612Sdelphij			minTime.tv_sec  = up->delayTime[i].tv_sec  ;
3072285612Sdelphij			minTime.tv_usec = up->delayTime[i].tv_usec ;
3073285612Sdelphij			minIndex = i ;
3074285612Sdelphij		} else if ( maxTime.tv_sec  < up->delayTime[i].tv_sec
3075285612Sdelphij		       || ( maxTime.tv_sec == up->delayTime[i].tv_sec
3076285612Sdelphij		         && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
3077285612Sdelphij			maxTime.tv_sec  = up->delayTime[i].tv_sec  ;
3078285612Sdelphij			maxTime.tv_usec = up->delayTime[i].tv_usec ;
3079285612Sdelphij			maxIndex = i ;
3080285612Sdelphij		}
3081285612Sdelphij		up->iLoopbackValidCount ++ ;
3082285612Sdelphij	}
3083285612Sdelphij
3084285612Sdelphij	if ( up->iLoopbackValidCount < 2 ) {
3085285612Sdelphij		return -1 ;
3086285612Sdelphij	}
3087285612Sdelphij
3088285612Sdelphij	averTime.tv_usec = 0;
3089285612Sdelphij
3090285612Sdelphij	for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
3091285612Sdelphij		if ( up->bLoopbackTimeout[i]
3092285612Sdelphij		  || up->delayTime[i].tv_sec  > iThresholdSecond
3093285612Sdelphij		|| ( up->delayTime[i].tv_sec == iThresholdSecond
3094285612Sdelphij		  && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
3095285612Sdelphij			continue ;
3096285612Sdelphij		}
3097285612Sdelphij		if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
3098285612Sdelphij			continue ;
3099285612Sdelphij		}
3100285612Sdelphij		if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
3101285612Sdelphij			continue ;
3102285612Sdelphij		}
3103285612Sdelphij		averTime.tv_usec += up->delayTime[i].tv_usec ;
3104285612Sdelphij		iAverCount ++ ;
3105285612Sdelphij	}
3106285612Sdelphij
3107285612Sdelphij	if ( iAverCount == 0 ) {
3108285612Sdelphij		/* This is never happened. */
3109285612Sdelphij		/* Previous for-if-for blocks assure iAverCount > 0. */
3110285612Sdelphij		/* This code avoids a claim by the coverity scan tool. */
3111285612Sdelphij		return -1 ;
3112285612Sdelphij	}
3113285612Sdelphij
3114285612Sdelphij	/* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
3115285612Sdelphij
3116285612Sdelphij	iPercent = ( peer->ttl - 100 ) ;
3117285612Sdelphij
3118285612Sdelphij	/* Average delay time in milli second */
3119285612Sdelphij
3120285612Sdelphij	return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
3121285612Sdelphij
3122285612Sdelphij}
3123285612Sdelphij
3124285612Sdelphij/******************************/
3125285612Sdelphijstatic int
3126285612Sdelphijteljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3127285612Sdelphij{
3128285612Sdelphij
3129285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
3130285612Sdelphij
3131285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3132285612Sdelphij
3133285612Sdelphij}
3134285612Sdelphij
3135285612Sdelphij/******************************/
3136285612Sdelphijstatic int
3137285612Sdelphijteljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3138285612Sdelphij{
3139285612Sdelphij
3140285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
3141285612Sdelphij
3142285612Sdelphij	modem_connect ( peer->refclkunit, peer ) ;
3143285612Sdelphij
3144285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3145285612Sdelphij
3146285612Sdelphij}
3147285612Sdelphij
3148285612Sdelphij/******************************/
3149285612Sdelphijstatic int
3150285612Sdelphijteljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3151285612Sdelphij{
3152285612Sdelphij
3153285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
3154285612Sdelphij
3155285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3156285612Sdelphij
3157285612Sdelphij}
3158285612Sdelphij
3159285612Sdelphij/******************************/
3160285612Sdelphijstatic int
3161285612Sdelphijteljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3162285612Sdelphij{
3163285612Sdelphij
3164285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
3165285612Sdelphij
3166285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3167285612Sdelphij
3168285612Sdelphij}
3169285612Sdelphij
3170285612Sdelphij/******************************/
3171285612Sdelphijstatic int
3172285612Sdelphijteljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3173285612Sdelphij{
3174285612Sdelphij
3175285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
3176285612Sdelphij
3177285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3178285612Sdelphij
3179285612Sdelphij}
3180285612Sdelphij
3181285612Sdelphij/******************************/
3182285612Sdelphijstatic int
3183285612Sdelphijteljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3184285612Sdelphij{
3185285612Sdelphij
3186285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
3187285612Sdelphij
3188285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3189285612Sdelphij
3190285612Sdelphij}
3191285612Sdelphij
3192285612Sdelphij/******************************/
3193285612Sdelphijstatic int
3194285612Sdelphijteljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3195285612Sdelphij{
3196285612Sdelphij
3197285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
3198285612Sdelphij
3199285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3200285612Sdelphij
3201285612Sdelphij}
3202285612Sdelphij
3203285612Sdelphij/******************************/
3204285612Sdelphijstatic int
3205285612Sdelphijteljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3206285612Sdelphij{
3207285612Sdelphij
3208285612Sdelphij	int	i ;
3209285612Sdelphij
3210285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
3211285612Sdelphij
3212285612Sdelphij	up->bLineError = FALSE ;
3213285612Sdelphij	up->iClockCommandSeq = 0 ;
3214285612Sdelphij	up->iTimestampCount = 0 ;
3215285612Sdelphij	up->iLoopbackCount = 0 ;
3216285612Sdelphij	for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3217285612Sdelphij		up->bLoopbackTimeout[i] = FALSE ;
3218285612Sdelphij	}
3219285612Sdelphij
3220285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3221285612Sdelphij
3222285612Sdelphij}
3223285612Sdelphij
3224285612Sdelphij/******************************/
3225285612Sdelphijstatic int
3226285612Sdelphijteljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3227285612Sdelphij{
3228285612Sdelphij
3229294569Sdelphij	const char *	pCmd ;
3230294569Sdelphij	int		iCmdLen ;
3231285612Sdelphij
3232285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
3233285612Sdelphij
3234285612Sdelphij	/* Send a guest user ID */
3235285612Sdelphij	pCmd = "TJJY\r" ;
3236285612Sdelphij
3237285612Sdelphij	/* Send login ID */
3238285612Sdelphij	iCmdLen = strlen( pCmd ) ;
3239285612Sdelphij	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
3240285612Sdelphij		refclock_report( peer, CEVNT_FAULT ) ;
3241285612Sdelphij	}
3242285612Sdelphij
3243285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3244285612Sdelphij
3245285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3246285612Sdelphij
3247285612Sdelphij}
3248285612Sdelphij
3249285612Sdelphij/******************************/
3250285612Sdelphijstatic int
3251285612Sdelphijteljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3252285612Sdelphij{
3253285612Sdelphij
3254285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
3255285612Sdelphij
3256285612Sdelphij	if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
3257285612Sdelphij		refclock_report( peer, CEVNT_FAULT ) ;
3258285612Sdelphij	}
3259285612Sdelphij
3260285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
3261285612Sdelphij
3262285612Sdelphij	up->iTeljjySilentTimer = 0 ;
3263285612Sdelphij
3264285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3265285612Sdelphij
3266285612Sdelphij}
3267285612Sdelphij
3268285612Sdelphij/******************************/
3269285612Sdelphijstatic int
3270285612Sdelphijteljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3271285612Sdelphij{
3272285612Sdelphij
3273285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
3274285612Sdelphij
3275285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3276285612Sdelphij
3277285612Sdelphij}
3278285612Sdelphij
3279285612Sdelphij/******************************/
3280285612Sdelphijstatic int
3281285612Sdelphijteljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3282285612Sdelphij{
3283285612Sdelphij
3284285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
3285285612Sdelphij
3286285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3287285612Sdelphij
3288285612Sdelphij}
3289285612Sdelphij
3290285612Sdelphij/******************************/
3291285612Sdelphijstatic int
3292285612Sdelphijteljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3293285612Sdelphij{
3294285612Sdelphij
3295285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
3296285612Sdelphij
3297285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3298285612Sdelphij
3299285612Sdelphij}
3300285612Sdelphij
3301285612Sdelphij/******************************/
3302285612Sdelphijstatic int
3303285612Sdelphijteljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3304285612Sdelphij{
3305285612Sdelphij
3306294569Sdelphij	const char *	pCmd ;
3307294569Sdelphij	int		i, iLen, iNextClockState ;
3308330567Sgordon	char	sLog [ 120 ] ;
3309285612Sdelphij
3310285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
3311285612Sdelphij
3312285612Sdelphij	if ( up->iClockCommandSeq > 0
3313285612Sdelphij	  && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
3314285612Sdelphij		/* Command sequence has been completed */
3315285612Sdelphij	  	return TELJJY_CHANGE_CLOCK_STATE ;
3316285612Sdelphij	}
3317285612Sdelphij
3318285612Sdelphij	if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
3319285612Sdelphij		/* Skip loopback */
3320285612Sdelphij
3321285612Sdelphij		up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
3322285612Sdelphij
3323285612Sdelphij	} else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
3324285612Sdelphij		/* Loopback start */
3325285612Sdelphij
3326285612Sdelphij		up->iLoopbackCount = 0 ;
3327285612Sdelphij		for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
3328285612Sdelphij			up->bLoopbackTimeout[i] = FALSE ;
3329285612Sdelphij		}
3330285612Sdelphij
3331285612Sdelphij	} else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
3332285612Sdelphij		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3333285612Sdelphij		 && up->iLoopbackCount < MAX_LOOPBACK ) {
3334285612Sdelphij		/* Loopback character comes */
3335182007Sroberto#ifdef DEBUG
3336285612Sdelphij		if ( debug ) {
3337330567Sgordon			printf( "refclock_jjy.c : teljjy_conn_send : iClockCommandSeq=%d iLoopbackCount=%d\n",
3338330567Sgordon				 up->iClockCommandSeq, up->iLoopbackCount ) ;
3339285612Sdelphij		}
3340182007Sroberto#endif
3341285612Sdelphij
3342285612Sdelphij		teljjy_setDelay( peer, up ) ;
3343285612Sdelphij
3344285612Sdelphij		up->iLoopbackCount ++ ;
3345285612Sdelphij
3346285612Sdelphij	}
3347285612Sdelphij
3348285612Sdelphij	up->iClockCommandSeq++ ;
3349285612Sdelphij
3350285612Sdelphij	pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
3351285612Sdelphij	iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
3352285612Sdelphij
3353285612Sdelphij	if ( pCmd != NULL ) {
3354285612Sdelphij
3355285612Sdelphij		if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
3356285612Sdelphij			refclock_report( peer, CEVNT_FAULT ) ;
3357182007Sroberto		}
3358182007Sroberto
3359285612Sdelphij		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3360285612Sdelphij			/* Loopback character and timestamp */
3361330567Sgordon			if ( up->iLoopbackCount < MAX_LOOPBACK ) {
3362330567Sgordon				gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
3363330567Sgordon				up->bLoopbackMode = TRUE ;
3364330567Sgordon			} else {
3365330567Sgordon				/* This else-block is never come. */
3366330567Sgordon				/* This code avoid wrong report of the coverity static analysis scan tool. */
3367330567Sgordon				snprintf( sLog, sizeof(sLog)-1, "refclock_jjy.c ; teljjy_conn_send ; iClockCommandSeq=%d iLoopbackCount=%d MAX_LOOPBACK=%d",
3368330567Sgordon					  up->iClockCommandSeq, up->iLoopbackCount, MAX_LOOPBACK ) ;
3369330567Sgordon				jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_BUG, sLog ) ;
3370330567Sgordon				msyslog ( LOG_ERR, "%s", sLog ) ;
3371330567Sgordon				up->bLoopbackMode = FALSE ;
3372330567Sgordon			}
3373285612Sdelphij		} else {
3374285612Sdelphij			/* Regular command */
3375285612Sdelphij			up->bLoopbackMode = FALSE ;
3376285612Sdelphij		}
3377182007Sroberto
3378285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3379182007Sroberto
3380285612Sdelphij		if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
3381285612Sdelphij			/* Last command of the command sequence */
3382285612Sdelphij			iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3383285612Sdelphij		} else {
3384285612Sdelphij			/* More commands to be issued */
3385285612Sdelphij			iNextClockState = TELJJY_STAY_CLOCK_STATE ;
3386285612Sdelphij		}
3387285612Sdelphij
3388285612Sdelphij	} else {
3389285612Sdelphij
3390285612Sdelphij		iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
3391285612Sdelphij
3392285612Sdelphij	}
3393285612Sdelphij
3394285612Sdelphij	return iNextClockState ;
3395285612Sdelphij
3396285612Sdelphij}
3397285612Sdelphij
3398285612Sdelphij/******************************/
3399285612Sdelphijstatic int
3400285612Sdelphijteljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3401285612Sdelphij{
3402285612Sdelphij
3403285612Sdelphij	char	*pBuf ;
3404285612Sdelphij	int	iLen, rc ;
3405285612Sdelphij	char	sLog [ 80 ] ;
3406285612Sdelphij	char	bAdjustment ;
3407285612Sdelphij
3408285612Sdelphij
3409285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
3410285612Sdelphij
3411285612Sdelphij	if ( up->linediscipline == LDISC_RAW ) {
3412285612Sdelphij		pBuf = up->sTextBuf ;
3413285612Sdelphij		iLen = up->iTextBufLen ;
3414285612Sdelphij	} else {
3415285612Sdelphij		pBuf = pp->a_lastcode ;
3416285612Sdelphij		iLen = pp->lencode ;
3417285612Sdelphij	}
3418285612Sdelphij
3419285612Sdelphij	if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3420285612Sdelphij	  && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
3421285612Sdelphij	  && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
3422285612Sdelphij	  && up->iLoopbackCount < MAX_LOOPBACK ) {
3423285612Sdelphij		/* Loopback */
3424285612Sdelphij
3425285612Sdelphij		teljjy_setDelay( peer, up ) ;
3426285612Sdelphij
3427285612Sdelphij		up->iLoopbackCount ++ ;
3428285612Sdelphij
3429285612Sdelphij	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
3430285612Sdelphij	    && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
3431285612Sdelphij		/* Maybe echoback */
3432285612Sdelphij
3433285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
3434285612Sdelphij
3435285612Sdelphij	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3436285612Sdelphij		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
3437285612Sdelphij		/* 4DATE<CR> -> YYYYMMDD<CR> */
3438285612Sdelphij
3439285612Sdelphij		rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
3440285612Sdelphij
3441285612Sdelphij		if ( rc != 3 || up->year < 2000 || 2099 <= up->year
3442285612Sdelphij		  || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
3443285612Sdelphij			/* Invalid date */
3444285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
3445285612Sdelphij				  rc, up->year, up->month, up->day ) ;
3446285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3447285612Sdelphij			up->bLineError = TRUE ;
3448285612Sdelphij		}
3449285612Sdelphij
3450285612Sdelphij	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3451285612Sdelphij		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
3452285612Sdelphij	         && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
3453285612Sdelphij		/* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
3454285612Sdelphij
3455285612Sdelphij		rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
3456285612Sdelphij
3457285612Sdelphij		if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
3458285612Sdelphij			/* Invalid leap second */
3459285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
3460285612Sdelphij				  pBuf ) ;
3461285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3462285612Sdelphij			up->bLineError = TRUE ;
3463285612Sdelphij		}
3464285612Sdelphij
3465285612Sdelphij	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
3466285612Sdelphij		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
3467285612Sdelphij		/* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
3468285612Sdelphij
3469285612Sdelphij		rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
3470285612Sdelphij
3471285612Sdelphij		if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
3472285612Sdelphij			/* Invalid time */
3473285612Sdelphij			snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
3474285612Sdelphij				  rc, up->hour, up->minute, up->second ) ;
3475285612Sdelphij			jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3476285612Sdelphij			up->bLineError = TRUE ;
3477285612Sdelphij		}
3478285612Sdelphij		up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
3479285612Sdelphij
3480285612Sdelphij		up->iTimestampCount++ ;
3481285612Sdelphij
3482285612Sdelphij		if ( up->iTimestampCount == 6 && ! up->bLineError ) {
3483285612Sdelphij#if DEBUG
3484285612Sdelphij			printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
3485285612Sdelphij				up->bLineError,
3486285612Sdelphij				up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
3487285612Sdelphij#endif
3488285612Sdelphij			bAdjustment = TRUE ;
3489285612Sdelphij
3490285612Sdelphij			if ( peer->ttl == 100 ) {
3491285612Sdelphij				/* mode=100 */
3492285612Sdelphij				up->msecond = 0 ;
3493285612Sdelphij			} else {
3494285612Sdelphij				/* mode=101 to 110 */
3495285612Sdelphij				up->msecond = teljjy_getDelay( peer, up ) ;
3496285612Sdelphij				if (up->msecond < 0 ) {
3497285612Sdelphij					up->msecond = 0 ;
3498285612Sdelphij					bAdjustment = FALSE ;
3499182007Sroberto				}
3500182007Sroberto			}
3501182007Sroberto
3502285612Sdelphij			if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
3503285612Sdelphij			  &&   up->iTimestamp[2]        <= up->iTimestamp[3]
3504285612Sdelphij			  && ( up->iTimestamp[3] +  1 ) == up->iTimestamp[4]
3505285612Sdelphij			  && ( up->iTimestamp[4] +  1 ) == up->iTimestamp[5] ) {
3506285612Sdelphij				/* Non over midnight */
3507285612Sdelphij
3508285612Sdelphij				jjy_synctime( peer, pp, up ) ;
3509285612Sdelphij
3510285612Sdelphij				if ( peer->ttl != 100 ) {
3511285612Sdelphij					if ( bAdjustment ) {
3512285612Sdelphij						snprintf( sLog, sizeof(sLog),
3513285612Sdelphij							  JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
3514285612Sdelphij							  up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3515285612Sdelphij						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
3516285612Sdelphij					} else {
3517285612Sdelphij						snprintf( sLog, sizeof(sLog),
3518285612Sdelphij							  JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
3519285612Sdelphij							   up->iLoopbackValidCount, MAX_LOOPBACK ) ;
3520285612Sdelphij						jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3521285612Sdelphij					}
3522285612Sdelphij				}
3523285612Sdelphij
3524182007Sroberto			}
3525182007Sroberto		}
3526182007Sroberto
3527285612Sdelphij	} else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
3528285612Sdelphij		 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3529285612Sdelphij		/* Loopback noise ( Unexpected replay ) */
3530182007Sroberto
3531285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
3532285612Sdelphij			  pBuf ) ;
3533285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
3534182007Sroberto
3535285612Sdelphij	} else {
3536285612Sdelphij
3537285612Sdelphij		up->bLineError = TRUE ;
3538285612Sdelphij
3539285612Sdelphij		snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
3540285612Sdelphij			  pBuf ) ;
3541285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
3542285612Sdelphij
3543285612Sdelphij	}
3544285612Sdelphij
3545285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3546285612Sdelphij
3547285612Sdelphij}
3548285612Sdelphij
3549285612Sdelphij/******************************/
3550285612Sdelphijstatic int
3551285612Sdelphijteljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3552285612Sdelphij{
3553285612Sdelphij
3554294569Sdelphij	const char *	pCmd ;
3555285612Sdelphij
3556285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
3557285612Sdelphij
3558285612Sdelphij	if ( up->iClockCommandSeq >= 1
3559285612Sdelphij	  && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
3560285612Sdelphij		/* Loopback */
3561182007Sroberto#ifdef DEBUG
3562182007Sroberto		if ( debug ) {
3563285612Sdelphij			printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
3564182007Sroberto		}
3565182007Sroberto#endif
3566285612Sdelphij		if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
3567285612Sdelphij			up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
3568182007Sroberto		}
3569285612Sdelphij		up->iTeljjySilentTimer = 0 ;
3570285612Sdelphij		return teljjy_conn_send( peer, pp, up ) ;
3571285612Sdelphij	} else {
3572285612Sdelphij		pCmd = "\r" ;
3573285612Sdelphij	}
3574182007Sroberto
3575285612Sdelphij	if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
3576285612Sdelphij		refclock_report( peer, CEVNT_FAULT ) ;
3577182007Sroberto	}
3578182007Sroberto
3579285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
3580182007Sroberto
3581285612Sdelphij	up->iTeljjySilentTimer = 0 ;
3582285612Sdelphij
3583285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3584285612Sdelphij
3585182007Sroberto}
3586182007Sroberto
3587285612Sdelphij/******************************/
3588285612Sdelphijstatic int
3589285612Sdelphijteljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3590285612Sdelphij{
3591285612Sdelphij
3592285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
3593285612Sdelphij
3594285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3595285612Sdelphij
3596285612Sdelphij}
3597285612Sdelphij
3598285612Sdelphij/******************************/
3599285612Sdelphijstatic int
3600285612Sdelphijteljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3601285612Sdelphij{
3602285612Sdelphij
3603285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
3604285612Sdelphij
3605285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3606285612Sdelphij
3607285612Sdelphij}
3608285612Sdelphij
3609285612Sdelphij/******************************/
3610285612Sdelphijstatic int
3611285612Sdelphijteljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3612285612Sdelphij{
3613285612Sdelphij
3614285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
3615285612Sdelphij
3616285612Sdelphij	return TELJJY_CHANGE_CLOCK_STATE ;
3617285612Sdelphij
3618285612Sdelphij}
3619285612Sdelphij
3620285612Sdelphij/******************************/
3621285612Sdelphijstatic int
3622285612Sdelphijteljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3623285612Sdelphij{
3624285612Sdelphij
3625285612Sdelphij	DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
3626285612Sdelphij
3627285612Sdelphij	modem_disconnect ( peer->refclkunit, peer ) ;
3628285612Sdelphij
3629285612Sdelphij	return TELJJY_STAY_CLOCK_STATE ;
3630285612Sdelphij
3631285612Sdelphij}
3632285612Sdelphij
3633285612Sdelphij/*################################################################################################*/
3634285612Sdelphij/*################################################################################################*/
3635285612Sdelphij/*##												##*/
3636285612Sdelphij/*##    Modem control finite state machine							##*/
3637285612Sdelphij/*##												##*/
3638285612Sdelphij/*################################################################################################*/
3639285612Sdelphij/*################################################################################################*/
3640285612Sdelphij
3641285612Sdelphij/* struct jjyunit.iModemState */
3642285612Sdelphij
3643285612Sdelphij#define	MODEM_STATE_DISCONNECT		0
3644285612Sdelphij#define	MODEM_STATE_INITIALIZE		1
3645285612Sdelphij#define	MODEM_STATE_DAILING		2
3646285612Sdelphij#define	MODEM_STATE_CONNECT		3
3647285612Sdelphij#define	MODEM_STATE_ESCAPE		4
3648285612Sdelphij
3649285612Sdelphij/* struct jjyunit.iModemEvent */
3650285612Sdelphij
3651285612Sdelphij#define MODEM_EVENT_NULL		0
3652285612Sdelphij#define	MODEM_EVENT_INITIALIZE		1
3653285612Sdelphij#define	MODEM_EVENT_DIALOUT		2
3654285612Sdelphij#define	MODEM_EVENT_DISCONNECT		3
3655285612Sdelphij#define	MODEM_EVENT_RESP_OK		4
3656285612Sdelphij#define	MODEM_EVENT_RESP_CONNECT	5
3657285612Sdelphij#define	MODEM_EVENT_RESP_RING		6
3658285612Sdelphij#define	MODEM_EVENT_RESP_NO_CARRIER	7
3659285612Sdelphij#define	MODEM_EVENT_RESP_ERROR		8
3660285612Sdelphij#define	MODEM_EVENT_RESP_CONNECT_X	9
3661285612Sdelphij#define	MODEM_EVENT_RESP_NO_DAILTONE	10
3662285612Sdelphij#define	MODEM_EVENT_RESP_BUSY		11
3663285612Sdelphij#define	MODEM_EVENT_RESP_NO_ANSWER	12
3664285612Sdelphij#define	MODEM_EVENT_RESP_UNKNOWN	13
3665285612Sdelphij#define	MODEM_EVENT_SILENT		14
3666285612Sdelphij#define	MODEM_EVENT_TIMEOUT		15
3667285612Sdelphij
3668285612Sdelphij/* Function prototypes */
3669285612Sdelphij
3670285612Sdelphijstatic	void	modem_control		( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3671285612Sdelphij
3672285612Sdelphijstatic	int 	modem_disc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3673285612Sdelphijstatic	int 	modem_disc_init  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3674285612Sdelphijstatic	int 	modem_init_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3675285612Sdelphijstatic	int 	modem_init_start 	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3676285612Sdelphijstatic	int 	modem_init_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3677285612Sdelphijstatic	int 	modem_init_resp00	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3678285612Sdelphijstatic	int 	modem_init_resp04	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3679285612Sdelphijstatic	int 	modem_dial_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3680285612Sdelphijstatic	int 	modem_dial_dialout	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3681285612Sdelphijstatic	int 	modem_dial_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3682285612Sdelphijstatic	int 	modem_dial_connect	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3683285612Sdelphijstatic	int 	modem_dial_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3684285612Sdelphijstatic	int 	modem_conn_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3685285612Sdelphijstatic	int 	modem_conn_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3686285612Sdelphijstatic	int 	modem_esc_ignore	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3687285612Sdelphijstatic	int 	modem_esc_escape	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3688285612Sdelphijstatic	int 	modem_esc_data  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3689285612Sdelphijstatic	int 	modem_esc_silent	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3690285612Sdelphijstatic	int 	modem_esc_disc  	( struct peer *, struct refclockproc *, struct jjyunit * ) ;
3691285612Sdelphij
3692294569Sdelphijstatic int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) =
3693285612Sdelphij{                         	/*STATE_DISCONNECT   STATE_INITIALIZE   STATE_DAILING       STATE_CONNECT      STATE_ESCAPE     */
3694285612Sdelphij/* NULL                 */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3695285612Sdelphij/* INITIALIZE           */	{ modem_disc_init  , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
3696285612Sdelphij/* DIALOUT              */	{ modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
3697285612Sdelphij/* DISCONNECT           */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_escape },
3698285612Sdelphij/* RESP: 0: OK          */	{ modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3699285612Sdelphij/* RESP: 1: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3700285612Sdelphij/* RESP: 2: RING        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3701285612Sdelphij/* RESP: 3: NO CARRIER  */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3702285612Sdelphij/* RESP: 4: ERROR       */	{ modem_disc_ignore, modem_init_resp04, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3703285612Sdelphij/* RESP: 5: CONNECT     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data   },
3704285612Sdelphij/* RESP: 6: NO DAILTONE */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3705285612Sdelphij/* RESP: 7: BUSY        */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3706285612Sdelphij/* RESP: 8: NO ANSWER   */	{ modem_disc_ignore, modem_init_ignore, modem_dial_disc   , modem_conn_ignore, modem_esc_data   },
3707285612Sdelphij/* RESP: 9: UNKNOWN     */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data   },
3708285612Sdelphij/* SILENT               */	{ modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
3709285612Sdelphij/* TIMEOUT              */	{ modem_disc_ignore, modem_init_disc  , modem_dial_escape , modem_conn_escape, modem_esc_disc   }
3710285612Sdelphij} ;
3711285612Sdelphij
3712285612Sdelphijstatic short iModemNextState [ ] [ 5 ] =
3713285612Sdelphij{                         	/*STATE_DISCONNECT        STATE_INITIALIZE        STATE_DAILING        STATE_CONNECT        STATE_ESCAPE           */
3714285612Sdelphij/* NULL                 */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3715285612Sdelphij/* INITIALIZE           */	{ MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3716285612Sdelphij/* DIALOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3717285612Sdelphij/* DISCONNECT           */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE     },
3718285612Sdelphij/* RESP: 0: OK          */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3719285612Sdelphij/* RESP: 1: CONNECT     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3720285612Sdelphij/* RESP: 2: RING        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3721285612Sdelphij/* RESP: 3: NO CARRIER  */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3722285612Sdelphij/* RESP: 4: ERROR       */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING   , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3723285612Sdelphij/* RESP: 5: CONNECT X   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3724285612Sdelphij/* RESP: 6: NO DAILTONE */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3725285612Sdelphij/* RESP: 7: BUSY        */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3726285612Sdelphij/* RESP: 8: NO ANSWER   */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3727285612Sdelphij/* RESP: 9: UNKNOWN     */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE     },
3728285612Sdelphij/* SILENT               */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING   , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
3729285612Sdelphij/* TIMEOUT              */	{ MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE    , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
3730285612Sdelphij} ;
3731285612Sdelphij
3732285612Sdelphijstatic short iModemPostEvent [ ] [ 5 ] =
3733285612Sdelphij{                         	/*STATE_DISCONNECT        STATE_INITIALIZE     STATE_DAILING           STATE_CONNECT           STATE_ESCAPE     */
3734285612Sdelphij/* NULL                 */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3735285612Sdelphij/* INITIALIZE           */	{ MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3736285612Sdelphij/* DIALOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3737285612Sdelphij/* DISCONNECT           */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
3738285612Sdelphij/* RESP: 0: OK          */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3739285612Sdelphij/* RESP: 1: CONNECT     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3740285612Sdelphij/* RESP: 2: RING        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3741285612Sdelphij/* RESP: 3: NO CARRIER  */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3742285612Sdelphij/* RESP: 4: ERROR       */	{ MODEM_EVENT_NULL      , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3743285612Sdelphij/* RESP: 5: CONNECT X   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3744285612Sdelphij/* RESP: 6: NO DAILTONE */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3745285612Sdelphij/* RESP: 7: BUSY        */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3746285612Sdelphij/* RESP: 8: NO ANSWER   */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3747285612Sdelphij/* RESP: 9: UNKNOWN     */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3748285612Sdelphij/* SILENT               */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_NULL      , MODEM_EVENT_NULL      , MODEM_EVENT_NULL },
3749285612Sdelphij/* TIMEOUT              */	{ MODEM_EVENT_NULL      , MODEM_EVENT_NULL   , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
3750285612Sdelphij} ;
3751285612Sdelphij
3752285612Sdelphijstatic short iModemSilentTimeout [ 5 ] = { 0,  0,  0, 0,  5 } ;
3753285612Sdelphijstatic short iModemStateTimeout  [ 5 ] = { 0, 20, 90, 0, 20 } ;
3754285612Sdelphij
3755285612Sdelphij#define	STAY_MODEM_STATE	0
3756285612Sdelphij#define	CHANGE_MODEM_STATE	1
3757285612Sdelphij
3758285612Sdelphij#ifdef	DEBUG
3759285612Sdelphij#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 ) ; } }
3760285612Sdelphij#else
3761285612Sdelphij#define	DEBUG_MODEM_PRINTF(sFunc)
3762285612Sdelphij#endif
3763285612Sdelphij
3764182007Sroberto/**************************************************************************************************/
3765200576Sroberto
3766285612Sdelphijstatic short
3767285612SdelphijgetModemState ( struct jjyunit *up )
3768285612Sdelphij{
3769285612Sdelphij	return up->iModemState ;
3770285612Sdelphij}
3771285612Sdelphij
3772285612Sdelphij/**************************************************************************************************/
3773285612Sdelphij
3774200576Srobertostatic int
3775285612SdelphijisModemStateConnect ( short iCheckState )
3776200576Sroberto{
3777285612Sdelphij	return ( iCheckState == MODEM_STATE_CONNECT ) ;
3778285612Sdelphij}
3779200576Sroberto
3780285612Sdelphij/**************************************************************************************************/
3781200576Sroberto
3782285612Sdelphijstatic int
3783285612SdelphijisModemStateDisconnect ( short iCheckState )
3784285612Sdelphij{
3785285612Sdelphij	return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
3786285612Sdelphij}
3787200576Sroberto
3788285612Sdelphij/**************************************************************************************************/
3789200576Sroberto
3790285612Sdelphijstatic int
3791285612SdelphijisModemStateTimerOn ( struct jjyunit *up )
3792285612Sdelphij{
3793285612Sdelphij	return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
3794285612Sdelphij}
3795200576Sroberto
3796285612Sdelphij/**************************************************************************************************/
3797200576Sroberto
3798285612Sdelphijstatic void
3799285612Sdelphijmodem_connect ( int unit, struct peer *peer )
3800285612Sdelphij{
3801285612Sdelphij	struct	refclockproc	*pp;
3802285612Sdelphij	struct	jjyunit 	*up;
3803200576Sroberto
3804285612Sdelphij	pp = peer->procptr ;
3805285612Sdelphij	up = pp->unitptr ;
3806200576Sroberto
3807285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_connect" ) ;
3808200576Sroberto
3809285612Sdelphij	up->iModemEvent = MODEM_EVENT_INITIALIZE ;
3810285612Sdelphij
3811285612Sdelphij	modem_control ( peer, pp, up ) ;
3812285612Sdelphij
3813285612Sdelphij}
3814285612Sdelphij
3815285612Sdelphij/**************************************************************************************************/
3816285612Sdelphij
3817285612Sdelphijstatic void
3818285612Sdelphijmodem_disconnect ( int unit, struct peer *peer )
3819285612Sdelphij{
3820285612Sdelphij	struct	refclockproc	*pp;
3821285612Sdelphij	struct	jjyunit 	*up;
3822285612Sdelphij
3823285612Sdelphij	pp = peer->procptr ;
3824285612Sdelphij	up = pp->unitptr ;
3825285612Sdelphij
3826285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
3827285612Sdelphij
3828285612Sdelphij	up->iModemEvent = MODEM_EVENT_DISCONNECT ;
3829285612Sdelphij
3830285612Sdelphij	modem_control ( peer, pp, up ) ;
3831285612Sdelphij
3832285612Sdelphij}
3833285612Sdelphij
3834285612Sdelphij/**************************************************************************************************/
3835285612Sdelphij
3836285612Sdelphijstatic int
3837285612Sdelphijmodem_receive ( struct recvbuf *rbufp )
3838285612Sdelphij{
3839285612Sdelphij
3840285612Sdelphij	struct	peer		*peer;
3841285612Sdelphij	struct	jjyunit		*up;
3842285612Sdelphij	struct	refclockproc	*pp;
3843285612Sdelphij	char	*pBuf ;
3844316722Sdelphij	size_t	iLen ;
3845285612Sdelphij
3846200576Sroberto#ifdef DEBUG
3847285612Sdelphij	static const char *sFunctionName = "modem_receive" ;
3848200576Sroberto#endif
3849200576Sroberto
3850285612Sdelphij	peer = rbufp->recv_peer ;
3851285612Sdelphij	pp = peer->procptr ;
3852285612Sdelphij	up = pp->unitptr ;
3853285612Sdelphij
3854285612Sdelphij	DEBUG_MODEM_PRINTF( sFunctionName ) ;
3855285612Sdelphij
3856285612Sdelphij	if ( up->linediscipline == LDISC_RAW ) {
3857285612Sdelphij		pBuf = up->sTextBuf ;
3858285612Sdelphij		iLen = up->iTextBufLen ;
3859285612Sdelphij	} else {
3860285612Sdelphij		pBuf = pp->a_lastcode ;
3861285612Sdelphij		iLen = pp->lencode ;
3862285612Sdelphij	}
3863285612Sdelphij
3864285612Sdelphij	if      ( iLen ==  2 && strncmp( pBuf, "OK"         ,  2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK          ; }
3865285612Sdelphij	else if ( iLen ==  7 && strncmp( pBuf, "CONNECT"    ,  7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT     ; }
3866285612Sdelphij	else if ( iLen ==  4 && strncmp( pBuf, "RING"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING        ; }
3867285612Sdelphij	else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER  ; }
3868285612Sdelphij	else if ( iLen ==  5 && strncmp( pBuf, "ERROR"      ,  5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR       ; }
3869285612Sdelphij	else if ( iLen >=  8 && strncmp( pBuf, "CONNECT "   ,  8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X   ; }
3870285612Sdelphij	else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
3871285612Sdelphij	else if ( iLen ==  4 && strncmp( pBuf, "BUSY"       ,  4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY        ; }
3872285612Sdelphij	else if ( iLen ==  9 && strncmp( pBuf, "NO ANSWER"  ,  9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER   ; }
3873285612Sdelphij	else                                                              { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN     ; }
3874285612Sdelphij
3875200576Sroberto#ifdef DEBUG
3876285612Sdelphij	if ( debug ) {
3877285612Sdelphij		char	sResp [ 40 ] ;
3878316722Sdelphij		size_t	iCopyLen ;
3879285612Sdelphij		iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3880285612Sdelphij		strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
3881285612Sdelphij		sResp[iCopyLen] = 0 ;
3882316722Sdelphij		printf ( "refclock_jjy.c : modem_receive : iLen=%zu pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
3883285612Sdelphij	}
3884200576Sroberto#endif
3885285612Sdelphij	modem_control ( peer, pp, up ) ;
3886200576Sroberto
3887285612Sdelphij	return 0 ;
3888200576Sroberto
3889285612Sdelphij}
3890200576Sroberto
3891285612Sdelphij/**************************************************************************************************/
3892200576Sroberto
3893285612Sdelphijstatic void
3894285612Sdelphijmodem_timer ( int unit, struct peer *peer )
3895285612Sdelphij{
3896200576Sroberto
3897285612Sdelphij	struct	refclockproc *pp ;
3898285612Sdelphij	struct	jjyunit      *up ;
3899200576Sroberto
3900285612Sdelphij	pp = peer->procptr ;
3901285612Sdelphij	up = pp->unitptr ;
3902200576Sroberto
3903285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_timer" ) ;
3904285612Sdelphij
3905285612Sdelphij	if ( iModemSilentTimeout[up->iModemState] != 0 ) {
3906285612Sdelphij		up->iModemSilentTimer++ ;
3907285612Sdelphij		if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
3908285612Sdelphij			up->iModemEvent = MODEM_EVENT_SILENT ;
3909285612Sdelphij			modem_control ( peer, pp, up ) ;
3910285612Sdelphij		}
3911285612Sdelphij	}
3912285612Sdelphij
3913285612Sdelphij	if ( iModemStateTimeout[up->iModemState] != 0 ) {
3914285612Sdelphij		up->iModemStateTimer++ ;
3915285612Sdelphij		if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
3916285612Sdelphij			up->iModemEvent = MODEM_EVENT_TIMEOUT ;
3917285612Sdelphij			modem_control ( peer, pp, up ) ;
3918285612Sdelphij		}
3919285612Sdelphij	}
3920285612Sdelphij
3921200576Sroberto}
3922200576Sroberto
3923200576Sroberto/**************************************************************************************************/
3924285612Sdelphij
3925106163Srobertostatic void
3926285612Sdelphijmodem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3927106163Sroberto{
3928106163Sroberto
3929285612Sdelphij	int	rc ;
3930285612Sdelphij	short	iPostEvent = MODEM_EVENT_NULL ;
3931106163Sroberto
3932285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_control" ) ;
3933106163Sroberto
3934285612Sdelphij	rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
3935285612Sdelphij
3936285612Sdelphij	if ( rc == CHANGE_MODEM_STATE ) {
3937285612Sdelphij		iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
3938285612Sdelphij#ifdef DEBUG
3939285612Sdelphij		if ( debug ) {
3940285612Sdelphij			printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d  iPostEvent=%d\n",
3941285612Sdelphij				 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
3942285612Sdelphij		}
3943285612Sdelphij#endif
3944285612Sdelphij
3945285612Sdelphij		if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
3946285612Sdelphij			up->iModemSilentCount = 0 ;
3947285612Sdelphij			up->iModemStateTimer = 0 ;
3948285612Sdelphij			up->iModemCommandSeq = 0 ;
3949285612Sdelphij		}
3950285612Sdelphij
3951285612Sdelphij		up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
3952106163Sroberto	}
3953106163Sroberto
3954285612Sdelphij	if ( iPostEvent != MODEM_EVENT_NULL ) {
3955285612Sdelphij		up->iModemEvent = iPostEvent ;
3956285612Sdelphij		modem_control ( peer, pp, up ) ;
3957285612Sdelphij	}
3958285612Sdelphij
3959285612Sdelphij	up->iModemEvent = MODEM_EVENT_NULL ;
3960285612Sdelphij
3961285612Sdelphij}
3962285612Sdelphij
3963285612Sdelphij/******************************/
3964285612Sdelphijstatic int
3965285612Sdelphijmodem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3966285612Sdelphij{
3967285612Sdelphij
3968285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
3969285612Sdelphij
3970285612Sdelphij	return STAY_MODEM_STATE ;
3971285612Sdelphij
3972285612Sdelphij}
3973285612Sdelphij
3974285612Sdelphij/******************************/
3975285612Sdelphijstatic int
3976285612Sdelphijmodem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3977285612Sdelphij{
3978285612Sdelphij
3979285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
3980285612Sdelphij
3981285612Sdelphij	return CHANGE_MODEM_STATE ;
3982285612Sdelphij
3983285612Sdelphij}
3984285612Sdelphij
3985285612Sdelphij/******************************/
3986285612Sdelphijstatic int
3987285612Sdelphijmodem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3988285612Sdelphij{
3989285612Sdelphij
3990285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
3991285612Sdelphij
3992285612Sdelphij	return STAY_MODEM_STATE ;
3993285612Sdelphij
3994285612Sdelphij}
3995285612Sdelphij
3996285612Sdelphij/******************************/
3997285612Sdelphijstatic int
3998285612Sdelphijmodem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
3999285612Sdelphij{
4000285612Sdelphij
4001285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
4002285612Sdelphij
4003285612Sdelphij	up->iModemCommandSeq = 0 ;
4004285612Sdelphij
4005106163Sroberto#ifdef DEBUG
4006106163Sroberto	if ( debug ) {
4007285612Sdelphij		printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
4008106163Sroberto	}
4009106163Sroberto#endif
4010106163Sroberto
4011285612Sdelphij	return modem_init_resp00( peer, pp, up ) ;
4012106163Sroberto
4013285612Sdelphij}
4014106163Sroberto
4015285612Sdelphij/******************************/
4016285612Sdelphijstatic int
4017285612Sdelphijmodem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4018285612Sdelphij{
4019285612Sdelphij
4020294569Sdelphij	const char *	pCmd ;
4021294569Sdelphij	char		cBuf [ 46 ] ;
4022294569Sdelphij	int		iCmdLen ;
4023294569Sdelphij	int		iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
4024294569Sdelphij	int		iNextModemState = STAY_MODEM_STATE ;
4025285612Sdelphij
4026285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
4027285612Sdelphij
4028285612Sdelphij	up->iModemCommandSeq++ ;
4029285612Sdelphij
4030285612Sdelphij	switch ( up->iModemCommandSeq ) {
4031285612Sdelphij
4032285612Sdelphij	case 1 :
4033285612Sdelphij		/* En = Echoback      0:Off      1:On   */
4034285612Sdelphij		/* Qn = Result codes  0:On       1:Off  */
4035285612Sdelphij		/* Vn = Result codes  0:Numeric  1:Text */
4036285612Sdelphij		pCmd = "ATE0Q0V1\r\n" ;
4037106163Sroberto		break ;
4038106163Sroberto
4039285612Sdelphij	case 2 :
4040285612Sdelphij		/* Mn = Speaker switch  0:Off  1:On until remote carrier detected  2:On */
4041285612Sdelphij		if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
4042285612Sdelphij			/* fudge 127.127.40.n flag3 0 */
4043285612Sdelphij			iSpeakerSwitch = 0 ;
4044285612Sdelphij		} else {
4045285612Sdelphij			/* fudge 127.127.40.n flag3 1 */
4046285612Sdelphij			iSpeakerSwitch = 2 ;
4047285612Sdelphij		}
4048285612Sdelphij
4049285612Sdelphij		/* Ln = Speaker volume  0:Very low  1:Low  2:Middle  3:High */
4050285612Sdelphij		if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
4051285612Sdelphij			/* fudge 127.127.40.n flag4 0 */
4052285612Sdelphij			iSpeakerVolume = 1 ;
4053285612Sdelphij		} else {
4054285612Sdelphij			/* fudge 127.127.40.n flag4 1 */
4055285612Sdelphij			iSpeakerVolume = 2 ;
4056285612Sdelphij		}
4057285612Sdelphij
4058285612Sdelphij		pCmd = cBuf ;
4059294569Sdelphij		snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
4060106163Sroberto		break ;
4061106163Sroberto
4062285612Sdelphij	case 3 :
4063285612Sdelphij		/* &Kn = Flow control  4:XON/XOFF */
4064285612Sdelphij		pCmd = "AT&K4\r\n" ;
4065182007Sroberto		break ;
4066182007Sroberto
4067285612Sdelphij	case 4 :
4068285612Sdelphij		/* +MS = Protocol  V22B:1200,2400bps�iV.22bis) */
4069285612Sdelphij		pCmd = "AT+MS=V22B\r\n" ;
4070285612Sdelphij		break ;
4071200576Sroberto
4072285612Sdelphij	case 5 :
4073285612Sdelphij		/* %Cn = Data compression  0:No data compression */
4074285612Sdelphij		pCmd = "AT%C0\r\n" ;
4075285612Sdelphij		break ;
4076285612Sdelphij
4077285612Sdelphij	case 6 :
4078285612Sdelphij		/* \Nn = Error correction  0:Normal mode  1:Direct mode  2:V42,MNP  3:V42,MNP,Normal */
4079285612Sdelphij		if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
4080285612Sdelphij			/* fudge 127.127.40.n flag2 0 */
4081285612Sdelphij			iErrorCorrection = 0 ;
4082285612Sdelphij		} else {
4083285612Sdelphij			/* fudge 127.127.40.n flag2 1 */
4084285612Sdelphij			iErrorCorrection = 3 ;
4085285612Sdelphij		}
4086285612Sdelphij
4087285612Sdelphij		pCmd = cBuf ;
4088294569Sdelphij		snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
4089285612Sdelphij		break ;
4090285612Sdelphij
4091285612Sdelphij	case 7 :
4092285612Sdelphij		/* Hn = Hook  0:Hook-On ( Disconnect )  1:Hook-Off ( Connect ) */
4093285612Sdelphij		pCmd = "ATH1\r\n" ;
4094285612Sdelphij		break ;
4095285612Sdelphij
4096285612Sdelphij	case 8 :
4097285612Sdelphij		/* Initialize completion */
4098285612Sdelphij		pCmd = NULL ;
4099285612Sdelphij		iNextModemState = CHANGE_MODEM_STATE ;
4100285612Sdelphij		break ;
4101285612Sdelphij
4102106163Sroberto	default :
4103285612Sdelphij		pCmd = NULL ;
4104106163Sroberto		break ;
4105106163Sroberto
4106106163Sroberto	}
4107106163Sroberto
4108285612Sdelphij	if ( pCmd != NULL ) {
4109285612Sdelphij
4110285612Sdelphij		iCmdLen = strlen( pCmd ) ;
4111285612Sdelphij		if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4112285612Sdelphij			refclock_report( peer, CEVNT_FAULT ) ;
4113285612Sdelphij		}
4114285612Sdelphij
4115285612Sdelphij		jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4116285612Sdelphij
4117285612Sdelphij	}
4118285612Sdelphij
4119285612Sdelphij	return iNextModemState ;
4120285612Sdelphij
4121106163Sroberto}
4122106163Sroberto
4123285612Sdelphij/******************************/
4124285612Sdelphijstatic int
4125285612Sdelphijmodem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4126106163Sroberto{
4127106163Sroberto
4128285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
4129106163Sroberto
4130285612Sdelphij	return modem_init_resp00( peer, pp, up ) ;
4131106163Sroberto
4132285612Sdelphij}
4133106163Sroberto
4134285612Sdelphij/******************************/
4135285612Sdelphijstatic int
4136285612Sdelphijmodem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4137285612Sdelphij{
4138285612Sdelphij
4139285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
4140182007Sroberto#ifdef DEBUG
4141182007Sroberto	if ( debug ) {
4142285612Sdelphij		printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
4143182007Sroberto	}
4144182007Sroberto#endif
4145182007Sroberto
4146285612Sdelphij	return CHANGE_MODEM_STATE ;
4147106163Sroberto
4148182007Sroberto}
4149182007Sroberto
4150285612Sdelphij/******************************/
4151285612Sdelphijstatic int
4152285612Sdelphijmodem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4153285612Sdelphij{
4154182007Sroberto
4155285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
4156285612Sdelphij
4157285612Sdelphij	return STAY_MODEM_STATE ;
4158285612Sdelphij
4159285612Sdelphij}
4160285612Sdelphij
4161285612Sdelphij/******************************/
4162285612Sdelphijstatic int
4163285612Sdelphijmodem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4164182007Sroberto{
4165182007Sroberto
4166285612Sdelphij	char	sCmd [ 46 ] ;
4167285612Sdelphij	int	iCmdLen ;
4168285612Sdelphij	char	cToneOrPulse ;
4169182007Sroberto
4170285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
4171182007Sroberto
4172285612Sdelphij	/* Tone or Pulse */
4173285612Sdelphij	if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
4174285612Sdelphij		/* fudge 127.127.40.n flag1 0 */
4175285612Sdelphij		cToneOrPulse = 'T' ;
4176285612Sdelphij	} else {
4177285612Sdelphij		/* fudge 127.127.40.n flag1 1 */
4178285612Sdelphij		cToneOrPulse = 'P' ;
4179285612Sdelphij	}
4180106163Sroberto
4181285612Sdelphij	/* Connect ( Dial number ) */
4182285612Sdelphij	snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
4183285612Sdelphij
4184285612Sdelphij	/* Send command */
4185285612Sdelphij	iCmdLen = strlen( sCmd ) ;
4186285612Sdelphij	if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
4187285612Sdelphij		refclock_report( peer, CEVNT_FAULT ) ;
4188285612Sdelphij	}
4189285612Sdelphij
4190285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
4191285612Sdelphij
4192285612Sdelphij	return STAY_MODEM_STATE ;
4193285612Sdelphij
4194285612Sdelphij}
4195285612Sdelphij
4196285612Sdelphij/******************************/
4197285612Sdelphijstatic int
4198285612Sdelphijmodem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4199285612Sdelphij{
4200285612Sdelphij
4201285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
4202182007Sroberto#ifdef DEBUG
4203182007Sroberto	if ( debug ) {
4204285612Sdelphij		printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
4205106163Sroberto	}
4206182007Sroberto#endif
4207106163Sroberto
4208285612Sdelphij	return modem_conn_escape( peer, pp, up ) ;
4209285612Sdelphij
4210285612Sdelphij}
4211285612Sdelphij
4212285612Sdelphij/******************************/
4213285612Sdelphijstatic int
4214285612Sdelphijmodem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4215285612Sdelphij{
4216285612Sdelphij
4217285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
4218285612Sdelphij
4219285612Sdelphij	return CHANGE_MODEM_STATE ;
4220285612Sdelphij
4221285612Sdelphij}
4222285612Sdelphij
4223285612Sdelphij/******************************/
4224285612Sdelphijstatic int
4225285612Sdelphijmodem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4226285612Sdelphij{
4227285612Sdelphij
4228285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
4229285612Sdelphij#ifdef DEBUG
4230285612Sdelphij	if ( debug ) {
4231285612Sdelphij		printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
4232182007Sroberto	}
4233285612Sdelphij#endif
4234182007Sroberto
4235285612Sdelphij	modem_esc_disc( peer, pp, up ) ;
4236285612Sdelphij
4237285612Sdelphij	return CHANGE_MODEM_STATE ;
4238285612Sdelphij
4239106163Sroberto}
4240106163Sroberto
4241285612Sdelphij/******************************/
4242285612Sdelphijstatic int
4243285612Sdelphijmodem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4244285612Sdelphij{
4245106163Sroberto
4246285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
4247285612Sdelphij
4248285612Sdelphij	return STAY_MODEM_STATE ;
4249285612Sdelphij
4250285612Sdelphij}
4251285612Sdelphij
4252285612Sdelphij/******************************/
4253285612Sdelphijstatic int
4254285612Sdelphijmodem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4255106163Sroberto{
4256106163Sroberto
4257285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
4258106163Sroberto
4259285612Sdelphij	return CHANGE_MODEM_STATE ;
4260182007Sroberto
4261285612Sdelphij}
4262106163Sroberto
4263285612Sdelphij/******************************/
4264285612Sdelphijstatic int
4265285612Sdelphijmodem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4266285612Sdelphij{
4267106163Sroberto
4268285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
4269285612Sdelphij
4270285612Sdelphij	return STAY_MODEM_STATE ;
4271285612Sdelphij
4272285612Sdelphij}
4273285612Sdelphij
4274285612Sdelphij/******************************/
4275285612Sdelphijstatic int
4276285612Sdelphijmodem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4277285612Sdelphij{
4278285612Sdelphij
4279294569Sdelphij	const char *	pCmd ;
4280294569Sdelphij	int		iCmdLen ;
4281285612Sdelphij
4282285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
4283285612Sdelphij
4284285612Sdelphij	/* Escape command ( Go to command mode ) */
4285285612Sdelphij	pCmd = "+++" ;
4286285612Sdelphij
4287285612Sdelphij	/* Send command */
4288285612Sdelphij	iCmdLen = strlen( pCmd ) ;
4289285612Sdelphij	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4290285612Sdelphij		refclock_report( peer, CEVNT_FAULT ) ;
4291182007Sroberto	}
4292182007Sroberto
4293285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4294285612Sdelphij
4295285612Sdelphij	return STAY_MODEM_STATE ;
4296285612Sdelphij
4297285612Sdelphij}
4298285612Sdelphij
4299285612Sdelphij/******************************/
4300285612Sdelphijstatic int
4301285612Sdelphijmodem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4302285612Sdelphij{
4303285612Sdelphij
4304285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
4305285612Sdelphij
4306285612Sdelphij	up->iModemSilentTimer = 0 ;
4307285612Sdelphij
4308285612Sdelphij	return STAY_MODEM_STATE ;
4309285612Sdelphij
4310285612Sdelphij}
4311285612Sdelphij
4312285612Sdelphij/******************************/
4313285612Sdelphijstatic int
4314285612Sdelphijmodem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4315285612Sdelphij{
4316285612Sdelphij
4317285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
4318285612Sdelphij
4319285612Sdelphij	up->iModemSilentCount ++ ;
4320285612Sdelphij
4321285612Sdelphij	if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
4322182007Sroberto#ifdef DEBUG
4323285612Sdelphij		if ( debug ) {
4324285612Sdelphij			printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
4325285612Sdelphij		}
4326285612Sdelphij#endif
4327285612Sdelphij		modem_esc_escape( peer, pp, up ) ;
4328285612Sdelphij		up->iModemSilentTimer = 0 ;
4329285612Sdelphij		return STAY_MODEM_STATE ;
4330285612Sdelphij	}
4331285612Sdelphij
4332285612Sdelphij#ifdef DEBUG
4333182007Sroberto	if ( debug ) {
4334285612Sdelphij		printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
4335182007Sroberto	}
4336182007Sroberto#endif
4337285612Sdelphij	return modem_esc_disc( peer, pp, up ) ;
4338182007Sroberto
4339285612Sdelphij}
4340285612Sdelphij/******************************/
4341285612Sdelphijstatic int
4342285612Sdelphijmodem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
4343285612Sdelphij{
4344285612Sdelphij
4345294569Sdelphij	const char *	pCmd ;
4346294569Sdelphij	int		iCmdLen ;
4347285612Sdelphij
4348285612Sdelphij	DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
4349285612Sdelphij
4350285612Sdelphij	/* Disconnect */
4351285612Sdelphij	pCmd = "ATH0\r\n" ;
4352285612Sdelphij
4353285612Sdelphij	/* Send command */
4354285612Sdelphij	iCmdLen = strlen( pCmd ) ;
4355285612Sdelphij	if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
4356285612Sdelphij		refclock_report( peer, CEVNT_FAULT ) ;
4357106163Sroberto	}
4358106163Sroberto
4359285612Sdelphij	jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
4360285612Sdelphij
4361285612Sdelphij	return CHANGE_MODEM_STATE ;
4362285612Sdelphij
4363106163Sroberto}
4364106163Sroberto
4365285612Sdelphij/*################################################################################################*/
4366285612Sdelphij/*################################################################################################*/
4367285612Sdelphij/*##												##*/
4368285612Sdelphij/*##    jjy_write_clockstats									##*/
4369285612Sdelphij/*##												##*/
4370285612Sdelphij/*################################################################################################*/
4371285612Sdelphij/*################################################################################################*/
4372200576Sroberto
4373200576Srobertostatic void
4374285612Sdelphijjjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
4375200576Sroberto{
4376200576Sroberto
4377294569Sdelphij	char		sLog [ 100 ] ;
4378294569Sdelphij	const char *	pMark ;
4379294569Sdelphij	int 		iMarkLen, iDataLen ;
4380200576Sroberto
4381285612Sdelphij	switch ( iMark ) {
4382285612Sdelphij	case JJY_CLOCKSTATS_MARK_JJY :
4383285612Sdelphij		pMark = "JJY " ;
4384285612Sdelphij		break ;
4385285612Sdelphij	case JJY_CLOCKSTATS_MARK_SEND :
4386285612Sdelphij		pMark = "--> " ;
4387285612Sdelphij		break ;
4388285612Sdelphij	case JJY_CLOCKSTATS_MARK_RECEIVE :
4389285612Sdelphij		pMark = "<-- " ;
4390285612Sdelphij		break ;
4391285612Sdelphij	case JJY_CLOCKSTATS_MARK_INFORMATION :
4392285612Sdelphij		pMark = "--- " ;
4393285612Sdelphij		break ;
4394285612Sdelphij	case JJY_CLOCKSTATS_MARK_ATTENTION :
4395285612Sdelphij		pMark = "=== " ;
4396285612Sdelphij		break ;
4397285612Sdelphij	case JJY_CLOCKSTATS_MARK_WARNING :
4398285612Sdelphij		pMark = "-W- " ;
4399285612Sdelphij		break ;
4400285612Sdelphij	case JJY_CLOCKSTATS_MARK_ERROR :
4401285612Sdelphij		pMark = "-X- " ;
4402285612Sdelphij		break ;
4403330567Sgordon	case JJY_CLOCKSTATS_MARK_BUG :
4404330567Sgordon		pMark = "!!! " ;
4405330567Sgordon		break ;
4406285612Sdelphij	default :
4407285612Sdelphij		pMark = "" ;
4408285612Sdelphij		break ;
4409285612Sdelphij	}
4410285612Sdelphij
4411285612Sdelphij	iDataLen = strlen( pData ) ;
4412285612Sdelphij	iMarkLen = strlen( pMark ) ;
4413285612Sdelphij	strcpy( sLog, pMark ) ; /* Harmless because of enough length */
4414285612Sdelphij	printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
4415285612Sdelphij
4416285612Sdelphij#ifdef DEBUG
4417285612Sdelphij	if ( debug ) {
4418285612Sdelphij		printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
4419285612Sdelphij	}
4420285612Sdelphij#endif
4421285612Sdelphij	record_clock_stats( &peer->srcadr, sLog ) ;
4422285612Sdelphij
4423200576Sroberto}
4424200576Sroberto
4425285612Sdelphij/*################################################################################################*/
4426285612Sdelphij/*################################################################################################*/
4427285612Sdelphij/*##												##*/
4428285612Sdelphij/*##    printableString										##*/
4429285612Sdelphij/*##												##*/
4430285612Sdelphij/*################################################################################################*/
4431285612Sdelphij/*################################################################################################*/
4432285612Sdelphij
4433285612Sdelphijstatic void
4434285612SdelphijprintableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
4435285612Sdelphij{
4436285612Sdelphij	const char	*printableControlChar[] = {
4437285612Sdelphij			"<NUL>", "<SOH>", "<STX>", "<ETX>",
4438285612Sdelphij			"<EOT>", "<ENQ>", "<ACK>", "<BEL>",
4439285612Sdelphij			"<BS>" , "<HT>" , "<LF>" , "<VT>" ,
4440285612Sdelphij			"<FF>" , "<CR>" , "<SO>" , "<SI>" ,
4441285612Sdelphij			"<DLE>", "<DC1>", "<DC2>", "<DC3>",
4442285612Sdelphij			"<DC4>", "<NAK>", "<SYN>", "<ETB>",
4443285612Sdelphij			"<CAN>", "<EM>" , "<SUB>", "<ESC>",
4444285612Sdelphij			"<FS>" , "<GS>" , "<RS>" , "<US>" ,
4445285612Sdelphij			" " } ;
4446285612Sdelphij
4447285612Sdelphij	size_t	i, j, n ;
4448285612Sdelphij	size_t	InputLen;
4449285612Sdelphij	size_t	OutputLen;
4450285612Sdelphij
4451285612Sdelphij	InputLen = (size_t)iInputLen;
4452285612Sdelphij	OutputLen = (size_t)iOutputLen;
4453285612Sdelphij	for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
4454285612Sdelphij		if ( isprint( (unsigned char)sInput[i] ) ) {
4455285612Sdelphij			n = 1 ;
4456285612Sdelphij			if ( j + 1 >= OutputLen )
4457285612Sdelphij				break ;
4458285612Sdelphij			sOutput[j] = sInput[i] ;
4459285612Sdelphij		} else if ( ( sInput[i] & 0xFF ) <
4460285612Sdelphij			    COUNTOF(printableControlChar) ) {
4461285612Sdelphij			n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
4462285612Sdelphij			if ( j + n + 1 >= OutputLen )
4463285612Sdelphij				break ;
4464285612Sdelphij			strlcpy( sOutput + j,
4465285612Sdelphij				 printableControlChar[sInput[i] & 0xFF],
4466285612Sdelphij				 OutputLen - j ) ;
4467285612Sdelphij		} else {
4468285612Sdelphij			n = 5 ;
4469285612Sdelphij			if ( j + n + 1 >= OutputLen )
4470285612Sdelphij				break ;
4471285612Sdelphij			snprintf( sOutput + j, OutputLen - j, "<x%X>",
4472285612Sdelphij				  sInput[i] & 0xFF ) ;
4473285612Sdelphij		}
4474285612Sdelphij		j += n ;
4475285612Sdelphij	}
4476285612Sdelphij
4477285612Sdelphij	sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
4478285612Sdelphij
4479285612Sdelphij}
4480285612Sdelphij
4481285612Sdelphij/**************************************************************************************************/
4482285612Sdelphij
4483106163Sroberto#else
4484106163Srobertoint refclock_jjy_bs ;
4485106163Sroberto#endif /* REFCLOCK */
4486