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