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