refclock_jjy.c revision 1.14
1/* $NetBSD: refclock_jjy.c,v 1.14 2019/02/03 10:48:47 mrg Exp $ */ 2 3/* 4 * refclock_jjy - clock driver for JJY receivers 5 */ 6 7/**********************************************************************/ 8/* */ 9/* Copyright (C) 2001-2015, Takao Abe. All rights reserved. */ 10/* */ 11/* Permission to use, copy, modify, and distribute this software */ 12/* and its documentation for any purpose is hereby granted */ 13/* without fee, provided that the following conditions are met: */ 14/* */ 15/* One retains the entire copyright notice properly, and both the */ 16/* copyright notice and this license. in the documentation and/or */ 17/* other materials provided with the distribution. */ 18/* */ 19/* This software and the name of the author must not be used to */ 20/* endorse or promote products derived from this software without */ 21/* prior written permission. */ 22/* */ 23/* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */ 24/* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */ 25/* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */ 26/* PARTICULAR PURPOSE. */ 27/* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */ 28/* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 29/* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ 30/* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */ 31/* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ 32/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */ 33/* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */ 34/* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 35/* */ 36/* This driver is developed in my private time, and is opened as */ 37/* voluntary contributions for the NTP. */ 38/* The manufacturer of the JJY receiver has not participated in */ 39/* a development of this driver. */ 40/* The manufacturer does not warrant anything about this driver, */ 41/* and is not liable for anything about this driver. */ 42/* */ 43/**********************************************************************/ 44/* */ 45/* Author Takao Abe */ 46/* Email takao_abe@xurb.jp */ 47/* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */ 48/* */ 49/* The email address abetakao@bea.hi-ho.ne.jp is never read */ 50/* from 2010, because a few filtering rule are provided by the */ 51/* "hi-ho.ne.jp", and lots of spam mail are reached. */ 52/* New email address for supporting the refclock_jjy is */ 53/* takao_abe@xurb.jp */ 54/* */ 55/**********************************************************************/ 56/* */ 57/* History */ 58/* */ 59/* 2001/07/15 */ 60/* [New] Support the Tristate Ltd. JJY receiver */ 61/* */ 62/* 2001/08/04 */ 63/* [Change] Log to clockstats even if bad reply */ 64/* [Fix] PRECISION = (-3) (about 100 ms) */ 65/* [Add] Support the C-DEX Co.Ltd. JJY receiver */ 66/* */ 67/* 2001/12/04 */ 68/* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */ 69/* */ 70/* 2002/07/12 */ 71/* [Fix] Portability for FreeBSD ( patched by the user ) */ 72/* */ 73/* 2004/10/31 */ 74/* [Change] Command send timing for the Tristate Ltd. JJY receiver */ 75/* JJY-01 ( Firmware version 2.01 ) */ 76/* Thanks to Andy Taki for testing under FreeBSD */ 77/* */ 78/* 2004/11/28 */ 79/* [Add] Support the Echo Keisokuki LT-2000 receiver */ 80/* */ 81/* 2006/11/04 */ 82/* [Fix] C-DEX JST2000 */ 83/* Thanks to Hideo Kuramatsu for the patch */ 84/* */ 85/* 2009/04/05 */ 86/* [Add] Support the CITIZEN T.I.C JJY-200 receiver */ 87/* */ 88/* 2010/11/20 */ 89/* [Change] Bug 1618 ( Harmless ) */ 90/* Code clean up ( Remove unreachable codes ) in */ 91/* jjy_start() */ 92/* [Change] Change clockstats format of the Tristate JJY01/02 */ 93/* Issues more command to get the status of the receiver */ 94/* when "fudge 127.127.40.X flag1 1" is specified */ 95/* ( DATE,STIM -> DCST,STUS,DATE,STIM ) */ 96/* */ 97/* 2011/04/30 */ 98/* [Add] Support the Tristate Ltd. TS-GPSclock-01 */ 99/* */ 100/* 2015/03/29 */ 101/* [Add] Support the Telephone JJY */ 102/* [Change] Split the start up routine into each JJY receivers. */ 103/* Change raw data internal bufferring process */ 104/* Change over midnight handling of TS-JJY01 and TS-GPS01 */ 105/* to put DATE command between before and after TIME's. */ 106/* Unify the writing clockstats of all JJY receivers. */ 107/* */ 108/* 2015/05/15 */ 109/* [Add] Support the SEIKO TIME SYSTEMS TDC-300 */ 110/* */ 111/* 2016/05/08 */ 112/* [Fix] C-DEX JST2000 */ 113/* Thanks to Mr. Kuramatsu for the report and the patch. */ 114/* */ 115/* 2017/04/30 */ 116/* [Change] Avoid a wrong report of the coverity static analysis */ 117/* tool. ( The code is harmless and has no bug. ) */ 118/* teljjy_conn_send() */ 119/* */ 120/**********************************************************************/ 121 122#ifdef HAVE_CONFIG_H 123#include <config.h> 124#endif 125 126#if defined(REFCLOCK) && defined(CLOCK_JJY) 127 128#include <stdio.h> 129#include <ctype.h> 130#include <string.h> 131#include <sys/time.h> 132#include <time.h> 133 134#include "ntpd.h" 135#include "ntp_io.h" 136#include "ntp_tty.h" 137#include "ntp_refclock.h" 138#include "ntp_calendar.h" 139#include "ntp_stdlib.h" 140 141/**********************************************************************/ 142 143/* 144 * Interface definitions 145 */ 146#define DEVICE "/dev/jjy%d" /* device name and unit */ 147#define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */ 148#define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */ 149#define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */ 150#define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */ 151#define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */ 152#define SPEED232_SEIKO_TIMESYS_TDC_300 B2400 /* UART speed (2400 baud) */ 153#define SPEED232_TELEPHONE B2400 /* UART speed (4800 baud) */ 154#define REFID "JJY" /* reference ID */ 155#define DESCRIPTION "JJY Receiver" 156#define PRECISION (-3) /* precision assumed (about 100 ms) */ 157 158/* 159 * JJY unit control structure 160 */ 161 162struct jjyRawDataBreak { 163 const char * pString ; 164 int iLength ; 165} ; 166 167#define MAX_TIMESTAMP 6 168#define MAX_RAWBUF 100 169#define MAX_LOOPBACK 5 170 171struct jjyunit { 172/* Set up by the function "jjy_start_xxxxxxxx" */ 173 char unittype ; /* UNITTYPE_XXXXXXXXXX */ 174 short operationmode ; /* Echo Keisokuki LT-2000 */ 175 int linespeed ; /* SPEED232_XXXXXXXXXX */ 176 short linediscipline ; /* LDISC_CLK or LDISC_RAW */ 177/* Receiving data */ 178 char bInitError ; /* Set by jjy_start if any error during initialization */ 179 short iProcessState ; /* JJY_PROCESS_STATE_XXXXXX */ 180 char bReceiveFlag ; /* Set and reset by jjy_receive */ 181 char bLineError ; /* Reset by jjy_poll / Set by jjy_receive_xxxxxxxx*/ 182 short iCommandSeq ; /* 0:Idle Non-Zero:Issued */ 183 short iReceiveSeq ; 184 int iLineCount ; 185 int year, month, day, hour, minute, second, msecond ; 186 int leapsecond ; 187 int iTimestampCount ; /* TS-JJY01, TS-GPS01, Telephone-JJY */ 188 int iTimestamp [ MAX_TIMESTAMP ] ; /* Serial second ( 0 - 86399 ) */ 189/* LDISC_RAW only */ 190 char sRawBuf [ MAX_RAWBUF ] ; 191 int iRawBufLen ; 192 struct jjyRawDataBreak *pRawBreak ; 193 char bWaitBreakString ; 194 char sLineBuf [ MAX_RAWBUF ] ; 195 int iLineBufLen ; 196 char sTextBuf [ MAX_RAWBUF ] ; 197 int iTextBufLen ; 198 char bSkipCntrlCharOnly ; 199/* Telephone JJY auto measurement of the loopback delay */ 200 char bLoopbackMode ; 201 short iLoopbackCount ; 202 struct timeval sendTime[MAX_LOOPBACK], delayTime[MAX_LOOPBACK] ; 203 char bLoopbackTimeout[MAX_LOOPBACK] ; 204 short iLoopbackValidCount ; 205/* Telephone JJY timer */ 206 short iTeljjySilentTimer ; 207 short iTeljjyStateTimer ; 208/* Telephone JJY control finite state machine */ 209 short iClockState ; 210 short iClockEvent ; 211 short iClockCommandSeq ; 212/* Modem timer */ 213 short iModemSilentCount ; 214 short iModemSilentTimer ; 215 short iModemStateTimer ; 216/* Modem control finite state machine */ 217 short iModemState ; 218 short iModemEvent ; 219 short iModemCommandSeq ; 220}; 221 222#define UNITTYPE_TRISTATE_JJY01 1 223#define UNITTYPE_CDEX_JST2000 2 224#define UNITTYPE_ECHOKEISOKUKI_LT2000 3 225#define UNITTYPE_CITIZENTIC_JJY200 4 226#define UNITTYPE_TRISTATE_GPSCLOCK01 5 227#define UNITTYPE_SEIKO_TIMESYS_TDC_300 6 228#define UNITTYPE_TELEPHONE 100 229 230#define JJY_PROCESS_STATE_IDLE 0 231#define JJY_PROCESS_STATE_POLL 1 232#define JJY_PROCESS_STATE_RECEIVE 2 233#define JJY_PROCESS_STATE_DONE 3 234#define JJY_PROCESS_STATE_ERROR 4 235 236/**********************************************************************/ 237 238/* 239 * Function calling structure 240 * 241 * jjy_start 242 * |-- jjy_start_tristate_jjy01 243 * |-- jjy_start_cdex_jst2000 244 * |-- jjy_start_echokeisokuki_lt2000 245 * |-- jjy_start_citizentic_jjy200 246 * |-- jjy_start_tristate_gpsclock01 247 * |-- jjy_start_seiko_tsys_tdc_300 248 * |-- jjy_start_telephone 249 * 250 * jjy_shutdown 251 * 252 * jjy_poll 253 * |-- jjy_poll_tristate_jjy01 254 * |-- jjy_poll_cdex_jst2000 255 * |-- jjy_poll_echokeisokuki_lt2000 256 * |-- jjy_poll_citizentic_jjy200 257 * |-- jjy_poll_tristate_gpsclock01 258 * |-- jjy_poll_seiko_tsys_tdc_300 259 * |-- jjy_poll_telephone 260 * |-- teljjy_control 261 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 262 * |-- modem_connect 263 * |-- modem_control 264 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 265 * 266 * jjy_receive 267 * | 268 * |-- jjy_receive_tristate_jjy01 269 * | |-- jjy_synctime 270 * |-- jjy_receive_cdex_jst2000 271 * | |-- jjy_synctime 272 * |-- jjy_receive_echokeisokuki_lt2000 273 * | |-- jjy_synctime 274 * |-- jjy_receive_citizentic_jjy200 275 * | |-- jjy_synctime 276 * |-- jjy_receive_tristate_gpsclock01 277 * | |-- jjy_synctime 278 * |-- jjy_receive_seiko_tsys_tdc_300 279 * | |-- jjy_synctime 280 * |-- jjy_receive_telephone 281 * |-- modem_receive 282 * | |-- modem_control 283 * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 284 * |-- teljjy_control 285 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 286 * |-- jjy_synctime 287 * |-- modem_disconnect 288 * |-- modem_control 289 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 290 * 291 * jjy_timer 292 * |-- jjy_timer_telephone 293 * |-- modem_timer 294 * | |-- modem_control 295 * | |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 296 * |-- teljjy_control 297 * |-- teljjy_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 298 * |-- modem_disconnect 299 * |-- modem_control 300 * |-- modem_XXXX_YYYY ( XXXX_YYYY is an event handler name. ) 301 * 302 * Function prototypes 303 */ 304 305static int jjy_start (int, struct peer *); 306static int jjy_start_tristate_jjy01 (int, struct peer *, struct jjyunit *); 307static int jjy_start_cdex_jst2000 (int, struct peer *, struct jjyunit *); 308static int jjy_start_echokeisokuki_lt2000 (int, struct peer *, struct jjyunit *); 309static int jjy_start_citizentic_jjy200 (int, struct peer *, struct jjyunit *); 310static int jjy_start_tristate_gpsclock01 (int, struct peer *, struct jjyunit *); 311static int jjy_start_seiko_tsys_tdc_300 (int, struct peer *, struct jjyunit *); 312static int jjy_start_telephone (int, struct peer *, struct jjyunit *); 313 314static void jjy_shutdown (int, struct peer *); 315 316static void jjy_poll (int, struct peer *); 317static void jjy_poll_tristate_jjy01 (int, struct peer *); 318static void jjy_poll_cdex_jst2000 (int, struct peer *); 319static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *); 320static void jjy_poll_citizentic_jjy200 (int, struct peer *); 321static void jjy_poll_tristate_gpsclock01 (int, struct peer *); 322static void jjy_poll_seiko_tsys_tdc_300 (int, struct peer *); 323static void jjy_poll_telephone (int, struct peer *); 324 325static void jjy_receive (struct recvbuf *); 326static int jjy_receive_tristate_jjy01 (struct recvbuf *); 327static int jjy_receive_cdex_jst2000 (struct recvbuf *); 328static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *); 329static int jjy_receive_citizentic_jjy200 (struct recvbuf *); 330static int jjy_receive_tristate_gpsclock01 (struct recvbuf *); 331static int jjy_receive_seiko_tsys_tdc_300 (struct recvbuf *); 332static int jjy_receive_telephone (struct recvbuf *); 333 334static void jjy_timer (int, struct peer *); 335static void jjy_timer_telephone (int, struct peer *); 336 337static void jjy_synctime ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 338static void jjy_write_clockstats ( struct peer *, int, const char* ) ; 339 340static int getRawDataBreakPosition ( struct jjyunit *, int ) ; 341 342static short getModemState ( struct jjyunit * ) ; 343static int isModemStateConnect ( short ) ; 344static int isModemStateDisconnect ( short ) ; 345static int isModemStateTimerOn ( struct jjyunit * ) ; 346static void modem_connect ( int, struct peer * ) ; 347static void modem_disconnect ( int, struct peer * ) ; 348static int modem_receive ( struct recvbuf * ) ; 349static void modem_timer ( int, struct peer * ); 350 351static void printableString ( char*, int, const char*, int ) ; 352 353/* 354 * Transfer vector 355 */ 356struct refclock refclock_jjy = { 357 jjy_start, /* start up driver */ 358 jjy_shutdown, /* shutdown driver */ 359 jjy_poll, /* transmit poll message */ 360 noentry, /* not used */ 361 noentry, /* not used */ 362 noentry, /* not used */ 363 jjy_timer /* 1 second interval timer */ 364}; 365 366/* 367 * Start up driver return code 368 */ 369#define RC_START_SUCCESS 1 370#define RC_START_ERROR 0 371 372/* 373 * Local constants definition 374 */ 375 376#define MAX_LOGTEXT 100 377 378#ifndef TRUE 379#define TRUE (0==0) 380#endif 381#ifndef FALSE 382#define FALSE (!TRUE) 383#endif 384 385/* Local constants definition for the return code of the jjy_receive_xxxxxxxx */ 386 387#define JJY_RECEIVE_DONE 0 388#define JJY_RECEIVE_SKIP 1 389#define JJY_RECEIVE_UNPROCESS 2 390#define JJY_RECEIVE_WAIT 3 391#define JJY_RECEIVE_ERROR 4 392 393/* Local constants definition for the 2nd parameter of the jjy_write_clockstats */ 394 395#define JJY_CLOCKSTATS_MARK_NONE 0 396#define JJY_CLOCKSTATS_MARK_JJY 1 397#define JJY_CLOCKSTATS_MARK_SEND 2 398#define JJY_CLOCKSTATS_MARK_RECEIVE 3 399#define JJY_CLOCKSTATS_MARK_INFORMATION 4 400#define JJY_CLOCKSTATS_MARK_ATTENTION 5 401#define JJY_CLOCKSTATS_MARK_WARNING 6 402#define JJY_CLOCKSTATS_MARK_ERROR 7 403#define JJY_CLOCKSTATS_MARK_BUG 8 404 405/* Local constants definition for the clockstats messages */ 406 407#define JJY_CLOCKSTATS_MESSAGE_ECHOBACK "* Echoback" 408#define JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY "* Ignore replay : [%s]" 409#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2 "* Over midnight : timestamp=%d, %d" 410#define JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_3 "* Over midnight : timestamp=%d, %d, %d" 411#define JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE "* Unsure timestamp : %s" 412#define JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY "* Loopback delay : %d.%03d mSec." 413#define JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST "* Delay adjustment : %d mSec. ( valid=%hd/%d )" 414#define JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST "* Delay adjustment : None ( valid=%hd/%d )" 415 416#define JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY "# Unexpected reply : [%s]" 417#define JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH "# Invalid length : length=%d" 418#define JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY "# Too many reply : count=%d" 419#define JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY "# Invalid reply : [%s]" 420#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2 "# Slow reply : timestamp=%d, %d" 421#define JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_3 "# Slow reply : timestamp=%d, %d, %d" 422#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE "# Invalid date : rc=%d year=%d month=%d day=%d" 423#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME "# Invalid time : rc=%d hour=%d minute=%d second=%d" 424#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME "# Invalid time : rc=%d year=%d month=%d day=%d hour=%d minute=%d second=%d" 425#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP "# Invalid leap : leapsecond=[%s]" 426#define JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_STATUS "# Invalid status : status=[%s]" 427 428/* Debug print macro */ 429 430#ifdef DEBUG 431#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 ) ; } } 432#else 433#define DEBUG_PRINTF_JJY_RECEIVE(sFunc,iLen) 434#endif 435 436/**************************************************************************************************/ 437/* jjy_start - open the devices and initialize data for processing */ 438/**************************************************************************************************/ 439static int 440jjy_start ( int unit, struct peer *peer ) 441{ 442 443 struct refclockproc *pp ; 444 struct jjyunit *up ; 445 int rc ; 446 int fd ; 447 char sDeviceName [ sizeof(DEVICE) + 10 ], sLog [ 60 ] ; 448 449#ifdef DEBUG 450 if ( debug ) { 451 printf( "refclock_jjy.c : jjy_start : %s mode=%d dev=%s unit=%d\n", 452 ntoa(&peer->srcadr), peer->ttl, DEVICE, unit ) ; 453 } 454#endif 455 456 /* Allocate memory for the unit structure */ 457 up = emalloc( sizeof(*up) ) ; 458 if ( up == NULL ) { 459 msyslog ( LOG_ERR, "refclock_jjy.c : jjy_start : emalloc" ) ; 460 return RC_START_ERROR ; 461 } 462 memset ( up, 0, sizeof(*up) ) ; 463 464 up->bInitError = FALSE ; 465 up->iProcessState = JJY_PROCESS_STATE_IDLE ; 466 up->bReceiveFlag = FALSE ; 467 up->iCommandSeq = 0 ; 468 up->iLineCount = 0 ; 469 up->iTimestampCount = 0 ; 470 up->bWaitBreakString = FALSE ; 471 up->iRawBufLen = up->iLineBufLen = up->iTextBufLen = 0 ; 472 up->bSkipCntrlCharOnly = TRUE ; 473 474 /* Set up the device name */ 475 snprintf( sDeviceName, sizeof(sDeviceName), DEVICE, unit ) ; 476 477 snprintf( sLog, sizeof(sLog), "mode=%d dev=%s", peer->ttl, sDeviceName ) ; 478 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 479 480 /* 481 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf 482 */ 483 switch ( peer->ttl ) { 484 case 0 : 485 case 1 : 486 rc = jjy_start_tristate_jjy01 ( unit, peer, up ) ; 487 break ; 488 case 2 : 489 rc = jjy_start_cdex_jst2000 ( unit, peer, up ) ; 490 break ; 491 case 3 : 492 rc = jjy_start_echokeisokuki_lt2000 ( unit, peer, up ) ; 493 break ; 494 case 4 : 495 rc = jjy_start_citizentic_jjy200 ( unit, peer, up ) ; 496 break ; 497 case 5 : 498 rc = jjy_start_tristate_gpsclock01 ( unit, peer, up ) ; 499 break ; 500 case 6 : 501 rc = jjy_start_seiko_tsys_tdc_300 ( unit, peer, up ) ; 502 break ; 503 case 100 : 504 rc = jjy_start_telephone ( unit, peer, up ) ; 505 break ; 506 default : 507 if ( 101 <= peer->ttl && peer->ttl <= 180 ) { 508 rc = jjy_start_telephone ( unit, peer, up ) ; 509 } else { 510 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", 511 ntoa(&peer->srcadr), peer->ttl ) ; 512 free ( (void*) up ) ; 513 return RC_START_ERROR ; 514 } 515 } 516 517 if ( rc != 0 ) { 518 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Initialize error", 519 ntoa(&peer->srcadr), peer->ttl ) ; 520 free ( (void*) up ) ; 521 return RC_START_ERROR ; 522 } 523 524 /* Open the device */ 525 fd = refclock_open ( sDeviceName, up->linespeed, up->linediscipline ) ; 526 if ( fd <= 0 ) { 527 free ( (void*) up ) ; 528 return RC_START_ERROR ; 529 } 530 531 /* 532 * Initialize variables 533 */ 534 pp = peer->procptr ; 535 536 pp->clockdesc = DESCRIPTION ; 537 pp->unitptr = up ; 538 pp->io.clock_recv = jjy_receive ; 539 pp->io.srcclock = peer ; 540 pp->io.datalen = 0 ; 541 pp->io.fd = fd ; 542 if ( ! io_addclock(&pp->io) ) { 543 close ( fd ) ; 544 pp->io.fd = -1 ; 545 free ( up ) ; 546 pp->unitptr = NULL ; 547 return RC_START_ERROR ; 548 } 549 memcpy( (char*)&pp->refid, REFID, strlen(REFID) ) ; 550 551 peer->precision = PRECISION ; 552 553 snprintf( sLog, sizeof(sLog), "minpoll=%d maxpoll=%d", peer->minpoll, peer->maxpoll ) ; 554 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 555 556 return RC_START_SUCCESS ; 557 558} 559 560/**************************************************************************************************/ 561/* jjy_shutdown - shutdown the clock */ 562/**************************************************************************************************/ 563static void 564jjy_shutdown ( int unit, struct peer *peer ) 565{ 566 567 struct jjyunit *up; 568 struct refclockproc *pp; 569 570 char sLog [ 60 ] ; 571 572 pp = peer->procptr ; 573 up = pp->unitptr ; 574 if ( -1 != pp->io.fd ) { 575 io_closeclock ( &pp->io ) ; 576 } 577 if ( NULL != up ) { 578 free ( up ) ; 579 } 580 581 snprintf( sLog, sizeof(sLog), "JJY stopped. unit=%d mode=%d", unit, peer->ttl ) ; 582 record_clock_stats( &peer->srcadr, sLog ) ; 583 584} 585 586/**************************************************************************************************/ 587/* jjy_receive - receive data from the serial interface */ 588/**************************************************************************************************/ 589static void 590jjy_receive ( struct recvbuf *rbufp ) 591{ 592#ifdef DEBUG 593 static const char *sFunctionName = "jjy_receive" ; 594#endif 595 596 struct jjyunit *up ; 597 struct refclockproc *pp ; 598 struct peer *peer; 599 600 l_fp tRecvTimestamp; /* arrival timestamp */ 601 int rc ; 602 char *pBuf, sLogText [ MAX_LOGTEXT ] ; 603 size_t iLen, iCopyLen ; 604 int i, j, iReadRawBuf, iBreakPosition ; 605 606 /* 607 * Initialize pointers and read the timecode and timestamp 608 */ 609 peer = rbufp->recv_peer ; 610 pp = peer->procptr ; 611 up = pp->unitptr ; 612 613 /* 614 * Get next input line 615 */ 616 if ( up->linediscipline == LDISC_RAW ) { 617 618 pp->lencode = refclock_gtraw ( rbufp, pp->a_lastcode, BMAX-1, &tRecvTimestamp ) ; 619 /* 3rd argument can be BMAX, but the coverity scan tool claim "Memory - corruptions (OVERRUN)" */ 620 /* "a_lastcode" is defined as "char a_lastcode[BMAX]" in the ntp_refclock.h */ 621 /* To avoid its claim, pass the value BMAX-1. */ 622 623 /* 624 * Append received charaters to temporary buffer 625 */ 626 for ( i = 0 ; 627 i < pp->lencode && up->iRawBufLen < MAX_RAWBUF - 2 ; 628 i ++ , up->iRawBufLen ++ ) { 629 up->sRawBuf[up->iRawBufLen] = pp->a_lastcode[i] ; 630 } 631 up->sRawBuf[up->iRawBufLen] = 0 ; 632 633 634 } else { 635 636 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ; 637 638 } 639#ifdef DEBUG 640 printf( "\nrefclock_jjy.c : %s : Len=%d ", sFunctionName, pp->lencode ) ; 641 for ( i = 0 ; i < pp->lencode ; i ++ ) { 642 if ( iscntrl( (u_char)(pp->a_lastcode[i] & 0x7F) ) ) { 643 printf( "<x%02X>", pp->a_lastcode[i] & 0xFF ) ; 644 } else { 645 printf( "%c", pp->a_lastcode[i] ) ; 646 } 647 } 648 printf( "\n" ) ; 649#endif 650 651 /* 652 * The reply with <CR><LF> gives a blank line 653 */ 654 655 if ( pp->lencode == 0 ) return ; 656 657 /* 658 * Receiving data is not expected 659 */ 660 661 if ( up->iProcessState == JJY_PROCESS_STATE_IDLE 662 || up->iProcessState == JJY_PROCESS_STATE_DONE 663 || up->iProcessState == JJY_PROCESS_STATE_ERROR ) { 664 /* Discard received data */ 665 up->iRawBufLen = 0 ; 666#ifdef DEBUG 667 if ( debug ) { 668 printf( "refclock_jjy.c : %s : Discard received data\n", sFunctionName ) ; 669 } 670#endif 671 return ; 672 } 673 674 /* 675 * We get down to business 676 */ 677 678 pp->lastrec = tRecvTimestamp ; 679 680 up->iLineCount ++ ; 681 682 up->iProcessState = JJY_PROCESS_STATE_RECEIVE ; 683 up->bReceiveFlag = TRUE ; 684 685 iReadRawBuf = 0 ; 686 iBreakPosition = up->iRawBufLen - 1 ; 687 for ( ; up->iProcessState == JJY_PROCESS_STATE_RECEIVE ; ) { 688 689 if ( up->linediscipline == LDISC_RAW ) { 690 691 if ( up->bWaitBreakString ) { 692 iBreakPosition = getRawDataBreakPosition( up, iReadRawBuf ) ; 693 if ( iBreakPosition == -1 ) { 694 /* Break string have not come yet */ 695 if ( up->iRawBufLen < MAX_RAWBUF - 2 696 || iReadRawBuf > 0 ) { 697 /* Temporary buffer is not full */ 698 break ; 699 } else { 700 /* Temporary buffer is full */ 701 iBreakPosition = up->iRawBufLen - 1 ; 702 } 703 } 704 } else { 705 iBreakPosition = up->iRawBufLen - 1 ; 706 } 707 708 /* Copy charaters from temporary buffer to process buffer */ 709 up->iLineBufLen = up->iTextBufLen = 0 ; 710 for ( i = iReadRawBuf ; i <= iBreakPosition ; i ++ ) { 711 712 /* Copy all characters */ 713 up->sLineBuf[up->iLineBufLen] = up->sRawBuf[i] ; 714 up->iLineBufLen ++ ; 715 716 /* Copy printable characters */ 717 if ( ! iscntrl( (u_char)up->sRawBuf[i] ) ) { 718 up->sTextBuf[up->iTextBufLen] = up->sRawBuf[i] ; 719 up->iTextBufLen ++ ; 720 } 721 722 } 723 up->sLineBuf[up->iLineBufLen] = 0 ; 724 up->sTextBuf[up->iTextBufLen] = 0 ; 725#ifdef DEBUG 726 printf( "refclock_jjy.c : %s : up->iLineBufLen=%d up->iTextBufLen=%d\n", 727 sFunctionName, up->iLineBufLen, up->iTextBufLen ) ; 728#endif 729 730 if ( up->bSkipCntrlCharOnly && up->iTextBufLen == 0 ) { 731#ifdef DEBUG 732 printf( "refclock_jjy.c : %s : Skip cntrl char only : up->iRawBufLen=%d iReadRawBuf=%d iBreakPosition=%d\n", 733 sFunctionName, up->iRawBufLen, iReadRawBuf, iBreakPosition ) ; 734#endif 735 if ( iBreakPosition + 1 < up->iRawBufLen ) { 736 iReadRawBuf = iBreakPosition + 1 ; 737 continue ; 738 } else { 739 break ; 740 } 741 742 } 743 744 } 745 746 if ( up->linediscipline == LDISC_RAW ) { 747 pBuf = up->sLineBuf ; 748 iLen = up->iLineBufLen ; 749 } else { 750 pBuf = pp->a_lastcode ; 751 iLen = pp->lencode ; 752 } 753 754 iCopyLen = ( iLen <= sizeof(sLogText)-1 ? iLen : sizeof(sLogText)-1 ) ; 755 memcpy( sLogText, pBuf, iCopyLen ) ; 756 sLogText[iCopyLen] = '\0' ; 757 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_RECEIVE, sLogText ) ; 758 759 switch ( up->unittype ) { 760 761 case UNITTYPE_TRISTATE_JJY01 : 762 rc = jjy_receive_tristate_jjy01 ( rbufp ) ; 763 break ; 764 765 case UNITTYPE_CDEX_JST2000 : 766 rc = jjy_receive_cdex_jst2000 ( rbufp ) ; 767 break ; 768 769 case UNITTYPE_ECHOKEISOKUKI_LT2000 : 770 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ; 771 break ; 772 773 case UNITTYPE_CITIZENTIC_JJY200 : 774 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ; 775 break ; 776 777 case UNITTYPE_TRISTATE_GPSCLOCK01 : 778 rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ; 779 break ; 780 781 case UNITTYPE_SEIKO_TIMESYS_TDC_300 : 782 rc = jjy_receive_seiko_tsys_tdc_300 ( rbufp ) ; 783 break ; 784 785 case UNITTYPE_TELEPHONE : 786 rc = jjy_receive_telephone ( rbufp ) ; 787 break ; 788 789 default : 790 rc = JJY_RECEIVE_ERROR ; 791 break ; 792 793 } 794 795 switch ( rc ) { 796 case JJY_RECEIVE_DONE : 797 case JJY_RECEIVE_SKIP : 798 up->iProcessState = JJY_PROCESS_STATE_DONE ; 799 break ; 800 case JJY_RECEIVE_ERROR : 801 up->iProcessState = JJY_PROCESS_STATE_ERROR ; 802 break ; 803 default : 804 break ; 805 } 806 807 if ( up->linediscipline == LDISC_RAW ) { 808 if ( rc == JJY_RECEIVE_UNPROCESS ) { 809 break ; 810 } 811 iReadRawBuf = iBreakPosition + 1 ; 812 if ( iReadRawBuf >= up->iRawBufLen ) { 813 /* Processed all received data */ 814 break ; 815 } 816 } 817 818 if ( up->linediscipline == LDISC_CLK ) { 819 break ; 820 } 821 822 } 823 824 if ( up->linediscipline == LDISC_RAW && iReadRawBuf > 0 ) { 825 for ( i = 0, j = iReadRawBuf ; j < up->iRawBufLen ; i ++, j++ ) { 826 up->sRawBuf[i] = up->sRawBuf[j] ; 827 } 828 up->iRawBufLen -= iReadRawBuf ; 829 if ( up->iRawBufLen < 0 ) { 830 up->iRawBufLen = 0 ; 831 } 832 } 833 834 up->bReceiveFlag = FALSE ; 835 836} 837 838/**************************************************************************************************/ 839 840static int 841getRawDataBreakPosition ( struct jjyunit *up, int iStart ) 842{ 843 844 int i, j ; 845 846 if ( iStart >= up->iRawBufLen ) { 847#ifdef DEBUG 848 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ; 849#endif 850 return -1 ; 851 } 852 853 for ( i = iStart ; i < up->iRawBufLen ; i ++ ) { 854 855 for ( j = 0 ; up->pRawBreak[j].pString != NULL ; j ++ ) { 856 857 if ( i + up->pRawBreak[j].iLength <= up->iRawBufLen ) { 858 859 if ( strncmp( up->sRawBuf + i, 860 up->pRawBreak[j].pString, 861 up->pRawBreak[j].iLength ) == 0 ) { 862 863#ifdef DEBUG 864 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=%d\n", 865 iStart, i + up->pRawBreak[j].iLength - 1 ) ; 866#endif 867 return i + up->pRawBreak[j].iLength - 1 ; 868 869 } 870 } 871 } 872 } 873 874#ifdef DEBUG 875 printf( "refclock_jjy.c : getRawDataBreakPosition : iStart=%d return=-1\n", iStart ) ; 876#endif 877 return -1 ; 878 879} 880 881/**************************************************************************************************/ 882/* jjy_poll - called by the transmit procedure */ 883/**************************************************************************************************/ 884static void 885jjy_poll ( int unit, struct peer *peer ) 886{ 887 888 char sLog [ 40 ], sReach [ 9 ] ; 889 890 struct jjyunit *up; 891 struct refclockproc *pp; 892 893 pp = peer->procptr; 894 up = pp->unitptr ; 895 896 if ( up->bInitError ) { 897 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, "Ignore polling because of error during initializing" ) ; 898 return ; 899 } 900 901 if ( pp->polls > 0 && up->iLineCount == 0 ) { 902 /* 903 * No reply for last command 904 */ 905 refclock_report ( peer, CEVNT_TIMEOUT ) ; 906 } 907 908 pp->polls ++ ; 909 910 sReach[0] = peer->reach & 0x80 ? '1' : '0' ; 911 sReach[1] = peer->reach & 0x40 ? '1' : '0' ; 912 sReach[2] = peer->reach & 0x20 ? '1' : '0' ; 913 sReach[3] = peer->reach & 0x10 ? '1' : '0' ; 914 sReach[4] = peer->reach & 0x08 ? '1' : '0' ; 915 sReach[5] = peer->reach & 0x04 ? '1' : '0' ; 916 sReach[6] = peer->reach & 0x02 ? '1' : '0' ; 917 sReach[7] = 0 ; /* This poll */ 918 sReach[8] = 0 ; 919 920 snprintf( sLog, sizeof(sLog), "polls=%ld reach=%s", pp->polls, sReach ) ; 921 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ; 922 923 up->iProcessState = JJY_PROCESS_STATE_POLL ; 924 up->iCommandSeq = 0 ; 925 up->iReceiveSeq = 0 ; 926 up->iLineCount = 0 ; 927 up->bLineError = FALSE ; 928 up->iRawBufLen = 0 ; 929 930 switch ( up->unittype ) { 931 932 case UNITTYPE_TRISTATE_JJY01 : 933 jjy_poll_tristate_jjy01 ( unit, peer ) ; 934 break ; 935 936 case UNITTYPE_CDEX_JST2000 : 937 jjy_poll_cdex_jst2000 ( unit, peer ) ; 938 break ; 939 940 case UNITTYPE_ECHOKEISOKUKI_LT2000 : 941 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ; 942 break ; 943 944 case UNITTYPE_CITIZENTIC_JJY200 : 945 jjy_poll_citizentic_jjy200 ( unit, peer ) ; 946 break ; 947 948 case UNITTYPE_TRISTATE_GPSCLOCK01 : 949 jjy_poll_tristate_gpsclock01 ( unit, peer ) ; 950 break ; 951 952 case UNITTYPE_SEIKO_TIMESYS_TDC_300 : 953 jjy_poll_seiko_tsys_tdc_300 ( unit, peer ) ; 954 break ; 955 956 case UNITTYPE_TELEPHONE : 957 jjy_poll_telephone ( unit, peer ) ; 958 break ; 959 960 default : 961 break ; 962 963 } 964 965} 966 967/**************************************************************************************************/ 968/* jjy_timer - called at one-second intervals */ 969/**************************************************************************************************/ 970static void 971jjy_timer ( int unit, struct peer *peer ) 972{ 973 974 struct refclockproc *pp ; 975 struct jjyunit *up ; 976 977#ifdef DEBUG 978 if ( debug ) { 979 printf ( "refclock_jjy.c : jjy_timer\n" ) ; 980 } 981#endif 982 983 pp = peer->procptr ; 984 up = pp->unitptr ; 985 986 if ( up->bReceiveFlag ) { 987#ifdef DEBUG 988 if ( debug ) { 989 printf ( "refclock_jjy.c : jjy_timer : up->bReceiveFlag= TRUE : Timer skipped.\n" ) ; 990 } 991#endif 992 return ; 993 } 994 995 switch ( up->unittype ) { 996 997 case UNITTYPE_TELEPHONE : 998 jjy_timer_telephone ( unit, peer ) ; 999 break ; 1000 1001 default : 1002 break ; 1003 1004 } 1005 1006} 1007 1008/**************************************************************************************************/ 1009/* jjy_synctime */ 1010/**************************************************************************************************/ 1011static void 1012jjy_synctime ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 1013{ 1014 1015 char sLog [ 192 ], cStatus ; 1016 const char *pStatus ; 1017 1018 pp->year = up->year ; 1019 pp->day = ymd2yd( up->year, up->month, up->day ) ; 1020 pp->hour = up->hour ; 1021 pp->minute = up->minute ; 1022 pp->second = up->second ; 1023 pp->nsec = up->msecond * 1000000 ; 1024 1025 /* 1026 * JST to UTC 1027 */ 1028 pp->hour -= 9 ; 1029 if ( pp->hour < 0 ) { 1030 pp->hour += 24 ; 1031 pp->day -- ; 1032 if ( pp->day < 1 ) { 1033 pp->year -- ; 1034 pp->day = ymd2yd( pp->year, 12, 31 ) ; 1035 } 1036 } 1037 1038 /* 1039 * Process the new sample in the median filter and determine the 1040 * timecode timestamp. 1041 */ 1042 1043 if ( ! refclock_process( pp ) ) { 1044 refclock_report( peer, CEVNT_BADTIME ) ; 1045 return ; 1046 } 1047 1048 pp->lastref = pp->lastrec ; 1049 1050 refclock_receive( peer ) ; 1051 1052 /* 1053 * Write into the clockstats file 1054 */ 1055 snprintf ( sLog, sizeof(sLog), 1056 "%04d/%02d/%02d %02d:%02d:%02d.%03d JST ( %04d/%03d %02d:%02d:%02d.%03d UTC )", 1057 up->year, up->month, up->day, 1058 up->hour, up->minute, up->second, up->msecond, 1059 pp->year, pp->day, pp->hour, pp->minute, pp->second, 1060 (int)(pp->nsec/1000000) ) ; 1061 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ATTENTION, sLog ) ; 1062 1063 cStatus = ' ' ; 1064 pStatus = "" ; 1065 1066 switch ( peer->status ) { 1067 case 0 : cStatus = ' ' ; pStatus = "Reject" ; break ; 1068 case 1 : cStatus = 'x' ; pStatus = "FalseTick" ; break ; 1069 case 2 : cStatus = '.' ; pStatus = "Excess" ; break ; 1070 case 3 : cStatus = '-' ; pStatus = "Outlier" ; break ; 1071 case 4 : cStatus = '+' ; pStatus = "Candidate" ; break ; 1072 case 5 : cStatus = '#' ; pStatus = "Selected" ; break ; 1073 case 6 : cStatus = '*' ; pStatus = "Sys.Peer" ; break ; 1074 case 7 : cStatus = 'o' ; pStatus = "PPS.Peer" ; break ; 1075 default : break ; 1076 } 1077 1078 snprintf ( sLog, sizeof(sLog), 1079 "status %d [%c] %s : offset %3.3f mSec. : jitter %3.3f mSec.", 1080 peer->status, cStatus, pStatus, peer->offset * 1000, peer->jitter * 1000 ) ; 1081 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 1082 1083} 1084 1085/*################################################################################################*/ 1086/*################################################################################################*/ 1087/*## ##*/ 1088/*## The Tristate Ltd. JJY receiver TS-JJY01, TS-JJY02 ##*/ 1089/*## ##*/ 1090/*## server 127.127.40.X mode 1 ##*/ 1091/*## ##*/ 1092/*################################################################################################*/ 1093/*################################################################################################*/ 1094/* */ 1095/* Command Response Remarks */ 1096/* -------------------- ---------------------------------------- ---------------------------- */ 1097/* dcst<CR><LF> VALID<CR><LF> or INVALID<CR><LF> */ 1098/* stus<CR><LF> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */ 1099/* date<CR><LF> YYYY/MM/DD XXX<CR><LF> XXX is the day of the week */ 1100/* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */ 1101/* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */ 1102/* */ 1103/*################################################################################################*/ 1104 1105#define TS_JJY01_COMMAND_NUMBER_DATE 1 1106#define TS_JJY01_COMMAND_NUMBER_TIME 2 1107#define TS_JJY01_COMMAND_NUMBER_STIM 3 1108#define TS_JJY01_COMMAND_NUMBER_STUS 4 1109#define TS_JJY01_COMMAND_NUMBER_DCST 5 1110 1111#define TS_JJY01_REPLY_DATE "yyyy/mm/dd www" 1112#define TS_JJY01_REPLY_STIM "hh:mm:ss" 1113#define TS_JJY01_REPLY_STUS_ADJUSTED "adjusted" 1114#define TS_JJY01_REPLY_STUS_UNADJUSTED "unadjusted" 1115#define TS_JJY01_REPLY_DCST_VALID "valid" 1116#define TS_JJY01_REPLY_DCST_INVALID "invalid" 1117 1118#define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */ 1119#define TS_JJY01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */ 1120#define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */ 1121#define TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED 8 /* Length without <CR><LF> */ 1122#define TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED 10 /* Length without <CR><LF> */ 1123#define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */ 1124#define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */ 1125 1126static struct 1127{ 1128 const char commandNumber ; 1129 const char *command ; 1130 int commandLength ; 1131 int iExpectedReplyLength [ 2 ] ; 1132} tristate_jjy01_command_sequence[] = 1133{ 1134 { 0, NULL, 0, { 0, 0 } }, /* Idle */ 1135 { TS_JJY01_COMMAND_NUMBER_DCST, "dcst\r\n", 6, { TS_JJY01_REPLY_LENGTH_DCST_VALID , TS_JJY01_REPLY_LENGTH_DCST_INVALID } }, 1136 { TS_JJY01_COMMAND_NUMBER_STUS, "stus\r\n", 6, { TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED, TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED } }, 1137 { TS_JJY01_COMMAND_NUMBER_TIME, "time\r\n", 6, { TS_JJY01_REPLY_LENGTH_TIME , TS_JJY01_REPLY_LENGTH_TIME } }, 1138 { TS_JJY01_COMMAND_NUMBER_DATE, "date\r\n", 6, { TS_JJY01_REPLY_LENGTH_DATE , TS_JJY01_REPLY_LENGTH_DATE } }, 1139 { TS_JJY01_COMMAND_NUMBER_STIM, "stim\r\n", 6, { TS_JJY01_REPLY_LENGTH_STIM , TS_JJY01_REPLY_LENGTH_STIM } }, 1140 /* End of command */ 1141 { 0, NULL, 0, { 0, 0 } } 1142} ; 1143 1144/**************************************************************************************************/ 1145 1146static int 1147jjy_start_tristate_jjy01 ( int unit, struct peer *peer, struct jjyunit *up ) 1148{ 1149 1150 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-JJY01, TS-JJY02" ) ; 1151 1152 up->unittype = UNITTYPE_TRISTATE_JJY01 ; 1153 up->linespeed = SPEED232_TRISTATE_JJY01 ; 1154 up->linediscipline = LDISC_CLK ; 1155 1156 return 0 ; 1157 1158} 1159 1160/**************************************************************************************************/ 1161 1162static int 1163jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp ) 1164{ 1165 struct jjyunit *up ; 1166 struct refclockproc *pp ; 1167 struct peer *peer; 1168 1169 char * pBuf ; 1170 char sLog [ 192 ] ; 1171 int iLen ; 1172 int rc ; 1173 1174 const char * pCmd ; 1175 int iCmdLen ; 1176 1177 /* Initialize pointers */ 1178 1179 peer = rbufp->recv_peer ; 1180 pp = peer->procptr ; 1181 up = pp->unitptr ; 1182 1183 if ( up->linediscipline == LDISC_RAW ) { 1184 pBuf = up->sTextBuf ; 1185 iLen = up->iTextBufLen ; 1186 } else { 1187 pBuf = pp->a_lastcode ; 1188 iLen = pp->lencode ; 1189 } 1190 1191 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ; 1192 1193 /* Check expected reply */ 1194 1195 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) { 1196 /* Command sequence has not been started, or has been completed */ 1197 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 1198 pBuf ) ; 1199 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1200 up->bLineError = TRUE ; 1201 return JJY_RECEIVE_ERROR ; 1202 } 1203 1204 /* Check reply length */ 1205 1206 if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0] 1207 && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) { 1208 /* Unexpected reply length */ 1209 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1210 iLen ) ; 1211 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1212 up->bLineError = TRUE ; 1213 return JJY_RECEIVE_ERROR ; 1214 } 1215 1216 /* Parse reply */ 1217 1218 switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) { 1219 1220 case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */ 1221 1222 rc = sscanf ( pBuf, "%4d/%2d/%2d", 1223 &up->year, &up->month, &up->day ) ; 1224 1225 if ( rc != 3 || up->year < 2000 || 2099 <= up->year 1226 || up->month < 1 || 12 < up->month 1227 || up->day < 1 || 31 < up->day ) { 1228 /* Invalid date */ 1229 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 1230 rc, up->year, up->month, up->day ) ; 1231 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1232 up->bLineError = TRUE ; 1233 return JJY_RECEIVE_ERROR ; 1234 } 1235 1236 break ; 1237 1238 case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 1239 case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */ 1240 1241 if ( up->iTimestampCount >= 2 ) { 1242 /* Too many time reply */ 1243 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY, 1244 up->iTimestampCount ) ; 1245 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1246 up->bLineError = TRUE ; 1247 return JJY_RECEIVE_ERROR ; 1248 } 1249 1250 rc = sscanf ( pBuf, "%2d:%2d:%2d", 1251 &up->hour, &up->minute, &up->second ) ; 1252 1253 if ( rc != 3 || up->hour > 23 || up->minute > 59 || 1254 up->second > 60 ) { 1255 /* Invalid time */ 1256 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 1257 rc, up->hour, up->minute, up->second ) ; 1258 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1259 up->bLineError = TRUE ; 1260 return JJY_RECEIVE_ERROR ; 1261 } 1262 1263 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 1264 1265 up->iTimestampCount++ ; 1266 1267 up->msecond = 0 ; 1268 1269 break ; 1270 1271 case TS_JJY01_COMMAND_NUMBER_STUS : 1272 1273 if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED, 1274 TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0 1275 || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED, 1276 TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) { 1277 /* Good */ 1278 } else { 1279 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1280 pBuf ) ; 1281 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1282 up->bLineError = TRUE ; 1283 return JJY_RECEIVE_ERROR ; 1284 } 1285 1286 break ; 1287 1288 case TS_JJY01_COMMAND_NUMBER_DCST : 1289 1290 if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID, 1291 TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 1292 || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID, 1293 TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) { 1294 /* Good */ 1295 } else { 1296 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1297 pBuf ) ; 1298 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1299 up->bLineError = TRUE ; 1300 return JJY_RECEIVE_ERROR ; 1301 } 1302 1303 break ; 1304 1305 default : /* Unexpected reply */ 1306 1307 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1308 pBuf ) ; 1309 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1310 up->bLineError = TRUE ; 1311 return JJY_RECEIVE_ERROR ; 1312 1313 } 1314 1315 if ( up->iTimestampCount == 2 ) { 1316 /* Process date and time */ 1317 1318 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0] 1319 && up->iTimestamp[0] <= up->iTimestamp[1] ) { 1320 /* 3 commands (time,date,stim) was excuted in two seconds */ 1321 jjy_synctime( peer, pp, up ) ; 1322 return JJY_RECEIVE_DONE ; 1323 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) { 1324 /* Over midnight, and date is unsure */ 1325 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2, 1326 up->iTimestamp[0], up->iTimestamp[1] ) ; 1327 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 1328 return JJY_RECEIVE_SKIP ; 1329 } else { 1330 /* Slow reply */ 1331 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2, 1332 up->iTimestamp[0], up->iTimestamp[1] ) ; 1333 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1334 up->bLineError = TRUE ; 1335 return JJY_RECEIVE_ERROR ; 1336 } 1337 1338 } 1339 1340 /* Issue next command */ 1341 1342 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) { 1343 up->iCommandSeq ++ ; 1344 } 1345 1346 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) { 1347 /* Command sequence completed */ 1348 return JJY_RECEIVE_DONE ; 1349 } 1350 1351 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ; 1352 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ; 1353 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1354 refclock_report ( peer, CEVNT_FAULT ) ; 1355 } 1356 1357 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 1358 1359 return JJY_RECEIVE_WAIT ; 1360 1361} 1362 1363/**************************************************************************************************/ 1364 1365static void 1366jjy_poll_tristate_jjy01 ( int unit, struct peer *peer ) 1367{ 1368#ifdef DEBUG 1369 static const char *sFunctionName = "jjy_poll_tristate_jjy01" ; 1370#endif 1371 1372 struct refclockproc *pp ; 1373 struct jjyunit *up ; 1374 1375 const char * pCmd ; 1376 int iCmdLen ; 1377 1378 pp = peer->procptr; 1379 up = pp->unitptr ; 1380 1381 up->bLineError = FALSE ; 1382 up->iTimestampCount = 0 ; 1383 1384 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 1385 /* Skip "dcst" and "stus" commands */ 1386 up->iCommandSeq = 2 ; 1387 up->iLineCount = 2 ; 1388 } 1389 1390#ifdef DEBUG 1391 if ( debug ) { 1392 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n", 1393 sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 1394 up->iLineCount ) ; 1395 } 1396#endif 1397 1398 /* 1399 * Send a first command 1400 */ 1401 1402 up->iCommandSeq ++ ; 1403 1404 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ; 1405 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ; 1406 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1407 refclock_report ( peer, CEVNT_FAULT ) ; 1408 } 1409 1410 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 1411 1412} 1413 1414/*################################################################################################*/ 1415/*################################################################################################*/ 1416/*## ##*/ 1417/*## The C-DEX Co. Ltd. JJY receiver JST2000 ##*/ 1418/*## ##*/ 1419/*## server 127.127.40.X mode 2 ##*/ 1420/*## ##*/ 1421/*################################################################################################*/ 1422/*################################################################################################*/ 1423/* */ 1424/* Command Response Remarks */ 1425/* -------------------- ---------------------------------------- ---------------------------- */ 1426/* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> J is a fixed character */ 1427/* */ 1428/*################################################################################################*/ 1429 1430static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] = 1431{ 1432 { "\x03", 1 }, { NULL, 0 } 1433} ; 1434 1435/**************************************************************************************************/ 1436 1437static int 1438jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up ) 1439{ 1440 1441 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ; 1442 1443 up->unittype = UNITTYPE_CDEX_JST2000 ; 1444 up->linespeed = SPEED232_CDEX_JST2000 ; 1445 up->linediscipline = LDISC_RAW ; 1446 1447 up->pRawBreak = cdex_jst2000_raw_break ; 1448 up->bWaitBreakString = TRUE ; 1449 1450 up->bSkipCntrlCharOnly = FALSE ; 1451 1452 return 0 ; 1453 1454} 1455 1456/**************************************************************************************************/ 1457 1458static int 1459jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp ) 1460{ 1461 1462 struct jjyunit *up ; 1463 struct refclockproc *pp ; 1464 struct peer *peer ; 1465 1466 char *pBuf, sLog [ 192 ] ; 1467 int iLen ; 1468 int rc ; 1469 1470 /* Initialize pointers */ 1471 1472 peer = rbufp->recv_peer ; 1473 pp = peer->procptr ; 1474 up = pp->unitptr ; 1475 1476 if ( up->linediscipline == LDISC_RAW ) { 1477 pBuf = up->sTextBuf ; 1478 iLen = up->iTextBufLen ; 1479 } else { 1480 pBuf = pp->a_lastcode ; 1481 iLen = pp->lencode ; 1482 } 1483 1484 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ; 1485 1486 /* Check expected reply */ 1487 1488 if ( up->iCommandSeq != 1 ) { 1489 /* Command sequence has not been started, or has been completed */ 1490 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 1491 pBuf ) ; 1492 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1493 up->bLineError = TRUE ; 1494 return JJY_RECEIVE_ERROR ; 1495 } 1496 1497 /* Wait until ETX comes */ 1498 1499 if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) { 1500 return JJY_RECEIVE_UNPROCESS ; 1501 } 1502 1503 /* Check reply length */ 1504 1505 if ( iLen != 15 ) { 1506 /* Unexpected reply length */ 1507 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1508 iLen ) ; 1509 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1510 up->bLineError = TRUE ; 1511 return JJY_RECEIVE_ERROR ; 1512 } 1513 1514 /* JYYMMDDWHHMMSSS */ 1515 1516 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d", 1517 &up->year, &up->month, &up->day, 1518 &up->hour, &up->minute, &up->second, 1519 &up->msecond ) ; 1520 1521 if ( rc != 7 || up->month < 1 || up->month > 12 || 1522 up->day < 1 || up->day > 31 || up->hour > 23 || 1523 up->minute > 59 || up->second > 60 ) { 1524 /* Invalid date and time */ 1525 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1526 rc, up->year, up->month, up->day, 1527 up->hour, up->minute, up->second ) ; 1528 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1529 up->bLineError = TRUE ; 1530 return JJY_RECEIVE_ERROR ; 1531 } 1532 1533 up->year += 2000 ; 1534 up->msecond *= 100 ; 1535 1536 jjy_synctime( peer, pp, up ) ; 1537 1538 return JJY_RECEIVE_DONE ; 1539 1540} 1541 1542/**************************************************************************************************/ 1543 1544static void 1545jjy_poll_cdex_jst2000 ( int unit, struct peer *peer ) 1546{ 1547 1548 struct refclockproc *pp ; 1549 struct jjyunit *up ; 1550 1551 pp = peer->procptr ; 1552 up = pp->unitptr ; 1553 1554 up->bLineError = FALSE ; 1555 up->iRawBufLen = 0 ; 1556 up->iLineBufLen = 0 ; 1557 up->iTextBufLen = 0 ; 1558 1559 /* 1560 * Send "<ENQ>1J<ETX>" command 1561 */ 1562 1563 up->iCommandSeq ++ ; 1564 1565 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) { 1566 refclock_report ( peer, CEVNT_FAULT ) ; 1567 } 1568 1569 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ; 1570 1571} 1572 1573/*################################################################################################*/ 1574/*################################################################################################*/ 1575/*## ##*/ 1576/*## The Echo Keisokuki Co. Ltd. JJY receiver LT2000 ##*/ 1577/*## ##*/ 1578/*## server 127.127.40.X mode 3 ##*/ 1579/*## ##*/ 1580/*################################################################################################*/ 1581/*################################################################################################*/ 1582/* */ 1583/* Command Response Remarks */ 1584/* -------------------- ---------------------------------------- ---------------------------- */ 1585/* # Mode 1 ( Request & Send ) */ 1586/* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */ 1587/* C Mode 2 ( Continuous ) */ 1588/* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> 0.5 sec before time stamp */ 1589/* <SUB> Second signal */ 1590/* */ 1591/*################################################################################################*/ 1592 1593#define ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1 1594#define ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 2 1595#define ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 3 1596 1597#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND "#" 1598#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME "T" 1599#define ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS "C" 1600 1601/**************************************************************************************************/ 1602 1603static int 1604jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up ) 1605{ 1606 1607 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ; 1608 1609 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ; 1610 up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ; 1611 up->linediscipline = LDISC_CLK ; 1612 1613 up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ; 1614 1615 return 0 ; 1616 1617} 1618 1619/**************************************************************************************************/ 1620 1621static int 1622jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp ) 1623{ 1624 1625 struct jjyunit *up ; 1626 struct refclockproc *pp ; 1627 struct peer *peer; 1628 1629 char *pBuf, sLog [ 100 ], sErr [ 60 ] ; 1630 int iLen ; 1631 int rc ; 1632 int i, ibcc, ibcc1, ibcc2 ; 1633 1634 /* Initialize pointers */ 1635 1636 peer = rbufp->recv_peer ; 1637 pp = peer->procptr ; 1638 up = pp->unitptr ; 1639 1640 if ( up->linediscipline == LDISC_RAW ) { 1641 pBuf = up->sTextBuf ; 1642 iLen = up->iTextBufLen ; 1643 } else { 1644 pBuf = pp->a_lastcode ; 1645 iLen = pp->lencode ; 1646 } 1647 1648 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ; 1649 1650 /* Check reply length */ 1651 1652 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1653 && iLen != 15 ) 1654 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1655 && iLen != 17 ) 1656 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 1657 && iLen != 17 ) ) { 1658 /* Unexpected reply length */ 1659 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1660 iLen ) ; 1661 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1662 up->bLineError = TRUE ; 1663 return JJY_RECEIVE_ERROR ; 1664 } 1665 1666 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) { 1667 /* YYMMDDWHHMMSS<BCC1><BCC2> */ 1668 1669 for ( i = ibcc = 0 ; i < 13 ; i ++ ) { 1670 ibcc ^= pBuf[i] ; 1671 } 1672 1673 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ; 1674 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ; 1675 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) { 1676 snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ", 1677 pBuf[13] & 0xFF, pBuf[14] & 0xFF, 1678 ibcc1, ibcc2 ) ; 1679 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1680 sErr ) ; 1681 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1682 up->bLineError = TRUE ; 1683 return JJY_RECEIVE_ERROR ; 1684 } 1685 1686 } 1687 1688 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1689 && iLen == 15 ) 1690 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1691 && iLen == 17 ) 1692 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 1693 && iLen == 17 ) ) { 1694 /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */ 1695 1696 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d", 1697 &up->year, &up->month, &up->day, 1698 &up->hour, &up->minute, &up->second ) ; 1699 1700 if ( rc != 6 || up->month < 1 || up->month > 12 1701 || up->day < 1 || up->day > 31 1702 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 1703 /* Invalid date and time */ 1704 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1705 rc, up->year, up->month, up->day, 1706 up->hour, up->minute, up->second ) ; 1707 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1708 up->bLineError = TRUE ; 1709 return JJY_RECEIVE_ERROR ; 1710 } 1711 1712 up->year += 2000 ; 1713 1714 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1715 || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) { 1716 /* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */ 1717 1718 up->msecond = 500 ; 1719 up->second -- ; 1720 if ( up->second < 0 ) { 1721 up->second = 59 ; 1722 up->minute -- ; 1723 if ( up->minute < 0 ) { 1724 up->minute = 59 ; 1725 up->hour -- ; 1726 if ( up->hour < 0 ) { 1727 up->hour = 23 ; 1728 up->day -- ; 1729 if ( up->day < 1 ) { 1730 up->month -- ; 1731 if ( up->month < 1 ) { 1732 up->month = 12 ; 1733 up->year -- ; 1734 } 1735 } 1736 } 1737 } 1738 } 1739 1740 } 1741 1742 jjy_synctime( peer, pp, up ) ; 1743 1744 1745 } 1746 1747 if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) { 1748 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */ 1749 1750 iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ; 1751 if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen ) { 1752 refclock_report ( peer, CEVNT_FAULT ) ; 1753 } 1754 1755 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ; 1756 1757 } 1758 1759 return JJY_RECEIVE_DONE ; 1760 1761} 1762 1763/**************************************************************************************************/ 1764 1765static void 1766jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer ) 1767{ 1768 1769 struct refclockproc *pp ; 1770 struct jjyunit *up ; 1771 1772 char sCmd[2] ; 1773 1774 pp = peer->procptr ; 1775 up = pp->unitptr ; 1776 1777 up->bLineError = FALSE ; 1778 1779 /* 1780 * Send "T" or "C" command 1781 */ 1782 1783 switch ( up->operationmode ) { 1784 case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND : 1785 sCmd[0] = 'T' ; 1786 break ; 1787 case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS : 1788 case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS : 1789 sCmd[0] = 'C' ; 1790 break ; 1791 } 1792 sCmd[1] = 0 ; 1793 1794 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) { 1795 refclock_report ( peer, CEVNT_FAULT ) ; 1796 } 1797 1798 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ; 1799 1800} 1801 1802/*################################################################################################*/ 1803/*################################################################################################*/ 1804/*## ##*/ 1805/*## The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 ##*/ 1806/*## ##*/ 1807/*## server 127.127.40.X mode 4 ##*/ 1808/*## ##*/ 1809/*################################################################################################*/ 1810/*################################################################################################*/ 1811/* */ 1812/* Command Response Remarks */ 1813/* -------------------- ---------------------------------------- ---------------------------- */ 1814/* 'XX YY/MM/DD W HH:MM:SS<CR> XX:OK|NG|ER W:0(Mon)-6(Sun) */ 1815/* */ 1816/*################################################################################################*/ 1817 1818static int 1819jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up ) 1820{ 1821 1822 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ; 1823 1824 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ; 1825 up->linespeed = SPEED232_CITIZENTIC_JJY200 ; 1826 up->linediscipline = LDISC_CLK ; 1827 1828 return 0 ; 1829 1830} 1831 1832/**************************************************************************************************/ 1833 1834static int 1835jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp ) 1836{ 1837 1838 struct jjyunit *up ; 1839 struct refclockproc *pp ; 1840 struct peer *peer; 1841 1842 char *pBuf, sLog [ 100 ], sMsg [ 16 ] ; 1843 int iLen ; 1844 int rc ; 1845 char cApostrophe, sStatus[3] ; 1846 int iWeekday ; 1847 1848 /* Initialize pointers */ 1849 1850 peer = rbufp->recv_peer ; 1851 pp = peer->procptr ; 1852 up = pp->unitptr ; 1853 1854 if ( up->linediscipline == LDISC_RAW ) { 1855 pBuf = up->sTextBuf ; 1856 iLen = up->iTextBufLen ; 1857 } else { 1858 pBuf = pp->a_lastcode ; 1859 iLen = pp->lencode ; 1860 } 1861 1862 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ; 1863 1864 /* 1865 * JJY-200 sends a timestamp every second. 1866 * So, a timestamp is ignored unless it is right after polled. 1867 */ 1868 1869 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) { 1870 return JJY_RECEIVE_SKIP ; 1871 } 1872 1873 /* Check reply length */ 1874 1875 if ( iLen != 23 ) { 1876 /* Unexpected reply length */ 1877 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1878 iLen ) ; 1879 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1880 up->bLineError = TRUE ; 1881 return JJY_RECEIVE_ERROR ; 1882 } 1883 1884 /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 1885 1886 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d", 1887 &cApostrophe, sStatus, 1888 &up->year, &up->month, &up->day, &iWeekday, 1889 &up->hour, &up->minute, &up->second ) ; 1890 sStatus[2] = 0 ; 1891 1892 if ( rc != 9 || cApostrophe != '\'' 1893 || ( strcmp( sStatus, "OK" ) != 0 1894 && strcmp( sStatus, "NG" ) != 0 1895 && strcmp( sStatus, "ER" ) != 0 ) 1896 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 1897 || iWeekday > 6 1898 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 1899 /* Invalid date and time */ 1900 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1901 rc, up->year, up->month, up->day, 1902 up->hour, up->minute, up->second ) ; 1903 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1904 up->bLineError = TRUE ; 1905 return JJY_RECEIVE_ERROR ; 1906 } else if ( strcmp( sStatus, "NG" ) == 0 1907 || strcmp( sStatus, "ER" ) == 0 ) { 1908 /* Timestamp is unsure */ 1909 snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ; 1910 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE, 1911 sMsg ) ; 1912 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 1913 return JJY_RECEIVE_SKIP ; 1914 } 1915 1916 up->year += 2000 ; 1917 up->msecond = 0 ; 1918 1919 jjy_synctime( peer, pp, up ) ; 1920 1921 return JJY_RECEIVE_DONE ; 1922 1923} 1924 1925/**************************************************************************************************/ 1926 1927static void 1928jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer ) 1929{ 1930 1931 struct refclockproc *pp ; 1932 struct jjyunit *up ; 1933 1934 pp = peer->procptr ; 1935 up = pp->unitptr ; 1936 1937 up->bLineError = FALSE ; 1938 1939} 1940 1941/*################################################################################################*/ 1942/*################################################################################################*/ 1943/*## ##*/ 1944/*## The Tristate Ltd. GPS clock TS-GPS01 ##*/ 1945/*## ##*/ 1946/*## server 127.127.40.X mode 5 ##*/ 1947/*## ##*/ 1948/*################################################################################################*/ 1949/*################################################################################################*/ 1950/* */ 1951/* This clock has NMEA mode and command/respose mode. */ 1952/* When this jjy driver are used, set to command/respose mode of this clock */ 1953/* by the onboard switch SW4, and make sure the LED-Y is tured on. */ 1954/* Other than this JJY driver, the refclock driver type 20, generic NMEA driver, */ 1955/* works with the NMEA mode of this clock. */ 1956/* */ 1957/* Command Response Remarks */ 1958/* -------------------- ---------------------------------------- ---------------------------- */ 1959/* stus<CR><LF> *R|*G|*U|+U<CR><LF> */ 1960/* date<CR><LF> YY/MM/DD<CR><LF> */ 1961/* time<CR><LF> HH:MM:SS<CR><LF> */ 1962/* */ 1963/*################################################################################################*/ 1964 1965#define TS_GPS01_COMMAND_NUMBER_DATE 1 1966#define TS_GPS01_COMMAND_NUMBER_TIME 2 1967#define TS_GPS01_COMMAND_NUMBER_STUS 4 1968 1969#define TS_GPS01_REPLY_DATE "yyyy/mm/dd" 1970#define TS_GPS01_REPLY_TIME "hh:mm:ss" 1971#define TS_GPS01_REPLY_STUS_RTC "*R" 1972#define TS_GPS01_REPLY_STUS_GPS "*G" 1973#define TS_GPS01_REPLY_STUS_UTC "*U" 1974#define TS_GPS01_REPLY_STUS_PPS "+U" 1975 1976#define TS_GPS01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */ 1977#define TS_GPS01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */ 1978#define TS_GPS01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */ 1979 1980static struct 1981{ 1982 char commandNumber ; 1983 const char *command ; 1984 int commandLength ; 1985 int iExpectedReplyLength ; 1986} tristate_gps01_command_sequence[] = 1987{ 1988 { 0, NULL, 0, 0 }, /* Idle */ 1989 { TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS }, 1990 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME }, 1991 { TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE }, 1992 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME }, 1993 /* End of command */ 1994 { 0, NULL, 0, 0 } 1995} ; 1996 1997/**************************************************************************************************/ 1998 1999static int 2000jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up ) 2001{ 2002 2003 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ; 2004 2005 up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ; 2006 up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ; 2007 up->linediscipline = LDISC_CLK ; 2008 2009 return 0 ; 2010 2011} 2012 2013/**************************************************************************************************/ 2014 2015static int 2016jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp ) 2017{ 2018#ifdef DEBUG 2019 static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ; 2020#endif 2021 2022 struct jjyunit *up ; 2023 struct refclockproc *pp ; 2024 struct peer *peer; 2025 2026 char * pBuf ; 2027 char sLog [ 100 ] ; 2028 int iLen ; 2029 int rc ; 2030 2031 const char * pCmd ; 2032 int iCmdLen ; 2033 2034 /* Initialize pointers */ 2035 2036 peer = rbufp->recv_peer ; 2037 pp = peer->procptr ; 2038 up = pp->unitptr ; 2039 2040 if ( up->linediscipline == LDISC_RAW ) { 2041 pBuf = up->sTextBuf ; 2042 iLen = up->iTextBufLen ; 2043 } else { 2044 pBuf = pp->a_lastcode ; 2045 iLen = pp->lencode ; 2046 } 2047 2048 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ; 2049 2050 /* Ignore NMEA data stream */ 2051 2052 if ( iLen > 5 2053 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 2054#ifdef DEBUG 2055 if ( debug ) { 2056 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 2057 sFunctionName, pBuf ) ; 2058 } 2059#endif 2060 return JJY_RECEIVE_WAIT ; 2061 } 2062 2063 /* 2064 * Skip command prompt '$Cmd>' from the TS-GPSclock-01 2065 */ 2066 if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 2067 return JJY_RECEIVE_WAIT ; 2068 } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 2069 pBuf += 5 ; 2070 iLen -= 5 ; 2071 } 2072 2073 /* 2074 * Ignore NMEA data stream after command prompt 2075 */ 2076 if ( iLen > 5 2077 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 2078#ifdef DEBUG 2079 if ( debug ) { 2080 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 2081 sFunctionName, pBuf ) ; 2082 } 2083#endif 2084 return JJY_RECEIVE_WAIT ; 2085 } 2086 2087 /* Check expected reply */ 2088 2089 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2090 /* Command sequence has not been started, or has been completed */ 2091 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 2092 pBuf ) ; 2093 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2094 up->bLineError = TRUE ; 2095 return JJY_RECEIVE_ERROR ; 2096 } 2097 2098 /* Check reply length */ 2099 2100 if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) { 2101 /* Unexpected reply length */ 2102 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 2103 iLen ) ; 2104 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2105 up->bLineError = TRUE ; 2106 return JJY_RECEIVE_ERROR ; 2107 } 2108 2109 /* Parse reply */ 2110 2111 switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) { 2112 2113 case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */ 2114 2115 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ; 2116 2117 if ( rc != 3 || up->year < 2000 || 2099 <= up->year 2118 || up->month < 1 || 12 < up->month 2119 || up->day < 1 || 31 < up->day ) { 2120 /* Invalid date */ 2121 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 2122 rc, up->year, up->month, up->day ) ; 2123 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2124 up->bLineError = TRUE ; 2125 return JJY_RECEIVE_ERROR ; 2126 } 2127 2128 break ; 2129 2130 case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 2131 2132 if ( up->iTimestampCount >= 2 ) { 2133 /* Too many time reply */ 2134 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY, 2135 up->iTimestampCount ) ; 2136 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2137 up->bLineError = TRUE ; 2138 return JJY_RECEIVE_ERROR ; 2139 } 2140 2141 rc = sscanf ( pBuf, "%2d:%2d:%2d", 2142 &up->hour, &up->minute, &up->second ) ; 2143 2144 if ( rc != 3 2145 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2146 /* Invalid time */ 2147 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 2148 rc, up->hour, up->minute, up->second ) ; 2149 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2150 up->bLineError = TRUE ; 2151 return JJY_RECEIVE_ERROR ; 2152 } 2153 2154 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 2155 2156 up->iTimestampCount++ ; 2157 2158 up->msecond = 0 ; 2159 2160 break ; 2161 2162 case TS_GPS01_COMMAND_NUMBER_STUS : 2163 2164 if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2165 || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2166 || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2167 || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) { 2168 /* Good */ 2169 } else { 2170 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2171 pBuf ) ; 2172 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2173 up->bLineError = TRUE ; 2174 return JJY_RECEIVE_ERROR ; 2175 } 2176 2177 break ; 2178 2179 default : /* Unexpected reply */ 2180 2181 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2182 pBuf ) ; 2183 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2184 up->bLineError = TRUE ; 2185 return JJY_RECEIVE_ERROR ; 2186 2187 } 2188 2189 if ( up->iTimestampCount == 2 ) { 2190 /* Process date and time */ 2191 2192 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0] 2193 && up->iTimestamp[0] <= up->iTimestamp[1] ) { 2194 /* 3 commands (time,date,stim) was excuted in two seconds */ 2195 jjy_synctime( peer, pp, up ) ; 2196 return JJY_RECEIVE_DONE ; 2197 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) { 2198 /* Over midnight, and date is unsure */ 2199 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2, 2200 up->iTimestamp[0], up->iTimestamp[1] ) ; 2201 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 2202 return JJY_RECEIVE_SKIP ; 2203 } else { 2204 /* Slow reply */ 2205 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2, 2206 up->iTimestamp[0], up->iTimestamp[1] ) ; 2207 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2208 up->bLineError = TRUE ; 2209 return JJY_RECEIVE_ERROR ; 2210 } 2211 2212 } 2213 2214 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2215 /* Command sequence completed */ 2216 jjy_synctime( peer, pp, up ) ; 2217 return JJY_RECEIVE_DONE ; 2218 } 2219 2220 /* Issue next command */ 2221 2222 if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) { 2223 up->iCommandSeq ++ ; 2224 } 2225 2226 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2227 /* Command sequence completed */ 2228 up->iProcessState = JJY_PROCESS_STATE_DONE ; 2229 return JJY_RECEIVE_DONE ; 2230 } 2231 2232 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ; 2233 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ; 2234 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 2235 refclock_report ( peer, CEVNT_FAULT ) ; 2236 } 2237 2238 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 2239 2240 return JJY_RECEIVE_WAIT ; 2241 2242} 2243 2244/**************************************************************************************************/ 2245 2246static void 2247jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer ) 2248{ 2249#ifdef DEBUG 2250 static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ; 2251#endif 2252 2253 struct refclockproc *pp ; 2254 struct jjyunit *up ; 2255 2256 const char * pCmd ; 2257 int iCmdLen ; 2258 2259 pp = peer->procptr ; 2260 up = pp->unitptr ; 2261 2262 up->iTimestampCount = 0 ; 2263 2264 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 2265 /* Skip "stus" command */ 2266 up->iCommandSeq = 1 ; 2267 up->iLineCount = 1 ; 2268 } 2269 2270#ifdef DEBUG 2271 if ( debug ) { 2272 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n", 2273 sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 2274 up->iLineCount ) ; 2275 } 2276#endif 2277 2278 /* 2279 * Send a first command 2280 */ 2281 2282 up->iCommandSeq ++ ; 2283 2284 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ; 2285 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ; 2286 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 2287 refclock_report ( peer, CEVNT_FAULT ) ; 2288 } 2289 2290 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 2291 2292} 2293 2294/*################################################################################################*/ 2295/*################################################################################################*/ 2296/*## ##*/ 2297/*## The SEIKO TIME SYSTEMS TDC-300 ##*/ 2298/*## ##*/ 2299/*## server 127.127.40.X mode 6 ##*/ 2300/*## ##*/ 2301/*################################################################################################*/ 2302/*################################################################################################*/ 2303/* */ 2304/* Type Response Remarks */ 2305/* -------------------- ---------------------------------------- ---------------------------- */ 2306/* Type 1 <STX>HH:MM:SS<ETX> */ 2307/* Type 2 <STX>YYMMDDHHMMSSWLSCU<ETX> W:0(Sun)-6(Sat) */ 2308/* Type 3 <STX>YYMMDDWHHMMSS<ETX> W:0(Sun)-6(Sat) */ 2309/* <STX><xE5><ETX> 5 to 10 mSec. before second */ 2310/* */ 2311/*################################################################################################*/ 2312 2313static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] = 2314{ 2315 { "\x03", 1 }, { NULL, 0 } 2316} ; 2317 2318/**************************************************************************************************/ 2319 2320static int 2321jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up ) 2322{ 2323 2324 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ; 2325 2326 up->unittype = UNITTYPE_SEIKO_TIMESYS_TDC_300 ; 2327 up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ; 2328 up->linediscipline = LDISC_RAW ; 2329 2330 up->pRawBreak = seiko_tsys_tdc_300_raw_break ; 2331 up->bWaitBreakString = TRUE ; 2332 2333 up->bSkipCntrlCharOnly = FALSE ; 2334 2335 return 0 ; 2336 2337} 2338 2339/**************************************************************************************************/ 2340 2341static int 2342jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp ) 2343{ 2344 2345 struct peer *peer; 2346 struct refclockproc *pp ; 2347 struct jjyunit *up ; 2348 2349 char *pBuf, sLog [ 192 ] ; 2350 int iLen, i ; 2351 int rc, iWeekday ; 2352 time_t now ; 2353 struct tm *pTime ; 2354 2355 /* Initialize pointers */ 2356 2357 peer = rbufp->recv_peer ; 2358 pp = peer->procptr ; 2359 up = pp->unitptr ; 2360 2361 if ( up->linediscipline == LDISC_RAW ) { 2362 pBuf = up->sTextBuf ; 2363 iLen = up->iTextBufLen ; 2364 } else { 2365 pBuf = pp->a_lastcode ; 2366 iLen = pp->lencode ; 2367 } 2368 2369 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ; 2370 2371 /* 2372 * TDC-300 sends a timestamp every second. 2373 * So, a timestamp is ignored unless it is right after polled. 2374 */ 2375 2376 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) { 2377 return JJY_RECEIVE_SKIP ; 2378 } 2379 2380 /* Process timestamp */ 2381 2382 up->iReceiveSeq ++ ; 2383 2384 switch ( iLen ) { 2385 2386 case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */ 2387 2388 for ( i = 0 ; i < iLen ; i ++ ) { 2389 pBuf[i] &= 0x7F ; 2390 } 2391 2392 rc = sscanf ( pBuf+1, "%2d:%2d:%2d", 2393 &up->hour, &up->minute, &up->second ) ; 2394 2395 if ( rc != 3 2396 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2397 /* Invalid time */ 2398 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 2399 rc, up->hour, up->minute, up->second ) ; 2400 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2401 up->bLineError = TRUE ; 2402 return JJY_RECEIVE_ERROR ; 2403 } else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) { 2404 /* Uncertainty date guard */ 2405 return JJY_RECEIVE_WAIT ; 2406 } 2407 2408 time( &now ) ; 2409 pTime = localtime( &now ) ; 2410 up->year = pTime->tm_year ; 2411 up->month = pTime->tm_mon + 1 ; 2412 up->day = pTime->tm_mday ; 2413 2414 break ; 2415 2416 case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */ 2417 2418 for ( i = 0 ; i < iLen ; i ++ ) { 2419 pBuf[i] &= 0x7F ; 2420 } 2421 2422 rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d", 2423 &up->year, &up->month, &up->day, 2424 &up->hour, &up->minute, &up->second, &iWeekday ) ; 2425 2426 if ( rc != 7 2427 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 2428 || iWeekday > 6 2429 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2430 /* Invalid date and time */ 2431 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 2432 rc, up->year, up->month, up->day, 2433 up->hour, up->minute, up->second ) ; 2434 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2435 up->bLineError = TRUE ; 2436 return JJY_RECEIVE_ERROR ; 2437 } 2438 2439 break ; 2440 2441 case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */ 2442 2443 rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d", 2444 &up->year, &up->month, &up->day, &iWeekday, 2445 &up->hour, &up->minute, &up->second ) ; 2446 2447 if ( rc != 7 2448 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 2449 || iWeekday > 6 2450 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2451 /* Invalid date and time */ 2452 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 2453 rc, up->year, up->month, up->day, 2454 up->hour, up->minute, up->second ) ; 2455 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2456 up->bLineError = TRUE ; 2457 return JJY_RECEIVE_ERROR ; 2458 } 2459 2460 return JJY_RECEIVE_WAIT ; 2461 2462 case 1 : /* Type 3 : <STX><xE5><ETX> */ 2463 2464 if ( ( *pBuf & 0xFF ) != 0xE5 ) { 2465 /* Invalid second signal */ 2466 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2467 up->sLineBuf ) ; 2468 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2469 up->bLineError = TRUE ; 2470 return JJY_RECEIVE_ERROR ; 2471 } else if ( up->iReceiveSeq == 1 ) { 2472 /* Wait for next timestamp */ 2473 up->iReceiveSeq -- ; 2474 return JJY_RECEIVE_WAIT ; 2475 } else if ( up->iReceiveSeq >= 3 ) { 2476 /* Unexpected second signal */ 2477 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 2478 up->sLineBuf ) ; 2479 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2480 up->bLineError = TRUE ; 2481 return JJY_RECEIVE_ERROR ; 2482 } 2483 2484 break ; 2485 2486 default : /* Unexpected reply length */ 2487 2488 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 2489 iLen ) ; 2490 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2491 up->bLineError = TRUE ; 2492 return JJY_RECEIVE_ERROR ; 2493 2494 } 2495 2496 up->year += 2000 ; 2497 up->msecond = 0 ; 2498 2499 jjy_synctime( peer, pp, up ) ; 2500 2501 return JJY_RECEIVE_DONE ; 2502 2503} 2504 2505/**************************************************************************************************/ 2506 2507static void 2508jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer ) 2509{ 2510 2511 struct refclockproc *pp ; 2512 struct jjyunit *up ; 2513 2514 pp = peer->procptr ; 2515 up = pp->unitptr ; 2516 2517 up->bLineError = FALSE ; 2518 2519} 2520 2521/*################################################################################################*/ 2522/*################################################################################################*/ 2523/*## ##*/ 2524/*## Telephone JJY ##*/ 2525/*## ##*/ 2526/*## server 127.127.40.X mode 100 to 180 ##*/ 2527/*## ##*/ 2528/*################################################################################################*/ 2529/*################################################################################################*/ 2530/* */ 2531/* Prompt Command Response Remarks */ 2532/* -------------------- -------------------- -------------------- -------------------------- */ 2533/* Name<SP>?<SP> TJJY<CR> Welcome messages TJJY is a guest user ID */ 2534/* > 4DATE<CR> YYYYMMDD<CR> */ 2535/* > LEAPSEC<CR> XX<CR> One of <SP>0, +1, -1 */ 2536/* > TIME<CR> HHMMSS<CR> 3 times on second */ 2537/* > BYE<CR> Sayounara messages */ 2538/* */ 2539/*################################################################################################*/ 2540 2541static struct jjyRawDataBreak teljjy_raw_break [ ] = 2542{ 2543 { "\r\n", 2 }, 2544 { "\r" , 1 }, 2545 { "\n" , 1 }, 2546 { "Name ? ", 7 }, 2547 { ">" , 1 }, 2548 { "+++" , 3 }, 2549 { NULL , 0 } 2550} ; 2551 2552#define TELJJY_STATE_IDLE 0 2553#define TELJJY_STATE_DAILOUT 1 2554#define TELJJY_STATE_LOGIN 2 2555#define TELJJY_STATE_CONNECT 3 2556#define TELJJY_STATE_BYE 4 2557 2558#define TELJJY_EVENT_NULL 0 2559#define TELJJY_EVENT_START 1 2560#define TELJJY_EVENT_CONNECT 2 2561#define TELJJY_EVENT_DISCONNECT 3 2562#define TELJJY_EVENT_COMMAND 4 2563#define TELJJY_EVENT_LOGIN 5 /* Posted by the jjy_receive_telephone */ 2564#define TELJJY_EVENT_PROMPT 6 /* Posted by the jjy_receive_telephone */ 2565#define TELJJY_EVENT_DATA 7 /* Posted by the jjy_receive_telephone */ 2566#define TELJJY_EVENT_ERROR 8 /* Posted by the jjy_receive_telephone */ 2567#define TELJJY_EVENT_SILENT 9 /* Posted by the jjy_timer_telephone */ 2568#define TELJJY_EVENT_TIMEOUT 10 /* Posted by the jjy_timer_telephone */ 2569 2570static void teljjy_control ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2571 2572static int teljjy_idle_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2573static int teljjy_idle_dialout ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2574static int teljjy_dial_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2575static int teljjy_dial_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2576static int teljjy_dial_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2577static int teljjy_login_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2578static int teljjy_login_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2579static int teljjy_login_conn ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2580static int teljjy_login_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2581static int teljjy_login_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2582static int teljjy_login_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2583static int teljjy_conn_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2584static int teljjy_conn_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2585static int teljjy_conn_send ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2586static int teljjy_conn_data ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2587static int teljjy_conn_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2588static int teljjy_conn_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2589static int teljjy_bye_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2590static int teljjy_bye_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2591static int teljjy_bye_modem ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2592 2593static int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) = 2594{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2595/* NULL */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2596/* START */ { teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2597/* CONNECT */ { teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2598/* DISCONNECT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_disc , teljjy_conn_disc , teljjy_bye_disc }, 2599/* COMMAND */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem }, 2600/* LOGIN */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore }, 2601/* PROMPT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn , teljjy_conn_send , teljjy_bye_ignore }, 2602/* DATA */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data , teljjy_bye_ignore }, 2603/* ERROR */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore }, 2604/* SILENT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore }, 2605/* TIMEOUT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem } 2606} ; 2607 2608static short iTeljjyNextState [ ] [ 5 ] = 2609{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2610/* NULL */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2611/* START */ { TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2612/* CONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_LOGIN , TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2613/* DISCONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE }, 2614/* COMMAND */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2615/* LOGIN */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2616/* PROMPT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2617/* DATA */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2618/* ERROR */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2619/* SILENT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2620/* TIMEOUT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE } 2621} ; 2622 2623static short iTeljjyPostEvent [ ] [ 5 ] = 2624{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2625/* NULL */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2626/* START */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2627/* CONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2628/* DISCONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2629/* COMMAND */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2630/* LOGIN */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2631/* PROMPT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2632/* DATA */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2633/* ERROR */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2634/* SILENT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2635/* TIMEOUT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL } 2636} ; 2637 2638static short iTeljjySilentTimeout [ 5 ] = { 0, 0, 10, 5, 0 } ; 2639static short iTeljjyStateTimeout [ 5 ] = { 0, 120, 60, 60, 40 } ; 2640 2641#define TELJJY_STAY_CLOCK_STATE 0 2642#define TELJJY_CHANGE_CLOCK_STATE 1 2643 2644/* Command and replay */ 2645 2646#define TELJJY_REPLY_NONE 0 2647#define TELJJY_REPLY_4DATE 1 2648#define TELJJY_REPLY_TIME 2 2649#define TELJJY_REPLY_LEAPSEC 3 2650#define TELJJY_REPLY_LOOP 4 2651#define TELJJY_REPLY_PROMPT 5 2652#define TELJJY_REPLY_LOOPBACK 6 2653#define TELJJY_REPLY_COM 7 2654 2655#define TELJJY_COMMAND_START_SKIP_LOOPBACK 7 2656 2657static struct 2658{ 2659 const char *command ; 2660 int commandLength ; 2661 int iEchobackReplyLength ; 2662 int iExpectedReplyType ; 2663 int iExpectedReplyLength ; 2664} teljjy_command_sequence[] = 2665{ 2666 { NULL, 0, 0, 0, 0 }, /* Idle */ 2667 { "LOOP\r" , 5, 4, TELJJY_REPLY_LOOP , 0 }, /* Getting into loopback mode */ 2668 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2669 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2670 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2671 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2672 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2673 { "COM\r" , 4, 3, TELJJY_REPLY_COM , 0 }, /* Exit from loopback mode */ 2674 /* TELJJY_COMMAND_START_SKIP_LOOPBACK */ 2675 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 }, 2676 { "4DATE\r" , 6, 5, TELJJY_REPLY_4DATE , 8 }, 2677 { "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 }, 2678 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 }, 2679 { "BYE\r" , 4, 3, TELJJY_REPLY_NONE , 0 }, 2680 /* End of command */ 2681 { NULL, 0, 0, 0, 0 } 2682} ; 2683 2684#define TELJJY_LOOPBACK_DELAY_THRESHOLD 700 /* Milli second */ 2685 2686#ifdef DEBUG 2687#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 ) ; } } 2688#else 2689#define DEBUG_TELJJY_PRINTF(sFunc) 2690#endif 2691 2692/**************************************************************************************************/ 2693 2694static int 2695jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up ) 2696{ 2697 2698 char sLog [ 192 ], sFirstThreeDigits [ 4 ] ; 2699 int iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ; 2700 size_t i ; 2701 size_t iFirstThreeDigitsCount ; 2702 2703 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ; 2704 2705 up->unittype = UNITTYPE_TELEPHONE ; 2706 up->linespeed = SPEED232_TELEPHONE ; 2707 up->linediscipline = LDISC_RAW ; 2708 2709 up->pRawBreak = teljjy_raw_break ; 2710 up->bWaitBreakString = TRUE ; 2711 2712 up->bSkipCntrlCharOnly = TRUE ; 2713 2714 up->iClockState = TELJJY_STATE_IDLE ; 2715 up->iClockEvent = TELJJY_EVENT_NULL ; 2716 2717 /* Check the telephone number */ 2718 2719 if ( sys_phone[0] == NULL ) { 2720 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ; 2721 up->bInitError = TRUE ; 2722 return 1 ; 2723 } 2724 2725 if ( sys_phone[1] != NULL ) { 2726 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ; 2727 up->bInitError = TRUE ; 2728 return 1 ; 2729 } 2730 2731 iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ; 2732 for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) { 2733 if ( isdigit( (u_char)sys_phone[0][i] ) ) { 2734 if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) { 2735 sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ; 2736 } 2737 iNumberOfDigitsOfPhoneNumber ++ ; 2738 } else if ( sys_phone[0][i] == ',' ) { 2739 iCommaCount ++ ; 2740 if ( iCommaCount > 1 ) { 2741 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ; 2742 up->bInitError = TRUE ; 2743 return 1 ; 2744 } 2745 iFirstThreeDigitsCount = 0 ; 2746 iCommaPosition = i ; 2747 } else if ( sys_phone[0][i] != '-' ) { 2748 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ; 2749 up->bInitError = TRUE ; 2750 return 1 ; 2751 } 2752 } 2753 sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ; 2754 2755 if ( iCommaCount == 1 ) { 2756 if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) { 2757 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ; 2758 up->bInitError = TRUE ; 2759 return 1 ; 2760 } 2761 } 2762 2763 if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) { 2764 /* Too short or too long */ 2765 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ; 2766 up->bInitError = TRUE ; 2767 return 1 ; 2768 } 2769 2770 if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0 2771 || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0 2772 || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0 2773 || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0 2774 || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0 2775 || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0 2776 || ( sFirstThreeDigits[0] == '0' && sFirstThreeDigits[2] == '0' ) ) { 2777 /* Not allowed because of emergency numbers or special service numbers */ 2778 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ; 2779 up->bInitError = TRUE ; 2780 return 1 ; 2781 } 2782 2783 snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ; 2784 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 2785 2786 if ( peer->minpoll < 8 ) { 2787 /* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */ 2788 int oldminpoll = peer->minpoll ; 2789 peer->minpoll = 8 ; 2790 if ( peer->ppoll < peer->minpoll ) { 2791 peer->ppoll = peer->minpoll ; 2792 } 2793 if ( peer->maxpoll < peer->minpoll ) { 2794 peer->maxpoll = peer->minpoll ; 2795 } 2796 snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ; 2797 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 2798 } 2799 2800 return 0 ; 2801 2802} 2803 2804/**************************************************************************************************/ 2805 2806static int 2807jjy_receive_telephone ( struct recvbuf *rbufp ) 2808{ 2809#ifdef DEBUG 2810 static const char *sFunctionName = "jjy_receive_telephone" ; 2811#endif 2812 2813 struct peer *peer; 2814 struct refclockproc *pp ; 2815 struct jjyunit *up ; 2816 char *pBuf ; 2817 int iLen ; 2818 short iPreviousModemState ; 2819 2820 peer = rbufp->recv_peer ; 2821 pp = peer->procptr ; 2822 up = pp->unitptr ; 2823 2824 DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2825 2826 if ( up->iClockState == TELJJY_STATE_IDLE 2827 || up->iClockState == TELJJY_STATE_DAILOUT 2828 || up->iClockState == TELJJY_STATE_BYE ) { 2829 2830 iPreviousModemState = getModemState( up ) ; 2831 2832 modem_receive ( rbufp ) ; 2833 2834 if ( iPreviousModemState != up->iModemState ) { 2835 /* Modem state is changed just now. */ 2836 if ( isModemStateDisconnect( up->iModemState ) ) { 2837 up->iClockEvent = TELJJY_EVENT_DISCONNECT ; 2838 teljjy_control ( peer, pp, up ) ; 2839 } else if ( isModemStateConnect( up->iModemState ) ) { 2840 up->iClockEvent = TELJJY_EVENT_CONNECT ; 2841 teljjy_control ( peer, pp, up ) ; 2842 } 2843 } 2844 2845 return JJY_RECEIVE_WAIT ; 2846 2847 } 2848 2849 if ( up->linediscipline == LDISC_RAW ) { 2850 pBuf = up->sTextBuf ; 2851 iLen = up->iTextBufLen ; 2852 } else { 2853 pBuf = pp->a_lastcode ; 2854 iLen = pp->lencode ; 2855 } 2856 2857 up->iTeljjySilentTimer = 0 ; 2858 if ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN ; } 2859 else if ( iLen == 1 && strncmp( pBuf, ">" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; } 2860 else if ( iLen >= 1 && strncmp( pBuf, "?" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR ; } 2861 else { up->iClockEvent = TELJJY_EVENT_DATA ; } 2862 2863 teljjy_control ( peer, pp, up ) ; 2864 2865 return JJY_RECEIVE_WAIT ; 2866 2867} 2868 2869/**************************************************************************************************/ 2870 2871static void 2872jjy_poll_telephone ( int unit, struct peer *peer ) 2873{ 2874#ifdef DEBUG 2875 static const char *sFunctionName = "jjy_poll_telephone" ; 2876#endif 2877 2878 struct refclockproc *pp ; 2879 struct jjyunit *up ; 2880 2881 pp = peer->procptr ; 2882 up = pp->unitptr ; 2883 2884 DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2885 2886 if ( up->iClockState == TELJJY_STATE_IDLE ) { 2887 up->iRawBufLen = 0 ; 2888 up->iLineBufLen = 0 ; 2889 up->iTextBufLen = 0 ; 2890 } 2891 2892 up->iClockEvent = TELJJY_EVENT_START ; 2893 teljjy_control ( peer, pp, up ) ; 2894 2895} 2896 2897/**************************************************************************************************/ 2898 2899static void 2900jjy_timer_telephone ( int unit, struct peer *peer ) 2901{ 2902#ifdef DEBUG 2903 static const char *sFunctionName = "jjy_timer_telephone" ; 2904#endif 2905 2906 struct refclockproc *pp ; 2907 struct jjyunit *up ; 2908 short iPreviousModemState ; 2909 2910 pp = peer->procptr ; 2911 up = pp->unitptr ; 2912 2913 DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2914 2915 if ( iTeljjySilentTimeout[up->iClockState] != 0 ) { 2916 up->iTeljjySilentTimer++ ; 2917 if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) { 2918 up->iClockEvent = TELJJY_EVENT_SILENT ; 2919 teljjy_control ( peer, pp, up ) ; 2920 } 2921 } 2922 2923 if ( iTeljjyStateTimeout[up->iClockState] != 0 ) { 2924 up->iTeljjyStateTimer++ ; 2925 if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) { 2926 up->iClockEvent = TELJJY_EVENT_TIMEOUT ; 2927 teljjy_control ( peer, pp, up ) ; 2928 } 2929 } 2930 2931 if ( isModemStateTimerOn( up ) ) { 2932 2933 iPreviousModemState = getModemState( up ) ; 2934 2935 modem_timer ( unit, peer ) ; 2936 2937 if ( iPreviousModemState != up->iModemState ) { 2938 /* Modem state is changed just now. */ 2939 if ( isModemStateDisconnect( up->iModemState ) ) { 2940 up->iClockEvent = TELJJY_EVENT_DISCONNECT ; 2941 teljjy_control ( peer, pp, up ) ; 2942 } else if ( isModemStateConnect( up->iModemState ) ) { 2943 up->iClockEvent = TELJJY_EVENT_CONNECT ; 2944 teljjy_control ( peer, pp, up ) ; 2945 } 2946 } 2947 2948 } 2949 2950} 2951 2952/**************************************************************************************************/ 2953 2954static void 2955teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 2956{ 2957 2958 int i, rc ; 2959 short iPostEvent = TELJJY_EVENT_NULL ; 2960 2961 DEBUG_TELJJY_PRINTF( "teljjy_control" ) ; 2962 2963 rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ; 2964 2965 if ( rc == TELJJY_CHANGE_CLOCK_STATE ) { 2966 iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ; 2967#ifdef DEBUG 2968 if ( debug ) { 2969 printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd iPostEvent=%hd\n", 2970 up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ; 2971 } 2972#endif 2973 up->iTeljjySilentTimer = 0 ; 2974 if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) { 2975 /* Telephone JJY state is changing now */ 2976 up->iTeljjyStateTimer = 0 ; 2977 up->bLineError = FALSE ; 2978 up->iClockCommandSeq = 0 ; 2979 up->iTimestampCount = 0 ; 2980 up->iLoopbackCount = 0 ; 2981 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 2982 up->bLoopbackTimeout[i] = FALSE ; 2983 } 2984 if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) { 2985 /* Telephone JJY state is changing to IDLE just now */ 2986 up->iProcessState = JJY_PROCESS_STATE_DONE ; 2987 } 2988 } 2989 up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ; 2990 2991 } 2992 2993 if ( iPostEvent != TELJJY_EVENT_NULL ) { 2994 up->iClockEvent = iPostEvent ; 2995 teljjy_control ( peer, pp, up ) ; 2996 } 2997 2998 up->iClockEvent = TELJJY_EVENT_NULL ; 2999 3000} 3001 3002/**************************************************************************************************/ 3003 3004static void 3005teljjy_setDelay ( struct peer *peer, struct jjyunit *up ) 3006{ 3007 3008 char sLog [ 60 ] ; 3009 int milliSecond, microSecond ; 3010 3011 gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ; 3012 3013 up->delayTime[up->iLoopbackCount].tv_sec -= up->sendTime[up->iLoopbackCount].tv_sec ; 3014 up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ; 3015 if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) { 3016 up->delayTime[up->iLoopbackCount].tv_sec -- ; 3017 up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ; 3018 } 3019 3020 milliSecond = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ; 3021 microSecond = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ; 3022 milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ; 3023 3024 snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY, 3025 milliSecond, microSecond ) ; 3026 3027 if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) { 3028 /* Delay > 700 mS */ 3029 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 3030 } else { 3031 /* Delay <= 700 mS */ 3032 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 3033 } 3034 3035} 3036 3037/**************************************************************************************************/ 3038 3039static int 3040teljjy_getDelay ( struct peer *peer, struct jjyunit *up ) 3041{ 3042 3043 struct timeval maxTime, minTime, averTime ; 3044 int i ; 3045 int minIndex = 0, maxIndex = 0, iAverCount = 0 ; 3046 int iThresholdSecond, iThresholdMicroSecond ; 3047 int iPercent ; 3048 3049 minTime.tv_sec = minTime.tv_usec = 0 ; 3050 maxTime.tv_sec = maxTime.tv_usec = 0 ; 3051 3052 iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ; 3053 iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ; 3054 3055 up->iLoopbackValidCount = 0 ; 3056 3057 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) { 3058 if ( up->bLoopbackTimeout[i] 3059 || up->delayTime[i].tv_sec > iThresholdSecond 3060 || ( up->delayTime[i].tv_sec == iThresholdSecond 3061 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) { 3062 continue ; 3063 } 3064 if ( up->iLoopbackValidCount == 0 ) { 3065 minTime.tv_sec = up->delayTime[i].tv_sec ; 3066 minTime.tv_usec = up->delayTime[i].tv_usec ; 3067 maxTime.tv_sec = up->delayTime[i].tv_sec ; 3068 maxTime.tv_usec = up->delayTime[i].tv_usec ; 3069 minIndex = maxIndex = i ; 3070 } else if ( minTime.tv_sec > up->delayTime[i].tv_sec 3071 || ( minTime.tv_sec == up->delayTime[i].tv_sec 3072 && minTime.tv_usec > up->delayTime[i].tv_usec ) ) { 3073 minTime.tv_sec = up->delayTime[i].tv_sec ; 3074 minTime.tv_usec = up->delayTime[i].tv_usec ; 3075 minIndex = i ; 3076 } else if ( maxTime.tv_sec < up->delayTime[i].tv_sec 3077 || ( maxTime.tv_sec == up->delayTime[i].tv_sec 3078 && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) { 3079 maxTime.tv_sec = up->delayTime[i].tv_sec ; 3080 maxTime.tv_usec = up->delayTime[i].tv_usec ; 3081 maxIndex = i ; 3082 } 3083 up->iLoopbackValidCount ++ ; 3084 } 3085 3086 if ( up->iLoopbackValidCount < 2 ) { 3087 return -1 ; 3088 } 3089 3090 averTime.tv_usec = 0; 3091 3092 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) { 3093 if ( up->bLoopbackTimeout[i] 3094 || up->delayTime[i].tv_sec > iThresholdSecond 3095 || ( up->delayTime[i].tv_sec == iThresholdSecond 3096 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) { 3097 continue ; 3098 } 3099 if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) { 3100 continue ; 3101 } 3102 if ( up->iLoopbackValidCount >= 4 && i == minIndex ) { 3103 continue ; 3104 } 3105 averTime.tv_usec += up->delayTime[i].tv_usec ; 3106 iAverCount ++ ; 3107 } 3108 3109 if ( iAverCount == 0 ) { 3110 /* This is never happened. */ 3111 /* Previous for-if-for blocks assure iAverCount > 0. */ 3112 /* This code avoids a claim by the coverity scan tool. */ 3113 return -1 ; 3114 } 3115 3116 /* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */ 3117 3118 iPercent = ( peer->ttl - 100 ) ; 3119 3120 /* Average delay time in milli second */ 3121 3122 return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ; 3123 3124} 3125 3126/******************************/ 3127static int 3128teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3129{ 3130 3131 DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ; 3132 3133 return TELJJY_STAY_CLOCK_STATE ; 3134 3135} 3136 3137/******************************/ 3138static int 3139teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3140{ 3141 3142 DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ; 3143 3144 modem_connect ( peer->refclkunit, peer ) ; 3145 3146 return TELJJY_CHANGE_CLOCK_STATE ; 3147 3148} 3149 3150/******************************/ 3151static int 3152teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3153{ 3154 3155 DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ; 3156 3157 return TELJJY_STAY_CLOCK_STATE ; 3158 3159} 3160 3161/******************************/ 3162static int 3163teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3164{ 3165 3166 DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ; 3167 3168 return TELJJY_CHANGE_CLOCK_STATE ; 3169 3170} 3171 3172/******************************/ 3173static int 3174teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3175{ 3176 3177 DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ; 3178 3179 return TELJJY_CHANGE_CLOCK_STATE ; 3180 3181} 3182 3183/******************************/ 3184static int 3185teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3186{ 3187 3188 DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ; 3189 3190 return TELJJY_STAY_CLOCK_STATE ; 3191 3192} 3193 3194/******************************/ 3195static int 3196teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3197{ 3198 3199 DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ; 3200 3201 return TELJJY_CHANGE_CLOCK_STATE ; 3202 3203} 3204 3205/******************************/ 3206static int 3207teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3208{ 3209 3210 int i ; 3211 3212 DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ; 3213 3214 up->bLineError = FALSE ; 3215 up->iClockCommandSeq = 0 ; 3216 up->iTimestampCount = 0 ; 3217 up->iLoopbackCount = 0 ; 3218 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 3219 up->bLoopbackTimeout[i] = FALSE ; 3220 } 3221 3222 return TELJJY_CHANGE_CLOCK_STATE ; 3223 3224} 3225 3226/******************************/ 3227static int 3228teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3229{ 3230 3231 const char * pCmd ; 3232 int iCmdLen ; 3233 3234 DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ; 3235 3236 /* Send a guest user ID */ 3237 pCmd = "TJJY\r" ; 3238 3239 /* Send login ID */ 3240 iCmdLen = strlen( pCmd ) ; 3241 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 3242 refclock_report( peer, CEVNT_FAULT ) ; 3243 } 3244 3245 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3246 3247 return TELJJY_STAY_CLOCK_STATE ; 3248 3249} 3250 3251/******************************/ 3252static int 3253teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3254{ 3255 3256 DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ; 3257 3258 if ( write( pp->io.fd, "\r", 1 ) != 1 ) { 3259 refclock_report( peer, CEVNT_FAULT ) ; 3260 } 3261 3262 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ; 3263 3264 up->iTeljjySilentTimer = 0 ; 3265 3266 return TELJJY_CHANGE_CLOCK_STATE ; 3267 3268} 3269 3270/******************************/ 3271static int 3272teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3273{ 3274 3275 DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ; 3276 3277 return TELJJY_CHANGE_CLOCK_STATE ; 3278 3279} 3280 3281/******************************/ 3282static int 3283teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3284{ 3285 3286 DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ; 3287 3288 return TELJJY_STAY_CLOCK_STATE ; 3289 3290} 3291 3292/******************************/ 3293static int 3294teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3295{ 3296 3297 DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ; 3298 3299 return TELJJY_CHANGE_CLOCK_STATE ; 3300 3301} 3302 3303/******************************/ 3304static int 3305teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3306{ 3307 3308 const char * pCmd ; 3309 int i, iLen, iNextClockState ; 3310 char sLog [ 120 ] ; 3311 3312 DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ; 3313 3314 if ( up->iClockCommandSeq > 0 3315 && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) { 3316 /* Command sequence has been completed */ 3317 return TELJJY_CHANGE_CLOCK_STATE ; 3318 } 3319 3320 if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) { 3321 /* Skip loopback */ 3322 3323 up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ; 3324 3325 } else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) { 3326 /* Loopback start */ 3327 3328 up->iLoopbackCount = 0 ; 3329 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 3330 up->bLoopbackTimeout[i] = FALSE ; 3331 } 3332 3333 } else if ( up->iClockCommandSeq > 0 && peer->ttl != 100 3334 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK 3335 && up->iLoopbackCount < MAX_LOOPBACK ) { 3336 /* Loopback character comes */ 3337#ifdef DEBUG 3338 if ( debug ) { 3339 printf( "refclock_jjy.c : teljjy_conn_send : iClockCommandSeq=%d iLoopbackCount=%d\n", 3340 up->iClockCommandSeq, up->iLoopbackCount ) ; 3341 } 3342#endif 3343 3344 teljjy_setDelay( peer, up ) ; 3345 3346 up->iLoopbackCount ++ ; 3347 3348 } 3349 3350 up->iClockCommandSeq++ ; 3351 3352 pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ; 3353 iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ; 3354 3355 if ( pCmd != NULL ) { 3356 3357 if ( write( pp->io.fd, pCmd, iLen ) != iLen ) { 3358 refclock_report( peer, CEVNT_FAULT ) ; 3359 } 3360 3361 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3362 /* Loopback character and timestamp */ 3363 if ( up->iLoopbackCount < MAX_LOOPBACK ) { 3364 gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ; 3365 up->bLoopbackMode = TRUE ; 3366 } else { 3367 /* This else-block is never come. */ 3368 /* This code avoid wrong report of the coverity static analysis scan tool. */ 3369 snprintf( sLog, sizeof(sLog)-1, "refclock_jjy.c ; teljjy_conn_send ; iClockCommandSeq=%d iLoopbackCount=%d MAX_LOOPBACK=%d", 3370 up->iClockCommandSeq, up->iLoopbackCount, MAX_LOOPBACK ) ; 3371 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_BUG, sLog ) ; 3372 msyslog ( LOG_ERR, "%s", sLog ) ; 3373 up->bLoopbackMode = FALSE ; 3374 } 3375 } else { 3376 /* Regular command */ 3377 up->bLoopbackMode = FALSE ; 3378 } 3379 3380 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3381 3382 if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) { 3383 /* Last command of the command sequence */ 3384 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ; 3385 } else { 3386 /* More commands to be issued */ 3387 iNextClockState = TELJJY_STAY_CLOCK_STATE ; 3388 } 3389 3390 } else { 3391 3392 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ; 3393 3394 } 3395 3396 return iNextClockState ; 3397 3398} 3399 3400/******************************/ 3401static int 3402teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3403{ 3404 3405 char *pBuf ; 3406 int iLen, rc ; 3407 char sLog [ 192 ] ; 3408 char bAdjustment ; 3409 3410 3411 DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ; 3412 3413 if ( up->linediscipline == LDISC_RAW ) { 3414 pBuf = up->sTextBuf ; 3415 iLen = up->iTextBufLen ; 3416 } else { 3417 pBuf = pp->a_lastcode ; 3418 iLen = pp->lencode ; 3419 } 3420 3421 if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen 3422 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK 3423 && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command) 3424 && up->iLoopbackCount < MAX_LOOPBACK ) { 3425 /* Loopback */ 3426 3427 teljjy_setDelay( peer, up ) ; 3428 3429 up->iLoopbackCount ++ ; 3430 3431 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen 3432 && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) { 3433 /* Maybe echoback */ 3434 3435 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ; 3436 3437 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3438 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) { 3439 /* 4DATE<CR> -> YYYYMMDD<CR> */ 3440 3441 rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ; 3442 3443 if ( rc != 3 || up->year < 2000 || 2099 <= up->year 3444 || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) { 3445 /* Invalid date */ 3446 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 3447 rc, up->year, up->month, up->day ) ; 3448 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3449 up->bLineError = TRUE ; 3450 } 3451 3452 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3453 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC 3454 && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) { 3455 /* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */ 3456 3457 rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ; 3458 3459 if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) { 3460 /* Invalid leap second */ 3461 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP, 3462 pBuf ) ; 3463 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3464 up->bLineError = TRUE ; 3465 } 3466 3467 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3468 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) { 3469 /* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */ 3470 3471 rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ; 3472 3473 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 3474 /* Invalid time */ 3475 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 3476 rc, up->hour, up->minute, up->second ) ; 3477 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3478 up->bLineError = TRUE ; 3479 } 3480 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 3481 3482 up->iTimestampCount++ ; 3483 3484 if ( up->iTimestampCount == 6 && ! up->bLineError ) { 3485#if DEBUG 3486 printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n", 3487 up->bLineError, 3488 up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ; 3489#endif 3490 bAdjustment = TRUE ; 3491 3492 if ( peer->ttl == 100 ) { 3493 /* mode=100 */ 3494 up->msecond = 0 ; 3495 } else { 3496 /* mode=101 to 110 */ 3497 up->msecond = teljjy_getDelay( peer, up ) ; 3498 if (up->msecond < 0 ) { 3499 up->msecond = 0 ; 3500 bAdjustment = FALSE ; 3501 } 3502 } 3503 3504 if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2] 3505 && up->iTimestamp[2] <= up->iTimestamp[3] 3506 && ( up->iTimestamp[3] + 1 ) == up->iTimestamp[4] 3507 && ( up->iTimestamp[4] + 1 ) == up->iTimestamp[5] ) { 3508 /* Non over midnight */ 3509 3510 jjy_synctime( peer, pp, up ) ; 3511 3512 if ( peer->ttl != 100 ) { 3513 if ( bAdjustment ) { 3514 snprintf( sLog, sizeof(sLog), 3515 JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST, 3516 up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ; 3517 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 3518 } else { 3519 snprintf( sLog, sizeof(sLog), 3520 JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST, 3521 up->iLoopbackValidCount, MAX_LOOPBACK ) ; 3522 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3523 } 3524 } 3525 3526 } 3527 } 3528 3529 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen 3530 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3531 /* Loopback noise ( Unexpected replay ) */ 3532 3533 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY, 3534 pBuf ) ; 3535 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 3536 3537 } else { 3538 3539 up->bLineError = TRUE ; 3540 3541 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 3542 pBuf ) ; 3543 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3544 3545 } 3546 3547 return TELJJY_STAY_CLOCK_STATE ; 3548 3549} 3550 3551/******************************/ 3552static int 3553teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3554{ 3555 3556 const char * pCmd ; 3557 3558 DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ; 3559 3560 if ( up->iClockCommandSeq >= 1 3561 && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) { 3562 /* Loopback */ 3563#ifdef DEBUG 3564 if ( debug ) { 3565 printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ; 3566 } 3567#endif 3568 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3569 up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ; 3570 } 3571 up->iTeljjySilentTimer = 0 ; 3572 return teljjy_conn_send( peer, pp, up ) ; 3573 } else { 3574 pCmd = "\r" ; 3575 } 3576 3577 if ( write( pp->io.fd, pCmd, 1 ) != 1 ) { 3578 refclock_report( peer, CEVNT_FAULT ) ; 3579 } 3580 3581 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3582 3583 up->iTeljjySilentTimer = 0 ; 3584 3585 return TELJJY_STAY_CLOCK_STATE ; 3586 3587} 3588 3589/******************************/ 3590static int 3591teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3592{ 3593 3594 DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ; 3595 3596 return TELJJY_CHANGE_CLOCK_STATE ; 3597 3598} 3599 3600/******************************/ 3601static int 3602teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3603{ 3604 3605 DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ; 3606 3607 return TELJJY_STAY_CLOCK_STATE ; 3608 3609} 3610 3611/******************************/ 3612static int 3613teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3614{ 3615 3616 DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ; 3617 3618 return TELJJY_CHANGE_CLOCK_STATE ; 3619 3620} 3621 3622/******************************/ 3623static int 3624teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3625{ 3626 3627 DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ; 3628 3629 modem_disconnect ( peer->refclkunit, peer ) ; 3630 3631 return TELJJY_STAY_CLOCK_STATE ; 3632 3633} 3634 3635/*################################################################################################*/ 3636/*################################################################################################*/ 3637/*## ##*/ 3638/*## Modem control finite state machine ##*/ 3639/*## ##*/ 3640/*################################################################################################*/ 3641/*################################################################################################*/ 3642 3643/* struct jjyunit.iModemState */ 3644 3645#define MODEM_STATE_DISCONNECT 0 3646#define MODEM_STATE_INITIALIZE 1 3647#define MODEM_STATE_DAILING 2 3648#define MODEM_STATE_CONNECT 3 3649#define MODEM_STATE_ESCAPE 4 3650 3651/* struct jjyunit.iModemEvent */ 3652 3653#define MODEM_EVENT_NULL 0 3654#define MODEM_EVENT_INITIALIZE 1 3655#define MODEM_EVENT_DIALOUT 2 3656#define MODEM_EVENT_DISCONNECT 3 3657#define MODEM_EVENT_RESP_OK 4 3658#define MODEM_EVENT_RESP_CONNECT 5 3659#define MODEM_EVENT_RESP_RING 6 3660#define MODEM_EVENT_RESP_NO_CARRIER 7 3661#define MODEM_EVENT_RESP_ERROR 8 3662#define MODEM_EVENT_RESP_CONNECT_X 9 3663#define MODEM_EVENT_RESP_NO_DAILTONE 10 3664#define MODEM_EVENT_RESP_BUSY 11 3665#define MODEM_EVENT_RESP_NO_ANSWER 12 3666#define MODEM_EVENT_RESP_UNKNOWN 13 3667#define MODEM_EVENT_SILENT 14 3668#define MODEM_EVENT_TIMEOUT 15 3669 3670/* Function prototypes */ 3671 3672static void modem_control ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3673 3674static int modem_disc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3675static int modem_disc_init ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3676static int modem_init_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3677static int modem_init_start ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3678static int modem_init_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3679static int modem_init_resp00 ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3680static int modem_init_resp04 ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3681static int modem_dial_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3682static int modem_dial_dialout ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3683static int modem_dial_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3684static int modem_dial_connect ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3685static int modem_dial_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3686static int modem_conn_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3687static int modem_conn_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3688static int modem_esc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3689static int modem_esc_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3690static int modem_esc_data ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3691static int modem_esc_silent ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3692static int modem_esc_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3693 3694static int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) = 3695{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3696/* NULL */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore }, 3697/* INITIALIZE */ { modem_disc_init , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore }, 3698/* DIALOUT */ { modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore }, 3699/* DISCONNECT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_escape }, 3700/* RESP: 0: OK */ { modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3701/* RESP: 1: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data }, 3702/* RESP: 2: RING */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3703/* RESP: 3: NO CARRIER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3704/* RESP: 4: ERROR */ { modem_disc_ignore, modem_init_resp04, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3705/* RESP: 5: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data }, 3706/* RESP: 6: NO DAILTONE */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3707/* RESP: 7: BUSY */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3708/* RESP: 8: NO ANSWER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3709/* RESP: 9: UNKNOWN */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3710/* SILENT */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent }, 3711/* TIMEOUT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_disc } 3712} ; 3713 3714static short iModemNextState [ ] [ 5 ] = 3715{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3716/* NULL */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3717/* INITIALIZE */ { MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3718/* DIALOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3719/* DISCONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE }, 3720/* RESP: 0: OK */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3721/* RESP: 1: CONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3722/* RESP: 2: RING */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3723/* RESP: 3: NO CARRIER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3724/* RESP: 4: ERROR */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3725/* RESP: 5: CONNECT X */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3726/* RESP: 6: NO DAILTONE */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3727/* RESP: 7: BUSY */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3728/* RESP: 8: NO ANSWER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3729/* RESP: 9: UNKNOWN */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3730/* SILENT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT }, 3731/* TIMEOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT } 3732} ; 3733 3734static short iModemPostEvent [ ] [ 5 ] = 3735{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3736/* NULL */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3737/* INITIALIZE */ { MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3738/* DIALOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3739/* DISCONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }, 3740/* RESP: 0: OK */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3741/* RESP: 1: CONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3742/* RESP: 2: RING */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3743/* RESP: 3: NO CARRIER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3744/* RESP: 4: ERROR */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3745/* RESP: 5: CONNECT X */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3746/* RESP: 6: NO DAILTONE */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3747/* RESP: 7: BUSY */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3748/* RESP: 8: NO ANSWER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3749/* RESP: 9: UNKNOWN */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3750/* SILENT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3751/* TIMEOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL } 3752} ; 3753 3754static short iModemSilentTimeout [ 5 ] = { 0, 0, 0, 0, 5 } ; 3755static short iModemStateTimeout [ 5 ] = { 0, 20, 90, 0, 20 } ; 3756 3757#define STAY_MODEM_STATE 0 3758#define CHANGE_MODEM_STATE 1 3759 3760#ifdef DEBUG 3761#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 ) ; } } 3762#else 3763#define DEBUG_MODEM_PRINTF(sFunc) 3764#endif 3765 3766/**************************************************************************************************/ 3767 3768static short 3769getModemState ( struct jjyunit *up ) 3770{ 3771 return up->iModemState ; 3772} 3773 3774/**************************************************************************************************/ 3775 3776static int 3777isModemStateConnect ( short iCheckState ) 3778{ 3779 return ( iCheckState == MODEM_STATE_CONNECT ) ; 3780} 3781 3782/**************************************************************************************************/ 3783 3784static int 3785isModemStateDisconnect ( short iCheckState ) 3786{ 3787 return ( iCheckState == MODEM_STATE_DISCONNECT ) ; 3788} 3789 3790/**************************************************************************************************/ 3791 3792static int 3793isModemStateTimerOn ( struct jjyunit *up ) 3794{ 3795 return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ; 3796} 3797 3798/**************************************************************************************************/ 3799 3800static void 3801modem_connect ( int unit, struct peer *peer ) 3802{ 3803 struct refclockproc *pp; 3804 struct jjyunit *up; 3805 3806 pp = peer->procptr ; 3807 up = pp->unitptr ; 3808 3809 DEBUG_MODEM_PRINTF( "modem_connect" ) ; 3810 3811 up->iModemEvent = MODEM_EVENT_INITIALIZE ; 3812 3813 modem_control ( peer, pp, up ) ; 3814 3815} 3816 3817/**************************************************************************************************/ 3818 3819static void 3820modem_disconnect ( int unit, struct peer *peer ) 3821{ 3822 struct refclockproc *pp; 3823 struct jjyunit *up; 3824 3825 pp = peer->procptr ; 3826 up = pp->unitptr ; 3827 3828 DEBUG_MODEM_PRINTF( "modem_disconnect" ) ; 3829 3830 up->iModemEvent = MODEM_EVENT_DISCONNECT ; 3831 3832 modem_control ( peer, pp, up ) ; 3833 3834} 3835 3836/**************************************************************************************************/ 3837 3838static int 3839modem_receive ( struct recvbuf *rbufp ) 3840{ 3841 3842 struct peer *peer; 3843 struct jjyunit *up; 3844 struct refclockproc *pp; 3845 char *pBuf ; 3846 size_t iLen ; 3847 3848#ifdef DEBUG 3849 static const char *sFunctionName = "modem_receive" ; 3850#endif 3851 3852 peer = rbufp->recv_peer ; 3853 pp = peer->procptr ; 3854 up = pp->unitptr ; 3855 3856 DEBUG_MODEM_PRINTF( sFunctionName ) ; 3857 3858 if ( up->linediscipline == LDISC_RAW ) { 3859 pBuf = up->sTextBuf ; 3860 iLen = up->iTextBufLen ; 3861 } else { 3862 pBuf = pp->a_lastcode ; 3863 iLen = pp->lencode ; 3864 } 3865 3866 if ( iLen == 2 && strncmp( pBuf, "OK" , 2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK ; } 3867 else if ( iLen == 7 && strncmp( pBuf, "CONNECT" , 7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT ; } 3868 else if ( iLen == 4 && strncmp( pBuf, "RING" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING ; } 3869 else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER ; } 3870 else if ( iLen == 5 && strncmp( pBuf, "ERROR" , 5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR ; } 3871 else if ( iLen >= 8 && strncmp( pBuf, "CONNECT " , 8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X ; } 3872 else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; } 3873 else if ( iLen == 4 && strncmp( pBuf, "BUSY" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY ; } 3874 else if ( iLen == 9 && strncmp( pBuf, "NO ANSWER" , 9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER ; } 3875 else { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN ; } 3876 3877#ifdef DEBUG 3878 if ( debug ) { 3879 char sResp [ 40 ] ; 3880 size_t iCopyLen ; 3881 iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ; 3882 strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ; 3883 sResp[iCopyLen] = 0 ; 3884 printf ( "refclock_jjy.c : modem_receive : iLen=%zu pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ; 3885 } 3886#endif 3887 modem_control ( peer, pp, up ) ; 3888 3889 return 0 ; 3890 3891} 3892 3893/**************************************************************************************************/ 3894 3895static void 3896modem_timer ( int unit, struct peer *peer ) 3897{ 3898 3899 struct refclockproc *pp ; 3900 struct jjyunit *up ; 3901 3902 pp = peer->procptr ; 3903 up = pp->unitptr ; 3904 3905 DEBUG_MODEM_PRINTF( "modem_timer" ) ; 3906 3907 if ( iModemSilentTimeout[up->iModemState] != 0 ) { 3908 up->iModemSilentTimer++ ; 3909 if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) { 3910 up->iModemEvent = MODEM_EVENT_SILENT ; 3911 modem_control ( peer, pp, up ) ; 3912 } 3913 } 3914 3915 if ( iModemStateTimeout[up->iModemState] != 0 ) { 3916 up->iModemStateTimer++ ; 3917 if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) { 3918 up->iModemEvent = MODEM_EVENT_TIMEOUT ; 3919 modem_control ( peer, pp, up ) ; 3920 } 3921 } 3922 3923} 3924 3925/**************************************************************************************************/ 3926 3927static void 3928modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3929{ 3930 3931 int rc ; 3932 short iPostEvent = MODEM_EVENT_NULL ; 3933 3934 DEBUG_MODEM_PRINTF( "modem_control" ) ; 3935 3936 rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ; 3937 3938 if ( rc == CHANGE_MODEM_STATE ) { 3939 iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ; 3940#ifdef DEBUG 3941 if ( debug ) { 3942 printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d iPostEvent=%d\n", 3943 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ; 3944 } 3945#endif 3946 3947 if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) { 3948 up->iModemSilentCount = 0 ; 3949 up->iModemStateTimer = 0 ; 3950 up->iModemCommandSeq = 0 ; 3951 } 3952 3953 up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ; 3954 } 3955 3956 if ( iPostEvent != MODEM_EVENT_NULL ) { 3957 up->iModemEvent = iPostEvent ; 3958 modem_control ( peer, pp, up ) ; 3959 } 3960 3961 up->iModemEvent = MODEM_EVENT_NULL ; 3962 3963} 3964 3965/******************************/ 3966static int 3967modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3968{ 3969 3970 DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ; 3971 3972 return STAY_MODEM_STATE ; 3973 3974} 3975 3976/******************************/ 3977static int 3978modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3979{ 3980 3981 DEBUG_MODEM_PRINTF( "modem_disc_init" ) ; 3982 3983 return CHANGE_MODEM_STATE ; 3984 3985} 3986 3987/******************************/ 3988static int 3989modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3990{ 3991 3992 DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ; 3993 3994 return STAY_MODEM_STATE ; 3995 3996} 3997 3998/******************************/ 3999static int 4000modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4001{ 4002 4003 DEBUG_MODEM_PRINTF( "modem_init_start" ) ; 4004 4005 up->iModemCommandSeq = 0 ; 4006 4007#ifdef DEBUG 4008 if ( debug ) { 4009 printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ; 4010 } 4011#endif 4012 4013 return modem_init_resp00( peer, pp, up ) ; 4014 4015} 4016 4017/******************************/ 4018static int 4019modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4020{ 4021 4022 const char * pCmd ; 4023 char cBuf [ 46 ] ; 4024 int iCmdLen ; 4025 int iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ; 4026 int iNextModemState = STAY_MODEM_STATE ; 4027 4028 DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ; 4029 4030 up->iModemCommandSeq++ ; 4031 4032 switch ( up->iModemCommandSeq ) { 4033 4034 case 1 : 4035 /* En = Echoback 0:Off 1:On */ 4036 /* Qn = Result codes 0:On 1:Off */ 4037 /* Vn = Result codes 0:Numeric 1:Text */ 4038 pCmd = "ATE0Q0V1\r\n" ; 4039 break ; 4040 4041 case 2 : 4042 /* Mn = Speaker switch 0:Off 1:On until remote carrier detected 2:On */ 4043 if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) { 4044 /* fudge 127.127.40.n flag3 0 */ 4045 iSpeakerSwitch = 0 ; 4046 } else { 4047 /* fudge 127.127.40.n flag3 1 */ 4048 iSpeakerSwitch = 2 ; 4049 } 4050 4051 /* Ln = Speaker volume 0:Very low 1:Low 2:Middle 3:High */ 4052 if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) { 4053 /* fudge 127.127.40.n flag4 0 */ 4054 iSpeakerVolume = 1 ; 4055 } else { 4056 /* fudge 127.127.40.n flag4 1 */ 4057 iSpeakerVolume = 2 ; 4058 } 4059 4060 pCmd = cBuf ; 4061 snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ; 4062 break ; 4063 4064 case 3 : 4065 /* &Kn = Flow control 4:XON/XOFF */ 4066 pCmd = "AT&K4\r\n" ; 4067 break ; 4068 4069 case 4 : 4070 /* +MS = Protocol V22B:1200,2400bps�iV.22bis) */ 4071 pCmd = "AT+MS=V22B\r\n" ; 4072 break ; 4073 4074 case 5 : 4075 /* %Cn = Data compression 0:No data compression */ 4076 pCmd = "AT%C0\r\n" ; 4077 break ; 4078 4079 case 6 : 4080 /* \Nn = Error correction 0:Normal mode 1:Direct mode 2:V42,MNP 3:V42,MNP,Normal */ 4081 if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) { 4082 /* fudge 127.127.40.n flag2 0 */ 4083 iErrorCorrection = 0 ; 4084 } else { 4085 /* fudge 127.127.40.n flag2 1 */ 4086 iErrorCorrection = 3 ; 4087 } 4088 4089 pCmd = cBuf ; 4090 snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ; 4091 break ; 4092 4093 case 7 : 4094 /* Hn = Hook 0:Hook-On ( Disconnect ) 1:Hook-Off ( Connect ) */ 4095 pCmd = "ATH1\r\n" ; 4096 break ; 4097 4098 case 8 : 4099 /* Initialize completion */ 4100 pCmd = NULL ; 4101 iNextModemState = CHANGE_MODEM_STATE ; 4102 break ; 4103 4104 default : 4105 pCmd = NULL ; 4106 break ; 4107 4108 } 4109 4110 if ( pCmd != NULL ) { 4111 4112 iCmdLen = strlen( pCmd ) ; 4113 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4114 refclock_report( peer, CEVNT_FAULT ) ; 4115 } 4116 4117 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4118 4119 } 4120 4121 return iNextModemState ; 4122 4123} 4124 4125/******************************/ 4126static int 4127modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4128{ 4129 4130 DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ; 4131 4132 return modem_init_resp00( peer, pp, up ) ; 4133 4134} 4135 4136/******************************/ 4137static int 4138modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4139{ 4140 4141 DEBUG_MODEM_PRINTF( "modem_init_disc" ) ; 4142#ifdef DEBUG 4143 if ( debug ) { 4144 printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ; 4145 } 4146#endif 4147 4148 return CHANGE_MODEM_STATE ; 4149 4150} 4151 4152/******************************/ 4153static int 4154modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4155{ 4156 4157 DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ; 4158 4159 return STAY_MODEM_STATE ; 4160 4161} 4162 4163/******************************/ 4164static int 4165modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4166{ 4167 4168 char sCmd [ 46 ] ; 4169 int iCmdLen ; 4170 char cToneOrPulse ; 4171 4172 DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ; 4173 4174 /* Tone or Pulse */ 4175 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 4176 /* fudge 127.127.40.n flag1 0 */ 4177 cToneOrPulse = 'T' ; 4178 } else { 4179 /* fudge 127.127.40.n flag1 1 */ 4180 cToneOrPulse = 'P' ; 4181 } 4182 4183 /* Connect ( Dial number ) */ 4184 snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ; 4185 4186 /* Send command */ 4187 iCmdLen = strlen( sCmd ) ; 4188 if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) { 4189 refclock_report( peer, CEVNT_FAULT ) ; 4190 } 4191 4192 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ; 4193 4194 return STAY_MODEM_STATE ; 4195 4196} 4197 4198/******************************/ 4199static int 4200modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4201{ 4202 4203 DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ; 4204#ifdef DEBUG 4205 if ( debug ) { 4206 printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ; 4207 } 4208#endif 4209 4210 return modem_conn_escape( peer, pp, up ) ; 4211 4212} 4213 4214/******************************/ 4215static int 4216modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4217{ 4218 4219 DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ; 4220 4221 return CHANGE_MODEM_STATE ; 4222 4223} 4224 4225/******************************/ 4226static int 4227modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4228{ 4229 4230 DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ; 4231#ifdef DEBUG 4232 if ( debug ) { 4233 printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ; 4234 } 4235#endif 4236 4237 modem_esc_disc( peer, pp, up ) ; 4238 4239 return CHANGE_MODEM_STATE ; 4240 4241} 4242 4243/******************************/ 4244static int 4245modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4246{ 4247 4248 DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ; 4249 4250 return STAY_MODEM_STATE ; 4251 4252} 4253 4254/******************************/ 4255static int 4256modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4257{ 4258 4259 DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ; 4260 4261 return CHANGE_MODEM_STATE ; 4262 4263} 4264 4265/******************************/ 4266static int 4267modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4268{ 4269 4270 DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ; 4271 4272 return STAY_MODEM_STATE ; 4273 4274} 4275 4276/******************************/ 4277static int 4278modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4279{ 4280 4281 const char * pCmd ; 4282 int iCmdLen ; 4283 4284 DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ; 4285 4286 /* Escape command ( Go to command mode ) */ 4287 pCmd = "+++" ; 4288 4289 /* Send command */ 4290 iCmdLen = strlen( pCmd ) ; 4291 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4292 refclock_report( peer, CEVNT_FAULT ) ; 4293 } 4294 4295 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4296 4297 return STAY_MODEM_STATE ; 4298 4299} 4300 4301/******************************/ 4302static int 4303modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4304{ 4305 4306 DEBUG_MODEM_PRINTF( "modem_esc_data" ) ; 4307 4308 up->iModemSilentTimer = 0 ; 4309 4310 return STAY_MODEM_STATE ; 4311 4312} 4313 4314/******************************/ 4315static int 4316modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4317{ 4318 4319 DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ; 4320 4321 up->iModemSilentCount ++ ; 4322 4323 if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) { 4324#ifdef DEBUG 4325 if ( debug ) { 4326 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ; 4327 } 4328#endif 4329 modem_esc_escape( peer, pp, up ) ; 4330 up->iModemSilentTimer = 0 ; 4331 return STAY_MODEM_STATE ; 4332 } 4333 4334#ifdef DEBUG 4335 if ( debug ) { 4336 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ; 4337 } 4338#endif 4339 return modem_esc_disc( peer, pp, up ) ; 4340 4341} 4342/******************************/ 4343static int 4344modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4345{ 4346 4347 const char * pCmd ; 4348 int iCmdLen ; 4349 4350 DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ; 4351 4352 /* Disconnect */ 4353 pCmd = "ATH0\r\n" ; 4354 4355 /* Send command */ 4356 iCmdLen = strlen( pCmd ) ; 4357 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4358 refclock_report( peer, CEVNT_FAULT ) ; 4359 } 4360 4361 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4362 4363 return CHANGE_MODEM_STATE ; 4364 4365} 4366 4367/*################################################################################################*/ 4368/*################################################################################################*/ 4369/*## ##*/ 4370/*## jjy_write_clockstats ##*/ 4371/*## ##*/ 4372/*################################################################################################*/ 4373/*################################################################################################*/ 4374 4375static void 4376jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData ) 4377{ 4378 4379 char sLog [ 100 ] ; 4380 const char * pMark ; 4381 int iMarkLen, iDataLen ; 4382 4383 switch ( iMark ) { 4384 case JJY_CLOCKSTATS_MARK_JJY : 4385 pMark = "JJY " ; 4386 break ; 4387 case JJY_CLOCKSTATS_MARK_SEND : 4388 pMark = "--> " ; 4389 break ; 4390 case JJY_CLOCKSTATS_MARK_RECEIVE : 4391 pMark = "<-- " ; 4392 break ; 4393 case JJY_CLOCKSTATS_MARK_INFORMATION : 4394 pMark = "--- " ; 4395 break ; 4396 case JJY_CLOCKSTATS_MARK_ATTENTION : 4397 pMark = "=== " ; 4398 break ; 4399 case JJY_CLOCKSTATS_MARK_WARNING : 4400 pMark = "-W- " ; 4401 break ; 4402 case JJY_CLOCKSTATS_MARK_ERROR : 4403 pMark = "-X- " ; 4404 break ; 4405 case JJY_CLOCKSTATS_MARK_BUG : 4406 pMark = "!!! " ; 4407 break ; 4408 default : 4409 pMark = "" ; 4410 break ; 4411 } 4412 4413 iDataLen = strlen( pData ) ; 4414 iMarkLen = strlen( pMark ) ; 4415 strcpy( sLog, pMark ) ; /* Harmless because of enough length */ 4416 printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ; 4417 4418#ifdef DEBUG 4419 if ( debug ) { 4420 printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ; 4421 } 4422#endif 4423 record_clock_stats( &peer->srcadr, sLog ) ; 4424 4425} 4426 4427/*################################################################################################*/ 4428/*################################################################################################*/ 4429/*## ##*/ 4430/*## printableString ##*/ 4431/*## ##*/ 4432/*################################################################################################*/ 4433/*################################################################################################*/ 4434 4435static void 4436printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen ) 4437{ 4438 const char *printableControlChar[] = { 4439 "<NUL>", "<SOH>", "<STX>", "<ETX>", 4440 "<EOT>", "<ENQ>", "<ACK>", "<BEL>", 4441 "<BS>" , "<HT>" , "<LF>" , "<VT>" , 4442 "<FF>" , "<CR>" , "<SO>" , "<SI>" , 4443 "<DLE>", "<DC1>", "<DC2>", "<DC3>", 4444 "<DC4>", "<NAK>", "<SYN>", "<ETB>", 4445 "<CAN>", "<EM>" , "<SUB>", "<ESC>", 4446 "<FS>" , "<GS>" , "<RS>" , "<US>" , 4447 " " } ; 4448 4449 size_t i, j, n ; 4450 size_t InputLen; 4451 size_t OutputLen; 4452 4453 InputLen = (size_t)iInputLen; 4454 OutputLen = (size_t)iOutputLen; 4455 for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) { 4456 if ( isprint( (unsigned char)sInput[i] ) ) { 4457 n = 1 ; 4458 if ( j + 1 >= OutputLen ) 4459 break ; 4460 sOutput[j] = sInput[i] ; 4461 } else if ( ( sInput[i] & 0xFF ) < 4462 COUNTOF(printableControlChar) ) { 4463 n = strlen( printableControlChar[sInput[i] & 0xFF] ) ; 4464 if ( j + n + 1 >= OutputLen ) 4465 break ; 4466 strlcpy( sOutput + j, 4467 printableControlChar[sInput[i] & 0xFF], 4468 OutputLen - j ) ; 4469 } else { 4470 n = 5 ; 4471 if ( j + n + 1 >= OutputLen ) 4472 break ; 4473 snprintf( sOutput + j, OutputLen - j, "<x%X>", 4474 sInput[i] & 0xFF ) ; 4475 } 4476 j += n ; 4477 } 4478 4479 sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ; 4480 4481} 4482 4483/**************************************************************************************************/ 4484 4485#else 4486int refclock_jjy_bs ; 4487#endif /* REFCLOCK */ 4488