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.c4445
1 files changed, 3580 insertions, 865 deletions
diff --git a/ntpd/refclock_jjy.c b/ntpd/refclock_jjy.c
index e279ee307d737..fef829ca071b2 100644
--- a/ntpd/refclock_jjy.c
+++ b/ntpd/refclock_jjy.c
@@ -4,7 +4,7 @@
/**********************************************************************/
/* */
-/* Copyright (C) 2001-2011, Takao Abe. All rights reserved. */
+/* Copyright (C) 2001-2015, Takao Abe. All rights reserved. */
/* */
/* Permission to use, copy, modify, and distribute this software */
/* and its documentation for any purpose is hereby granted */
@@ -95,6 +95,17 @@
/* 2011/04/30 */
/* [Add] Support the Tristate Ltd. TS-GPSclock-01 */
/* */
+/* 2015/03/29 */
+/* [Add] Support the Telephone JJY */
+/* [Change] Split the start up routine into each JJY receivers. */
+/* Change raw data internal bufferring process */
+/* Change over midnight handling of TS-JJY01 and TS-GPS01 */
+/* to put DATE command between before and after TIME's. */
+/* Unify the writing clockstats of all JJY receivers. */
+/* */
+/* 2015/05/15 */
+/* [Add] Support the SEIKO TIME SYSTEMS TDC-300 */
+/* */
/**********************************************************************/
#ifdef HAVE_CONFIG_H
@@ -117,81 +128,18 @@
#include "ntp_stdlib.h"
/**********************************************************************/
-/* */
-/* The Tristate Ltd. JJY receiver JJY01 */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* dcst<CR><LF> VALID|INVALID<CR><LF> */
-/* stus<CR><LF> ADJUSTED|UNADJUSTED<CR><LF> */
-/* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */
-/* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */
-/* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
-/* */
-/* During synchronization after a receiver is turned on, */
-/* It replies the past time from 2000/01/01 00:00:00. */
-/* The function "refclock_process" checks the time and tells */
-/* as an insanity time. */
-/* */
-/**********************************************************************/
-/* */
-/* The C-DEX Co. Ltd. JJY receiver JST2000 */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* <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 */
-/* */
-/**********************************************************************/
-/* */
-/* The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* 'XX YY/MM/DD W HH:MM:SS<CR> */
-/* XX: OK|NG|ER */
-/* W: 0(Monday)-6(Sunday) */
-/* */
-/**********************************************************************/
-/* */
-/* The Tristate Ltd. GPS clock TS-GPSCLOCK-01 */
-/* */
-/* This clock has NMEA mode and command/respose mode. */
-/* When this jjy driver are used, set to command/respose mode */
-/* of this clock by the onboard switch SW4, and make sure the */
-/* LED-Y is tured on. */
-/* Other than this JJY driver, the refclock driver type 20, */
-/* generic NMEA driver, works with the NMEA mode of this clock. */
-/* */
-/* Command Response Remarks */
-/* ------------ ---------------------- --------------------- */
-/* stus<CR><LF> *R|*G|*U|+U<CR><LF> */
-/* date<CR><LF> YY/MM/DD<CR><LF> */
-/* time<CR><LF> HH:MM:SS<CR><LF> */
-/* */
-/**********************************************************************/
/*
* Interface definitions
*/
#define DEVICE "/dev/jjy%d" /* device name and unit */
-#define SPEED232 B9600 /* uart speed (9600 baud) */
#define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */
#define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */
#define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */
#define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */
#define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */
+#define SPEED232_SEIKO_TIMESYS_TDC_300 B2400 /* UART speed (2400 baud) */
+#define SPEED232_TELEPHONE B2400 /* UART speed (4800 baud) */
#define REFID "JJY" /* reference ID */
#define DESCRIPTION "JJY Receiver"
#define PRECISION (-3) /* precision assumed (about 100 ms) */
@@ -199,22 +147,65 @@
/*
* JJY unit control structure
*/
+
+struct jjyRawDataBreak {
+ char *pString ;
+ int iLength ;
+} ;
+
+#define MAX_TIMESTAMP 6
+#define MAX_RAWBUF 100
+#define MAX_LOOPBACK 5
+
struct jjyunit {
+/* Set up by the function "jjy_start_xxxxxxxx" */
char unittype ; /* UNITTYPE_XXXXXXXXXX */
- short operationmode ; /* Echo Keisokuki LT-2000 : 1 or 2 */
- short version ;
+ short operationmode ; /* Echo Keisokuki LT-2000 */
+ int linespeed ; /* SPEED232_XXXXXXXXXX */
short linediscipline ; /* LDISC_CLK or LDISC_RAW */
- char bPollFlag ; /* Set by jjy_pool and Reset by jjy_receive */
- int linecount ;
- int lineerror ;
+/* Receiving data */
+ char bInitError ; /* Set by jjy_start if any error during initialization */
+ short iProcessState ; /* JJY_PROCESS_STATE_XXXXXX */
+ char bReceiveFlag ; /* Set and reset by jjy_receive */
+ char bLineError ; /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/
+ short iCommandSeq ; /* 0:Idle Non-Zero:Issued */
+ short iReceiveSeq ;
+ int iLineCount ;
int year, month, day, hour, minute, second, msecond ;
+ int leapsecond ;
+ int iTimestampCount ; /* TS-JJY01, TS-GPS01, Telephone-JJY */
+ int iTimestamp [ MAX_TIMESTAMP ] ; /* Serial second ( 0 - 86399 ) */
/* LDISC_RAW only */
-#define MAX_LINECOUNT 8
-#define MAX_RAWBUF 64
- int lineexpect ;
- int charexpect [ MAX_LINECOUNT ] ;
- int charcount ;
- char rawbuf [ MAX_RAWBUF ] ;
+ char sRawBuf [ MAX_RAWBUF ] ;
+ int iRawBufLen ;
+ struct jjyRawDataBreak *pRawBreak ;
+ char bWaitBreakString ;
+ char sLineBuf [ MAX_RAWBUF ] ;
+ int iLineBufLen ;
+ char sTextBuf [ MAX_RAWBUF ] ;
+ int iTextBufLen ;
+ char bSkipCntrlCharOnly ;
+/* Telephone JJY auto measurement of the loopback delay */
+ char bLoopbackMode ;
+ short iLoopbackCount ;
+ struct timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ;
+ char bLoopbackTimeout[MAX_LOOPBACK] ;
+ short iLoopbackValidCount ;
+/* Telephone JJY timer */
+ short iTeljjySilentTimer ;
+ short iTeljjyStateTimer ;
+/* Telephone JJY control finite state machine */
+ short iClockState ;
+ short iClockEvent ;
+ short iClockCommandSeq ;
+/* Modem timer */
+ short iModemSilentCount ;
+ short iModemSilentTimer ;
+ short iModemStateTimer ;
+/* Modem control finite state machine */
+ short iModemState ;
+ short iModemEvent ;
+ short iModemCommandSeq ;
};
#define UNITTYPE_TRISTATE_JJY01 1
@@ -222,12 +213,93 @@ struct jjyunit {
#define UNITTYPE_ECHOKEISOKUKI_LT2000 3
#define UNITTYPE_CITIZENTIC_JJY200 4
#define UNITTYPE_TRISTATE_GPSCLOCK01 5
+#define UNITTYPE_SEIKO_TIMESYS_TDC_300 6
+#define UNITTYPE_TELEPHONE 100
+
+#define JJY_PROCESS_STATE_IDLE 0
+#define JJY_PROCESS_STATE_POLL 1
+#define JJY_PROCESS_STATE_RECEIVE 2
+#define JJY_PROCESS_STATE_DONE 3
+#define JJY_PROCESS_STATE_ERROR 4
+
+/**********************************************************************/
/*
+ * Function calling structure
+ *
+ * jjy_start
+ * |-- jjy_start_tristate_jjy01
+ * |-- jjy_start_cdex_jst2000
+ * |-- jjy_start_echokeisokuki_lt2000
+ * |-- jjy_start_citizentic_jjy200
+ * |-- jjy_start_tristate_gpsclock01
+ * |-- jjy_start_seiko_tsys_tdc_300
+ * |-- jjy_start_telephone
+ *
+ * jjy_shutdown
+ *
+ * jjy_poll
+ * |-- jjy_poll_tristate_jjy01
+ * |-- jjy_poll_cdex_jst2000
+ * |-- jjy_poll_echokeisokuki_lt2000
+ * |-- jjy_poll_citizentic_jjy200
+ * |-- jjy_poll_tristate_gpsclock01
+ * |-- jjy_poll_seiko_tsys_tdc_300
+ * |-- jjy_poll_telephone
+ * |-- teljjy_control
+ * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- modem_connect
+ * |-- modem_control
+ * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ *
+ * jjy_receive
+ * |
+ * |-- jjy_receive_tristate_jjy01
+ * | |-- jjy_synctime
+ * |-- jjy_receive_cdex_jst2000
+ * | |-- jjy_synctime
+ * |-- jjy_receive_echokeisokuki_lt2000
+ * | |-- jjy_synctime
+ * |-- jjy_receive_citizentic_jjy200
+ * | |-- jjy_synctime
+ * |-- jjy_receive_tristate_gpsclock01
+ * | |-- jjy_synctime
+ * |-- jjy_receive_seiko_tsys_tdc_300
+ * | |-- jjy_synctime
+ * |-- jjy_receive_telephone
+ * |-- modem_receive
+ * | |-- modem_control
+ * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- teljjy_control
+ * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- jjy_synctime
+ * |-- modem_disconnect
+ * |-- modem_control
+ * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ *
+ * jjy_timer
+ * |-- jjy_timer_telephone
+ * |-- modem_timer
+ * | |-- modem_control
+ * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- teljjy_control
+ * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ * |-- modem_disconnect
+ * |-- modem_control
+ * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. )
+ *
* Function prototypes
*/
-
+
static int jjy_start (int, struct peer *);
+static int jjy_start_tristate_jjy01 (int, struct peer *, struct jjyunit *);
+static int jjy_start_cdex_jst2000 (int, struct peer *, struct jjyunit *);
+static int jjy_start_echokeisokuki_lt2000 (int, struct peer *, struct jjyunit *);
+static int jjy_start_citizentic_jjy200 (int, struct peer *, struct jjyunit *);
+static int jjy_start_tristate_gpsclock01 (int, struct peer *, struct jjyunit *);
+static int jjy_start_seiko_tsys_tdc_300 (int, struct peer *, struct jjyunit *);
+static int jjy_start_telephone (int, struct peer *, struct jjyunit *);
+
static void jjy_shutdown (int, struct peer *);
static void jjy_poll (int, struct peer *);
@@ -236,15 +308,36 @@ static void jjy_poll_cdex_jst2000 (int, struct peer *);
static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *);
static void jjy_poll_citizentic_jjy200 (int, struct peer *);
static void jjy_poll_tristate_gpsclock01 (int, struct peer *);
+static void jjy_poll_seiko_tsys_tdc_300 (int, struct peer *);
+static void jjy_poll_telephone (int, struct peer *);
static void jjy_receive (struct recvbuf *);
-static int jjy_receive_tristate_jjy01 (struct recvbuf *);
-static int jjy_receive_cdex_jst2000 (struct recvbuf *);
-static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
-static int jjy_receive_citizentic_jjy200 (struct recvbuf *);
-static int jjy_receive_tristate_gpsclock01 (struct recvbuf *);
+static int jjy_receive_tristate_jjy01 (struct recvbuf *);
+static int jjy_receive_cdex_jst2000 (struct recvbuf *);
+static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *);
+static int jjy_receive_citizentic_jjy200 (struct recvbuf *);
+static int jjy_receive_tristate_gpsclock01 (struct recvbuf *);
+static int jjy_receive_seiko_tsys_tdc_300 (struct recvbuf *);
+static int jjy_receive_telephone (struct recvbuf *);
-static void printableString ( char*, int, char*, int ) ;
+static void jjy_timer (int, struct peer *);
+static void jjy_timer_telephone (int, struct peer *);
+
+static void jjy_synctime ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static void jjy_write_clockstats ( struct peer *, int, const char* ) ;
+
+static int getRawDataBreakPosition ( struct jjyunit *, int ) ;
+
+static short getModemState ( struct jjyunit * ) ;
+static int isModemStateConnect ( short ) ;
+static int isModemStateDisconnect ( short ) ;
+static int isModemStateTimerOn ( struct jjyunit * ) ;
+static void modem_connect ( int, struct peer * ) ;
+static void modem_disconnect ( int, struct peer * ) ;
+static int modem_receive ( struct recvbuf * ) ;
+static void modem_timer ( int, struct peer * );
+
+static void printableString ( char*, int, const char*, int ) ;
/*
* Transfer vector
@@ -256,7 +349,7 @@ struct refclock refclock_jjy = {
noentry, /* not used */
noentry, /* not used */
noentry, /* not used */
- NOFLAGS /* not used */
+ jjy_timer /* 1 second interval timer */
};
/*
@@ -269,88 +362,64 @@ struct refclock refclock_jjy = {
* Local constants definition
*/
-#define MAX_LOGTEXT 64
-
-/*
- * Tristate JJY01/JJY02 constants definition
- */
-
-#define TS_JJY01_COMMAND_NUMBER_DATE 1
-#define TS_JJY01_COMMAND_NUMBER_TIME 2
-#define TS_JJY01_COMMAND_NUMBER_STIM 3
-#define TS_JJY01_COMMAND_NUMBER_STUS 4
-#define TS_JJY01_COMMAND_NUMBER_DCST 5
-
-#define TS_JJY01_REPLY_DATE "yyyy/mm/dd www\r\n"
-#define TS_JJY01_REPLY_STIM "hh:mm:ss\r\n"
-#define TS_JJY01_REPLY_STUS_YES "adjusted\r\n"
-#define TS_JJY01_REPLY_STUS_NO "unadjusted\r\n"
-#define TS_JJY01_REPLY_DCST_VALID "valid\r\n"
-#define TS_JJY01_REPLY_DCST_INVALID "invalid\r\n"
-
-#define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */
-#define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */
-#define TS_JJY01_REPLY_LENGTH_STUS_YES 8 /* Length without <CR><LF> */
-#define TS_JJY01_REPLY_LENGTH_STUS_NO 10 /* Length without <CR><LF> */
-#define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */
-#define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */
-
-static struct
-{
- const char commandNumber ;
- const char *commandLog ;
- const char *command ;
- int commandLength ;
-} tristate_jjy01_command_sequence[] =
-{
- /* dcst<CR><LF> -> VALID<CR><LF> or INVALID<CR><LF> */
- { TS_JJY01_COMMAND_NUMBER_DCST, "dcst", "dcst\r\n", 6 },
- /* stus<CR><LF> -> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
- { TS_JJY01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
- /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
- { TS_JJY01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
- /* stim<CR><LF> -> HH:MM:SS<CR><LF> */
- { TS_JJY01_COMMAND_NUMBER_STIM, "stim", "stim\r\n", 6 },
- /* End of command */
- { 0, NULL, NULL, 0 }
-} ;
-
-/*
- * Tristate TS-GPSCLOCK01 constants definition
- */
-
-#define TS_GPSCLOCK01_COMMAND_NUMBER_DATE 1
-#define TS_GPSCLOCK01_COMMAND_NUMBER_TIME 2
-#define TS_GPSCLOCK01_COMMAND_NUMBER_STUS 4
+#define MAX_LOGTEXT 100
-#define TS_GPSCLOCK01_REPLY_DATE "yyyy/mm/dd\r\n"
-#define TS_GPSCLOCK01_REPLY_TIME "hh:mm:ss\r\n"
-#define TS_GPSCLOCK01_REPLY_STUS_RTC "*R\r\n"
-#define TS_GPSCLOCK01_REPLY_STUS_GPS "*G\r\n"
-#define TS_GPSCLOCK01_REPLY_STUS_UTC "*U\r\n"
-#define TS_GPSCLOCK01_REPLY_STUS_PPS "+U\r\n"
-
-#define TS_GPSCLOCK01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */
-#define TS_GPSCLOCK01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
-#define TS_GPSCLOCK01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */
+#ifndef TRUE
+#define TRUE (0==0)
+#endif
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif
-static struct
-{
- char commandNumber ;
- const char *commandLog ;
- const char *command ;
- int commandLength ;
-} tristate_gpsclock01_command_sequence[] =
-{
- /* stus<CR><LF> -> *R<CR><LF> or *G<CR><LF> or *U<CR><LF> or +U<CR><LF> */
- { TS_GPSCLOCK01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 },
- /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */
- { TS_GPSCLOCK01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 },
- /* time<CR><LF> -> HH:MM:SS<CR><LF> */
- { TS_GPSCLOCK01_COMMAND_NUMBER_TIME, "time", "time\r\n", 6 },
- /* End of command */
- { 0, NULL, NULL, 0 }
-} ;
+/* Local constants definition for the return code of the jjy_receive_xxxxxxxx */
+
+#define JJY_RECEIVE_DONE 0
+#define JJY_RECEIVE_SKIP 1
+#define JJY_RECEIVE_UNPROCESS 2
+#define JJY_RECEIVE_WAIT 3
+#define JJY_RECEIVE_ERROR 4
+
+/* Local constants definition for the 2nd parameter of the jjy_write_clockstats */
+
+#define JJY_CLOCKSTATS_MARK_NONE 0
+#define JJY_CLOCKSTATS_MARK_JJY 1
+#define JJY_CLOCKSTATS_MARK_SEND 2
+#define JJY_CLOCKSTATS_MARK_RECEIVE 3
+#define JJY_CLOCKSTATS_MARK_INFORMATION 4
+#define JJY_CLOCKSTATS_MARK_ATTENTION 5
+#define JJY_CLOCKSTATS_MARK_WARNING 6
+#define JJY_CLOCKSTATS_MARK_ERROR 7
+
+/* Local constants definition for the clockstats messages */
+
+#define JJY_CLOCKSTATS_MESSAGE_ECHOBACK "* Echoback"
+#define JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY "* Ignore replay : [%s]"
+#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2 "* Over midnight : timestamp=%d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3 "* Over midnight : timestamp=%d, %d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE "* Unsure timestamp : %s"
+#define JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY "* Loopback delay : %d.%03d mSec."
+#define JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST "* Delay adjustment : %d mSec. ( valid=%hd/%d )"
+#define JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST "* Delay adjustment : None ( valid=%hd/%d )"
+
+#define JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY "# Unexpected reply : [%s]"
+#define JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH "# Invalid length : length=%d"
+#define JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY "# Too many reply : count=%d"
+#define JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY "# Invalid reply : [%s]"
+#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2 "# Slow reply : timestamp=%d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3 "# Slow reply : timestamp=%d, %d, %d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE "# Invalid date : rc=%d year=%d month=%d day=%d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME "# Invalid time : rc=%d hour=%d minute=%d second=%d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME "# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP "# Invalid leap : leapsecond=[%s]"
+#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS "# Invalid status : status=[%s]"
+
+/* Debug print macro */
+
+#ifdef DEBUG
+#define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen) { if ( debug ) { printf ( "refclock_jjy.c : %s : iProcessState=%d bLineError=%d iCommandSeq=%d iLineCount=%d iTimestampCount=%d iLen=%d\n", sFunc, up->iProcessState, up->bLineError, up->iCommandSeq, up->iLineCount, up->iTimestampCount, iLen ) ; } }
+#else
+#define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen)
+#endif
/**************************************************************************************************/
/* jjy_start - open the devices and initialize data for processing */
@@ -359,31 +428,42 @@ static int
jjy_start ( int unit, struct peer *peer )
{
- struct jjyunit *up ;
- struct refclockproc *pp ;
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+ int rc ;
int fd ;
- char *pDeviceName ;
- short iDiscipline ;
- int iSpeed232 ;
-
- char sLogText [ MAX_LOGTEXT ] , sDevText [ MAX_LOGTEXT ] ;
+ char sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ;
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ;
- printf ( DEVICE, unit ) ;
- printf ( "\n" ) ;
+ printf( "refclock_jjy.c : jjy_start : %s mode=%d dev=%s unit=%d\n",
+ ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ;
}
#endif
- snprintf ( sDevText, sizeof(sDevText), DEVICE, unit ) ;
- snprintf ( sLogText, sizeof(sLogText), "*Initialze* %s mode=%d", sDevText, peer->ttl ) ;
- record_clock_stats ( &peer->srcadr, sLogText ) ;
- /*
- * Open serial port
- */
- pDeviceName = emalloc ( strlen(DEVICE) + 10 );
- snprintf ( pDeviceName, strlen(DEVICE) + 10, DEVICE, unit ) ;
+ /* Allocate memory for the unit structure */
+ up = emalloc( sizeof(*up) ) ;
+ if ( up == NULL ) {
+ msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ;
+ return RC_START_ERROR ;
+ }
+ memset ( up, 0, sizeof(*up) ) ;
+
+ up->bInitError = FALSE ;
+ up->iProcessState = JJY_PROCESS_STATE_IDLE ;
+ up->bReceiveFlag = FALSE ;
+ up->iCommandSeq = 0 ;
+ up->iLineCount = 0 ;
+ up->iTimestampCount = 0 ;
+ up->bWaitBreakString = FALSE ;
+ up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ;
+ up->bSkipCntrlCharOnly = TRUE ;
+
+ /* Set up the device name */
+ snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ;
+
+ snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
/*
* peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
@@ -391,101 +471,57 @@ jjy_start ( int unit, struct peer *peer )
switch ( peer->ttl ) {
case 0 :
case 1 :
- iDiscipline = LDISC_CLK ;
- iSpeed232 = SPEED232_TRISTATE_JJY01 ;
+ rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ;
break ;
case 2 :
- iDiscipline = LDISC_RAW ;
- iSpeed232 = SPEED232_CDEX_JST2000 ;
+ rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ;
break ;
case 3 :
- iDiscipline = LDISC_CLK ;
- iSpeed232 = SPEED232_ECHOKEISOKUKI_LT2000 ;
+ rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ;
break ;
case 4 :
- iDiscipline = LDISC_CLK ;
- iSpeed232 = SPEED232_CITIZENTIC_JJY200 ;
+ rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ;
break ;
case 5 :
- iDiscipline = LDISC_CLK ;
- iSpeed232 = SPEED232_TRISTATE_GPSCLOCK01 ;
+ rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ;
+ break ;
+ case 6 :
+ rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ;
+ break ;
+ case 100 :
+ rc = jjy_start_telephone ( unit, peer, up ) ;
break ;
default :
- msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
+ if ( 101 <= peer->ttl && peer->ttl <= 180 ) {
+ rc = jjy_start_telephone ( unit, peer, up ) ;
+ } else {
+ msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode",
+ ntoa(&peer->srcadr), peer->ttl ) ;
+ free ( (void*) up ) ;
+ return RC_START_ERROR ;
+ }
+ }
+
+ if ( rc != 0 ) {
+ msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error",
ntoa(&peer->srcadr), peer->ttl ) ;
- free ( (void*) pDeviceName ) ;
+ free ( (void*) up ) ;
return RC_START_ERROR ;
}
- fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ;
+ /* Open the device */
+ fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ;
if ( fd <= 0 ) {
- free ( (void*) pDeviceName ) ;
+ free ( (void*) up ) ;
return RC_START_ERROR ;
}
- free ( (void*) pDeviceName ) ;
/*
- * Allocate and initialize unit structure
- */
- up = emalloc (sizeof(*up));
- memset ( up, 0, sizeof(*up) ) ;
- up->linediscipline = iDiscipline ;
-
- /*
- * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf
+ * Initialize variables
*/
- switch ( peer->ttl ) {
- case 0 :
- /*
- * The mode 0 is a default clock type at this time.
- * But this will be change to auto-detect mode in the future.
- */
- case 1 :
- up->unittype = UNITTYPE_TRISTATE_JJY01 ;
- up->version = 100 ;
- /* 2010/11/20 */
- /* Command sequence is defined by the struct tristate_jjy01_command_sequence, */
- /* and the following 3 lines are not used in the mode LDISC_CLK. */
- /* up->lineexpect = 2 ; */
- /* up->charexpect[0] = 14 ; */ /* YYYY/MM/DD WWW<CR><LF> */
- /* up->charexpect[1] = 8 ; */ /* HH:MM:SS<CR><LF> */
- break ;
- case 2 :
- up->unittype = UNITTYPE_CDEX_JST2000 ;
- 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 ;
- case 4 :
- up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
- up->lineexpect = 1 ;
- up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */
- break ;
- case 5 :
- up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
- break ;
-
- /* 2010/11/20 */
- /* The "default:" section of this switch block is never executed, */
- /* because the former switch block traps the same "default:" case. */
- /* This "default:" section codes are removed to avoid spending time */
- /* in the future looking, though the codes are functionally harmless. */
-
- }
-
pp = peer->procptr ;
+
+ pp->clockdesc = DESCRIPTION ;
pp->unitptr = up ;
pp->io.clock_recv = jjy_receive ;
pp->io.srcclock = peer ;
@@ -498,19 +534,17 @@ jjy_start ( int unit, struct peer *peer )
pp->unitptr = NULL ;
return RC_START_ERROR ;
}
+ memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ;
- /*
- * Initialize miscellaneous variables
- */
peer->precision = PRECISION ;
- pp->clockdesc = DESCRIPTION ;
- memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ;
+
+ snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
return RC_START_SUCCESS ;
}
-
/**************************************************************************************************/
/* jjy_shutdown - shutdown the clock */
/**************************************************************************************************/
@@ -521,15 +555,21 @@ jjy_shutdown ( int unit, struct peer *peer )
struct jjyunit *up;
struct refclockproc *pp;
+ char sLog [ 60 ] ;
+
pp = peer->procptr ;
up = pp->unitptr ;
- if ( -1 != pp->io.fd )
+ if ( -1 != pp->io.fd ) {
io_closeclock ( &pp->io ) ;
- if ( NULL != up )
+ }
+ if ( NULL != up ) {
free ( up ) ;
+ }
-}
+ snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ;
+ record_clock_stats( &peer->srcadr, sLog ) ;
+}
/**************************************************************************************************/
/* jjy_receive - receive data from the serial interface */
@@ -537,6 +577,9 @@ jjy_shutdown ( int unit, struct peer *peer )
static void
jjy_receive ( struct recvbuf *rbufp )
{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_receive" ;
+#endif
struct jjyunit *up ;
struct refclockproc *pp ;
@@ -544,8 +587,9 @@ jjy_receive ( struct recvbuf *rbufp )
l_fp tRecvTimestamp; /* arrival timestamp */
int rc ;
- char sLogText [ MAX_LOGTEXT ] ;
- int i, bCntrlChar ;
+ char *pBuf, sLogText [ MAX_LOGTEXT ] ;
+ int iLen, iCopyLen ;
+ int i, j, iReadRawBuf, iBreakPosition ;
/*
* Initialize pointers and read the timecode and timestamp
@@ -557,139 +601,414 @@ jjy_receive ( struct recvbuf *rbufp )
/*
* Get next input line
*/
- pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
-
if ( up->linediscipline == LDISC_RAW ) {
+
+ pp->lencode = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ;
+ /* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions (OVERRUN)" */
+ /* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */
+ /* To avoid its claim, pass the value BMAX-1. */
+
/*
- * The reply with <STX> and <ETX> may give a blank line
- */
- if ( pp->lencode == 0 && up->charcount == 0 ) return ;
- /*
- * Copy received charaters to temporary buffer
+ * Append received charaters to temporary buffer
*/
for ( i = 0 ;
- i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ;
- i ++ , up->charcount ++ ) {
- up->rawbuf[up->charcount] = pp->a_lastcode[i] ;
- }
- while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) {
- for ( i = 0 ; i < up->charcount - 1 ; i ++ )
- up->rawbuf[i] = up->rawbuf[i+1] ;
- up->charcount -- ;
- }
- bCntrlChar = 0 ;
- for ( i = 0 ; i < up->charcount ; i ++ ) {
- if ( up->rawbuf[i] < ' ' ) {
- bCntrlChar = 1 ;
- break ;
- }
+ i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ;
+ i ++ , up->iRawBufLen ++ ) {
+ up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ;
}
- if ( pp->lencode > 0 && up->linecount < up->lineexpect ) {
- if ( bCntrlChar == 0 &&
- up->charcount < up->charexpect[up->linecount] )
- return ;
- }
- up->rawbuf[up->charcount] = 0 ;
+ up->sRawBuf[up->iRawBufLen] = 0 ;
+
+
} else {
- /*
- * The reply with <CR><LF> gives a blank line
- */
- if ( pp->lencode == 0 ) return ;
+
+ pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ;
+
}
+#ifdef DEBUG
+ printf( "\nrefclock_jjy.c : %s : Len=%d ", sFunctionName, pp->lencode ) ;
+ for ( i = 0 ; i < pp->lencode ; i ++ ) {
+ if ( iscntrl( pp->a_lastcode[i] & 0x7F ) ) {
+ printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ;
+ } else {
+ printf( "%c", pp->a_lastcode[i] ) ;
+ }
+ }
+ printf( "\n" ) ;
+#endif
+
+ /*
+ * The reply with <CR><LF> gives a blank line
+ */
+
+ if ( pp->lencode == 0 ) return ;
+
+ /*
+ * Receiving data is not expected
+ */
+
+ if ( up->iProcessState == JJY_PROCESS_STATE_IDLE
+ || up->iProcessState == JJY_PROCESS_STATE_DONE
+ || up->iProcessState == JJY_PROCESS_STATE_ERROR ) {
+ /* Discard received data */
+ up->iRawBufLen = 0 ;
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ;
+ }
+#endif
+ return ;
+ }
+
/*
* We get down to business
*/
+ pp->lastrec = tRecvTimestamp ;
+
+ up->iLineCount ++ ;
+
+ up->iProcessState = JJY_PROCESS_STATE_RECEIVE ;
+ up->bReceiveFlag = TRUE ;
+
+ iReadRawBuf = 0 ;
+ iBreakPosition = up->iRawBufLen - 1 ;
+ for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) {
+
+ if ( up->linediscipline == LDISC_RAW ) {
+
+ if ( up->bWaitBreakString ) {
+ iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ;
+ if ( iBreakPosition == -1 ) {
+ /* Break string have not come yet */
+ if ( up->iRawBufLen < MAX_RAWBUF - 2
+ || iReadRawBuf > 0 ) {
+ /* Temporary buffer is not full */
+ break ;
+ } else {
+ /* Temporary buffer is full */
+ iBreakPosition = up->iRawBufLen - 1 ;
+ }
+ }
+ } else {
+ iBreakPosition = up->iRawBufLen - 1 ;
+ }
+
+ /* Copy charaters from temporary buffer to process buffer */
+ up->iLineBufLen = up->iTextBufLen = 0 ;
+ for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) {
+
+ /* Copy all characters */
+ up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ;
+ up->iLineBufLen ++ ;
+
+ /* Copy printable characters */
+ if ( ! iscntrl( up->sRawBuf[i] ) ) {
+ up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ;
+ up->iTextBufLen ++ ;
+ }
+
+ }
+ up->sLineBuf[up->iLineBufLen] = 0 ;
+ up->sTextBuf[up->iTextBufLen] = 0 ;
#ifdef DEBUG
- if ( debug ) {
+ printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n",
+ sFunctionName, up->iLineBufLen, up->iTextBufLen ) ;
+#endif
+
+ if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) {
+#ifdef DEBUG
+ printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n",
+ sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ;
+#endif
+ if ( iBreakPosition + 1 < up->iRawBufLen ) {
+ iReadRawBuf = iBreakPosition + 1 ;
+ continue ;
+ } else {
+ break ;
+ }
+
+ }
+
+ }
+
if ( up->linediscipline == LDISC_RAW ) {
- printableString( sLogText, MAX_LOGTEXT, up->rawbuf, up->charcount ) ;
+ pBuf = up->sLineBuf ;
+ iLen = up->iLineBufLen ;
} else {
- printableString( sLogText, MAX_LOGTEXT, pp->a_lastcode, pp->lencode ) ;
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ;
+ strncpy( sLogText, pBuf, iCopyLen ) ;
+ sLogText[iCopyLen] = 0 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ;
+
+ switch ( up->unittype ) {
+
+ case UNITTYPE_TRISTATE_JJY01 :
+ rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_CDEX_JST2000 :
+ rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_ECHOKEISOKUKI_LT2000 :
+ rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_CITIZENTIC_JJY200 :
+ rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_TRISTATE_GPSCLOCK01 :
+ rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
+ rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ;
+ break ;
+
+ case UNITTYPE_TELEPHONE :
+ rc = jjy_receive_telephone ( rbufp ) ;
+ break ;
+
+ default :
+ rc = JJY_RECEIVE_ERROR ;
+ break ;
+
+ }
+
+ switch ( rc ) {
+ case JJY_RECEIVE_DONE :
+ case JJY_RECEIVE_SKIP :
+ up->iProcessState = JJY_PROCESS_STATE_DONE ;
+ break ;
+ case JJY_RECEIVE_ERROR :
+ up->iProcessState = JJY_PROCESS_STATE_ERROR ;
+ break ;
+ default :
+ break ;
+ }
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ if ( rc == JJY_RECEIVE_UNPROCESS ) {
+ break ;
+ }
+ iReadRawBuf = iBreakPosition + 1 ;
+ if ( iReadRawBuf >= up->iRawBufLen ) {
+ /* Processed all received data */
+ break ;
+ }
+ }
+
+ if ( up->linediscipline == LDISC_CLK ) {
+ break ;
+ }
+
+ }
+
+ if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) {
+ for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) {
+ up->sRawBuf[i] = up->sRawBuf[j] ;
}
- printf ( "jjy_receive (refclock_jjy.c) : [%s]\n", sLogText ) ;
+ up->iRawBufLen -= iReadRawBuf ;
+ if ( up->iRawBufLen < 0 ) {
+ up->iRawBufLen = 0 ;
+ }
+ }
+
+ up->bReceiveFlag = FALSE ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+getRawDataBreakPosition ( struct jjyunit *up, int iStart )
+{
+
+ int i, j ;
+
+ if ( iStart >= up->iRawBufLen ) {
+#ifdef DEBUG
+ printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
+#endif
+ return -1 ;
}
+
+ for ( i = iStart ; i < up->iRawBufLen ; i ++ ) {
+
+ for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) {
+
+ if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) {
+
+ if ( strncmp( up->sRawBuf + i,
+ up->pRawBreak[j].pString,
+ up->pRawBreak[j].iLength ) == 0 ) {
+
+#ifdef DEBUG
+ printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n",
+ iStart, i + up->pRawBreak[j].iLength - 1 ) ;
#endif
+ return i + up->pRawBreak[j].iLength - 1 ;
- pp->lastrec = tRecvTimestamp ;
+ }
+ }
+ }
+ }
+
+#ifdef DEBUG
+ printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ;
+#endif
+ return -1 ;
+
+}
+
+/**************************************************************************************************/
+/* jjy_poll - called by the transmit procedure */
+/**************************************************************************************************/
+static void
+jjy_poll ( int unit, struct peer *peer )
+{
+
+ char sLog [ 40 ], sReach [ 9 ] ;
+
+ struct jjyunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = pp->unitptr ;
+
+ if ( up->bInitError ) {
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ;
+ return ;
+ }
+
+ if ( pp->polls > 0 && up->iLineCount == 0 ) {
+ /*
+ * No reply for last command
+ */
+ refclock_report ( peer, CEVNT_TIMEOUT ) ;
+ }
- up->linecount ++ ;
+ pp->polls ++ ;
- if ( up->lineerror != 0 ) return ;
+ sReach[0] = peer->reach & 0x80 ? '1' : '0' ;
+ sReach[1] = peer->reach & 0x40 ? '1' : '0' ;
+ sReach[2] = peer->reach & 0x20 ? '1' : '0' ;
+ sReach[3] = peer->reach & 0x10 ? '1' : '0' ;
+ sReach[4] = peer->reach & 0x08 ? '1' : '0' ;
+ sReach[5] = peer->reach & 0x04 ? '1' : '0' ;
+ sReach[6] = peer->reach & 0x02 ? '1' : '0' ;
+ sReach[7] = 0 ; /* This poll */
+ sReach[8] = 0 ;
+
+ snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
+
+ up->iProcessState = JJY_PROCESS_STATE_POLL ;
+ up->iCommandSeq = 0 ;
+ up->iReceiveSeq = 0 ;
+ up->iLineCount = 0 ;
+ up->bLineError = FALSE ;
+ up->iRawBufLen = 0 ;
switch ( up->unittype ) {
case UNITTYPE_TRISTATE_JJY01 :
- rc = jjy_receive_tristate_jjy01 ( rbufp ) ;
+ jjy_poll_tristate_jjy01 ( unit, peer ) ;
break ;
case UNITTYPE_CDEX_JST2000 :
- rc = jjy_receive_cdex_jst2000 ( rbufp ) ;
+ jjy_poll_cdex_jst2000 ( unit, peer ) ;
break ;
case UNITTYPE_ECHOKEISOKUKI_LT2000 :
- rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ;
+ jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
break ;
case UNITTYPE_CITIZENTIC_JJY200 :
- rc = jjy_receive_citizentic_jjy200 ( rbufp ) ;
+ jjy_poll_citizentic_jjy200 ( unit, peer ) ;
break ;
case UNITTYPE_TRISTATE_GPSCLOCK01 :
- rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ;
+ jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
+ break ;
+
+ case UNITTYPE_SEIKO_TIMESYS_TDC_300 :
+ jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ;
+ break ;
+
+ case UNITTYPE_TELEPHONE :
+ jjy_poll_telephone ( unit, peer ) ;
break ;
default :
- rc = 0 ;
break ;
}
- if ( up->linediscipline == LDISC_RAW ) {
- if ( up->linecount <= up->lineexpect &&
- up->charcount > up->charexpect[up->linecount-1] ) {
- for ( i = 0 ;
- i < up->charcount - up->charexpect[up->linecount-1] ;
- i ++ ) {
- up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ;
- }
- up->charcount -= up->charexpect[up->linecount-1] ;
- } else {
- up->charcount = 0 ;
- }
+}
+
+/**************************************************************************************************/
+/* jjy_timer - called at one-second intervals */
+/**************************************************************************************************/
+static void
+jjy_timer ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "refclock_jjy.c : jjy_timer\n" ) ;
}
+#endif
- if ( rc == 0 ) {
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ if ( up->bReceiveFlag ) {
+#ifdef DEBUG
+ if ( debug ) {
+ printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ;
+ }
+#endif
return ;
}
- up->bPollFlag = 0 ;
+ switch ( up->unittype ) {
+
+ case UNITTYPE_TELEPHONE :
+ jjy_timer_telephone ( unit, peer ) ;
+ break ;
+
+ default :
+ break ;
- if ( up->lineerror != 0 ) {
- refclock_report ( peer, CEVNT_BADREPLY ) ;
- strlcpy ( sLogText, "BAD REPLY [",
- sizeof( sLogText ) ) ;
- if ( up->linediscipline == LDISC_RAW ) {
- strlcat ( sLogText, up->rawbuf,
- sizeof( sLogText ) ) ;
- } else {
- strlcat ( sLogText, pp->a_lastcode,
- sizeof( sLogText ) ) ;
- }
- sLogText[MAX_LOGTEXT-1] = 0 ;
- if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 )
- strlcat ( sLogText, "]",
- sizeof( sLogText ) ) ;
- record_clock_stats ( &peer->srcadr, sLogText ) ;
- return ;
}
+}
+
+/**************************************************************************************************/
+/* jjy_synctime */
+/**************************************************************************************************/
+static void
+jjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char sLog [ 80 ], cStatus ;
+ const char *pStatus ;
+
pp->year = up->year ;
- pp->day = ymd2yd ( up->year, up->month, up->day ) ;
+ pp->day = ymd2yd( up->year, up->month, up->day ) ;
pp->hour = up->hour ;
pp->minute = up->minute ;
pp->second = up->second ;
- pp->nsec = up->msecond * 1000000;
+ pp->nsec = up->msecond * 1000000 ;
/*
* JST to UTC
@@ -700,226 +1019,423 @@ jjy_receive ( struct recvbuf *rbufp )
pp->day -- ;
if ( pp->day < 1 ) {
pp->year -- ;
- pp->day = ymd2yd ( pp->year, 12, 31 ) ;
+ pp->day = ymd2yd( pp->year, 12, 31 ) ;
}
}
-#ifdef DEBUG
- if ( debug ) {
- 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
/*
* Process the new sample in the median filter and determine the
* timecode timestamp.
*/
- snprintf ( sLogText, sizeof(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);
+ if ( ! refclock_process( pp ) ) {
+ refclock_report( peer, CEVNT_BADTIME ) ;
return ;
}
- pp->lastref = pp->lastrec;
- refclock_receive(peer);
+ pp->lastref = pp->lastrec ;
+
+ refclock_receive( peer ) ;
+
+ /*
+ * Write into the clockstats file
+ */
+ snprintf ( sLog, sizeof(sLog),
+ "%04d/%02d/%02d %02d:%02d:%02d.%03d JST ( %04d/%03d %02d:%02d:%02d.%03d UTC )",
+ up->year, up->month, up->day,
+ up->hour, up->minute, up->second, up->msecond,
+ pp->year, pp->day, pp->hour, pp->minute, pp->second,
+ (int)(pp->nsec/1000000) ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ;
+
+ cStatus = ' ' ;
+ pStatus = "" ;
+
+ switch ( peer->status ) {
+ case 0 : cStatus = ' ' ; pStatus = "Reject" ; break ;
+ case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ;
+ case 2 : cStatus = '.' ; pStatus = "Excess" ; break ;
+ case 3 : cStatus = '-' ; pStatus = "Outlier" ; break ;
+ case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ;
+ case 5 : cStatus = '#' ; pStatus = "Selected" ; break ;
+ case 6 : cStatus = '*' ; pStatus = "Sys.Peer" ; break ;
+ case 7 : cStatus = 'o' ; pStatus = "PPS.Peer" ; break ;
+ default : break ;
+ }
+
+ snprintf ( sLog, sizeof(sLog),
+ "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.",
+ peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
}
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 1 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* dcst<CR><LF> VALID<CR><LF> or INVALID<CR><LF> */
+/* stus<CR><LF> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */
+/* date<CR><LF> YYYY/MM/DD XXX<CR><LF> XXX is the day of the week */
+/* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */
+/* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */
+/* */
+/*################################################################################################*/
+
+#define TS_JJY01_COMMAND_NUMBER_DATE 1
+#define TS_JJY01_COMMAND_NUMBER_TIME 2
+#define TS_JJY01_COMMAND_NUMBER_STIM 3
+#define TS_JJY01_COMMAND_NUMBER_STUS 4
+#define TS_JJY01_COMMAND_NUMBER_DCST 5
+
+#define TS_JJY01_REPLY_DATE "yyyy/mm/dd www"
+#define TS_JJY01_REPLY_STIM "hh:mm:ss"
+#define TS_JJY01_REPLY_STUS_ADJUSTED "adjusted"
+#define TS_JJY01_REPLY_STUS_UNADJUSTED "unadjusted"
+#define TS_JJY01_REPLY_DCST_VALID "valid"
+#define TS_JJY01_REPLY_DCST_INVALID "invalid"
+
+#define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED 8 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED 10 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */
+#define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */
+
+static struct
+{
+ const char commandNumber ;
+ const char *command ;
+ int commandLength ;
+ int iExpectedReplyLength [ 2 ] ;
+} tristate_jjy01_command_sequence[] =
+{
+ { 0, NULL, 0, { 0, 0 } }, /* Idle */
+ { TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID , TS_JJY01_REPLY_LENGTH_DCST_INVALID } },
+ { TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } },
+ { TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME , TS_JJY01_REPLY_LENGTH_TIME } },
+ { TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE , TS_JJY01_REPLY_LENGTH_DATE } },
+ { TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM , TS_JJY01_REPLY_LENGTH_STIM } },
+ /* End of command */
+ { 0, NULL, 0, { 0, 0 } }
+} ;
+
/**************************************************************************************************/
static int
-jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
+jjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up )
{
-#ifdef DEBUG
- static const char *sFunctionName = "jjy_receive_tristate_jjy01" ;
-#endif
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ;
+
+ up->unittype = UNITTYPE_TRISTATE_JJY01 ;
+ up->linespeed = SPEED232_TRISTATE_JJY01 ;
+ up->linediscipline = LDISC_CLK ;
+
+ return 0 ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
+{
struct jjyunit *up ;
struct refclockproc *pp ;
struct peer *peer;
- char *pBuf ;
+ char *pBuf, sLog [ 100 ] ;
int iLen ;
int rc ;
- int bOverMidnight = 0 ;
-
- char sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ;
-
const char *pCmd ;
int iCmdLen ;
- /*
- * Initialize pointers and read the timecode and timestamp
- */
+ /* Initialize pointers */
+
peer = rbufp->recv_peer ;
pp = peer->procptr ;
up = pp->unitptr ;
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
pBuf = pp->a_lastcode ;
iLen = pp->lencode ;
}
- switch ( tristate_jjy01_command_sequence[up->linecount-1].commandNumber ) {
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ;
- case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
+ /* Check expected reply */
- if ( iLen != TS_JJY01_REPLY_LENGTH_DATE ) {
- up->lineerror = 1 ;
- break ;
- }
+ if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence has not been started, or has been completed */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- 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 ) {
- up->lineerror = 1 ;
- break ;
- }
+ /* Check reply length */
- /*** 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".
- */
+ if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0]
+ && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- /*** 2010/11/20 ***/
- /*
- * Codes of a next command issue are moved to the end of this function.
- */
+ /* Parse reply */
+
+ switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) {
+
+ case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */
- /*** End of modification ***/
+ rc = sscanf ( pBuf, "%4d/%2d/%2d",
+ &up->year, &up->month, &up->day ) ;
+
+ if ( rc != 3 || up->year < 2000 || 2099 <= up->year
+ || up->month < 1 || 12 < up->month
+ || up->day < 1 || 31 < up->day ) {
+ /* Invalid date */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
+ rc, up->year, up->month, up->day ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
break ;
case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */
- if ( iLen != TS_JJY01_REPLY_LENGTH_STIM ) {
- up->lineerror = 1 ;
- break ;
+ if ( up->iTimestampCount >= 2 ) {
+ /* Too many time reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
+ up->iTimestampCount ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
- rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour,
- &up->minute, &up->second ) ;
+ rc = sscanf ( pBuf, "%2d:%2d:%2d",
+ &up->hour, &up->minute, &up->second ) ;
+
if ( rc != 3 || up->hour > 23 || up->minute > 59 ||
up->second > 60 ) {
- up->lineerror = 1 ;
- break ;
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
+ up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
+
+ up->iTimestampCount++ ;
+
up->msecond = 0 ;
- if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
- /*
- * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver separately,
- * and the JJY receiver replies a date and time separately.
- * Just after midnight transitions, we ignore this time.
- */
- bOverMidnight = 1 ;
- }
+
break ;
case TS_JJY01_COMMAND_NUMBER_STUS :
- if ( ( iLen == TS_JJY01_REPLY_LENGTH_STUS_YES
- && strncmp( pBuf, TS_JJY01_REPLY_STUS_YES,
- TS_JJY01_REPLY_LENGTH_STUS_YES ) == 0 )
- || ( iLen == TS_JJY01_REPLY_LENGTH_STUS_NO
- && strncmp( pBuf, TS_JJY01_REPLY_STUS_NO,
- TS_JJY01_REPLY_LENGTH_STUS_NO ) == 0 ) ) {
+ if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED,
+ TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0
+ || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED,
+ TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) {
/* Good */
} else {
- up->lineerror = 1 ;
- break ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
break ;
case TS_JJY01_COMMAND_NUMBER_DCST :
- if ( ( iLen == TS_JJY01_REPLY_LENGTH_DCST_VALID
- && strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
- TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 )
- || ( iLen == TS_JJY01_REPLY_LENGTH_DCST_INVALID
- && strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
- TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) ) {
+ if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID,
+ TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0
+ || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID,
+ TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) {
/* Good */
} else {
- up->lineerror = 1 ;
- break ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
break ;
default : /* Unexpected reply */
- up->lineerror = 1 ;
- break ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
- /* Clockstats Log */
+ if ( up->iTimestampCount == 2 ) {
+ /* Process date and time */
+
+ if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
+ && up->iTimestamp[0] <= up->iTimestamp[1] ) {
+ /* 3 commands (time,date,stim) was excuted in two seconds */
+ jjy_synctime( peer, pp, up ) ;
+ return JJY_RECEIVE_DONE ;
+ } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
+ /* Over midnight, and date is unsure */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ return JJY_RECEIVE_SKIP ;
+ } else {
+ /* Slow reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
- snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
- up->linecount,
- tristate_jjy01_command_sequence[up->linecount-1].commandLog,
- ( up->lineerror == 0 )
- ? ( ( bOverMidnight == 0 )
- ? 'O'
- : 'S' )
- : 'X',
- sReplyText ) ;
- record_clock_stats ( &peer->srcadr, sLogText ) ;
+ }
- /* Check before issue next command */
+ /* Issue next command */
- if ( up->lineerror != 0 ) {
- /* Do not issue next command */
- return 0 ;
+ if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) {
+ up->iCommandSeq ++ ;
}
- if ( bOverMidnight != 0 ) {
- /* Do not issue next command */
- return 0 ;
+ if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence completed */
+ return JJY_RECEIVE_DONE ;
}
- if ( tristate_jjy01_command_sequence[up->linecount].command == NULL ) {
- /* Command sequence completed */
- return 1 ;
+ pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
+ if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
}
- /* Issue next command */
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return JJY_RECEIVE_WAIT ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
+{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
+#endif
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ const char *pCmd ;
+ int iCmdLen ;
+
+ pp = peer->procptr;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+ up->iTimestampCount = 0 ;
+
+ if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
+ /* Skip "dcst" and "stus" commands */
+ up->iCommandSeq = 2 ;
+ up->iLineCount = 2 ;
+ }
#ifdef DEBUG
if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '%s'\n",
- sFunctionName, tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
+ printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
+ sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
+ up->iLineCount ) ;
}
#endif
- pCmd = tristate_jjy01_command_sequence[up->linecount].command ;
- iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
+ /*
+ * Send a first command
+ */
+
+ up->iCommandSeq ++ ;
+
+ pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ;
if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
refclock_report ( peer, CEVNT_FAULT ) ;
}
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The C-DEX Co. Ltd. JJY receiver JST2000 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 2 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> J is a fixed character */
+/* */
+/*################################################################################################*/
+
+static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] =
+{
+ { "\x03", 1 }, { NULL, 0 }
+} ;
+
+/**************************************************************************************************/
+
+static int
+jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ;
+
+ up->unittype = UNITTYPE_CDEX_JST2000 ;
+ up->linespeed = SPEED232_CDEX_JST2000 ;
+ up->linediscipline = LDISC_RAW ;
+
+ up->pRawBreak = cdex_jst2000_raw_break ;
+ up->bWaitBreakString = TRUE ;
+
+ up->bSkipCntrlCharOnly = FALSE ;
+
return 0 ;
}
@@ -929,78 +1445,161 @@ jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp )
static int
jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
{
-#ifdef DEBUG
- static const char *sFunctionName = "jjy_receive_cdex_jst2000" ;
-#endif
struct jjyunit *up ;
struct refclockproc *pp ;
- struct peer *peer;
+ struct peer *peer ;
- char *pBuf ;
+ char *pBuf, sLog [ 100 ] ;
int iLen ;
int rc ;
- /*
- * Initialize pointers and read the timecode and timestamp
- */
+ /* Initialize pointers */
+
peer = rbufp->recv_peer ;
pp = peer->procptr ;
up = pp->unitptr ;
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
pBuf = pp->a_lastcode ;
iLen = pp->lencode ;
}
- switch ( up->linecount ) {
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ;
- case 1 : /* JYYMMDD HHMMSSS */
+ /* Check expected reply */
- 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 ;
- }
- rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d",
- &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 ;
- }
- up->year += 2000 ;
- up->msecond *= 100 ;
- break ;
+ if ( up->iCommandSeq != 1 ) {
+ /* Command sequence has not been started, or has been completed */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- default : /* Unexpected reply */
+ /* Wait until ETX comes */
- up->lineerror = 1 ;
- break ;
+ if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) {
+ return JJY_RECEIVE_UNPROCESS ;
+ }
+
+ /* Check reply length */
+ if ( iLen != 15 ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
- return 1 ;
+ /* JYYMMDD HHMMSSS */
+
+ rc = sscanf ( pBuf, "J%2d%2d%2d %2d%2d%2d%1d",
+ &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 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ up->year += 2000 ;
+ up->msecond *= 100 ;
+
+ jjy_synctime( peer, pp, up ) ;
+
+ return JJY_RECEIVE_DONE ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+ up->iRawBufLen = 0 ;
+ up->iLineBufLen = 0 ;
+ up->iTextBufLen = 0 ;
+
+ /*
+ * Send "<ENQ>1J<ETX>" command
+ */
+
+ up->iCommandSeq ++ ;
+
+ if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The Echo Keisokuki Co. Ltd. JJY receiver LT2000 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 3 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* # Mode 1 ( Request & Send ) */
+/* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */
+/* C Mode 2 ( Continuous ) */
+/* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> 0.5 sec before time stamp */
+/* <SUB> Second signal */
+/* */
+/*################################################################################################*/
+
+#define ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1
+#define ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 2
+#define ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 3
+
+#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND "#"
+#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME "T"
+#define ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS "C"
+
+/**************************************************************************************************/
+
+static int
+jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ;
+
+ up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ;
+ up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ;
+ up->linediscipline = LDISC_CLK ;
+
+ up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ;
+
+ return 0 ;
}
@@ -1009,157 +1608,211 @@ jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp )
static int
jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
{
-#ifdef DEBUG
- static const char *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ;
-#endif
struct jjyunit *up ;
struct refclockproc *pp ;
struct peer *peer;
- char *pBuf ;
+ char *pBuf, sLog [ 100 ], sErr [ 60 ] ;
int iLen ;
int rc ;
int i, ibcc, ibcc1, ibcc2 ;
- /*
- * Initialize pointers and read the timecode and timestamp
- */
+ /* Initialize pointers */
+
peer = rbufp->recv_peer ;
pp = peer->procptr ;
up = pp->unitptr ;
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
pBuf = pp->a_lastcode ;
iLen = pp->lencode ;
}
- switch ( up->linecount ) {
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ;
+
+ /* Check reply length */
+
+ if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
+ && iLen != 15 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
+ && iLen != 17 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
+ && iLen != 17 ) ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
+ if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) {
+ /* YYMMDDWHHMMSS<BCC1><BCC2> */
- 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", __func__ ) ;
- }
-#endif
- if ( write ( pp->io.fd, "#",1 ) != 1 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
- }
- }
- up->lineerror = 1 ;
- break ;
+ for ( i = ibcc = 0 ; i < 13 ; i ++ ) {
+ ibcc ^= pBuf[i] ;
}
- if ( up->operationmode == 1 ) {
+ ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ;
+ ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ;
+ if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) {
+ snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ",
+ pBuf[13] & 0xFF, pBuf[14] & 0xFF,
+ ibcc1, ibcc2 ) ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ sErr ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- 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 ;
- }
+ }
- }
+ if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND
+ && iLen == 15 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
+ && iLen == 17 )
+ || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS
+ && iLen == 17 ) ) {
+ /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */
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 ;
+
+ if ( rc != 6 || up->month < 1 || up->month > 12
+ || up->day < 1 || up->day > 31
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
up->year += 2000 ;
- if ( up->operationmode == 2 ) {
+ if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS
+ || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
+ /* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */
- /* 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 ) ;
+ up->second -- ;
+ if ( up->second < 0 ) {
+ up->second = 59 ;
+ up->minute -- ;
+ if ( up->minute < 0 ) {
+ up->minute = 59 ;
+ up->hour -- ;
+ if ( up->hour < 0 ) {
+ up->hour = 23 ;
+ up->day -- ;
+ if ( up->day < 1 ) {
+ up->month -- ;
+ if ( up->month < 1 ) {
+ up->month = 12 ;
+ up->year -- ;
+ }
}
}
}
}
- /* 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 ;
+ jjy_synctime( peer, pp, up ) ;
- default : /* Unexpected reply */
-#ifdef DEBUG
- if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '#'\n",
- sFunctionName ) ;
- }
-#endif
- if ( write ( pp->io.fd, "#",1 ) != 1 ) {
+ }
+
+ if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) {
+ /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */
+
+ iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
+ if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen ) {
refclock_report ( peer, CEVNT_FAULT ) ;
}
- up->lineerror = 1 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ;
+
+ }
+
+ return JJY_RECEIVE_DONE ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ char sCmd[2] ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+
+ /*
+ * Send "T" or "C" command
+ */
+
+ switch ( up->operationmode ) {
+ case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND :
+ sCmd[0] = 'T' ;
+ break ;
+ case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS :
+ case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS :
+ sCmd[0] = 'C' ;
break ;
+ }
+ sCmd[1] = 0 ;
+ if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
}
- return 1 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 4 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* 'XX YY/MM/DD W HH:MM:SS<CR> XX:OK|NG|ER W:0(Mon)-6(Sun) */
+/* */
+/*################################################################################################*/
+
+static int
+jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ;
+
+ up->unittype = UNITTYPE_CITIZENTIC_JJY200 ;
+ up->linespeed = SPEED232_CITIZENTIC_JJY200 ;
+ up->linediscipline = LDISC_CLK ;
+
+ return 0 ;
}
@@ -1168,93 +1821,179 @@ jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp )
static int
jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp )
{
-#ifdef DEBUG
- static const char *sFunctionName = "jjy_receive_citizentic_jjy200" ;
-#endif
struct jjyunit *up ;
struct refclockproc *pp ;
struct peer *peer;
- char *pBuf ;
+ char *pBuf, sLog [ 100 ], sMsg [ 16 ] ;
int iLen ;
int rc ;
char cApostrophe, sStatus[3] ;
int iWeekday ;
- /*
- * Initialize pointers and read the timecode and timestamp
- */
+ /* Initialize pointers */
+
peer = rbufp->recv_peer ;
pp = peer->procptr ;
up = pp->unitptr ;
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
pBuf = pp->a_lastcode ;
iLen = pp->lencode ;
}
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ;
+
/*
- * JJY-200 sends a timestamp every second.
- * So, a timestamp is ignored unless it is right after polled.
- */
- if ( ! up->bPollFlag )
- return 0 ;
+ * JJY-200 sends a timestamp every second.
+ * So, a timestamp is ignored unless it is right after polled.
+ */
- switch ( up->linecount ) {
+ if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
+ return JJY_RECEIVE_SKIP ;
+ }
- case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */
+ /* Check reply length */
- if ( iLen != 23 ) {
-#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n",
- sFunctionName, iLen ) ;
- }
-#endif
- up->lineerror = 1 ;
- break ;
- }
+ if ( iLen != 23 ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
- &cApostrophe, sStatus, &up->year,
- &up->month, &up->day, &iWeekday,
- &up->hour, &up->minute, &up->second ) ;
- sStatus[2] = 0 ;
- if ( rc != 9 || cApostrophe != '\'' ||
- strcmp( sStatus, "OK" ) != 0 || up->month < 1 ||
- up->month > 12 || up->day < 1 || up->day > 31 ||
- iWeekday > 6 || up->hour > 23 || up->minute > 59 ||
- up->second > 60 ) {
-#ifdef DEBUG
- if ( debug >= 2 ) {
- printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n",
- sFunctionName, rc, cApostrophe,
- sStatus, up->year, up->month,
- up->day, iWeekday, up->hour,
- up->minute, up->second ) ;
- }
-#endif
- up->lineerror = 1 ;
- break ;
- }
+ /* 'XX YY/MM/DD W HH:MM:SS<CR> */
+
+ rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d",
+ &cApostrophe, sStatus,
+ &up->year, &up->month, &up->day, &iWeekday,
+ &up->hour, &up->minute, &up->second ) ;
+ sStatus[2] = 0 ;
+
+ if ( rc != 9 || cApostrophe != '\''
+ || ( strcmp( sStatus, "OK" ) != 0
+ && strcmp( sStatus, "NG" ) != 0
+ && strcmp( sStatus, "ER" ) != 0 )
+ || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+ || iWeekday > 6
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ } else if ( strcmp( sStatus, "NG" ) == 0
+ || strcmp( sStatus, "ER" ) == 0 ) {
+ /* Timestamp is unsure */
+ snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE,
+ sMsg ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
+ return JJY_RECEIVE_SKIP ;
+ }
- up->year += 2000 ;
- up->msecond = 0 ;
+ up->year += 2000 ;
+ up->msecond = 0 ;
- break ;
+ jjy_synctime( peer, pp, up ) ;
- default : /* Unexpected reply */
+ return JJY_RECEIVE_DONE ;
- up->lineerror = 1 ;
- break ;
+}
- }
+/**************************************************************************************************/
- return 1 ;
+static void
+jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
+{
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The Tristate Ltd. GPS clock TS-GPS01 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 5 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* This clock has NMEA mode and command/respose mode. */
+/* When this jjy driver are used, set to command/respose mode of this clock */
+/* by the onboard switch SW4, and make sure the LED-Y is tured on. */
+/* Other than this JJY driver, the refclock driver type 20, generic NMEA driver, */
+/* works with the NMEA mode of this clock. */
+/* */
+/* Command Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* stus<CR><LF> *R|*G|*U|+U<CR><LF> */
+/* date<CR><LF> YY/MM/DD<CR><LF> */
+/* time<CR><LF> HH:MM:SS<CR><LF> */
+/* */
+/*################################################################################################*/
+
+#define TS_GPS01_COMMAND_NUMBER_DATE 1
+#define TS_GPS01_COMMAND_NUMBER_TIME 2
+#define TS_GPS01_COMMAND_NUMBER_STUS 4
+
+#define TS_GPS01_REPLY_DATE "yyyy/mm/dd"
+#define TS_GPS01_REPLY_TIME "hh:mm:ss"
+#define TS_GPS01_REPLY_STUS_RTC "*R"
+#define TS_GPS01_REPLY_STUS_GPS "*G"
+#define TS_GPS01_REPLY_STUS_UTC "*U"
+#define TS_GPS01_REPLY_STUS_PPS "+U"
+
+#define TS_GPS01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */
+#define TS_GPS01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */
+#define TS_GPS01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */
+
+static struct
+{
+ char commandNumber ;
+ const char *command ;
+ int commandLength ;
+ int iExpectedReplyLength ;
+} tristate_gps01_command_sequence[] =
+{
+ { 0, NULL, 0, 0 }, /* Idle */
+ { TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS },
+ { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
+ { TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE },
+ { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME },
+ /* End of command */
+ { 0, NULL, 0, 0 }
+} ;
+
+/**************************************************************************************************/
+
+static int
+jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ;
+
+ up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ;
+ up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ;
+ up->linediscipline = LDISC_CLK ;
+
+ return 0 ;
}
@@ -1271,35 +2010,31 @@ jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
struct refclockproc *pp ;
struct peer *peer;
- char *pBuf ;
+ char *pBuf, sLog [ 100 ] ;
int iLen ;
int rc ;
- int bOverMidnight = 0 ;
-
- char sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ;
-
const char *pCmd ;
int iCmdLen ;
- /*
- * Initialize pointers and read the timecode and timestamp
- */
+ /* Initialize pointers */
+
peer = rbufp->recv_peer ;
pp = peer->procptr ;
up = pp->unitptr ;
if ( up->linediscipline == LDISC_RAW ) {
- pBuf = up->rawbuf ;
- iLen = up->charcount ;
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
} else {
pBuf = pp->a_lastcode ;
iLen = pp->lencode ;
}
- /*
- * Ignore NMEA data stream
- */
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ;
+
+ /* Ignore NMEA data stream */
+
if ( iLen > 5
&& ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) {
#ifdef DEBUG
@@ -1308,14 +2043,14 @@ jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
sFunctionName, pBuf ) ;
}
#endif
- return 0 ;
+ return JJY_RECEIVE_WAIT ;
}
/*
* Skip command prompt '$Cmd>' from the TS-GPSclock-01
*/
if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
- return 0 ;
+ return JJY_RECEIVE_WAIT ;
} else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) {
pBuf += 5 ;
iLen -= 5 ;
@@ -1332,363 +2067,2343 @@ jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp )
sFunctionName, pBuf ) ;
}
#endif
- return 0 ;
+ return JJY_RECEIVE_WAIT ;
}
- switch ( tristate_gpsclock01_command_sequence[up->linecount-1].commandNumber ) {
+ /* Check expected reply */
- case TS_GPSCLOCK01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence has not been started, or has been completed */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_DATE ) {
- up->lineerror = 1 ;
- break ;
- }
+ /* Check reply length */
+
+ if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) {
+ /* Unexpected reply length */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ /* Parse reply */
+
+ switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) {
+
+ case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */
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 ) {
- up->lineerror = 1 ;
- break ;
+
+ if ( rc != 3 || up->year < 2000 || 2099 <= up->year
+ || up->month < 1 || 12 < up->month
+ || up->day < 1 || 31 < up->day ) {
+ /* Invalid date */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
+ rc, up->year, up->month, up->day ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
break ;
- case TS_GPSCLOCK01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
+ case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */
- if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_TIME ) {
- up->lineerror = 1 ;
- break ;
+ if ( up->iTimestampCount >= 2 ) {
+ /* Too many time reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY,
+ up->iTimestampCount ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
- rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ;
- if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
- 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 ) {
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
- up->msecond = 0 ;
+ up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
- if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) {
- /*
- * The command "date" and "time" were sent to the JJY receiver separately,
- * and the JJY receiver replies a date and time separately.
- * Just after midnight transitions, we ignore this time.
- */
- bOverMidnight = 1 ;
- }
+ up->iTimestampCount++ ;
+
+ up->msecond = 0 ;
break ;
- case TS_GPSCLOCK01_COMMAND_NUMBER_STUS :
+ case TS_GPS01_COMMAND_NUMBER_STUS :
- if ( iLen == TS_GPSCLOCK01_REPLY_LENGTH_STUS
- && ( strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_RTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
- || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_GPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
- || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_UTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0
- || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_PPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 ) ) {
+ if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
+ || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0
+ || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0
+ || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) {
/* Good */
} else {
- up->lineerror = 1 ;
- break ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
break ;
default : /* Unexpected reply */
- up->lineerror = 1 ;
- break ;
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
}
- /* Clockstats Log */
-
- printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ;
- snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s",
- up->linecount,
- tristate_gpsclock01_command_sequence[up->linecount-1].commandLog,
- ( up->lineerror == 0 )
- ? ( ( bOverMidnight == 0 )
- ? 'O'
- : 'S' )
- : 'X',
- sReplyText ) ;
- record_clock_stats ( &peer->srcadr, sLogText ) ;
+ if ( up->iTimestampCount == 2 ) {
+ /* Process date and time */
+
+ if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0]
+ && up->iTimestamp[0] <= up->iTimestamp[1] ) {
+ /* 3 commands (time,date,stim) was excuted in two seconds */
+ jjy_synctime( peer, pp, up ) ;
+ return JJY_RECEIVE_DONE ;
+ } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) {
+ /* Over midnight, and date is unsure */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ return JJY_RECEIVE_SKIP ;
+ } else {
+ /* Slow reply */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2,
+ up->iTimestamp[0], up->iTimestamp[1] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
- /* Check before issue next command */
+ }
- if ( up->lineerror != 0 ) {
- /* Do not issue next command */
- return 0 ;
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
+ /* Command sequence completed */
+ jjy_synctime( peer, pp, up ) ;
+ return JJY_RECEIVE_DONE ;
}
- if ( bOverMidnight != 0 ) {
- /* Do not issue next command */
- return 0 ;
+ /* Issue next command */
+
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) {
+ up->iCommandSeq ++ ;
}
- if ( tristate_gpsclock01_command_sequence[up->linecount].command == NULL ) {
+ if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) {
/* Command sequence completed */
- return 1 ;
+ up->iProcessState = JJY_PROCESS_STATE_DONE ;
+ return JJY_RECEIVE_DONE ;
}
- /* Issue next command */
+ pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
+ if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report ( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return JJY_RECEIVE_WAIT ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
+{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
+#endif
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ const char *pCmd ;
+ int iCmdLen ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->iTimestampCount = 0 ;
+
+ if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
+ /* Skip "stus" command */
+ up->iCommandSeq = 1 ;
+ up->iLineCount = 1 ;
+ }
#ifdef DEBUG
if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '%s'\n",
- sFunctionName, tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
+ printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n",
+ sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
+ up->iLineCount ) ;
}
#endif
- pCmd = tristate_gpsclock01_command_sequence[up->linecount].command ;
- iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
+ /*
+ * Send a first command
+ */
+
+ up->iCommandSeq ++ ;
+
+ pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ;
+ iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ;
if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
refclock_report ( peer, CEVNT_FAULT ) ;
}
- return 0 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
}
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## The SEIKO TIME SYSTEMS TDC-300 ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 6 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Type Response Remarks */
+/* -------------------- ---------------------------------------- ---------------------------- */
+/* Type 1 <STX>HH:MM:SS<ETX> */
+/* Type 2 <STX>YYMMDDHHMMSSWLSCU<ETX> W:0(Sun)-6(Sat) */
+/* Type 3 <STX>YYMMDDWHHMMSS<ETX> W:0(Sun)-6(Sat) */
+/* <STX><xE5><ETX> 5 to 10 mSec. before second */
+/* */
+/*################################################################################################*/
+
+static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] =
+{
+ { "\x03", 1 }, { NULL, 0 }
+} ;
+
/**************************************************************************************************/
-/* jjy_poll - called by the transmit procedure */
+
+static int
+jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up )
+{
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ;
+
+ up->unittype = UNITTYPE_SEIKO_TIMESYS_TDC_300 ;
+ up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ;
+ up->linediscipline = LDISC_RAW ;
+
+ up->pRawBreak = seiko_tsys_tdc_300_raw_break ;
+ up->bWaitBreakString = TRUE ;
+
+ up->bSkipCntrlCharOnly = FALSE ;
+
+ return 0 ;
+
+}
+
/**************************************************************************************************/
-static void
-jjy_poll ( int unit, struct peer *peer )
+
+static int
+jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp )
{
- struct jjyunit *up;
- struct refclockproc *pp;
+ struct peer *peer;
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
- pp = peer->procptr;
+ char *pBuf, sLog [ 100 ] ;
+ int iLen, i ;
+ int rc, iWeekday ;
+ time_t now ;
+ struct tm *pTime ;
+
+ /* Initialize pointers */
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
up = pp->unitptr ;
- if ( pp->polls > 0 && up->linecount == 0 ) {
- /*
- * No reply for last command
- */
- refclock_report ( peer, CEVNT_TIMEOUT ) ;
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
}
-#ifdef DEBUG
- if ( debug ) {
- printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ;
+ DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ;
+
+ /*
+ * TDC-300 sends a timestamp every second.
+ * So, a timestamp is ignored unless it is right after polled.
+ */
+
+ if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) {
+ return JJY_RECEIVE_SKIP ;
}
-#endif
- pp->polls ++ ;
+ /* Process timestamp */
- up->bPollFlag = 1 ;
- up->linecount = 0 ;
- up->lineerror = 0 ;
- up->charcount = 0 ;
+ up->iReceiveSeq ++ ;
- switch ( up->unittype ) {
-
- case UNITTYPE_TRISTATE_JJY01 :
- jjy_poll_tristate_jjy01 ( unit, peer ) ;
- break ;
+ switch ( iLen ) {
- case UNITTYPE_CDEX_JST2000 :
- jjy_poll_cdex_jst2000 ( unit, peer ) ;
- break ;
+ case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */
- case UNITTYPE_ECHOKEISOKUKI_LT2000 :
- jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ;
- break ;
+ for ( i = 0 ; i < iLen ; i ++ ) {
+ pBuf[i] &= 0x7F ;
+ }
+
+ rc = sscanf ( pBuf+1, "%2d:%2d:%2d",
+ &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 3
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ } else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) {
+ /* Uncertainty date guard */
+ return JJY_RECEIVE_WAIT ;
+ }
+
+ time( &now ) ;
+ pTime = localtime( &now ) ;
+ up->year = pTime->tm_year ;
+ up->month = pTime->tm_mon + 1 ;
+ up->day = pTime->tm_mday ;
- case UNITTYPE_CITIZENTIC_JJY200 :
- jjy_poll_citizentic_jjy200 ( unit, peer ) ;
break ;
- case UNITTYPE_TRISTATE_GPSCLOCK01 :
- jjy_poll_tristate_gpsclock01 ( unit, peer ) ;
+ case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */
+
+ for ( i = 0 ; i < iLen ; i ++ ) {
+ pBuf[i] &= 0x7F ;
+ }
+
+ rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d",
+ &up->year, &up->month, &up->day,
+ &up->hour, &up->minute, &up->second, &iWeekday ) ;
+
+ if ( rc != 7
+ || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+ || iWeekday > 6
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
break ;
- default :
+ case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */
+
+ rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d",
+ &up->year, &up->month, &up->day, &iWeekday,
+ &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 7
+ || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31
+ || iWeekday > 6
+ || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid date and time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME,
+ rc, up->year, up->month, up->day,
+ up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
+ return JJY_RECEIVE_WAIT ;
+
+ case 1 : /* Type 3 : <STX><xE5><ETX> */
+
+ if ( ( *pBuf & 0xFF ) != 0xE5 ) {
+ /* Invalid second signal */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY,
+ up->sLineBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ } else if ( up->iReceiveSeq == 1 ) {
+ /* Wait for next timestamp */
+ up->iReceiveSeq -- ;
+ return JJY_RECEIVE_WAIT ;
+ } else if ( up->iReceiveSeq >= 3 ) {
+ /* Unexpected second signal */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ up->sLineBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+ }
+
break ;
+ default : /* Unexpected reply length */
+
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH,
+ iLen ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ return JJY_RECEIVE_ERROR ;
+
}
+ up->year += 2000 ;
+ up->msecond = 0 ;
+
+ jjy_synctime( peer, pp, up ) ;
+
+ return JJY_RECEIVE_DONE ;
+
}
/**************************************************************************************************/
static void
-jjy_poll_tristate_jjy01 ( int unit, struct peer *peer )
+jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer )
{
-#ifdef DEBUG
- static const char *sFunctionName = "jjy_poll_tristate_jjy01" ;
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ up->bLineError = FALSE ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## Telephone JJY ##*/
+/*## ##*/
+/*## server 127.127.40.X mode 100 to 180 ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+/* */
+/* Prompt Command Response Remarks */
+/* -------------------- -------------------- -------------------- -------------------------- */
+/* Name<SP>?<SP> TJJY<CR> Welcome messages TJJY is a guest user ID */
+/* > 4DATE<CR> YYYYMMDD<CR> */
+/* > LEAPSEC<CR> XX<CR> One of <SP>0, +1, -1 */
+/* > TIME<CR> HHMMSS<CR> 3 times on second */
+/* > BYE<CR> Sayounara messages */
+/* */
+/*################################################################################################*/
+
+static struct jjyRawDataBreak teljjy_raw_break [ ] =
+{
+ { "\r\n", 2 },
+ { "\r" , 1 },
+ { "\n" , 1 },
+ { "Name ? ", 7 },
+ { ">" , 1 },
+ { "+++" , 3 },
+ { NULL , 0 }
+} ;
+
+#define TELJJY_STATE_IDLE 0
+#define TELJJY_STATE_DAILOUT 1
+#define TELJJY_STATE_LOGIN 2
+#define TELJJY_STATE_CONNECT 3
+#define TELJJY_STATE_BYE 4
+
+#define TELJJY_EVENT_NULL 0
+#define TELJJY_EVENT_START 1
+#define TELJJY_EVENT_CONNECT 2
+#define TELJJY_EVENT_DISCONNECT 3
+#define TELJJY_EVENT_COMMAND 4
+#define TELJJY_EVENT_LOGIN 5 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_PROMPT 6 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_DATA 7 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_ERROR 8 /* Posted by the jjy_receive_telephone */
+#define TELJJY_EVENT_SILENT 9 /* Posted by the jjy_timer_telephone */
+#define TELJJY_EVENT_TIMEOUT 10 /* Posted by the jjy_timer_telephone */
+
+static void teljjy_control ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+
+static int teljjy_idle_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_idle_dialout ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_dial_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_dial_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_dial_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_conn ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_login_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_send ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_data ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_conn_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_bye_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_bye_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+static int teljjy_bye_modem ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ;
+
+static int ( *pTeljjyHandler [ ] [ 5 ] ) ( ) =
+{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
+/* NULL */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
+/* START */ { teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
+/* CONNECT */ { teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore },
+/* DISCONNECT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_disc , teljjy_conn_disc , teljjy_bye_disc },
+/* COMMAND */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem },
+/* LOGIN */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore },
+/* PROMPT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn , teljjy_conn_send , teljjy_bye_ignore },
+/* DATA */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data , teljjy_bye_ignore },
+/* ERROR */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore },
+/* SILENT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore },
+/* TIMEOUT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem }
+} ;
+
+static short iTeljjyNextState [ ] [ 5 ] =
+{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
+/* NULL */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* START */ { TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* CONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_LOGIN , TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* DISCONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE },
+/* COMMAND */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* LOGIN */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
+/* PROMPT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE , TELJJY_STATE_BYE },
+/* DATA */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* ERROR */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE },
+/* SILENT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE },
+/* TIMEOUT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE }
+} ;
+
+static short iTeljjyPostEvent [ ] [ 5 ] =
+{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */
+/* NULL */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* START */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* CONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* DISCONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* COMMAND */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* LOGIN */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
+/* PROMPT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
+/* DATA */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* ERROR */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL },
+/* SILENT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL },
+/* TIMEOUT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }
+} ;
+
+static short iTeljjySilentTimeout [ 5 ] = { 0, 0, 10, 5, 0 } ;
+static short iTeljjyStateTimeout [ 5 ] = { 0, 120, 60, 60, 40 } ;
+
+#define TELJJY_STAY_CLOCK_STATE 0
+#define TELJJY_CHANGE_CLOCK_STATE 1
+
+/* Command and replay */
+
+#define TELJJY_REPLY_NONE 0
+#define TELJJY_REPLY_4DATE 1
+#define TELJJY_REPLY_TIME 2
+#define TELJJY_REPLY_LEAPSEC 3
+#define TELJJY_REPLY_LOOP 4
+#define TELJJY_REPLY_PROMPT 5
+#define TELJJY_REPLY_LOOPBACK 6
+#define TELJJY_REPLY_COM 7
+
+#define TELJJY_COMMAND_START_SKIP_LOOPBACK 7
+
+static struct
+{
+ const char *command ;
+ int commandLength ;
+ int iEchobackReplyLength ;
+ int iExpectedReplyType ;
+ int iExpectedReplyLength ;
+} teljjy_command_sequence[] =
+{
+ { NULL, 0, 0, 0, 0 }, /* Idle */
+ { "LOOP\r" , 5, 4, TELJJY_REPLY_LOOP , 0 }, /* Getting into loopback mode */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */
+ { "COM\r" , 4, 3, TELJJY_REPLY_COM , 0 }, /* Exit from loopback mode */
+ /* TELJJY_COMMAND_START_SKIP_LOOPBACK */
+ { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
+ { "4DATE\r" , 6, 5, TELJJY_REPLY_4DATE , 8 },
+ { "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 },
+ { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 },
+ { "BYE\r" , 4, 3, TELJJY_REPLY_NONE , 0 },
+ /* End of command */
+ { NULL, 0, 0, 0, 0 }
+} ;
+
+#define TELJJY_LOOPBACK_DELAY_THRESHOLD 700 /* Milli second */
+
+#ifdef DEBUG
+#define DEBUG_TELJJY_PRINTF(sFunc) { if ( debug ) { printf ( "refclock_jjy.c : %s : iClockState=%d iClockEvent=%d iTeljjySilentTimer=%d iTeljjyStateTimer=%d iClockCommandSeq=%d\n", sFunc, up->iClockState, up->iClockEvent, up->iTeljjySilentTimer, up->iTeljjyStateTimer, up->iClockCommandSeq ) ; } }
+#else
+#define DEBUG_TELJJY_PRINTF(sFunc)
#endif
- struct jjyunit *up;
- struct refclockproc *pp;
+/**************************************************************************************************/
- const char *pCmd ;
- int iCmdLen ;
+static int
+jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up )
+{
- pp = peer->procptr;
- up = pp->unitptr ;
+ char sLog [ 80 ], sFirstThreeDigits [ 4 ] ;
+ int i, iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ;
+ int iFirstThreeDigitsCount ;
- if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
- up->linecount = 2 ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ;
+
+ up->unittype = UNITTYPE_TELEPHONE ;
+ up->linespeed = SPEED232_TELEPHONE ;
+ up->linediscipline = LDISC_RAW ;
+
+ up->pRawBreak = teljjy_raw_break ;
+ up->bWaitBreakString = TRUE ;
+
+ up->bSkipCntrlCharOnly = TRUE ;
+
+ up->iClockState = TELJJY_STATE_IDLE ;
+ up->iClockEvent = TELJJY_EVENT_NULL ;
+
+ /* Check the telephone number */
+
+ if ( sys_phone[0] == NULL ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+
+ if ( sys_phone[1] != NULL ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+
+ iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ;
+ for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) {
+ if ( isdigit( *(sys_phone[0]+i) ) ) {
+ if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) {
+ sFirstThreeDigits[iFirstThreeDigitsCount++] = *(sys_phone[0]+i) ;
+ }
+ iNumberOfDigitsOfPhoneNumber ++ ;
+ } else if ( *(sys_phone[0]+i) == ',' ) {
+ iCommaCount ++ ;
+ if ( iCommaCount > 1 ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+ iFirstThreeDigitsCount = 0 ;
+ iCommaPosition = i ;
+ } else if ( *(sys_phone[0]+i) != '-' ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+ }
+ sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ;
+
+ if ( iCommaCount == 1 ) {
+ if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) {
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+ }
+
+ if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) {
+ /* Too short or too long */
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
+ }
+
+ if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0
+ || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0
+ || ( sFirstThreeDigits[0] == '0' && sFirstThreeDigits[2] == '0' ) ) {
+ /* Not allowed because of emergency numbers or special service numbers */
+ msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ;
+ up->bInitError = TRUE ;
+ return 1 ;
}
+ snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
+
+ if ( peer->minpoll < 8 ) {
+ /* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */
+ int oldminpoll = peer->minpoll ;
+ peer->minpoll = 8 ;
+ if ( peer->ppoll < peer->minpoll ) {
+ peer->ppoll = peer->minpoll ;
+ }
+ if ( peer->maxpoll < peer->minpoll ) {
+ peer->maxpoll = peer->minpoll ;
+ }
+ snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ;
+ }
+
+ return 0 ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+jjy_receive_telephone ( struct recvbuf *rbufp )
+{
#ifdef DEBUG
- if ( debug ) {
- printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
- sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
- up->linecount ) ;
+ static const char *sFunctionName = "jjy_receive_telephone" ;
+#endif
+
+ struct peer *peer;
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+ char *pBuf ;
+ int iLen ;
+ short iPreviousModemState ;
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_TELJJY_PRINTF( sFunctionName ) ;
+
+ if ( up->iClockState == TELJJY_STATE_IDLE
+ || up->iClockState == TELJJY_STATE_DAILOUT
+ || up->iClockState == TELJJY_STATE_BYE ) {
+
+ iPreviousModemState = getModemState( up ) ;
+
+ modem_receive ( rbufp ) ;
+
+ if ( iPreviousModemState != up->iModemState ) {
+ /* Modem state is changed just now. */
+ if ( isModemStateDisconnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
+ teljjy_control ( peer, pp, up ) ;
+ } else if ( isModemStateConnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_CONNECT ;
+ teljjy_control ( peer, pp, up ) ;
+ }
+ }
+
+ return JJY_RECEIVE_WAIT ;
+
}
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ up->iTeljjySilentTimer = 0 ;
+ if ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN ; }
+ else if ( iLen == 1 && strncmp( pBuf, ">" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; }
+ else if ( iLen >= 1 && strncmp( pBuf, "?" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR ; }
+ else { up->iClockEvent = TELJJY_EVENT_DATA ; }
+
+ teljjy_control ( peer, pp, up ) ;
+
+ return JJY_RECEIVE_WAIT ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_poll_telephone ( int unit, struct peer *peer )
+{
+#ifdef DEBUG
+ static const char *sFunctionName = "jjy_poll_telephone" ;
#endif
- /*
- * Send a first command
- */
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_TELJJY_PRINTF( sFunctionName ) ;
+
+ if ( up->iClockState == TELJJY_STATE_IDLE ) {
+ up->iRawBufLen = 0 ;
+ up->iLineBufLen = 0 ;
+ up->iTextBufLen = 0 ;
+ }
+
+ up->iClockEvent = TELJJY_EVENT_START ;
+ teljjy_control ( peer, pp, up ) ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+jjy_timer_telephone ( int unit, struct peer *peer )
+{
#ifdef DEBUG
- if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '%s'\n",
- sFunctionName,
- tristate_jjy01_command_sequence[up->linecount].commandLog ) ;
+ static const char *sFunctionName = "jjy_timer_telephone" ;
+#endif
+
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+ short iPreviousModemState ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_TELJJY_PRINTF( sFunctionName ) ;
+
+ if ( iTeljjySilentTimeout[up->iClockState] != 0 ) {
+ up->iTeljjySilentTimer++ ;
+ if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) {
+ up->iClockEvent = TELJJY_EVENT_SILENT ;
+ teljjy_control ( peer, pp, up ) ;
+ }
+ }
+
+ if ( iTeljjyStateTimeout[up->iClockState] != 0 ) {
+ up->iTeljjyStateTimer++ ;
+ if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) {
+ up->iClockEvent = TELJJY_EVENT_TIMEOUT ;
+ teljjy_control ( peer, pp, up ) ;
+ }
}
+
+ if ( isModemStateTimerOn( up ) ) {
+
+ iPreviousModemState = getModemState( up ) ;
+
+ modem_timer ( unit, peer ) ;
+
+ if ( iPreviousModemState != up->iModemState ) {
+ /* Modem state is changed just now. */
+ if ( isModemStateDisconnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_DISCONNECT ;
+ teljjy_control ( peer, pp, up ) ;
+ } else if ( isModemStateConnect( up->iModemState ) ) {
+ up->iClockEvent = TELJJY_EVENT_CONNECT ;
+ teljjy_control ( peer, pp, up ) ;
+ }
+ }
+
+ }
+
+}
+
+/**************************************************************************************************/
+
+static void
+teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ int i, rc ;
+ short iPostEvent = TELJJY_EVENT_NULL ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_control" ) ;
+
+ rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ;
+
+ if ( rc == TELJJY_CHANGE_CLOCK_STATE ) {
+ iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ;
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd iPostEvent=%hd\n",
+ up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ;
+ }
#endif
+ up->iTeljjySilentTimer = 0 ;
+ if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) {
+ /* Telephone JJY state is changing now */
+ up->iTeljjyStateTimer = 0 ;
+ up->bLineError = FALSE ;
+ up->iClockCommandSeq = 0 ;
+ up->iTimestampCount = 0 ;
+ up->iLoopbackCount = 0 ;
+ for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
+ up->bLoopbackTimeout[i] = FALSE ;
+ }
+ if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) {
+ /* Telephone JJY state is changing to IDLE just now */
+ up->iProcessState = JJY_PROCESS_STATE_DONE ;
+ }
+ }
+ up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ;
- pCmd = tristate_jjy01_command_sequence[up->linecount].command ;
- iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ;
- if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
}
+ if ( iPostEvent != TELJJY_EVENT_NULL ) {
+ up->iClockEvent = iPostEvent ;
+ teljjy_control ( peer, pp, up ) ;
+ }
+
+ up->iClockEvent = TELJJY_EVENT_NULL ;
+
}
/**************************************************************************************************/
static void
-jjy_poll_cdex_jst2000 ( int unit, struct peer *peer )
+teljjy_setDelay ( struct peer *peer, struct jjyunit *up )
{
- struct refclockproc *pp;
+ char sLog [ 60 ] ;
+ int milliSecond, microSecond ;
- pp = peer->procptr;
+ gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ;
- /*
- * Send "<ENQ>1J<ETX>" command
- */
+ up->delayTime[up->iLoopbackCount].tv_sec -= up->sendTime[up->iLoopbackCount].tv_sec ;
+ up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ;
+ if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) {
+ up->delayTime[up->iLoopbackCount].tv_sec -- ;
+ up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ;
+ }
+
+ milliSecond = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ;
+ microSecond = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ;
+ milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ;
+
+ snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY,
+ milliSecond, microSecond ) ;
+
+ if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) {
+ /* Delay > 700 mS */
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
+ } else {
+ /* Delay <= 700 mS */
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ }
+
+}
+
+/**************************************************************************************************/
+
+static int
+teljjy_getDelay ( struct peer *peer, struct jjyunit *up )
+{
+
+ struct timeval maxTime, minTime, averTime ;
+ int i ;
+ int minIndex = 0, maxIndex = 0, iAverCount = 0 ;
+ int iThresholdSecond, iThresholdMicroSecond ;
+ int iPercent ;
+
+ minTime.tv_sec = minTime.tv_usec = 0 ;
+ maxTime.tv_sec = maxTime.tv_usec = 0 ;
+
+ iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ;
+ iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ;
+ up->iLoopbackValidCount = 0 ;
+
+ for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
+ if ( up->bLoopbackTimeout[i]
+ || up->delayTime[i].tv_sec > iThresholdSecond
+ || ( up->delayTime[i].tv_sec == iThresholdSecond
+ && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
+ continue ;
+ }
+ if ( up->iLoopbackValidCount == 0 ) {
+ minTime.tv_sec = up->delayTime[i].tv_sec ;
+ minTime.tv_usec = up->delayTime[i].tv_usec ;
+ maxTime.tv_sec = up->delayTime[i].tv_sec ;
+ maxTime.tv_usec = up->delayTime[i].tv_usec ;
+ minIndex = maxIndex = i ;
+ } else if ( minTime.tv_sec > up->delayTime[i].tv_sec
+ || ( minTime.tv_sec == up->delayTime[i].tv_sec
+ && minTime.tv_usec > up->delayTime[i].tv_usec ) ) {
+ minTime.tv_sec = up->delayTime[i].tv_sec ;
+ minTime.tv_usec = up->delayTime[i].tv_usec ;
+ minIndex = i ;
+ } else if ( maxTime.tv_sec < up->delayTime[i].tv_sec
+ || ( maxTime.tv_sec == up->delayTime[i].tv_sec
+ && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) {
+ maxTime.tv_sec = up->delayTime[i].tv_sec ;
+ maxTime.tv_usec = up->delayTime[i].tv_usec ;
+ maxIndex = i ;
+ }
+ up->iLoopbackValidCount ++ ;
+ }
+
+ if ( up->iLoopbackValidCount < 2 ) {
+ return -1 ;
+ }
+
+ averTime.tv_usec = 0;
+
+ for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) {
+ if ( up->bLoopbackTimeout[i]
+ || up->delayTime[i].tv_sec > iThresholdSecond
+ || ( up->delayTime[i].tv_sec == iThresholdSecond
+ && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) {
+ continue ;
+ }
+ if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) {
+ continue ;
+ }
+ if ( up->iLoopbackValidCount >= 4 && i == minIndex ) {
+ continue ;
+ }
+ averTime.tv_usec += up->delayTime[i].tv_usec ;
+ iAverCount ++ ;
+ }
+
+ if ( iAverCount == 0 ) {
+ /* This is never happened. */
+ /* Previous for-if-for blocks assure iAverCount > 0. */
+ /* This code avoids a claim by the coverity scan tool. */
+ return -1 ;
+ }
+
+ /* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */
+
+ iPercent = ( peer->ttl - 100 ) ;
+
+ /* Average delay time in milli second */
+
+ return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ;
+
+}
+
+/******************************/
+static int
+teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ;
+
+ modem_connect ( peer->refclkunit, peer ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ int i ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ;
+
+ up->bLineError = FALSE ;
+ up->iClockCommandSeq = 0 ;
+ up->iTimestampCount = 0 ;
+ up->iLoopbackCount = 0 ;
+ for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
+ up->bLoopbackTimeout[i] = FALSE ;
+ }
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pCmd ;
+ int iCmdLen ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ;
+
+ /* Send a guest user ID */
+ pCmd = "TJJY\r" ;
+
+ /* Send login ID */
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ;
+
+ if ( write( pp->io.fd, "\r", 1 ) != 1 ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ;
+
+ up->iTeljjySilentTimer = 0 ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ const char *pCmd ;
+ int i, iLen, iNextClockState ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ;
+
+ if ( up->iClockCommandSeq > 0
+ && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) {
+ /* Command sequence has been completed */
+ return TELJJY_CHANGE_CLOCK_STATE ;
+ }
+
+ if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) {
+ /* Skip loopback */
+
+ up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ;
+
+ } else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) {
+ /* Loopback start */
+
+ up->iLoopbackCount = 0 ;
+ for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) {
+ up->bLoopbackTimeout[i] = FALSE ;
+ }
+
+ } else if ( up->iClockCommandSeq > 0 && peer->ttl != 100
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
+ && up->iLoopbackCount < MAX_LOOPBACK ) {
+ /* Loopback character comes */
#ifdef DEBUG
- if ( debug ) {
- printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ;
+ if ( debug ) {
+ printf( "refclock_jjy.c : teljjy_conn_send : iLoopbackCount=%d\n",
+ up->iLoopbackCount ) ;
+ }
+#endif
+
+ teljjy_setDelay( peer, up ) ;
+
+ up->iLoopbackCount ++ ;
+
}
+
+ up->iClockCommandSeq++ ;
+
+ pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ;
+ iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ;
+
+ if ( pCmd != NULL ) {
+
+ if ( write( pp->io.fd, pCmd, iLen ) != iLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
+ /* Loopback character and timestamp */
+ gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ;
+ up->bLoopbackMode = TRUE ;
+ } else {
+ /* Regular command */
+ up->bLoopbackMode = FALSE ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) {
+ /* Last command of the command sequence */
+ iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
+ } else {
+ /* More commands to be issued */
+ iNextClockState = TELJJY_STAY_CLOCK_STATE ;
+ }
+
+ } else {
+
+ iNextClockState = TELJJY_CHANGE_CLOCK_STATE ;
+
+ }
+
+ return iNextClockState ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pBuf ;
+ int iLen, rc ;
+ char sLog [ 80 ] ;
+ char bAdjustment ;
+
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
+ }
+
+ if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK
+ && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command)
+ && up->iLoopbackCount < MAX_LOOPBACK ) {
+ /* Loopback */
+
+ teljjy_setDelay( peer, up ) ;
+
+ up->iLoopbackCount ++ ;
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen
+ && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) {
+ /* Maybe echoback */
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ;
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) {
+ /* 4DATE<CR> -> YYYYMMDD<CR> */
+
+ rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ;
+
+ if ( rc != 3 || up->year < 2000 || 2099 <= up->year
+ || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) {
+ /* Invalid date */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE,
+ rc, up->year, up->month, up->day ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ }
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC
+ && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) {
+ /* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */
+
+ rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ;
+
+ if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) {
+ /* Invalid leap second */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ }
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) {
+ /* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */
+
+ rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ;
+
+ if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) {
+ /* Invalid time */
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME,
+ rc, up->hour, up->minute, up->second ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ up->bLineError = TRUE ;
+ }
+ up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ;
+
+ up->iTimestampCount++ ;
+
+ if ( up->iTimestampCount == 6 && ! up->bLineError ) {
+#if DEBUG
+ printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n",
+ up->bLineError,
+ up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ;
#endif
+ bAdjustment = TRUE ;
+
+ if ( peer->ttl == 100 ) {
+ /* mode=100 */
+ up->msecond = 0 ;
+ } else {
+ /* mode=101 to 110 */
+ up->msecond = teljjy_getDelay( peer, up ) ;
+ if (up->msecond < 0 ) {
+ up->msecond = 0 ;
+ bAdjustment = FALSE ;
+ }
+ }
- if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
+ if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2]
+ && up->iTimestamp[2] <= up->iTimestamp[3]
+ && ( up->iTimestamp[3] + 1 ) == up->iTimestamp[4]
+ && ( up->iTimestamp[4] + 1 ) == up->iTimestamp[5] ) {
+ /* Non over midnight */
+
+ jjy_synctime( peer, pp, up ) ;
+
+ if ( peer->ttl != 100 ) {
+ if ( bAdjustment ) {
+ snprintf( sLog, sizeof(sLog),
+ JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST,
+ up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ;
+ } else {
+ snprintf( sLog, sizeof(sLog),
+ JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST,
+ up->iLoopbackValidCount, MAX_LOOPBACK ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+ }
+ }
+
+ }
+ }
+
+ } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen
+ && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
+ /* Loopback noise ( Unexpected replay ) */
+
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ;
+
+ } else {
+
+ up->bLineError = TRUE ;
+
+ snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY,
+ pBuf ) ;
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ;
+
+ }
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ const char *pCmd ;
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ;
+
+ if ( up->iClockCommandSeq >= 1
+ && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) {
+ /* Loopback */
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ;
+ }
+#endif
+ if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) {
+ up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ;
+ }
+ up->iTeljjySilentTimer = 0 ;
+ return teljjy_conn_send( peer, pp, up ) ;
+ } else {
+ pCmd = "\r" ;
+ }
+
+ if ( write( pp->io.fd, pCmd, 1 ) != 1 ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
}
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ up->iTeljjySilentTimer = 0 ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ;
+
+ return TELJJY_CHANGE_CLOCK_STATE ;
+
+}
+
+/******************************/
+static int
+teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ;
+
+ modem_disconnect ( peer->refclkunit, peer ) ;
+
+ return TELJJY_STAY_CLOCK_STATE ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## Modem control finite state machine ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+
+/* struct jjyunit.iModemState */
+
+#define MODEM_STATE_DISCONNECT 0
+#define MODEM_STATE_INITIALIZE 1
+#define MODEM_STATE_DAILING 2
+#define MODEM_STATE_CONNECT 3
+#define MODEM_STATE_ESCAPE 4
+
+/* struct jjyunit.iModemEvent */
+
+#define MODEM_EVENT_NULL 0
+#define MODEM_EVENT_INITIALIZE 1
+#define MODEM_EVENT_DIALOUT 2
+#define MODEM_EVENT_DISCONNECT 3
+#define MODEM_EVENT_RESP_OK 4
+#define MODEM_EVENT_RESP_CONNECT 5
+#define MODEM_EVENT_RESP_RING 6
+#define MODEM_EVENT_RESP_NO_CARRIER 7
+#define MODEM_EVENT_RESP_ERROR 8
+#define MODEM_EVENT_RESP_CONNECT_X 9
+#define MODEM_EVENT_RESP_NO_DAILTONE 10
+#define MODEM_EVENT_RESP_BUSY 11
+#define MODEM_EVENT_RESP_NO_ANSWER 12
+#define MODEM_EVENT_RESP_UNKNOWN 13
+#define MODEM_EVENT_SILENT 14
+#define MODEM_EVENT_TIMEOUT 15
+
+/* Function prototypes */
+
+static void modem_control ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+
+static int modem_disc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_disc_init ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_start ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_resp00 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_init_resp04 ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_dialout ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_connect ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_dial_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_conn_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_conn_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_data ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_silent ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+static int modem_esc_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ;
+
+static int ( *pModemHandler [ ] [ 5 ] ) ( ) =
+{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
+/* NULL */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
+/* INITIALIZE */ { modem_disc_init , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore },
+/* DIALOUT */ { modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore },
+/* DISCONNECT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_escape },
+/* RESP: 0: OK */ { modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
+/* RESP: 1: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
+/* RESP: 2: RING */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
+/* RESP: 3: NO CARRIER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 4: ERROR */ { modem_disc_ignore, modem_init_resp04, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 5: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data },
+/* RESP: 6: NO DAILTONE */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 7: BUSY */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 8: NO ANSWER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data },
+/* RESP: 9: UNKNOWN */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data },
+/* SILENT */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent },
+/* TIMEOUT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_disc }
+} ;
+
+static short iModemNextState [ ] [ 5 ] =
+{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
+/* NULL */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* INITIALIZE */ { MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* DIALOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* DISCONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE },
+/* RESP: 0: OK */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 1: CONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 2: RING */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 3: NO CARRIER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 4: ERROR */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 5: CONNECT X */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 6: NO DAILTONE */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 7: BUSY */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 8: NO ANSWER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* RESP: 9: UNKNOWN */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE },
+/* SILENT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT },
+/* TIMEOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT }
+} ;
+
+static short iModemPostEvent [ ] [ 5 ] =
+{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */
+/* NULL */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* INITIALIZE */ { MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* DIALOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* DISCONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL },
+/* RESP: 0: OK */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 1: CONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 2: RING */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 3: NO CARRIER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 4: ERROR */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 5: CONNECT X */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 6: NO DAILTONE */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 7: BUSY */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 8: NO ANSWER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* RESP: 9: UNKNOWN */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* SILENT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL },
+/* TIMEOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }
+} ;
+
+static short iModemSilentTimeout [ 5 ] = { 0, 0, 0, 0, 5 } ;
+static short iModemStateTimeout [ 5 ] = { 0, 20, 90, 0, 20 } ;
+
+#define STAY_MODEM_STATE 0
+#define CHANGE_MODEM_STATE 1
+
+#ifdef DEBUG
+#define DEBUG_MODEM_PRINTF(sFunc) { if ( debug ) { printf ( "refclock_jjy.c : %s : iModemState=%d iModemEvent=%d iModemSilentTimer=%d iModemStateTimer=%d\n", sFunc, up->iModemState, up->iModemEvent, up->iModemSilentTimer, up->iModemStateTimer ) ; } }
+#else
+#define DEBUG_MODEM_PRINTF(sFunc)
+#endif
+
+/**************************************************************************************************/
+
+static short
+getModemState ( struct jjyunit *up )
+{
+ return up->iModemState ;
+}
+
+/**************************************************************************************************/
+
+static int
+isModemStateConnect ( short iCheckState )
+{
+ return ( iCheckState == MODEM_STATE_CONNECT ) ;
+}
+
+/**************************************************************************************************/
+
+static int
+isModemStateDisconnect ( short iCheckState )
+{
+ return ( iCheckState == MODEM_STATE_DISCONNECT ) ;
+}
+
+/**************************************************************************************************/
+
+static int
+isModemStateTimerOn ( struct jjyunit *up )
+{
+ return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ;
}
/**************************************************************************************************/
static void
-jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer )
+modem_connect ( int unit, struct peer *peer )
{
+ struct refclockproc *pp;
+ struct jjyunit *up;
- struct jjyunit *up;
- struct refclockproc *pp;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
- char sCmd[2] ;
+ DEBUG_MODEM_PRINTF( "modem_connect" ) ;
- pp = peer->procptr;
+ up->iModemEvent = MODEM_EVENT_INITIALIZE ;
+
+ modem_control ( peer, pp, up ) ;
+
+}
+
+/**************************************************************************************************/
+
+static void
+modem_disconnect ( int unit, struct peer *peer )
+{
+ struct refclockproc *pp;
+ struct jjyunit *up;
+
+ pp = peer->procptr ;
up = pp->unitptr ;
- /*
- * Send "T" or "C" command
- */
+ DEBUG_MODEM_PRINTF( "modem_disconnect" ) ;
- switch ( up->operationmode ) {
- case 1 : sCmd[0] = 'T' ; break ;
- case 2 : sCmd[0] = 'C' ; break ;
+ up->iModemEvent = MODEM_EVENT_DISCONNECT ;
+
+ modem_control ( peer, pp, up ) ;
+
+}
+
+/**************************************************************************************************/
+
+static int
+modem_receive ( struct recvbuf *rbufp )
+{
+
+ struct peer *peer;
+ struct jjyunit *up;
+ struct refclockproc *pp;
+ char *pBuf ;
+ int iLen ;
+
+#ifdef DEBUG
+ static const char *sFunctionName = "modem_receive" ;
+#endif
+
+ peer = rbufp->recv_peer ;
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_MODEM_PRINTF( sFunctionName ) ;
+
+ if ( up->linediscipline == LDISC_RAW ) {
+ pBuf = up->sTextBuf ;
+ iLen = up->iTextBufLen ;
+ } else {
+ pBuf = pp->a_lastcode ;
+ iLen = pp->lencode ;
}
- sCmd[1] = 0 ;
+
+ if ( iLen == 2 && strncmp( pBuf, "OK" , 2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK ; }
+ else if ( iLen == 7 && strncmp( pBuf, "CONNECT" , 7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT ; }
+ else if ( iLen == 4 && strncmp( pBuf, "RING" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING ; }
+ else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER ; }
+ else if ( iLen == 5 && strncmp( pBuf, "ERROR" , 5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR ; }
+ else if ( iLen >= 8 && strncmp( pBuf, "CONNECT " , 8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X ; }
+ else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; }
+ else if ( iLen == 4 && strncmp( pBuf, "BUSY" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY ; }
+ else if ( iLen == 9 && strncmp( pBuf, "NO ANSWER" , 9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER ; }
+ else { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN ; }
#ifdef DEBUG
if ( debug ) {
- printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ;
+ char sResp [ 40 ] ;
+ int iCopyLen ;
+ iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
+ strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ;
+ sResp[iCopyLen] = 0 ;
+ printf ( "refclock_jjy.c : modem_receive : iLen=%d pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ;
}
#endif
+ modem_control ( peer, pp, up ) ;
- if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
- }
+ return 0 ;
}
/**************************************************************************************************/
static void
-jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer )
+modem_timer ( int unit, struct peer *peer )
{
- /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */
+ struct refclockproc *pp ;
+ struct jjyunit *up ;
+
+ pp = peer->procptr ;
+ up = pp->unitptr ;
+
+ DEBUG_MODEM_PRINTF( "modem_timer" ) ;
+
+ if ( iModemSilentTimeout[up->iModemState] != 0 ) {
+ up->iModemSilentTimer++ ;
+ if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) {
+ up->iModemEvent = MODEM_EVENT_SILENT ;
+ modem_control ( peer, pp, up ) ;
+ }
+ }
+
+ if ( iModemStateTimeout[up->iModemState] != 0 ) {
+ up->iModemStateTimer++ ;
+ if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) {
+ up->iModemEvent = MODEM_EVENT_TIMEOUT ;
+ modem_control ( peer, pp, up ) ;
+ }
+ }
}
/**************************************************************************************************/
static void
-jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer )
+modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
{
+
+ int rc ;
+ short iPostEvent = MODEM_EVENT_NULL ;
+
+ DEBUG_MODEM_PRINTF( "modem_control" ) ;
+
+ rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ;
+
+ if ( rc == CHANGE_MODEM_STATE ) {
+ iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ;
#ifdef DEBUG
- static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ;
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d iPostEvent=%d\n",
+ up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ;
+ }
#endif
- struct jjyunit *up;
- struct refclockproc *pp;
+ if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) {
+ up->iModemSilentCount = 0 ;
+ up->iModemStateTimer = 0 ;
+ up->iModemCommandSeq = 0 ;
+ }
- const char *pCmd ;
- int iCmdLen ;
+ up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ;
+ }
- pp = peer->procptr;
- up = pp->unitptr ;
+ if ( iPostEvent != MODEM_EVENT_NULL ) {
+ up->iModemEvent = iPostEvent ;
+ modem_control ( peer, pp, up ) ;
+ }
+ up->iModemEvent = MODEM_EVENT_NULL ;
+
+}
+
+/******************************/
+static int
+modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_disc_init" ) ;
+
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_init_start" ) ;
+
+ up->iModemCommandSeq = 0 ;
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ;
+ }
+#endif
+
+ return modem_init_resp00( peer, pp, up ) ;
+
+}
+
+/******************************/
+static int
+modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pCmd, cBuf [ 46 ] ;
+ int iCmdLen ;
+ int iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ;
+ int iNextModemState = STAY_MODEM_STATE ;
+
+ DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ;
+
+ up->iModemCommandSeq++ ;
+
+ switch ( up->iModemCommandSeq ) {
+
+ case 1 :
+ /* En = Echoback 0:Off 1:On */
+ /* Qn = Result codes 0:On 1:Off */
+ /* Vn = Result codes 0:Numeric 1:Text */
+ pCmd = "ATE0Q0V1\r\n" ;
+ break ;
+
+ case 2 :
+ /* Mn = Speaker switch 0:Off 1:On until remote carrier detected 2:On */
+ if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) {
+ /* fudge 127.127.40.n flag3 0 */
+ iSpeakerSwitch = 0 ;
+ } else {
+ /* fudge 127.127.40.n flag3 1 */
+ iSpeakerSwitch = 2 ;
+ }
+
+ /* Ln = Speaker volume 0:Very low 1:Low 2:Middle 3:High */
+ if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) {
+ /* fudge 127.127.40.n flag4 0 */
+ iSpeakerVolume = 1 ;
+ } else {
+ /* fudge 127.127.40.n flag4 1 */
+ iSpeakerVolume = 2 ;
+ }
+
+ pCmd = cBuf ;
+ snprintf( pCmd, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ;
+ break ;
+
+ case 3 :
+ /* &Kn = Flow control 4:XON/XOFF */
+ pCmd = "AT&K4\r\n" ;
+ break ;
+
+ case 4 :
+ /* +MS = Protocol V22B:1200,2400bpsiV.22bis) */
+ pCmd = "AT+MS=V22B\r\n" ;
+ break ;
+
+ case 5 :
+ /* %Cn = Data compression 0:No data compression */
+ pCmd = "AT%C0\r\n" ;
+ break ;
+
+ case 6 :
+ /* \Nn = Error correction 0:Normal mode 1:Direct mode 2:V42,MNP 3:V42,MNP,Normal */
+ if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) {
+ /* fudge 127.127.40.n flag2 0 */
+ iErrorCorrection = 0 ;
+ } else {
+ /* fudge 127.127.40.n flag2 1 */
+ iErrorCorrection = 3 ;
+ }
+
+ pCmd = cBuf ;
+ snprintf( pCmd, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ;
+ break ;
+
+ case 7 :
+ /* Hn = Hook 0:Hook-On ( Disconnect ) 1:Hook-Off ( Connect ) */
+ pCmd = "ATH1\r\n" ;
+ break ;
+
+ case 8 :
+ /* Initialize completion */
+ pCmd = NULL ;
+ iNextModemState = CHANGE_MODEM_STATE ;
+ break ;
+
+ default :
+ pCmd = NULL ;
+ break ;
+
+ }
+
+ if ( pCmd != NULL ) {
+
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ }
+
+ return iNextModemState ;
+
+}
+
+/******************************/
+static int
+modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ;
+
+ return modem_init_resp00( peer, pp, up ) ;
+
+}
+
+/******************************/
+static int
+modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_init_disc" ) ;
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ;
+ }
+#endif
+
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char sCmd [ 46 ] ;
+ int iCmdLen ;
+ char cToneOrPulse ;
+
+ DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ;
+
+ /* Tone or Pulse */
if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) {
- up->linecount = 1 ;
+ /* fudge 127.127.40.n flag1 0 */
+ cToneOrPulse = 'T' ;
+ } else {
+ /* fudge 127.127.40.n flag1 1 */
+ cToneOrPulse = 'P' ;
}
+ /* Connect ( Dial number ) */
+ snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ;
+
+ /* Send command */
+ iCmdLen = strlen( sCmd ) ;
+ if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ;
#ifdef DEBUG
if ( debug ) {
- printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n",
- sFunctionName, pp->sloppyclockflag, CLK_FLAG1,
- up->linecount ) ;
+ printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ;
}
#endif
- /*
- * Send a first command
- */
+ return modem_conn_escape( peer, pp, up ) ;
+
+}
+
+/******************************/
+static int
+modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ;
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ;
#ifdef DEBUG
if ( debug ) {
- printf ( "%s (refclock_jjy.c) : send '%s'\n",
- sFunctionName,
- tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ;
+ printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ;
}
#endif
- pCmd = tristate_gpsclock01_command_sequence[up->linecount].command ;
- iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ;
- if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
- refclock_report ( peer, CEVNT_FAULT ) ;
+ modem_esc_disc( peer, pp, up ) ;
+
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ;
+
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pCmd ;
+ int iCmdLen ;
+
+ DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ;
+
+ /* Escape command ( Go to command mode ) */
+ pCmd = "+++" ;
+
+ /* Send command */
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
}
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return STAY_MODEM_STATE ;
+
}
-/**************************************************************************************************/
+/******************************/
+static int
+modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_esc_data" ) ;
+
+ up->iModemSilentTimer = 0 ;
+
+ return STAY_MODEM_STATE ;
+
+}
+
+/******************************/
+static int
+modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ;
+
+ up->iModemSilentCount ++ ;
+
+ if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) {
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ;
+ }
+#endif
+ modem_esc_escape( peer, pp, up ) ;
+ up->iModemSilentTimer = 0 ;
+ return STAY_MODEM_STATE ;
+ }
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ;
+ }
+#endif
+ return modem_esc_disc( peer, pp, up ) ;
+
+}
+/******************************/
+static int
+modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up )
+{
+
+ char *pCmd ;
+ int iCmdLen ;
+
+ DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ;
+
+ /* Disconnect */
+ pCmd = "ATH0\r\n" ;
+
+ /* Send command */
+ iCmdLen = strlen( pCmd ) ;
+ if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) {
+ refclock_report( peer, CEVNT_FAULT ) ;
+ }
+
+ jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ;
+
+ return CHANGE_MODEM_STATE ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## jjy_write_clockstats ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
+
+static void
+jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData )
+{
+
+ char sLog [ 100 ] ;
+ char *pMark ;
+ int iMarkLen, iDataLen ;
+
+ switch ( iMark ) {
+ case JJY_CLOCKSTATS_MARK_JJY :
+ pMark = "JJY " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_SEND :
+ pMark = "--> " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_RECEIVE :
+ pMark = "<-- " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_INFORMATION :
+ pMark = "--- " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_ATTENTION :
+ pMark = "=== " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_WARNING :
+ pMark = "-W- " ;
+ break ;
+ case JJY_CLOCKSTATS_MARK_ERROR :
+ pMark = "-X- " ;
+ break ;
+ default :
+ pMark = "" ;
+ break ;
+ }
+
+ iDataLen = strlen( pData ) ;
+ iMarkLen = strlen( pMark ) ;
+ strcpy( sLog, pMark ) ; /* Harmless because of enough length */
+ printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ;
+
+#ifdef DEBUG
+ if ( debug ) {
+ printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ;
+ }
+#endif
+ record_clock_stats( &peer->srcadr, sLog ) ;
+
+}
+
+/*################################################################################################*/
+/*################################################################################################*/
+/*## ##*/
+/*## printableString ##*/
+/*## ##*/
+/*################################################################################################*/
+/*################################################################################################*/
static void
-printableString ( char *sOutput, int iOutputLen, char *sInput, int iInputLen )
+printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen )
{
const char *printableControlChar[] = {
"<NUL>", "<SOH>", "<STX>", "<ETX>",