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