Coverage Report

Created: 2026-02-26 06:20

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