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