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