]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/ntpd/refclock_jjy.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / ntpd / refclock_jjy.c
1 /*
2  * refclock_jjy - clock driver for JJY receivers
3  */
4
5 /**********************************************************************/
6 /*                                                                    */
7 /*  Copyright (C) 2001-2004, 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      abetakao@bea.hi-ho.ne.jp                               */
45 /*  Homepage   http://www.bea.hi-ho.ne.jp/abetakao/                   */
46 /*                                                                    */
47 /**********************************************************************/
48 /*                                                                    */
49 /*  History                                                           */
50 /*                                                                    */
51 /*  2001/07/15                                                        */
52 /*    [New]    Support the Tristate Ltd. JJY receiver                 */
53 /*                                                                    */
54 /*  2001/08/04                                                        */
55 /*    [Change] Log to clockstats even if bad reply                    */
56 /*    [Fix]    PRECISION = (-3) (about 100 ms)                        */
57 /*    [Add]    Support the C-DEX Co.Ltd. JJY receiver                 */
58 /*                                                                    */
59 /*  2001/12/04                                                        */
60 /*    [Fix]    C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp )      */
61 /*                                                                    */
62 /*  2002/07/12                                                        */
63 /*    [Fix]    Portability for FreeBSD ( patched by the user )        */
64 /*                                                                    */
65 /*  2004/10/31                                                        */
66 /*    [Change] Command send timing for the Tristate Ltd. JJY receiver */
67 /*             JJY-01 ( Firmware version 2.01 )                       */
68 /*             Thanks to Andy Taki for testing under FreeBSD          */
69 /*                                                                    */
70 /*  2004/11/28                                                        */
71 /*    [Add]    Support the Echo Keisokuki LT-2000 receiver            */
72 /*                                                                    */
73 /*  2006/11/04                                                        */
74 /*    [Fix]    C-DEX JST2000                                          */
75 /*             Thanks to Hideo Kuramatsu for the patch                */
76 /*                                                                    */
77 /*  2009/04/05                                                        */
78 /*    [Add]    Support the CITIZEN T.I.C JJY-200 receiver             */
79 /*                                                                    */
80 /**********************************************************************/
81
82 #ifdef HAVE_CONFIG_H
83 #include <config.h>
84 #endif
85
86 #if defined(REFCLOCK) && defined(CLOCK_JJY)
87
88 #include <stdio.h>
89 #include <ctype.h>
90 #include <string.h>
91 #include <sys/time.h>
92 #include <time.h>
93
94 #include "ntpd.h"
95 #include "ntp_io.h"
96 #include "ntp_tty.h"
97 #include "ntp_refclock.h"
98 #include "ntp_calendar.h"
99 #include "ntp_stdlib.h"
100
101 /**********************************************************************/
102 /*                                                                    */
103 /*  The Tristate Ltd. JJY receiver JJY01                              */
104 /*                                                                    */
105 /*  Command        Response                 Remarks                   */
106 /*  ------------   ----------------------   ---------------------     */
107 /*  date<CR><LF>   YYYY/MM/DD XXX<CR><LF>                             */
108 /*  time<CR><LF>   HH:MM:SS<CR><LF>                                   */
109 /*  stim<CR><LF>   HH:MM:SS<CR><LF>         Reply at just second      */
110 /*                                                                    */
111 /*  During synchronization after a receiver is turned on,             */
112 /*  It replies the past time from 2000/01/01 00:00:00.                */
113 /*  The function "refclock_process" checks the time and tells         */
114 /*  as an insanity time.                                              */
115 /*                                                                    */
116 /**********************************************************************/
117 /*                                                                    */
118 /*  The C-DEX Co. Ltd. JJY receiver JST2000                           */
119 /*                                                                    */
120 /*  Command        Response                 Remarks                   */
121 /*  ------------   ----------------------   ---------------------     */
122 /*  <ENQ>1J<ETX>   <STX>JYYMMDD HHMMSSS<ETX>                          */
123 /*                                                                    */
124 /**********************************************************************/
125 /*                                                                    */
126 /*  The Echo Keisokuki Co. Ltd. JJY receiver LT2000                   */
127 /*                                                                    */
128 /*  Command        Response                 Remarks                   */
129 /*  ------------   ----------------------   ---------------------     */
130 /*  #                                       Mode 1 (Request&Send)     */
131 /*  T              YYMMDDWHHMMSS<BCC1><BCC2><CR>                      */
132 /*  C                                       Mode 2 (Continuous)       */
133 /*                 YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR>              */
134 /*                 <SUB>                    Second signal             */
135 /*                                                                    */
136 /**********************************************************************/
137 /*                                                                    */
138 /*  The CITIZEN T.I.C CO., LTD. JJY receiver JJY200                   */
139 /*                                                                    */
140 /*  Command        Response                 Remarks                   */
141 /*  ------------   ----------------------   ---------------------     */
142 /*                 'XX YY/MM/DD W HH:MM:SS<CR>                        */
143 /*                                          XX: OK|NG|ER              */
144 /*                                          W:  0(Monday)-6(Sunday)   */
145 /*                                                                    */
146 /**********************************************************************/
147
148 /*
149  * Interface definitions
150  */
151 #define DEVICE          "/dev/jjy%d"    /* device name and unit */
152 #define SPEED232        B9600           /* uart speed (9600 baud) */
153 #define SPEED232_TRISTATE_JJY01         B9600   /* UART speed (9600 baud) */
154 #define SPEED232_CDEX_JST2000           B9600   /* UART speed (9600 baud) */
155 #define SPEED232_ECHOKEISOKUKI_LT2000   B9600   /* UART speed (9600 baud) */
156 #define SPEED232_CITIZENTIC_JJY200      B4800   /* UART speed (4800 baud) */
157 #define REFID           "JJY"           /* reference ID */
158 #define DESCRIPTION     "JJY Receiver"
159 #define PRECISION       (-3)           /* precision assumed (about 100 ms) */
160
161 /*
162  * JJY unit control structure
163  */
164 struct jjyunit {
165         char    unittype ;          /* UNITTYPE_XXXXXXXXXX */
166     short   operationmode ;     /* Echo Keisokuki LT-2000 : 1 or 2 */
167         short   version ;
168         short   linediscipline ;        /* LDISC_CLK or LDISC_RAW */
169     char    bPollFlag ;         /* Set by jjy_pool and Reset by jjy_receive */
170         int     linecount ;
171         int     lineerror ;
172         int     year, month, day, hour, minute, second, msecond ;
173 /* LDISC_RAW only */
174 #define MAX_LINECOUNT   8
175 #define MAX_RAWBUF      64
176         int     lineexpect ;
177         int     charexpect [ MAX_LINECOUNT ] ;
178         int     charcount ;
179         char    rawbuf [ MAX_RAWBUF ] ;
180 };
181
182 #define UNITTYPE_TRISTATE_JJY01 1
183 #define UNITTYPE_CDEX_JST2000   2
184 #define UNITTYPE_ECHOKEISOKUKI_LT2000   3
185 #define UNITTYPE_CITIZENTIC_JJY200      4
186
187 /*
188  * Function prototypes
189  */
190 static  int     jjy_start                   P((int, struct peer *));
191 static  void    jjy_shutdown                P((int, struct peer *));
192 static  void    jjy_poll                    P((int, struct peer *));
193 static  void    jjy_poll_tristate_jjy01     P((int, struct peer *));
194 static  void    jjy_poll_cdex_jst2000       P((int, struct peer *));
195 static  void    jjy_poll_echokeisokuki_lt2000    P((int, struct peer *));
196 static  void    jjy_poll_citizentic_jjy200          P((int, struct peer *));
197 static  void    jjy_receive                 P((struct recvbuf *));
198 static  int     jjy_receive_tristate_jjy01  P((struct recvbuf *));
199 static  int     jjy_receive_cdex_jst2000    P((struct recvbuf *));
200 static  int     jjy_receive_echokeisokuki_lt2000 P((struct recvbuf *));
201 static  int     jjy_receive_citizentic_jjy200       P((struct recvbuf *));
202
203 /*
204  * Transfer vector
205  */
206 struct  refclock refclock_jjy = {
207         jjy_start,      /* start up driver */
208         jjy_shutdown,   /* shutdown driver */
209         jjy_poll,       /* transmit poll message */
210         noentry,        /* not used */
211         noentry,        /* not used */
212         noentry,        /* not used */
213         NOFLAGS         /* not used */
214 };
215
216 /*
217  * Start up driver return code
218  */
219 #define RC_START_SUCCESS        1
220 #define RC_START_ERROR          0
221
222 /*
223  * Local constants definition
224  */
225
226 #define MAX_LOGTEXT     64
227
228
229 /**************************************************************************************************/
230 /*  jjy_start - open the devices and initialize data for processing                               */
231 /**************************************************************************************************/
232 static int
233 jjy_start ( int unit, struct peer *peer )
234 {
235
236         struct jjyunit      *up ;
237         struct refclockproc *pp ;
238         int     fd ;
239         char    *pDeviceName ;
240         short   iDiscipline ;
241         int     iSpeed232 ;
242
243 #ifdef DEBUG
244         if ( debug ) {
245                 printf ( "jjy_start (refclock_jjy.c) : %s  mode=%d  ", ntoa(&peer->srcadr), peer->ttl ) ;
246                 printf ( DEVICE, unit ) ;
247                 printf ( "\n" ) ;
248         }
249 #endif
250         /*
251          * Open serial port
252          */
253         if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
254                 return RC_START_ERROR ;
255         }
256         sprintf ( pDeviceName, DEVICE, unit ) ;
257
258         /*
259          * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
260          */
261         switch ( peer->ttl ) {
262         case 0 :
263     case 1 :
264         iDiscipline = LDISC_CLK ;
265         iSpeed232   = SPEED232_TRISTATE_JJY01 ;
266         break ;
267     case 2 :
268         iDiscipline = LDISC_RAW ;
269         iSpeed232   = SPEED232_CDEX_JST2000   ;
270         break ;
271     case 3 :
272         iDiscipline = LDISC_CLK ;
273         iSpeed232   = SPEED232_ECHOKEISOKUKI_LT2000 ;
274         break ;
275     case 4 :
276         iDiscipline = LDISC_CLK ;
277         iSpeed232   = SPEED232_CITIZENTIC_JJY200 ;
278         break ;
279         default :
280                 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
281                           ntoa(&peer->srcadr), peer->ttl ) ;
282                 free ( (void*) pDeviceName ) ;
283                 return RC_START_ERROR ;
284         }
285
286         if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) {
287                 free ( (void*) pDeviceName ) ;
288                 return RC_START_ERROR ;
289         }
290         free ( (void*) pDeviceName ) ;
291
292         /*
293          * Allocate and initialize unit structure
294          */
295         if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
296                 close ( fd ) ;
297                 return RC_START_ERROR ;
298         }
299
300         memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
301         up->linediscipline = iDiscipline ;
302
303         /*
304          * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
305          */
306         switch ( peer->ttl ) {
307         case 0 :
308                 /*
309                  * The mode 0 is a default clock type at this time.
310                  * But this will be change to auto-detect mode in the future.
311                  */
312         case 1 :
313                 up->unittype = UNITTYPE_TRISTATE_JJY01 ;
314                 up->version  = 100 ;
315                 up->lineexpect = 2 ;
316                 up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
317                 up->charexpect[1] =  8 ; /* HH:MM:SS<CR><LF> */
318                 break ;
319         case 2 :
320                 up->unittype = UNITTYPE_CDEX_JST2000 ;
321                 up->lineexpect = 1 ;
322                 up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
323                 break ;
324         case 3 :
325                 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
326                 up->operationmode = 2 ;  /* Mode 2 : Continuous mode */
327                 up->lineexpect = 1 ;
328         switch ( up->operationmode ) {
329         case 1 :
330                         up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
331                         break ;
332                 case 2 :
333                         up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
334                         break ;
335                 }
336                 break ;
337     case 4 :
338         up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
339         up->lineexpect = 1 ;
340         up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
341         break ;
342         default :
343                 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
344                           ntoa(&peer->srcadr), peer->ttl ) ;
345                 close ( fd ) ;
346                 free ( (void*) up ) ;
347                 return RC_START_ERROR ;
348         }
349
350         pp = peer->procptr ;
351         pp->unitptr       = (caddr_t) up ;
352         pp->io.clock_recv = jjy_receive ;
353         pp->io.srcclock   = (caddr_t) peer ;
354         pp->io.datalen    = 0 ;
355         pp->io.fd         = fd ;
356         if ( ! io_addclock(&pp->io) ) {
357                 close ( fd ) ;
358                 free ( (void*) up ) ;
359                 return RC_START_ERROR ;
360         }
361
362         /*
363          * Initialize miscellaneous variables
364          */
365         peer->precision = PRECISION ;
366         peer->burst     = 1 ;
367         pp->clockdesc   = DESCRIPTION ;
368         memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
369
370         return RC_START_SUCCESS ;
371
372 }
373
374
375 /**************************************************************************************************/
376 /*  jjy_shutdown - shutdown the clock                                                             */
377 /**************************************************************************************************/
378 static void
379 jjy_shutdown ( int unit, struct peer *peer )
380 {
381
382         struct jjyunit      *up;
383         struct refclockproc *pp;
384
385         pp = peer->procptr ;
386         up = (struct jjyunit *) pp->unitptr ;
387         io_closeclock ( &pp->io ) ;
388         free ( (void*) up ) ;
389
390 }
391
392
393 /**************************************************************************************************/
394 /*  jjy_receive - receive data from the serial interface                                          */
395 /**************************************************************************************************/
396 static void
397 jjy_receive ( struct recvbuf *rbufp )
398 {
399
400         struct jjyunit      *up ;
401         struct refclockproc *pp ;
402         struct peer         *peer;
403
404         l_fp    tRecvTimestamp;         /* arrival timestamp */
405         int     rc ;
406         char    sLogText [ MAX_LOGTEXT ] ;
407         int     i, bCntrlChar ;
408
409         /*
410          * Initialize pointers and read the timecode and timestamp
411          */
412         peer = (struct peer *) rbufp->recv_srcclock ;
413         pp = peer->procptr ;
414         up = (struct jjyunit *) pp->unitptr ;
415
416         /*
417          * Get next input line
418          */
419         pp->lencode  = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
420
421         if ( up->linediscipline == LDISC_RAW ) {
422                 /*
423                  * The reply with <STX> and <ETX> may give a blank line
424                  */
425                 if ( pp->lencode == 0  &&  up->charcount == 0 ) return ;
426                 /*
427                  * Copy received charaters to temporary buffer 
428                  */
429                 for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
430                         up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
431                 }
432                 while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
433                         for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ;
434                         up->charcount -- ;
435                 }
436                 bCntrlChar = 0 ;
437                 for ( i = 0 ; i < up->charcount ; i ++ ) {
438                         if ( up->rawbuf[i] < ' ' ) {
439                                 bCntrlChar = 1 ;
440                                 break ;
441                         }
442                 }
443                 if ( pp->lencode > 0  &&  up->linecount < up->lineexpect ) {
444                         if ( bCntrlChar == 0  &&  up->charcount < up->charexpect[up->linecount] ) return ;
445                 }
446                 up->rawbuf[up->charcount] = 0 ;
447         } else {
448                 /*
449                  * The reply with <CR><LF> gives a blank line
450                  */
451                 if ( pp->lencode == 0 ) return ;
452         }
453         /*
454          * We get down to business
455          */
456
457         pp->lastrec = tRecvTimestamp ;
458
459         up->linecount ++ ;
460
461         if ( up->lineerror != 0 ) return ;
462
463         switch ( up->unittype ) {
464         
465         case UNITTYPE_TRISTATE_JJY01 :
466                 rc = jjy_receive_tristate_jjy01  ( rbufp ) ;
467                 break ;
468
469         case UNITTYPE_CDEX_JST2000 :
470                 rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
471                 break ;
472
473         case UNITTYPE_ECHOKEISOKUKI_LT2000 :
474                 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
475                 break ;
476
477     case UNITTYPE_CITIZENTIC_JJY200 :
478         rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
479         break ;
480
481         default :
482                 rc = 0 ;
483                 break ;
484
485         }
486
487         if ( up->linediscipline == LDISC_RAW ) {
488                 if ( up->linecount <= up->lineexpect  &&  up->charcount > up->charexpect[up->linecount-1] ) {
489                         for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) {
490                                 up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
491                         }
492                         up->charcount -= up->charexpect[up->linecount-1] ;
493                 } else {
494                         up->charcount = 0 ;
495                 }
496         }
497
498         if ( rc == 0 ) return ;
499
500     up->bPollFlag = 0 ;
501
502         if ( up->lineerror != 0 ) {
503                 refclock_report ( peer, CEVNT_BADREPLY ) ;
504                 strcpy  ( sLogText, "BAD REPLY [" ) ;
505                 if ( up->linediscipline == LDISC_RAW ) {
506                         strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
507                 } else {
508                         strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
509                 }
510                 sLogText[MAX_LOGTEXT-1] = 0 ;
511                 if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
512                 record_clock_stats ( &peer->srcadr, sLogText ) ;
513                 return ;
514         }
515
516         pp->year   = up->year ;
517         pp->day    = ymd2yd ( up->year, up->month, up->day ) ;
518         pp->hour   = up->hour ;
519         pp->minute = up->minute ;
520         pp->second = up->second ;
521         pp->nsec   = up->msecond * 1000000;
522
523         /* 
524          * JST to UTC 
525          */
526         pp->hour -= 9 ;
527         if ( pp->hour < 0 ) {
528                 pp->hour += 24 ;
529                 pp->day -- ;
530                 if ( pp->day < 1 ) {
531                         pp->year -- ;
532                         pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
533                 }
534         }
535 #ifdef DEBUG
536         if ( debug ) {
537                 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST   ", 
538                           up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
539                 printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
540                           pp->year, pp->day, pp->hour, pp->minute, pp->second, (int)(pp->nsec/100000000) ) ;
541         }
542 #endif
543
544         /*
545          * Process the new sample in the median filter and determine the
546          * timecode timestamp.
547          */
548
549         sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
550                   up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
551         record_clock_stats ( &peer->srcadr, sLogText ) ;
552
553         if ( ! refclock_process ( pp ) ) {
554                 refclock_report(peer, CEVNT_BADTIME);
555                 return ;
556         }
557
558         pp->lastref = pp->lastrec;
559         refclock_receive(peer);
560
561 }
562
563 /**************************************************************************************************/
564
565 static int
566 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
567 {
568
569         static  char    *sFunctionName = "jjy_receive_tristate_jjy01" ;
570
571         struct jjyunit      *up ;
572         struct refclockproc *pp ;
573         struct peer         *peer;
574
575         char    *pBuf ;
576         int     iLen ;
577         int     rc ;
578
579         /*
580          * Initialize pointers and read the timecode and timestamp
581          */
582         peer = (struct peer *) rbufp->recv_srcclock ;
583         pp = peer->procptr ;
584         up = (struct jjyunit *) pp->unitptr ;
585
586         if ( up->linediscipline == LDISC_RAW ) {
587                 pBuf = up->rawbuf ;
588                 iLen = up->charcount ;
589         } else {
590             pBuf = pp->a_lastcode ;
591             iLen = pp->lencode ;
592         }
593
594         switch ( up->linecount ) {
595
596         case 1 : /* YYYY/MM/DD WWW */
597
598                 if ( iLen != 14 ) {
599 #ifdef DEBUG
600                 if ( debug >= 2 ) {
601                         printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d  iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
602                 }
603 #endif
604                         up->lineerror = 1 ;
605                         break ;
606                 }
607                 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
608                 if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
609 #ifdef DEBUG
610                 if ( debug >= 2 ) {
611                         printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
612                 }
613 #endif
614                         up->lineerror = 1 ;
615                         break ;
616                 }
617
618                 /*** Start of modification on 2004/10/31 */
619                 /*
620                  * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
621                  * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
622                  * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
623                  * so this driver issues the second command "stim" after the reply of the first command "date".
624                  */
625
626                 /*
627                  * Send "stim<CR><LF>" or "time<CR><LF>" command
628                  */
629                  
630
631                 if ( up->version >= 100 ) {
632 #ifdef DEBUG
633                         if ( debug ) {
634                                 printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName ) ;
635                         }
636 #endif
637                         if ( write ( pp->io.fd, "stim\r\n",6 ) != 6  ) {
638                                 refclock_report ( peer, CEVNT_FAULT ) ;
639                         }
640                 } else {
641 #ifdef DEBUG
642                         if ( debug ) {
643                                 printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName ) ;
644                         }
645 #endif
646                         if ( write ( pp->io.fd, "time\r\n",6 ) != 6  ) {
647                                 refclock_report ( peer, CEVNT_FAULT ) ;
648                         }
649                 }
650                 /*** End of modification ***/
651
652                 return 0 ;
653
654         case 2 : /* HH:MM:SS */
655
656                 if ( iLen != 8 ) {
657 #ifdef DEBUG
658                 if ( debug >= 2 ) {
659                         printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d  iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
660                 }
661 #endif
662                         up->lineerror = 1 ;
663                         break ;
664                 }
665                 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
666                 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
667 #ifdef DEBUG
668                 if ( debug >= 2 ) {
669                         printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
670                 }
671 #endif
672                         up->lineerror = 1 ;
673                         break ;
674                 }
675                 up->msecond = 0 ;
676                 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
677                         /*
678                          * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
679                          * But the JJY receiver replies a date and time separately.
680                          * Just after midnight transitions, we ignore this time.
681                          */
682                         return 0 ;
683                 }
684                 break ;
685
686         default : /*  Unexpected reply */
687
688                 up->lineerror = 1 ;
689                 break ;
690
691         }
692
693         return 1 ;
694
695 }
696
697 /**************************************************************************************************/
698
699 static int
700 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
701 {
702
703         static  char    *sFunctionName = "jjy_receive_cdex_jst2000" ;
704
705         struct jjyunit      *up ;
706         struct refclockproc *pp ;
707         struct peer         *peer;
708
709         char    *pBuf ;
710         int     iLen ;
711         int     rc ;
712
713         /*
714          * Initialize pointers and read the timecode and timestamp
715          */
716         peer = (struct peer *) rbufp->recv_srcclock ;
717         pp = peer->procptr ;
718         up = (struct jjyunit *) pp->unitptr ;
719
720         if ( up->linediscipline == LDISC_RAW ) {
721                 pBuf = up->rawbuf ;
722                 iLen = up->charcount ;
723         } else {
724             pBuf = pp->a_lastcode ;
725             iLen = pp->lencode ;
726         }
727
728         switch ( up->linecount ) {
729
730         case 1 : /* JYYMMDD HHMMSSS */
731
732                 if ( iLen != 15 ) {
733 #ifdef DEBUG
734                 if ( debug >= 2 ) {
735                         printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
736                 }
737 #endif
738                         up->lineerror = 1 ;
739                         break ;
740                 }
741                 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
742                               &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
743                 if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
744                   || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
745 #ifdef DEBUG
746                 if ( debug >= 2 ) {
747                         printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName,
748                                                  rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ;
749                 }
750 #endif
751                         up->lineerror = 1 ;
752                         break ;
753                 }
754                 up->year    += 2000 ;
755                 up->msecond *= 100 ;
756                 break ;
757
758         default : /*  Unexpected reply */
759
760                 up->lineerror = 1 ;
761                 break ;
762
763         }
764
765         return 1 ;
766
767 }
768
769 /**************************************************************************************************/
770
771 static int
772 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
773 {
774
775         static  char    *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
776
777         struct jjyunit      *up ;
778         struct refclockproc *pp ;
779         struct peer         *peer;
780
781         char    *pBuf ;
782         int     iLen ;
783         int     rc ;
784     int     i, ibcc, ibcc1, ibcc2 ;
785
786         /*
787          * Initialize pointers and read the timecode and timestamp
788          */
789         peer = (struct peer *) rbufp->recv_srcclock ;
790         pp = peer->procptr ;
791         up = (struct jjyunit *) pp->unitptr ;
792
793         if ( up->linediscipline == LDISC_RAW ) {
794                 pBuf = up->rawbuf ;
795                 iLen = up->charcount ;
796         } else {
797             pBuf = pp->a_lastcode ;
798             iLen = pp->lencode ;
799         }
800
801         switch ( up->linecount ) {
802
803         case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
804
805                 if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) {
806 #ifdef DEBUG
807                 if ( debug >= 2 ) {
808                         printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
809                 }
810 #endif
811                         if ( up->operationmode == 1 ) {
812 #ifdef DEBUG
813                                 if ( debug ) {
814                                         printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
815                                 }
816 #endif
817                                 if ( write ( pp->io.fd, "#",1 ) != 1  ) {
818                                         refclock_report ( peer, CEVNT_FAULT ) ;
819                                 }
820                         }
821                         up->lineerror = 1 ;
822                         break ;
823                 }
824
825                 if ( up->operationmode == 1 ) {
826
827                 for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ;
828                 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
829                 ibcc2 = 0x30 | ( ( ibcc      ) & 0xF ) ;
830                 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
831 #ifdef DEBUG
832                         if ( debug >= 2 ) {
833                                 printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ;
834                         }
835 #endif
836                                 up->lineerror = 1 ;
837                                 break ;
838                         }
839
840         }
841
842                 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
843                       &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ;
844                 if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
845                   || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
846 #ifdef DEBUG
847                 if ( debug >= 2 ) {
848                         printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName,
849                                                  rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
850                 }
851 #endif
852                         up->lineerror = 1 ;
853                         break ;
854                 }
855
856                 up->year += 2000 ;
857
858                 if ( up->operationmode == 2 ) {
859
860                         /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
861                         up->msecond = 500 ;
862                         pp->second -- ;
863                         if ( pp->second < 0 ) {
864                                 pp->second = 59 ;
865                                 pp->minute -- ;
866                                 if ( pp->minute < 0 ) {
867                                         pp->minute = 59 ;
868                                         pp->hour -- ;
869                                         if ( pp->hour < 0 ) {
870                                                 pp->hour = 23 ;
871                                                 pp->day -- ;
872                                                 if ( pp->day < 1 ) {
873                                                         pp->year -- ;
874                                                         pp->day  = ymd2yd ( pp->year, 12, 31 ) ;
875                                                 }
876                                         }
877                                 }
878                         }
879
880                         /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
881 #ifdef DEBUG
882                         if ( debug ) {
883                                 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
884                         }
885 #endif
886                         if ( write ( pp->io.fd, "#",1 ) != 1  ) {
887                                 refclock_report ( peer, CEVNT_FAULT ) ;
888                         }
889
890                 }
891
892                 break ;
893
894         default : /*  Unexpected reply */
895
896 #ifdef DEBUG
897                 if ( debug ) {
898                         printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
899                 }
900 #endif
901                 if ( write ( pp->io.fd, "#",1 ) != 1  ) {
902                         refclock_report ( peer, CEVNT_FAULT ) ;
903                 }
904
905                 up->lineerror = 1 ;
906                 break ;
907
908         }
909
910         return 1 ;
911
912 }
913
914 /**************************************************************************************************/
915
916 static int
917 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
918 {
919
920     static  char    *sFunctionName = "jjy_receive_citizentic_jjy200" ;
921
922     struct jjyunit      *up ;
923     struct refclockproc *pp ;
924     struct peer         *peer;
925
926     char    *pBuf ;
927     int     iLen ;
928     int     rc ;
929     char    cApostrophe, sStatus[3] ;
930     int     iWeekday ;
931
932     /*
933      * Initialize pointers and read the timecode and timestamp
934      */
935     peer = (struct peer *) rbufp->recv_srcclock ;
936     pp = peer->procptr ;
937     up = (struct jjyunit *) pp->unitptr ;
938
939     if ( up->linediscipline == LDISC_RAW ) {
940         pBuf = up->rawbuf ;
941         iLen = up->charcount ;
942     } else {
943         pBuf = pp->a_lastcode ;
944         iLen = pp->lencode ;
945     }
946
947     /*
948      * JJY-200 sends a timestamp every second.
949      * So, a timestamp is ignored unless it is right after polled.
950      */
951     if ( ! up->bPollFlag ) return 0 ;
952
953     switch ( up->linecount ) {
954
955     case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
956
957         if ( iLen != 23 ) {
958 #ifdef DEBUG
959             if ( debug >= 2 ) {
960                 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
961             }
962 #endif
963             up->lineerror = 1 ;
964             break ;
965         }
966
967         rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
968                       &cApostrophe, sStatus, 
969                       &up->year, &up->month, &up->day, &iWeekday, &up->hour, &up->minute, &up->second ) ;
970         sStatus[2] = 0 ;
971         if ( rc != 9 || cApostrophe != '\'' || strcmp( sStatus, "OK" ) != 0
972           || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
973           || iWeekday > 6
974           || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
975 #ifdef DEBUG
976             if ( debug >= 2 ) {
977                 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", sFunctionName,
978                          rc, cApostrophe, sStatus, up->year, up->month, up->day, iWeekday, up->hour, up->minute, up->second ) ;
979             }
980 #endif
981             up->lineerror = 1 ;
982             break ;
983         }
984
985         up->year += 2000 ;
986         up->msecond = 0 ;
987
988         break ;
989
990     default : /* Unexpected reply */
991
992         up->lineerror = 1 ;
993         break ;
994
995     }
996
997     return 1 ;
998
999 }
1000
1001 /**************************************************************************************************/
1002 /*  jjy_poll - called by the transmit procedure                                                   */
1003 /**************************************************************************************************/
1004 static void
1005 jjy_poll ( int unit, struct peer *peer )
1006 {
1007
1008         struct jjyunit      *up;
1009         struct refclockproc *pp;
1010
1011         pp = peer->procptr;
1012         up = (struct jjyunit *) pp->unitptr ;
1013
1014         if ( pp->polls > 0  &&  up->linecount == 0 ) {
1015                 /*
1016                  * No reply for last command
1017                  */
1018                 refclock_report ( peer, CEVNT_TIMEOUT ) ;
1019         }
1020
1021 #ifdef DEBUG
1022         if ( debug ) {
1023                 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
1024         }
1025 #endif
1026
1027         pp->polls ++ ;
1028
1029     up->bPollFlag = 1 ;
1030         up->linecount = 0 ;
1031         up->lineerror = 0 ;
1032         up->charcount = 0 ;
1033
1034         switch ( up->unittype ) {
1035         
1036         case UNITTYPE_TRISTATE_JJY01 :
1037                 jjy_poll_tristate_jjy01  ( unit, peer ) ;
1038                 break ;
1039
1040         case UNITTYPE_CDEX_JST2000 :
1041                 jjy_poll_cdex_jst2000 ( unit, peer ) ;
1042                 break ;
1043
1044         case UNITTYPE_ECHOKEISOKUKI_LT2000 :
1045                 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
1046                 break ;
1047
1048     case UNITTYPE_CITIZENTIC_JJY200 :
1049         jjy_poll_citizentic_jjy200 ( unit, peer ) ;
1050         break ;
1051
1052         default :
1053                 break ;
1054
1055         }
1056
1057 }
1058
1059 /**************************************************************************************************/
1060
1061 static void
1062 jjy_poll_tristate_jjy01  ( int unit, struct peer *peer )
1063 {
1064
1065         struct refclockproc *pp;
1066
1067         pp = peer->procptr;
1068
1069         /*
1070          * Send "date<CR><LF>" command
1071          */
1072
1073 #ifdef DEBUG
1074         if ( debug ) {
1075                 printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
1076         }
1077 #endif
1078
1079         if ( write ( pp->io.fd, "date\r\n",6 ) != 6  ) {
1080                 refclock_report ( peer, CEVNT_FAULT ) ;
1081         }
1082
1083 }
1084
1085 /**************************************************************************************************/
1086
1087 static void
1088 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
1089 {
1090
1091         struct refclockproc *pp;
1092
1093         pp = peer->procptr;
1094
1095         /*
1096          * Send "<ENQ>1J<ETX>" command
1097          */
1098
1099 #ifdef DEBUG
1100         if ( debug ) {
1101                 printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1102         }
1103 #endif
1104
1105         if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4  ) {
1106                 refclock_report ( peer, CEVNT_FAULT ) ;
1107         }
1108
1109 }
1110
1111 /**************************************************************************************************/
1112
1113 static void
1114 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
1115 {
1116
1117         struct jjyunit      *up;
1118         struct refclockproc *pp;
1119
1120         char    sCmd[2] ;
1121
1122         pp = peer->procptr;
1123         up = (struct jjyunit *) pp->unitptr ;
1124
1125         /*
1126          * Send "T" or "C" command
1127          */
1128
1129         switch ( up->operationmode ) {
1130         case 1 : sCmd[0] = 'T' ; break ;
1131         case 2 : sCmd[0] = 'C' ; break ;
1132         }
1133         sCmd[1] = 0 ;
1134
1135 #ifdef DEBUG
1136         if ( debug ) {
1137                 printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
1138         }
1139 #endif
1140
1141         if ( write ( pp->io.fd, sCmd, 1 ) != 1  ) {
1142                 refclock_report ( peer, CEVNT_FAULT ) ;
1143         }
1144
1145 }
1146
1147 /**************************************************************************************************/
1148
1149 static void
1150 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
1151 {
1152
1153     /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1154
1155 }
1156
1157 #else
1158 int refclock_jjy_bs ;
1159 #endif /* REFCLOCK */