2 * refclock_jjy - clock driver for JJY receivers
5 /**********************************************************************/
7 /* Copyright (C) 2001, Takao Abe. All rights reserved. */
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: */
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. */
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. */
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. */
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. */
41 /**********************************************************************/
43 /* Author Takao Abe */
44 /* Email abetakao@bea.hi-ho.ne.jp */
45 /* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */
47 /**********************************************************************/
52 /* [New] Support the Tristate Ltd. JJY receiver */
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 */
59 /* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */
61 /**********************************************************************/
67 #if defined(REFCLOCK) && defined(CLOCK_JJY)
78 #include "ntp_refclock.h"
79 #include "ntp_calendar.h"
80 #include "ntp_stdlib.h"
82 /**********************************************************************/
84 /* The Tristate Ltd. JJY receiver JJY01 */
86 /* Command Response Remarks */
87 /* ------------ ---------------------- --------------------- */
88 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */
89 /* time<CR><LF> HH:MM:SS<CR><LF> */
90 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
92 /* During synchronization after a receiver is turned on, */
93 /* It replies the past time from 2000/01/01 00:00:00. */
94 /* The function "refclock_process" checks the time and tells */
95 /* as an insanity time. */
97 /**********************************************************************/
99 /* The C-DEX Co. Ltd. JJY receiver JST2000 */
101 /* Command Response Remarks */
102 /* ------------ ---------------------- --------------------- */
103 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */
105 /**********************************************************************/
108 * Interface definitions
110 #define DEVICE "/dev/jjy%d" /* device name and unit */
111 #define SPEED232 B9600 /* uart speed (9600 baud) */
112 #define REFID "JJY" /* reference ID */
113 #define DESCRIPTION "JJY Receiver"
114 #define PRECISION (-3) /* precision assumed (about 100 ms) */
117 * JJY unit control structure
120 char unittype ; /* UNITTYPE_XXXXXXXXXX */
122 short linediscipline ; /* LDISC_CLK or LDISC_RAW */
125 int year, month, day, hour, minute, second, msecond ;
127 #define MAX_LINECOUNT 8
128 #define MAX_RAWBUF 64
130 int charexpect [ MAX_LINECOUNT ] ;
132 char rawbuf [ MAX_RAWBUF ] ;
135 #define UNITTYPE_TRISTATE_JJY01 1
136 #define UNITTYPE_CDEX_JST2000 2
139 * Function prototypes
141 static int jjy_start P((int, struct peer *));
142 static void jjy_shutdown P((int, struct peer *));
143 static void jjy_poll P((int, struct peer *));
144 static void jjy_poll_tristate_jjy01 P((int, struct peer *));
145 static void jjy_poll_cdex_jst2000 P((int, struct peer *));
146 static void jjy_receive P((struct recvbuf *));
147 static int jjy_receive_tristate_jjy01 P((struct recvbuf *));
148 static int jjy_receive_cdex_jst2000 P((struct recvbuf *));
153 struct refclock refclock_jjy = {
154 jjy_start, /* start up driver */
155 jjy_shutdown, /* shutdown driver */
156 jjy_poll, /* transmit poll message */
157 noentry, /* not used */
158 noentry, /* not used */
159 noentry, /* not used */
160 NOFLAGS /* not used */
164 * Start up driver return code
166 #define RC_START_SUCCESS 1
167 #define RC_START_ERROR 0
170 * Local constants definition
173 #define MAX_LOGTEXT 64
176 /**************************************************************************************************/
177 /* jjy_start - open the devices and initialize data for processing */
178 /**************************************************************************************************/
180 jjy_start ( int unit, struct peer *peer )
184 struct refclockproc *pp ;
191 printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ;
192 printf ( DEVICE, unit ) ;
199 if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) {
200 return RC_START_ERROR ;
202 sprintf ( pDeviceName, DEVICE, unit ) ;
205 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
207 switch ( peer->ttl ) {
209 case 1 : iDiscipline = LDISC_CLK ; break ;
210 case 2 : iDiscipline = LDISC_RAW ; break ;
212 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
213 ntoa(&peer->srcadr), peer->ttl ) ;
214 free ( (void*) pDeviceName ) ;
215 return RC_START_ERROR ;
218 if ( ! ( fd = refclock_open ( pDeviceName, SPEED232, iDiscipline ) ) ) {
219 free ( (void*) pDeviceName ) ;
220 return RC_START_ERROR ;
222 free ( (void*) pDeviceName ) ;
225 * Allocate and initialize unit structure
227 if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) {
229 return RC_START_ERROR ;
232 memset ( (char*)up, 0, sizeof(struct jjyunit) ) ;
233 up->linediscipline = iDiscipline ;
236 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
238 switch ( peer->ttl ) {
241 * The mode 0 is a default clock type at this time.
242 * But this will be change to auto-detect mode in the future.
245 up->unittype = UNITTYPE_TRISTATE_JJY01 ;
248 up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */
249 up->charexpect[1] = 8 ; /* HH:MM:SS<CR><LF> */
252 up->unittype = UNITTYPE_CDEX_JST2000 ;
254 up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
257 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
258 ntoa(&peer->srcadr), peer->ttl ) ;
260 free ( (void*) up ) ;
261 return RC_START_ERROR ;
265 pp->unitptr = (caddr_t) up ;
266 pp->io.clock_recv = jjy_receive ;
267 pp->io.srcclock = (caddr_t) peer ;
270 if ( ! io_addclock(&pp->io) ) {
272 free ( (void*) up ) ;
273 return RC_START_ERROR ;
277 * Initialize miscellaneous variables
279 peer->precision = PRECISION ;
281 pp->clockdesc = DESCRIPTION ;
282 memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
284 return RC_START_SUCCESS ;
289 /**************************************************************************************************/
290 /* jjy_shutdown - shutdown the clock */
291 /**************************************************************************************************/
293 jjy_shutdown ( int unit, struct peer *peer )
297 struct refclockproc *pp;
300 up = (struct jjyunit *) pp->unitptr ;
301 io_closeclock ( &pp->io ) ;
302 free ( (void*) up ) ;
307 /**************************************************************************************************/
308 /* jjy_receive - receive data from the serial interface */
309 /**************************************************************************************************/
311 jjy_receive ( struct recvbuf *rbufp )
315 struct refclockproc *pp ;
318 l_fp tRecvTimestamp; /* arrival timestamp */
320 char sLogText [ MAX_LOGTEXT ] ;
324 * Initialize pointers and read the timecode and timestamp
326 peer = (struct peer *) rbufp->recv_srcclock ;
328 up = (struct jjyunit *) pp->unitptr ;
331 * Get next input line
333 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
335 if ( up->linediscipline == LDISC_RAW ) {
337 * The reply with <STX> and <ETX> may give a blank line
339 if ( pp->lencode == 0 && up->charcount == 0 ) return ;
341 * Copy received charaters to temporary buffer
343 for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) {
344 up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
346 while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
347 for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ;
351 for ( i = 0 ; i < up->charcount ; i ++ ) {
352 if ( up->rawbuf[i] < ' ' ) {
357 if ( pp->lencode > 0 && up->linecount < up->lineexpect ) {
358 if ( bCntrlChar == 0 && up->charcount < up->charexpect[up->linecount] ) return ;
360 up->rawbuf[up->charcount] = 0 ;
363 * The reply with <CR><LF> gives a blank line
365 if ( pp->lencode == 0 ) return ;
368 * We get down to business
371 pp->lastrec = tRecvTimestamp ;
375 if ( up->lineerror != 0 ) return ;
377 switch ( up->unittype ) {
379 case UNITTYPE_TRISTATE_JJY01 :
380 rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
383 case UNITTYPE_CDEX_JST2000 :
384 rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
393 if ( up->linediscipline == LDISC_RAW ) {
394 if ( up->linecount <= up->lineexpect && up->charcount > up->charexpect[up->linecount-1] ) {
395 for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) {
396 up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
398 up->charcount -= up->charexpect[up->linecount-1] ;
404 if ( rc == 0 ) return ;
406 if ( up->lineerror != 0 ) {
407 refclock_report ( peer, CEVNT_BADREPLY ) ;
408 strcpy ( sLogText, "BAD REPLY [" ) ;
409 if ( up->linediscipline == LDISC_RAW ) {
410 strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
412 strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ;
414 sLogText[MAX_LOGTEXT-1] = 0 ;
415 if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ;
416 record_clock_stats ( &peer->srcadr, sLogText ) ;
420 pp->year = up->year ;
421 pp->day = ymd2yd ( up->year, up->month, up->day ) ;
422 pp->hour = up->hour ;
423 pp->minute = up->minute ;
424 pp->second = up->second ;
425 pp->nsec = up->msecond * 1000000;
431 if ( pp->hour < 0 ) {
436 pp->day = ymd2yd ( pp->year, 12, 31 ) ;
441 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d JST ",
442 up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
443 printf ( "( %04d/%03d %02d:%02d:%02d UTC )\n",
444 pp->year, pp->day, pp->hour, pp->minute, pp->second ) ;
449 * Process the new sample in the median filter and determine the
450 * timecode timestamp.
452 if ( ! refclock_process ( pp ) ) {
453 refclock_report(peer, CEVNT_BADTIME);
454 sprintf ( sLogText, "BAD TIME %04d/%02d/%02d %02d:%02d:%02d JST",
455 up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
456 record_clock_stats ( &peer->srcadr, sLogText ) ;
460 sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d JST",
461 up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
462 pp->lastref = pp->lastrec;
463 refclock_receive(peer);
464 record_clock_stats ( &peer->srcadr, sLogText ) ;
467 /**************************************************************************************************/
470 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
474 struct refclockproc *pp ;
482 * Initialize pointers and read the timecode and timestamp
484 peer = (struct peer *) rbufp->recv_srcclock ;
486 up = (struct jjyunit *) pp->unitptr ;
488 if ( up->linediscipline == LDISC_RAW ) {
490 iLen = up->charcount ;
492 pBuf = pp->a_lastcode ;
496 switch ( up->linecount ) {
498 case 1 : /* YYYY/MM/DD */
504 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
505 if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
511 case 2 : /* HH:MM:SS */
517 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
518 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
523 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
525 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
526 * But the JJY receiver replies a date and time separately.
527 * Just after midnight transtions, we ignore this time.
533 default : /* Unexpected reply */
544 /**************************************************************************************************/
547 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
551 struct refclockproc *pp ;
559 * Initialize pointers and read the timecode and timestamp
561 peer = (struct peer *) rbufp->recv_srcclock ;
563 up = (struct jjyunit *) pp->unitptr ;
565 if ( up->linediscipline == LDISC_RAW ) {
567 iLen = up->charcount ;
569 pBuf = pp->a_lastcode ;
573 switch ( up->linecount ) {
575 case 1 : /* JYYMMDD HHMMSSS */
581 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
582 &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
583 if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
584 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
592 default : /* Unexpected reply */
603 /**************************************************************************************************/
604 /* jjy_poll - called by the transmit procedure */
605 /**************************************************************************************************/
607 jjy_poll ( int unit, struct peer *peer )
611 struct refclockproc *pp;
614 up = (struct jjyunit *) pp->unitptr ;
616 if ( pp->polls > 0 && up->linecount == 0 ) {
618 * No reply for last command
620 refclock_report ( peer, CEVNT_TIMEOUT ) ;
625 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
635 switch ( up->unittype ) {
637 case UNITTYPE_TRISTATE_JJY01 :
638 jjy_poll_tristate_jjy01 ( unit, peer ) ;
641 case UNITTYPE_CDEX_JST2000 :
642 jjy_poll_cdex_jst2000 ( unit, peer ) ;
652 /**************************************************************************************************/
655 jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
659 struct refclockproc *pp;
662 up = (struct jjyunit *) pp->unitptr ;
665 * Send "date<CR><LF>" command
668 if ( write ( pp->io.fd, "date\r\n",6 ) != 6 ) {
669 refclock_report ( peer, CEVNT_FAULT ) ;
673 * Send "stim<CR><LF>" or "time<CR><LF>" command
676 if ( up->version >= 100 ) {
677 if ( write ( pp->io.fd, "stim\r\n",6 ) != 6 ) {
678 refclock_report ( peer, CEVNT_FAULT ) ;
681 if ( write ( pp->io.fd, "time\r\n",6 ) != 6 ) {
682 refclock_report ( peer, CEVNT_FAULT ) ;
688 /**************************************************************************************************/
691 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
694 struct refclockproc *pp;
699 * Send "<ENQ>1J<ETX>" command
702 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
703 refclock_report ( peer, CEVNT_FAULT ) ;
709 int refclock_jjy_bs ;
710 #endif /* REFCLOCK */