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