1 /* $NetBSD: refclock_jjy.c,v 1.4 2007/01/06 19:45:23 kardel Exp $ */
4 * refclock_jjy - clock driver for JJY receivers
7 /**********************************************************************/
9 /* Copyright (C) 2001-2004, Takao Abe. All rights reserved. */
11 /* Permission to use, copy, modify, and distribute this software */
12 /* and its documentation for any purpose is hereby granted */
13 /* without fee, provided that the following conditions are met: */
15 /* One retains the entire copyright notice properly, and both the */
16 /* copyright notice and this license. in the documentation and/or */
17 /* other materials provided with the distribution. */
19 /* This software and the name of the author must not be used to */
20 /* endorse or promote products derived from this software without */
21 /* prior written permission. */
23 /* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */
24 /* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */
25 /* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */
26 /* PARTICULAR PURPOSE. */
27 /* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */
28 /* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
29 /* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
30 /* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */
31 /* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */
32 /* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */
33 /* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */
34 /* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* This driver is developed in my private time, and is opened as */
37 /* voluntary contributions for the NTP. */
38 /* The manufacturer of the JJY receiver has not participated in */
39 /* a development of this driver. */
40 /* The manufacturer does not warrant anything about this driver, */
41 /* and is not liable for anything about this driver. */
43 /**********************************************************************/
45 /* Author Takao Abe */
46 /* Email abetakao@bea.hi-ho.ne.jp */
47 /* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */
49 /**********************************************************************/
54 /* [New] Support the Tristate Ltd. JJY receiver */
57 /* [Change] Log to clockstats even if bad reply */
58 /* [Fix] PRECISION = (-3) (about 100 ms) */
59 /* [Add] Support the C-DEX Co.Ltd. JJY receiver */
62 /* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */
65 /* [Fix] Portability for FreeBSD ( patched by the user ) */
68 /* [Change] Command send timing for the Tristate Ltd. JJY receiver */
69 /* JJY-01 ( Firmware version 2.01 ) */
70 /* Thanks to Andy Taki for testing under FreeBSD */
73 /* [Add] Support the Echo Keisokuki LT-2000 receiver */
76 /* [Fix] C-DEX JST2000 */
77 /* Thanks to Hideo Kuramatsu for the patch */
80 /* [Add] Support the CITIZEN T.I.C JJY-200 receiver */
82 /**********************************************************************/
88 #if defined(REFCLOCK) && defined(CLOCK_JJY)
99 #include "ntp_refclock.h"
100 #include "ntp_calendar.h"
101 #include "ntp_stdlib.h"
103 /**********************************************************************/
105 /* The Tristate Ltd. JJY receiver JJY01 */
107 /* Command Response Remarks */
108 /* ------------ ---------------------- --------------------- */
109 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */
110 /* time<CR><LF> HH:MM:SS<CR><LF> */
111 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
113 /* During synchronization after a receiver is turned on, */
114 /* It replies the past time from 2000/01/01 00:00:00. */
115 /* The function "refclock_process" checks the time and tells */
116 /* as an insanity time. */
118 /**********************************************************************/
120 /* The C-DEX Co. Ltd. JJY receiver JST2000 */
122 /* Command Response Remarks */
123 /* ------------ ---------------------- --------------------- */
124 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */
126 /**********************************************************************/
128 /* The Echo Keisokuki Co. Ltd. JJY receiver LT2000 */
130 /* Command Response Remarks */
131 /* ------------ ---------------------- --------------------- */
132 /* # Mode 1 (Request&Send) */
133 /* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
134 /* C Mode 2 (Continuous) */
135 /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
136 /* <SUB> Second signal */
138 /**********************************************************************/
140 /* The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 */
142 /* Command Response Remarks */
143 /* ------------ ---------------------- --------------------- */
144 /* 'XX YY/MM/DD W HH:MM:SS<CR> */
146 /* W: 0(Monday)-6(Sunday) */
148 /**********************************************************************/
151 * Interface definitions
153 #define DEVICE "/dev/jjy%d" /* device name and unit */
154 #define SPEED232 B9600 /* uart speed (9600 baud) */
155 #define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
156 #define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
157 #define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
158 #define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
159 #define REFID "JJY" /* reference ID */
160 #define DESCRIPTION "JJY Receiver"
161 #define PRECISION (-3) /* precision assumed (about 100 ms) */
164 * JJY unit control structure
167 char unittype
; /* UNITTYPE_XXXXXXXXXX */
168 short operationmode
; /* Echo Keisokuki LT-2000 : 1 or 2 */
170 short linediscipline
; /* LDISC_CLK or LDISC_RAW */
171 char bPollFlag
; /* Set by jjy_pool and Reset by jjy_receive */
174 int year
, month
, day
, hour
, minute
, second
, msecond
;
176 #define MAX_LINECOUNT 8
177 #define MAX_RAWBUF 64
179 int charexpect
[ MAX_LINECOUNT
] ;
181 char rawbuf
[ MAX_RAWBUF
] ;
184 #define UNITTYPE_TRISTATE_JJY01 1
185 #define UNITTYPE_CDEX_JST2000 2
186 #define UNITTYPE_ECHOKEISOKUKI_LT2000 3
187 #define UNITTYPE_CITIZENTIC_JJY200 4
190 * Function prototypes
192 static int jjy_start
P((int, struct peer
*));
193 static void jjy_shutdown
P((int, struct peer
*));
194 static void jjy_poll
P((int, struct peer
*));
195 static void jjy_poll_tristate_jjy01
P((int, struct peer
*));
196 static void jjy_poll_cdex_jst2000
P((int, struct peer
*));
197 static void jjy_poll_echokeisokuki_lt2000
P((int, struct peer
*));
198 static void jjy_poll_citizentic_jjy200
P((int, struct peer
*));
199 static void jjy_receive
P((struct recvbuf
*));
200 static int jjy_receive_tristate_jjy01
P((struct recvbuf
*));
201 static int jjy_receive_cdex_jst2000
P((struct recvbuf
*));
202 static int jjy_receive_echokeisokuki_lt2000
P((struct recvbuf
*));
203 static int jjy_receive_citizentic_jjy200
P((struct recvbuf
*));
208 struct refclock refclock_jjy
= {
209 jjy_start
, /* start up driver */
210 jjy_shutdown
, /* shutdown driver */
211 jjy_poll
, /* transmit poll message */
212 noentry
, /* not used */
213 noentry
, /* not used */
214 noentry
, /* not used */
215 NOFLAGS
/* not used */
219 * Start up driver return code
221 #define RC_START_SUCCESS 1
222 #define RC_START_ERROR 0
225 * Local constants definition
228 #define MAX_LOGTEXT 64
231 /**************************************************************************************************/
232 /* jjy_start - open the devices and initialize data for processing */
233 /**************************************************************************************************/
235 jjy_start ( int unit
, struct peer
*peer
)
239 struct refclockproc
*pp
;
247 printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer
->srcadr
), peer
->ttl
) ;
248 printf ( DEVICE
, unit
) ;
255 if ( ! ( pDeviceName
= (char*) emalloc ( strlen(DEVICE
) + 10 ) ) ) {
256 return RC_START_ERROR
;
258 sprintf ( pDeviceName
, DEVICE
, unit
) ;
261 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
263 switch ( peer
->ttl
) {
266 iDiscipline
= LDISC_CLK
;
267 iSpeed232
= SPEED232_TRISTATE_JJY01
;
270 iDiscipline
= LDISC_RAW
;
271 iSpeed232
= SPEED232_CDEX_JST2000
;
274 iDiscipline
= LDISC_CLK
;
275 iSpeed232
= SPEED232_ECHOKEISOKUKI_LT2000
;
278 iDiscipline
= LDISC_CLK
;
279 iSpeed232
= SPEED232_CITIZENTIC_JJY200
;
282 msyslog ( LOG_ERR
, "JJY receiver [ %s mode %d ] : Unsupported mode",
283 ntoa(&peer
->srcadr
), peer
->ttl
) ;
284 free ( (void*) pDeviceName
) ;
285 return RC_START_ERROR
;
288 if ( ! ( fd
= refclock_open ( pDeviceName
, iSpeed232
, iDiscipline
) ) ) {
289 free ( (void*) pDeviceName
) ;
290 return RC_START_ERROR
;
292 free ( (void*) pDeviceName
) ;
295 * Allocate and initialize unit structure
297 if ( ! ( up
= (struct jjyunit
*) emalloc (sizeof(struct jjyunit
)) ) ) {
299 return RC_START_ERROR
;
302 memset ( (char*)up
, 0, sizeof(struct jjyunit
) ) ;
303 up
->linediscipline
= iDiscipline
;
306 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
308 switch ( peer
->ttl
) {
311 * The mode 0 is a default clock type at this time.
312 * But this will be change to auto-detect mode in the future.
315 up
->unittype
= UNITTYPE_TRISTATE_JJY01
;
318 up
->charexpect
[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
319 up
->charexpect
[1] = 8 ; /* HH:MM:SS<CR><LF> */
322 up
->unittype
= UNITTYPE_CDEX_JST2000
;
324 up
->charexpect
[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
327 up
->unittype
= UNITTYPE_ECHOKEISOKUKI_LT2000
;
328 up
->operationmode
= 2 ; /* Mode 2 : Continuous mode */
330 switch ( up
->operationmode
) {
332 up
->charexpect
[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
335 up
->charexpect
[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
340 up
->unittype
= UNITTYPE_CITIZENTIC_JJY200
;
342 up
->charexpect
[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
345 msyslog ( LOG_ERR
, "JJY receiver [ %s mode %d ] : Unsupported mode",
346 ntoa(&peer
->srcadr
), peer
->ttl
) ;
348 free ( (void*) up
) ;
349 return RC_START_ERROR
;
353 pp
->unitptr
= (caddr_t
) up
;
354 pp
->io
.clock_recv
= jjy_receive
;
355 pp
->io
.srcclock
= (caddr_t
) peer
;
358 if ( ! io_addclock(&pp
->io
) ) {
360 free ( (void*) up
) ;
361 return RC_START_ERROR
;
365 * Initialize miscellaneous variables
367 peer
->precision
= PRECISION
;
369 pp
->clockdesc
= DESCRIPTION
;
370 memcpy ( (char*)&pp
->refid
, REFID
, strlen(REFID
) ) ;
372 return RC_START_SUCCESS
;
377 /**************************************************************************************************/
378 /* jjy_shutdown - shutdown the clock */
379 /**************************************************************************************************/
381 jjy_shutdown ( int unit
, struct peer
*peer
)
385 struct refclockproc
*pp
;
388 up
= (struct jjyunit
*) pp
->unitptr
;
389 io_closeclock ( &pp
->io
) ;
390 free ( (void*) up
) ;
395 /**************************************************************************************************/
396 /* jjy_receive - receive data from the serial interface */
397 /**************************************************************************************************/
399 jjy_receive ( struct recvbuf
*rbufp
)
403 struct refclockproc
*pp
;
406 l_fp tRecvTimestamp
; /* arrival timestamp */
408 char sLogText
[ MAX_LOGTEXT
] ;
412 * Initialize pointers and read the timecode and timestamp
414 peer
= (struct peer
*) rbufp
->recv_srcclock
;
416 up
= (struct jjyunit
*) pp
->unitptr
;
419 * Get next input line
421 pp
->lencode
= refclock_gtlin ( rbufp
, pp
->a_lastcode
, BMAX
, &tRecvTimestamp
) ;
423 if ( up
->linediscipline
== LDISC_RAW
) {
425 * The reply with <STX> and <ETX> may give a blank line
427 if ( pp
->lencode
== 0 && up
->charcount
== 0 ) return ;
429 * Copy received charaters to temporary buffer
431 for ( i
= 0 ; i
< pp
->lencode
&& up
->charcount
< MAX_RAWBUF
- 2 ; i
++ , up
->charcount
++ ) {
432 up
->rawbuf
[up
->charcount
] = pp
->a_lastcode
[i
] ;
434 while ( up
->charcount
> 0 && up
->rawbuf
[0] < ' ' ) {
435 for ( i
= 0 ; i
< up
->charcount
- 1 ; i
++ ) up
->rawbuf
[i
] = up
->rawbuf
[i
+1] ;
439 for ( i
= 0 ; i
< up
->charcount
; i
++ ) {
440 if ( up
->rawbuf
[i
] < ' ' ) {
445 if ( pp
->lencode
> 0 && up
->linecount
< up
->lineexpect
) {
446 if ( bCntrlChar
== 0 && up
->charcount
< up
->charexpect
[up
->linecount
] ) return ;
448 up
->rawbuf
[up
->charcount
] = 0 ;
451 * The reply with <CR><LF> gives a blank line
453 if ( pp
->lencode
== 0 ) return ;
456 * We get down to business
459 pp
->lastrec
= tRecvTimestamp
;
463 if ( up
->lineerror
!= 0 ) return ;
465 switch ( up
->unittype
) {
467 case UNITTYPE_TRISTATE_JJY01
:
468 rc
= jjy_receive_tristate_jjy01 ( rbufp
) ;
471 case UNITTYPE_CDEX_JST2000
:
472 rc
= jjy_receive_cdex_jst2000 ( rbufp
) ;
475 case UNITTYPE_ECHOKEISOKUKI_LT2000
:
476 rc
= jjy_receive_echokeisokuki_lt2000 ( rbufp
) ;
479 case UNITTYPE_CITIZENTIC_JJY200
:
480 rc
= jjy_receive_citizentic_jjy200 ( rbufp
) ;
489 if ( up
->linediscipline
== LDISC_RAW
) {
490 if ( up
->linecount
<= up
->lineexpect
&& up
->charcount
> up
->charexpect
[up
->linecount
-1] ) {
491 for ( i
= 0 ; i
< up
->charcount
- up
->charexpect
[up
->linecount
-1] ; i
++ ) {
492 up
->rawbuf
[i
] = up
->rawbuf
[i
+up
->charexpect
[up
->linecount
-1]] ;
494 up
->charcount
-= up
->charexpect
[up
->linecount
-1] ;
500 if ( rc
== 0 ) return ;
504 if ( up
->lineerror
!= 0 ) {
505 refclock_report ( peer
, CEVNT_BADREPLY
) ;
506 strcpy ( sLogText
, "BAD REPLY [" ) ;
507 if ( up
->linediscipline
== LDISC_RAW
) {
508 strncat ( sLogText
, up
->rawbuf
, MAX_LOGTEXT
- strlen ( sLogText
) - 1 ) ;
510 strncat ( sLogText
, pp
->a_lastcode
, MAX_LOGTEXT
- strlen ( sLogText
) - 1 ) ;
512 sLogText
[MAX_LOGTEXT
-1] = 0 ;
513 if ( strlen ( sLogText
) < MAX_LOGTEXT
- 2 ) strcat ( sLogText
, "]" ) ;
514 record_clock_stats ( &peer
->srcadr
, sLogText
) ;
518 pp
->year
= up
->year
;
519 pp
->day
= ymd2yd ( up
->year
, up
->month
, up
->day
) ;
520 pp
->hour
= up
->hour
;
521 pp
->minute
= up
->minute
;
522 pp
->second
= up
->second
;
523 pp
->nsec
= up
->msecond
* 1000000;
529 if ( pp
->hour
< 0 ) {
534 pp
->day
= ymd2yd ( pp
->year
, 12, 31 ) ;
539 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST ",
540 up
->year
, up
->month
, up
->day
, up
->hour
, up
->minute
, up
->second
, up
->msecond
/100 ) ;
541 printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
542 pp
->year
, pp
->day
, pp
->hour
, pp
->minute
, pp
->second
, (int)(pp
->nsec
/100000000) ) ;
547 * Process the new sample in the median filter and determine the
548 * timecode timestamp.
551 sprintf ( sLogText
, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
552 up
->year
, up
->month
, up
->day
, up
->hour
, up
->minute
, up
->second
, up
->msecond
/100 ) ;
553 record_clock_stats ( &peer
->srcadr
, sLogText
) ;
555 if ( ! refclock_process ( pp
) ) {
556 refclock_report(peer
, CEVNT_BADTIME
);
560 pp
->lastref
= pp
->lastrec
;
561 refclock_receive(peer
);
565 /**************************************************************************************************/
568 jjy_receive_tristate_jjy01 ( struct recvbuf
*rbufp
)
571 static char *sFunctionName
= "jjy_receive_tristate_jjy01" ;
574 struct refclockproc
*pp
;
582 * Initialize pointers and read the timecode and timestamp
584 peer
= (struct peer
*) rbufp
->recv_srcclock
;
586 up
= (struct jjyunit
*) pp
->unitptr
;
588 if ( up
->linediscipline
== LDISC_RAW
) {
590 iLen
= up
->charcount
;
592 pBuf
= pp
->a_lastcode
;
596 switch ( up
->linecount
) {
598 case 1 : /* YYYY/MM/DD WWW */
603 printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName
, up
->linecount
, iLen
) ;
609 rc
= sscanf ( pBuf
, "%4d/%2d/%2d", &up
->year
, &up
->month
, &up
->day
) ;
610 if ( rc
!= 3 || up
->year
< 2000 || up
->month
< 1 || up
->month
> 12 || up
->day
< 1 || up
->day
> 31 ) {
613 printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", sFunctionName
, up
->linecount
) ;
620 /*** Start of modification on 2004/10/31 */
622 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
623 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
624 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
625 * so this driver issues the second command "stim" after the reply of the first command "date".
629 * Send "stim<CR><LF>" or "time<CR><LF>" command
633 if ( up
->version
>= 100 ) {
636 printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName
) ;
639 if ( write ( pp
->io
.fd
, "stim\r\n",6 ) != 6 ) {
640 refclock_report ( peer
, CEVNT_FAULT
) ;
645 printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName
) ;
648 if ( write ( pp
->io
.fd
, "time\r\n",6 ) != 6 ) {
649 refclock_report ( peer
, CEVNT_FAULT
) ;
652 /*** End of modification ***/
656 case 2 : /* HH:MM:SS */
661 printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName
, up
->linecount
, iLen
) ;
667 rc
= sscanf ( pBuf
, "%2d:%2d:%2d", &up
->hour
, &up
->minute
, &up
->second
) ;
668 if ( rc
!= 3 || up
->hour
> 23 || up
->minute
> 59 || up
->second
> 60 ) {
671 printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", sFunctionName
, up
->linecount
) ;
678 if ( up
->hour
== 0 && up
->minute
== 0 && up
->second
<= 2 ) {
680 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
681 * But the JJY receiver replies a date and time separately.
682 * Just after midnight transitions, we ignore this time.
688 default : /* Unexpected reply */
699 /**************************************************************************************************/
702 jjy_receive_cdex_jst2000 ( struct recvbuf
*rbufp
)
705 static char *sFunctionName
= "jjy_receive_cdex_jst2000" ;
708 struct refclockproc
*pp
;
716 * Initialize pointers and read the timecode and timestamp
718 peer
= (struct peer
*) rbufp
->recv_srcclock
;
720 up
= (struct jjyunit
*) pp
->unitptr
;
722 if ( up
->linediscipline
== LDISC_RAW
) {
724 iLen
= up
->charcount
;
726 pBuf
= pp
->a_lastcode
;
730 switch ( up
->linecount
) {
732 case 1 : /* JYYMMDD HHMMSSS */
737 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName
, iLen
) ;
743 rc
= sscanf ( pBuf
, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
744 &up
->year
, &up
->month
, &up
->day
, &up
->hour
, &up
->minute
, &up
->second
, &up
->msecond
) ;
745 if ( rc
!= 7 || up
->month
< 1 || up
->month
> 12 || up
->day
< 1 || up
->day
> 31
746 || up
->hour
> 23 || up
->minute
> 59 || up
->second
> 60 ) {
749 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName
,
750 rc
, up
->year
, up
->month
, up
->day
, up
->hour
, up
->minute
, up
->second
, up
->msecond
) ;
760 default : /* Unexpected reply */
771 /**************************************************************************************************/
774 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf
*rbufp
)
777 static char *sFunctionName
= "jjy_receive_echokeisokuki_lt2000" ;
780 struct refclockproc
*pp
;
786 int i
, ibcc
, ibcc1
, ibcc2
;
789 * Initialize pointers and read the timecode and timestamp
791 peer
= (struct peer
*) rbufp
->recv_srcclock
;
793 up
= (struct jjyunit
*) pp
->unitptr
;
795 if ( up
->linediscipline
== LDISC_RAW
) {
797 iLen
= up
->charcount
;
799 pBuf
= pp
->a_lastcode
;
803 switch ( up
->linecount
) {
805 case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
807 if ( ( up
->operationmode
== 1 && iLen
!= 15 ) || ( up
->operationmode
== 2 && iLen
!= 17 ) ) {
810 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName
, iLen
) ;
813 if ( up
->operationmode
== 1 ) {
816 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName
) ;
819 if ( write ( pp
->io
.fd
, "#",1 ) != 1 ) {
820 refclock_report ( peer
, CEVNT_FAULT
) ;
827 if ( up
->operationmode
== 1 ) {
829 for ( i
= ibcc
= 0 ; i
< 13 ; i
++ ) ibcc
^= pBuf
[i
] ;
830 ibcc1
= 0x30 | ( ( ibcc
>> 4 ) & 0xF ) ;
831 ibcc2
= 0x30 | ( ( ibcc
) & 0xF ) ;
832 if ( pBuf
[13] != ibcc1
|| pBuf
[14] != ibcc2
) {
835 printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName
, pBuf
[13]&0xFF, pBuf
[14]&0xFF, ibcc1
, ibcc2
) ;
844 rc
= sscanf ( pBuf
, "%2d%2d%2d%*1d%2d%2d%2d",
845 &up
->year
, &up
->month
, &up
->day
, &up
->hour
, &up
->minute
, &up
->second
) ;
846 if ( rc
!= 6 || up
->month
< 1 || up
->month
> 12 || up
->day
< 1 || up
->day
> 31
847 || up
->hour
> 23 || up
->minute
> 59 || up
->second
> 60 ) {
850 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName
,
851 rc
, up
->year
, up
->month
, up
->day
, up
->hour
, up
->minute
, up
->second
) ;
860 if ( up
->operationmode
== 2 ) {
862 /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
865 if ( pp
->second
< 0 ) {
868 if ( pp
->minute
< 0 ) {
871 if ( pp
->hour
< 0 ) {
876 pp
->day
= ymd2yd ( pp
->year
, 12, 31 ) ;
882 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
885 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName
) ;
888 if ( write ( pp
->io
.fd
, "#",1 ) != 1 ) {
889 refclock_report ( peer
, CEVNT_FAULT
) ;
896 default : /* Unexpected reply */
900 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName
) ;
903 if ( write ( pp
->io
.fd
, "#",1 ) != 1 ) {
904 refclock_report ( peer
, CEVNT_FAULT
) ;
916 /**************************************************************************************************/
919 jjy_receive_citizentic_jjy200 ( struct recvbuf
*rbufp
)
922 static char *sFunctionName
= "jjy_receive_citizentic_jjy200" ;
925 struct refclockproc
*pp
;
931 char cApostrophe
, sStatus
[3] ;
935 * Initialize pointers and read the timecode and timestamp
937 peer
= (struct peer
*) rbufp
->recv_srcclock
;
939 up
= (struct jjyunit
*) pp
->unitptr
;
941 if ( up
->linediscipline
== LDISC_RAW
) {
943 iLen
= up
->charcount
;
945 pBuf
= pp
->a_lastcode
;
950 * JJY-200 sends a timestamp every second.
951 * So, a timestamp is ignored unless it is right after polled.
953 if ( ! up
->bPollFlag
) return 0 ;
955 switch ( up
->linecount
) {
957 case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
962 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName
, iLen
) ;
969 rc
= sscanf ( pBuf
, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
970 &cApostrophe
, sStatus
,
971 &up
->year
, &up
->month
, &up
->day
, &iWeekday
, &up
->hour
, &up
->minute
, &up
->second
) ;
973 if ( rc
!= 9 || cApostrophe
!= '\'' || strcmp( sStatus
, "OK" ) != 0
974 || up
->month
< 1 || up
->month
> 12 || up
->day
< 1 || up
->day
> 31
976 || up
->hour
> 23 || up
->minute
> 59 || up
->second
> 60 ) {
979 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", sFunctionName
,
980 rc
, cApostrophe
, sStatus
, up
->year
, up
->month
, up
->day
, iWeekday
, up
->hour
, up
->minute
, up
->second
) ;
992 default : /* Unexpected reply */
1003 /**************************************************************************************************/
1004 /* jjy_poll - called by the transmit procedure */
1005 /**************************************************************************************************/
1007 jjy_poll ( int unit
, struct peer
*peer
)
1011 struct refclockproc
*pp
;
1014 up
= (struct jjyunit
*) pp
->unitptr
;
1016 if ( pp
->polls
> 0 && up
->linecount
== 0 ) {
1018 * No reply for last command
1020 refclock_report ( peer
, CEVNT_TIMEOUT
) ;
1025 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp
->polls
) ;
1036 switch ( up
->unittype
) {
1038 case UNITTYPE_TRISTATE_JJY01
:
1039 jjy_poll_tristate_jjy01 ( unit
, peer
) ;
1042 case UNITTYPE_CDEX_JST2000
:
1043 jjy_poll_cdex_jst2000 ( unit
, peer
) ;
1046 case UNITTYPE_ECHOKEISOKUKI_LT2000
:
1047 jjy_poll_echokeisokuki_lt2000 ( unit
, peer
) ;
1050 case UNITTYPE_CITIZENTIC_JJY200
:
1051 jjy_poll_citizentic_jjy200 ( unit
, peer
) ;
1061 /**************************************************************************************************/
1064 jjy_poll_tristate_jjy01 ( int unit
, struct peer
*peer
)
1067 struct refclockproc
*pp
;
1072 * Send "date<CR><LF>" command
1077 printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
1081 if ( write ( pp
->io
.fd
, "date\r\n",6 ) != 6 ) {
1082 refclock_report ( peer
, CEVNT_FAULT
) ;
1087 /**************************************************************************************************/
1090 jjy_poll_cdex_jst2000 ( int unit
, struct peer
*peer
)
1093 struct refclockproc
*pp
;
1098 * Send "<ENQ>1J<ETX>" command
1103 printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
1107 if ( write ( pp
->io
.fd
, "\0051J\003", 4 ) != 4 ) {
1108 refclock_report ( peer
, CEVNT_FAULT
) ;
1113 /**************************************************************************************************/
1116 jjy_poll_echokeisokuki_lt2000 ( int unit
, struct peer
*peer
)
1120 struct refclockproc
*pp
;
1125 up
= (struct jjyunit
*) pp
->unitptr
;
1128 * Send "T" or "C" command
1131 switch ( up
->operationmode
) {
1132 case 1 : sCmd
[0] = 'T' ; break ;
1133 case 2 : sCmd
[0] = 'C' ; break ;
1139 printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd
) ;
1143 if ( write ( pp
->io
.fd
, sCmd
, 1 ) != 1 ) {
1144 refclock_report ( peer
, CEVNT_FAULT
) ;
1149 /**************************************************************************************************/
1152 jjy_poll_citizentic_jjy200 ( int unit
, struct peer
*peer
)
1155 /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
1160 int refclock_jjy_bs
;
1161 #endif /* REFCLOCK */