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