]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/refclock_jjy.c
Update Makefiles and other build glue for llvm/clang 3.7.0, as of trunk
[FreeBSD/FreeBSD.git] / contrib / ntp / ntpd / refclock_jjy.c
1 /*
2  * refclock_jjy - clock driver for JJY receivers
3  */
4
5 /**********************************************************************/
6 /*                                                                    */
7 /*  Copyright (C) 2001-2011, 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 /**********************************************************************/
99
100 #ifdef HAVE_CONFIG_H
101 #include <config.h>
102 #endif
103
104 #if defined(REFCLOCK) && defined(CLOCK_JJY)
105
106 #include <stdio.h>
107 #include <ctype.h>
108 #include <string.h>
109 #include <sys/time.h>
110 #include <time.h>
111
112 #include "ntpd.h"
113 #include "ntp_io.h"
114 #include "ntp_tty.h"
115 #include "ntp_refclock.h"
116 #include "ntp_calendar.h"
117 #include "ntp_stdlib.h"
118
119 /**********************************************************************/
120 /*                                                                    */
121 /*  The Tristate Ltd. JJY receiver JJY01                              */
122 /*                                                                    */
123 /*  Command        Response                 Remarks                   */
124 /*  ------------   ----------------------   ---------------------     */
125 /*  dcst<CR><LF>   VALID|INVALID<CR><LF>                              */
126 /*  stus<CR><LF>   ADJUSTED|UNADJUSTED<CR><LF>                        */
127 /*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>                             */
128 /*  time<CR><LF>   HH:MM:SS<CR><LF>         Not used by this driver   */
129 /*  stim<CR><LF>   HH:MM:SS<CR><LF>         Reply at just second      */
130 /*                                                                    */
131 /*  During synchronization after a receiver is turned on,             */
132 /*  It replies the past time from 2000/01/01 00:00:00.                */
133 /*  The function "refclock_process" checks the time and tells         */
134 /*  as an insanity time.                                              */
135 /*                                                                    */
136 /**********************************************************************/
137 /*                                                                    */
138 /*  The C-DEX Co. Ltd. JJY receiver JST2000                           */
139 /*                                                                    */
140 /*  Command        Response                 Remarks                   */
141 /*  ------------   ----------------------   ---------------------     */
142 /*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>                          */
143 /*                                                                    */
144 /**********************************************************************/
145 /*                                                                    */
146 /*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000                   */
147 /*                                                                    */
148 /*  Command        Response                 Remarks                   */
149 /*  ------------   ----------------------   ---------------------     */
150 /*  #                                       Mode 1 (Request&Send)     */
151 /*  T              YYMMDDWHHMMSS<BCC1><BCC2><CR>                      */
152 /*  C                                       Mode 2 (Continuous)       */
153 /*                 YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>              */
154 /*                 <SUB>                    Second signal             */
155 /*                                                                    */
156 /**********************************************************************/
157 /*                                                                    */
158 /*  The CITIZEN T.I.C CO., LTD. JJY receiver JJY200                   */
159 /*                                                                    */
160 /*  Command        Response                 Remarks                   */
161 /*  ------------   ----------------------   ---------------------     */
162 /*                 'XX YY/MM/DD W HH:MM:SS<CR>                        */
163 /*                                          XX: OK|NG|ER              */
164 /*                                          W:  0(Monday)-6(Sunday)   */
165 /*                                                                    */
166 /**********************************************************************/
167 /*                                                                    */
168 /*  The Tristate Ltd. GPS clock TS-GPSCLOCK-01                        */
169 /*                                                                    */
170 /*  This clock has NMEA mode and command/respose mode.                */
171 /*  When this jjy driver are used, set to command/respose mode        */
172 /*  of this clock by the onboard switch SW4, and make sure the        */
173 /*  LED-Y is tured on.                                                */
174 /*  Other than this JJY driver, the refclock driver type 20,          */
175 /*  generic NMEA driver, works with the NMEA mode of this clock.      */
176 /*                                                                    */
177 /*  Command        Response                 Remarks                   */
178 /*  ------------   ----------------------   ---------------------     */
179 /*  stus<CR><LF>   *R|*G|*U|+U<CR><LF>                                */
180 /*  date<CR><LF>   YY/MM/DD<CR><LF>                                   */
181 /*  time<CR><LF>   HH:MM:SS<CR><LF>                                   */
182 /*                                                                    */
183 /**********************************************************************/
184
185 /*
186  * Interface definitions
187  */
188 #define DEVICE          "/dev/jjy%d"    /* device name and unit */
189 #define SPEED232        B9600           /* uart speed (9600 baud) */
190 #define SPEED232_TRISTATE_JJY01         B9600   /* UART speed (9600 baud) */
191 #define SPEED232_CDEX_JST2000           B9600   /* UART speed (9600 baud) */
192 #define SPEED232_ECHOKEISOKUKI_LT2000   B9600   /* UART speed (9600 baud) */
193 #define SPEED232_CITIZENTIC_JJY200      B4800   /* UART speed (4800 baud) */
194 #define SPEED232_TRISTATE_GPSCLOCK01    B38400  /* USB  speed (38400 baud) */
195 #define REFID           "JJY"           /* reference ID */
196 #define DESCRIPTION     "JJY Receiver"
197 #define PRECISION       (-3)            /* precision assumed (about 100 ms) */
198
199 /*
200  * JJY unit control structure
201  */
202 struct jjyunit {
203         char    unittype ;          /* UNITTYPE_XXXXXXXXXX */
204         short   operationmode ;     /* Echo Keisokuki LT-2000 : 1 or 2 */
205         short   version ;
206         short   linediscipline ;    /* LDISC_CLK or LDISC_RAW */
207         char    bPollFlag ;         /* Set by jjy_pool and Reset by jjy_receive */
208         int     linecount ;
209         int     lineerror ;
210         int     year, month, day, hour, minute, second, msecond ;
211 /* LDISC_RAW only */
212 #define MAX_LINECOUNT   8
213 #define MAX_RAWBUF      64
214         int     lineexpect ;
215         int     charexpect [ MAX_LINECOUNT ] ;
216         int     charcount ;
217         char    rawbuf [ MAX_RAWBUF ] ;
218 };
219
220 #define UNITTYPE_TRISTATE_JJY01         1
221 #define UNITTYPE_CDEX_JST2000           2
222 #define UNITTYPE_ECHOKEISOKUKI_LT2000   3
223 #define UNITTYPE_CITIZENTIC_JJY200      4
224 #define UNITTYPE_TRISTATE_GPSCLOCK01    5
225
226 /*
227  * Function prototypes
228  */
229  
230 static  int     jjy_start                       (int, struct peer *);
231 static  void    jjy_shutdown                    (int, struct peer *);
232
233 static  void    jjy_poll                        (int, struct peer *);
234 static  void    jjy_poll_tristate_jjy01         (int, struct peer *);
235 static  void    jjy_poll_cdex_jst2000           (int, struct peer *);
236 static  void    jjy_poll_echokeisokuki_lt2000   (int, struct peer *);
237 static  void    jjy_poll_citizentic_jjy200      (int, struct peer *);
238 static  void    jjy_poll_tristate_gpsclock01    (int, struct peer *);
239
240 static  void    jjy_receive                     (struct recvbuf *);
241 static  int     jjy_receive_tristate_jjy01      (struct recvbuf *);
242 static  int     jjy_receive_cdex_jst2000        (struct recvbuf *);
243 static  int     jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
244 static  int     jjy_receive_citizentic_jjy200   (struct recvbuf *);
245 static  int     jjy_receive_tristate_gpsclock01 (struct recvbuf *);
246
247 static  void    printableString ( char*, int, char*, int ) ;
248
249 /*
250  * Transfer vector
251  */
252 struct  refclock refclock_jjy = {
253         jjy_start,      /* start up driver */
254         jjy_shutdown,   /* shutdown driver */
255         jjy_poll,       /* transmit poll message */
256         noentry,        /* not used */
257         noentry,        /* not used */
258         noentry,        /* not used */
259         NOFLAGS         /* not used */
260 };
261
262 /*
263  * Start up driver return code
264  */
265 #define RC_START_SUCCESS        1
266 #define RC_START_ERROR          0
267
268 /*
269  * Local constants definition
270  */
271
272 #define MAX_LOGTEXT     64
273
274 /*
275  * Tristate JJY01/JJY02 constants definition
276  */
277
278 #define TS_JJY01_COMMAND_NUMBER_DATE    1
279 #define TS_JJY01_COMMAND_NUMBER_TIME    2
280 #define TS_JJY01_COMMAND_NUMBER_STIM    3
281 #define TS_JJY01_COMMAND_NUMBER_STUS    4
282 #define TS_JJY01_COMMAND_NUMBER_DCST    5
283
284 #define TS_JJY01_REPLY_DATE             "yyyy/mm/dd www\r\n"
285 #define TS_JJY01_REPLY_STIM             "hh:mm:ss\r\n"
286 #define TS_JJY01_REPLY_STUS_YES         "adjusted\r\n"
287 #define TS_JJY01_REPLY_STUS_NO          "unadjusted\r\n"
288 #define TS_JJY01_REPLY_DCST_VALID       "valid\r\n"
289 #define TS_JJY01_REPLY_DCST_INVALID     "invalid\r\n"
290
291 #define TS_JJY01_REPLY_LENGTH_DATE          14  /* Length without <CR><LF> */
292 #define TS_JJY01_REPLY_LENGTH_STIM          8   /* Length without <CR><LF> */
293 #define TS_JJY01_REPLY_LENGTH_STUS_YES      8   /* Length without <CR><LF> */
294 #define TS_JJY01_REPLY_LENGTH_STUS_NO       10  /* Length without <CR><LF> */
295 #define TS_JJY01_REPLY_LENGTH_DCST_VALID    5   /* Length without <CR><LF> */
296 #define TS_JJY01_REPLY_LENGTH_DCST_INVALID  7   /* Length without <CR><LF> */
297
298 static  struct
299 {
300         const char      commandNumber ;
301         const char      *commandLog ;
302         const char      *command ;
303         int     commandLength ;
304 } tristate_jjy01_command_sequence[] =
305 {
306         /* dcst<CR><LF> -> VALID<CR><LF> or INVALID<CR><LF> */
307         { TS_JJY01_COMMAND_NUMBER_DCST, "dcst", "dcst\r\n", 6 },
308         /* stus<CR><LF> -> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
309         { TS_JJY01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
310         /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
311         { TS_JJY01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
312         /* stim<CR><LF> -> HH:MM:SS<CR><LF> */
313         { TS_JJY01_COMMAND_NUMBER_STIM, "stim", "stim\r\n", 6 },
314         /* End of command */
315         { 0, NULL, NULL, 0 }
316 } ;
317
318 /*
319  * Tristate TS-GPSCLOCK01 constants definition
320  */
321
322 #define TS_GPSCLOCK01_COMMAND_NUMBER_DATE       1
323 #define TS_GPSCLOCK01_COMMAND_NUMBER_TIME       2
324 #define TS_GPSCLOCK01_COMMAND_NUMBER_STUS       4
325
326 #define TS_GPSCLOCK01_REPLY_DATE                "yyyy/mm/dd\r\n"
327 #define TS_GPSCLOCK01_REPLY_TIME                "hh:mm:ss\r\n"
328 #define TS_GPSCLOCK01_REPLY_STUS_RTC            "*R\r\n"
329 #define TS_GPSCLOCK01_REPLY_STUS_GPS            "*G\r\n"
330 #define TS_GPSCLOCK01_REPLY_STUS_UTC            "*U\r\n"
331 #define TS_GPSCLOCK01_REPLY_STUS_PPS            "+U\r\n"
332
333 #define TS_GPSCLOCK01_REPLY_LENGTH_DATE     10  /* Length without <CR><LF> */
334 #define TS_GPSCLOCK01_REPLY_LENGTH_TIME     8   /* Length without <CR><LF> */
335 #define TS_GPSCLOCK01_REPLY_LENGTH_STUS     2   /* Length without <CR><LF> */
336
337 static  struct
338 {
339         char    commandNumber ;
340         const char      *commandLog ;
341         const char      *command ;
342         int     commandLength ;
343 } tristate_gpsclock01_command_sequence[] =
344 {
345         /* stus<CR><LF> -> *R<CR><LF> or *G<CR><LF> or *U<CR><LF> or +U<CR><LF> */
346         { TS_GPSCLOCK01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
347         /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
348         { TS_GPSCLOCK01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
349         /* time<CR><LF> -> HH:MM:SS<CR><LF> */
350         { TS_GPSCLOCK01_COMMAND_NUMBER_TIME, "time", "time\r\n", 6 },
351         /* End of command */
352         { 0, NULL, NULL, 0 }
353 } ;
354
355 /**************************************************************************************************/
356 /*  jjy_start - open the devices and initialize data for processing                               */
357 /**************************************************************************************************/
358 static int
359 jjy_start ( int unit, struct peer *peer )
360 {
361
362         struct jjyunit      *up ;
363         struct refclockproc *pp ;
364         int     fd ;
365         char    *pDeviceName ;
366         short   iDiscipline ;
367         int     iSpeed232 ;
368
369         char    sLogText [ MAX_LOGTEXT ] , sDevText [ MAX_LOGTEXT ] ;
370
371 #ifdef DEBUG
372         if ( debug ) {
373                 printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttl ) ;
374                 printf ( DEVICE, unit ) ;
375                 printf ( "\n" ) ;
376         }
377 #endif
378         snprintf ( sDevText, sizeof(sDevText), DEVICE, unit ) ;
379         snprintf ( sLogText, sizeof(sLogText), "*Initialze*  %s  mode=%d", sDevText, peer->ttl ) ;
380         record_clock_stats ( &peer->srcadr, sLogText ) ;
381
382         /*
383          * Open serial port
384          */
385         pDeviceName = emalloc ( strlen(DEVICE) + 10 );
386         snprintf ( pDeviceName, strlen(DEVICE) + 10, DEVICE, unit ) ;
387
388         /*
389          * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
390          */
391         switch ( peer->ttl ) {
392         case 0 :
393         case 1 :
394                 iDiscipline = LDISC_CLK ;
395                 iSpeed232   = SPEED232_TRISTATE_JJY01 ;
396                 break ;
397         case 2 :
398                 iDiscipline = LDISC_RAW ;
399                 iSpeed232   = SPEED232_CDEX_JST2000   ;
400                 break ;
401         case 3 :
402                 iDiscipline = LDISC_CLK ;
403                 iSpeed232   = SPEED232_ECHOKEISOKUKI_LT2000 ;
404                 break ;
405         case 4 :
406                 iDiscipline = LDISC_CLK ;
407                 iSpeed232   = SPEED232_CITIZENTIC_JJY200 ;
408                 break ;
409         case 5 :
410                 iDiscipline = LDISC_CLK ;
411                 iSpeed232   = SPEED232_TRISTATE_GPSCLOCK01 ;
412                 break ;
413         default :
414                 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
415                           ntoa(&peer->srcadr), peer->ttl ) ;
416                 free ( (void*) pDeviceName ) ;
417                 return RC_START_ERROR ;
418         }
419
420         fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ;
421         if ( fd <= 0 ) {
422                 free ( (void*) pDeviceName ) ;
423                 return RC_START_ERROR ;
424         }
425         free ( (void*) pDeviceName ) ;
426
427         /*
428          * Allocate and initialize unit structure
429          */
430         up = emalloc (sizeof(*up));
431         memset ( up, 0, sizeof(*up) ) ;
432         up->linediscipline = iDiscipline ;
433
434         /*
435          * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
436          */
437         switch ( peer->ttl ) {
438         case 0 :
439                 /*
440                  * The mode 0 is a default clock type at this time.
441                  * But this will be change to auto-detect mode in the future.
442                  */
443         case 1 :
444                 up->unittype = UNITTYPE_TRISTATE_JJY01 ;
445                 up->version  = 100 ;
446                 /* 2010/11/20 */
447                 /* Command sequence is defined by the struct tristate_jjy01_command_sequence, */
448                 /* and the following 3 lines are not used in the mode LDISC_CLK. */
449                 /* up->lineexpect = 2 ; */
450                 /* up->charexpect[0] = 14 ; */ /* YYYY/MM/DD WWW<CR><LF> */
451                 /* up->charexpect[1] =  8 ; */ /* HH:MM:SS<CR><LF> */
452                 break ;
453         case 2 :
454                 up->unittype = UNITTYPE_CDEX_JST2000 ;
455                 up->lineexpect = 1 ;
456                 up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
457                 break ;
458         case 3 :
459                 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
460                 up->operationmode = 2 ;  /* Mode 2 : Continuous mode */
461                 up->lineexpect = 1 ;
462                 switch ( up->operationmode ) {
463                 case 1 :
464                         up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
465                         break ;
466                 case 2 :
467                         up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
468                         break ;
469                 }
470                 break ;
471         case 4 :
472                 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
473                 up->lineexpect = 1 ;
474                 up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
475                 break ;
476         case 5 :
477                 up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
478                 break ;
479
480         /* 2010/11/20 */
481         /* The "default:" section of this switch block is never executed,     */
482         /* because the former switch block traps the same "default:" case.    */
483         /* This "default:" section codes are removed to avoid spending time   */
484         /* in the future looking, though the codes are functionally harmless. */
485
486         }
487
488         pp = peer->procptr ;
489         pp->unitptr       = up ;
490         pp->io.clock_recv = jjy_receive ;
491         pp->io.srcclock   = peer ;
492         pp->io.datalen    = 0 ;
493         pp->io.fd         = fd ;
494         if ( ! io_addclock(&pp->io) ) {
495                 close ( fd ) ;
496                 pp->io.fd = -1 ;
497                 free ( up ) ;
498                 pp->unitptr = NULL ;
499                 return RC_START_ERROR ;
500         }
501
502         /*
503          * Initialize miscellaneous variables
504          */
505         peer->precision = PRECISION ;
506         pp->clockdesc   = DESCRIPTION ;
507         memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
508
509         return RC_START_SUCCESS ;
510
511 }
512
513
514 /**************************************************************************************************/
515 /*  jjy_shutdown - shutdown the clock                                                             */
516 /**************************************************************************************************/
517 static void
518 jjy_shutdown ( int unit, struct peer *peer )
519 {
520
521         struct jjyunit      *up;
522         struct refclockproc *pp;
523
524         pp = peer->procptr ;
525         up = pp->unitptr ;
526         if ( -1 != pp->io.fd )
527                 io_closeclock ( &pp->io ) ;
528         if ( NULL != up )
529                 free ( up ) ;
530
531 }
532
533
534 /**************************************************************************************************/
535 /*  jjy_receive - receive data from the serial interface                                          */
536 /**************************************************************************************************/
537 static void
538 jjy_receive ( struct recvbuf *rbufp )
539 {
540
541         struct jjyunit      *up ;
542         struct refclockproc *pp ;
543         struct peer         *peer;
544
545         l_fp    tRecvTimestamp;         /* arrival timestamp */
546         int     rc ;
547         char    sLogText [ MAX_LOGTEXT ] ;
548         int     i, bCntrlChar ;
549
550         /*
551          * Initialize pointers and read the timecode and timestamp
552          */
553         peer = rbufp->recv_peer ;
554         pp = peer->procptr ;
555         up = pp->unitptr ;
556
557         /*
558          * Get next input line
559          */
560         pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
561
562         if ( up->linediscipline == LDISC_RAW ) {
563                 /*
564                  * The reply with <STX> and <ETX> may give a blank line
565                  */
566                 if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
567                 /*
568                  * Copy received charaters to temporary buffer 
569                  */
570                 for ( i = 0 ;
571                       i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ;
572                       i ++ , up->charcount ++ ) {
573                         up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
574                 }
575                 while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
576                         for ( i = 0 ; i < up->charcount - 1 ; i ++ )
577                                 up->rawbuf[i] = up->rawbuf[i+1] ;
578                         up->charcount -- ;
579                 }
580                 bCntrlChar = 0 ;
581                 for ( i = 0 ; i < up->charcount ; i ++ ) {
582                         if ( up->rawbuf[i] < ' ' ) {
583                                 bCntrlChar = 1 ;
584                                 break ;
585                         }
586                 }
587                 if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
588                         if ( bCntrlChar == 0  &&
589                              up->charcount < up->charexpect[up->linecount] )
590                                 return ;
591                 }
592                 up->rawbuf[up->charcount] = 0 ;
593         } else {
594                 /*
595                  * The reply with <CR><LF> gives a blank line
596                  */
597                 if ( pp->lencode == 0 ) return ;
598         }
599         /*
600          * We get down to business
601          */
602
603 #ifdef DEBUG
604         if ( debug ) {
605                 if ( up->linediscipline == LDISC_RAW ) {
606                         printableString( sLogText, MAX_LOGTEXT, up->rawbuf, up->charcount ) ;
607                 } else {
608                         printableString( sLogText, MAX_LOGTEXT, pp->a_lastcode, pp->lencode ) ;
609                 }
610                 printf ( "jjy_receive (refclock_jjy.c) : [%s]\n", sLogText ) ;
611         }
612 #endif
613
614         pp->lastrec = tRecvTimestamp ;
615
616         up->linecount ++ ;
617
618         if ( up->lineerror != 0 ) return ;
619
620         switch ( up->unittype ) {
621         
622         case UNITTYPE_TRISTATE_JJY01 :
623                 rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
624                 break ;
625
626         case UNITTYPE_CDEX_JST2000 :
627                 rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
628                 break ;
629
630         case UNITTYPE_ECHOKEISOKUKI_LT2000 :
631                 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
632                 break ;
633
634         case UNITTYPE_CITIZENTIC_JJY200 :
635                 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
636                 break ;
637
638         case UNITTYPE_TRISTATE_GPSCLOCK01 :
639                 rc = jjy_receive_tristate_gpsclock01  ( rbufp ) ;
640                 break ;
641
642         default :
643                 rc = 0 ;
644                 break ;
645
646         }
647
648         if ( up->linediscipline == LDISC_RAW ) {
649                 if ( up->linecount <= up->lineexpect  &&
650                      up->charcount > up->charexpect[up->linecount-1] ) {
651                         for ( i = 0 ;
652                               i < up->charcount - up->charexpect[up->linecount-1] ;
653                               i ++ ) {
654                                 up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
655                         }
656                         up->charcount -= up->charexpect[up->linecount-1] ;
657                 } else {
658                         up->charcount = 0 ;
659                 }
660         }
661
662         if ( rc == 0 ) {
663                 return ;
664         }
665
666         up->bPollFlag = 0 ;
667
668         if ( up->lineerror != 0 ) {
669                 refclock_report ( peer, CEVNT_BADREPLY ) ;
670                 strlcpy  ( sLogText, "BAD REPLY [",
671                            sizeof( sLogText ) ) ;
672                 if ( up->linediscipline == LDISC_RAW ) {
673                         strlcat ( sLogText, up->rawbuf,
674                                   sizeof( sLogText ) ) ;
675                 } else {
676                         strlcat ( sLogText, pp->a_lastcode,
677                                   sizeof( sLogText ) ) ;
678                 }
679                 sLogText[MAX_LOGTEXT-1] = 0 ;
680                 if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 )
681                         strlcat ( sLogText, "]",
682                                   sizeof( sLogText ) ) ;
683                 record_clock_stats ( &peer->srcadr, sLogText ) ;
684                 return ;
685         }
686
687         pp->year   = up->year ;
688         pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
689         pp->hour   = up->hour ;
690         pp->minute = up->minute ;
691         pp->second = up->second ;
692         pp->nsec   = up->msecond * 1000000;
693
694         /* 
695          * JST to UTC 
696          */
697         pp->hour -= 9 ;
698         if ( pp->hour < 0 ) {
699                 pp->hour += 24 ;
700                 pp->day -- ;
701                 if ( pp->day < 1 ) {
702                         pp->year -- ;
703                         pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
704                 }
705         }
706 #ifdef DEBUG
707         if ( debug ) {
708                 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST   ", 
709                           up->year, up->month, up->day, up->hour,
710                           up->minute, up->second, up->msecond/100 ) ;
711                 printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
712                           pp->year, pp->day, pp->hour, pp->minute,
713                           pp->second, (int)(pp->nsec/100000000) ) ;
714         }
715 #endif
716
717         /*
718          * Process the new sample in the median filter and determine the
719          * timecode timestamp.
720          */
721
722         snprintf ( sLogText, sizeof(sLogText),
723                    "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
724                    up->year, up->month, up->day,
725                    up->hour, up->minute, up->second, up->msecond/100 ) ;
726         record_clock_stats ( &peer->srcadr, sLogText ) ;
727
728         if ( ! refclock_process ( pp ) ) {
729                 refclock_report(peer, CEVNT_BADTIME);
730                 return ;
731         }
732
733         pp->lastref = pp->lastrec;
734         refclock_receive(peer);
735
736 }
737
738 /**************************************************************************************************/
739
740 static int
741 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
742 {
743 #ifdef DEBUG
744         static  const char      *sFunctionName = "jjy_receive_tristate_jjy01" ;
745 #endif
746
747         struct jjyunit      *up ;
748         struct refclockproc *pp ;
749         struct peer         *peer;
750
751         char    *pBuf ;
752         int     iLen ;
753         int     rc ;
754
755         int     bOverMidnight = 0 ;
756
757         char    sLogText [ MAX_LOGTEXT ], sReplyText  [ MAX_LOGTEXT ] ;
758
759         const char *pCmd ;
760         int     iCmdLen ;
761
762         /*
763          * Initialize pointers and read the timecode and timestamp
764          */
765         peer = rbufp->recv_peer ;
766         pp = peer->procptr ;
767         up = pp->unitptr ;
768
769         if ( up->linediscipline == LDISC_RAW ) {
770                 pBuf = up->rawbuf ;
771                 iLen = up->charcount ;
772         } else {
773                 pBuf = pp->a_lastcode ;
774                 iLen = pp->lencode ;
775         }
776
777         switch ( tristate_jjy01_command_sequence[up->linecount-1].commandNumber ) {
778
779         case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
780
781                 if ( iLen != TS_JJY01_REPLY_LENGTH_DATE ) {
782                         up->lineerror = 1 ;
783                         break ;
784                 }
785
786                 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year,
787                               &up->month, &up->day ) ;
788                 if ( rc != 3 || up->year < 2000 || up->month < 1 ||
789                      up->month > 12 || up->day < 1 || up->day > 31 ) {
790                         up->lineerror = 1 ;
791                         break ;
792                 }
793
794                 /*** Start of modification on 2004/10/31 ***/
795                 /*
796                  * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
797                  * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
798                  * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
799                  * so this driver issues the second command "stim" after the reply of the first command "date".
800                  */
801
802                 /*** 2010/11/20 ***/
803                 /*
804                  * Codes of a next command issue are moved to the end of this function.
805                  */
806
807                 /*** End of modification ***/
808
809                 break ;
810
811         case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
812         case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
813
814                 if ( iLen != TS_JJY01_REPLY_LENGTH_STIM ) {
815                         up->lineerror = 1 ;
816                         break ;
817                 }
818
819                 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour,
820                               &up->minute, &up->second ) ;
821                 if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
822                      up->second > 60 ) {
823                         up->lineerror = 1 ;
824                         break ;
825                 }
826
827                 up->msecond = 0 ;
828                 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
829                         /*
830                          * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver separately,
831                          * and the JJY receiver replies a date and time separately.
832                          * Just after midnight transitions, we ignore this time.
833                          */
834                         bOverMidnight = 1 ;
835                 }
836                 break ;
837
838         case TS_JJY01_COMMAND_NUMBER_STUS :
839
840                 if ( ( iLen == TS_JJY01_REPLY_LENGTH_STUS_YES
841                     && strncmp( pBuf, TS_JJY01_REPLY_STUS_YES,
842                                 TS_JJY01_REPLY_LENGTH_STUS_YES ) == 0 )
843                   || ( iLen == TS_JJY01_REPLY_LENGTH_STUS_NO
844                     && strncmp( pBuf, TS_JJY01_REPLY_STUS_NO,
845                                 TS_JJY01_REPLY_LENGTH_STUS_NO ) == 0 ) ) {
846                         /* Good */
847                 } else {
848                         up->lineerror = 1 ;
849                         break ;
850                 }
851
852                 break ;
853
854         case TS_JJY01_COMMAND_NUMBER_DCST :
855
856                 if ( ( iLen == TS_JJY01_REPLY_LENGTH_DCST_VALID
857                     && strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
858                                 TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 )
859                   || ( iLen == TS_JJY01_REPLY_LENGTH_DCST_INVALID
860                     && strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
861                                 TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) ) {
862                         /* Good */
863                 } else {
864                         up->lineerror = 1 ;
865                         break ;
866                 }
867
868                 break ;
869
870         default : /*  Unexpected reply */
871
872                 up->lineerror = 1 ;
873                 break ;
874
875         }
876
877         /* Clockstats Log */
878
879         printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
880         snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
881                    up->linecount,
882                    tristate_jjy01_command_sequence[up->linecount-1].commandLog,
883                    ( up->lineerror == 0 ) 
884                         ? ( ( bOverMidnight == 0 )
885                                 ? 'O' 
886                                 : 'S' ) 
887                         : 'X',
888                    sReplyText ) ;
889         record_clock_stats ( &peer->srcadr, sLogText ) ;
890
891         /* Check before issue next command */
892
893         if ( up->lineerror != 0 ) {
894                 /* Do not issue next command */
895                 return 0 ;
896         }
897
898         if ( bOverMidnight != 0 ) {
899                 /* Do not issue next command */
900                 return 0 ;
901         }
902
903         if ( tristate_jjy01_command_sequence[up->linecount].command == NULL ) {
904                 /* Command sequence completed */
905                 return 1 ;
906         }
907
908         /* Issue next command */
909
910 #ifdef DEBUG
911         if ( debug ) {
912                 printf ( "%s (refclock_jjy.c) : send '%s'\n",
913                         sFunctionName, tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
914         }
915 #endif
916
917         pCmd =  tristate_jjy01_command_sequence[up->linecount].command ;
918         iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
919         if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
920                 refclock_report ( peer, CEVNT_FAULT ) ;
921         }
922
923         return 0 ;
924
925 }
926
927 /**************************************************************************************************/
928
929 static int
930 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
931 {
932 #ifdef DEBUG
933         static  const char      *sFunctionName = "jjy_receive_cdex_jst2000" ;
934 #endif
935
936         struct jjyunit      *up ;
937         struct refclockproc *pp ;
938         struct peer         *peer;
939
940         char    *pBuf ;
941         int     iLen ;
942         int     rc ;
943
944         /*
945          * Initialize pointers and read the timecode and timestamp
946          */
947         peer = rbufp->recv_peer ;
948         pp = peer->procptr ;
949         up = pp->unitptr ;
950
951         if ( up->linediscipline == LDISC_RAW ) {
952                 pBuf = up->rawbuf ;
953                 iLen = up->charcount ;
954         } else {
955                 pBuf = pp->a_lastcode ;
956                 iLen = pp->lencode ;
957         }
958
959         switch ( up->linecount ) {
960
961         case 1 : /* JYYMMDD HHMMSSS */
962
963                 if ( iLen != 15 ) {
964 #ifdef DEBUG
965                         if ( debug >= 2 ) {
966                                 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
967                                          sFunctionName, iLen ) ;
968                         }
969 #endif
970                         up->lineerror = 1 ;
971                         break ;
972                 }
973                 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
974                               &up->year, &up->month, &up->day,
975                               &up->hour, &up->minute, &up->second,
976                               &up->msecond ) ;
977                 if ( rc != 7 || up->month < 1 || up->month > 12 ||
978                      up->day < 1 || up->day > 31 || up->hour > 23 ||
979                      up->minute > 59 || up->second > 60 ) {
980 #ifdef DEBUG
981                         if ( debug >= 2 ) {
982                                 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n",
983                                          sFunctionName, rc, up->year,
984                                          up->month, up->day, up->hour,
985                                          up->minute, up->second,
986                                          up->msecond ) ;
987                         }
988 #endif
989                         up->lineerror = 1 ;
990                         break ;
991                 }
992                 up->year    += 2000 ;
993                 up->msecond *= 100 ;
994                 break ;
995
996         default : /*  Unexpected reply */
997
998                 up->lineerror = 1 ;
999                 break ;
1000
1001         }
1002
1003         return 1 ;
1004
1005 }
1006
1007 /**************************************************************************************************/
1008
1009 static int
1010 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
1011 {
1012 #ifdef DEBUG
1013         static  const char      *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
1014 #endif
1015
1016         struct jjyunit      *up ;
1017         struct refclockproc *pp ;
1018         struct peer         *peer;
1019
1020         char    *pBuf ;
1021         int     iLen ;
1022         int     rc ;
1023         int     i, ibcc, ibcc1, ibcc2 ;
1024
1025         /*
1026          * Initialize pointers and read the timecode and timestamp
1027          */
1028         peer = rbufp->recv_peer ;
1029         pp = peer->procptr ;
1030         up = pp->unitptr ;
1031
1032         if ( up->linediscipline == LDISC_RAW ) {
1033                 pBuf = up->rawbuf ;
1034                 iLen = up->charcount ;
1035         } else {
1036                 pBuf = pp->a_lastcode ;
1037                 iLen = pp->lencode ;
1038         }
1039
1040         switch ( up->linecount ) {
1041
1042         case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
1043
1044                 if ( ( up->operationmode == 1 && iLen != 15 ) ||
1045                      ( up->operationmode == 2 && iLen != 17 ) ) {
1046 #ifdef DEBUG
1047                         if ( debug >= 2 ) {
1048                                 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
1049                                          sFunctionName, iLen ) ;
1050                         }
1051 #endif
1052                         if ( up->operationmode == 1 ) {
1053 #ifdef DEBUG
1054                                 if ( debug ) {
1055                                         printf ( "%s (refclock_jjy.c) : send '#'\n", __func__ ) ;
1056                                 }
1057 #endif
1058                                 if ( write ( pp->io.fd, "#",1 ) != 1  ) {
1059                                         refclock_report ( peer, CEVNT_FAULT ) ;
1060                                 }
1061                         }
1062                         up->lineerror = 1 ;
1063                         break ;
1064                 }
1065
1066                 if ( up->operationmode == 1 ) {
1067
1068                         for ( i = ibcc = 0 ; i < 13 ; i ++ )
1069                                 ibcc ^= pBuf[i] ;
1070                         ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
1071                         ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
1072                         if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
1073 #ifdef DEBUG
1074                                 if ( debug >= 2 ) {
1075                                         printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n",
1076                                                  sFunctionName,
1077                                                  pBuf[13] & 0xFF,
1078                                                  pBuf[14] & 0xFF,
1079                                                  ibcc1, ibcc2 ) ;
1080                                 }
1081 #endif
1082                                 up->lineerror = 1 ;
1083                                 break ;
1084                         }
1085
1086                 }
1087
1088                 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
1089                               &up->year, &up->month, &up->day,
1090                               &up->hour, &up->minute, &up->second ) ;
1091                 if ( rc != 6 || up->month < 1 || up->month > 12 ||
1092                      up->day < 1 || up->day > 31 || up->hour > 23 ||
1093                      up->minute > 59 || up->second > 60 ) {
1094 #ifdef DEBUG
1095                         if ( debug >= 2 ) {
1096                                 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n",
1097                                          sFunctionName, rc, up->year,
1098                                          up->month, up->day, up->hour,
1099                                          up->minute, up->second ) ;
1100                         }
1101 #endif
1102                         up->lineerror = 1 ;
1103                         break ;
1104                 }
1105
1106                 up->year += 2000 ;
1107
1108                 if ( up->operationmode == 2 ) {
1109
1110                         /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
1111                         up->msecond = 500 ;
1112                         pp->second -- ;
1113                         if ( pp->second < 0 ) {
1114                                 pp->second = 59 ;
1115                                 pp->minute -- ;
1116                                 if ( pp->minute < 0 ) {
1117                                         pp->minute = 59 ;
1118                                         pp->hour -- ;
1119                                         if ( pp->hour < 0 ) {
1120                                                 pp->hour = 23 ;
1121                                                 pp->day -- ;
1122                                                 if ( pp->day < 1 ) {
1123                                                         pp->year -- ;
1124                                                         pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
1125                                                 }
1126                                         }
1127                                 }
1128                         }
1129
1130                         /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
1131 #ifdef DEBUG
1132                         if ( debug ) {
1133                                 printf ( "%s (refclock_jjy.c) : send '#'\n",
1134                                          sFunctionName ) ;
1135                         }
1136 #endif
1137                         if ( write ( pp->io.fd, "#",1 ) != 1  ) {
1138                                 refclock_report ( peer, CEVNT_FAULT ) ;
1139                         }
1140
1141                 }
1142
1143                 break ;
1144
1145         default : /*  Unexpected reply */
1146
1147 #ifdef DEBUG
1148                 if ( debug ) {
1149                         printf ( "%s (refclock_jjy.c) : send '#'\n",
1150                                  sFunctionName ) ;
1151                 }
1152 #endif
1153                 if ( write ( pp->io.fd, "#",1 ) != 1  ) {
1154                         refclock_report ( peer, CEVNT_FAULT ) ;
1155                 }
1156
1157                 up->lineerror = 1 ;
1158                 break ;
1159
1160         }
1161
1162         return 1 ;
1163
1164 }
1165
1166 /**************************************************************************************************/
1167
1168 static int
1169 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
1170 {
1171 #ifdef DEBUG
1172         static const char *sFunctionName = "jjy_receive_citizentic_jjy200" ;
1173 #endif
1174
1175         struct jjyunit          *up ;
1176         struct refclockproc     *pp ;
1177         struct peer             *peer;
1178
1179         char    *pBuf ;
1180         int     iLen ;
1181         int     rc ;
1182         char    cApostrophe, sStatus[3] ;
1183         int     iWeekday ;
1184
1185         /*
1186         * Initialize pointers and read the timecode and timestamp
1187         */
1188         peer = rbufp->recv_peer ;
1189         pp = peer->procptr ;
1190         up = pp->unitptr ;
1191
1192         if ( up->linediscipline == LDISC_RAW ) {
1193                 pBuf = up->rawbuf ;
1194                 iLen = up->charcount ;
1195         } else {
1196                 pBuf = pp->a_lastcode ;
1197                 iLen = pp->lencode ;
1198         }
1199
1200         /*
1201         * JJY-200 sends a timestamp every second.
1202         * So, a timestamp is ignored unless it is right after polled.
1203         */
1204         if ( ! up->bPollFlag )
1205                 return 0 ;
1206
1207         switch ( up->linecount ) {
1208
1209         case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
1210
1211                 if ( iLen != 23 ) {
1212 #ifdef DEBUG
1213                         if ( debug >= 2 ) {
1214                                 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
1215                                          sFunctionName, iLen ) ;
1216                         }
1217 #endif
1218                         up->lineerror = 1 ;
1219                         break ;
1220                 }
1221
1222                 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
1223                               &cApostrophe, sStatus, &up->year,
1224                               &up->month, &up->day, &iWeekday,
1225                               &up->hour, &up->minute, &up->second ) ;
1226                 sStatus[2] = 0 ;
1227                 if ( rc != 9 || cApostrophe != '\'' ||
1228                      strcmp( sStatus, "OK" ) != 0 || up->month < 1 ||
1229                      up->month > 12 || up->day < 1 || up->day > 31 ||
1230                      iWeekday > 6 || up->hour > 23 || up->minute > 59 ||
1231                      up->second > 60 ) {
1232 #ifdef DEBUG
1233                         if ( debug >= 2 ) {
1234                                 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n",
1235                                          sFunctionName, rc, cApostrophe,
1236                                          sStatus, up->year, up->month,
1237                                          up->day, iWeekday, up->hour,
1238                                          up->minute, up->second ) ;
1239                         }
1240 #endif
1241                         up->lineerror = 1 ;
1242                         break ;
1243                 }
1244
1245                 up->year += 2000 ;
1246                 up->msecond = 0 ;
1247
1248                 break ;
1249
1250         default : /* Unexpected reply */
1251
1252                 up->lineerror = 1 ;
1253                 break ;
1254
1255         }
1256
1257         return 1 ;
1258
1259 }
1260
1261 /**************************************************************************************************/
1262
1263 static int
1264 jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
1265 {
1266 #ifdef DEBUG
1267         static  const char      *sFunctionName = "jjy_receive_tristate_gpsclock01" ;
1268 #endif
1269
1270         struct jjyunit      *up ;
1271         struct refclockproc *pp ;
1272         struct peer         *peer;
1273
1274         char    *pBuf ;
1275         int     iLen ;
1276         int     rc ;
1277
1278         int     bOverMidnight = 0 ;
1279
1280         char    sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ;
1281
1282         const char      *pCmd ;
1283         int     iCmdLen ;
1284
1285         /*
1286          * Initialize pointers and read the timecode and timestamp
1287          */
1288         peer = rbufp->recv_peer ;
1289         pp = peer->procptr ;
1290         up = pp->unitptr ;
1291
1292         if ( up->linediscipline == LDISC_RAW ) {
1293                 pBuf = up->rawbuf ;
1294                 iLen = up->charcount ;
1295         } else {
1296                 pBuf = pp->a_lastcode ;
1297                 iLen = pp->lencode ;
1298         }
1299
1300         /*
1301          * Ignore NMEA data stream
1302          */
1303         if ( iLen > 5
1304           && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
1305 #ifdef DEBUG
1306                 if ( debug ) {
1307                         printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
1308                                 sFunctionName, pBuf ) ;
1309                 }
1310 #endif
1311                 return 0 ;
1312         }
1313
1314         /*
1315          * Skip command prompt '$Cmd>' from the TS-GPSclock-01
1316          */
1317         if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
1318                 return 0 ;
1319         } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
1320                 pBuf += 5 ;
1321                 iLen -= 5 ;
1322         }
1323
1324         /*
1325          * Ignore NMEA data stream after command prompt
1326          */
1327         if ( iLen > 5
1328           && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
1329 #ifdef DEBUG
1330                 if ( debug ) {
1331                         printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n",
1332                                 sFunctionName, pBuf ) ;
1333                 }
1334 #endif
1335                 return 0 ;
1336         }
1337
1338         switch ( tristate_gpsclock01_command_sequence[up->linecount-1].commandNumber ) {
1339
1340         case TS_GPSCLOCK01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
1341
1342                 if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_DATE ) {
1343                         up->lineerror = 1 ;
1344                         break ;
1345                 }
1346
1347                 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
1348                 if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 ||
1349                      up->day < 1 || up->day > 31 ) {
1350                         up->lineerror = 1 ;
1351                         break ;
1352                 }
1353
1354                 break ;
1355
1356         case TS_GPSCLOCK01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
1357
1358                 if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_TIME ) {
1359                         up->lineerror = 1 ;
1360                         break ;
1361                 }
1362
1363                 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
1364                 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
1365                         up->lineerror = 1 ;
1366                         break ;
1367                 }
1368
1369                 up->msecond = 0 ;
1370
1371                 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
1372                         /*
1373                          * The command "date" and "time" were sent to the JJY receiver separately,
1374                          * and the JJY receiver replies a date and time separately.
1375                          * Just after midnight transitions, we ignore this time.
1376                          */
1377                         bOverMidnight = 1 ;
1378                 }
1379
1380                 break ;
1381
1382         case TS_GPSCLOCK01_COMMAND_NUMBER_STUS :
1383
1384                 if ( iLen == TS_GPSCLOCK01_REPLY_LENGTH_STUS
1385                   && ( strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_RTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1386                     || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_GPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1387                     || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_UTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
1388                     || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_PPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 ) ) {
1389                         /* Good */
1390                 } else {
1391                         up->lineerror = 1 ;
1392                         break ;
1393                 }
1394
1395                 break ;
1396
1397         default : /*  Unexpected reply */
1398
1399                 up->lineerror = 1 ;
1400                 break ;
1401
1402         }
1403
1404         /* Clockstats Log */
1405
1406         printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
1407         snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
1408                    up->linecount,
1409                    tristate_gpsclock01_command_sequence[up->linecount-1].commandLog,
1410                    ( up->lineerror == 0 ) 
1411                         ? ( ( bOverMidnight == 0 )
1412                                 ? 'O' 
1413                                 : 'S' ) 
1414                         : 'X',
1415                    sReplyText ) ;
1416         record_clock_stats ( &peer->srcadr, sLogText ) ;
1417
1418         /* Check before issue next command */
1419
1420         if ( up->lineerror != 0 ) {
1421                 /* Do not issue next command */
1422                 return 0 ;
1423         }
1424
1425         if ( bOverMidnight != 0 ) {
1426                 /* Do not issue next command */
1427                 return 0 ;
1428         }
1429
1430         if ( tristate_gpsclock01_command_sequence[up->linecount].command == NULL ) {
1431                 /* Command sequence completed */
1432                 return 1 ;
1433         }
1434
1435         /* Issue next command */
1436
1437 #ifdef DEBUG
1438         if ( debug ) {
1439                 printf ( "%s (refclock_jjy.c) : send '%s'\n",
1440                         sFunctionName, tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
1441         }
1442 #endif
1443
1444         pCmd =  tristate_gpsclock01_command_sequence[up->linecount].command ;
1445         iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
1446         if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1447                 refclock_report ( peer, CEVNT_FAULT ) ;
1448         }
1449
1450         return 0 ;
1451
1452 }
1453
1454 /**************************************************************************************************/
1455 /*  jjy_poll - called by the transmit procedure                                                   */
1456 /**************************************************************************************************/
1457 static void
1458 jjy_poll ( int unit, struct peer *peer )
1459 {
1460
1461         struct jjyunit      *up;
1462         struct refclockproc *pp;
1463
1464         pp = peer->procptr;
1465         up = pp->unitptr ;
1466
1467         if ( pp->polls > 0  &&  up->linecount == 0 ) {
1468                 /*
1469                  * No reply for last command
1470                  */
1471                 refclock_report ( peer, CEVNT_TIMEOUT ) ;
1472         }
1473
1474 #ifdef DEBUG
1475         if ( debug ) {
1476                 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1477         }
1478 #endif
1479
1480         pp->polls ++ ;
1481
1482         up->bPollFlag = 1 ;
1483         up->linecount = 0 ;
1484         up->lineerror = 0 ;
1485         up->charcount = 0 ;
1486
1487         switch ( up->unittype ) {
1488         
1489         case UNITTYPE_TRISTATE_JJY01 :
1490                 jjy_poll_tristate_jjy01  ( unit, peer ) ;
1491                 break ;
1492
1493         case UNITTYPE_CDEX_JST2000 :
1494                 jjy_poll_cdex_jst2000 ( unit, peer ) ;
1495                 break ;
1496
1497         case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1498                 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1499                 break ;
1500
1501         case UNITTYPE_CITIZENTIC_JJY200 :
1502                 jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1503                 break ;
1504
1505         case UNITTYPE_TRISTATE_GPSCLOCK01 :
1506                 jjy_poll_tristate_gpsclock01  ( unit, peer ) ;
1507                 break ;
1508
1509         default :
1510                 break ;
1511
1512         }
1513
1514 }
1515
1516 /**************************************************************************************************/
1517
1518 static void
1519 jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1520 {
1521 #ifdef DEBUG
1522         static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
1523 #endif
1524
1525         struct jjyunit      *up;
1526         struct refclockproc *pp;
1527
1528         const char *pCmd ;
1529         int     iCmdLen ;
1530
1531         pp = peer->procptr;
1532         up = pp->unitptr ;
1533
1534         if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1535                 up->linecount = 2 ;
1536         }
1537
1538 #ifdef DEBUG
1539         if ( debug ) {
1540                 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
1541                         sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1542                         up->linecount ) ;
1543         }
1544 #endif
1545
1546         /*
1547          * Send a first command
1548          */
1549
1550 #ifdef DEBUG
1551         if ( debug ) {
1552                 printf ( "%s (refclock_jjy.c) : send '%s'\n",
1553                          sFunctionName,
1554                          tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
1555         }
1556 #endif
1557
1558         pCmd =  tristate_jjy01_command_sequence[up->linecount].command ;
1559         iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
1560         if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1561                 refclock_report ( peer, CEVNT_FAULT ) ;
1562         }
1563
1564 }
1565
1566 /**************************************************************************************************/
1567
1568 static void
1569 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1570 {
1571
1572         struct refclockproc *pp;
1573
1574         pp = peer->procptr;
1575
1576         /*
1577          * Send "<ENQ>1J<ETX>" command
1578          */
1579
1580 #ifdef DEBUG
1581         if ( debug ) {
1582                 printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1583         }
1584 #endif
1585
1586         if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1587                 refclock_report ( peer, CEVNT_FAULT ) ;
1588         }
1589
1590 }
1591
1592 /**************************************************************************************************/
1593
1594 static void
1595 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1596 {
1597
1598         struct jjyunit      *up;
1599         struct refclockproc *pp;
1600
1601         char    sCmd[2] ;
1602
1603         pp = peer->procptr;
1604         up = pp->unitptr ;
1605
1606         /*
1607          * Send "T" or "C" command
1608          */
1609
1610         switch ( up->operationmode ) {
1611         case 1 : sCmd[0] = 'T' ; break ;
1612         case 2 : sCmd[0] = 'C' ; break ;
1613         }
1614         sCmd[1] = 0 ;
1615
1616 #ifdef DEBUG
1617         if ( debug ) {
1618                 printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1619         }
1620 #endif
1621
1622         if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1623                 refclock_report ( peer, CEVNT_FAULT ) ;
1624         }
1625
1626 }
1627
1628 /**************************************************************************************************/
1629
1630 static void
1631 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1632 {
1633
1634         /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1635
1636 }
1637
1638 /**************************************************************************************************/
1639
1640 static void
1641 jjy_poll_tristate_gpsclock01  ( int unit, struct peer *peer )
1642 {
1643 #ifdef DEBUG
1644         static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
1645 #endif
1646
1647         struct jjyunit      *up;
1648         struct refclockproc *pp;
1649
1650         const char      *pCmd ;
1651         int     iCmdLen ;
1652
1653         pp = peer->procptr;
1654         up = pp->unitptr ;
1655
1656         if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
1657                 up->linecount = 1 ;
1658         }
1659
1660 #ifdef DEBUG
1661         if ( debug ) {
1662                 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
1663                         sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
1664                         up->linecount ) ;
1665         }
1666 #endif
1667
1668         /*
1669          * Send a first command
1670          */
1671
1672 #ifdef DEBUG
1673         if ( debug ) {
1674                 printf ( "%s (refclock_jjy.c) : send '%s'\n",
1675                          sFunctionName,
1676                          tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
1677         }
1678 #endif
1679
1680         pCmd =  tristate_gpsclock01_command_sequence[up->linecount].command ;
1681         iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
1682         if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
1683                 refclock_report ( peer, CEVNT_FAULT ) ;
1684         }
1685
1686 }
1687
1688 /**************************************************************************************************/
1689
1690 static void
1691 printableString ( char *sOutput, int iOutputLen, char *sInput, int iInputLen )
1692 {
1693         const char      *printableControlChar[] = {
1694                         "<NUL>", "<SOH>", "<STX>", "<ETX>",
1695                         "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
1696                         "<BS>" , "<HT>" , "<LF>" , "<VT>" ,
1697                         "<FF>" , "<CR>" , "<SO>" , "<SI>" ,
1698                         "<DLE>", "<DC1>", "<DC2>", "<DC3>",
1699                         "<DC4>", "<NAK>", "<SYN>", "<ETB>",
1700                         "<CAN>", "<EM>" , "<SUB>", "<ESC>",
1701                         "<FS>" , "<GS>" , "<RS>" , "<US>" ,
1702                         " " } ;
1703
1704         size_t  i, j, n ;
1705         size_t  InputLen;
1706         size_t  OutputLen;
1707
1708         InputLen = (size_t)iInputLen;
1709         OutputLen = (size_t)iOutputLen;
1710         for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) {
1711                 if ( isprint( (unsigned char)sInput[i] ) ) {
1712                         n = 1 ;
1713                         if ( j + 1 >= OutputLen )
1714                                 break ;
1715                         sOutput[j] = sInput[i] ;
1716                 } else if ( ( sInput[i] & 0xFF ) < 
1717                             COUNTOF(printableControlChar) ) {
1718                         n = strlen( printableControlChar[sInput[i] & 0xFF] ) ;
1719                         if ( j + n + 1 >= OutputLen )
1720                                 break ;
1721                         strlcpy( sOutput + j,
1722                                  printableControlChar[sInput[i] & 0xFF],
1723                                  OutputLen - j ) ;
1724                 } else {
1725                         n = 5 ;
1726                         if ( j + n + 1 >= OutputLen )
1727                                 break ;
1728                         snprintf( sOutput + j, OutputLen - j, "<x%X>",
1729                                   sInput[i] & 0xFF ) ;
1730                 }
1731                 j += n ;
1732         }
1733
1734         sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ;
1735
1736 }
1737
1738 /**************************************************************************************************/
1739
1740 #else
1741 int refclock_jjy_bs ;
1742 #endif /* REFCLOCK */