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