Coverage Report

Created: 2023-05-19 06:16

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