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