1106163Sroberto/* 2106163Sroberto * refclock_jjy - clock driver for JJY receivers 3106163Sroberto */ 4106163Sroberto 5106163Sroberto/**********************************************************************/ 6280849Scy/* */ 7362716Scy/* Copyright (C) 2001-2020, Takao Abe. All rights reserved. */ 8280849Scy/* */ 9106163Sroberto/* Permission to use, copy, modify, and distribute this software */ 10280849Scy/* and its documentation for any purpose is hereby granted */ 11106163Sroberto/* without fee, provided that the following conditions are met: */ 12280849Scy/* */ 13106163Sroberto/* One retains the entire copyright notice properly, and both the */ 14106163Sroberto/* copyright notice and this license. in the documentation and/or */ 15280849Scy/* other materials provided with the distribution. */ 16280849Scy/* */ 17106163Sroberto/* This software and the name of the author must not be used to */ 18106163Sroberto/* endorse or promote products derived from this software without */ 19280849Scy/* prior written permission. */ 20280849Scy/* */ 21106163Sroberto/* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */ 22280849Scy/* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */ 23280849Scy/* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */ 24280849Scy/* PARTICULAR PURPOSE. */ 25106163Sroberto/* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */ 26106163Sroberto/* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 27280849Scy/* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ 28106163Sroberto/* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */ 29106163Sroberto/* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ 30280849Scy/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */ 31106163Sroberto/* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */ 32106163Sroberto/* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 33280849Scy/* */ 34106163Sroberto/* This driver is developed in my private time, and is opened as */ 35280849Scy/* voluntary contributions for the NTP. */ 36106163Sroberto/* The manufacturer of the JJY receiver has not participated in */ 37280849Scy/* a development of this driver. */ 38106163Sroberto/* The manufacturer does not warrant anything about this driver, */ 39280849Scy/* and is not liable for anything about this driver. */ 40280849Scy/* */ 41106163Sroberto/**********************************************************************/ 42280849Scy/* */ 43280849Scy/* Author Takao Abe */ 44280849Scy/* Email takao_abe@xurb.jp */ 45280849Scy/* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */ 46280849Scy/* */ 47280849Scy/* The email address abetakao@bea.hi-ho.ne.jp is never read */ 48280849Scy/* from 2010, because a few filtering rule are provided by the */ 49280849Scy/* "hi-ho.ne.jp", and lots of spam mail are reached. */ 50280849Scy/* New email address for supporting the refclock_jjy is */ 51280849Scy/* takao_abe@xurb.jp */ 52280849Scy/* */ 53106163Sroberto/**********************************************************************/ 54280849Scy/* */ 55280849Scy/* History */ 56280849Scy/* */ 57280849Scy/* 2001/07/15 */ 58280849Scy/* [New] Support the Tristate Ltd. JJY receiver */ 59280849Scy/* */ 60280849Scy/* 2001/08/04 */ 61280849Scy/* [Change] Log to clockstats even if bad reply */ 62280849Scy/* [Fix] PRECISION = (-3) (about 100 ms) */ 63280849Scy/* [Add] Support the C-DEX Co.Ltd. JJY receiver */ 64280849Scy/* */ 65280849Scy/* 2001/12/04 */ 66106163Sroberto/* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */ 67280849Scy/* */ 68280849Scy/* 2002/07/12 */ 69280849Scy/* [Fix] Portability for FreeBSD ( patched by the user ) */ 70280849Scy/* */ 71280849Scy/* 2004/10/31 */ 72182007Sroberto/* [Change] Command send timing for the Tristate Ltd. JJY receiver */ 73280849Scy/* JJY-01 ( Firmware version 2.01 ) */ 74280849Scy/* Thanks to Andy Taki for testing under FreeBSD */ 75280849Scy/* */ 76280849Scy/* 2004/11/28 */ 77280849Scy/* [Add] Support the Echo Keisokuki LT-2000 receiver */ 78280849Scy/* */ 79280849Scy/* 2006/11/04 */ 80280849Scy/* [Fix] C-DEX JST2000 */ 81280849Scy/* Thanks to Hideo Kuramatsu for the patch */ 82280849Scy/* */ 83280849Scy/* 2009/04/05 */ 84280849Scy/* [Add] Support the CITIZEN T.I.C JJY-200 receiver */ 85280849Scy/* */ 86280849Scy/* 2010/11/20 */ 87280849Scy/* [Change] Bug 1618 ( Harmless ) */ 88280849Scy/* Code clean up ( Remove unreachable codes ) in */ 89280849Scy/* jjy_start() */ 90280849Scy/* [Change] Change clockstats format of the Tristate JJY01/02 */ 91280849Scy/* Issues more command to get the status of the receiver */ 92280849Scy/* when "fudge 127.127.40.X flag1 1" is specified */ 93280849Scy/* ( DATE,STIM -> DCST,STUS,DATE,STIM ) */ 94280849Scy/* */ 95280849Scy/* 2011/04/30 */ 96280849Scy/* [Add] Support the Tristate Ltd. TS-GPSclock-01 */ 97280849Scy/* */ 98285169Scy/* 2015/03/29 */ 99285169Scy/* [Add] Support the Telephone JJY */ 100285169Scy/* [Change] Split the start up routine into each JJY receivers. */ 101285169Scy/* Change raw data internal bufferring process */ 102285169Scy/* Change over midnight handling of TS-JJY01 and TS-GPS01 */ 103285169Scy/* to put DATE command between before and after TIME's. */ 104285169Scy/* Unify the writing clockstats of all JJY receivers. */ 105285169Scy/* */ 106285169Scy/* 2015/05/15 */ 107285169Scy/* [Add] Support the SEIKO TIME SYSTEMS TDC-300 */ 108285169Scy/* */ 109309007Sdelphij/* 2016/05/08 */ 110309007Sdelphij/* [Fix] C-DEX JST2000 */ 111309007Sdelphij/* Thanks to Mr. Kuramatsu for the report and the patch. */ 112309007Sdelphij/* */ 113330106Sdelphij/* 2017/04/30 */ 114330106Sdelphij/* [Change] Avoid a wrong report of the coverity static analysis */ 115330106Sdelphij/* tool. ( The code is harmless and has no bug. ) */ 116330106Sdelphij/* teljjy_conn_send() */ 117330106Sdelphij/* */ 118362716Scy/* 2020/01/19 */ 119362716Scy/* [Change] Handling TS-JJY01/02 status of the the STUS reply. */ 120362716Scy/* Time synchronization can be skipped by the settings of */ 121362716Scy/* the flag2 when the status of the reply is UNADJUSTED. */ 122362716Scy/* [Change] Quiet compilation for the GCC 9.2.0. */ 123362716Scy/* [Fix] Correct typos in comment lines */ 124362716Scy/* */ 125106163Sroberto/**********************************************************************/ 126106163Sroberto 127106163Sroberto#ifdef HAVE_CONFIG_H 128106163Sroberto#include <config.h> 129106163Sroberto#endif 130106163Sroberto 131106163Sroberto#if defined(REFCLOCK) && defined(CLOCK_JJY) 132106163Sroberto 133106163Sroberto#include <stdio.h> 134106163Sroberto#include <ctype.h> 135106163Sroberto#include <string.h> 136106163Sroberto#include <sys/time.h> 137106163Sroberto#include <time.h> 138106163Sroberto 139106163Sroberto#include "ntpd.h" 140106163Sroberto#include "ntp_io.h" 141106163Sroberto#include "ntp_tty.h" 142106163Sroberto#include "ntp_refclock.h" 143106163Sroberto#include "ntp_calendar.h" 144106163Sroberto#include "ntp_stdlib.h" 145106163Sroberto 146106163Sroberto/**********************************************************************/ 147106163Sroberto 148106163Sroberto/* 149106163Sroberto * Interface definitions 150106163Sroberto */ 151280849Scy#define DEVICE "/dev/jjy%d" /* device name and unit */ 152280849Scy#define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */ 153280849Scy#define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */ 154280849Scy#define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */ 155280849Scy#define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */ 156280849Scy#define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */ 157285169Scy#define SPEED232_SEIKO_TIMESYS_TDC_300 B2400 /* UART speed (2400 baud) */ 158285169Scy#define SPEED232_TELEPHONE B2400 /* UART speed (4800 baud) */ 159280849Scy#define REFID "JJY" /* reference ID */ 160106163Sroberto#define DESCRIPTION "JJY Receiver" 161280849Scy#define PRECISION (-3) /* precision assumed (about 100 ms) */ 162106163Sroberto 163106163Sroberto/* 164106163Sroberto * JJY unit control structure 165106163Sroberto */ 166285169Scy 167285169Scystruct jjyRawDataBreak { 168294554Sdelphij const char * pString ; 169294554Sdelphij int iLength ; 170285169Scy} ; 171285169Scy 172285169Scy#define MAX_TIMESTAMP 6 173285169Scy#define MAX_RAWBUF 100 174285169Scy#define MAX_LOOPBACK 5 175285169Scy 176106163Srobertostruct jjyunit { 177285169Scy/* Set up by the function "jjy_start_xxxxxxxx" */ 178280849Scy char unittype ; /* UNITTYPE_XXXXXXXXXX */ 179285169Scy short operationmode ; /* Echo Keisokuki LT-2000 */ 180285169Scy int linespeed ; /* SPEED232_XXXXXXXXXX */ 181280849Scy short linediscipline ; /* LDISC_CLK or LDISC_RAW */ 182285169Scy/* Receiving data */ 183285169Scy char bInitError ; /* Set by jjy_start if any error during initialization */ 184285169Scy short iProcessState ; /* JJY_PROCESS_STATE_XXXXXX */ 185285169Scy char bReceiveFlag ; /* Set and reset by jjy_receive */ 186285169Scy char bLineError ; /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/ 187285169Scy short iCommandSeq ; /* 0:Idle Non-Zero:Issued */ 188285169Scy short iReceiveSeq ; 189285169Scy int iLineCount ; 190106163Sroberto int year, month, day, hour, minute, second, msecond ; 191285169Scy int leapsecond ; 192285169Scy int iTimestampCount ; /* TS-JJY01, TS-GPS01, Telephone-JJY */ 193285169Scy int iTimestamp [ MAX_TIMESTAMP ] ; /* Serial second ( 0 - 86399 ) */ 194106163Sroberto/* LDISC_RAW only */ 195285169Scy char sRawBuf [ MAX_RAWBUF ] ; 196285169Scy int iRawBufLen ; 197285169Scy struct jjyRawDataBreak *pRawBreak ; 198285169Scy char bWaitBreakString ; 199285169Scy char sLineBuf [ MAX_RAWBUF ] ; 200285169Scy int iLineBufLen ; 201285169Scy char sTextBuf [ MAX_RAWBUF ] ; 202285169Scy int iTextBufLen ; 203285169Scy char bSkipCntrlCharOnly ; 204362716Scy/* TS-JJY01, TS-JJY02 */ 205362716Scy time_t tLastAdjustedTimestamp ; 206362716Scy char bStusReplyAdjusted ; 207362716Scy char bStusReplyAdjustedAtLeastOnce ; 208285169Scy/* Telephone JJY auto measurement of the loopback delay */ 209285169Scy char bLoopbackMode ; 210285169Scy short iLoopbackCount ; 211285169Scy struct timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ; 212285169Scy char bLoopbackTimeout[MAX_LOOPBACK] ; 213285169Scy short iLoopbackValidCount ; 214285169Scy/* Telephone JJY timer */ 215285169Scy short iTeljjySilentTimer ; 216285169Scy short iTeljjyStateTimer ; 217285169Scy/* Telephone JJY control finite state machine */ 218285169Scy short iClockState ; 219285169Scy short iClockEvent ; 220285169Scy short iClockCommandSeq ; 221285169Scy/* Modem timer */ 222285169Scy short iModemSilentCount ; 223285169Scy short iModemSilentTimer ; 224285169Scy short iModemStateTimer ; 225285169Scy/* Modem control finite state machine */ 226285169Scy short iModemState ; 227285169Scy short iModemEvent ; 228285169Scy short iModemCommandSeq ; 229106163Sroberto}; 230106163Sroberto 231280849Scy#define UNITTYPE_TRISTATE_JJY01 1 232280849Scy#define UNITTYPE_CDEX_JST2000 2 233182007Sroberto#define UNITTYPE_ECHOKEISOKUKI_LT2000 3 234200576Sroberto#define UNITTYPE_CITIZENTIC_JJY200 4 235280849Scy#define UNITTYPE_TRISTATE_GPSCLOCK01 5 236285169Scy#define UNITTYPE_SEIKO_TIMESYS_TDC_300 6 237285169Scy#define UNITTYPE_TELEPHONE 100 238106163Sroberto 239285169Scy#define JJY_PROCESS_STATE_IDLE 0 240285169Scy#define JJY_PROCESS_STATE_POLL 1 241285169Scy#define JJY_PROCESS_STATE_RECEIVE 2 242285169Scy#define JJY_PROCESS_STATE_DONE 3 243285169Scy#define JJY_PROCESS_STATE_ERROR 4 244285169Scy 245285169Scy/**********************************************************************/ 246285169Scy 247106163Sroberto/* 248285169Scy * Function calling structure 249285169Scy * 250285169Scy * jjy_start 251285169Scy * |-- jjy_start_tristate_jjy01 252285169Scy * |-- jjy_start_cdex_jst2000 253285169Scy * |-- jjy_start_echokeisokuki_lt2000 254285169Scy * |-- jjy_start_citizentic_jjy200 255285169Scy * |-- jjy_start_tristate_gpsclock01 256285169Scy * |-- jjy_start_seiko_tsys_tdc_300 257285169Scy * |-- jjy_start_telephone 258285169Scy * 259285169Scy * jjy_shutdown 260285169Scy * 261285169Scy * jjy_poll 262285169Scy * |-- jjy_poll_tristate_jjy01 263285169Scy * |-- jjy_poll_cdex_jst2000 264285169Scy * |-- jjy_poll_echokeisokuki_lt2000 265285169Scy * |-- jjy_poll_citizentic_jjy200 266285169Scy * |-- jjy_poll_tristate_gpsclock01 267285169Scy * |-- jjy_poll_seiko_tsys_tdc_300 268285169Scy * |-- jjy_poll_telephone 269285169Scy * |-- teljjy_control 270285169Scy * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 271285169Scy * |-- modem_connect 272285169Scy * |-- modem_control 273285169Scy * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 274285169Scy * 275285169Scy * jjy_receive 276285169Scy * | 277285169Scy * |-- jjy_receive_tristate_jjy01 278285169Scy * | |-- jjy_synctime 279285169Scy * |-- jjy_receive_cdex_jst2000 280285169Scy * | |-- jjy_synctime 281285169Scy * |-- jjy_receive_echokeisokuki_lt2000 282285169Scy * | |-- jjy_synctime 283285169Scy * |-- jjy_receive_citizentic_jjy200 284285169Scy * | |-- jjy_synctime 285285169Scy * |-- jjy_receive_tristate_gpsclock01 286285169Scy * | |-- jjy_synctime 287285169Scy * |-- jjy_receive_seiko_tsys_tdc_300 288285169Scy * | |-- jjy_synctime 289285169Scy * |-- jjy_receive_telephone 290285169Scy * |-- modem_receive 291285169Scy * | |-- modem_control 292285169Scy * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 293285169Scy * |-- teljjy_control 294285169Scy * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 295285169Scy * |-- jjy_synctime 296285169Scy * |-- modem_disconnect 297285169Scy * |-- modem_control 298285169Scy * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 299285169Scy * 300285169Scy * jjy_timer 301285169Scy * |-- jjy_timer_telephone 302285169Scy * |-- modem_timer 303285169Scy * | |-- modem_control 304285169Scy * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 305285169Scy * |-- teljjy_control 306285169Scy * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 307285169Scy * |-- modem_disconnect 308285169Scy * |-- modem_control 309285169Scy * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 310285169Scy * 311106163Sroberto * Function prototypes 312106163Sroberto */ 313285169Scy 314280849Scystatic int jjy_start (int, struct peer *); 315285169Scystatic int jjy_start_tristate_jjy01 (int, struct peer *, struct jjyunit *); 316285169Scystatic int jjy_start_cdex_jst2000 (int, struct peer *, struct jjyunit *); 317285169Scystatic int jjy_start_echokeisokuki_lt2000 (int, struct peer *, struct jjyunit *); 318285169Scystatic int jjy_start_citizentic_jjy200 (int, struct peer *, struct jjyunit *); 319285169Scystatic int jjy_start_tristate_gpsclock01 (int, struct peer *, struct jjyunit *); 320285169Scystatic int jjy_start_seiko_tsys_tdc_300 (int, struct peer *, struct jjyunit *); 321285169Scystatic int jjy_start_telephone (int, struct peer *, struct jjyunit *); 322285169Scy 323280849Scystatic void jjy_shutdown (int, struct peer *); 324106163Sroberto 325280849Scystatic void jjy_poll (int, struct peer *); 326280849Scystatic void jjy_poll_tristate_jjy01 (int, struct peer *); 327280849Scystatic void jjy_poll_cdex_jst2000 (int, struct peer *); 328280849Scystatic void jjy_poll_echokeisokuki_lt2000 (int, struct peer *); 329280849Scystatic void jjy_poll_citizentic_jjy200 (int, struct peer *); 330280849Scystatic void jjy_poll_tristate_gpsclock01 (int, struct peer *); 331285169Scystatic void jjy_poll_seiko_tsys_tdc_300 (int, struct peer *); 332285169Scystatic void jjy_poll_telephone (int, struct peer *); 333280849Scy 334280849Scystatic void jjy_receive (struct recvbuf *); 335285169Scystatic int jjy_receive_tristate_jjy01 (struct recvbuf *); 336285169Scystatic int jjy_receive_cdex_jst2000 (struct recvbuf *); 337285169Scystatic int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *); 338285169Scystatic int jjy_receive_citizentic_jjy200 (struct recvbuf *); 339285169Scystatic int jjy_receive_tristate_gpsclock01 (struct recvbuf *); 340285169Scystatic int jjy_receive_seiko_tsys_tdc_300 (struct recvbuf *); 341285169Scystatic int jjy_receive_telephone (struct recvbuf *); 342280849Scy 343285169Scystatic void jjy_timer (int, struct peer *); 344285169Scystatic void jjy_timer_telephone (int, struct peer *); 345280849Scy 346285169Scystatic void jjy_synctime ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 347285169Scystatic void jjy_write_clockstats ( struct peer *, int, const char* ) ; 348285169Scy 349285169Scystatic int getRawDataBreakPosition ( struct jjyunit *, int ) ; 350285169Scy 351285169Scystatic short getModemState ( struct jjyunit * ) ; 352285169Scystatic int isModemStateConnect ( short ) ; 353285169Scystatic int isModemStateDisconnect ( short ) ; 354285169Scystatic int isModemStateTimerOn ( struct jjyunit * ) ; 355285169Scystatic void modem_connect ( int, struct peer * ) ; 356285169Scystatic void modem_disconnect ( int, struct peer * ) ; 357285169Scystatic int modem_receive ( struct recvbuf * ) ; 358285169Scystatic void modem_timer ( int, struct peer * ); 359285169Scy 360285169Scystatic void printableString ( char*, int, const char*, int ) ; 361285169Scy 362106163Sroberto/* 363106163Sroberto * Transfer vector 364106163Sroberto */ 365106163Srobertostruct refclock refclock_jjy = { 366280849Scy jjy_start, /* start up driver */ 367280849Scy jjy_shutdown, /* shutdown driver */ 368280849Scy jjy_poll, /* transmit poll message */ 369280849Scy noentry, /* not used */ 370280849Scy noentry, /* not used */ 371280849Scy noentry, /* not used */ 372285169Scy jjy_timer /* 1 second interval timer */ 373106163Sroberto}; 374106163Sroberto 375106163Sroberto/* 376106163Sroberto * Start up driver return code 377106163Sroberto */ 378106163Sroberto#define RC_START_SUCCESS 1 379280849Scy#define RC_START_ERROR 0 380106163Sroberto 381106163Sroberto/* 382106163Sroberto * Local constants definition 383106163Sroberto */ 384106163Sroberto 385362716Scy#define MAX_LOGTEXT 200 386106163Sroberto 387285169Scy#ifndef TRUE 388285169Scy#define TRUE (0==0) 389285169Scy#endif 390285169Scy#ifndef FALSE 391285169Scy#define FALSE (!TRUE) 392285169Scy#endif 393106163Sroberto 394285169Scy/* Local constants definition for the return code of the jjy_receive_xxxxxxxx */ 395280849Scy 396285169Scy#define JJY_RECEIVE_DONE 0 397285169Scy#define JJY_RECEIVE_SKIP 1 398285169Scy#define JJY_RECEIVE_UNPROCESS 2 399285169Scy#define JJY_RECEIVE_WAIT 3 400285169Scy#define JJY_RECEIVE_ERROR 4 401280849Scy 402285169Scy/* Local constants definition for the 2nd parameter of the jjy_write_clockstats */ 403280849Scy 404285169Scy#define JJY_CLOCKSTATS_MARK_NONE 0 405285169Scy#define JJY_CLOCKSTATS_MARK_JJY 1 406285169Scy#define JJY_CLOCKSTATS_MARK_SEND 2 407285169Scy#define JJY_CLOCKSTATS_MARK_RECEIVE 3 408285169Scy#define JJY_CLOCKSTATS_MARK_INFORMATION 4 409285169Scy#define JJY_CLOCKSTATS_MARK_ATTENTION 5 410285169Scy#define JJY_CLOCKSTATS_MARK_WARNING 6 411285169Scy#define JJY_CLOCKSTATS_MARK_ERROR 7 412330106Sdelphij#define JJY_CLOCKSTATS_MARK_BUG 8 413280849Scy 414285169Scy/* Local constants definition for the clockstats messages */ 415280849Scy 416285169Scy#define JJY_CLOCKSTATS_MESSAGE_ECHOBACK "* Echoback" 417285169Scy#define JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY "* Ignore replay : [%s]" 418285169Scy#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2 "* Over midnight : timestamp=%d, %d" 419285169Scy#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3 "* Over midnight : timestamp=%d, %d, %d" 420285169Scy#define JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE "* Unsure timestamp : %s" 421285169Scy#define JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY "* Loopback delay : %d.%03d mSec." 422285169Scy#define JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST "* Delay adjustment : %d mSec. ( valid=%hd/%d )" 423285169Scy#define JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST "* Delay adjustment : None ( valid=%hd/%d )" 424362716Scy#define JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED "* Skip time synchronization : STUS is 'UNADJUSTED' for %.0lf %s" 425280849Scy 426285169Scy#define JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY "# Unexpected reply : [%s]" 427285169Scy#define JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH "# Invalid length : length=%d" 428285169Scy#define JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY "# Too many reply : count=%d" 429285169Scy#define JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY "# Invalid reply : [%s]" 430285169Scy#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2 "# Slow reply : timestamp=%d, %d" 431285169Scy#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3 "# Slow reply : timestamp=%d, %d, %d" 432285169Scy#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE "# Invalid date : rc=%d year=%d month=%d day=%d" 433285169Scy#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME "# Invalid time : rc=%d hour=%d minute=%d second=%d" 434285169Scy#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME "# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d" 435285169Scy#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP "# Invalid leap : leapsecond=[%s]" 436285169Scy#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS "# Invalid status : status=[%s]" 437280849Scy 438285169Scy/* Debug print macro */ 439280849Scy 440285169Scy#ifdef DEBUG 441285169Scy#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 ) ; } } 442285169Scy#else 443285169Scy#define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen) 444285169Scy#endif 445280849Scy 446106163Sroberto/**************************************************************************************************/ 447106163Sroberto/* jjy_start - open the devices and initialize data for processing */ 448106163Sroberto/**************************************************************************************************/ 449106163Srobertostatic int 450106163Srobertojjy_start ( int unit, struct peer *peer ) 451106163Sroberto{ 452106163Sroberto 453285169Scy struct refclockproc *pp ; 454285169Scy struct jjyunit *up ; 455285169Scy int rc ; 456106163Sroberto int fd ; 457285169Scy char sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ; 458106163Sroberto 459106163Sroberto#ifdef DEBUG 460106163Sroberto if ( debug ) { 461285169Scy printf( "refclock_jjy.c : jjy_start : %s mode=%d dev=%s unit=%d\n", 462285169Scy ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ; 463106163Sroberto } 464106163Sroberto#endif 465280849Scy 466285169Scy /* Allocate memory for the unit structure */ 467285169Scy up = emalloc( sizeof(*up) ) ; 468285169Scy if ( up == NULL ) { 469285169Scy msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ; 470285169Scy return RC_START_ERROR ; 471285169Scy } 472285169Scy memset ( up, 0, sizeof(*up) ) ; 473106163Sroberto 474285169Scy up->bInitError = FALSE ; 475285169Scy up->iProcessState = JJY_PROCESS_STATE_IDLE ; 476285169Scy up->bReceiveFlag = FALSE ; 477285169Scy up->iCommandSeq = 0 ; 478285169Scy up->iLineCount = 0 ; 479285169Scy up->iTimestampCount = 0 ; 480285169Scy up->bWaitBreakString = FALSE ; 481285169Scy up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ; 482285169Scy up->bSkipCntrlCharOnly = TRUE ; 483285169Scy 484285169Scy /* Set up the device name */ 485285169Scy snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ; 486285169Scy 487285169Scy snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ; 488285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 489285169Scy 490106163Sroberto /* 491132451Sroberto * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf 492106163Sroberto */ 493132451Sroberto switch ( peer->ttl ) { 494106163Sroberto case 0 : 495280849Scy case 1 : 496285169Scy rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ; 497280849Scy break ; 498280849Scy case 2 : 499285169Scy rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ; 500280849Scy break ; 501280849Scy case 3 : 502285169Scy rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ; 503280849Scy break ; 504280849Scy case 4 : 505285169Scy rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ; 506280849Scy break ; 507280849Scy case 5 : 508285169Scy rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ; 509280849Scy break ; 510285169Scy case 6 : 511285169Scy rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ; 512285169Scy break ; 513285169Scy case 100 : 514285169Scy rc = jjy_start_telephone ( unit, peer, up ) ; 515285169Scy break ; 516106163Sroberto default : 517285169Scy if ( 101 <= peer->ttl && peer->ttl <= 180 ) { 518285169Scy rc = jjy_start_telephone ( unit, peer, up ) ; 519285169Scy } else { 520285169Scy msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", 521285169Scy ntoa(&peer->srcadr), peer->ttl ) ; 522285169Scy free ( (void*) up ) ; 523285169Scy return RC_START_ERROR ; 524285169Scy } 525285169Scy } 526285169Scy 527285169Scy if ( rc != 0 ) { 528285169Scy msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error", 529280849Scy ntoa(&peer->srcadr), peer->ttl ) ; 530285169Scy free ( (void*) up ) ; 531106163Sroberto return RC_START_ERROR ; 532106163Sroberto } 533106163Sroberto 534285169Scy /* Open the device */ 535285169Scy fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ; 536280849Scy if ( fd <= 0 ) { 537285169Scy free ( (void*) up ) ; 538106163Sroberto return RC_START_ERROR ; 539106163Sroberto } 540106163Sroberto 541106163Sroberto /* 542285169Scy * Initialize variables 543106163Sroberto */ 544285169Scy pp = peer->procptr ; 545106163Sroberto 546285169Scy pp->clockdesc = DESCRIPTION ; 547280849Scy pp->unitptr = up ; 548106163Sroberto pp->io.clock_recv = jjy_receive ; 549280849Scy pp->io.srcclock = peer ; 550280849Scy pp->io.datalen = 0 ; 551280849Scy pp->io.fd = fd ; 552106163Sroberto if ( ! io_addclock(&pp->io) ) { 553106163Sroberto close ( fd ) ; 554280849Scy pp->io.fd = -1 ; 555280849Scy free ( up ) ; 556280849Scy pp->unitptr = NULL ; 557106163Sroberto return RC_START_ERROR ; 558106163Sroberto } 559285169Scy memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ; 560106163Sroberto 561106163Sroberto peer->precision = PRECISION ; 562106163Sroberto 563285169Scy snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ; 564285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 565285169Scy 566106163Sroberto return RC_START_SUCCESS ; 567106163Sroberto 568106163Sroberto} 569106163Sroberto 570106163Sroberto/**************************************************************************************************/ 571106163Sroberto/* jjy_shutdown - shutdown the clock */ 572106163Sroberto/**************************************************************************************************/ 573106163Srobertostatic void 574106163Srobertojjy_shutdown ( int unit, struct peer *peer ) 575106163Sroberto{ 576106163Sroberto 577280849Scy struct jjyunit *up; 578106163Sroberto struct refclockproc *pp; 579106163Sroberto 580285169Scy char sLog [ 60 ] ; 581285169Scy 582106163Sroberto pp = peer->procptr ; 583280849Scy up = pp->unitptr ; 584285169Scy if ( -1 != pp->io.fd ) { 585280849Scy io_closeclock ( &pp->io ) ; 586285169Scy } 587285169Scy if ( NULL != up ) { 588280849Scy free ( up ) ; 589285169Scy } 590106163Sroberto 591285169Scy snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ; 592285169Scy record_clock_stats( &peer->srcadr, sLog ) ; 593285169Scy 594106163Sroberto} 595106163Sroberto 596106163Sroberto/**************************************************************************************************/ 597106163Sroberto/* jjy_receive - receive data from the serial interface */ 598106163Sroberto/**************************************************************************************************/ 599106163Srobertostatic void 600106163Srobertojjy_receive ( struct recvbuf *rbufp ) 601106163Sroberto{ 602285169Scy#ifdef DEBUG 603285169Scy static const char *sFunctionName = "jjy_receive" ; 604285169Scy#endif 605106163Sroberto 606280849Scy struct jjyunit *up ; 607106163Sroberto struct refclockproc *pp ; 608280849Scy struct peer *peer; 609106163Sroberto 610106163Sroberto l_fp tRecvTimestamp; /* arrival timestamp */ 611106163Sroberto int rc ; 612285169Scy char *pBuf, sLogText [ MAX_LOGTEXT ] ; 613316068Sdelphij size_t iLen, iCopyLen ; 614285169Scy int i, j, iReadRawBuf, iBreakPosition ; 615106163Sroberto 616106163Sroberto /* 617106163Sroberto * Initialize pointers and read the timecode and timestamp 618106163Sroberto */ 619280849Scy peer = rbufp->recv_peer ; 620106163Sroberto pp = peer->procptr ; 621280849Scy up = pp->unitptr ; 622106163Sroberto 623106163Sroberto /* 624106163Sroberto * Get next input line 625106163Sroberto */ 626285169Scy if ( up->linediscipline == LDISC_RAW ) { 627106163Sroberto 628285169Scy pp->lencode = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ; 629285169Scy /* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions (OVERRUN)" */ 630285169Scy /* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */ 631285169Scy /* To avoid its claim, pass the value BMAX-1. */ 632285169Scy 633106163Sroberto /* 634362716Scy * Append received characters to temporary buffer 635106163Sroberto */ 636280849Scy for ( i = 0 ; 637285169Scy i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ; 638285169Scy i ++ , up->iRawBufLen ++ ) { 639285169Scy up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ; 640106163Sroberto } 641285169Scy up->sRawBuf[up->iRawBufLen] = 0 ; 642285169Scy 643285169Scy 644285169Scy } else { 645285169Scy 646285169Scy pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ; 647285169Scy 648285169Scy } 649285169Scy#ifdef DEBUG 650285169Scy printf( "\nrefclock_jjy.c : %s : Len=%d ", sFunctionName, pp->lencode ) ; 651285169Scy for ( i = 0 ; i < pp->lencode ; i ++ ) { 652294554Sdelphij if ( iscntrl( (u_char)(pp->a_lastcode[i] & 0x7F) ) ) { 653285169Scy printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ; 654285169Scy } else { 655285169Scy printf( "%c", pp->a_lastcode[i] ) ; 656106163Sroberto } 657285169Scy } 658285169Scy printf( "\n" ) ; 659285169Scy#endif 660285169Scy 661285169Scy /* 662285169Scy * The reply with <CR><LF> gives a blank line 663285169Scy */ 664285169Scy 665285169Scy if ( pp->lencode == 0 ) return ; 666285169Scy 667285169Scy /* 668285169Scy * Receiving data is not expected 669285169Scy */ 670285169Scy 671285169Scy if ( up->iProcessState == JJY_PROCESS_STATE_IDLE 672285169Scy || up->iProcessState == JJY_PROCESS_STATE_DONE 673285169Scy || up->iProcessState == JJY_PROCESS_STATE_ERROR ) { 674285169Scy /* Discard received data */ 675285169Scy up->iRawBufLen = 0 ; 676285169Scy#ifdef DEBUG 677285169Scy if ( debug ) { 678285169Scy printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ; 679106163Sroberto } 680285169Scy#endif 681285169Scy return ; 682106163Sroberto } 683285169Scy 684106163Sroberto /* 685106163Sroberto * We get down to business 686106163Sroberto */ 687106163Sroberto 688285169Scy pp->lastrec = tRecvTimestamp ; 689285169Scy 690285169Scy up->iLineCount ++ ; 691285169Scy 692285169Scy up->iProcessState = JJY_PROCESS_STATE_RECEIVE ; 693285169Scy up->bReceiveFlag = TRUE ; 694285169Scy 695285169Scy iReadRawBuf = 0 ; 696285169Scy iBreakPosition = up->iRawBufLen - 1 ; 697285169Scy for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) { 698285169Scy 699285169Scy if ( up->linediscipline == LDISC_RAW ) { 700285169Scy 701285169Scy if ( up->bWaitBreakString ) { 702285169Scy iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ; 703285169Scy if ( iBreakPosition == -1 ) { 704285169Scy /* Break string have not come yet */ 705285169Scy if ( up->iRawBufLen < MAX_RAWBUF - 2 706285169Scy || iReadRawBuf > 0 ) { 707285169Scy /* Temporary buffer is not full */ 708285169Scy break ; 709285169Scy } else { 710285169Scy /* Temporary buffer is full */ 711285169Scy iBreakPosition = up->iRawBufLen - 1 ; 712285169Scy } 713285169Scy } 714285169Scy } else { 715285169Scy iBreakPosition = up->iRawBufLen - 1 ; 716285169Scy } 717285169Scy 718362716Scy /* Copy characters from temporary buffer to process buffer */ 719285169Scy up->iLineBufLen = up->iTextBufLen = 0 ; 720285169Scy for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) { 721285169Scy 722285169Scy /* Copy all characters */ 723285169Scy up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ; 724285169Scy up->iLineBufLen ++ ; 725285169Scy 726285169Scy /* Copy printable characters */ 727294554Sdelphij if ( ! iscntrl( (u_char)up->sRawBuf[i] ) ) { 728285169Scy up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ; 729285169Scy up->iTextBufLen ++ ; 730285169Scy } 731285169Scy 732285169Scy } 733285169Scy up->sLineBuf[up->iLineBufLen] = 0 ; 734285169Scy up->sTextBuf[up->iTextBufLen] = 0 ; 735280849Scy#ifdef DEBUG 736285169Scy printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n", 737285169Scy sFunctionName, up->iLineBufLen, up->iTextBufLen ) ; 738285169Scy#endif 739285169Scy 740285169Scy if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) { 741285169Scy#ifdef DEBUG 742285169Scy printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n", 743285169Scy sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ; 744285169Scy#endif 745285169Scy if ( iBreakPosition + 1 < up->iRawBufLen ) { 746285169Scy iReadRawBuf = iBreakPosition + 1 ; 747285169Scy continue ; 748285169Scy } else { 749285169Scy break ; 750285169Scy } 751285169Scy 752285169Scy } 753285169Scy 754285169Scy } 755285169Scy 756280849Scy if ( up->linediscipline == LDISC_RAW ) { 757285169Scy pBuf = up->sLineBuf ; 758285169Scy iLen = up->iLineBufLen ; 759280849Scy } else { 760285169Scy pBuf = pp->a_lastcode ; 761285169Scy iLen = pp->lencode ; 762280849Scy } 763285169Scy 764285169Scy iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ; 765316068Sdelphij memcpy( sLogText, pBuf, iCopyLen ) ; 766316068Sdelphij sLogText[iCopyLen] = '\0' ; 767285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ; 768285169Scy 769285169Scy switch ( up->unittype ) { 770285169Scy 771285169Scy case UNITTYPE_TRISTATE_JJY01 : 772285169Scy rc = jjy_receive_tristate_jjy01 ( rbufp ) ; 773285169Scy break ; 774285169Scy 775285169Scy case UNITTYPE_CDEX_JST2000 : 776285169Scy rc = jjy_receive_cdex_jst2000 ( rbufp ) ; 777285169Scy break ; 778285169Scy 779285169Scy case UNITTYPE_ECHOKEISOKUKI_LT2000 : 780285169Scy rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ; 781285169Scy break ; 782285169Scy 783285169Scy case UNITTYPE_CITIZENTIC_JJY200 : 784285169Scy rc = jjy_receive_citizentic_jjy200 ( rbufp ) ; 785285169Scy break ; 786285169Scy 787285169Scy case UNITTYPE_TRISTATE_GPSCLOCK01 : 788285169Scy rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ; 789285169Scy break ; 790285169Scy 791285169Scy case UNITTYPE_SEIKO_TIMESYS_TDC_300 : 792285169Scy rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ; 793285169Scy break ; 794285169Scy 795285169Scy case UNITTYPE_TELEPHONE : 796285169Scy rc = jjy_receive_telephone ( rbufp ) ; 797285169Scy break ; 798285169Scy 799285169Scy default : 800285169Scy rc = JJY_RECEIVE_ERROR ; 801285169Scy break ; 802285169Scy 803285169Scy } 804285169Scy 805285169Scy switch ( rc ) { 806285169Scy case JJY_RECEIVE_DONE : 807285169Scy case JJY_RECEIVE_SKIP : 808285169Scy up->iProcessState = JJY_PROCESS_STATE_DONE ; 809285169Scy break ; 810285169Scy case JJY_RECEIVE_ERROR : 811285169Scy up->iProcessState = JJY_PROCESS_STATE_ERROR ; 812285169Scy break ; 813285169Scy default : 814285169Scy break ; 815285169Scy } 816285169Scy 817285169Scy if ( up->linediscipline == LDISC_RAW ) { 818285169Scy if ( rc == JJY_RECEIVE_UNPROCESS ) { 819285169Scy break ; 820285169Scy } 821285169Scy iReadRawBuf = iBreakPosition + 1 ; 822285169Scy if ( iReadRawBuf >= up->iRawBufLen ) { 823285169Scy /* Processed all received data */ 824285169Scy break ; 825285169Scy } 826285169Scy } 827285169Scy 828285169Scy if ( up->linediscipline == LDISC_CLK ) { 829285169Scy break ; 830285169Scy } 831285169Scy 832280849Scy } 833285169Scy 834285169Scy if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) { 835285169Scy for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) { 836285169Scy up->sRawBuf[i] = up->sRawBuf[j] ; 837285169Scy } 838285169Scy up->iRawBufLen -= iReadRawBuf ; 839285169Scy if ( up->iRawBufLen < 0 ) { 840285169Scy up->iRawBufLen = 0 ; 841285169Scy } 842285169Scy } 843285169Scy 844285169Scy up->bReceiveFlag = FALSE ; 845285169Scy 846285169Scy} 847285169Scy 848285169Scy/**************************************************************************************************/ 849285169Scy 850285169Scystatic int 851285169ScygetRawDataBreakPosition ( struct jjyunit *up, int iStart ) 852285169Scy{ 853285169Scy 854285169Scy int i, j ; 855285169Scy 856285169Scy if ( iStart >= up->iRawBufLen ) { 857285169Scy#ifdef DEBUG 858285169Scy printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ; 859280849Scy#endif 860285169Scy return -1 ; 861285169Scy } 862280849Scy 863285169Scy for ( i = iStart ; i < up->iRawBufLen ; i ++ ) { 864106163Sroberto 865285169Scy for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) { 866106163Sroberto 867285169Scy if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) { 868106163Sroberto 869285169Scy if ( strncmp( up->sRawBuf + i, 870285169Scy up->pRawBreak[j].pString, 871285169Scy up->pRawBreak[j].iLength ) == 0 ) { 872285169Scy 873285169Scy#ifdef DEBUG 874285169Scy printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n", 875285169Scy iStart, i + up->pRawBreak[j].iLength - 1 ) ; 876285169Scy#endif 877285169Scy return i + up->pRawBreak[j].iLength - 1 ; 878285169Scy 879285169Scy } 880285169Scy } 881285169Scy } 882285169Scy } 883285169Scy 884285169Scy#ifdef DEBUG 885285169Scy printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ; 886285169Scy#endif 887285169Scy return -1 ; 888285169Scy 889285169Scy} 890285169Scy 891285169Scy/**************************************************************************************************/ 892285169Scy/* jjy_poll - called by the transmit procedure */ 893285169Scy/**************************************************************************************************/ 894285169Scystatic void 895285169Scyjjy_poll ( int unit, struct peer *peer ) 896285169Scy{ 897285169Scy 898285169Scy char sLog [ 40 ], sReach [ 9 ] ; 899285169Scy 900285169Scy struct jjyunit *up; 901285169Scy struct refclockproc *pp; 902285169Scy 903285169Scy pp = peer->procptr; 904285169Scy up = pp->unitptr ; 905285169Scy 906285169Scy if ( up->bInitError ) { 907285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ; 908285169Scy return ; 909285169Scy } 910285169Scy 911285169Scy if ( pp->polls > 0 && up->iLineCount == 0 ) { 912285169Scy /* 913285169Scy * No reply for last command 914285169Scy */ 915285169Scy refclock_report ( peer, CEVNT_TIMEOUT ) ; 916285169Scy } 917285169Scy 918285169Scy pp->polls ++ ; 919285169Scy 920285169Scy sReach[0] = peer->reach & 0x80 ? '1' : '0' ; 921285169Scy sReach[1] = peer->reach & 0x40 ? '1' : '0' ; 922285169Scy sReach[2] = peer->reach & 0x20 ? '1' : '0' ; 923285169Scy sReach[3] = peer->reach & 0x10 ? '1' : '0' ; 924285169Scy sReach[4] = peer->reach & 0x08 ? '1' : '0' ; 925285169Scy sReach[5] = peer->reach & 0x04 ? '1' : '0' ; 926285169Scy sReach[6] = peer->reach & 0x02 ? '1' : '0' ; 927285169Scy sReach[7] = 0 ; /* This poll */ 928285169Scy sReach[8] = 0 ; 929285169Scy 930285169Scy snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ; 931285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ; 932285169Scy 933285169Scy up->iProcessState = JJY_PROCESS_STATE_POLL ; 934285169Scy up->iCommandSeq = 0 ; 935285169Scy up->iReceiveSeq = 0 ; 936285169Scy up->iLineCount = 0 ; 937285169Scy up->bLineError = FALSE ; 938285169Scy up->iRawBufLen = 0 ; 939285169Scy 940106163Sroberto switch ( up->unittype ) { 941362716Scy 942106163Sroberto case UNITTYPE_TRISTATE_JJY01 : 943285169Scy jjy_poll_tristate_jjy01 ( unit, peer ) ; 944106163Sroberto break ; 945106163Sroberto 946106163Sroberto case UNITTYPE_CDEX_JST2000 : 947285169Scy jjy_poll_cdex_jst2000 ( unit, peer ) ; 948106163Sroberto break ; 949106163Sroberto 950182007Sroberto case UNITTYPE_ECHOKEISOKUKI_LT2000 : 951285169Scy jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ; 952182007Sroberto break ; 953182007Sroberto 954280849Scy case UNITTYPE_CITIZENTIC_JJY200 : 955285169Scy jjy_poll_citizentic_jjy200 ( unit, peer ) ; 956280849Scy break ; 957200576Sroberto 958280849Scy case UNITTYPE_TRISTATE_GPSCLOCK01 : 959285169Scy jjy_poll_tristate_gpsclock01 ( unit, peer ) ; 960280849Scy break ; 961280849Scy 962285169Scy case UNITTYPE_SEIKO_TIMESYS_TDC_300 : 963285169Scy jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ; 964285169Scy break ; 965285169Scy 966285169Scy case UNITTYPE_TELEPHONE : 967285169Scy jjy_poll_telephone ( unit, peer ) ; 968285169Scy break ; 969285169Scy 970106163Sroberto default : 971106163Sroberto break ; 972106163Sroberto 973106163Sroberto } 974106163Sroberto 975285169Scy} 976106163Sroberto 977285169Scy/**************************************************************************************************/ 978285169Scy/* jjy_timer - called at one-second intervals */ 979285169Scy/**************************************************************************************************/ 980285169Scystatic void 981285169Scyjjy_timer ( int unit, struct peer *peer ) 982285169Scy{ 983285169Scy 984285169Scy struct refclockproc *pp ; 985285169Scy struct jjyunit *up ; 986285169Scy 987285169Scy#ifdef DEBUG 988285169Scy if ( debug ) { 989285169Scy printf ( "refclock_jjy.c : jjy_timer\n" ) ; 990280849Scy } 991285169Scy#endif 992106163Sroberto 993285169Scy pp = peer->procptr ; 994285169Scy up = pp->unitptr ; 995200576Sroberto 996285169Scy if ( up->bReceiveFlag ) { 997285169Scy#ifdef DEBUG 998285169Scy if ( debug ) { 999285169Scy printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ; 1000106163Sroberto } 1001285169Scy#endif 1002106163Sroberto return ; 1003106163Sroberto } 1004106163Sroberto 1005285169Scy switch ( up->unittype ) { 1006362716Scy 1007285169Scy case UNITTYPE_TELEPHONE : 1008285169Scy jjy_timer_telephone ( unit, peer ) ; 1009285169Scy break ; 1010285169Scy 1011285169Scy default : 1012285169Scy break ; 1013285169Scy 1014285169Scy } 1015285169Scy 1016285169Scy} 1017285169Scy 1018285169Scy/**************************************************************************************************/ 1019285169Scy/* jjy_synctime */ 1020285169Scy/**************************************************************************************************/ 1021285169Scystatic void 1022285169Scyjjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 1023285169Scy{ 1024285169Scy 1025285169Scy char sLog [ 80 ], cStatus ; 1026285169Scy const char *pStatus ; 1027285169Scy 1028106163Sroberto pp->year = up->year ; 1029285169Scy pp->day = ymd2yd( up->year, up->month, up->day ) ; 1030106163Sroberto pp->hour = up->hour ; 1031106163Sroberto pp->minute = up->minute ; 1032106163Sroberto pp->second = up->second ; 1033285169Scy pp->nsec = up->msecond * 1000000 ; 1034106163Sroberto 1035362716Scy /* 1036362716Scy * JST to UTC 1037106163Sroberto */ 1038106163Sroberto pp->hour -= 9 ; 1039106163Sroberto if ( pp->hour < 0 ) { 1040106163Sroberto pp->hour += 24 ; 1041106163Sroberto pp->day -- ; 1042106163Sroberto if ( pp->day < 1 ) { 1043106163Sroberto pp->year -- ; 1044285169Scy pp->day = ymd2yd( pp->year, 12, 31 ) ; 1045106163Sroberto } 1046106163Sroberto } 1047106163Sroberto 1048106163Sroberto /* 1049106163Sroberto * Process the new sample in the median filter and determine the 1050106163Sroberto * timecode timestamp. 1051106163Sroberto */ 1052182007Sroberto 1053285169Scy if ( ! refclock_process( pp ) ) { 1054285169Scy refclock_report( peer, CEVNT_BADTIME ) ; 1055285169Scy return ; 1056285169Scy } 1057285169Scy 1058285169Scy pp->lastref = pp->lastrec ; 1059285169Scy 1060285169Scy refclock_receive( peer ) ; 1061285169Scy 1062285169Scy /* 1063285169Scy * Write into the clockstats file 1064285169Scy */ 1065285169Scy snprintf ( sLog, sizeof(sLog), 1066285169Scy "%04d/%02d/%02d %02d:%02d:%02d.%03d JST ( %04d/%03d %02d:%02d:%02d.%03d UTC )", 1067280849Scy up->year, up->month, up->day, 1068285169Scy up->hour, up->minute, up->second, up->msecond, 1069285169Scy pp->year, pp->day, pp->hour, pp->minute, pp->second, 1070285169Scy (int)(pp->nsec/1000000) ) ; 1071285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ; 1072182007Sroberto 1073285169Scy cStatus = ' ' ; 1074285169Scy pStatus = "" ; 1075285169Scy 1076285169Scy switch ( peer->status ) { 1077285169Scy case 0 : cStatus = ' ' ; pStatus = "Reject" ; break ; 1078285169Scy case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ; 1079285169Scy case 2 : cStatus = '.' ; pStatus = "Excess" ; break ; 1080285169Scy case 3 : cStatus = '-' ; pStatus = "Outlier" ; break ; 1081285169Scy case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ; 1082285169Scy case 5 : cStatus = '#' ; pStatus = "Selected" ; break ; 1083285169Scy case 6 : cStatus = '*' ; pStatus = "Sys.Peer" ; break ; 1084285169Scy case 7 : cStatus = 'o' ; pStatus = "PPS.Peer" ; break ; 1085362716Scy default : break ; 1086106163Sroberto } 1087106163Sroberto 1088285169Scy snprintf ( sLog, sizeof(sLog), 1089285169Scy "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.", 1090285169Scy peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ; 1091285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 1092182007Sroberto 1093106163Sroberto} 1094106163Sroberto 1095285169Scy/*################################################################################################*/ 1096285169Scy/*################################################################################################*/ 1097285169Scy/*## ##*/ 1098285169Scy/*## The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02 ##*/ 1099285169Scy/*## ##*/ 1100285169Scy/*## server 127.127.40.X mode 1 ##*/ 1101285169Scy/*## ##*/ 1102285169Scy/*################################################################################################*/ 1103285169Scy/*################################################################################################*/ 1104285169Scy/* */ 1105285169Scy/* Command Response Remarks */ 1106285169Scy/* -------------------- ---------------------------------------- ---------------------------- */ 1107285169Scy/* dcst<CR><LF> VALID<CR><LF> or INVALID<CR><LF> */ 1108285169Scy/* stus<CR><LF> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */ 1109285169Scy/* date<CR><LF> YYYY/MM/DD XXX<CR><LF> XXX is the day of the week */ 1110285169Scy/* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */ 1111285169Scy/* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */ 1112285169Scy/* */ 1113285169Scy/*################################################################################################*/ 1114285169Scy 1115285169Scy#define TS_JJY01_COMMAND_NUMBER_DATE 1 1116285169Scy#define TS_JJY01_COMMAND_NUMBER_TIME 2 1117285169Scy#define TS_JJY01_COMMAND_NUMBER_STIM 3 1118285169Scy#define TS_JJY01_COMMAND_NUMBER_STUS 4 1119285169Scy#define TS_JJY01_COMMAND_NUMBER_DCST 5 1120285169Scy 1121285169Scy#define TS_JJY01_REPLY_DATE "yyyy/mm/dd www" 1122285169Scy#define TS_JJY01_REPLY_STIM "hh:mm:ss" 1123285169Scy#define TS_JJY01_REPLY_STUS_ADJUSTED "adjusted" 1124285169Scy#define TS_JJY01_REPLY_STUS_UNADJUSTED "unadjusted" 1125285169Scy#define TS_JJY01_REPLY_DCST_VALID "valid" 1126285169Scy#define TS_JJY01_REPLY_DCST_INVALID "invalid" 1127285169Scy 1128285169Scy#define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */ 1129285169Scy#define TS_JJY01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */ 1130285169Scy#define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */ 1131285169Scy#define TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED 8 /* Length without <CR><LF> */ 1132285169Scy#define TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED 10 /* Length without <CR><LF> */ 1133285169Scy#define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */ 1134285169Scy#define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */ 1135285169Scy 1136285169Scystatic struct 1137285169Scy{ 1138285169Scy const char commandNumber ; 1139285169Scy const char *command ; 1140285169Scy int commandLength ; 1141285169Scy int iExpectedReplyLength [ 2 ] ; 1142285169Scy} tristate_jjy01_command_sequence[] = 1143285169Scy{ 1144285169Scy { 0, NULL, 0, { 0, 0 } }, /* Idle */ 1145285169Scy { TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID , TS_JJY01_REPLY_LENGTH_DCST_INVALID } }, 1146285169Scy { TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } }, 1147285169Scy { TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME , TS_JJY01_REPLY_LENGTH_TIME } }, 1148285169Scy { TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE , TS_JJY01_REPLY_LENGTH_DATE } }, 1149285169Scy { TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM , TS_JJY01_REPLY_LENGTH_STIM } }, 1150285169Scy /* End of command */ 1151285169Scy { 0, NULL, 0, { 0, 0 } } 1152285169Scy} ; 1153285169Scy 1154106163Sroberto/**************************************************************************************************/ 1155106163Sroberto 1156106163Srobertostatic int 1157285169Scyjjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up ) 1158285169Scy{ 1159285169Scy 1160285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ; 1161285169Scy 1162285169Scy up->unittype = UNITTYPE_TRISTATE_JJY01 ; 1163285169Scy up->linespeed = SPEED232_TRISTATE_JJY01 ; 1164285169Scy up->linediscipline = LDISC_CLK ; 1165285169Scy 1166362716Scy time( &(up->tLastAdjustedTimestamp) ) ; 1167362716Scy up->bStusReplyAdjustedAtLeastOnce = FALSE ; 1168362716Scy 1169285169Scy return 0 ; 1170285169Scy 1171285169Scy} 1172285169Scy 1173285169Scy/**************************************************************************************************/ 1174285169Scy 1175285169Scystatic int 1176106163Srobertojjy_receive_tristate_jjy01 ( struct recvbuf *rbufp ) 1177106163Sroberto{ 1178280849Scy struct jjyunit *up ; 1179106163Sroberto struct refclockproc *pp ; 1180280849Scy struct peer *peer; 1181106163Sroberto 1182362716Scy char * pBuf ; 1183362716Scy char sLog [ MAX_LOGTEXT ] ; 1184362716Scy int iLen ; 1185362716Scy int rc ; 1186362716Scy time_t now ; 1187362716Scy double fSeconds ; 1188106163Sroberto 1189294554Sdelphij const char * pCmd ; 1190294554Sdelphij int iCmdLen ; 1191280849Scy 1192285169Scy /* Initialize pointers */ 1193285169Scy 1194280849Scy peer = rbufp->recv_peer ; 1195106163Sroberto pp = peer->procptr ; 1196280849Scy up = pp->unitptr ; 1197106163Sroberto 1198106163Sroberto if ( up->linediscipline == LDISC_RAW ) { 1199285169Scy pBuf = up->sTextBuf ; 1200285169Scy iLen = up->iTextBufLen ; 1201106163Sroberto } else { 1202280849Scy pBuf = pp->a_lastcode ; 1203280849Scy iLen = pp->lencode ; 1204106163Sroberto } 1205106163Sroberto 1206285169Scy DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ; 1207106163Sroberto 1208285169Scy /* Check expected reply */ 1209106163Sroberto 1210285169Scy if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) { 1211285169Scy /* Command sequence has not been started, or has been completed */ 1212285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 1213285169Scy pBuf ) ; 1214285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1215285169Scy up->bLineError = TRUE ; 1216285169Scy return JJY_RECEIVE_ERROR ; 1217285169Scy } 1218280849Scy 1219285169Scy /* Check reply length */ 1220182007Sroberto 1221285169Scy if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0] 1222285169Scy && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) { 1223285169Scy /* Unexpected reply length */ 1224285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1225285169Scy iLen ) ; 1226285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1227285169Scy up->bLineError = TRUE ; 1228285169Scy return JJY_RECEIVE_ERROR ; 1229285169Scy } 1230182007Sroberto 1231285169Scy /* Parse reply */ 1232182007Sroberto 1233285169Scy switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) { 1234182007Sroberto 1235285169Scy case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */ 1236285169Scy 1237285169Scy rc = sscanf ( pBuf, "%4d/%2d/%2d", 1238285169Scy &up->year, &up->month, &up->day ) ; 1239285169Scy 1240285169Scy if ( rc != 3 || up->year < 2000 || 2099 <= up->year 1241285169Scy || up->month < 1 || 12 < up->month 1242285169Scy || up->day < 1 || 31 < up->day ) { 1243285169Scy /* Invalid date */ 1244285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 1245285169Scy rc, up->year, up->month, up->day ) ; 1246285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1247285169Scy up->bLineError = TRUE ; 1248285169Scy return JJY_RECEIVE_ERROR ; 1249285169Scy } 1250285169Scy 1251280849Scy break ; 1252106163Sroberto 1253280849Scy case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 1254280849Scy case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */ 1255106163Sroberto 1256285169Scy if ( up->iTimestampCount >= 2 ) { 1257285169Scy /* Too many time reply */ 1258285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY, 1259285169Scy up->iTimestampCount ) ; 1260285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1261285169Scy up->bLineError = TRUE ; 1262285169Scy return JJY_RECEIVE_ERROR ; 1263106163Sroberto } 1264280849Scy 1265285169Scy rc = sscanf ( pBuf, "%2d:%2d:%2d", 1266285169Scy &up->hour, &up->minute, &up->second ) ; 1267285169Scy 1268280849Scy if ( rc != 3 || up->hour > 23 || up->minute > 59 || 1269280849Scy up->second > 60 ) { 1270285169Scy /* Invalid time */ 1271285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 1272285169Scy rc, up->hour, up->minute, up->second ) ; 1273285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1274285169Scy up->bLineError = TRUE ; 1275285169Scy return JJY_RECEIVE_ERROR ; 1276106163Sroberto } 1277280849Scy 1278285169Scy up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 1279285169Scy 1280285169Scy up->iTimestampCount++ ; 1281285169Scy 1282106163Sroberto up->msecond = 0 ; 1283285169Scy 1284106163Sroberto break ; 1285106163Sroberto 1286280849Scy case TS_JJY01_COMMAND_NUMBER_STUS : 1287280849Scy 1288285169Scy if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED, 1289362716Scy TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0 ) { 1290362716Scy /* STUS reply : adjusted */ 1291362716Scy up->bStusReplyAdjusted = TRUE ; 1292362716Scy up->bStusReplyAdjustedAtLeastOnce = TRUE ; 1293362716Scy time( &(up->tLastAdjustedTimestamp) ) ; 1294362716Scy } else if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED, 1295362716Scy TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) { 1296362716Scy /* STUS reply : unadjusted */ 1297362716Scy up->bStusReplyAdjusted = FALSE ; 1298280849Scy } else { 1299362716Scy /* Bad reply */ 1300285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1301285169Scy pBuf ) ; 1302285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1303285169Scy up->bLineError = TRUE ; 1304285169Scy return JJY_RECEIVE_ERROR ; 1305280849Scy } 1306280849Scy 1307280849Scy break ; 1308280849Scy 1309280849Scy case TS_JJY01_COMMAND_NUMBER_DCST : 1310280849Scy 1311285169Scy if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID, 1312362716Scy TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 1313285169Scy || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID, 1314362716Scy TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) { 1315362716Scy /* Valid reply */ 1316280849Scy } else { 1317362716Scy /* Bad reply */ 1318285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1319285169Scy pBuf ) ; 1320285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1321285169Scy up->bLineError = TRUE ; 1322285169Scy return JJY_RECEIVE_ERROR ; 1323280849Scy } 1324280849Scy 1325280849Scy break ; 1326280849Scy 1327362716Scy default : /* Unexpected reply */ 1328106163Sroberto 1329285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1330285169Scy pBuf ) ; 1331285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1332285169Scy up->bLineError = TRUE ; 1333285169Scy return JJY_RECEIVE_ERROR ; 1334106163Sroberto 1335106163Sroberto } 1336106163Sroberto 1337285169Scy if ( up->iTimestampCount == 2 ) { 1338285169Scy /* Process date and time */ 1339106163Sroberto 1340362716Scy time( &now ) ; 1341362716Scy fSeconds = difftime( now, up->tLastAdjustedTimestamp ) ; 1342362716Scy 1343362716Scy if ( ( pp->sloppyclockflag & CLK_FLAG2 ) != 0 1344362716Scy && ( ! up->bStusReplyAdjusted ) 1345362716Scy && ( fSeconds >= ( pp->fudgetime2 * 3600 ) || ( ! up->bStusReplyAdjustedAtLeastOnce ) ) ) { 1346362716Scy /* STUS is not ADJUSTED */ 1347362716Scy if ( fSeconds < 60 ) { 1348362716Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds, "seconds" ) ; 1349362716Scy } else if ( fSeconds < 3600 ) { 1350362716Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 60, "minutes" ) ; 1351362716Scy } else if ( fSeconds < 86400 ) { 1352362716Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 3600, "hours" ) ; 1353362716Scy } else { 1354362716Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_STUS_UNADJUSTED, fSeconds / 86400, "days" ) ; 1355362716Scy } 1356362716Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 1357362716Scy return JJY_RECEIVE_SKIP ; 1358362716Scy } else if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0] 1359362716Scy && up->iTimestamp[0] <= up->iTimestamp[1] ) { 1360362716Scy /* 3 commands (time,date,stim) was executed in two seconds */ 1361285169Scy jjy_synctime( peer, pp, up ) ; 1362285169Scy return JJY_RECEIVE_DONE ; 1363285169Scy } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) { 1364285169Scy /* Over midnight, and date is unsure */ 1365285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2, 1366285169Scy up->iTimestamp[0], up->iTimestamp[1] ) ; 1367285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 1368285169Scy return JJY_RECEIVE_SKIP ; 1369285169Scy } else { 1370285169Scy /* Slow reply */ 1371285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2, 1372285169Scy up->iTimestamp[0], up->iTimestamp[1] ) ; 1373285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1374285169Scy up->bLineError = TRUE ; 1375285169Scy return JJY_RECEIVE_ERROR ; 1376285169Scy } 1377280849Scy 1378280849Scy } 1379280849Scy 1380285169Scy /* Issue next command */ 1381285169Scy 1382285169Scy if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) { 1383285169Scy up->iCommandSeq ++ ; 1384280849Scy } 1385280849Scy 1386285169Scy if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) { 1387280849Scy /* Command sequence completed */ 1388285169Scy return JJY_RECEIVE_DONE ; 1389280849Scy } 1390280849Scy 1391285169Scy pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ; 1392285169Scy iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ; 1393285169Scy if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1394285169Scy refclock_report ( peer, CEVNT_FAULT ) ; 1395285169Scy } 1396280849Scy 1397285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 1398285169Scy 1399285169Scy return JJY_RECEIVE_WAIT ; 1400285169Scy 1401285169Scy} 1402285169Scy 1403285169Scy/**************************************************************************************************/ 1404285169Scy 1405285169Scystatic void 1406285169Scyjjy_poll_tristate_jjy01 ( int unit, struct peer *peer ) 1407285169Scy{ 1408280849Scy#ifdef DEBUG 1409285169Scy static const char *sFunctionName = "jjy_poll_tristate_jjy01" ; 1410285169Scy#endif 1411285169Scy 1412285169Scy struct refclockproc *pp ; 1413285169Scy struct jjyunit *up ; 1414285169Scy 1415294554Sdelphij const char * pCmd ; 1416294554Sdelphij int iCmdLen ; 1417285169Scy 1418285169Scy pp = peer->procptr; 1419285169Scy up = pp->unitptr ; 1420285169Scy 1421285169Scy up->bLineError = FALSE ; 1422285169Scy up->iTimestampCount = 0 ; 1423285169Scy 1424285169Scy if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 1425285169Scy /* Skip "dcst" and "stus" commands */ 1426285169Scy up->iCommandSeq = 2 ; 1427285169Scy up->iLineCount = 2 ; 1428285169Scy } 1429285169Scy 1430362716Scy up->bStusReplyAdjusted = FALSE ; 1431362716Scy 1432285169Scy#ifdef DEBUG 1433280849Scy if ( debug ) { 1434285169Scy printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n", 1435285169Scy sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 1436285169Scy up->iLineCount ) ; 1437280849Scy } 1438280849Scy#endif 1439280849Scy 1440285169Scy /* 1441285169Scy * Send a first command 1442285169Scy */ 1443285169Scy 1444285169Scy up->iCommandSeq ++ ; 1445285169Scy 1446285169Scy pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ; 1447285169Scy iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ; 1448280849Scy if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1449280849Scy refclock_report ( peer, CEVNT_FAULT ) ; 1450280849Scy } 1451280849Scy 1452285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 1453285169Scy 1454285169Scy} 1455285169Scy 1456285169Scy/*################################################################################################*/ 1457285169Scy/*################################################################################################*/ 1458285169Scy/*## ##*/ 1459285169Scy/*## The C-DEX Co. Ltd. JJY receiver JST2000 ##*/ 1460285169Scy/*## ##*/ 1461285169Scy/*## server 127.127.40.X mode 2 ##*/ 1462285169Scy/*## ##*/ 1463285169Scy/*################################################################################################*/ 1464285169Scy/*################################################################################################*/ 1465285169Scy/* */ 1466285169Scy/* Command Response Remarks */ 1467285169Scy/* -------------------- ---------------------------------------- ---------------------------- */ 1468362716Scy/* <ENQ>1J<ETX> <STX>JYYMMDDWHHMMSSS<ETX> J is a fixed character */ 1469285169Scy/* */ 1470285169Scy/*################################################################################################*/ 1471285169Scy 1472285169Scystatic struct jjyRawDataBreak cdex_jst2000_raw_break [ ] = 1473285169Scy{ 1474285169Scy { "\x03", 1 }, { NULL, 0 } 1475285169Scy} ; 1476285169Scy 1477285169Scy/**************************************************************************************************/ 1478285169Scy 1479285169Scystatic int 1480285169Scyjjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up ) 1481285169Scy{ 1482285169Scy 1483285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ; 1484285169Scy 1485285169Scy up->unittype = UNITTYPE_CDEX_JST2000 ; 1486285169Scy up->linespeed = SPEED232_CDEX_JST2000 ; 1487285169Scy up->linediscipline = LDISC_RAW ; 1488285169Scy 1489285169Scy up->pRawBreak = cdex_jst2000_raw_break ; 1490285169Scy up->bWaitBreakString = TRUE ; 1491285169Scy 1492285169Scy up->bSkipCntrlCharOnly = FALSE ; 1493285169Scy 1494280849Scy return 0 ; 1495280849Scy 1496106163Sroberto} 1497106163Sroberto 1498106163Sroberto/**************************************************************************************************/ 1499106163Sroberto 1500106163Srobertostatic int 1501106163Srobertojjy_receive_cdex_jst2000 ( struct recvbuf *rbufp ) 1502106163Sroberto{ 1503106163Sroberto 1504106163Sroberto struct jjyunit *up ; 1505106163Sroberto struct refclockproc *pp ; 1506285169Scy struct peer *peer ; 1507106163Sroberto 1508362716Scy char *pBuf, sLog [ MAX_LOGTEXT ] ; 1509106163Sroberto int iLen ; 1510106163Sroberto int rc ; 1511106163Sroberto 1512285169Scy /* Initialize pointers */ 1513285169Scy 1514280849Scy peer = rbufp->recv_peer ; 1515106163Sroberto pp = peer->procptr ; 1516280849Scy up = pp->unitptr ; 1517106163Sroberto 1518106163Sroberto if ( up->linediscipline == LDISC_RAW ) { 1519285169Scy pBuf = up->sTextBuf ; 1520285169Scy iLen = up->iTextBufLen ; 1521106163Sroberto } else { 1522280849Scy pBuf = pp->a_lastcode ; 1523280849Scy iLen = pp->lencode ; 1524106163Sroberto } 1525106163Sroberto 1526285169Scy DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ; 1527106163Sroberto 1528285169Scy /* Check expected reply */ 1529106163Sroberto 1530285169Scy if ( up->iCommandSeq != 1 ) { 1531285169Scy /* Command sequence has not been started, or has been completed */ 1532285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 1533285169Scy pBuf ) ; 1534285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1535285169Scy up->bLineError = TRUE ; 1536285169Scy return JJY_RECEIVE_ERROR ; 1537285169Scy } 1538106163Sroberto 1539285169Scy /* Wait until ETX comes */ 1540106163Sroberto 1541285169Scy if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) { 1542285169Scy return JJY_RECEIVE_UNPROCESS ; 1543285169Scy } 1544106163Sroberto 1545285169Scy /* Check reply length */ 1546285169Scy 1547285169Scy if ( iLen != 15 ) { 1548285169Scy /* Unexpected reply length */ 1549285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1550285169Scy iLen ) ; 1551285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1552285169Scy up->bLineError = TRUE ; 1553285169Scy return JJY_RECEIVE_ERROR ; 1554106163Sroberto } 1555106163Sroberto 1556309007Sdelphij /* JYYMMDDWHHMMSSS */ 1557106163Sroberto 1558309007Sdelphij rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d", 1559285169Scy &up->year, &up->month, &up->day, 1560285169Scy &up->hour, &up->minute, &up->second, 1561285169Scy &up->msecond ) ; 1562285169Scy 1563285169Scy if ( rc != 7 || up->month < 1 || up->month > 12 || 1564285169Scy up->day < 1 || up->day > 31 || up->hour > 23 || 1565285169Scy up->minute > 59 || up->second > 60 ) { 1566285169Scy /* Invalid date and time */ 1567285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1568285169Scy rc, up->year, up->month, up->day, 1569285169Scy up->hour, up->minute, up->second ) ; 1570285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1571285169Scy up->bLineError = TRUE ; 1572285169Scy return JJY_RECEIVE_ERROR ; 1573285169Scy } 1574285169Scy 1575285169Scy up->year += 2000 ; 1576285169Scy up->msecond *= 100 ; 1577285169Scy 1578285169Scy jjy_synctime( peer, pp, up ) ; 1579285169Scy 1580285169Scy return JJY_RECEIVE_DONE ; 1581285169Scy 1582106163Sroberto} 1583106163Sroberto 1584106163Sroberto/**************************************************************************************************/ 1585182007Sroberto 1586285169Scystatic void 1587285169Scyjjy_poll_cdex_jst2000 ( int unit, struct peer *peer ) 1588285169Scy{ 1589285169Scy 1590285169Scy struct refclockproc *pp ; 1591285169Scy struct jjyunit *up ; 1592285169Scy 1593285169Scy pp = peer->procptr ; 1594285169Scy up = pp->unitptr ; 1595285169Scy 1596285169Scy up->bLineError = FALSE ; 1597285169Scy up->iRawBufLen = 0 ; 1598285169Scy up->iLineBufLen = 0 ; 1599285169Scy up->iTextBufLen = 0 ; 1600285169Scy 1601285169Scy /* 1602285169Scy * Send "<ENQ>1J<ETX>" command 1603285169Scy */ 1604285169Scy 1605285169Scy up->iCommandSeq ++ ; 1606285169Scy 1607285169Scy if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) { 1608285169Scy refclock_report ( peer, CEVNT_FAULT ) ; 1609285169Scy } 1610285169Scy 1611285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ; 1612285169Scy 1613285169Scy} 1614285169Scy 1615285169Scy/*################################################################################################*/ 1616285169Scy/*################################################################################################*/ 1617285169Scy/*## ##*/ 1618285169Scy/*## The Echo Keisokuki Co. Ltd. JJY receiver LT2000 ##*/ 1619285169Scy/*## ##*/ 1620285169Scy/*## server 127.127.40.X mode 3 ##*/ 1621285169Scy/*## ##*/ 1622285169Scy/*################################################################################################*/ 1623285169Scy/*################################################################################################*/ 1624285169Scy/* */ 1625285169Scy/* Command Response Remarks */ 1626285169Scy/* -------------------- ---------------------------------------- ---------------------------- */ 1627285169Scy/* # Mode 1 ( Request & Send ) */ 1628285169Scy/* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */ 1629285169Scy/* C Mode 2 ( Continuous ) */ 1630285169Scy/* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> 0.5 sec before time stamp */ 1631285169Scy/* <SUB> Second signal */ 1632285169Scy/* */ 1633285169Scy/*################################################################################################*/ 1634285169Scy 1635285169Scy#define ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1 1636285169Scy#define ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 2 1637285169Scy#define ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 3 1638285169Scy 1639285169Scy#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND "#" 1640285169Scy#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME "T" 1641285169Scy#define ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS "C" 1642285169Scy 1643285169Scy/**************************************************************************************************/ 1644285169Scy 1645182007Srobertostatic int 1646285169Scyjjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up ) 1647285169Scy{ 1648285169Scy 1649285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ; 1650285169Scy 1651285169Scy up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ; 1652285169Scy up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ; 1653285169Scy up->linediscipline = LDISC_CLK ; 1654285169Scy 1655285169Scy up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ; 1656285169Scy 1657285169Scy return 0 ; 1658285169Scy 1659285169Scy} 1660285169Scy 1661285169Scy/**************************************************************************************************/ 1662285169Scy 1663285169Scystatic int 1664182007Srobertojjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp ) 1665182007Sroberto{ 1666182007Sroberto 1667182007Sroberto struct jjyunit *up ; 1668182007Sroberto struct refclockproc *pp ; 1669280849Scy struct peer *peer; 1670182007Sroberto 1671285169Scy char *pBuf, sLog [ 100 ], sErr [ 60 ] ; 1672182007Sroberto int iLen ; 1673182007Sroberto int rc ; 1674280849Scy int i, ibcc, ibcc1, ibcc2 ; 1675182007Sroberto 1676285169Scy /* Initialize pointers */ 1677285169Scy 1678280849Scy peer = rbufp->recv_peer ; 1679182007Sroberto pp = peer->procptr ; 1680280849Scy up = pp->unitptr ; 1681182007Sroberto 1682182007Sroberto if ( up->linediscipline == LDISC_RAW ) { 1683285169Scy pBuf = up->sTextBuf ; 1684285169Scy iLen = up->iTextBufLen ; 1685182007Sroberto } else { 1686280849Scy pBuf = pp->a_lastcode ; 1687280849Scy iLen = pp->lencode ; 1688182007Sroberto } 1689182007Sroberto 1690285169Scy DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ; 1691182007Sroberto 1692285169Scy /* Check reply length */ 1693182007Sroberto 1694285169Scy if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1695285169Scy && iLen != 15 ) 1696285169Scy || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1697285169Scy && iLen != 17 ) 1698285169Scy || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 1699285169Scy && iLen != 17 ) ) { 1700285169Scy /* Unexpected reply length */ 1701285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1702285169Scy iLen ) ; 1703285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1704285169Scy up->bLineError = TRUE ; 1705285169Scy return JJY_RECEIVE_ERROR ; 1706285169Scy } 1707182007Sroberto 1708285169Scy if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) { 1709285169Scy /* YYMMDDWHHMMSS<BCC1><BCC2> */ 1710182007Sroberto 1711285169Scy for ( i = ibcc = 0 ; i < 13 ; i ++ ) { 1712285169Scy ibcc ^= pBuf[i] ; 1713285169Scy } 1714182007Sroberto 1715285169Scy ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ; 1716285169Scy ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ; 1717285169Scy if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) { 1718285169Scy snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ", 1719285169Scy pBuf[13] & 0xFF, pBuf[14] & 0xFF, 1720285169Scy ibcc1, ibcc2 ) ; 1721285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1722285169Scy sErr ) ; 1723285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1724285169Scy up->bLineError = TRUE ; 1725285169Scy return JJY_RECEIVE_ERROR ; 1726280849Scy } 1727182007Sroberto 1728285169Scy } 1729285169Scy 1730285169Scy if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1731285169Scy && iLen == 15 ) 1732285169Scy || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1733285169Scy && iLen == 17 ) 1734285169Scy || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 1735285169Scy && iLen == 17 ) ) { 1736285169Scy /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */ 1737285169Scy 1738182007Sroberto rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d", 1739280849Scy &up->year, &up->month, &up->day, 1740280849Scy &up->hour, &up->minute, &up->second ) ; 1741285169Scy 1742285169Scy if ( rc != 6 || up->month < 1 || up->month > 12 1743285169Scy || up->day < 1 || up->day > 31 1744285169Scy || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 1745285169Scy /* Invalid date and time */ 1746285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1747285169Scy rc, up->year, up->month, up->day, 1748285169Scy up->hour, up->minute, up->second ) ; 1749285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1750285169Scy up->bLineError = TRUE ; 1751285169Scy return JJY_RECEIVE_ERROR ; 1752182007Sroberto } 1753182007Sroberto 1754182007Sroberto up->year += 2000 ; 1755182007Sroberto 1756285169Scy if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1757285169Scy || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) { 1758285169Scy /* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */ 1759182007Sroberto 1760182007Sroberto up->msecond = 500 ; 1761285169Scy up->second -- ; 1762285169Scy if ( up->second < 0 ) { 1763285169Scy up->second = 59 ; 1764285169Scy up->minute -- ; 1765285169Scy if ( up->minute < 0 ) { 1766285169Scy up->minute = 59 ; 1767285169Scy up->hour -- ; 1768285169Scy if ( up->hour < 0 ) { 1769285169Scy up->hour = 23 ; 1770285169Scy up->day -- ; 1771285169Scy if ( up->day < 1 ) { 1772285169Scy up->month -- ; 1773285169Scy if ( up->month < 1 ) { 1774285169Scy up->month = 12 ; 1775285169Scy up->year -- ; 1776285169Scy } 1777182007Sroberto } 1778182007Sroberto } 1779182007Sroberto } 1780182007Sroberto } 1781182007Sroberto 1782182007Sroberto } 1783182007Sroberto 1784285169Scy jjy_synctime( peer, pp, up ) ; 1785182007Sroberto 1786182007Sroberto 1787285169Scy } 1788285169Scy 1789285169Scy if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) { 1790285169Scy /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */ 1791285169Scy 1792285169Scy iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ; 1793285169Scy if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen ) { 1794182007Sroberto refclock_report ( peer, CEVNT_FAULT ) ; 1795182007Sroberto } 1796182007Sroberto 1797285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ; 1798285169Scy 1799285169Scy } 1800285169Scy 1801285169Scy return JJY_RECEIVE_DONE ; 1802285169Scy 1803285169Scy} 1804285169Scy 1805285169Scy/**************************************************************************************************/ 1806285169Scy 1807285169Scystatic void 1808285169Scyjjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer ) 1809285169Scy{ 1810285169Scy 1811285169Scy struct refclockproc *pp ; 1812285169Scy struct jjyunit *up ; 1813285169Scy 1814285169Scy char sCmd[2] ; 1815285169Scy 1816285169Scy pp = peer->procptr ; 1817285169Scy up = pp->unitptr ; 1818285169Scy 1819285169Scy up->bLineError = FALSE ; 1820285169Scy 1821285169Scy /* 1822285169Scy * Send "T" or "C" command 1823285169Scy */ 1824285169Scy 1825285169Scy switch ( up->operationmode ) { 1826285169Scy case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND : 1827285169Scy sCmd[0] = 'T' ; 1828182007Sroberto break ; 1829285169Scy case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS : 1830285169Scy case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS : 1831285169Scy sCmd[0] = 'C' ; 1832285169Scy break ; 1833285169Scy } 1834285169Scy sCmd[1] = 0 ; 1835182007Sroberto 1836285169Scy if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) { 1837285169Scy refclock_report ( peer, CEVNT_FAULT ) ; 1838182007Sroberto } 1839182007Sroberto 1840285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ; 1841182007Sroberto 1842182007Sroberto} 1843182007Sroberto 1844285169Scy/*################################################################################################*/ 1845285169Scy/*################################################################################################*/ 1846285169Scy/*## ##*/ 1847285169Scy/*## The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 ##*/ 1848285169Scy/*## ##*/ 1849285169Scy/*## server 127.127.40.X mode 4 ##*/ 1850285169Scy/*## ##*/ 1851285169Scy/*################################################################################################*/ 1852285169Scy/*################################################################################################*/ 1853285169Scy/* */ 1854285169Scy/* Command Response Remarks */ 1855285169Scy/* -------------------- ---------------------------------------- ---------------------------- */ 1856285169Scy/* 'XX YY/MM/DD W HH:MM:SS<CR> XX:OK|NG|ER W:0(Mon)-6(Sun) */ 1857285169Scy/* */ 1858285169Scy/*################################################################################################*/ 1859285169Scy 1860285169Scystatic int 1861285169Scyjjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up ) 1862285169Scy{ 1863285169Scy 1864285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ; 1865285169Scy 1866285169Scy up->unittype = UNITTYPE_CITIZENTIC_JJY200 ; 1867285169Scy up->linespeed = SPEED232_CITIZENTIC_JJY200 ; 1868285169Scy up->linediscipline = LDISC_CLK ; 1869285169Scy 1870285169Scy return 0 ; 1871285169Scy 1872285169Scy} 1873285169Scy 1874182007Sroberto/**************************************************************************************************/ 1875200576Sroberto 1876200576Srobertostatic int 1877200576Srobertojjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp ) 1878200576Sroberto{ 1879200576Sroberto 1880280849Scy struct jjyunit *up ; 1881280849Scy struct refclockproc *pp ; 1882280849Scy struct peer *peer; 1883200576Sroberto 1884285169Scy char *pBuf, sLog [ 100 ], sMsg [ 16 ] ; 1885280849Scy int iLen ; 1886280849Scy int rc ; 1887280849Scy char cApostrophe, sStatus[3] ; 1888280849Scy int iWeekday ; 1889200576Sroberto 1890285169Scy /* Initialize pointers */ 1891285169Scy 1892280849Scy peer = rbufp->recv_peer ; 1893280849Scy pp = peer->procptr ; 1894280849Scy up = pp->unitptr ; 1895200576Sroberto 1896280849Scy if ( up->linediscipline == LDISC_RAW ) { 1897285169Scy pBuf = up->sTextBuf ; 1898285169Scy iLen = up->iTextBufLen ; 1899280849Scy } else { 1900280849Scy pBuf = pp->a_lastcode ; 1901280849Scy iLen = pp->lencode ; 1902280849Scy } 1903200576Sroberto 1904285169Scy DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ; 1905285169Scy 1906280849Scy /* 1907285169Scy * JJY-200 sends a timestamp every second. 1908285169Scy * So, a timestamp is ignored unless it is right after polled. 1909285169Scy */ 1910200576Sroberto 1911285169Scy if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) { 1912285169Scy return JJY_RECEIVE_SKIP ; 1913285169Scy } 1914200576Sroberto 1915285169Scy /* Check reply length */ 1916200576Sroberto 1917285169Scy if ( iLen != 23 ) { 1918285169Scy /* Unexpected reply length */ 1919285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1920285169Scy iLen ) ; 1921285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1922285169Scy up->bLineError = TRUE ; 1923285169Scy return JJY_RECEIVE_ERROR ; 1924285169Scy } 1925200576Sroberto 1926285169Scy /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 1927200576Sroberto 1928285169Scy rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d", 1929285169Scy &cApostrophe, sStatus, 1930285169Scy &up->year, &up->month, &up->day, &iWeekday, 1931285169Scy &up->hour, &up->minute, &up->second ) ; 1932285169Scy sStatus[2] = 0 ; 1933280849Scy 1934285169Scy if ( rc != 9 || cApostrophe != '\'' 1935285169Scy || ( strcmp( sStatus, "OK" ) != 0 1936285169Scy && strcmp( sStatus, "NG" ) != 0 1937285169Scy && strcmp( sStatus, "ER" ) != 0 ) 1938285169Scy || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 1939285169Scy || iWeekday > 6 1940285169Scy || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 1941285169Scy /* Invalid date and time */ 1942285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1943285169Scy rc, up->year, up->month, up->day, 1944285169Scy up->hour, up->minute, up->second ) ; 1945285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1946285169Scy up->bLineError = TRUE ; 1947285169Scy return JJY_RECEIVE_ERROR ; 1948285169Scy } else if ( strcmp( sStatus, "NG" ) == 0 1949285169Scy || strcmp( sStatus, "ER" ) == 0 ) { 1950285169Scy /* Timestamp is unsure */ 1951285169Scy snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ; 1952285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE, 1953285169Scy sMsg ) ; 1954285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 1955285169Scy return JJY_RECEIVE_SKIP ; 1956285169Scy } 1957280849Scy 1958285169Scy up->year += 2000 ; 1959285169Scy up->msecond = 0 ; 1960280849Scy 1961285169Scy jjy_synctime( peer, pp, up ) ; 1962280849Scy 1963285169Scy return JJY_RECEIVE_DONE ; 1964280849Scy 1965285169Scy} 1966280849Scy 1967285169Scy/**************************************************************************************************/ 1968285169Scy 1969285169Scystatic void 1970285169Scyjjy_poll_citizentic_jjy200 ( int unit, struct peer *peer ) 1971285169Scy{ 1972285169Scy 1973285169Scy struct refclockproc *pp ; 1974285169Scy struct jjyunit *up ; 1975285169Scy 1976285169Scy pp = peer->procptr ; 1977285169Scy up = pp->unitptr ; 1978285169Scy 1979285169Scy up->bLineError = FALSE ; 1980285169Scy 1981280849Scy} 1982280849Scy 1983285169Scy/*################################################################################################*/ 1984285169Scy/*################################################################################################*/ 1985285169Scy/*## ##*/ 1986285169Scy/*## The Tristate Ltd. GPS clock TS-GPS01 ##*/ 1987285169Scy/*## ##*/ 1988285169Scy/*## server 127.127.40.X mode 5 ##*/ 1989285169Scy/*## ##*/ 1990285169Scy/*################################################################################################*/ 1991285169Scy/*################################################################################################*/ 1992285169Scy/* */ 1993362716Scy/* This clock has NMEA mode and command/response mode. */ 1994362716Scy/* When this jjy driver are used, set to command/response mode of this clock */ 1995285169Scy/* by the onboard switch SW4, and make sure the LED-Y is tured on. */ 1996285169Scy/* Other than this JJY driver, the refclock driver type 20, generic NMEA driver, */ 1997285169Scy/* works with the NMEA mode of this clock. */ 1998285169Scy/* */ 1999285169Scy/* Command Response Remarks */ 2000285169Scy/* -------------------- ---------------------------------------- ---------------------------- */ 2001285169Scy/* stus<CR><LF> *R|*G|*U|+U<CR><LF> */ 2002285169Scy/* date<CR><LF> YY/MM/DD<CR><LF> */ 2003285169Scy/* time<CR><LF> HH:MM:SS<CR><LF> */ 2004285169Scy/* */ 2005285169Scy/*################################################################################################*/ 2006285169Scy 2007285169Scy#define TS_GPS01_COMMAND_NUMBER_DATE 1 2008285169Scy#define TS_GPS01_COMMAND_NUMBER_TIME 2 2009285169Scy#define TS_GPS01_COMMAND_NUMBER_STUS 4 2010285169Scy 2011285169Scy#define TS_GPS01_REPLY_DATE "yyyy/mm/dd" 2012285169Scy#define TS_GPS01_REPLY_TIME "hh:mm:ss" 2013285169Scy#define TS_GPS01_REPLY_STUS_RTC "*R" 2014285169Scy#define TS_GPS01_REPLY_STUS_GPS "*G" 2015285169Scy#define TS_GPS01_REPLY_STUS_UTC "*U" 2016285169Scy#define TS_GPS01_REPLY_STUS_PPS "+U" 2017285169Scy 2018285169Scy#define TS_GPS01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */ 2019285169Scy#define TS_GPS01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */ 2020285169Scy#define TS_GPS01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */ 2021285169Scy 2022285169Scystatic struct 2023285169Scy{ 2024285169Scy char commandNumber ; 2025285169Scy const char *command ; 2026285169Scy int commandLength ; 2027285169Scy int iExpectedReplyLength ; 2028285169Scy} tristate_gps01_command_sequence[] = 2029285169Scy{ 2030285169Scy { 0, NULL, 0, 0 }, /* Idle */ 2031285169Scy { TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS }, 2032285169Scy { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME }, 2033285169Scy { TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE }, 2034285169Scy { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME }, 2035285169Scy /* End of command */ 2036285169Scy { 0, NULL, 0, 0 } 2037285169Scy} ; 2038285169Scy 2039280849Scy/**************************************************************************************************/ 2040280849Scy 2041280849Scystatic int 2042285169Scyjjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up ) 2043285169Scy{ 2044285169Scy 2045285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ; 2046285169Scy 2047285169Scy up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ; 2048285169Scy up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ; 2049285169Scy up->linediscipline = LDISC_CLK ; 2050285169Scy 2051285169Scy return 0 ; 2052285169Scy 2053285169Scy} 2054285169Scy 2055285169Scy/**************************************************************************************************/ 2056285169Scy 2057285169Scystatic int 2058280849Scyjjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp ) 2059280849Scy{ 2060200576Sroberto#ifdef DEBUG 2061280849Scy static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ; 2062200576Sroberto#endif 2063200576Sroberto 2064280849Scy struct jjyunit *up ; 2065280849Scy struct refclockproc *pp ; 2066280849Scy struct peer *peer; 2067200576Sroberto 2068294554Sdelphij char * pBuf ; 2069362716Scy char sLog [ MAX_LOGTEXT ] ; 2070294554Sdelphij int iLen ; 2071294554Sdelphij int rc ; 2072200576Sroberto 2073294554Sdelphij const char * pCmd ; 2074294554Sdelphij int iCmdLen ; 2075200576Sroberto 2076285169Scy /* Initialize pointers */ 2077285169Scy 2078280849Scy peer = rbufp->recv_peer ; 2079280849Scy pp = peer->procptr ; 2080280849Scy up = pp->unitptr ; 2081200576Sroberto 2082280849Scy if ( up->linediscipline == LDISC_RAW ) { 2083285169Scy pBuf = up->sTextBuf ; 2084285169Scy iLen = up->iTextBufLen ; 2085280849Scy } else { 2086280849Scy pBuf = pp->a_lastcode ; 2087280849Scy iLen = pp->lencode ; 2088280849Scy } 2089280849Scy 2090285169Scy DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ; 2091285169Scy 2092285169Scy /* Ignore NMEA data stream */ 2093285169Scy 2094280849Scy if ( iLen > 5 2095280849Scy && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 2096280849Scy#ifdef DEBUG 2097280849Scy if ( debug ) { 2098280849Scy printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 2099280849Scy sFunctionName, pBuf ) ; 2100280849Scy } 2101280849Scy#endif 2102285169Scy return JJY_RECEIVE_WAIT ; 2103280849Scy } 2104280849Scy 2105280849Scy /* 2106280849Scy * Skip command prompt '$Cmd>' from the TS-GPSclock-01 2107280849Scy */ 2108280849Scy if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 2109285169Scy return JJY_RECEIVE_WAIT ; 2110280849Scy } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 2111280849Scy pBuf += 5 ; 2112280849Scy iLen -= 5 ; 2113280849Scy } 2114280849Scy 2115280849Scy /* 2116280849Scy * Ignore NMEA data stream after command prompt 2117280849Scy */ 2118280849Scy if ( iLen > 5 2119280849Scy && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 2120280849Scy#ifdef DEBUG 2121280849Scy if ( debug ) { 2122280849Scy printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 2123280849Scy sFunctionName, pBuf ) ; 2124280849Scy } 2125280849Scy#endif 2126285169Scy return JJY_RECEIVE_WAIT ; 2127280849Scy } 2128280849Scy 2129285169Scy /* Check expected reply */ 2130280849Scy 2131285169Scy if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2132285169Scy /* Command sequence has not been started, or has been completed */ 2133285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 2134285169Scy pBuf ) ; 2135285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2136285169Scy up->bLineError = TRUE ; 2137285169Scy return JJY_RECEIVE_ERROR ; 2138285169Scy } 2139280849Scy 2140285169Scy /* Check reply length */ 2141280849Scy 2142285169Scy if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) { 2143285169Scy /* Unexpected reply length */ 2144285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 2145285169Scy iLen ) ; 2146285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2147285169Scy up->bLineError = TRUE ; 2148285169Scy return JJY_RECEIVE_ERROR ; 2149285169Scy } 2150285169Scy 2151285169Scy /* Parse reply */ 2152285169Scy 2153285169Scy switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) { 2154285169Scy 2155285169Scy case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */ 2156285169Scy 2157280849Scy rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ; 2158285169Scy 2159285169Scy if ( rc != 3 || up->year < 2000 || 2099 <= up->year 2160285169Scy || up->month < 1 || 12 < up->month 2161285169Scy || up->day < 1 || 31 < up->day ) { 2162285169Scy /* Invalid date */ 2163285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 2164285169Scy rc, up->year, up->month, up->day ) ; 2165285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2166285169Scy up->bLineError = TRUE ; 2167285169Scy return JJY_RECEIVE_ERROR ; 2168280849Scy } 2169280849Scy 2170280849Scy break ; 2171280849Scy 2172285169Scy case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 2173280849Scy 2174285169Scy if ( up->iTimestampCount >= 2 ) { 2175285169Scy /* Too many time reply */ 2176285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY, 2177285169Scy up->iTimestampCount ) ; 2178285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2179285169Scy up->bLineError = TRUE ; 2180285169Scy return JJY_RECEIVE_ERROR ; 2181280849Scy } 2182280849Scy 2183285169Scy rc = sscanf ( pBuf, "%2d:%2d:%2d", 2184285169Scy &up->hour, &up->minute, &up->second ) ; 2185285169Scy 2186285169Scy if ( rc != 3 2187285169Scy || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2188285169Scy /* Invalid time */ 2189285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 2190285169Scy rc, up->hour, up->minute, up->second ) ; 2191285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2192285169Scy up->bLineError = TRUE ; 2193285169Scy return JJY_RECEIVE_ERROR ; 2194280849Scy } 2195280849Scy 2196285169Scy up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 2197285169Scy 2198285169Scy up->iTimestampCount++ ; 2199285169Scy 2200280849Scy up->msecond = 0 ; 2201280849Scy 2202280849Scy break ; 2203280849Scy 2204285169Scy case TS_GPS01_COMMAND_NUMBER_STUS : 2205280849Scy 2206285169Scy if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2207285169Scy || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2208285169Scy || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2209285169Scy || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) { 2210280849Scy /* Good */ 2211280849Scy } else { 2212285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2213285169Scy pBuf ) ; 2214285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2215285169Scy up->bLineError = TRUE ; 2216285169Scy return JJY_RECEIVE_ERROR ; 2217280849Scy } 2218280849Scy 2219280849Scy break ; 2220280849Scy 2221280849Scy default : /* Unexpected reply */ 2222280849Scy 2223285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2224285169Scy pBuf ) ; 2225285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2226285169Scy up->bLineError = TRUE ; 2227285169Scy return JJY_RECEIVE_ERROR ; 2228280849Scy 2229280849Scy } 2230280849Scy 2231285169Scy if ( up->iTimestampCount == 2 ) { 2232285169Scy /* Process date and time */ 2233280849Scy 2234285169Scy if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0] 2235285169Scy && up->iTimestamp[0] <= up->iTimestamp[1] ) { 2236362716Scy /* 3 commands (time,date,stim) was executed in two seconds */ 2237285169Scy jjy_synctime( peer, pp, up ) ; 2238285169Scy return JJY_RECEIVE_DONE ; 2239285169Scy } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) { 2240285169Scy /* Over midnight, and date is unsure */ 2241285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2, 2242285169Scy up->iTimestamp[0], up->iTimestamp[1] ) ; 2243285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 2244285169Scy return JJY_RECEIVE_SKIP ; 2245285169Scy } else { 2246285169Scy /* Slow reply */ 2247285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2, 2248285169Scy up->iTimestamp[0], up->iTimestamp[1] ) ; 2249285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2250285169Scy up->bLineError = TRUE ; 2251285169Scy return JJY_RECEIVE_ERROR ; 2252285169Scy } 2253280849Scy 2254285169Scy } 2255280849Scy 2256285169Scy if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2257285169Scy /* Command sequence completed */ 2258285169Scy jjy_synctime( peer, pp, up ) ; 2259285169Scy return JJY_RECEIVE_DONE ; 2260280849Scy } 2261280849Scy 2262285169Scy /* Issue next command */ 2263285169Scy 2264285169Scy if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) { 2265285169Scy up->iCommandSeq ++ ; 2266280849Scy } 2267280849Scy 2268285169Scy if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2269280849Scy /* Command sequence completed */ 2270285169Scy up->iProcessState = JJY_PROCESS_STATE_DONE ; 2271285169Scy return JJY_RECEIVE_DONE ; 2272280849Scy } 2273280849Scy 2274285169Scy pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ; 2275285169Scy iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ; 2276285169Scy if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 2277285169Scy refclock_report ( peer, CEVNT_FAULT ) ; 2278285169Scy } 2279280849Scy 2280285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 2281285169Scy 2282285169Scy return JJY_RECEIVE_WAIT ; 2283285169Scy 2284285169Scy} 2285285169Scy 2286285169Scy/**************************************************************************************************/ 2287285169Scy 2288285169Scystatic void 2289285169Scyjjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer ) 2290285169Scy{ 2291280849Scy#ifdef DEBUG 2292285169Scy static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ; 2293285169Scy#endif 2294285169Scy 2295285169Scy struct refclockproc *pp ; 2296285169Scy struct jjyunit *up ; 2297285169Scy 2298294554Sdelphij const char * pCmd ; 2299294554Sdelphij int iCmdLen ; 2300285169Scy 2301285169Scy pp = peer->procptr ; 2302285169Scy up = pp->unitptr ; 2303285169Scy 2304285169Scy up->iTimestampCount = 0 ; 2305285169Scy 2306285169Scy if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 2307285169Scy /* Skip "stus" command */ 2308285169Scy up->iCommandSeq = 1 ; 2309285169Scy up->iLineCount = 1 ; 2310285169Scy } 2311285169Scy 2312285169Scy#ifdef DEBUG 2313280849Scy if ( debug ) { 2314285169Scy printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n", 2315285169Scy sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 2316285169Scy up->iLineCount ) ; 2317280849Scy } 2318280849Scy#endif 2319280849Scy 2320285169Scy /* 2321285169Scy * Send a first command 2322285169Scy */ 2323285169Scy 2324285169Scy up->iCommandSeq ++ ; 2325285169Scy 2326285169Scy pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ; 2327285169Scy iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ; 2328280849Scy if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 2329280849Scy refclock_report ( peer, CEVNT_FAULT ) ; 2330280849Scy } 2331280849Scy 2332285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 2333285169Scy 2334285169Scy} 2335285169Scy 2336285169Scy/*################################################################################################*/ 2337285169Scy/*################################################################################################*/ 2338285169Scy/*## ##*/ 2339285169Scy/*## The SEIKO TIME SYSTEMS TDC-300 ##*/ 2340285169Scy/*## ##*/ 2341285169Scy/*## server 127.127.40.X mode 6 ##*/ 2342285169Scy/*## ##*/ 2343285169Scy/*################################################################################################*/ 2344285169Scy/*################################################################################################*/ 2345285169Scy/* */ 2346285169Scy/* Type Response Remarks */ 2347285169Scy/* -------------------- ---------------------------------------- ---------------------------- */ 2348285169Scy/* Type 1 <STX>HH:MM:SS<ETX> */ 2349285169Scy/* Type 2 <STX>YYMMDDHHMMSSWLSCU<ETX> W:0(Sun)-6(Sat) */ 2350285169Scy/* Type 3 <STX>YYMMDDWHHMMSS<ETX> W:0(Sun)-6(Sat) */ 2351285169Scy/* <STX><xE5><ETX> 5 to 10 mSec. before second */ 2352285169Scy/* */ 2353285169Scy/*################################################################################################*/ 2354285169Scy 2355285169Scystatic struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] = 2356285169Scy{ 2357285169Scy { "\x03", 1 }, { NULL, 0 } 2358285169Scy} ; 2359285169Scy 2360285169Scy/**************************************************************************************************/ 2361285169Scy 2362285169Scystatic int 2363285169Scyjjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up ) 2364285169Scy{ 2365285169Scy 2366285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ; 2367285169Scy 2368285169Scy up->unittype = UNITTYPE_SEIKO_TIMESYS_TDC_300 ; 2369285169Scy up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ; 2370285169Scy up->linediscipline = LDISC_RAW ; 2371285169Scy 2372285169Scy up->pRawBreak = seiko_tsys_tdc_300_raw_break ; 2373285169Scy up->bWaitBreakString = TRUE ; 2374285169Scy 2375285169Scy up->bSkipCntrlCharOnly = FALSE ; 2376285169Scy 2377280849Scy return 0 ; 2378280849Scy 2379200576Sroberto} 2380200576Sroberto 2381200576Sroberto/**************************************************************************************************/ 2382285169Scy 2383285169Scystatic int 2384285169Scyjjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp ) 2385106163Sroberto{ 2386106163Sroberto 2387285169Scy struct peer *peer; 2388285169Scy struct refclockproc *pp ; 2389285169Scy struct jjyunit *up ; 2390106163Sroberto 2391362716Scy char *pBuf, sLog [ MAX_LOGTEXT ] ; 2392285169Scy int iLen, i ; 2393285169Scy int rc, iWeekday ; 2394285169Scy time_t now ; 2395285169Scy struct tm *pTime ; 2396285169Scy 2397285169Scy /* Initialize pointers */ 2398285169Scy 2399285169Scy peer = rbufp->recv_peer ; 2400285169Scy pp = peer->procptr ; 2401280849Scy up = pp->unitptr ; 2402106163Sroberto 2403285169Scy if ( up->linediscipline == LDISC_RAW ) { 2404285169Scy pBuf = up->sTextBuf ; 2405285169Scy iLen = up->iTextBufLen ; 2406285169Scy } else { 2407285169Scy pBuf = pp->a_lastcode ; 2408285169Scy iLen = pp->lencode ; 2409106163Sroberto } 2410106163Sroberto 2411285169Scy DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ; 2412285169Scy 2413285169Scy /* 2414285169Scy * TDC-300 sends a timestamp every second. 2415285169Scy * So, a timestamp is ignored unless it is right after polled. 2416285169Scy */ 2417285169Scy 2418285169Scy if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) { 2419285169Scy return JJY_RECEIVE_SKIP ; 2420106163Sroberto } 2421106163Sroberto 2422285169Scy /* Process timestamp */ 2423106163Sroberto 2424285169Scy up->iReceiveSeq ++ ; 2425106163Sroberto 2426285169Scy switch ( iLen ) { 2427106163Sroberto 2428285169Scy case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */ 2429106163Sroberto 2430285169Scy for ( i = 0 ; i < iLen ; i ++ ) { 2431285169Scy pBuf[i] &= 0x7F ; 2432285169Scy } 2433182007Sroberto 2434285169Scy rc = sscanf ( pBuf+1, "%2d:%2d:%2d", 2435285169Scy &up->hour, &up->minute, &up->second ) ; 2436285169Scy 2437285169Scy if ( rc != 3 2438285169Scy || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2439285169Scy /* Invalid time */ 2440285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 2441285169Scy rc, up->hour, up->minute, up->second ) ; 2442285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2443285169Scy up->bLineError = TRUE ; 2444285169Scy return JJY_RECEIVE_ERROR ; 2445285169Scy } else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) { 2446285169Scy /* Uncertainty date guard */ 2447285169Scy return JJY_RECEIVE_WAIT ; 2448285169Scy } 2449285169Scy 2450285169Scy time( &now ) ; 2451285169Scy pTime = localtime( &now ) ; 2452285169Scy up->year = pTime->tm_year ; 2453285169Scy up->month = pTime->tm_mon + 1 ; 2454285169Scy up->day = pTime->tm_mday ; 2455285169Scy 2456280849Scy break ; 2457200576Sroberto 2458285169Scy case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */ 2459285169Scy 2460285169Scy for ( i = 0 ; i < iLen ; i ++ ) { 2461285169Scy pBuf[i] &= 0x7F ; 2462285169Scy } 2463285169Scy 2464285169Scy rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d", 2465285169Scy &up->year, &up->month, &up->day, 2466285169Scy &up->hour, &up->minute, &up->second, &iWeekday ) ; 2467285169Scy 2468285169Scy if ( rc != 7 2469285169Scy || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 2470285169Scy || iWeekday > 6 2471285169Scy || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2472285169Scy /* Invalid date and time */ 2473285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 2474285169Scy rc, up->year, up->month, up->day, 2475285169Scy up->hour, up->minute, up->second ) ; 2476285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2477285169Scy up->bLineError = TRUE ; 2478285169Scy return JJY_RECEIVE_ERROR ; 2479285169Scy } 2480285169Scy 2481280849Scy break ; 2482280849Scy 2483285169Scy case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */ 2484285169Scy 2485285169Scy rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d", 2486285169Scy &up->year, &up->month, &up->day, &iWeekday, 2487285169Scy &up->hour, &up->minute, &up->second ) ; 2488285169Scy 2489285169Scy if ( rc != 7 2490285169Scy || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 2491285169Scy || iWeekday > 6 2492285169Scy || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2493285169Scy /* Invalid date and time */ 2494285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 2495285169Scy rc, up->year, up->month, up->day, 2496285169Scy up->hour, up->minute, up->second ) ; 2497285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2498285169Scy up->bLineError = TRUE ; 2499285169Scy return JJY_RECEIVE_ERROR ; 2500285169Scy } 2501285169Scy 2502285169Scy return JJY_RECEIVE_WAIT ; 2503285169Scy 2504285169Scy case 1 : /* Type 3 : <STX><xE5><ETX> */ 2505285169Scy 2506285169Scy if ( ( *pBuf & 0xFF ) != 0xE5 ) { 2507285169Scy /* Invalid second signal */ 2508285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2509285169Scy up->sLineBuf ) ; 2510285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2511285169Scy up->bLineError = TRUE ; 2512285169Scy return JJY_RECEIVE_ERROR ; 2513285169Scy } else if ( up->iReceiveSeq == 1 ) { 2514285169Scy /* Wait for next timestamp */ 2515285169Scy up->iReceiveSeq -- ; 2516285169Scy return JJY_RECEIVE_WAIT ; 2517285169Scy } else if ( up->iReceiveSeq >= 3 ) { 2518285169Scy /* Unexpected second signal */ 2519285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 2520285169Scy up->sLineBuf ) ; 2521285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2522285169Scy up->bLineError = TRUE ; 2523285169Scy return JJY_RECEIVE_ERROR ; 2524285169Scy } 2525285169Scy 2526106163Sroberto break ; 2527106163Sroberto 2528285169Scy default : /* Unexpected reply length */ 2529285169Scy 2530285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 2531285169Scy iLen ) ; 2532285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2533285169Scy up->bLineError = TRUE ; 2534285169Scy return JJY_RECEIVE_ERROR ; 2535285169Scy 2536106163Sroberto } 2537106163Sroberto 2538285169Scy up->year += 2000 ; 2539285169Scy up->msecond = 0 ; 2540285169Scy 2541285169Scy jjy_synctime( peer, pp, up ) ; 2542285169Scy 2543285169Scy return JJY_RECEIVE_DONE ; 2544285169Scy 2545106163Sroberto} 2546106163Sroberto 2547106163Sroberto/**************************************************************************************************/ 2548106163Sroberto 2549106163Srobertostatic void 2550285169Scyjjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer ) 2551106163Sroberto{ 2552285169Scy 2553285169Scy struct refclockproc *pp ; 2554285169Scy struct jjyunit *up ; 2555285169Scy 2556285169Scy pp = peer->procptr ; 2557285169Scy up = pp->unitptr ; 2558285169Scy 2559285169Scy up->bLineError = FALSE ; 2560285169Scy 2561285169Scy} 2562285169Scy 2563285169Scy/*################################################################################################*/ 2564285169Scy/*################################################################################################*/ 2565285169Scy/*## ##*/ 2566285169Scy/*## Telephone JJY ##*/ 2567285169Scy/*## ##*/ 2568285169Scy/*## server 127.127.40.X mode 100 to 180 ##*/ 2569285169Scy/*## ##*/ 2570285169Scy/*################################################################################################*/ 2571285169Scy/*################################################################################################*/ 2572285169Scy/* */ 2573285169Scy/* Prompt Command Response Remarks */ 2574285169Scy/* -------------------- -------------------- -------------------- -------------------------- */ 2575285169Scy/* Name<SP>?<SP> TJJY<CR> Welcome messages TJJY is a guest user ID */ 2576285169Scy/* > 4DATE<CR> YYYYMMDD<CR> */ 2577285169Scy/* > LEAPSEC<CR> XX<CR> One of <SP>0, +1, -1 */ 2578285169Scy/* > TIME<CR> HHMMSS<CR> 3 times on second */ 2579285169Scy/* > BYE<CR> Sayounara messages */ 2580285169Scy/* */ 2581285169Scy/*################################################################################################*/ 2582285169Scy 2583285169Scystatic struct jjyRawDataBreak teljjy_raw_break [ ] = 2584285169Scy{ 2585285169Scy { "\r\n", 2 }, 2586285169Scy { "\r" , 1 }, 2587285169Scy { "\n" , 1 }, 2588285169Scy { "Name ? ", 7 }, 2589285169Scy { ">" , 1 }, 2590285169Scy { "+++" , 3 }, 2591285169Scy { NULL , 0 } 2592285169Scy} ; 2593285169Scy 2594285169Scy#define TELJJY_STATE_IDLE 0 2595285169Scy#define TELJJY_STATE_DAILOUT 1 2596285169Scy#define TELJJY_STATE_LOGIN 2 2597285169Scy#define TELJJY_STATE_CONNECT 3 2598285169Scy#define TELJJY_STATE_BYE 4 2599285169Scy 2600285169Scy#define TELJJY_EVENT_NULL 0 2601285169Scy#define TELJJY_EVENT_START 1 2602285169Scy#define TELJJY_EVENT_CONNECT 2 2603285169Scy#define TELJJY_EVENT_DISCONNECT 3 2604285169Scy#define TELJJY_EVENT_COMMAND 4 2605285169Scy#define TELJJY_EVENT_LOGIN 5 /* Posted by the jjy_receive_telephone */ 2606285169Scy#define TELJJY_EVENT_PROMPT 6 /* Posted by the jjy_receive_telephone */ 2607285169Scy#define TELJJY_EVENT_DATA 7 /* Posted by the jjy_receive_telephone */ 2608285169Scy#define TELJJY_EVENT_ERROR 8 /* Posted by the jjy_receive_telephone */ 2609285169Scy#define TELJJY_EVENT_SILENT 9 /* Posted by the jjy_timer_telephone */ 2610285169Scy#define TELJJY_EVENT_TIMEOUT 10 /* Posted by the jjy_timer_telephone */ 2611285169Scy 2612285169Scystatic void teljjy_control ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2613285169Scy 2614285169Scystatic int teljjy_idle_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2615285169Scystatic int teljjy_idle_dialout ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2616285169Scystatic int teljjy_dial_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2617285169Scystatic int teljjy_dial_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2618285169Scystatic int teljjy_dial_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2619285169Scystatic int teljjy_login_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2620285169Scystatic int teljjy_login_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2621285169Scystatic int teljjy_login_conn ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2622285169Scystatic int teljjy_login_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2623285169Scystatic int teljjy_login_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2624285169Scystatic int teljjy_login_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2625285169Scystatic int teljjy_conn_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2626285169Scystatic int teljjy_conn_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2627285169Scystatic int teljjy_conn_send ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2628285169Scystatic int teljjy_conn_data ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2629285169Scystatic int teljjy_conn_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2630285169Scystatic int teljjy_conn_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2631285169Scystatic int teljjy_bye_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2632285169Scystatic int teljjy_bye_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2633285169Scystatic int teljjy_bye_modem ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2634285169Scy 2635294554Sdelphijstatic int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) = 2636285169Scy{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2637285169Scy/* NULL */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2638285169Scy/* START */ { teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2639285169Scy/* CONNECT */ { teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2640285169Scy/* DISCONNECT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_disc , teljjy_conn_disc , teljjy_bye_disc }, 2641285169Scy/* COMMAND */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem }, 2642285169Scy/* LOGIN */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore }, 2643285169Scy/* PROMPT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn , teljjy_conn_send , teljjy_bye_ignore }, 2644285169Scy/* DATA */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data , teljjy_bye_ignore }, 2645285169Scy/* ERROR */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore }, 2646285169Scy/* SILENT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore }, 2647285169Scy/* TIMEOUT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem } 2648285169Scy} ; 2649285169Scy 2650285169Scystatic short iTeljjyNextState [ ] [ 5 ] = 2651285169Scy{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2652285169Scy/* NULL */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2653285169Scy/* START */ { TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2654285169Scy/* CONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_LOGIN , TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2655285169Scy/* DISCONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE }, 2656285169Scy/* COMMAND */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2657285169Scy/* LOGIN */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2658285169Scy/* PROMPT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2659285169Scy/* DATA */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2660285169Scy/* ERROR */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2661285169Scy/* SILENT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2662285169Scy/* TIMEOUT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE } 2663285169Scy} ; 2664285169Scy 2665285169Scystatic short iTeljjyPostEvent [ ] [ 5 ] = 2666285169Scy{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2667285169Scy/* NULL */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2668285169Scy/* START */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2669285169Scy/* CONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2670285169Scy/* DISCONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2671285169Scy/* COMMAND */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2672285169Scy/* LOGIN */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2673285169Scy/* PROMPT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2674285169Scy/* DATA */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2675285169Scy/* ERROR */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2676285169Scy/* SILENT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2677285169Scy/* TIMEOUT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL } 2678285169Scy} ; 2679285169Scy 2680285169Scystatic short iTeljjySilentTimeout [ 5 ] = { 0, 0, 10, 5, 0 } ; 2681285169Scystatic short iTeljjyStateTimeout [ 5 ] = { 0, 120, 60, 60, 40 } ; 2682285169Scy 2683285169Scy#define TELJJY_STAY_CLOCK_STATE 0 2684285169Scy#define TELJJY_CHANGE_CLOCK_STATE 1 2685285169Scy 2686285169Scy/* Command and replay */ 2687285169Scy 2688285169Scy#define TELJJY_REPLY_NONE 0 2689285169Scy#define TELJJY_REPLY_4DATE 1 2690285169Scy#define TELJJY_REPLY_TIME 2 2691285169Scy#define TELJJY_REPLY_LEAPSEC 3 2692285169Scy#define TELJJY_REPLY_LOOP 4 2693285169Scy#define TELJJY_REPLY_PROMPT 5 2694285169Scy#define TELJJY_REPLY_LOOPBACK 6 2695285169Scy#define TELJJY_REPLY_COM 7 2696285169Scy 2697285169Scy#define TELJJY_COMMAND_START_SKIP_LOOPBACK 7 2698285169Scy 2699285169Scystatic struct 2700285169Scy{ 2701285169Scy const char *command ; 2702285169Scy int commandLength ; 2703285169Scy int iEchobackReplyLength ; 2704285169Scy int iExpectedReplyType ; 2705285169Scy int iExpectedReplyLength ; 2706285169Scy} teljjy_command_sequence[] = 2707285169Scy{ 2708285169Scy { NULL, 0, 0, 0, 0 }, /* Idle */ 2709285169Scy { "LOOP\r" , 5, 4, TELJJY_REPLY_LOOP , 0 }, /* Getting into loopback mode */ 2710285169Scy { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2711285169Scy { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2712285169Scy { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2713285169Scy { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2714285169Scy { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2715285169Scy { "COM\r" , 4, 3, TELJJY_REPLY_COM , 0 }, /* Exit from loopback mode */ 2716285169Scy /* TELJJY_COMMAND_START_SKIP_LOOPBACK */ 2717285169Scy { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 }, 2718285169Scy { "4DATE\r" , 6, 5, TELJJY_REPLY_4DATE , 8 }, 2719285169Scy { "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 }, 2720285169Scy { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 }, 2721285169Scy { "BYE\r" , 4, 3, TELJJY_REPLY_NONE , 0 }, 2722285169Scy /* End of command */ 2723285169Scy { NULL, 0, 0, 0, 0 } 2724285169Scy} ; 2725285169Scy 2726285169Scy#define TELJJY_LOOPBACK_DELAY_THRESHOLD 700 /* Milli second */ 2727285169Scy 2728285169Scy#ifdef DEBUG 2729285169Scy#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 ) ; } } 2730285169Scy#else 2731285169Scy#define DEBUG_TELJJY_PRINTF(sFunc) 2732285169Scy#endif 2733285169Scy 2734285169Scy/**************************************************************************************************/ 2735285169Scy 2736285169Scystatic int 2737285169Scyjjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up ) 2738285169Scy{ 2739285169Scy 2740285169Scy char sLog [ 80 ], sFirstThreeDigits [ 4 ] ; 2741316068Sdelphij int iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ; 2742316068Sdelphij size_t i ; 2743316068Sdelphij size_t iFirstThreeDigitsCount ; 2744285169Scy 2745285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ; 2746285169Scy 2747285169Scy up->unittype = UNITTYPE_TELEPHONE ; 2748285169Scy up->linespeed = SPEED232_TELEPHONE ; 2749285169Scy up->linediscipline = LDISC_RAW ; 2750285169Scy 2751285169Scy up->pRawBreak = teljjy_raw_break ; 2752285169Scy up->bWaitBreakString = TRUE ; 2753285169Scy 2754285169Scy up->bSkipCntrlCharOnly = TRUE ; 2755285169Scy 2756285169Scy up->iClockState = TELJJY_STATE_IDLE ; 2757285169Scy up->iClockEvent = TELJJY_EVENT_NULL ; 2758285169Scy 2759285169Scy /* Check the telephone number */ 2760285169Scy 2761285169Scy if ( sys_phone[0] == NULL ) { 2762285169Scy msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ; 2763285169Scy up->bInitError = TRUE ; 2764285169Scy return 1 ; 2765285169Scy } 2766285169Scy 2767285169Scy if ( sys_phone[1] != NULL ) { 2768285169Scy msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ; 2769285169Scy up->bInitError = TRUE ; 2770285169Scy return 1 ; 2771285169Scy } 2772285169Scy 2773285169Scy iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ; 2774285169Scy for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) { 2775294554Sdelphij if ( isdigit( (u_char)sys_phone[0][i] ) ) { 2776285169Scy if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) { 2777294554Sdelphij sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ; 2778285169Scy } 2779285169Scy iNumberOfDigitsOfPhoneNumber ++ ; 2780294554Sdelphij } else if ( sys_phone[0][i] == ',' ) { 2781285169Scy iCommaCount ++ ; 2782285169Scy if ( iCommaCount > 1 ) { 2783285169Scy msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ; 2784285169Scy up->bInitError = TRUE ; 2785285169Scy return 1 ; 2786285169Scy } 2787285169Scy iFirstThreeDigitsCount = 0 ; 2788285169Scy iCommaPosition = i ; 2789294554Sdelphij } else if ( sys_phone[0][i] != '-' ) { 2790285169Scy msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ; 2791285169Scy up->bInitError = TRUE ; 2792285169Scy return 1 ; 2793285169Scy } 2794285169Scy } 2795285169Scy sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ; 2796285169Scy 2797285169Scy if ( iCommaCount == 1 ) { 2798285169Scy if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) { 2799285169Scy msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ; 2800285169Scy up->bInitError = TRUE ; 2801285169Scy return 1 ; 2802285169Scy } 2803285169Scy } 2804285169Scy 2805285169Scy if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) { 2806285169Scy /* Too short or too long */ 2807285169Scy msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ; 2808285169Scy up->bInitError = TRUE ; 2809285169Scy return 1 ; 2810285169Scy } 2811285169Scy 2812285169Scy if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0 2813285169Scy || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0 2814285169Scy || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0 2815285169Scy || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0 2816285169Scy || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0 2817285169Scy || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0 2818285169Scy || ( sFirstThreeDigits[0] == '0' && sFirstThreeDigits[2] == '0' ) ) { 2819285169Scy /* Not allowed because of emergency numbers or special service numbers */ 2820285169Scy msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ; 2821285169Scy up->bInitError = TRUE ; 2822285169Scy return 1 ; 2823285169Scy } 2824285169Scy 2825285169Scy snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ; 2826285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 2827285169Scy 2828285169Scy if ( peer->minpoll < 8 ) { 2829285169Scy /* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */ 2830285169Scy int oldminpoll = peer->minpoll ; 2831285169Scy peer->minpoll = 8 ; 2832285169Scy if ( peer->ppoll < peer->minpoll ) { 2833285169Scy peer->ppoll = peer->minpoll ; 2834285169Scy } 2835285169Scy if ( peer->maxpoll < peer->minpoll ) { 2836285169Scy peer->maxpoll = peer->minpoll ; 2837285169Scy } 2838285169Scy snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ; 2839285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 2840285169Scy } 2841285169Scy 2842285169Scy return 0 ; 2843285169Scy 2844285169Scy} 2845285169Scy 2846285169Scy/**************************************************************************************************/ 2847285169Scy 2848285169Scystatic int 2849285169Scyjjy_receive_telephone ( struct recvbuf *rbufp ) 2850285169Scy{ 2851280849Scy#ifdef DEBUG 2852285169Scy static const char *sFunctionName = "jjy_receive_telephone" ; 2853280849Scy#endif 2854106163Sroberto 2855285169Scy struct peer *peer; 2856285169Scy struct refclockproc *pp ; 2857285169Scy struct jjyunit *up ; 2858285169Scy char *pBuf ; 2859285169Scy int iLen ; 2860285169Scy short iPreviousModemState ; 2861106163Sroberto 2862285169Scy peer = rbufp->recv_peer ; 2863285169Scy pp = peer->procptr ; 2864285169Scy up = pp->unitptr ; 2865280849Scy 2866285169Scy DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2867285169Scy 2868285169Scy if ( up->iClockState == TELJJY_STATE_IDLE 2869285169Scy || up->iClockState == TELJJY_STATE_DAILOUT 2870285169Scy || up->iClockState == TELJJY_STATE_BYE ) { 2871285169Scy 2872285169Scy iPreviousModemState = getModemState( up ) ; 2873285169Scy 2874285169Scy modem_receive ( rbufp ) ; 2875285169Scy 2876285169Scy if ( iPreviousModemState != up->iModemState ) { 2877285169Scy /* Modem state is changed just now. */ 2878285169Scy if ( isModemStateDisconnect( up->iModemState ) ) { 2879285169Scy up->iClockEvent = TELJJY_EVENT_DISCONNECT ; 2880285169Scy teljjy_control ( peer, pp, up ) ; 2881285169Scy } else if ( isModemStateConnect( up->iModemState ) ) { 2882285169Scy up->iClockEvent = TELJJY_EVENT_CONNECT ; 2883285169Scy teljjy_control ( peer, pp, up ) ; 2884285169Scy } 2885285169Scy } 2886285169Scy 2887285169Scy return JJY_RECEIVE_WAIT ; 2888285169Scy 2889285169Scy } 2890285169Scy 2891285169Scy if ( up->linediscipline == LDISC_RAW ) { 2892285169Scy pBuf = up->sTextBuf ; 2893285169Scy iLen = up->iTextBufLen ; 2894285169Scy } else { 2895285169Scy pBuf = pp->a_lastcode ; 2896285169Scy iLen = pp->lencode ; 2897285169Scy } 2898285169Scy 2899285169Scy up->iTeljjySilentTimer = 0 ; 2900285169Scy if ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN ; } 2901285169Scy else if ( iLen == 1 && strncmp( pBuf, ">" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; } 2902285169Scy else if ( iLen >= 1 && strncmp( pBuf, "?" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR ; } 2903285169Scy else { up->iClockEvent = TELJJY_EVENT_DATA ; } 2904285169Scy 2905285169Scy teljjy_control ( peer, pp, up ) ; 2906285169Scy 2907285169Scy return JJY_RECEIVE_WAIT ; 2908285169Scy 2909285169Scy} 2910285169Scy 2911285169Scy/**************************************************************************************************/ 2912285169Scy 2913285169Scystatic void 2914285169Scyjjy_poll_telephone ( int unit, struct peer *peer ) 2915285169Scy{ 2916285169Scy#ifdef DEBUG 2917285169Scy static const char *sFunctionName = "jjy_poll_telephone" ; 2918285169Scy#endif 2919285169Scy 2920285169Scy struct refclockproc *pp ; 2921285169Scy struct jjyunit *up ; 2922285169Scy 2923285169Scy pp = peer->procptr ; 2924280849Scy up = pp->unitptr ; 2925106163Sroberto 2926285169Scy DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2927285169Scy 2928285169Scy if ( up->iClockState == TELJJY_STATE_IDLE ) { 2929285169Scy up->iRawBufLen = 0 ; 2930285169Scy up->iLineBufLen = 0 ; 2931285169Scy up->iTextBufLen = 0 ; 2932280849Scy } 2933280849Scy 2934285169Scy up->iClockEvent = TELJJY_EVENT_START ; 2935285169Scy teljjy_control ( peer, pp, up ) ; 2936285169Scy 2937285169Scy} 2938285169Scy 2939285169Scy/**************************************************************************************************/ 2940285169Scy 2941285169Scystatic void 2942285169Scyjjy_timer_telephone ( int unit, struct peer *peer ) 2943285169Scy{ 2944280849Scy#ifdef DEBUG 2945285169Scy static const char *sFunctionName = "jjy_timer_telephone" ; 2946280849Scy#endif 2947280849Scy 2948285169Scy struct refclockproc *pp ; 2949285169Scy struct jjyunit *up ; 2950285169Scy short iPreviousModemState ; 2951106163Sroberto 2952285169Scy pp = peer->procptr ; 2953285169Scy up = pp->unitptr ; 2954285169Scy 2955285169Scy DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2956285169Scy 2957285169Scy if ( iTeljjySilentTimeout[up->iClockState] != 0 ) { 2958285169Scy up->iTeljjySilentTimer++ ; 2959285169Scy if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) { 2960285169Scy up->iClockEvent = TELJJY_EVENT_SILENT ; 2961285169Scy teljjy_control ( peer, pp, up ) ; 2962285169Scy } 2963285169Scy } 2964285169Scy 2965285169Scy if ( iTeljjyStateTimeout[up->iClockState] != 0 ) { 2966285169Scy up->iTeljjyStateTimer++ ; 2967285169Scy if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) { 2968285169Scy up->iClockEvent = TELJJY_EVENT_TIMEOUT ; 2969285169Scy teljjy_control ( peer, pp, up ) ; 2970285169Scy } 2971285169Scy } 2972285169Scy 2973285169Scy if ( isModemStateTimerOn( up ) ) { 2974285169Scy 2975285169Scy iPreviousModemState = getModemState( up ) ; 2976285169Scy 2977285169Scy modem_timer ( unit, peer ) ; 2978285169Scy 2979285169Scy if ( iPreviousModemState != up->iModemState ) { 2980285169Scy /* Modem state is changed just now. */ 2981285169Scy if ( isModemStateDisconnect( up->iModemState ) ) { 2982285169Scy up->iClockEvent = TELJJY_EVENT_DISCONNECT ; 2983285169Scy teljjy_control ( peer, pp, up ) ; 2984285169Scy } else if ( isModemStateConnect( up->iModemState ) ) { 2985285169Scy up->iClockEvent = TELJJY_EVENT_CONNECT ; 2986285169Scy teljjy_control ( peer, pp, up ) ; 2987285169Scy } 2988285169Scy } 2989285169Scy 2990285169Scy } 2991285169Scy 2992285169Scy} 2993285169Scy 2994285169Scy/**************************************************************************************************/ 2995285169Scy 2996285169Scystatic void 2997285169Scyteljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 2998285169Scy{ 2999285169Scy 3000285169Scy int i, rc ; 3001285169Scy short iPostEvent = TELJJY_EVENT_NULL ; 3002285169Scy 3003285169Scy DEBUG_TELJJY_PRINTF( "teljjy_control" ) ; 3004285169Scy 3005285169Scy rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ; 3006285169Scy 3007285169Scy if ( rc == TELJJY_CHANGE_CLOCK_STATE ) { 3008285169Scy iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ; 3009182007Sroberto#ifdef DEBUG 3010285169Scy if ( debug ) { 3011285169Scy printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd iPostEvent=%hd\n", 3012285169Scy up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ; 3013285169Scy } 3014182007Sroberto#endif 3015285169Scy up->iTeljjySilentTimer = 0 ; 3016285169Scy if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) { 3017285169Scy /* Telephone JJY state is changing now */ 3018285169Scy up->iTeljjyStateTimer = 0 ; 3019285169Scy up->bLineError = FALSE ; 3020285169Scy up->iClockCommandSeq = 0 ; 3021285169Scy up->iTimestampCount = 0 ; 3022285169Scy up->iLoopbackCount = 0 ; 3023285169Scy for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 3024285169Scy up->bLoopbackTimeout[i] = FALSE ; 3025285169Scy } 3026285169Scy if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) { 3027285169Scy /* Telephone JJY state is changing to IDLE just now */ 3028285169Scy up->iProcessState = JJY_PROCESS_STATE_DONE ; 3029285169Scy } 3030285169Scy } 3031285169Scy up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ; 3032182007Sroberto 3033106163Sroberto } 3034106163Sroberto 3035285169Scy if ( iPostEvent != TELJJY_EVENT_NULL ) { 3036285169Scy up->iClockEvent = iPostEvent ; 3037285169Scy teljjy_control ( peer, pp, up ) ; 3038285169Scy } 3039285169Scy 3040285169Scy up->iClockEvent = TELJJY_EVENT_NULL ; 3041285169Scy 3042182007Sroberto} 3043182007Sroberto 3044182007Sroberto/**************************************************************************************************/ 3045182007Sroberto 3046182007Srobertostatic void 3047285169Scyteljjy_setDelay ( struct peer *peer, struct jjyunit *up ) 3048182007Sroberto{ 3049182007Sroberto 3050285169Scy char sLog [ 60 ] ; 3051285169Scy int milliSecond, microSecond ; 3052182007Sroberto 3053285169Scy gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ; 3054182007Sroberto 3055285169Scy up->delayTime[up->iLoopbackCount].tv_sec -= up->sendTime[up->iLoopbackCount].tv_sec ; 3056285169Scy up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ; 3057285169Scy if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) { 3058285169Scy up->delayTime[up->iLoopbackCount].tv_sec -- ; 3059285169Scy up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ; 3060285169Scy } 3061106163Sroberto 3062285169Scy milliSecond = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ; 3063285169Scy microSecond = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ; 3064285169Scy milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ; 3065285169Scy 3066285169Scy snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY, 3067285169Scy milliSecond, microSecond ) ; 3068285169Scy 3069285169Scy if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) { 3070285169Scy /* Delay > 700 mS */ 3071285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 3072285169Scy } else { 3073285169Scy /* Delay <= 700 mS */ 3074285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 3075285169Scy } 3076285169Scy 3077285169Scy} 3078285169Scy 3079285169Scy/**************************************************************************************************/ 3080285169Scy 3081285169Scystatic int 3082285169Scyteljjy_getDelay ( struct peer *peer, struct jjyunit *up ) 3083285169Scy{ 3084285169Scy 3085285169Scy struct timeval maxTime, minTime, averTime ; 3086285169Scy int i ; 3087285169Scy int minIndex = 0, maxIndex = 0, iAverCount = 0 ; 3088285169Scy int iThresholdSecond, iThresholdMicroSecond ; 3089285169Scy int iPercent ; 3090285169Scy 3091285169Scy minTime.tv_sec = minTime.tv_usec = 0 ; 3092285169Scy maxTime.tv_sec = maxTime.tv_usec = 0 ; 3093285169Scy 3094285169Scy iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ; 3095285169Scy iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ; 3096285169Scy 3097285169Scy up->iLoopbackValidCount = 0 ; 3098285169Scy 3099285169Scy for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) { 3100285169Scy if ( up->bLoopbackTimeout[i] 3101285169Scy || up->delayTime[i].tv_sec > iThresholdSecond 3102285169Scy || ( up->delayTime[i].tv_sec == iThresholdSecond 3103285169Scy && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) { 3104285169Scy continue ; 3105285169Scy } 3106285169Scy if ( up->iLoopbackValidCount == 0 ) { 3107285169Scy minTime.tv_sec = up->delayTime[i].tv_sec ; 3108285169Scy minTime.tv_usec = up->delayTime[i].tv_usec ; 3109285169Scy maxTime.tv_sec = up->delayTime[i].tv_sec ; 3110285169Scy maxTime.tv_usec = up->delayTime[i].tv_usec ; 3111285169Scy minIndex = maxIndex = i ; 3112285169Scy } else if ( minTime.tv_sec > up->delayTime[i].tv_sec 3113285169Scy || ( minTime.tv_sec == up->delayTime[i].tv_sec 3114285169Scy && minTime.tv_usec > up->delayTime[i].tv_usec ) ) { 3115285169Scy minTime.tv_sec = up->delayTime[i].tv_sec ; 3116285169Scy minTime.tv_usec = up->delayTime[i].tv_usec ; 3117285169Scy minIndex = i ; 3118285169Scy } else if ( maxTime.tv_sec < up->delayTime[i].tv_sec 3119285169Scy || ( maxTime.tv_sec == up->delayTime[i].tv_sec 3120285169Scy && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) { 3121285169Scy maxTime.tv_sec = up->delayTime[i].tv_sec ; 3122285169Scy maxTime.tv_usec = up->delayTime[i].tv_usec ; 3123285169Scy maxIndex = i ; 3124285169Scy } 3125285169Scy up->iLoopbackValidCount ++ ; 3126285169Scy } 3127285169Scy 3128285169Scy if ( up->iLoopbackValidCount < 2 ) { 3129285169Scy return -1 ; 3130285169Scy } 3131285169Scy 3132285169Scy averTime.tv_usec = 0; 3133285169Scy 3134285169Scy for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) { 3135285169Scy if ( up->bLoopbackTimeout[i] 3136285169Scy || up->delayTime[i].tv_sec > iThresholdSecond 3137285169Scy || ( up->delayTime[i].tv_sec == iThresholdSecond 3138285169Scy && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) { 3139285169Scy continue ; 3140285169Scy } 3141285169Scy if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) { 3142285169Scy continue ; 3143285169Scy } 3144285169Scy if ( up->iLoopbackValidCount >= 4 && i == minIndex ) { 3145285169Scy continue ; 3146285169Scy } 3147285169Scy averTime.tv_usec += up->delayTime[i].tv_usec ; 3148285169Scy iAverCount ++ ; 3149285169Scy } 3150285169Scy 3151285169Scy if ( iAverCount == 0 ) { 3152285169Scy /* This is never happened. */ 3153285169Scy /* Previous for-if-for blocks assure iAverCount > 0. */ 3154285169Scy /* This code avoids a claim by the coverity scan tool. */ 3155285169Scy return -1 ; 3156285169Scy } 3157285169Scy 3158285169Scy /* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */ 3159285169Scy 3160285169Scy iPercent = ( peer->ttl - 100 ) ; 3161285169Scy 3162285169Scy /* Average delay time in milli second */ 3163285169Scy 3164285169Scy return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ; 3165285169Scy 3166285169Scy} 3167285169Scy 3168285169Scy/******************************/ 3169285169Scystatic int 3170285169Scyteljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3171285169Scy{ 3172285169Scy 3173285169Scy DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ; 3174285169Scy 3175285169Scy return TELJJY_STAY_CLOCK_STATE ; 3176285169Scy 3177285169Scy} 3178285169Scy 3179285169Scy/******************************/ 3180285169Scystatic int 3181285169Scyteljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3182285169Scy{ 3183285169Scy 3184285169Scy DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ; 3185285169Scy 3186285169Scy modem_connect ( peer->refclkunit, peer ) ; 3187285169Scy 3188285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3189285169Scy 3190285169Scy} 3191285169Scy 3192285169Scy/******************************/ 3193285169Scystatic int 3194285169Scyteljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3195285169Scy{ 3196285169Scy 3197285169Scy DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ; 3198285169Scy 3199285169Scy return TELJJY_STAY_CLOCK_STATE ; 3200285169Scy 3201285169Scy} 3202285169Scy 3203285169Scy/******************************/ 3204285169Scystatic int 3205285169Scyteljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3206285169Scy{ 3207285169Scy 3208285169Scy DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ; 3209285169Scy 3210285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3211285169Scy 3212285169Scy} 3213285169Scy 3214285169Scy/******************************/ 3215285169Scystatic int 3216285169Scyteljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3217285169Scy{ 3218285169Scy 3219285169Scy DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ; 3220285169Scy 3221285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3222285169Scy 3223285169Scy} 3224285169Scy 3225285169Scy/******************************/ 3226285169Scystatic int 3227285169Scyteljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3228285169Scy{ 3229285169Scy 3230285169Scy DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ; 3231285169Scy 3232285169Scy return TELJJY_STAY_CLOCK_STATE ; 3233285169Scy 3234285169Scy} 3235285169Scy 3236285169Scy/******************************/ 3237285169Scystatic int 3238285169Scyteljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3239285169Scy{ 3240285169Scy 3241285169Scy DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ; 3242285169Scy 3243285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3244285169Scy 3245285169Scy} 3246285169Scy 3247285169Scy/******************************/ 3248285169Scystatic int 3249285169Scyteljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3250285169Scy{ 3251285169Scy 3252285169Scy int i ; 3253285169Scy 3254285169Scy DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ; 3255285169Scy 3256285169Scy up->bLineError = FALSE ; 3257285169Scy up->iClockCommandSeq = 0 ; 3258285169Scy up->iTimestampCount = 0 ; 3259285169Scy up->iLoopbackCount = 0 ; 3260285169Scy for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 3261285169Scy up->bLoopbackTimeout[i] = FALSE ; 3262285169Scy } 3263285169Scy 3264285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3265285169Scy 3266285169Scy} 3267285169Scy 3268285169Scy/******************************/ 3269285169Scystatic int 3270285169Scyteljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3271285169Scy{ 3272285169Scy 3273294554Sdelphij const char * pCmd ; 3274294554Sdelphij int iCmdLen ; 3275285169Scy 3276285169Scy DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ; 3277285169Scy 3278285169Scy /* Send a guest user ID */ 3279285169Scy pCmd = "TJJY\r" ; 3280285169Scy 3281285169Scy /* Send login ID */ 3282285169Scy iCmdLen = strlen( pCmd ) ; 3283285169Scy if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 3284285169Scy refclock_report( peer, CEVNT_FAULT ) ; 3285285169Scy } 3286285169Scy 3287285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3288285169Scy 3289285169Scy return TELJJY_STAY_CLOCK_STATE ; 3290285169Scy 3291285169Scy} 3292285169Scy 3293285169Scy/******************************/ 3294285169Scystatic int 3295285169Scyteljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3296285169Scy{ 3297285169Scy 3298285169Scy DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ; 3299285169Scy 3300285169Scy if ( write( pp->io.fd, "\r", 1 ) != 1 ) { 3301285169Scy refclock_report( peer, CEVNT_FAULT ) ; 3302285169Scy } 3303285169Scy 3304285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ; 3305285169Scy 3306285169Scy up->iTeljjySilentTimer = 0 ; 3307285169Scy 3308285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3309285169Scy 3310285169Scy} 3311285169Scy 3312285169Scy/******************************/ 3313285169Scystatic int 3314285169Scyteljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3315285169Scy{ 3316285169Scy 3317285169Scy DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ; 3318285169Scy 3319285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3320285169Scy 3321285169Scy} 3322285169Scy 3323285169Scy/******************************/ 3324285169Scystatic int 3325285169Scyteljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3326285169Scy{ 3327285169Scy 3328285169Scy DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ; 3329285169Scy 3330285169Scy return TELJJY_STAY_CLOCK_STATE ; 3331285169Scy 3332285169Scy} 3333285169Scy 3334285169Scy/******************************/ 3335285169Scystatic int 3336285169Scyteljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3337285169Scy{ 3338285169Scy 3339285169Scy DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ; 3340285169Scy 3341285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3342285169Scy 3343285169Scy} 3344285169Scy 3345285169Scy/******************************/ 3346285169Scystatic int 3347285169Scyteljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3348285169Scy{ 3349285169Scy 3350294554Sdelphij const char * pCmd ; 3351294554Sdelphij int i, iLen, iNextClockState ; 3352330106Sdelphij char sLog [ 120 ] ; 3353285169Scy 3354285169Scy DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ; 3355285169Scy 3356285169Scy if ( up->iClockCommandSeq > 0 3357285169Scy && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) { 3358285169Scy /* Command sequence has been completed */ 3359285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3360285169Scy } 3361285169Scy 3362285169Scy if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) { 3363285169Scy /* Skip loopback */ 3364285169Scy 3365285169Scy up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ; 3366285169Scy 3367285169Scy } else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) { 3368285169Scy /* Loopback start */ 3369285169Scy 3370285169Scy up->iLoopbackCount = 0 ; 3371285169Scy for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 3372285169Scy up->bLoopbackTimeout[i] = FALSE ; 3373285169Scy } 3374285169Scy 3375285169Scy } else if ( up->iClockCommandSeq > 0 && peer->ttl != 100 3376285169Scy && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK 3377285169Scy && up->iLoopbackCount < MAX_LOOPBACK ) { 3378285169Scy /* Loopback character comes */ 3379182007Sroberto#ifdef DEBUG 3380285169Scy if ( debug ) { 3381330106Sdelphij printf( "refclock_jjy.c : teljjy_conn_send : iClockCommandSeq=%d iLoopbackCount=%d\n", 3382330106Sdelphij up->iClockCommandSeq, up->iLoopbackCount ) ; 3383285169Scy } 3384285169Scy#endif 3385285169Scy 3386285169Scy teljjy_setDelay( peer, up ) ; 3387285169Scy 3388285169Scy up->iLoopbackCount ++ ; 3389285169Scy 3390106163Sroberto } 3391285169Scy 3392285169Scy up->iClockCommandSeq++ ; 3393285169Scy 3394285169Scy pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ; 3395285169Scy iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ; 3396285169Scy 3397285169Scy if ( pCmd != NULL ) { 3398285169Scy 3399285169Scy if ( write( pp->io.fd, pCmd, iLen ) != iLen ) { 3400285169Scy refclock_report( peer, CEVNT_FAULT ) ; 3401285169Scy } 3402285169Scy 3403285169Scy if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3404285169Scy /* Loopback character and timestamp */ 3405330106Sdelphij if ( up->iLoopbackCount < MAX_LOOPBACK ) { 3406330106Sdelphij gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ; 3407330106Sdelphij up->bLoopbackMode = TRUE ; 3408330106Sdelphij } else { 3409330106Sdelphij /* This else-block is never come. */ 3410330106Sdelphij /* This code avoid wrong report of the coverity static analysis scan tool. */ 3411330106Sdelphij snprintf( sLog, sizeof(sLog)-1, "refclock_jjy.c ; teljjy_conn_send ; iClockCommandSeq=%d iLoopbackCount=%d MAX_LOOPBACK=%d", 3412330106Sdelphij up->iClockCommandSeq, up->iLoopbackCount, MAX_LOOPBACK ) ; 3413330106Sdelphij jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_BUG, sLog ) ; 3414330106Sdelphij msyslog ( LOG_ERR, "%s", sLog ) ; 3415330106Sdelphij up->bLoopbackMode = FALSE ; 3416330106Sdelphij } 3417285169Scy } else { 3418285169Scy /* Regular command */ 3419285169Scy up->bLoopbackMode = FALSE ; 3420285169Scy } 3421285169Scy 3422285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3423285169Scy 3424285169Scy if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) { 3425285169Scy /* Last command of the command sequence */ 3426285169Scy iNextClockState = TELJJY_CHANGE_CLOCK_STATE ; 3427285169Scy } else { 3428285169Scy /* More commands to be issued */ 3429285169Scy iNextClockState = TELJJY_STAY_CLOCK_STATE ; 3430285169Scy } 3431285169Scy 3432285169Scy } else { 3433285169Scy 3434285169Scy iNextClockState = TELJJY_CHANGE_CLOCK_STATE ; 3435285169Scy 3436285169Scy } 3437285169Scy 3438285169Scy return iNextClockState ; 3439285169Scy 3440285169Scy} 3441285169Scy 3442285169Scy/******************************/ 3443285169Scystatic int 3444285169Scyteljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3445285169Scy{ 3446285169Scy 3447285169Scy char *pBuf ; 3448285169Scy int iLen, rc ; 3449362716Scy char sLog [ MAX_LOGTEXT ] ; 3450285169Scy char bAdjustment ; 3451285169Scy 3452285169Scy 3453285169Scy DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ; 3454285169Scy 3455285169Scy if ( up->linediscipline == LDISC_RAW ) { 3456285169Scy pBuf = up->sTextBuf ; 3457285169Scy iLen = up->iTextBufLen ; 3458285169Scy } else { 3459285169Scy pBuf = pp->a_lastcode ; 3460285169Scy iLen = pp->lencode ; 3461285169Scy } 3462285169Scy 3463285169Scy if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen 3464285169Scy && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK 3465285169Scy && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command) 3466285169Scy && up->iLoopbackCount < MAX_LOOPBACK ) { 3467285169Scy /* Loopback */ 3468285169Scy 3469285169Scy teljjy_setDelay( peer, up ) ; 3470285169Scy 3471285169Scy up->iLoopbackCount ++ ; 3472285169Scy 3473285169Scy } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen 3474285169Scy && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) { 3475285169Scy /* Maybe echoback */ 3476285169Scy 3477285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ; 3478285169Scy 3479285169Scy } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3480285169Scy && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) { 3481285169Scy /* 4DATE<CR> -> YYYYMMDD<CR> */ 3482285169Scy 3483285169Scy rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ; 3484285169Scy 3485285169Scy if ( rc != 3 || up->year < 2000 || 2099 <= up->year 3486285169Scy || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) { 3487285169Scy /* Invalid date */ 3488285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 3489285169Scy rc, up->year, up->month, up->day ) ; 3490285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3491285169Scy up->bLineError = TRUE ; 3492285169Scy } 3493285169Scy 3494285169Scy } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3495285169Scy && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC 3496285169Scy && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) { 3497285169Scy /* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */ 3498285169Scy 3499285169Scy rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ; 3500285169Scy 3501285169Scy if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) { 3502285169Scy /* Invalid leap second */ 3503285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP, 3504285169Scy pBuf ) ; 3505285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3506285169Scy up->bLineError = TRUE ; 3507285169Scy } 3508285169Scy 3509285169Scy } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3510285169Scy && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) { 3511285169Scy /* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */ 3512285169Scy 3513285169Scy rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ; 3514285169Scy 3515285169Scy if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 3516285169Scy /* Invalid time */ 3517285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 3518285169Scy rc, up->hour, up->minute, up->second ) ; 3519285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3520285169Scy up->bLineError = TRUE ; 3521285169Scy } 3522285169Scy up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 3523285169Scy 3524285169Scy up->iTimestampCount++ ; 3525285169Scy 3526285169Scy if ( up->iTimestampCount == 6 && ! up->bLineError ) { 3527285169Scy#if DEBUG 3528285169Scy printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n", 3529285169Scy up->bLineError, 3530285169Scy up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ; 3531182007Sroberto#endif 3532285169Scy bAdjustment = TRUE ; 3533106163Sroberto 3534285169Scy if ( peer->ttl == 100 ) { 3535285169Scy /* mode=100 */ 3536285169Scy up->msecond = 0 ; 3537285169Scy } else { 3538285169Scy /* mode=101 to 110 */ 3539285169Scy up->msecond = teljjy_getDelay( peer, up ) ; 3540285169Scy if (up->msecond < 0 ) { 3541285169Scy up->msecond = 0 ; 3542285169Scy bAdjustment = FALSE ; 3543285169Scy } 3544285169Scy } 3545285169Scy 3546285169Scy if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2] 3547285169Scy && up->iTimestamp[2] <= up->iTimestamp[3] 3548285169Scy && ( up->iTimestamp[3] + 1 ) == up->iTimestamp[4] 3549285169Scy && ( up->iTimestamp[4] + 1 ) == up->iTimestamp[5] ) { 3550285169Scy /* Non over midnight */ 3551285169Scy 3552285169Scy jjy_synctime( peer, pp, up ) ; 3553285169Scy 3554285169Scy if ( peer->ttl != 100 ) { 3555285169Scy if ( bAdjustment ) { 3556285169Scy snprintf( sLog, sizeof(sLog), 3557285169Scy JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST, 3558285169Scy up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ; 3559285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 3560285169Scy } else { 3561285169Scy snprintf( sLog, sizeof(sLog), 3562285169Scy JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST, 3563285169Scy up->iLoopbackValidCount, MAX_LOOPBACK ) ; 3564285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3565285169Scy } 3566285169Scy } 3567285169Scy 3568285169Scy } 3569285169Scy } 3570285169Scy 3571285169Scy } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen 3572285169Scy && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3573285169Scy /* Loopback noise ( Unexpected replay ) */ 3574285169Scy 3575285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY, 3576285169Scy pBuf ) ; 3577285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 3578285169Scy 3579285169Scy } else { 3580285169Scy 3581285169Scy up->bLineError = TRUE ; 3582285169Scy 3583285169Scy snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 3584285169Scy pBuf ) ; 3585285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3586285169Scy 3587182007Sroberto } 3588182007Sroberto 3589285169Scy return TELJJY_STAY_CLOCK_STATE ; 3590285169Scy 3591106163Sroberto} 3592106163Sroberto 3593285169Scy/******************************/ 3594285169Scystatic int 3595285169Scyteljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3596285169Scy{ 3597285169Scy 3598294554Sdelphij const char * pCmd ; 3599285169Scy 3600285169Scy DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ; 3601285169Scy 3602285169Scy if ( up->iClockCommandSeq >= 1 3603285169Scy && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) { 3604285169Scy /* Loopback */ 3605285169Scy#ifdef DEBUG 3606285169Scy if ( debug ) { 3607285169Scy printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ; 3608285169Scy } 3609285169Scy#endif 3610285169Scy if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3611285169Scy up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ; 3612285169Scy } 3613285169Scy up->iTeljjySilentTimer = 0 ; 3614285169Scy return teljjy_conn_send( peer, pp, up ) ; 3615285169Scy } else { 3616285169Scy pCmd = "\r" ; 3617285169Scy } 3618285169Scy 3619285169Scy if ( write( pp->io.fd, pCmd, 1 ) != 1 ) { 3620285169Scy refclock_report( peer, CEVNT_FAULT ) ; 3621285169Scy } 3622285169Scy 3623285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3624285169Scy 3625285169Scy up->iTeljjySilentTimer = 0 ; 3626285169Scy 3627285169Scy return TELJJY_STAY_CLOCK_STATE ; 3628285169Scy 3629285169Scy} 3630285169Scy 3631285169Scy/******************************/ 3632285169Scystatic int 3633285169Scyteljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3634285169Scy{ 3635285169Scy 3636285169Scy DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ; 3637285169Scy 3638285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3639285169Scy 3640285169Scy} 3641285169Scy 3642285169Scy/******************************/ 3643285169Scystatic int 3644285169Scyteljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3645285169Scy{ 3646285169Scy 3647285169Scy DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ; 3648285169Scy 3649285169Scy return TELJJY_STAY_CLOCK_STATE ; 3650285169Scy 3651285169Scy} 3652285169Scy 3653285169Scy/******************************/ 3654285169Scystatic int 3655285169Scyteljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3656285169Scy{ 3657285169Scy 3658285169Scy DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ; 3659285169Scy 3660285169Scy return TELJJY_CHANGE_CLOCK_STATE ; 3661285169Scy 3662285169Scy} 3663285169Scy 3664285169Scy/******************************/ 3665285169Scystatic int 3666285169Scyteljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3667285169Scy{ 3668285169Scy 3669285169Scy DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ; 3670285169Scy 3671285169Scy modem_disconnect ( peer->refclkunit, peer ) ; 3672285169Scy 3673285169Scy return TELJJY_STAY_CLOCK_STATE ; 3674285169Scy 3675285169Scy} 3676285169Scy 3677285169Scy/*################################################################################################*/ 3678285169Scy/*################################################################################################*/ 3679285169Scy/*## ##*/ 3680285169Scy/*## Modem control finite state machine ##*/ 3681285169Scy/*## ##*/ 3682285169Scy/*################################################################################################*/ 3683285169Scy/*################################################################################################*/ 3684285169Scy 3685285169Scy/* struct jjyunit.iModemState */ 3686285169Scy 3687285169Scy#define MODEM_STATE_DISCONNECT 0 3688285169Scy#define MODEM_STATE_INITIALIZE 1 3689285169Scy#define MODEM_STATE_DAILING 2 3690285169Scy#define MODEM_STATE_CONNECT 3 3691285169Scy#define MODEM_STATE_ESCAPE 4 3692285169Scy 3693285169Scy/* struct jjyunit.iModemEvent */ 3694285169Scy 3695285169Scy#define MODEM_EVENT_NULL 0 3696285169Scy#define MODEM_EVENT_INITIALIZE 1 3697285169Scy#define MODEM_EVENT_DIALOUT 2 3698285169Scy#define MODEM_EVENT_DISCONNECT 3 3699285169Scy#define MODEM_EVENT_RESP_OK 4 3700285169Scy#define MODEM_EVENT_RESP_CONNECT 5 3701285169Scy#define MODEM_EVENT_RESP_RING 6 3702285169Scy#define MODEM_EVENT_RESP_NO_CARRIER 7 3703285169Scy#define MODEM_EVENT_RESP_ERROR 8 3704285169Scy#define MODEM_EVENT_RESP_CONNECT_X 9 3705285169Scy#define MODEM_EVENT_RESP_NO_DAILTONE 10 3706285169Scy#define MODEM_EVENT_RESP_BUSY 11 3707285169Scy#define MODEM_EVENT_RESP_NO_ANSWER 12 3708285169Scy#define MODEM_EVENT_RESP_UNKNOWN 13 3709285169Scy#define MODEM_EVENT_SILENT 14 3710285169Scy#define MODEM_EVENT_TIMEOUT 15 3711285169Scy 3712285169Scy/* Function prototypes */ 3713285169Scy 3714285169Scystatic void modem_control ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3715285169Scy 3716285169Scystatic int modem_disc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3717285169Scystatic int modem_disc_init ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3718285169Scystatic int modem_init_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3719285169Scystatic int modem_init_start ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3720285169Scystatic int modem_init_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3721285169Scystatic int modem_init_resp00 ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3722285169Scystatic int modem_init_resp04 ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3723285169Scystatic int modem_dial_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3724285169Scystatic int modem_dial_dialout ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3725285169Scystatic int modem_dial_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3726285169Scystatic int modem_dial_connect ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3727285169Scystatic int modem_dial_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3728285169Scystatic int modem_conn_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3729285169Scystatic int modem_conn_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3730285169Scystatic int modem_esc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3731285169Scystatic int modem_esc_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3732285169Scystatic int modem_esc_data ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3733285169Scystatic int modem_esc_silent ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3734285169Scystatic int modem_esc_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3735285169Scy 3736294554Sdelphijstatic int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) = 3737285169Scy{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3738285169Scy/* NULL */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore }, 3739285169Scy/* INITIALIZE */ { modem_disc_init , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore }, 3740285169Scy/* DIALOUT */ { modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore }, 3741285169Scy/* DISCONNECT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_escape }, 3742285169Scy/* RESP: 0: OK */ { modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3743285169Scy/* RESP: 1: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data }, 3744285169Scy/* RESP: 2: RING */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3745285169Scy/* RESP: 3: NO CARRIER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3746285169Scy/* RESP: 4: ERROR */ { modem_disc_ignore, modem_init_resp04, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3747285169Scy/* RESP: 5: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data }, 3748285169Scy/* RESP: 6: NO DAILTONE */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3749285169Scy/* RESP: 7: BUSY */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3750285169Scy/* RESP: 8: NO ANSWER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3751285169Scy/* RESP: 9: UNKNOWN */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3752285169Scy/* SILENT */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent }, 3753285169Scy/* TIMEOUT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_disc } 3754285169Scy} ; 3755285169Scy 3756285169Scystatic short iModemNextState [ ] [ 5 ] = 3757285169Scy{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3758285169Scy/* NULL */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3759285169Scy/* INITIALIZE */ { MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3760285169Scy/* DIALOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3761285169Scy/* DISCONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE }, 3762285169Scy/* RESP: 0: OK */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3763285169Scy/* RESP: 1: CONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3764285169Scy/* RESP: 2: RING */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3765285169Scy/* RESP: 3: NO CARRIER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3766285169Scy/* RESP: 4: ERROR */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3767285169Scy/* RESP: 5: CONNECT X */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3768285169Scy/* RESP: 6: NO DAILTONE */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3769285169Scy/* RESP: 7: BUSY */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3770285169Scy/* RESP: 8: NO ANSWER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3771285169Scy/* RESP: 9: UNKNOWN */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3772285169Scy/* SILENT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT }, 3773285169Scy/* TIMEOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT } 3774285169Scy} ; 3775285169Scy 3776285169Scystatic short iModemPostEvent [ ] [ 5 ] = 3777285169Scy{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3778285169Scy/* NULL */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3779285169Scy/* INITIALIZE */ { MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3780285169Scy/* DIALOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3781285169Scy/* DISCONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }, 3782285169Scy/* RESP: 0: OK */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3783285169Scy/* RESP: 1: CONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3784285169Scy/* RESP: 2: RING */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3785285169Scy/* RESP: 3: NO CARRIER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3786285169Scy/* RESP: 4: ERROR */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3787285169Scy/* RESP: 5: CONNECT X */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3788285169Scy/* RESP: 6: NO DAILTONE */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3789285169Scy/* RESP: 7: BUSY */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3790285169Scy/* RESP: 8: NO ANSWER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3791285169Scy/* RESP: 9: UNKNOWN */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3792285169Scy/* SILENT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3793285169Scy/* TIMEOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL } 3794285169Scy} ; 3795285169Scy 3796285169Scystatic short iModemSilentTimeout [ 5 ] = { 0, 0, 0, 0, 5 } ; 3797285169Scystatic short iModemStateTimeout [ 5 ] = { 0, 20, 90, 0, 20 } ; 3798285169Scy 3799285169Scy#define STAY_MODEM_STATE 0 3800285169Scy#define CHANGE_MODEM_STATE 1 3801285169Scy 3802285169Scy#ifdef DEBUG 3803285169Scy#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 ) ; } } 3804285169Scy#else 3805285169Scy#define DEBUG_MODEM_PRINTF(sFunc) 3806285169Scy#endif 3807285169Scy 3808106163Sroberto/**************************************************************************************************/ 3809106163Sroberto 3810285169Scystatic short 3811285169ScygetModemState ( struct jjyunit *up ) 3812285169Scy{ 3813285169Scy return up->iModemState ; 3814285169Scy} 3815285169Scy 3816285169Scy/**************************************************************************************************/ 3817285169Scy 3818285169Scystatic int 3819285169ScyisModemStateConnect ( short iCheckState ) 3820285169Scy{ 3821285169Scy return ( iCheckState == MODEM_STATE_CONNECT ) ; 3822285169Scy} 3823285169Scy 3824285169Scy/**************************************************************************************************/ 3825285169Scy 3826285169Scystatic int 3827285169ScyisModemStateDisconnect ( short iCheckState ) 3828285169Scy{ 3829285169Scy return ( iCheckState == MODEM_STATE_DISCONNECT ) ; 3830285169Scy} 3831285169Scy 3832285169Scy/**************************************************************************************************/ 3833285169Scy 3834285169Scystatic int 3835285169ScyisModemStateTimerOn ( struct jjyunit *up ) 3836285169Scy{ 3837285169Scy return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ; 3838285169Scy} 3839285169Scy 3840285169Scy/**************************************************************************************************/ 3841285169Scy 3842106163Srobertostatic void 3843285169Scymodem_connect ( int unit, struct peer *peer ) 3844106163Sroberto{ 3845285169Scy struct refclockproc *pp; 3846285169Scy struct jjyunit *up; 3847106163Sroberto 3848285169Scy pp = peer->procptr ; 3849285169Scy up = pp->unitptr ; 3850106163Sroberto 3851285169Scy DEBUG_MODEM_PRINTF( "modem_connect" ) ; 3852182007Sroberto 3853285169Scy up->iModemEvent = MODEM_EVENT_INITIALIZE ; 3854285169Scy 3855285169Scy modem_control ( peer, pp, up ) ; 3856285169Scy 3857285169Scy} 3858285169Scy 3859285169Scy/**************************************************************************************************/ 3860285169Scy 3861285169Scystatic void 3862285169Scymodem_disconnect ( int unit, struct peer *peer ) 3863285169Scy{ 3864285169Scy struct refclockproc *pp; 3865285169Scy struct jjyunit *up; 3866285169Scy 3867285169Scy pp = peer->procptr ; 3868280849Scy up = pp->unitptr ; 3869106163Sroberto 3870285169Scy DEBUG_MODEM_PRINTF( "modem_disconnect" ) ; 3871106163Sroberto 3872285169Scy up->iModemEvent = MODEM_EVENT_DISCONNECT ; 3873285169Scy 3874285169Scy modem_control ( peer, pp, up ) ; 3875285169Scy 3876285169Scy} 3877285169Scy 3878285169Scy/**************************************************************************************************/ 3879285169Scy 3880285169Scystatic int 3881285169Scymodem_receive ( struct recvbuf *rbufp ) 3882285169Scy{ 3883285169Scy 3884285169Scy struct peer *peer; 3885285169Scy struct jjyunit *up; 3886285169Scy struct refclockproc *pp; 3887285169Scy char *pBuf ; 3888316068Sdelphij size_t iLen ; 3889285169Scy 3890285169Scy#ifdef DEBUG 3891285169Scy static const char *sFunctionName = "modem_receive" ; 3892285169Scy#endif 3893285169Scy 3894285169Scy peer = rbufp->recv_peer ; 3895285169Scy pp = peer->procptr ; 3896285169Scy up = pp->unitptr ; 3897285169Scy 3898285169Scy DEBUG_MODEM_PRINTF( sFunctionName ) ; 3899285169Scy 3900285169Scy if ( up->linediscipline == LDISC_RAW ) { 3901285169Scy pBuf = up->sTextBuf ; 3902285169Scy iLen = up->iTextBufLen ; 3903285169Scy } else { 3904285169Scy pBuf = pp->a_lastcode ; 3905285169Scy iLen = pp->lencode ; 3906182007Sroberto } 3907182007Sroberto 3908285169Scy if ( iLen == 2 && strncmp( pBuf, "OK" , 2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK ; } 3909285169Scy else if ( iLen == 7 && strncmp( pBuf, "CONNECT" , 7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT ; } 3910285169Scy else if ( iLen == 4 && strncmp( pBuf, "RING" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING ; } 3911285169Scy else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER ; } 3912285169Scy else if ( iLen == 5 && strncmp( pBuf, "ERROR" , 5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR ; } 3913285169Scy else if ( iLen >= 8 && strncmp( pBuf, "CONNECT " , 8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X ; } 3914285169Scy else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; } 3915285169Scy else if ( iLen == 4 && strncmp( pBuf, "BUSY" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY ; } 3916285169Scy else if ( iLen == 9 && strncmp( pBuf, "NO ANSWER" , 9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER ; } 3917285169Scy else { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN ; } 3918285169Scy 3919182007Sroberto#ifdef DEBUG 3920182007Sroberto if ( debug ) { 3921285169Scy char sResp [ 40 ] ; 3922316068Sdelphij size_t iCopyLen ; 3923285169Scy iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ; 3924285169Scy strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ; 3925285169Scy sResp[iCopyLen] = 0 ; 3926316068Sdelphij printf ( "refclock_jjy.c : modem_receive : iLen=%zu pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ; 3927182007Sroberto } 3928182007Sroberto#endif 3929285169Scy modem_control ( peer, pp, up ) ; 3930182007Sroberto 3931285169Scy return 0 ; 3932106163Sroberto 3933106163Sroberto} 3934106163Sroberto 3935200576Sroberto/**************************************************************************************************/ 3936200576Sroberto 3937200576Srobertostatic void 3938285169Scymodem_timer ( int unit, struct peer *peer ) 3939200576Sroberto{ 3940200576Sroberto 3941285169Scy struct refclockproc *pp ; 3942285169Scy struct jjyunit *up ; 3943200576Sroberto 3944285169Scy pp = peer->procptr ; 3945285169Scy up = pp->unitptr ; 3946285169Scy 3947285169Scy DEBUG_MODEM_PRINTF( "modem_timer" ) ; 3948285169Scy 3949285169Scy if ( iModemSilentTimeout[up->iModemState] != 0 ) { 3950285169Scy up->iModemSilentTimer++ ; 3951285169Scy if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) { 3952285169Scy up->iModemEvent = MODEM_EVENT_SILENT ; 3953285169Scy modem_control ( peer, pp, up ) ; 3954285169Scy } 3955285169Scy } 3956285169Scy 3957285169Scy if ( iModemStateTimeout[up->iModemState] != 0 ) { 3958285169Scy up->iModemStateTimer++ ; 3959285169Scy if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) { 3960285169Scy up->iModemEvent = MODEM_EVENT_TIMEOUT ; 3961285169Scy modem_control ( peer, pp, up ) ; 3962285169Scy } 3963285169Scy } 3964285169Scy 3965200576Sroberto} 3966200576Sroberto 3967280849Scy/**************************************************************************************************/ 3968280849Scy 3969280849Scystatic void 3970285169Scymodem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3971280849Scy{ 3972285169Scy 3973285169Scy int rc ; 3974285169Scy short iPostEvent = MODEM_EVENT_NULL ; 3975285169Scy 3976285169Scy DEBUG_MODEM_PRINTF( "modem_control" ) ; 3977285169Scy 3978285169Scy rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ; 3979285169Scy 3980285169Scy if ( rc == CHANGE_MODEM_STATE ) { 3981285169Scy iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ; 3982280849Scy#ifdef DEBUG 3983285169Scy if ( debug ) { 3984285169Scy printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d iPostEvent=%d\n", 3985285169Scy up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ; 3986285169Scy } 3987280849Scy#endif 3988280849Scy 3989285169Scy if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) { 3990285169Scy up->iModemSilentCount = 0 ; 3991285169Scy up->iModemStateTimer = 0 ; 3992285169Scy up->iModemCommandSeq = 0 ; 3993285169Scy } 3994280849Scy 3995285169Scy up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ; 3996285169Scy } 3997280849Scy 3998285169Scy if ( iPostEvent != MODEM_EVENT_NULL ) { 3999285169Scy up->iModemEvent = iPostEvent ; 4000285169Scy modem_control ( peer, pp, up ) ; 4001285169Scy } 4002280849Scy 4003285169Scy up->iModemEvent = MODEM_EVENT_NULL ; 4004285169Scy 4005285169Scy} 4006285169Scy 4007285169Scy/******************************/ 4008285169Scystatic int 4009285169Scymodem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4010285169Scy{ 4011285169Scy 4012285169Scy DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ; 4013285169Scy 4014285169Scy return STAY_MODEM_STATE ; 4015285169Scy 4016285169Scy} 4017285169Scy 4018285169Scy/******************************/ 4019285169Scystatic int 4020285169Scymodem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4021285169Scy{ 4022285169Scy 4023285169Scy DEBUG_MODEM_PRINTF( "modem_disc_init" ) ; 4024285169Scy 4025285169Scy return CHANGE_MODEM_STATE ; 4026285169Scy 4027285169Scy} 4028285169Scy 4029285169Scy/******************************/ 4030285169Scystatic int 4031285169Scymodem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4032285169Scy{ 4033285169Scy 4034285169Scy DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ; 4035285169Scy 4036285169Scy return STAY_MODEM_STATE ; 4037285169Scy 4038285169Scy} 4039285169Scy 4040285169Scy/******************************/ 4041285169Scystatic int 4042285169Scymodem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4043285169Scy{ 4044285169Scy 4045285169Scy DEBUG_MODEM_PRINTF( "modem_init_start" ) ; 4046285169Scy 4047285169Scy up->iModemCommandSeq = 0 ; 4048285169Scy 4049285169Scy#ifdef DEBUG 4050285169Scy if ( debug ) { 4051285169Scy printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ; 4052285169Scy } 4053285169Scy#endif 4054285169Scy 4055285169Scy return modem_init_resp00( peer, pp, up ) ; 4056285169Scy 4057285169Scy} 4058285169Scy 4059285169Scy/******************************/ 4060285169Scystatic int 4061285169Scymodem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4062285169Scy{ 4063285169Scy 4064294554Sdelphij const char * pCmd ; 4065294554Sdelphij char cBuf [ 46 ] ; 4066294554Sdelphij int iCmdLen ; 4067294554Sdelphij int iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ; 4068294554Sdelphij int iNextModemState = STAY_MODEM_STATE ; 4069285169Scy 4070285169Scy DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ; 4071285169Scy 4072285169Scy up->iModemCommandSeq++ ; 4073285169Scy 4074285169Scy switch ( up->iModemCommandSeq ) { 4075285169Scy 4076285169Scy case 1 : 4077285169Scy /* En = Echoback 0:Off 1:On */ 4078285169Scy /* Qn = Result codes 0:On 1:Off */ 4079285169Scy /* Vn = Result codes 0:Numeric 1:Text */ 4080285169Scy pCmd = "ATE0Q0V1\r\n" ; 4081285169Scy break ; 4082285169Scy 4083285169Scy case 2 : 4084285169Scy /* Mn = Speaker switch 0:Off 1:On until remote carrier detected 2:On */ 4085285169Scy if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) { 4086285169Scy /* fudge 127.127.40.n flag3 0 */ 4087285169Scy iSpeakerSwitch = 0 ; 4088285169Scy } else { 4089285169Scy /* fudge 127.127.40.n flag3 1 */ 4090285169Scy iSpeakerSwitch = 2 ; 4091285169Scy } 4092285169Scy 4093285169Scy /* Ln = Speaker volume 0:Very low 1:Low 2:Middle 3:High */ 4094285169Scy if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) { 4095285169Scy /* fudge 127.127.40.n flag4 0 */ 4096285169Scy iSpeakerVolume = 1 ; 4097285169Scy } else { 4098285169Scy /* fudge 127.127.40.n flag4 1 */ 4099285169Scy iSpeakerVolume = 2 ; 4100285169Scy } 4101285169Scy 4102285169Scy pCmd = cBuf ; 4103294554Sdelphij snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ; 4104285169Scy break ; 4105285169Scy 4106285169Scy case 3 : 4107285169Scy /* &Kn = Flow control 4:XON/XOFF */ 4108285169Scy pCmd = "AT&K4\r\n" ; 4109285169Scy break ; 4110285169Scy 4111285169Scy case 4 : 4112285169Scy /* +MS = Protocol V22B:1200,2400bps�iV.22bis) */ 4113285169Scy pCmd = "AT+MS=V22B\r\n" ; 4114285169Scy break ; 4115285169Scy 4116285169Scy case 5 : 4117285169Scy /* %Cn = Data compression 0:No data compression */ 4118285169Scy pCmd = "AT%C0\r\n" ; 4119285169Scy break ; 4120285169Scy 4121285169Scy case 6 : 4122285169Scy /* \Nn = Error correction 0:Normal mode 1:Direct mode 2:V42,MNP 3:V42,MNP,Normal */ 4123285169Scy if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) { 4124285169Scy /* fudge 127.127.40.n flag2 0 */ 4125285169Scy iErrorCorrection = 0 ; 4126285169Scy } else { 4127285169Scy /* fudge 127.127.40.n flag2 1 */ 4128285169Scy iErrorCorrection = 3 ; 4129285169Scy } 4130285169Scy 4131285169Scy pCmd = cBuf ; 4132294554Sdelphij snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ; 4133285169Scy break ; 4134285169Scy 4135285169Scy case 7 : 4136285169Scy /* Hn = Hook 0:Hook-On ( Disconnect ) 1:Hook-Off ( Connect ) */ 4137285169Scy pCmd = "ATH1\r\n" ; 4138285169Scy break ; 4139285169Scy 4140285169Scy case 8 : 4141285169Scy /* Initialize completion */ 4142285169Scy pCmd = NULL ; 4143285169Scy iNextModemState = CHANGE_MODEM_STATE ; 4144285169Scy break ; 4145285169Scy 4146285169Scy default : 4147285169Scy pCmd = NULL ; 4148285169Scy break ; 4149285169Scy 4150285169Scy } 4151285169Scy 4152285169Scy if ( pCmd != NULL ) { 4153285169Scy 4154285169Scy iCmdLen = strlen( pCmd ) ; 4155285169Scy if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4156285169Scy refclock_report( peer, CEVNT_FAULT ) ; 4157285169Scy } 4158285169Scy 4159285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4160285169Scy 4161285169Scy } 4162285169Scy 4163285169Scy return iNextModemState ; 4164285169Scy 4165285169Scy} 4166285169Scy 4167285169Scy/******************************/ 4168285169Scystatic int 4169285169Scymodem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4170285169Scy{ 4171285169Scy 4172285169Scy DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ; 4173285169Scy 4174285169Scy return modem_init_resp00( peer, pp, up ) ; 4175285169Scy 4176285169Scy} 4177285169Scy 4178285169Scy/******************************/ 4179285169Scystatic int 4180285169Scymodem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4181285169Scy{ 4182285169Scy 4183285169Scy DEBUG_MODEM_PRINTF( "modem_init_disc" ) ; 4184285169Scy#ifdef DEBUG 4185285169Scy if ( debug ) { 4186285169Scy printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ; 4187285169Scy } 4188285169Scy#endif 4189285169Scy 4190285169Scy return CHANGE_MODEM_STATE ; 4191285169Scy 4192285169Scy} 4193285169Scy 4194285169Scy/******************************/ 4195285169Scystatic int 4196285169Scymodem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4197285169Scy{ 4198285169Scy 4199285169Scy DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ; 4200285169Scy 4201285169Scy return STAY_MODEM_STATE ; 4202285169Scy 4203285169Scy} 4204285169Scy 4205285169Scy/******************************/ 4206285169Scystatic int 4207285169Scymodem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4208285169Scy{ 4209285169Scy 4210285169Scy char sCmd [ 46 ] ; 4211285169Scy int iCmdLen ; 4212285169Scy char cToneOrPulse ; 4213285169Scy 4214285169Scy DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ; 4215285169Scy 4216285169Scy /* Tone or Pulse */ 4217280849Scy if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 4218285169Scy /* fudge 127.127.40.n flag1 0 */ 4219285169Scy cToneOrPulse = 'T' ; 4220285169Scy } else { 4221285169Scy /* fudge 127.127.40.n flag1 1 */ 4222285169Scy cToneOrPulse = 'P' ; 4223280849Scy } 4224280849Scy 4225285169Scy /* Connect ( Dial number ) */ 4226285169Scy snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ; 4227285169Scy 4228285169Scy /* Send command */ 4229285169Scy iCmdLen = strlen( sCmd ) ; 4230285169Scy if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) { 4231285169Scy refclock_report( peer, CEVNT_FAULT ) ; 4232285169Scy } 4233285169Scy 4234285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ; 4235285169Scy 4236285169Scy return STAY_MODEM_STATE ; 4237285169Scy 4238285169Scy} 4239285169Scy 4240285169Scy/******************************/ 4241285169Scystatic int 4242285169Scymodem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4243285169Scy{ 4244285169Scy 4245285169Scy DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ; 4246280849Scy#ifdef DEBUG 4247280849Scy if ( debug ) { 4248285169Scy printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ; 4249280849Scy } 4250280849Scy#endif 4251280849Scy 4252285169Scy return modem_conn_escape( peer, pp, up ) ; 4253280849Scy 4254285169Scy} 4255285169Scy 4256285169Scy/******************************/ 4257285169Scystatic int 4258285169Scymodem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4259285169Scy{ 4260285169Scy 4261285169Scy DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ; 4262285169Scy 4263285169Scy return CHANGE_MODEM_STATE ; 4264285169Scy 4265285169Scy} 4266285169Scy 4267285169Scy/******************************/ 4268285169Scystatic int 4269285169Scymodem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4270285169Scy{ 4271285169Scy 4272285169Scy DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ; 4273280849Scy#ifdef DEBUG 4274280849Scy if ( debug ) { 4275285169Scy printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ; 4276280849Scy } 4277280849Scy#endif 4278280849Scy 4279285169Scy modem_esc_disc( peer, pp, up ) ; 4280285169Scy 4281285169Scy return CHANGE_MODEM_STATE ; 4282285169Scy 4283285169Scy} 4284285169Scy 4285285169Scy/******************************/ 4286285169Scystatic int 4287285169Scymodem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4288285169Scy{ 4289285169Scy 4290285169Scy DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ; 4291285169Scy 4292285169Scy return STAY_MODEM_STATE ; 4293285169Scy 4294285169Scy} 4295285169Scy 4296285169Scy/******************************/ 4297285169Scystatic int 4298285169Scymodem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4299285169Scy{ 4300285169Scy 4301285169Scy DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ; 4302285169Scy 4303285169Scy return CHANGE_MODEM_STATE ; 4304285169Scy 4305285169Scy} 4306285169Scy 4307285169Scy/******************************/ 4308285169Scystatic int 4309285169Scymodem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4310285169Scy{ 4311285169Scy 4312285169Scy DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ; 4313285169Scy 4314285169Scy return STAY_MODEM_STATE ; 4315285169Scy 4316285169Scy} 4317285169Scy 4318285169Scy/******************************/ 4319285169Scystatic int 4320285169Scymodem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4321285169Scy{ 4322285169Scy 4323294554Sdelphij const char * pCmd ; 4324294554Sdelphij int iCmdLen ; 4325285169Scy 4326285169Scy DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ; 4327285169Scy 4328285169Scy /* Escape command ( Go to command mode ) */ 4329285169Scy pCmd = "+++" ; 4330285169Scy 4331285169Scy /* Send command */ 4332285169Scy iCmdLen = strlen( pCmd ) ; 4333285169Scy if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4334285169Scy refclock_report( peer, CEVNT_FAULT ) ; 4335280849Scy } 4336280849Scy 4337285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4338285169Scy 4339285169Scy return STAY_MODEM_STATE ; 4340285169Scy 4341280849Scy} 4342280849Scy 4343285169Scy/******************************/ 4344285169Scystatic int 4345285169Scymodem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4346285169Scy{ 4347280849Scy 4348285169Scy DEBUG_MODEM_PRINTF( "modem_esc_data" ) ; 4349285169Scy 4350285169Scy up->iModemSilentTimer = 0 ; 4351285169Scy 4352285169Scy return STAY_MODEM_STATE ; 4353285169Scy 4354285169Scy} 4355285169Scy 4356285169Scy/******************************/ 4357285169Scystatic int 4358285169Scymodem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4359285169Scy{ 4360285169Scy 4361285169Scy DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ; 4362285169Scy 4363285169Scy up->iModemSilentCount ++ ; 4364285169Scy 4365285169Scy if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) { 4366285169Scy#ifdef DEBUG 4367285169Scy if ( debug ) { 4368285169Scy printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ; 4369285169Scy } 4370285169Scy#endif 4371285169Scy modem_esc_escape( peer, pp, up ) ; 4372285169Scy up->iModemSilentTimer = 0 ; 4373285169Scy return STAY_MODEM_STATE ; 4374285169Scy } 4375285169Scy 4376285169Scy#ifdef DEBUG 4377285169Scy if ( debug ) { 4378285169Scy printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ; 4379285169Scy } 4380285169Scy#endif 4381285169Scy return modem_esc_disc( peer, pp, up ) ; 4382285169Scy 4383285169Scy} 4384285169Scy/******************************/ 4385285169Scystatic int 4386285169Scymodem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4387285169Scy{ 4388285169Scy 4389294554Sdelphij const char * pCmd ; 4390294554Sdelphij int iCmdLen ; 4391285169Scy 4392285169Scy DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ; 4393285169Scy 4394285169Scy /* Disconnect */ 4395285169Scy pCmd = "ATH0\r\n" ; 4396285169Scy 4397285169Scy /* Send command */ 4398285169Scy iCmdLen = strlen( pCmd ) ; 4399285169Scy if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4400285169Scy refclock_report( peer, CEVNT_FAULT ) ; 4401285169Scy } 4402285169Scy 4403285169Scy jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4404285169Scy 4405285169Scy return CHANGE_MODEM_STATE ; 4406285169Scy 4407285169Scy} 4408285169Scy 4409285169Scy/*################################################################################################*/ 4410285169Scy/*################################################################################################*/ 4411285169Scy/*## ##*/ 4412285169Scy/*## jjy_write_clockstats ##*/ 4413285169Scy/*## ##*/ 4414285169Scy/*################################################################################################*/ 4415285169Scy/*################################################################################################*/ 4416285169Scy 4417280849Scystatic void 4418285169Scyjjy_write_clockstats ( struct peer *peer, int iMark, const char *pData ) 4419280849Scy{ 4420285169Scy 4421294554Sdelphij char sLog [ 100 ] ; 4422294554Sdelphij const char * pMark ; 4423294554Sdelphij int iMarkLen, iDataLen ; 4424285169Scy 4425285169Scy switch ( iMark ) { 4426285169Scy case JJY_CLOCKSTATS_MARK_JJY : 4427285169Scy pMark = "JJY " ; 4428285169Scy break ; 4429285169Scy case JJY_CLOCKSTATS_MARK_SEND : 4430285169Scy pMark = "--> " ; 4431285169Scy break ; 4432285169Scy case JJY_CLOCKSTATS_MARK_RECEIVE : 4433285169Scy pMark = "<-- " ; 4434285169Scy break ; 4435285169Scy case JJY_CLOCKSTATS_MARK_INFORMATION : 4436285169Scy pMark = "--- " ; 4437285169Scy break ; 4438285169Scy case JJY_CLOCKSTATS_MARK_ATTENTION : 4439285169Scy pMark = "=== " ; 4440285169Scy break ; 4441285169Scy case JJY_CLOCKSTATS_MARK_WARNING : 4442285169Scy pMark = "-W- " ; 4443285169Scy break ; 4444285169Scy case JJY_CLOCKSTATS_MARK_ERROR : 4445285169Scy pMark = "-X- " ; 4446285169Scy break ; 4447330106Sdelphij case JJY_CLOCKSTATS_MARK_BUG : 4448330106Sdelphij pMark = "!!! " ; 4449330106Sdelphij break ; 4450285169Scy default : 4451285169Scy pMark = "" ; 4452285169Scy break ; 4453285169Scy } 4454285169Scy 4455285169Scy iDataLen = strlen( pData ) ; 4456285169Scy iMarkLen = strlen( pMark ) ; 4457285169Scy strcpy( sLog, pMark ) ; /* Harmless because of enough length */ 4458285169Scy printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ; 4459285169Scy 4460285169Scy#ifdef DEBUG 4461285169Scy if ( debug ) { 4462285169Scy printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ; 4463285169Scy } 4464285169Scy#endif 4465285169Scy record_clock_stats( &peer->srcadr, sLog ) ; 4466285169Scy 4467285169Scy} 4468285169Scy 4469285169Scy/*################################################################################################*/ 4470285169Scy/*################################################################################################*/ 4471285169Scy/*## ##*/ 4472285169Scy/*## printableString ##*/ 4473285169Scy/*## ##*/ 4474285169Scy/*################################################################################################*/ 4475285169Scy/*################################################################################################*/ 4476285169Scy 4477285169Scystatic void 4478285169ScyprintableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen ) 4479285169Scy{ 4480280849Scy const char *printableControlChar[] = { 4481280849Scy "<NUL>", "<SOH>", "<STX>", "<ETX>", 4482280849Scy "<EOT>", "<ENQ>", "<ACK>", "<BEL>", 4483280849Scy "<BS>" , "<HT>" , "<LF>" , "<VT>" , 4484280849Scy "<FF>" , "<CR>" , "<SO>" , "<SI>" , 4485280849Scy "<DLE>", "<DC1>", "<DC2>", "<DC3>", 4486280849Scy "<DC4>", "<NAK>", "<SYN>", "<ETB>", 4487280849Scy "<CAN>", "<EM>" , "<SUB>", "<ESC>", 4488280849Scy "<FS>" , "<GS>" , "<RS>" , "<US>" , 4489280849Scy " " } ; 4490280849Scy 4491280849Scy size_t i, j, n ; 4492280849Scy size_t InputLen; 4493280849Scy size_t OutputLen; 4494280849Scy 4495280849Scy InputLen = (size_t)iInputLen; 4496280849Scy OutputLen = (size_t)iOutputLen; 4497280849Scy for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) { 4498280849Scy if ( isprint( (unsigned char)sInput[i] ) ) { 4499280849Scy n = 1 ; 4500280849Scy if ( j + 1 >= OutputLen ) 4501280849Scy break ; 4502280849Scy sOutput[j] = sInput[i] ; 4503280849Scy } else if ( ( sInput[i] & 0xFF ) < 4504280849Scy COUNTOF(printableControlChar) ) { 4505280849Scy n = strlen( printableControlChar[sInput[i] & 0xFF] ) ; 4506280849Scy if ( j + n + 1 >= OutputLen ) 4507280849Scy break ; 4508280849Scy strlcpy( sOutput + j, 4509280849Scy printableControlChar[sInput[i] & 0xFF], 4510280849Scy OutputLen - j ) ; 4511280849Scy } else { 4512280849Scy n = 5 ; 4513280849Scy if ( j + n + 1 >= OutputLen ) 4514280849Scy break ; 4515280849Scy snprintf( sOutput + j, OutputLen - j, "<x%X>", 4516280849Scy sInput[i] & 0xFF ) ; 4517280849Scy } 4518280849Scy j += n ; 4519280849Scy } 4520280849Scy 4521280849Scy sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ; 4522280849Scy 4523280849Scy} 4524280849Scy 4525280849Scy/**************************************************************************************************/ 4526280849Scy 4527106163Sroberto#else 4528106163Srobertoint refclock_jjy_bs ; 4529106163Sroberto#endif /* REFCLOCK */ 4530