summaryrefslogtreecommitdiff
path: root/ntpd/refclock_jjy.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntpd/refclock_jjy.c')
-rw-r--r--ntpd/refclock_jjy.c363
1 files changed, 332 insertions, 31 deletions
diff --git a/ntpd/refclock_jjy.c b/ntpd/refclock_jjy.c
index 2aa9d6a7d8b9c..9d1419a6f6baf 100644
--- a/ntpd/refclock_jjy.c
+++ b/ntpd/refclock_jjy.c
@@ -4,7 +4,7 @@
/**********************************************************************/
/* */
-/* Copyright (C) 2001, Takao Abe. All rights reserved. */
+/* Copyright (C) 2001-2004, Takao Abe. All rights reserved. */
/* */
/* Permission to use, copy, modify, and distribute this software */
/* and its documentation for any purpose is hereby granted */
@@ -55,9 +55,25 @@
/* [Change] Log to clockstats even if bad reply */
/* [Fix] PRECISION = (-3) (about 100 ms) */
/* [Add] Support the C-DEX Co.Ltd. JJY receiver */
+/* */
/* 2001/12/04 */
/* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */
/* */
+/* 2002/07/12 */
+/* [Fix] Portability for FreeBSD ( patched by the user ) */
+/* */
+/* 2004/10/31 */
+/* [Change] Command send timing for the Tristate Ltd. JJY receiver */
+/* JJY-01 ( Firmware version 2.01 ) */
+/* Thanks to Andy Taki for testing under FreeBSD */
+/* */
+/* 2004/11/28 */
+/* [Add] Support the Echo Keisokuki LT-2000 receiver */
+/* */
+/* 2006/11/04 */
+/* [Fix] C-DEX JST2000 */
+/* Thanks to Hideo Kuramatsu for the patch */
+/* */
/**********************************************************************/
#ifdef HAVE_CONFIG_H
@@ -103,6 +119,18 @@
/* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */
/* */
/**********************************************************************/
+/* */
+/* The Echo Keisokuki Co. Ltd. JJY receiver LT2000 */
+/* */
+/* Command Response Remarks */
+/* ------------ ---------------------- --------------------- */
+/* # Mode 1 (Request&Send) */
+/* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
+/* C Mode 2 (Continuous) */
+/* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
+/* <SUB> Second signal */
+/* */
+/**********************************************************************/
/*
* Interface definitions
@@ -117,7 +145,8 @@
* JJY unit control structure
*/
struct jjyunit {
- char unittype ; /* UNITTYPE_XXXXXXXXXX */
+ char unittype ; /* UNITTYPE_XXXXXXXXXX */
+ short operationmode ; /* Echo Keisokuki LT-2000 : 1 or 2 */
short version ;
short linediscipline ; /* LDISC_CLK or LDISC_RAW */
int linecount ;
@@ -134,6 +163,7 @@ struct jjyunit {
#define UNITTYPE_TRISTATE_JJY01 1
#define UNITTYPE_CDEX_JST2000 2
+#define UNITTYPE_ECHOKEISOKUKI_LT2000 3
/*
* Function prototypes
@@ -143,9 +173,11 @@ static void jjy_shutdown P((int, struct peer *));
static void jjy_poll P((int, struct peer *));
static void jjy_poll_tristate_jjy01 P((int, struct peer *));
static void jjy_poll_cdex_jst2000 P((int, struct peer *));
+static void jjy_poll_echokeisokuki_lt2000 P((int, struct peer *));
static void jjy_receive P((struct recvbuf *));
static int jjy_receive_tristate_jjy01 P((struct recvbuf *));
static int jjy_receive_cdex_jst2000 P((struct recvbuf *));
+static int jjy_receive_echokeisokuki_lt2000 P((struct recvbuf *));
/*
* Transfer vector
@@ -208,6 +240,7 @@ jjy_start ( int unit, struct peer *peer )
case 0 :
case 1 : iDiscipline = LDISC_CLK ; break ;
case 2 : iDiscipline = LDISC_RAW ; break ;
+ case 3 : iDiscipline = LDISC_CLK ; break ;
default :
msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
ntoa(&peer->srcadr), peer->ttl ) ;
@@ -253,6 +286,19 @@ jjy_start ( int unit, struct peer *peer )
up->lineexpect = 1 ;
up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */
break ;
+ case 3 :
+ up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
+ up->operationmode = 2 ; /* Mode 2 : Continuous mode */
+ up->lineexpect = 1 ;
+ switch ( up->operationmode ) {
+ case 1 :
+ up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */
+ break ;
+ case 2 :
+ up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */
+ break ;
+ }
+ break ;
default :
msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
ntoa(&peer->srcadr), peer->ttl ) ;
@@ -384,6 +430,10 @@ jjy_receive ( struct recvbuf *rbufp )
rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
break ;
+ case UNITTYPE_ECHOKEISOKUKI_LT2000 :
+ rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
+ break ;
+
default :
rc = 0 ;
break ;
@@ -438,10 +488,10 @@ jjy_receive ( struct recvbuf *rbufp )
}
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d JST ",
- up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
- printf ( "( %04d/%03d %02d:%02d:%02d UTC )\n",
- pp->year, pp->day, pp->hour, pp->minute, pp->second ) ;
+ printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST ",
+ up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
+ printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n",
+ pp->year, pp->day, pp->hour, pp->minute, pp->second, (int)(pp->nsec/100000000) ) ;
}
#endif
@@ -449,19 +499,19 @@ jjy_receive ( struct recvbuf *rbufp )
* Process the new sample in the median filter and determine the
* timecode timestamp.
*/
+
+ sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST",
+ up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ;
+ record_clock_stats ( &peer->srcadr, sLogText ) ;
+
if ( ! refclock_process ( pp ) ) {
refclock_report(peer, CEVNT_BADTIME);
- sprintf ( sLogText, "BAD TIME %04d/%02d/%02d %02d:%02d:%02d JST",
- up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
- record_clock_stats ( &peer->srcadr, sLogText ) ;
return ;
}
- sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d JST",
- up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
pp->lastref = pp->lastrec;
refclock_receive(peer);
- record_clock_stats ( &peer->srcadr, sLogText ) ;
+
}
/**************************************************************************************************/
@@ -470,6 +520,8 @@ static int
jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
{
+ static char *sFunctionName = "jjy_receive_tristate_jjy01" ;
+
struct jjyunit *up ;
struct refclockproc *pp ;
struct peer *peer;
@@ -495,27 +547,82 @@ jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
switch ( up->linecount ) {
- case 1 : /* YYYY/MM/DD */
+ case 1 : /* YYYY/MM/DD WWW */
- if ( iLen < 10 ) {
+ if ( iLen != 14 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
+ }
+#endif
up->lineerror = 1 ;
break ;
}
rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ;
if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
+ }
+#endif
up->lineerror = 1 ;
break ;
}
+
+ /*** Start of modification on 2004/10/31 */
+ /*
+ * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source.
+ * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay.
+ * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously,
+ * so this driver issues the second command "stim" after the reply of the first command "date".
+ */
+
+ /*
+ * Send "stim<CR><LF>" or "time<CR><LF>" command
+ */
+
+
+ if ( up->version >= 100 ) {
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName ) ;
+ }
+#endif
+ if ( write ( pp->io.fd, "stim\r\n",6 ) != 6 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+ } else {
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName ) ;
+ }
+#endif
+ if ( write ( pp->io.fd, "time\r\n",6 ) != 6 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+ }
+ /*** End of modification ***/
+
return 0 ;
case 2 : /* HH:MM:SS */
- if ( iLen < 8 ) {
+ if ( iLen != 8 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ;
+ }
+#endif
up->lineerror = 1 ;
break ;
}
rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ;
+ }
+#endif
up->lineerror = 1 ;
break ;
}
@@ -524,7 +631,7 @@ jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
/*
* The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously.
* But the JJY receiver replies a date and time separately.
- * Just after midnight transtions, we ignore this time.
+ * Just after midnight transitions, we ignore this time.
*/
return 0 ;
}
@@ -547,6 +654,8 @@ static int
jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
{
+ static char *sFunctionName = "jjy_receive_cdex_jst2000" ;
+
struct jjyunit *up ;
struct refclockproc *pp ;
struct peer *peer;
@@ -574,7 +683,12 @@ jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
case 1 : /* JYYMMDD HHMMSSS */
- if ( iLen < 15 ) {
+ if ( iLen != 15 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
+ }
+#endif
up->lineerror = 1 ;
break ;
}
@@ -582,6 +696,12 @@ jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
&up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ;
if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
|| up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName,
+ rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ;
+ }
+#endif
up->lineerror = 1 ;
break ;
}
@@ -601,6 +721,151 @@ jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
}
/**************************************************************************************************/
+
+static int
+jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
+{
+
+ static char *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
+
+ struct jjyunit *up ;
+ struct refclockproc *pp ;
+ struct peer *peer;
+
+ char *pBuf ;
+ int iLen ;
+ int rc ;
+ int i, ibcc, ibcc1, ibcc2 ;
+
+ /*
+ * Initialize pointers and read the timecode and timestamp
+ */
+ peer = (struct peer *) rbufp->recv_srcclock ;
+ pp = peer->procptr ;
+ up = (struct jjyunit *) pp->unitptr ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->rawbuf ;
+ iLen = up->charcount ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ switch ( up->linecount ) {
+
+ case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
+
+ if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ;
+ }
+#endif
+ if ( up->operationmode == 1 ) {
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
+ }
+#endif
+ if ( write ( pp->io.fd, "#",1 ) != 1 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+ }
+ up->lineerror = 1 ;
+ break ;
+ }
+
+ if ( up->operationmode == 1 ) {
+
+ for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ;
+ ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
+ ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
+ if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ;
+ }
+#endif
+ up->lineerror = 1 ;
+ break ;
+ }
+
+ }
+
+ rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d",
+ &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ;
+ if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+#ifdef DEBUG
+ if ( debug >= 2 ) {
+ printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName,
+ rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ;
+ }
+#endif
+ up->lineerror = 1 ;
+ break ;
+ }
+
+ up->year += 2000 ;
+
+ if ( up->operationmode == 2 ) {
+
+ /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */
+ up->msecond = 500 ;
+ pp->second -- ;
+ if ( pp->second < 0 ) {
+ pp->second = 59 ;
+ pp->minute -- ;
+ if ( pp->minute < 0 ) {
+ pp->minute = 59 ;
+ pp->hour -- ;
+ if ( pp->hour < 0 ) {
+ pp->hour = 23 ;
+ pp->day -- ;
+ if ( pp->day < 1 ) {
+ pp->year -- ;
+ pp->day = ymd2yd ( pp->year, 12, 31 ) ;
+ }
+ }
+ }
+ }
+
+ /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
+ }
+#endif
+ if ( write ( pp->io.fd, "#",1 ) != 1 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ }
+
+ break ;
+
+ default : /* Unexpected reply */
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ;
+ }
+#endif
+ if ( write ( pp->io.fd, "#",1 ) != 1 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ up->lineerror = 1 ;
+ break ;
+
+ }
+
+ return 1 ;
+
+}
+
+/**************************************************************************************************/
/* jjy_poll - called by the transmit procedure */
/**************************************************************************************************/
static void
@@ -642,6 +907,10 @@ jjy_poll ( int unit, struct peer *peer )
jjy_poll_cdex_jst2000 ( unit, peer ) ;
break ;
+ case UNITTYPE_ECHOKEISOKUKI_LT2000 :
+ jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
+ break ;
+
default :
break ;
@@ -655,32 +924,48 @@ static void
jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
{
- struct jjyunit *up;
struct refclockproc *pp;
pp = peer->procptr;
- up = (struct jjyunit *) pp->unitptr ;
/*
* Send "date<CR><LF>" command
*/
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ;
+ }
+#endif
+
if ( write ( pp->io.fd, "date\r\n",6 ) != 6 ) {
refclock_report ( peer, CEVNT_FAULT ) ;
}
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+
/*
- * Send "stim<CR><LF>" or "time<CR><LF>" command
+ * Send "<ENQ>1J<ETX>" command
*/
- if ( up->version >= 100 ) {
- if ( write ( pp->io.fd, "stim\r\n",6 ) != 6 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
- }
- } else {
- if ( write ( pp->io.fd, "time\r\n",6 ) != 6 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
- }
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
+ }
+#endif
+
+ if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
}
}
@@ -688,18 +973,34 @@ jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
/**************************************************************************************************/
static void
-jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
+jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
{
+ struct jjyunit *up;
struct refclockproc *pp;
+ char sCmd[2] ;
+
pp = peer->procptr;
+ up = (struct jjyunit *) pp->unitptr ;
/*
- * Send "<ENQ>1J<ETX>" command
+ * Send "T" or "C" command
*/
- if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
+ switch ( up->operationmode ) {
+ case 1 : sCmd[0] = 'T' ; break ;
+ case 2 : sCmd[0] = 'C' ; break ;
+ }
+ sCmd[1] = 0 ;
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
+ }
+#endif
+
+ if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
refclock_report ( peer, CEVNT_FAULT ) ;
}