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