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