refclock_jjy.c revision 1.10
1/* $NetBSD: refclock_jjy.c,v 1.10 2016/05/01 23:32:01 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( (u_char)(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( (u_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 ; 1160 char sLog [ 100 ] ; 1161 int iLen ; 1162 int rc ; 1163 1164 const char * pCmd ; 1165 int iCmdLen ; 1166 1167 /* Initialize pointers */ 1168 1169 peer = rbufp->recv_peer ; 1170 pp = peer->procptr ; 1171 up = pp->unitptr ; 1172 1173 if ( up->linediscipline == LDISC_RAW ) { 1174 pBuf = up->sTextBuf ; 1175 iLen = up->iTextBufLen ; 1176 } else { 1177 pBuf = pp->a_lastcode ; 1178 iLen = pp->lencode ; 1179 } 1180 1181 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_jjy01", iLen ) ; 1182 1183 /* Check expected reply */ 1184 1185 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) { 1186 /* Command sequence has not been started, or has been completed */ 1187 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 1188 pBuf ) ; 1189 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1190 up->bLineError = TRUE ; 1191 return JJY_RECEIVE_ERROR ; 1192 } 1193 1194 /* Check reply length */ 1195 1196 if ( iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[0] 1197 && iLen != tristate_jjy01_command_sequence[up->iCommandSeq].iExpectedReplyLength[1] ) { 1198 /* Unexpected reply length */ 1199 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1200 iLen ) ; 1201 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1202 up->bLineError = TRUE ; 1203 return JJY_RECEIVE_ERROR ; 1204 } 1205 1206 /* Parse reply */ 1207 1208 switch ( tristate_jjy01_command_sequence[up->iCommandSeq].commandNumber ) { 1209 1210 case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */ 1211 1212 rc = sscanf ( pBuf, "%4d/%2d/%2d", 1213 &up->year, &up->month, &up->day ) ; 1214 1215 if ( rc != 3 || up->year < 2000 || 2099 <= up->year 1216 || up->month < 1 || 12 < up->month 1217 || up->day < 1 || 31 < up->day ) { 1218 /* Invalid date */ 1219 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 1220 rc, up->year, up->month, up->day ) ; 1221 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1222 up->bLineError = TRUE ; 1223 return JJY_RECEIVE_ERROR ; 1224 } 1225 1226 break ; 1227 1228 case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 1229 case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */ 1230 1231 if ( up->iTimestampCount >= 2 ) { 1232 /* Too many time reply */ 1233 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY, 1234 up->iTimestampCount ) ; 1235 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1236 up->bLineError = TRUE ; 1237 return JJY_RECEIVE_ERROR ; 1238 } 1239 1240 rc = sscanf ( pBuf, "%2d:%2d:%2d", 1241 &up->hour, &up->minute, &up->second ) ; 1242 1243 if ( rc != 3 || up->hour > 23 || up->minute > 59 || 1244 up->second > 60 ) { 1245 /* Invalid time */ 1246 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 1247 rc, up->hour, up->minute, up->second ) ; 1248 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1249 up->bLineError = TRUE ; 1250 return JJY_RECEIVE_ERROR ; 1251 } 1252 1253 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 1254 1255 up->iTimestampCount++ ; 1256 1257 up->msecond = 0 ; 1258 1259 break ; 1260 1261 case TS_JJY01_COMMAND_NUMBER_STUS : 1262 1263 if ( strncmp( pBuf, TS_JJY01_REPLY_STUS_ADJUSTED, 1264 TS_JJY01_REPLY_LENGTH_STUS_ADJUSTED ) == 0 1265 || strncmp( pBuf, TS_JJY01_REPLY_STUS_UNADJUSTED, 1266 TS_JJY01_REPLY_LENGTH_STUS_UNADJUSTED ) == 0 ) { 1267 /* Good */ 1268 } else { 1269 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1270 pBuf ) ; 1271 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1272 up->bLineError = TRUE ; 1273 return JJY_RECEIVE_ERROR ; 1274 } 1275 1276 break ; 1277 1278 case TS_JJY01_COMMAND_NUMBER_DCST : 1279 1280 if ( strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID, 1281 TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 1282 || strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID, 1283 TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) { 1284 /* Good */ 1285 } else { 1286 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1287 pBuf ) ; 1288 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1289 up->bLineError = TRUE ; 1290 return JJY_RECEIVE_ERROR ; 1291 } 1292 1293 break ; 1294 1295 default : /* Unexpected reply */ 1296 1297 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1298 pBuf ) ; 1299 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1300 up->bLineError = TRUE ; 1301 return JJY_RECEIVE_ERROR ; 1302 1303 } 1304 1305 if ( up->iTimestampCount == 2 ) { 1306 /* Process date and time */ 1307 1308 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0] 1309 && up->iTimestamp[0] <= up->iTimestamp[1] ) { 1310 /* 3 commands (time,date,stim) was excuted in two seconds */ 1311 jjy_synctime( peer, pp, up ) ; 1312 return JJY_RECEIVE_DONE ; 1313 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) { 1314 /* Over midnight, and date is unsure */ 1315 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2, 1316 up->iTimestamp[0], up->iTimestamp[1] ) ; 1317 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 1318 return JJY_RECEIVE_SKIP ; 1319 } else { 1320 /* Slow reply */ 1321 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2, 1322 up->iTimestamp[0], up->iTimestamp[1] ) ; 1323 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1324 up->bLineError = TRUE ; 1325 return JJY_RECEIVE_ERROR ; 1326 } 1327 1328 } 1329 1330 /* Issue next command */ 1331 1332 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command != NULL ) { 1333 up->iCommandSeq ++ ; 1334 } 1335 1336 if ( tristate_jjy01_command_sequence[up->iCommandSeq].command == NULL ) { 1337 /* Command sequence completed */ 1338 return JJY_RECEIVE_DONE ; 1339 } 1340 1341 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ; 1342 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ; 1343 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1344 refclock_report ( peer, CEVNT_FAULT ) ; 1345 } 1346 1347 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 1348 1349 return JJY_RECEIVE_WAIT ; 1350 1351} 1352 1353/**************************************************************************************************/ 1354 1355static void 1356jjy_poll_tristate_jjy01 ( int unit, struct peer *peer ) 1357{ 1358#ifdef DEBUG 1359 static const char *sFunctionName = "jjy_poll_tristate_jjy01" ; 1360#endif 1361 1362 struct refclockproc *pp ; 1363 struct jjyunit *up ; 1364 1365 const char * pCmd ; 1366 int iCmdLen ; 1367 1368 pp = peer->procptr; 1369 up = pp->unitptr ; 1370 1371 up->bLineError = FALSE ; 1372 up->iTimestampCount = 0 ; 1373 1374 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 1375 /* Skip "dcst" and "stus" commands */ 1376 up->iCommandSeq = 2 ; 1377 up->iLineCount = 2 ; 1378 } 1379 1380#ifdef DEBUG 1381 if ( debug ) { 1382 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n", 1383 sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 1384 up->iLineCount ) ; 1385 } 1386#endif 1387 1388 /* 1389 * Send a first command 1390 */ 1391 1392 up->iCommandSeq ++ ; 1393 1394 pCmd = tristate_jjy01_command_sequence[up->iCommandSeq].command ; 1395 iCmdLen = tristate_jjy01_command_sequence[up->iCommandSeq].commandLength ; 1396 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1397 refclock_report ( peer, CEVNT_FAULT ) ; 1398 } 1399 1400 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 1401 1402} 1403 1404/*################################################################################################*/ 1405/*################################################################################################*/ 1406/*## ##*/ 1407/*## The C-DEX Co. Ltd. JJY receiver JST2000 ##*/ 1408/*## ##*/ 1409/*## server 127.127.40.X mode 2 ##*/ 1410/*## ##*/ 1411/*################################################################################################*/ 1412/*################################################################################################*/ 1413/* */ 1414/* Command Response Remarks */ 1415/* -------------------- ---------------------------------------- ---------------------------- */ 1416/* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> J is a fixed character */ 1417/* */ 1418/*################################################################################################*/ 1419 1420static struct jjyRawDataBreak cdex_jst2000_raw_break [ ] = 1421{ 1422 { "\x03", 1 }, { NULL, 0 } 1423} ; 1424 1425/**************************************************************************************************/ 1426 1427static int 1428jjy_start_cdex_jst2000 ( int unit, struct peer *peer, struct jjyunit *up ) 1429{ 1430 1431 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: C-DEX Co. Ltd. JST2000" ) ; 1432 1433 up->unittype = UNITTYPE_CDEX_JST2000 ; 1434 up->linespeed = SPEED232_CDEX_JST2000 ; 1435 up->linediscipline = LDISC_RAW ; 1436 1437 up->pRawBreak = cdex_jst2000_raw_break ; 1438 up->bWaitBreakString = TRUE ; 1439 1440 up->bSkipCntrlCharOnly = FALSE ; 1441 1442 return 0 ; 1443 1444} 1445 1446/**************************************************************************************************/ 1447 1448static int 1449jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp ) 1450{ 1451 1452 struct jjyunit *up ; 1453 struct refclockproc *pp ; 1454 struct peer *peer ; 1455 1456 char *pBuf, sLog [ 100 ] ; 1457 int iLen ; 1458 int rc ; 1459 1460 /* Initialize pointers */ 1461 1462 peer = rbufp->recv_peer ; 1463 pp = peer->procptr ; 1464 up = pp->unitptr ; 1465 1466 if ( up->linediscipline == LDISC_RAW ) { 1467 pBuf = up->sTextBuf ; 1468 iLen = up->iTextBufLen ; 1469 } else { 1470 pBuf = pp->a_lastcode ; 1471 iLen = pp->lencode ; 1472 } 1473 1474 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_cdex_jst2000", iLen ) ; 1475 1476 /* Check expected reply */ 1477 1478 if ( up->iCommandSeq != 1 ) { 1479 /* Command sequence has not been started, or has been completed */ 1480 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 1481 pBuf ) ; 1482 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1483 up->bLineError = TRUE ; 1484 return JJY_RECEIVE_ERROR ; 1485 } 1486 1487 /* Wait until ETX comes */ 1488 1489 if ( up->iLineBufLen < 17 || up->sLineBuf[up->iLineBufLen-1] != 0x03 ) { 1490 return JJY_RECEIVE_UNPROCESS ; 1491 } 1492 1493 /* Check reply length */ 1494 1495 if ( iLen != 15 ) { 1496 /* Unexpected reply length */ 1497 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1498 iLen ) ; 1499 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1500 up->bLineError = TRUE ; 1501 return JJY_RECEIVE_ERROR ; 1502 } 1503 1504 /* JYYMMDD HHMMSSS */ 1505 1506 rc = sscanf ( pBuf, "J%2d%2d%2d %2d%2d%2d%1d", 1507 &up->year, &up->month, &up->day, 1508 &up->hour, &up->minute, &up->second, 1509 &up->msecond ) ; 1510 1511 if ( rc != 7 || up->month < 1 || up->month > 12 || 1512 up->day < 1 || up->day > 31 || up->hour > 23 || 1513 up->minute > 59 || up->second > 60 ) { 1514 /* Invalid date and time */ 1515 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1516 rc, up->year, up->month, up->day, 1517 up->hour, up->minute, up->second ) ; 1518 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1519 up->bLineError = TRUE ; 1520 return JJY_RECEIVE_ERROR ; 1521 } 1522 1523 up->year += 2000 ; 1524 up->msecond *= 100 ; 1525 1526 jjy_synctime( peer, pp, up ) ; 1527 1528 return JJY_RECEIVE_DONE ; 1529 1530} 1531 1532/**************************************************************************************************/ 1533 1534static void 1535jjy_poll_cdex_jst2000 ( int unit, struct peer *peer ) 1536{ 1537 1538 struct refclockproc *pp ; 1539 struct jjyunit *up ; 1540 1541 pp = peer->procptr ; 1542 up = pp->unitptr ; 1543 1544 up->bLineError = FALSE ; 1545 up->iRawBufLen = 0 ; 1546 up->iLineBufLen = 0 ; 1547 up->iTextBufLen = 0 ; 1548 1549 /* 1550 * Send "<ENQ>1J<ETX>" command 1551 */ 1552 1553 up->iCommandSeq ++ ; 1554 1555 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) { 1556 refclock_report ( peer, CEVNT_FAULT ) ; 1557 } 1558 1559 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\0051J\003" ) ; 1560 1561} 1562 1563/*################################################################################################*/ 1564/*################################################################################################*/ 1565/*## ##*/ 1566/*## The Echo Keisokuki Co. Ltd. JJY receiver LT2000 ##*/ 1567/*## ##*/ 1568/*## server 127.127.40.X mode 3 ##*/ 1569/*## ##*/ 1570/*################################################################################################*/ 1571/*################################################################################################*/ 1572/* */ 1573/* Command Response Remarks */ 1574/* -------------------- ---------------------------------------- ---------------------------- */ 1575/* # Mode 1 ( Request & Send ) */ 1576/* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */ 1577/* C Mode 2 ( Continuous ) */ 1578/* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> 0.5 sec before time stamp */ 1579/* <SUB> Second signal */ 1580/* */ 1581/*################################################################################################*/ 1582 1583#define ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1 1584#define ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 2 1585#define ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 3 1586 1587#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND "#" 1588#define ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_TIME "T" 1589#define ECHOKEISOKUKI_LT2000_COMMAND_CONTINUOUS "C" 1590 1591/**************************************************************************************************/ 1592 1593static int 1594jjy_start_echokeisokuki_lt2000 ( int unit, struct peer *peer, struct jjyunit *up ) 1595{ 1596 1597 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Echo Keisokuki Co. Ltd. LT2000" ) ; 1598 1599 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ; 1600 up->linespeed = SPEED232_ECHOKEISOKUKI_LT2000 ; 1601 up->linediscipline = LDISC_CLK ; 1602 1603 up->operationmode = ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ; 1604 1605 return 0 ; 1606 1607} 1608 1609/**************************************************************************************************/ 1610 1611static int 1612jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp ) 1613{ 1614 1615 struct jjyunit *up ; 1616 struct refclockproc *pp ; 1617 struct peer *peer; 1618 1619 char *pBuf, sLog [ 100 ], sErr [ 60 ] ; 1620 int iLen ; 1621 int rc ; 1622 int i, ibcc, ibcc1, ibcc2 ; 1623 1624 /* Initialize pointers */ 1625 1626 peer = rbufp->recv_peer ; 1627 pp = peer->procptr ; 1628 up = pp->unitptr ; 1629 1630 if ( up->linediscipline == LDISC_RAW ) { 1631 pBuf = up->sTextBuf ; 1632 iLen = up->iTextBufLen ; 1633 } else { 1634 pBuf = pp->a_lastcode ; 1635 iLen = pp->lencode ; 1636 } 1637 1638 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_echokeisokuki_lt2000", iLen ) ; 1639 1640 /* Check reply length */ 1641 1642 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1643 && iLen != 15 ) 1644 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1645 && iLen != 17 ) 1646 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 1647 && iLen != 17 ) ) { 1648 /* Unexpected reply length */ 1649 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1650 iLen ) ; 1651 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1652 up->bLineError = TRUE ; 1653 return JJY_RECEIVE_ERROR ; 1654 } 1655 1656 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND && iLen == 15 ) { 1657 /* YYMMDDWHHMMSS<BCC1><BCC2> */ 1658 1659 for ( i = ibcc = 0 ; i < 13 ; i ++ ) { 1660 ibcc ^= pBuf[i] ; 1661 } 1662 1663 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ; 1664 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ; 1665 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) { 1666 snprintf( sErr, sizeof(sErr)-1, " BCC error : Recv=%02X,%02X / Calc=%02X,%02X ", 1667 pBuf[13] & 0xFF, pBuf[14] & 0xFF, 1668 ibcc1, ibcc2 ) ; 1669 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 1670 sErr ) ; 1671 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1672 up->bLineError = TRUE ; 1673 return JJY_RECEIVE_ERROR ; 1674 } 1675 1676 } 1677 1678 if ( ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND 1679 && iLen == 15 ) 1680 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1681 && iLen == 17 ) 1682 || ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS 1683 && iLen == 17 ) ) { 1684 /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */ 1685 1686 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d", 1687 &up->year, &up->month, &up->day, 1688 &up->hour, &up->minute, &up->second ) ; 1689 1690 if ( rc != 6 || up->month < 1 || up->month > 12 1691 || up->day < 1 || up->day > 31 1692 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 1693 /* Invalid date and time */ 1694 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1695 rc, up->year, up->month, up->day, 1696 up->hour, up->minute, up->second ) ; 1697 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1698 up->bLineError = TRUE ; 1699 return JJY_RECEIVE_ERROR ; 1700 } 1701 1702 up->year += 2000 ; 1703 1704 if ( up->operationmode == ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS 1705 || up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) { 1706 /* A time stamp comes on every 0.5 second in the mode 2 of the LT-2000. */ 1707 1708 up->msecond = 500 ; 1709 up->second -- ; 1710 if ( up->second < 0 ) { 1711 up->second = 59 ; 1712 up->minute -- ; 1713 if ( up->minute < 0 ) { 1714 up->minute = 59 ; 1715 up->hour -- ; 1716 if ( up->hour < 0 ) { 1717 up->hour = 23 ; 1718 up->day -- ; 1719 if ( up->day < 1 ) { 1720 up->month -- ; 1721 if ( up->month < 1 ) { 1722 up->month = 12 ; 1723 up->year -- ; 1724 } 1725 } 1726 } 1727 } 1728 } 1729 1730 } 1731 1732 jjy_synctime( peer, pp, up ) ; 1733 1734 1735 } 1736 1737 if (up->operationmode == ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS ) { 1738 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */ 1739 1740 iLen = strlen( ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ; 1741 if ( write ( pp->io.fd, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND, iLen ) != iLen ) { 1742 refclock_report ( peer, CEVNT_FAULT ) ; 1743 } 1744 1745 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, ECHOKEISOKUKI_LT2000_COMMAND_REQUEST_SEND ) ; 1746 1747 } 1748 1749 return JJY_RECEIVE_DONE ; 1750 1751} 1752 1753/**************************************************************************************************/ 1754 1755static void 1756jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer ) 1757{ 1758 1759 struct refclockproc *pp ; 1760 struct jjyunit *up ; 1761 1762 char sCmd[2] ; 1763 1764 pp = peer->procptr ; 1765 up = pp->unitptr ; 1766 1767 up->bLineError = FALSE ; 1768 1769 /* 1770 * Send "T" or "C" command 1771 */ 1772 1773 switch ( up->operationmode ) { 1774 case ECHOKEISOKUKI_LT2000_MODE_REQUEST_SEND : 1775 sCmd[0] = 'T' ; 1776 break ; 1777 case ECHOKEISOKUKI_LT2000_MODE_CONTINUOUS : 1778 case ECHOKEISOKUKI_LT2000_MODE_SWITCHING_CONTINUOUS : 1779 sCmd[0] = 'C' ; 1780 break ; 1781 } 1782 sCmd[1] = 0 ; 1783 1784 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) { 1785 refclock_report ( peer, CEVNT_FAULT ) ; 1786 } 1787 1788 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ; 1789 1790} 1791 1792/*################################################################################################*/ 1793/*################################################################################################*/ 1794/*## ##*/ 1795/*## The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 ##*/ 1796/*## ##*/ 1797/*## server 127.127.40.X mode 4 ##*/ 1798/*## ##*/ 1799/*################################################################################################*/ 1800/*################################################################################################*/ 1801/* */ 1802/* Command Response Remarks */ 1803/* -------------------- ---------------------------------------- ---------------------------- */ 1804/* 'XX YY/MM/DD W HH:MM:SS<CR> XX:OK|NG|ER W:0(Mon)-6(Sun) */ 1805/* */ 1806/*################################################################################################*/ 1807 1808static int 1809jjy_start_citizentic_jjy200 ( int unit, struct peer *peer, struct jjyunit *up ) 1810{ 1811 1812 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: CITIZEN T.I.C CO. LTD. JJY200" ) ; 1813 1814 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ; 1815 up->linespeed = SPEED232_CITIZENTIC_JJY200 ; 1816 up->linediscipline = LDISC_CLK ; 1817 1818 return 0 ; 1819 1820} 1821 1822/**************************************************************************************************/ 1823 1824static int 1825jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp ) 1826{ 1827 1828 struct jjyunit *up ; 1829 struct refclockproc *pp ; 1830 struct peer *peer; 1831 1832 char *pBuf, sLog [ 100 ], sMsg [ 16 ] ; 1833 int iLen ; 1834 int rc ; 1835 char cApostrophe, sStatus[3] ; 1836 int iWeekday ; 1837 1838 /* Initialize pointers */ 1839 1840 peer = rbufp->recv_peer ; 1841 pp = peer->procptr ; 1842 up = pp->unitptr ; 1843 1844 if ( up->linediscipline == LDISC_RAW ) { 1845 pBuf = up->sTextBuf ; 1846 iLen = up->iTextBufLen ; 1847 } else { 1848 pBuf = pp->a_lastcode ; 1849 iLen = pp->lencode ; 1850 } 1851 1852 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_citizentic_jjy200", iLen ) ; 1853 1854 /* 1855 * JJY-200 sends a timestamp every second. 1856 * So, a timestamp is ignored unless it is right after polled. 1857 */ 1858 1859 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) { 1860 return JJY_RECEIVE_SKIP ; 1861 } 1862 1863 /* Check reply length */ 1864 1865 if ( iLen != 23 ) { 1866 /* Unexpected reply length */ 1867 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 1868 iLen ) ; 1869 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1870 up->bLineError = TRUE ; 1871 return JJY_RECEIVE_ERROR ; 1872 } 1873 1874 /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 1875 1876 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d", 1877 &cApostrophe, sStatus, 1878 &up->year, &up->month, &up->day, &iWeekday, 1879 &up->hour, &up->minute, &up->second ) ; 1880 sStatus[2] = 0 ; 1881 1882 if ( rc != 9 || cApostrophe != '\'' 1883 || ( strcmp( sStatus, "OK" ) != 0 1884 && strcmp( sStatus, "NG" ) != 0 1885 && strcmp( sStatus, "ER" ) != 0 ) 1886 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 1887 || iWeekday > 6 1888 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 1889 /* Invalid date and time */ 1890 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 1891 rc, up->year, up->month, up->day, 1892 up->hour, up->minute, up->second ) ; 1893 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 1894 up->bLineError = TRUE ; 1895 return JJY_RECEIVE_ERROR ; 1896 } else if ( strcmp( sStatus, "NG" ) == 0 1897 || strcmp( sStatus, "ER" ) == 0 ) { 1898 /* Timestamp is unsure */ 1899 snprintf( sMsg, sizeof(sMsg)-1, "status=%s", sStatus ) ; 1900 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TIMESTAMP_UNSURE, 1901 sMsg ) ; 1902 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 1903 return JJY_RECEIVE_SKIP ; 1904 } 1905 1906 up->year += 2000 ; 1907 up->msecond = 0 ; 1908 1909 jjy_synctime( peer, pp, up ) ; 1910 1911 return JJY_RECEIVE_DONE ; 1912 1913} 1914 1915/**************************************************************************************************/ 1916 1917static void 1918jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer ) 1919{ 1920 1921 struct refclockproc *pp ; 1922 struct jjyunit *up ; 1923 1924 pp = peer->procptr ; 1925 up = pp->unitptr ; 1926 1927 up->bLineError = FALSE ; 1928 1929} 1930 1931/*################################################################################################*/ 1932/*################################################################################################*/ 1933/*## ##*/ 1934/*## The Tristate Ltd. GPS clock TS-GPS01 ##*/ 1935/*## ##*/ 1936/*## server 127.127.40.X mode 5 ##*/ 1937/*## ##*/ 1938/*################################################################################################*/ 1939/*################################################################################################*/ 1940/* */ 1941/* This clock has NMEA mode and command/respose mode. */ 1942/* When this jjy driver are used, set to command/respose mode of this clock */ 1943/* by the onboard switch SW4, and make sure the LED-Y is tured on. */ 1944/* Other than this JJY driver, the refclock driver type 20, generic NMEA driver, */ 1945/* works with the NMEA mode of this clock. */ 1946/* */ 1947/* Command Response Remarks */ 1948/* -------------------- ---------------------------------------- ---------------------------- */ 1949/* stus<CR><LF> *R|*G|*U|+U<CR><LF> */ 1950/* date<CR><LF> YY/MM/DD<CR><LF> */ 1951/* time<CR><LF> HH:MM:SS<CR><LF> */ 1952/* */ 1953/*################################################################################################*/ 1954 1955#define TS_GPS01_COMMAND_NUMBER_DATE 1 1956#define TS_GPS01_COMMAND_NUMBER_TIME 2 1957#define TS_GPS01_COMMAND_NUMBER_STUS 4 1958 1959#define TS_GPS01_REPLY_DATE "yyyy/mm/dd" 1960#define TS_GPS01_REPLY_TIME "hh:mm:ss" 1961#define TS_GPS01_REPLY_STUS_RTC "*R" 1962#define TS_GPS01_REPLY_STUS_GPS "*G" 1963#define TS_GPS01_REPLY_STUS_UTC "*U" 1964#define TS_GPS01_REPLY_STUS_PPS "+U" 1965 1966#define TS_GPS01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */ 1967#define TS_GPS01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */ 1968#define TS_GPS01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */ 1969 1970static struct 1971{ 1972 char commandNumber ; 1973 const char *command ; 1974 int commandLength ; 1975 int iExpectedReplyLength ; 1976} tristate_gps01_command_sequence[] = 1977{ 1978 { 0, NULL, 0, 0 }, /* Idle */ 1979 { TS_GPS01_COMMAND_NUMBER_STUS, "stus\r\n", 6, TS_GPS01_REPLY_LENGTH_STUS }, 1980 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME }, 1981 { TS_GPS01_COMMAND_NUMBER_DATE, "date\r\n", 6, TS_GPS01_REPLY_LENGTH_DATE }, 1982 { TS_GPS01_COMMAND_NUMBER_TIME, "time\r\n", 6, TS_GPS01_REPLY_LENGTH_TIME }, 1983 /* End of command */ 1984 { 0, NULL, 0, 0 } 1985} ; 1986 1987/**************************************************************************************************/ 1988 1989static int 1990jjy_start_tristate_gpsclock01 ( int unit, struct peer *peer, struct jjyunit *up ) 1991{ 1992 1993 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Tristate Ltd. TS-GPS01" ) ; 1994 1995 up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ; 1996 up->linespeed = SPEED232_TRISTATE_GPSCLOCK01 ; 1997 up->linediscipline = LDISC_CLK ; 1998 1999 return 0 ; 2000 2001} 2002 2003/**************************************************************************************************/ 2004 2005static int 2006jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp ) 2007{ 2008#ifdef DEBUG 2009 static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ; 2010#endif 2011 2012 struct jjyunit *up ; 2013 struct refclockproc *pp ; 2014 struct peer *peer; 2015 2016 char * pBuf ; 2017 char sLog [ 100 ] ; 2018 int iLen ; 2019 int rc ; 2020 2021 const char * pCmd ; 2022 int iCmdLen ; 2023 2024 /* Initialize pointers */ 2025 2026 peer = rbufp->recv_peer ; 2027 pp = peer->procptr ; 2028 up = pp->unitptr ; 2029 2030 if ( up->linediscipline == LDISC_RAW ) { 2031 pBuf = up->sTextBuf ; 2032 iLen = up->iTextBufLen ; 2033 } else { 2034 pBuf = pp->a_lastcode ; 2035 iLen = pp->lencode ; 2036 } 2037 2038 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_tristate_gpsclock01", iLen ) ; 2039 2040 /* Ignore NMEA data stream */ 2041 2042 if ( iLen > 5 2043 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 2044#ifdef DEBUG 2045 if ( debug ) { 2046 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 2047 sFunctionName, pBuf ) ; 2048 } 2049#endif 2050 return JJY_RECEIVE_WAIT ; 2051 } 2052 2053 /* 2054 * Skip command prompt '$Cmd>' from the TS-GPSclock-01 2055 */ 2056 if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 2057 return JJY_RECEIVE_WAIT ; 2058 } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 2059 pBuf += 5 ; 2060 iLen -= 5 ; 2061 } 2062 2063 /* 2064 * Ignore NMEA data stream after command prompt 2065 */ 2066 if ( iLen > 5 2067 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 2068#ifdef DEBUG 2069 if ( debug ) { 2070 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 2071 sFunctionName, pBuf ) ; 2072 } 2073#endif 2074 return JJY_RECEIVE_WAIT ; 2075 } 2076 2077 /* Check expected reply */ 2078 2079 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2080 /* Command sequence has not been started, or has been completed */ 2081 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 2082 pBuf ) ; 2083 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2084 up->bLineError = TRUE ; 2085 return JJY_RECEIVE_ERROR ; 2086 } 2087 2088 /* Check reply length */ 2089 2090 if ( iLen != tristate_gps01_command_sequence[up->iCommandSeq].iExpectedReplyLength ) { 2091 /* Unexpected reply length */ 2092 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 2093 iLen ) ; 2094 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2095 up->bLineError = TRUE ; 2096 return JJY_RECEIVE_ERROR ; 2097 } 2098 2099 /* Parse reply */ 2100 2101 switch ( tristate_gps01_command_sequence[up->iCommandSeq].commandNumber ) { 2102 2103 case TS_GPS01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */ 2104 2105 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ; 2106 2107 if ( rc != 3 || up->year < 2000 || 2099 <= up->year 2108 || up->month < 1 || 12 < up->month 2109 || up->day < 1 || 31 < up->day ) { 2110 /* Invalid date */ 2111 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 2112 rc, up->year, up->month, up->day ) ; 2113 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2114 up->bLineError = TRUE ; 2115 return JJY_RECEIVE_ERROR ; 2116 } 2117 2118 break ; 2119 2120 case TS_GPS01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 2121 2122 if ( up->iTimestampCount >= 2 ) { 2123 /* Too many time reply */ 2124 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_TOO_MANY_REPLY, 2125 up->iTimestampCount ) ; 2126 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2127 up->bLineError = TRUE ; 2128 return JJY_RECEIVE_ERROR ; 2129 } 2130 2131 rc = sscanf ( pBuf, "%2d:%2d:%2d", 2132 &up->hour, &up->minute, &up->second ) ; 2133 2134 if ( rc != 3 2135 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2136 /* Invalid time */ 2137 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 2138 rc, up->hour, up->minute, up->second ) ; 2139 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2140 up->bLineError = TRUE ; 2141 return JJY_RECEIVE_ERROR ; 2142 } 2143 2144 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 2145 2146 up->iTimestampCount++ ; 2147 2148 up->msecond = 0 ; 2149 2150 break ; 2151 2152 case TS_GPS01_COMMAND_NUMBER_STUS : 2153 2154 if ( strncmp( pBuf, TS_GPS01_REPLY_STUS_RTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2155 || strncmp( pBuf, TS_GPS01_REPLY_STUS_GPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2156 || strncmp( pBuf, TS_GPS01_REPLY_STUS_UTC, TS_GPS01_REPLY_LENGTH_STUS ) == 0 2157 || strncmp( pBuf, TS_GPS01_REPLY_STUS_PPS, TS_GPS01_REPLY_LENGTH_STUS ) == 0 ) { 2158 /* Good */ 2159 } else { 2160 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2161 pBuf ) ; 2162 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2163 up->bLineError = TRUE ; 2164 return JJY_RECEIVE_ERROR ; 2165 } 2166 2167 break ; 2168 2169 default : /* Unexpected reply */ 2170 2171 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2172 pBuf ) ; 2173 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2174 up->bLineError = TRUE ; 2175 return JJY_RECEIVE_ERROR ; 2176 2177 } 2178 2179 if ( up->iTimestampCount == 2 ) { 2180 /* Process date and time */ 2181 2182 if ( up->iTimestamp[1] - 2 <= up->iTimestamp[0] 2183 && up->iTimestamp[0] <= up->iTimestamp[1] ) { 2184 /* 3 commands (time,date,stim) was excuted in two seconds */ 2185 jjy_synctime( peer, pp, up ) ; 2186 return JJY_RECEIVE_DONE ; 2187 } else if ( up->iTimestamp[0] > up->iTimestamp[1] ) { 2188 /* Over midnight, and date is unsure */ 2189 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_OVER_MIDNIGHT_2, 2190 up->iTimestamp[0], up->iTimestamp[1] ) ; 2191 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 2192 return JJY_RECEIVE_SKIP ; 2193 } else { 2194 /* Slow reply */ 2195 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SLOW_REPLY_2, 2196 up->iTimestamp[0], up->iTimestamp[1] ) ; 2197 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2198 up->bLineError = TRUE ; 2199 return JJY_RECEIVE_ERROR ; 2200 } 2201 2202 } 2203 2204 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2205 /* Command sequence completed */ 2206 jjy_synctime( peer, pp, up ) ; 2207 return JJY_RECEIVE_DONE ; 2208 } 2209 2210 /* Issue next command */ 2211 2212 if ( tristate_gps01_command_sequence[up->iCommandSeq].command != NULL ) { 2213 up->iCommandSeq ++ ; 2214 } 2215 2216 if ( tristate_gps01_command_sequence[up->iCommandSeq].command == NULL ) { 2217 /* Command sequence completed */ 2218 up->iProcessState = JJY_PROCESS_STATE_DONE ; 2219 return JJY_RECEIVE_DONE ; 2220 } 2221 2222 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ; 2223 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ; 2224 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 2225 refclock_report ( peer, CEVNT_FAULT ) ; 2226 } 2227 2228 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 2229 2230 return JJY_RECEIVE_WAIT ; 2231 2232} 2233 2234/**************************************************************************************************/ 2235 2236static void 2237jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer ) 2238{ 2239#ifdef DEBUG 2240 static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ; 2241#endif 2242 2243 struct refclockproc *pp ; 2244 struct jjyunit *up ; 2245 2246 const char * pCmd ; 2247 int iCmdLen ; 2248 2249 pp = peer->procptr ; 2250 up = pp->unitptr ; 2251 2252 up->iTimestampCount = 0 ; 2253 2254 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 2255 /* Skip "stus" command */ 2256 up->iCommandSeq = 1 ; 2257 up->iLineCount = 1 ; 2258 } 2259 2260#ifdef DEBUG 2261 if ( debug ) { 2262 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->iLineCount=%d\n", 2263 sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 2264 up->iLineCount ) ; 2265 } 2266#endif 2267 2268 /* 2269 * Send a first command 2270 */ 2271 2272 up->iCommandSeq ++ ; 2273 2274 pCmd = tristate_gps01_command_sequence[up->iCommandSeq].command ; 2275 iCmdLen = tristate_gps01_command_sequence[up->iCommandSeq].commandLength ; 2276 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 2277 refclock_report ( peer, CEVNT_FAULT ) ; 2278 } 2279 2280 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 2281 2282} 2283 2284/*################################################################################################*/ 2285/*################################################################################################*/ 2286/*## ##*/ 2287/*## The SEIKO TIME SYSTEMS TDC-300 ##*/ 2288/*## ##*/ 2289/*## server 127.127.40.X mode 6 ##*/ 2290/*## ##*/ 2291/*################################################################################################*/ 2292/*################################################################################################*/ 2293/* */ 2294/* Type Response Remarks */ 2295/* -------------------- ---------------------------------------- ---------------------------- */ 2296/* Type 1 <STX>HH:MM:SS<ETX> */ 2297/* Type 2 <STX>YYMMDDHHMMSSWLSCU<ETX> W:0(Sun)-6(Sat) */ 2298/* Type 3 <STX>YYMMDDWHHMMSS<ETX> W:0(Sun)-6(Sat) */ 2299/* <STX><xE5><ETX> 5 to 10 mSec. before second */ 2300/* */ 2301/*################################################################################################*/ 2302 2303static struct jjyRawDataBreak seiko_tsys_tdc_300_raw_break [ ] = 2304{ 2305 { "\x03", 1 }, { NULL, 0 } 2306} ; 2307 2308/**************************************************************************************************/ 2309 2310static int 2311jjy_start_seiko_tsys_tdc_300 ( int unit, struct peer *peer, struct jjyunit *up ) 2312{ 2313 2314 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: SEIKO TIME SYSTEMS TDC-300" ) ; 2315 2316 up->unittype = UNITTYPE_SEIKO_TIMESYS_TDC_300 ; 2317 up->linespeed = SPEED232_SEIKO_TIMESYS_TDC_300 ; 2318 up->linediscipline = LDISC_RAW ; 2319 2320 up->pRawBreak = seiko_tsys_tdc_300_raw_break ; 2321 up->bWaitBreakString = TRUE ; 2322 2323 up->bSkipCntrlCharOnly = FALSE ; 2324 2325 return 0 ; 2326 2327} 2328 2329/**************************************************************************************************/ 2330 2331static int 2332jjy_receive_seiko_tsys_tdc_300 ( struct recvbuf *rbufp ) 2333{ 2334 2335 struct peer *peer; 2336 struct refclockproc *pp ; 2337 struct jjyunit *up ; 2338 2339 char *pBuf, sLog [ 100 ] ; 2340 int iLen, i ; 2341 int rc, iWeekday ; 2342 time_t now ; 2343 struct tm *pTime ; 2344 2345 /* Initialize pointers */ 2346 2347 peer = rbufp->recv_peer ; 2348 pp = peer->procptr ; 2349 up = pp->unitptr ; 2350 2351 if ( up->linediscipline == LDISC_RAW ) { 2352 pBuf = up->sTextBuf ; 2353 iLen = up->iTextBufLen ; 2354 } else { 2355 pBuf = pp->a_lastcode ; 2356 iLen = pp->lencode ; 2357 } 2358 2359 DEBUG_PRINTF_JJY_RECEIVE( "jjy_receive_seiko_tsys_tdc_300", iLen ) ; 2360 2361 /* 2362 * TDC-300 sends a timestamp every second. 2363 * So, a timestamp is ignored unless it is right after polled. 2364 */ 2365 2366 if ( up->iProcessState != JJY_PROCESS_STATE_RECEIVE ) { 2367 return JJY_RECEIVE_SKIP ; 2368 } 2369 2370 /* Process timestamp */ 2371 2372 up->iReceiveSeq ++ ; 2373 2374 switch ( iLen ) { 2375 2376 case 8 : /* Type 1 : <STX>HH:MM:SS<ETX> */ 2377 2378 for ( i = 0 ; i < iLen ; i ++ ) { 2379 pBuf[i] &= 0x7F ; 2380 } 2381 2382 rc = sscanf ( pBuf+1, "%2d:%2d:%2d", 2383 &up->hour, &up->minute, &up->second ) ; 2384 2385 if ( rc != 3 2386 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2387 /* Invalid time */ 2388 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 2389 rc, up->hour, up->minute, up->second ) ; 2390 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2391 up->bLineError = TRUE ; 2392 return JJY_RECEIVE_ERROR ; 2393 } else if ( up->hour == 23 && up->minute == 59 && up->second >= 55 ) { 2394 /* Uncertainty date guard */ 2395 return JJY_RECEIVE_WAIT ; 2396 } 2397 2398 time( &now ) ; 2399 pTime = localtime( &now ) ; 2400 up->year = pTime->tm_year ; 2401 up->month = pTime->tm_mon + 1 ; 2402 up->day = pTime->tm_mday ; 2403 2404 break ; 2405 2406 case 17 : /* Type 2 : <STX>YYMMDDHHMMSSWLSCU<ETX> */ 2407 2408 for ( i = 0 ; i < iLen ; i ++ ) { 2409 pBuf[i] &= 0x7F ; 2410 } 2411 2412 rc = sscanf ( pBuf+1, "%2d%2d%2d%2d%2d%2d%1d", 2413 &up->year, &up->month, &up->day, 2414 &up->hour, &up->minute, &up->second, &iWeekday ) ; 2415 2416 if ( rc != 7 2417 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 2418 || iWeekday > 6 2419 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2420 /* Invalid date and time */ 2421 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 2422 rc, up->year, up->month, up->day, 2423 up->hour, up->minute, up->second ) ; 2424 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2425 up->bLineError = TRUE ; 2426 return JJY_RECEIVE_ERROR ; 2427 } 2428 2429 break ; 2430 2431 case 13 : /* Type 3 : <STX>YYMMDDWHHMMSS<ETX> */ 2432 2433 rc = sscanf ( pBuf, "%2d%2d%2d%1d%2d%2d%2d", 2434 &up->year, &up->month, &up->day, &iWeekday, 2435 &up->hour, &up->minute, &up->second ) ; 2436 2437 if ( rc != 7 2438 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 2439 || iWeekday > 6 2440 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 2441 /* Invalid date and time */ 2442 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATETIME, 2443 rc, up->year, up->month, up->day, 2444 up->hour, up->minute, up->second ) ; 2445 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2446 up->bLineError = TRUE ; 2447 return JJY_RECEIVE_ERROR ; 2448 } 2449 2450 return JJY_RECEIVE_WAIT ; 2451 2452 case 1 : /* Type 3 : <STX><xE5><ETX> */ 2453 2454 if ( ( *pBuf & 0xFF ) != 0xE5 ) { 2455 /* Invalid second signal */ 2456 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_REPLY, 2457 up->sLineBuf ) ; 2458 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2459 up->bLineError = TRUE ; 2460 return JJY_RECEIVE_ERROR ; 2461 } else if ( up->iReceiveSeq == 1 ) { 2462 /* Wait for next timestamp */ 2463 up->iReceiveSeq -- ; 2464 return JJY_RECEIVE_WAIT ; 2465 } else if ( up->iReceiveSeq >= 3 ) { 2466 /* Unexpected second signal */ 2467 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 2468 up->sLineBuf ) ; 2469 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2470 up->bLineError = TRUE ; 2471 return JJY_RECEIVE_ERROR ; 2472 } 2473 2474 break ; 2475 2476 default : /* Unexpected reply length */ 2477 2478 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_INVALID_LENGTH, 2479 iLen ) ; 2480 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 2481 up->bLineError = TRUE ; 2482 return JJY_RECEIVE_ERROR ; 2483 2484 } 2485 2486 up->year += 2000 ; 2487 up->msecond = 0 ; 2488 2489 jjy_synctime( peer, pp, up ) ; 2490 2491 return JJY_RECEIVE_DONE ; 2492 2493} 2494 2495/**************************************************************************************************/ 2496 2497static void 2498jjy_poll_seiko_tsys_tdc_300 ( int unit, struct peer *peer ) 2499{ 2500 2501 struct refclockproc *pp ; 2502 struct jjyunit *up ; 2503 2504 pp = peer->procptr ; 2505 up = pp->unitptr ; 2506 2507 up->bLineError = FALSE ; 2508 2509} 2510 2511/*################################################################################################*/ 2512/*################################################################################################*/ 2513/*## ##*/ 2514/*## Telephone JJY ##*/ 2515/*## ##*/ 2516/*## server 127.127.40.X mode 100 to 180 ##*/ 2517/*## ##*/ 2518/*################################################################################################*/ 2519/*################################################################################################*/ 2520/* */ 2521/* Prompt Command Response Remarks */ 2522/* -------------------- -------------------- -------------------- -------------------------- */ 2523/* Name<SP>?<SP> TJJY<CR> Welcome messages TJJY is a guest user ID */ 2524/* > 4DATE<CR> YYYYMMDD<CR> */ 2525/* > LEAPSEC<CR> XX<CR> One of <SP>0, +1, -1 */ 2526/* > TIME<CR> HHMMSS<CR> 3 times on second */ 2527/* > BYE<CR> Sayounara messages */ 2528/* */ 2529/*################################################################################################*/ 2530 2531static struct jjyRawDataBreak teljjy_raw_break [ ] = 2532{ 2533 { "\r\n", 2 }, 2534 { "\r" , 1 }, 2535 { "\n" , 1 }, 2536 { "Name ? ", 7 }, 2537 { ">" , 1 }, 2538 { "+++" , 3 }, 2539 { NULL , 0 } 2540} ; 2541 2542#define TELJJY_STATE_IDLE 0 2543#define TELJJY_STATE_DAILOUT 1 2544#define TELJJY_STATE_LOGIN 2 2545#define TELJJY_STATE_CONNECT 3 2546#define TELJJY_STATE_BYE 4 2547 2548#define TELJJY_EVENT_NULL 0 2549#define TELJJY_EVENT_START 1 2550#define TELJJY_EVENT_CONNECT 2 2551#define TELJJY_EVENT_DISCONNECT 3 2552#define TELJJY_EVENT_COMMAND 4 2553#define TELJJY_EVENT_LOGIN 5 /* Posted by the jjy_receive_telephone */ 2554#define TELJJY_EVENT_PROMPT 6 /* Posted by the jjy_receive_telephone */ 2555#define TELJJY_EVENT_DATA 7 /* Posted by the jjy_receive_telephone */ 2556#define TELJJY_EVENT_ERROR 8 /* Posted by the jjy_receive_telephone */ 2557#define TELJJY_EVENT_SILENT 9 /* Posted by the jjy_timer_telephone */ 2558#define TELJJY_EVENT_TIMEOUT 10 /* Posted by the jjy_timer_telephone */ 2559 2560static void teljjy_control ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2561 2562static int teljjy_idle_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2563static int teljjy_idle_dialout ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2564static int teljjy_dial_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2565static int teljjy_dial_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2566static int teljjy_dial_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2567static int teljjy_login_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2568static int teljjy_login_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2569static int teljjy_login_conn ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2570static int teljjy_login_login ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2571static int teljjy_login_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2572static int teljjy_login_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2573static int teljjy_conn_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2574static int teljjy_conn_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2575static int teljjy_conn_send ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2576static int teljjy_conn_data ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2577static int teljjy_conn_silent ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2578static int teljjy_conn_error ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2579static int teljjy_bye_ignore ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2580static int teljjy_bye_disc ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2581static int teljjy_bye_modem ( struct peer *peer, struct refclockproc *, struct jjyunit * ) ; 2582 2583static int ( *pTeljjyHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit *) = 2584{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2585/* NULL */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2586/* START */ { teljjy_idle_dialout, teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2587/* CONNECT */ { teljjy_idle_ignore , teljjy_dial_login , teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_ignore }, 2588/* DISCONNECT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_disc , teljjy_conn_disc , teljjy_bye_disc }, 2589/* COMMAND */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_ignore, teljjy_bye_modem }, 2590/* LOGIN */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_login , teljjy_conn_error , teljjy_bye_ignore }, 2591/* PROMPT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_conn , teljjy_conn_send , teljjy_bye_ignore }, 2592/* DATA */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_ignore, teljjy_conn_data , teljjy_bye_ignore }, 2593/* ERROR */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_error , teljjy_conn_error , teljjy_bye_ignore }, 2594/* SILENT */ { teljjy_idle_ignore , teljjy_dial_ignore, teljjy_login_silent, teljjy_conn_silent, teljjy_bye_ignore }, 2595/* TIMEOUT */ { teljjy_idle_ignore , teljjy_dial_disc , teljjy_login_error , teljjy_conn_error , teljjy_bye_modem } 2596} ; 2597 2598static short iTeljjyNextState [ ] [ 5 ] = 2599{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2600/* NULL */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2601/* START */ { TELJJY_STATE_DAILOUT, TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2602/* CONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_LOGIN , TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2603/* DISCONNECT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_IDLE }, 2604/* COMMAND */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2605/* LOGIN */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2606/* PROMPT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_CONNECT, TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2607/* DATA */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2608/* ERROR */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE }, 2609/* SILENT */ { TELJJY_STATE_IDLE , TELJJY_STATE_DAILOUT, TELJJY_STATE_LOGIN , TELJJY_STATE_CONNECT, TELJJY_STATE_BYE }, 2610/* TIMEOUT */ { TELJJY_STATE_IDLE , TELJJY_STATE_IDLE , TELJJY_STATE_BYE , TELJJY_STATE_BYE , TELJJY_STATE_BYE } 2611} ; 2612 2613static short iTeljjyPostEvent [ ] [ 5 ] = 2614{ /*STATE_IDLE STATE_DAILOUT STATE_LOGIN STATE_CONNECT STATE_BYE */ 2615/* NULL */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2616/* START */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2617/* CONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2618/* DISCONNECT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2619/* COMMAND */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2620/* LOGIN */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2621/* PROMPT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_PROMPT , TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2622/* DATA */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2623/* ERROR */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL }, 2624/* SILENT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_NULL , TELJJY_EVENT_NULL , TELJJY_EVENT_NULL }, 2625/* TIMEOUT */ { TELJJY_EVENT_NULL, TELJJY_EVENT_NULL, TELJJY_EVENT_COMMAND, TELJJY_EVENT_COMMAND, TELJJY_EVENT_NULL } 2626} ; 2627 2628static short iTeljjySilentTimeout [ 5 ] = { 0, 0, 10, 5, 0 } ; 2629static short iTeljjyStateTimeout [ 5 ] = { 0, 120, 60, 60, 40 } ; 2630 2631#define TELJJY_STAY_CLOCK_STATE 0 2632#define TELJJY_CHANGE_CLOCK_STATE 1 2633 2634/* Command and replay */ 2635 2636#define TELJJY_REPLY_NONE 0 2637#define TELJJY_REPLY_4DATE 1 2638#define TELJJY_REPLY_TIME 2 2639#define TELJJY_REPLY_LEAPSEC 3 2640#define TELJJY_REPLY_LOOP 4 2641#define TELJJY_REPLY_PROMPT 5 2642#define TELJJY_REPLY_LOOPBACK 6 2643#define TELJJY_REPLY_COM 7 2644 2645#define TELJJY_COMMAND_START_SKIP_LOOPBACK 7 2646 2647static struct 2648{ 2649 const char *command ; 2650 int commandLength ; 2651 int iEchobackReplyLength ; 2652 int iExpectedReplyType ; 2653 int iExpectedReplyLength ; 2654} teljjy_command_sequence[] = 2655{ 2656 { NULL, 0, 0, 0, 0 }, /* Idle */ 2657 { "LOOP\r" , 5, 4, TELJJY_REPLY_LOOP , 0 }, /* Getting into loopback mode */ 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 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2662 { ">" , 1, 1, TELJJY_REPLY_LOOPBACK, 0 }, /* Loopback measuring of delay time */ 2663 { "COM\r" , 4, 3, TELJJY_REPLY_COM , 0 }, /* Exit from loopback mode */ 2664 /* TELJJY_COMMAND_START_SKIP_LOOPBACK */ 2665 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 }, 2666 { "4DATE\r" , 6, 5, TELJJY_REPLY_4DATE , 8 }, 2667 { "LEAPSEC\r", 8, 7, TELJJY_REPLY_LEAPSEC , 2 }, 2668 { "TIME\r" , 5, 4, TELJJY_REPLY_TIME , 6 }, 2669 { "BYE\r" , 4, 3, TELJJY_REPLY_NONE , 0 }, 2670 /* End of command */ 2671 { NULL, 0, 0, 0, 0 } 2672} ; 2673 2674#define TELJJY_LOOPBACK_DELAY_THRESHOLD 700 /* Milli second */ 2675 2676#ifdef DEBUG 2677#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 ) ; } } 2678#else 2679#define DEBUG_TELJJY_PRINTF(sFunc) 2680#endif 2681 2682/**************************************************************************************************/ 2683 2684static int 2685jjy_start_telephone ( int unit, struct peer *peer, struct jjyunit *up ) 2686{ 2687 2688 char sLog [ 80 ], sFirstThreeDigits [ 4 ] ; 2689 int iNumberOfDigitsOfPhoneNumber, iCommaCount, iCommaPosition ; 2690 size_t i; 2691 size_t iFirstThreeDigitsCount ; 2692 2693 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, "Refclock: Telephone JJY" ) ; 2694 2695 up->unittype = UNITTYPE_TELEPHONE ; 2696 up->linespeed = SPEED232_TELEPHONE ; 2697 up->linediscipline = LDISC_RAW ; 2698 2699 up->pRawBreak = teljjy_raw_break ; 2700 up->bWaitBreakString = TRUE ; 2701 2702 up->bSkipCntrlCharOnly = TRUE ; 2703 2704 up->iClockState = TELJJY_STATE_IDLE ; 2705 up->iClockEvent = TELJJY_EVENT_NULL ; 2706 2707 /* Check the telephone number */ 2708 2709 if ( sys_phone[0] == NULL ) { 2710 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf must be specified." ) ; 2711 up->bInitError = TRUE ; 2712 return 1 ; 2713 } 2714 2715 if ( sys_phone[1] != NULL ) { 2716 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be only one." ) ; 2717 up->bInitError = TRUE ; 2718 return 1 ; 2719 } 2720 2721 iNumberOfDigitsOfPhoneNumber = iCommaCount = iCommaPosition = iFirstThreeDigitsCount = 0 ; 2722 for ( i = 0 ; i < strlen( sys_phone[0] ) ; i ++ ) { 2723 if ( isdigit( (u_char)sys_phone[0][i] ) ) { 2724 if ( iFirstThreeDigitsCount < sizeof(sFirstThreeDigits)-1 ) { 2725 sFirstThreeDigits[iFirstThreeDigitsCount++] = sys_phone[0][i] ; 2726 } 2727 iNumberOfDigitsOfPhoneNumber ++ ; 2728 } else if ( sys_phone[0][i] == ',' ) { 2729 iCommaCount ++ ; 2730 if ( iCommaCount > 1 ) { 2731 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be zero or one comma." ) ; 2732 up->bInitError = TRUE ; 2733 return 1 ; 2734 } 2735 iFirstThreeDigitsCount = 0 ; 2736 iCommaPosition = i ; 2737 } else if ( sys_phone[0][i] != '-' ) { 2738 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone in the ntpd.conf should be a number or a hyphen." ) ; 2739 up->bInitError = TRUE ; 2740 return 1 ; 2741 } 2742 } 2743 sFirstThreeDigits[iFirstThreeDigitsCount] = 0 ; 2744 2745 if ( iCommaCount == 1 ) { 2746 if ( iCommaPosition != 1 || *sys_phone[0] != '0' ) { 2747 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : Getting an outside line should be '0,'." ) ; 2748 up->bInitError = TRUE ; 2749 return 1 ; 2750 } 2751 } 2752 2753 if ( iNumberOfDigitsOfPhoneNumber - iCommaPosition < 6 || 10 < iNumberOfDigitsOfPhoneNumber - iCommaPosition ) { 2754 /* Too short or too long */ 2755 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : Number of digits should be 6 to 10.", sys_phone[0] ) ; 2756 up->bInitError = TRUE ; 2757 return 1 ; 2758 } 2759 2760 if ( strncmp( sFirstThreeDigits + iCommaPosition, "00" , 2 ) == 0 2761 || strncmp( sFirstThreeDigits + iCommaPosition, "10" , 2 ) == 0 2762 || strncmp( sFirstThreeDigits + iCommaPosition, "11" , 2 ) == 0 2763 || strncmp( sFirstThreeDigits + iCommaPosition, "12" , 2 ) == 0 2764 || strncmp( sFirstThreeDigits + iCommaPosition, "171", 3 ) == 0 2765 || strncmp( sFirstThreeDigits + iCommaPosition, "177", 3 ) == 0 2766 || ( sFirstThreeDigits[0] == '0' && sFirstThreeDigits[2] == '0' ) ) { 2767 /* Not allowed because of emergency numbers or special service numbers */ 2768 msyslog( LOG_ERR, "refclock_jjy.c : jjy_start_telephone : phone=%s : First 2 or 3 digits are not allowed.", sys_phone[0] ) ; 2769 up->bInitError = TRUE ; 2770 return 1 ; 2771 } 2772 2773 snprintf( sLog, sizeof(sLog), "phone=%s", sys_phone[0] ) ; 2774 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 2775 2776 if ( peer->minpoll < 8 ) { 2777 /* minpoll must be greater or equal to 8 ( 256 seconds = about 4 minutes ) */ 2778 int oldminpoll = peer->minpoll ; 2779 peer->minpoll = 8 ; 2780 if ( peer->ppoll < peer->minpoll ) { 2781 peer->ppoll = peer->minpoll ; 2782 } 2783 if ( peer->maxpoll < peer->minpoll ) { 2784 peer->maxpoll = peer->minpoll ; 2785 } 2786 snprintf( sLog, sizeof(sLog), "minpoll=%d -> %d", oldminpoll, peer->minpoll ) ; 2787 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_JJY, sLog ) ; 2788 } 2789 2790 return 0 ; 2791 2792} 2793 2794/**************************************************************************************************/ 2795 2796static int 2797jjy_receive_telephone ( struct recvbuf *rbufp ) 2798{ 2799#ifdef DEBUG 2800 static const char *sFunctionName = "jjy_receive_telephone" ; 2801#endif 2802 2803 struct peer *peer; 2804 struct refclockproc *pp ; 2805 struct jjyunit *up ; 2806 char *pBuf ; 2807 int iLen ; 2808 short iPreviousModemState ; 2809 2810 peer = rbufp->recv_peer ; 2811 pp = peer->procptr ; 2812 up = pp->unitptr ; 2813 2814 DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2815 2816 if ( up->iClockState == TELJJY_STATE_IDLE 2817 || up->iClockState == TELJJY_STATE_DAILOUT 2818 || up->iClockState == TELJJY_STATE_BYE ) { 2819 2820 iPreviousModemState = getModemState( up ) ; 2821 2822 modem_receive ( rbufp ) ; 2823 2824 if ( iPreviousModemState != up->iModemState ) { 2825 /* Modem state is changed just now. */ 2826 if ( isModemStateDisconnect( up->iModemState ) ) { 2827 up->iClockEvent = TELJJY_EVENT_DISCONNECT ; 2828 teljjy_control ( peer, pp, up ) ; 2829 } else if ( isModemStateConnect( up->iModemState ) ) { 2830 up->iClockEvent = TELJJY_EVENT_CONNECT ; 2831 teljjy_control ( peer, pp, up ) ; 2832 } 2833 } 2834 2835 return JJY_RECEIVE_WAIT ; 2836 2837 } 2838 2839 if ( up->linediscipline == LDISC_RAW ) { 2840 pBuf = up->sTextBuf ; 2841 iLen = up->iTextBufLen ; 2842 } else { 2843 pBuf = pp->a_lastcode ; 2844 iLen = pp->lencode ; 2845 } 2846 2847 up->iTeljjySilentTimer = 0 ; 2848 if ( iLen == 7 && strncmp( pBuf, "Name ? ", 7 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_LOGIN ; } 2849 else if ( iLen == 1 && strncmp( pBuf, ">" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_PROMPT ; } 2850 else if ( iLen >= 1 && strncmp( pBuf, "?" , 1 ) == 0 ) { up->iClockEvent = TELJJY_EVENT_ERROR ; } 2851 else { up->iClockEvent = TELJJY_EVENT_DATA ; } 2852 2853 teljjy_control ( peer, pp, up ) ; 2854 2855 return JJY_RECEIVE_WAIT ; 2856 2857} 2858 2859/**************************************************************************************************/ 2860 2861static void 2862jjy_poll_telephone ( int unit, struct peer *peer ) 2863{ 2864#ifdef DEBUG 2865 static const char *sFunctionName = "jjy_poll_telephone" ; 2866#endif 2867 2868 struct refclockproc *pp ; 2869 struct jjyunit *up ; 2870 2871 pp = peer->procptr ; 2872 up = pp->unitptr ; 2873 2874 DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2875 2876 if ( up->iClockState == TELJJY_STATE_IDLE ) { 2877 up->iRawBufLen = 0 ; 2878 up->iLineBufLen = 0 ; 2879 up->iTextBufLen = 0 ; 2880 } 2881 2882 up->iClockEvent = TELJJY_EVENT_START ; 2883 teljjy_control ( peer, pp, up ) ; 2884 2885} 2886 2887/**************************************************************************************************/ 2888 2889static void 2890jjy_timer_telephone ( int unit, struct peer *peer ) 2891{ 2892#ifdef DEBUG 2893 static const char *sFunctionName = "jjy_timer_telephone" ; 2894#endif 2895 2896 struct refclockproc *pp ; 2897 struct jjyunit *up ; 2898 short iPreviousModemState ; 2899 2900 pp = peer->procptr ; 2901 up = pp->unitptr ; 2902 2903 DEBUG_TELJJY_PRINTF( sFunctionName ) ; 2904 2905 if ( iTeljjySilentTimeout[up->iClockState] != 0 ) { 2906 up->iTeljjySilentTimer++ ; 2907 if ( iTeljjySilentTimeout[up->iClockState] <= up->iTeljjySilentTimer ) { 2908 up->iClockEvent = TELJJY_EVENT_SILENT ; 2909 teljjy_control ( peer, pp, up ) ; 2910 } 2911 } 2912 2913 if ( iTeljjyStateTimeout[up->iClockState] != 0 ) { 2914 up->iTeljjyStateTimer++ ; 2915 if ( iTeljjyStateTimeout[up->iClockState] <= up->iTeljjyStateTimer ) { 2916 up->iClockEvent = TELJJY_EVENT_TIMEOUT ; 2917 teljjy_control ( peer, pp, up ) ; 2918 } 2919 } 2920 2921 if ( isModemStateTimerOn( up ) ) { 2922 2923 iPreviousModemState = getModemState( up ) ; 2924 2925 modem_timer ( unit, peer ) ; 2926 2927 if ( iPreviousModemState != up->iModemState ) { 2928 /* Modem state is changed just now. */ 2929 if ( isModemStateDisconnect( up->iModemState ) ) { 2930 up->iClockEvent = TELJJY_EVENT_DISCONNECT ; 2931 teljjy_control ( peer, pp, up ) ; 2932 } else if ( isModemStateConnect( up->iModemState ) ) { 2933 up->iClockEvent = TELJJY_EVENT_CONNECT ; 2934 teljjy_control ( peer, pp, up ) ; 2935 } 2936 } 2937 2938 } 2939 2940} 2941 2942/**************************************************************************************************/ 2943 2944static void 2945teljjy_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 2946{ 2947 2948 int i, rc ; 2949 short iPostEvent = TELJJY_EVENT_NULL ; 2950 2951 DEBUG_TELJJY_PRINTF( "teljjy_control" ) ; 2952 2953 rc = (*pTeljjyHandler[up->iClockEvent][up->iClockState])( peer, pp, up ) ; 2954 2955 if ( rc == TELJJY_CHANGE_CLOCK_STATE ) { 2956 iPostEvent = iTeljjyPostEvent[up->iClockEvent][up->iClockState] ; 2957#ifdef DEBUG 2958 if ( debug ) { 2959 printf( "refclock_jjy.c : teljjy_control : iClockState=%hd -> %hd iPostEvent=%hd\n", 2960 up->iClockState, iTeljjyNextState[up->iClockEvent][up->iClockState], iPostEvent ) ; 2961 } 2962#endif 2963 up->iTeljjySilentTimer = 0 ; 2964 if ( up->iClockState != iTeljjyNextState[up->iClockEvent][up->iClockState] ) { 2965 /* Telephone JJY state is changing now */ 2966 up->iTeljjyStateTimer = 0 ; 2967 up->bLineError = FALSE ; 2968 up->iClockCommandSeq = 0 ; 2969 up->iTimestampCount = 0 ; 2970 up->iLoopbackCount = 0 ; 2971 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 2972 up->bLoopbackTimeout[i] = FALSE ; 2973 } 2974 if (iTeljjyNextState[up->iClockEvent][up->iClockState] == TELJJY_STATE_IDLE ) { 2975 /* Telephone JJY state is changing to IDLE just now */ 2976 up->iProcessState = JJY_PROCESS_STATE_DONE ; 2977 } 2978 } 2979 up->iClockState = iTeljjyNextState[up->iClockEvent][up->iClockState] ; 2980 2981 } 2982 2983 if ( iPostEvent != TELJJY_EVENT_NULL ) { 2984 up->iClockEvent = iPostEvent ; 2985 teljjy_control ( peer, pp, up ) ; 2986 } 2987 2988 up->iClockEvent = TELJJY_EVENT_NULL ; 2989 2990} 2991 2992/**************************************************************************************************/ 2993 2994static void 2995teljjy_setDelay ( struct peer *peer, struct jjyunit *up ) 2996{ 2997 2998 char sLog [ 60 ] ; 2999 int milliSecond, microSecond ; 3000 3001 gettimeofday( &(up->delayTime[up->iLoopbackCount]), NULL ) ; 3002 3003 up->delayTime[up->iLoopbackCount].tv_sec -= up->sendTime[up->iLoopbackCount].tv_sec ; 3004 up->delayTime[up->iLoopbackCount].tv_usec -= up->sendTime[up->iLoopbackCount].tv_usec ; 3005 if ( up->delayTime[up->iLoopbackCount].tv_usec < 0 ) { 3006 up->delayTime[up->iLoopbackCount].tv_sec -- ; 3007 up->delayTime[up->iLoopbackCount].tv_usec += 1000000 ; 3008 } 3009 3010 milliSecond = up->delayTime[up->iLoopbackCount].tv_usec / 1000 ; 3011 microSecond = up->delayTime[up->iLoopbackCount].tv_usec - milliSecond * 1000 ; 3012 milliSecond += up->delayTime[up->iLoopbackCount].tv_sec * 1000 ; 3013 3014 snprintf( sLog, sizeof(sLog), JJY_CLOCKSTATS_MESSAGE_LOOPBACK_DELAY, 3015 milliSecond, microSecond ) ; 3016 3017 if ( milliSecond > TELJJY_LOOPBACK_DELAY_THRESHOLD ) { 3018 /* Delay > 700 mS */ 3019 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 3020 } else { 3021 /* Delay <= 700 mS */ 3022 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 3023 } 3024 3025} 3026 3027/**************************************************************************************************/ 3028 3029static int 3030teljjy_getDelay ( struct peer *peer, struct jjyunit *up ) 3031{ 3032 3033 struct timeval maxTime, minTime, averTime ; 3034 int i ; 3035 int minIndex = 0, maxIndex = 0, iAverCount = 0 ; 3036 int iThresholdSecond, iThresholdMicroSecond ; 3037 int iPercent ; 3038 3039 minTime.tv_sec = minTime.tv_usec = 0 ; 3040 maxTime.tv_sec = maxTime.tv_usec = 0 ; 3041 3042 iThresholdSecond = TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ; 3043 iThresholdMicroSecond = ( TELJJY_LOOPBACK_DELAY_THRESHOLD - ( TELJJY_LOOPBACK_DELAY_THRESHOLD / 1000 ) * 1000 ) * 1000 ; 3044 3045 up->iLoopbackValidCount = 0 ; 3046 3047 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) { 3048 if ( up->bLoopbackTimeout[i] 3049 || up->delayTime[i].tv_sec > iThresholdSecond 3050 || ( up->delayTime[i].tv_sec == iThresholdSecond 3051 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) { 3052 continue ; 3053 } 3054 if ( up->iLoopbackValidCount == 0 ) { 3055 minTime.tv_sec = up->delayTime[i].tv_sec ; 3056 minTime.tv_usec = up->delayTime[i].tv_usec ; 3057 maxTime.tv_sec = up->delayTime[i].tv_sec ; 3058 maxTime.tv_usec = up->delayTime[i].tv_usec ; 3059 minIndex = maxIndex = i ; 3060 } else if ( minTime.tv_sec > up->delayTime[i].tv_sec 3061 || ( minTime.tv_sec == up->delayTime[i].tv_sec 3062 && minTime.tv_usec > up->delayTime[i].tv_usec ) ) { 3063 minTime.tv_sec = up->delayTime[i].tv_sec ; 3064 minTime.tv_usec = up->delayTime[i].tv_usec ; 3065 minIndex = i ; 3066 } else if ( maxTime.tv_sec < up->delayTime[i].tv_sec 3067 || ( maxTime.tv_sec == up->delayTime[i].tv_sec 3068 && maxTime.tv_usec < up->delayTime[i].tv_usec ) ) { 3069 maxTime.tv_sec = up->delayTime[i].tv_sec ; 3070 maxTime.tv_usec = up->delayTime[i].tv_usec ; 3071 maxIndex = i ; 3072 } 3073 up->iLoopbackValidCount ++ ; 3074 } 3075 3076 if ( up->iLoopbackValidCount < 2 ) { 3077 return -1 ; 3078 } 3079 3080 averTime.tv_usec = 0; 3081 3082 for ( i = 0 ; i < MAX_LOOPBACK && i < up->iLoopbackCount ; i ++ ) { 3083 if ( up->bLoopbackTimeout[i] 3084 || up->delayTime[i].tv_sec > iThresholdSecond 3085 || ( up->delayTime[i].tv_sec == iThresholdSecond 3086 && up->delayTime[i].tv_usec > iThresholdMicroSecond ) ) { 3087 continue ; 3088 } 3089 if ( up->iLoopbackValidCount >= 3 && i == maxIndex ) { 3090 continue ; 3091 } 3092 if ( up->iLoopbackValidCount >= 4 && i == minIndex ) { 3093 continue ; 3094 } 3095 averTime.tv_usec += up->delayTime[i].tv_usec ; 3096 iAverCount ++ ; 3097 } 3098 3099 if ( iAverCount == 0 ) { 3100 /* This is never happened. */ 3101 /* Previous for-if-for blocks assure iAverCount > 0. */ 3102 /* This code avoids a claim by the coverity scan tool. */ 3103 return -1 ; 3104 } 3105 3106 /* mode 101 = 1%, mode 150 = 50%, mode 180 = 80% */ 3107 3108 iPercent = ( peer->ttl - 100 ) ; 3109 3110 /* Average delay time in milli second */ 3111 3112 return ( ( averTime.tv_usec / iAverCount ) * iPercent ) / 100000 ; 3113 3114} 3115 3116/******************************/ 3117static int 3118teljjy_idle_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3119{ 3120 3121 DEBUG_TELJJY_PRINTF( "teljjy_idle_ignore" ) ; 3122 3123 return TELJJY_STAY_CLOCK_STATE ; 3124 3125} 3126 3127/******************************/ 3128static int 3129teljjy_idle_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3130{ 3131 3132 DEBUG_TELJJY_PRINTF( "teljjy_idle_dialout" ) ; 3133 3134 modem_connect ( peer->refclkunit, peer ) ; 3135 3136 return TELJJY_CHANGE_CLOCK_STATE ; 3137 3138} 3139 3140/******************************/ 3141static int 3142teljjy_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3143{ 3144 3145 DEBUG_TELJJY_PRINTF( "teljjy_dial_ignore" ) ; 3146 3147 return TELJJY_STAY_CLOCK_STATE ; 3148 3149} 3150 3151/******************************/ 3152static int 3153teljjy_dial_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3154{ 3155 3156 DEBUG_TELJJY_PRINTF( "teljjy_dial_login" ) ; 3157 3158 return TELJJY_CHANGE_CLOCK_STATE ; 3159 3160} 3161 3162/******************************/ 3163static int 3164teljjy_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3165{ 3166 3167 DEBUG_TELJJY_PRINTF( "teljjy_dial_disc" ) ; 3168 3169 return TELJJY_CHANGE_CLOCK_STATE ; 3170 3171} 3172 3173/******************************/ 3174static int 3175teljjy_login_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3176{ 3177 3178 DEBUG_TELJJY_PRINTF( "teljjy_login_ignore" ) ; 3179 3180 return TELJJY_STAY_CLOCK_STATE ; 3181 3182} 3183 3184/******************************/ 3185static int 3186teljjy_login_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3187{ 3188 3189 DEBUG_TELJJY_PRINTF( "teljjy_login_disc" ) ; 3190 3191 return TELJJY_CHANGE_CLOCK_STATE ; 3192 3193} 3194 3195/******************************/ 3196static int 3197teljjy_login_conn ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3198{ 3199 3200 int i ; 3201 3202 DEBUG_TELJJY_PRINTF( "teljjy_login_conn" ) ; 3203 3204 up->bLineError = FALSE ; 3205 up->iClockCommandSeq = 0 ; 3206 up->iTimestampCount = 0 ; 3207 up->iLoopbackCount = 0 ; 3208 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 3209 up->bLoopbackTimeout[i] = FALSE ; 3210 } 3211 3212 return TELJJY_CHANGE_CLOCK_STATE ; 3213 3214} 3215 3216/******************************/ 3217static int 3218teljjy_login_login ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3219{ 3220 3221 const char * pCmd ; 3222 int iCmdLen ; 3223 3224 DEBUG_TELJJY_PRINTF( "teljjy_login_login" ) ; 3225 3226 /* Send a guest user ID */ 3227 pCmd = "TJJY\r" ; 3228 3229 /* Send login ID */ 3230 iCmdLen = strlen( pCmd ) ; 3231 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 3232 refclock_report( peer, CEVNT_FAULT ) ; 3233 } 3234 3235 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3236 3237 return TELJJY_STAY_CLOCK_STATE ; 3238 3239} 3240 3241/******************************/ 3242static int 3243teljjy_login_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3244{ 3245 3246 DEBUG_TELJJY_PRINTF( "teljjy_login_silent" ) ; 3247 3248 if ( write( pp->io.fd, "\r", 1 ) != 1 ) { 3249 refclock_report( peer, CEVNT_FAULT ) ; 3250 } 3251 3252 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, "\r" ) ; 3253 3254 up->iTeljjySilentTimer = 0 ; 3255 3256 return TELJJY_CHANGE_CLOCK_STATE ; 3257 3258} 3259 3260/******************************/ 3261static int 3262teljjy_login_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3263{ 3264 3265 DEBUG_TELJJY_PRINTF( "teljjy_login_error" ) ; 3266 3267 return TELJJY_CHANGE_CLOCK_STATE ; 3268 3269} 3270 3271/******************************/ 3272static int 3273teljjy_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3274{ 3275 3276 DEBUG_TELJJY_PRINTF( "teljjy_conn_ignore" ) ; 3277 3278 return TELJJY_STAY_CLOCK_STATE ; 3279 3280} 3281 3282/******************************/ 3283static int 3284teljjy_conn_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3285{ 3286 3287 DEBUG_TELJJY_PRINTF( "teljjy_conn_disc" ) ; 3288 3289 return TELJJY_CHANGE_CLOCK_STATE ; 3290 3291} 3292 3293/******************************/ 3294static int 3295teljjy_conn_send ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3296{ 3297 3298 const char * pCmd ; 3299 int i, iLen, iNextClockState ; 3300 3301 DEBUG_TELJJY_PRINTF( "teljjy_conn_send" ) ; 3302 3303 if ( up->iClockCommandSeq > 0 3304 && teljjy_command_sequence[up->iClockCommandSeq].command == NULL ) { 3305 /* Command sequence has been completed */ 3306 return TELJJY_CHANGE_CLOCK_STATE ; 3307 } 3308 3309 if ( up->iClockCommandSeq == 0 && peer->ttl == 100 ) { 3310 /* Skip loopback */ 3311 3312 up->iClockCommandSeq = TELJJY_COMMAND_START_SKIP_LOOPBACK ; 3313 3314 } else if ( up->iClockCommandSeq == 0 && peer->ttl != 100 ) { 3315 /* Loopback start */ 3316 3317 up->iLoopbackCount = 0 ; 3318 for ( i = 0 ; i < MAX_LOOPBACK ; i ++ ) { 3319 up->bLoopbackTimeout[i] = FALSE ; 3320 } 3321 3322 } else if ( up->iClockCommandSeq > 0 && peer->ttl != 100 3323 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK 3324 && up->iLoopbackCount < MAX_LOOPBACK ) { 3325 /* Loopback character comes */ 3326#ifdef DEBUG 3327 if ( debug ) { 3328 printf( "refclock_jjy.c : teljjy_conn_send : iLoopbackCount=%d\n", 3329 up->iLoopbackCount ) ; 3330 } 3331#endif 3332 3333 teljjy_setDelay( peer, up ) ; 3334 3335 up->iLoopbackCount ++ ; 3336 3337 } 3338 3339 up->iClockCommandSeq++ ; 3340 3341 pCmd = teljjy_command_sequence[up->iClockCommandSeq].command ; 3342 iLen = teljjy_command_sequence[up->iClockCommandSeq].commandLength ; 3343 3344 if ( pCmd != NULL ) { 3345 3346 if ( write( pp->io.fd, pCmd, iLen ) != iLen ) { 3347 refclock_report( peer, CEVNT_FAULT ) ; 3348 } 3349 3350 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3351 /* Loopback character and timestamp */ 3352 gettimeofday( &(up->sendTime[up->iLoopbackCount]), NULL ) ; 3353 up->bLoopbackMode = TRUE ; 3354 } else { 3355 /* Regular command */ 3356 up->bLoopbackMode = FALSE ; 3357 } 3358 3359 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3360 3361 if ( teljjy_command_sequence[up->iClockCommandSeq+1].command == NULL ) { 3362 /* Last command of the command sequence */ 3363 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ; 3364 } else { 3365 /* More commands to be issued */ 3366 iNextClockState = TELJJY_STAY_CLOCK_STATE ; 3367 } 3368 3369 } else { 3370 3371 iNextClockState = TELJJY_CHANGE_CLOCK_STATE ; 3372 3373 } 3374 3375 return iNextClockState ; 3376 3377} 3378 3379/******************************/ 3380static int 3381teljjy_conn_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3382{ 3383 3384 char *pBuf ; 3385 int iLen, rc ; 3386 char sLog [ 80 ] ; 3387 char bAdjustment ; 3388 3389 3390 DEBUG_TELJJY_PRINTF( "teljjy_conn_data" ) ; 3391 3392 if ( up->linediscipline == LDISC_RAW ) { 3393 pBuf = up->sTextBuf ; 3394 iLen = up->iTextBufLen ; 3395 } else { 3396 pBuf = pp->a_lastcode ; 3397 iLen = pp->lencode ; 3398 } 3399 3400 if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen 3401 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK 3402 && up->sTextBuf[0] == *(teljjy_command_sequence[up->iClockCommandSeq].command) 3403 && up->iLoopbackCount < MAX_LOOPBACK ) { 3404 /* Loopback */ 3405 3406 teljjy_setDelay( peer, up ) ; 3407 3408 up->iLoopbackCount ++ ; 3409 3410 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength == iLen 3411 && strncmp( pBuf, teljjy_command_sequence[up->iClockCommandSeq].command, iLen ) == 0 ) { 3412 /* Maybe echoback */ 3413 3414 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, JJY_CLOCKSTATS_MESSAGE_ECHOBACK ) ; 3415 3416 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3417 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_4DATE ) { 3418 /* 4DATE<CR> -> YYYYMMDD<CR> */ 3419 3420 rc = sscanf ( pBuf, "%4d%2d%2d", &up->year, &up->month, &up->day ) ; 3421 3422 if ( rc != 3 || up->year < 2000 || 2099 <= up->year 3423 || up->month < 1 || 12 < up->month || up->day < 1 || 31 < up->day ) { 3424 /* Invalid date */ 3425 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_DATE, 3426 rc, up->year, up->month, up->day ) ; 3427 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3428 up->bLineError = TRUE ; 3429 } 3430 3431 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3432 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LEAPSEC 3433 && ( strncmp( pBuf, " 0", 2 ) == 0 || strncmp( pBuf, "+1", 2 ) == 0 || strncmp( pBuf, "-1", 2 ) == 0 ) ) { 3434 /* LEAPSEC<CR> -> XX<CR> ( One of <SP>0, +1, -1 ) */ 3435 3436 rc = sscanf ( pBuf, "%2d", &up->leapsecond ) ; 3437 3438 if ( rc != 1 || up->leapsecond < -1 || 1 < up->leapsecond ) { 3439 /* Invalid leap second */ 3440 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_LEAP, 3441 pBuf ) ; 3442 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3443 up->bLineError = TRUE ; 3444 } 3445 3446 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyLength == iLen 3447 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_TIME ) { 3448 /* TIME<CR> -> HHMMSS<CR> ( 3 times on second ) */ 3449 3450 rc = sscanf ( pBuf, "%2d%2d%2d", &up->hour, &up->minute, &up->second ) ; 3451 3452 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 3453 /* Invalid time */ 3454 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_SSCANF_INVALID_TIME, 3455 rc, up->hour, up->minute, up->second ) ; 3456 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3457 up->bLineError = TRUE ; 3458 } 3459 up->iTimestamp[up->iTimestampCount] = ( up->hour * 60 + up->minute ) * 60 + up->second ; 3460 3461 up->iTimestampCount++ ; 3462 3463 if ( up->iTimestampCount == 6 && ! up->bLineError ) { 3464#if DEBUG 3465 printf( "refclock_jjy.c : teljjy_conn_data : bLineError=%d iTimestamp=%d, %d, %d\n", 3466 up->bLineError, 3467 up->iTimestamp[3], up->iTimestamp[4], up->iTimestamp[5] ) ; 3468#endif 3469 bAdjustment = TRUE ; 3470 3471 if ( peer->ttl == 100 ) { 3472 /* mode=100 */ 3473 up->msecond = 0 ; 3474 } else { 3475 /* mode=101 to 110 */ 3476 up->msecond = teljjy_getDelay( peer, up ) ; 3477 if (up->msecond < 0 ) { 3478 up->msecond = 0 ; 3479 bAdjustment = FALSE ; 3480 } 3481 } 3482 3483 if ( ( up->iTimestamp[3] - 15 ) <= up->iTimestamp[2] 3484 && up->iTimestamp[2] <= up->iTimestamp[3] 3485 && ( up->iTimestamp[3] + 1 ) == up->iTimestamp[4] 3486 && ( up->iTimestamp[4] + 1 ) == up->iTimestamp[5] ) { 3487 /* Non over midnight */ 3488 3489 jjy_synctime( peer, pp, up ) ; 3490 3491 if ( peer->ttl != 100 ) { 3492 if ( bAdjustment ) { 3493 snprintf( sLog, sizeof(sLog), 3494 JJY_CLOCKSTATS_MESSAGE_DELAY_ADJUST, 3495 up->msecond, up->iLoopbackValidCount, MAX_LOOPBACK ) ; 3496 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_INFORMATION, sLog ) ; 3497 } else { 3498 snprintf( sLog, sizeof(sLog), 3499 JJY_CLOCKSTATS_MESSAGE_DELAY_UNADJUST, 3500 up->iLoopbackValidCount, MAX_LOOPBACK ) ; 3501 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3502 } 3503 } 3504 3505 } 3506 } 3507 3508 } else if ( teljjy_command_sequence[up->iClockCommandSeq].iEchobackReplyLength != iLen 3509 && teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3510 /* Loopback noise ( Unexpected replay ) */ 3511 3512 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_IGNORE_REPLY, 3513 pBuf ) ; 3514 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_WARNING, sLog ) ; 3515 3516 } else { 3517 3518 up->bLineError = TRUE ; 3519 3520 snprintf( sLog, sizeof(sLog)-1, JJY_CLOCKSTATS_MESSAGE_UNEXPECTED_REPLY, 3521 pBuf ) ; 3522 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_ERROR, sLog ) ; 3523 3524 } 3525 3526 return TELJJY_STAY_CLOCK_STATE ; 3527 3528} 3529 3530/******************************/ 3531static int 3532teljjy_conn_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3533{ 3534 3535 const char * pCmd ; 3536 3537 DEBUG_TELJJY_PRINTF( "teljjy_conn_silent" ) ; 3538 3539 if ( up->iClockCommandSeq >= 1 3540 && up->iClockCommandSeq < TELJJY_COMMAND_START_SKIP_LOOPBACK ) { 3541 /* Loopback */ 3542#ifdef DEBUG 3543 if ( debug ) { 3544 printf( "refclock_jjy.c : teljjy_conn_silent : call teljjy_conn_send\n" ) ; 3545 } 3546#endif 3547 if ( teljjy_command_sequence[up->iClockCommandSeq].iExpectedReplyType == TELJJY_REPLY_LOOPBACK ) { 3548 up->bLoopbackTimeout[up->iLoopbackCount] = TRUE ; 3549 } 3550 up->iTeljjySilentTimer = 0 ; 3551 return teljjy_conn_send( peer, pp, up ) ; 3552 } else { 3553 pCmd = "\r" ; 3554 } 3555 3556 if ( write( pp->io.fd, pCmd, 1 ) != 1 ) { 3557 refclock_report( peer, CEVNT_FAULT ) ; 3558 } 3559 3560 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 3561 3562 up->iTeljjySilentTimer = 0 ; 3563 3564 return TELJJY_STAY_CLOCK_STATE ; 3565 3566} 3567 3568/******************************/ 3569static int 3570teljjy_conn_error ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3571{ 3572 3573 DEBUG_TELJJY_PRINTF( "teljjy_conn_error" ) ; 3574 3575 return TELJJY_CHANGE_CLOCK_STATE ; 3576 3577} 3578 3579/******************************/ 3580static int 3581teljjy_bye_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3582{ 3583 3584 DEBUG_TELJJY_PRINTF( "teljjy_bye_ignore" ) ; 3585 3586 return TELJJY_STAY_CLOCK_STATE ; 3587 3588} 3589 3590/******************************/ 3591static int 3592teljjy_bye_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3593{ 3594 3595 DEBUG_TELJJY_PRINTF( "teljjy_bye_disc" ) ; 3596 3597 return TELJJY_CHANGE_CLOCK_STATE ; 3598 3599} 3600 3601/******************************/ 3602static int 3603teljjy_bye_modem ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3604{ 3605 3606 DEBUG_TELJJY_PRINTF( "teljjy_bye_modem" ) ; 3607 3608 modem_disconnect ( peer->refclkunit, peer ) ; 3609 3610 return TELJJY_STAY_CLOCK_STATE ; 3611 3612} 3613 3614/*################################################################################################*/ 3615/*################################################################################################*/ 3616/*## ##*/ 3617/*## Modem control finite state machine ##*/ 3618/*## ##*/ 3619/*################################################################################################*/ 3620/*################################################################################################*/ 3621 3622/* struct jjyunit.iModemState */ 3623 3624#define MODEM_STATE_DISCONNECT 0 3625#define MODEM_STATE_INITIALIZE 1 3626#define MODEM_STATE_DAILING 2 3627#define MODEM_STATE_CONNECT 3 3628#define MODEM_STATE_ESCAPE 4 3629 3630/* struct jjyunit.iModemEvent */ 3631 3632#define MODEM_EVENT_NULL 0 3633#define MODEM_EVENT_INITIALIZE 1 3634#define MODEM_EVENT_DIALOUT 2 3635#define MODEM_EVENT_DISCONNECT 3 3636#define MODEM_EVENT_RESP_OK 4 3637#define MODEM_EVENT_RESP_CONNECT 5 3638#define MODEM_EVENT_RESP_RING 6 3639#define MODEM_EVENT_RESP_NO_CARRIER 7 3640#define MODEM_EVENT_RESP_ERROR 8 3641#define MODEM_EVENT_RESP_CONNECT_X 9 3642#define MODEM_EVENT_RESP_NO_DAILTONE 10 3643#define MODEM_EVENT_RESP_BUSY 11 3644#define MODEM_EVENT_RESP_NO_ANSWER 12 3645#define MODEM_EVENT_RESP_UNKNOWN 13 3646#define MODEM_EVENT_SILENT 14 3647#define MODEM_EVENT_TIMEOUT 15 3648 3649/* Function prototypes */ 3650 3651static void modem_control ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3652 3653static int modem_disc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3654static int modem_disc_init ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3655static int modem_init_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3656static int modem_init_start ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3657static int modem_init_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3658static int modem_init_resp00 ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3659static int modem_init_resp04 ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3660static int modem_dial_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3661static int modem_dial_dialout ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3662static int modem_dial_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3663static int modem_dial_connect ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3664static int modem_dial_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3665static int modem_conn_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3666static int modem_conn_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3667static int modem_esc_ignore ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3668static int modem_esc_escape ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3669static int modem_esc_data ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3670static int modem_esc_silent ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3671static int modem_esc_disc ( struct peer *, struct refclockproc *, struct jjyunit * ) ; 3672 3673static int ( *pModemHandler [ ] [ 5 ] ) ( struct peer *, struct refclockproc *, struct jjyunit * ) = 3674{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3675/* NULL */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_ignore }, 3676/* INITIALIZE */ { modem_disc_init , modem_init_start , modem_dial_ignore , modem_conn_ignore, modem_esc_ignore }, 3677/* DIALOUT */ { modem_disc_ignore, modem_init_ignore, modem_dial_dialout, modem_conn_ignore, modem_esc_ignore }, 3678/* DISCONNECT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_escape }, 3679/* RESP: 0: OK */ { modem_disc_ignore, modem_init_resp00, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3680/* RESP: 1: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data }, 3681/* RESP: 2: RING */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3682/* RESP: 3: NO CARRIER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3683/* RESP: 4: ERROR */ { modem_disc_ignore, modem_init_resp04, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3684/* RESP: 5: CONNECT */ { modem_disc_ignore, modem_init_ignore, modem_dial_connect, modem_conn_ignore, modem_esc_data }, 3685/* RESP: 6: NO DAILTONE */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3686/* RESP: 7: BUSY */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3687/* RESP: 8: NO ANSWER */ { modem_disc_ignore, modem_init_ignore, modem_dial_disc , modem_conn_ignore, modem_esc_data }, 3688/* RESP: 9: UNKNOWN */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_data }, 3689/* SILENT */ { modem_disc_ignore, modem_init_ignore, modem_dial_ignore , modem_conn_ignore, modem_esc_silent }, 3690/* TIMEOUT */ { modem_disc_ignore, modem_init_disc , modem_dial_escape , modem_conn_escape, modem_esc_disc } 3691} ; 3692 3693static short iModemNextState [ ] [ 5 ] = 3694{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3695/* NULL */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3696/* INITIALIZE */ { MODEM_STATE_INITIALIZE, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3697/* DIALOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3698/* DISCONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE }, 3699/* RESP: 0: OK */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3700/* RESP: 1: CONNECT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3701/* RESP: 2: RING */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3702/* RESP: 3: NO CARRIER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3703/* RESP: 4: ERROR */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DAILING , MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3704/* RESP: 5: CONNECT X */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_CONNECT , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3705/* RESP: 6: NO DAILTONE */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3706/* RESP: 7: BUSY */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3707/* RESP: 8: NO ANSWER */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DISCONNECT, MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3708/* RESP: 9: UNKNOWN */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_ESCAPE }, 3709/* SILENT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_INITIALIZE, MODEM_STATE_DAILING , MODEM_STATE_CONNECT, MODEM_STATE_DISCONNECT }, 3710/* TIMEOUT */ { MODEM_STATE_DISCONNECT, MODEM_STATE_DISCONNECT, MODEM_STATE_ESCAPE , MODEM_STATE_ESCAPE , MODEM_STATE_DISCONNECT } 3711} ; 3712 3713static short iModemPostEvent [ ] [ 5 ] = 3714{ /*STATE_DISCONNECT STATE_INITIALIZE STATE_DAILING STATE_CONNECT STATE_ESCAPE */ 3715/* NULL */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3716/* INITIALIZE */ { MODEM_EVENT_INITIALIZE, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3717/* DIALOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3718/* DISCONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL }, 3719/* RESP: 0: OK */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3720/* RESP: 1: CONNECT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3721/* RESP: 2: RING */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3722/* RESP: 3: NO CARRIER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3723/* RESP: 4: ERROR */ { MODEM_EVENT_NULL , MODEM_EVENT_DIALOUT, MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3724/* RESP: 5: CONNECT X */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3725/* RESP: 6: NO DAILTONE */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3726/* RESP: 7: BUSY */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3727/* RESP: 8: NO ANSWER */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3728/* RESP: 9: UNKNOWN */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3729/* SILENT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_NULL }, 3730/* TIMEOUT */ { MODEM_EVENT_NULL , MODEM_EVENT_NULL , MODEM_EVENT_DISCONNECT, MODEM_EVENT_DISCONNECT, MODEM_EVENT_NULL } 3731} ; 3732 3733static short iModemSilentTimeout [ 5 ] = { 0, 0, 0, 0, 5 } ; 3734static short iModemStateTimeout [ 5 ] = { 0, 20, 90, 0, 20 } ; 3735 3736#define STAY_MODEM_STATE 0 3737#define CHANGE_MODEM_STATE 1 3738 3739#ifdef DEBUG 3740#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 ) ; } } 3741#else 3742#define DEBUG_MODEM_PRINTF(sFunc) 3743#endif 3744 3745/**************************************************************************************************/ 3746 3747static short 3748getModemState ( struct jjyunit *up ) 3749{ 3750 return up->iModemState ; 3751} 3752 3753/**************************************************************************************************/ 3754 3755static int 3756isModemStateConnect ( short iCheckState ) 3757{ 3758 return ( iCheckState == MODEM_STATE_CONNECT ) ; 3759} 3760 3761/**************************************************************************************************/ 3762 3763static int 3764isModemStateDisconnect ( short iCheckState ) 3765{ 3766 return ( iCheckState == MODEM_STATE_DISCONNECT ) ; 3767} 3768 3769/**************************************************************************************************/ 3770 3771static int 3772isModemStateTimerOn ( struct jjyunit *up ) 3773{ 3774 return ( iModemSilentTimeout[up->iModemState] != 0 || iModemStateTimeout[up->iModemState] != 0 ) ; 3775} 3776 3777/**************************************************************************************************/ 3778 3779static void 3780modem_connect ( int unit, struct peer *peer ) 3781{ 3782 struct refclockproc *pp; 3783 struct jjyunit *up; 3784 3785 pp = peer->procptr ; 3786 up = pp->unitptr ; 3787 3788 DEBUG_MODEM_PRINTF( "modem_connect" ) ; 3789 3790 up->iModemEvent = MODEM_EVENT_INITIALIZE ; 3791 3792 modem_control ( peer, pp, up ) ; 3793 3794} 3795 3796/**************************************************************************************************/ 3797 3798static void 3799modem_disconnect ( int unit, struct peer *peer ) 3800{ 3801 struct refclockproc *pp; 3802 struct jjyunit *up; 3803 3804 pp = peer->procptr ; 3805 up = pp->unitptr ; 3806 3807 DEBUG_MODEM_PRINTF( "modem_disconnect" ) ; 3808 3809 up->iModemEvent = MODEM_EVENT_DISCONNECT ; 3810 3811 modem_control ( peer, pp, up ) ; 3812 3813} 3814 3815/**************************************************************************************************/ 3816 3817static int 3818modem_receive ( struct recvbuf *rbufp ) 3819{ 3820 3821 struct peer *peer; 3822 struct jjyunit *up; 3823 struct refclockproc *pp; 3824 char *pBuf ; 3825 size_t iLen ; 3826 3827#ifdef DEBUG 3828 static const char *sFunctionName = "modem_receive" ; 3829#endif 3830 3831 peer = rbufp->recv_peer ; 3832 pp = peer->procptr ; 3833 up = pp->unitptr ; 3834 3835 DEBUG_MODEM_PRINTF( sFunctionName ) ; 3836 3837 if ( up->linediscipline == LDISC_RAW ) { 3838 pBuf = up->sTextBuf ; 3839 iLen = up->iTextBufLen ; 3840 } else { 3841 pBuf = pp->a_lastcode ; 3842 iLen = pp->lencode ; 3843 } 3844 3845 if ( iLen == 2 && strncmp( pBuf, "OK" , 2 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_OK ; } 3846 else if ( iLen == 7 && strncmp( pBuf, "CONNECT" , 7 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT ; } 3847 else if ( iLen == 4 && strncmp( pBuf, "RING" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_RING ; } 3848 else if ( iLen == 10 && strncmp( pBuf, "NO CARRIER" , 10 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_CARRIER ; } 3849 else if ( iLen == 5 && strncmp( pBuf, "ERROR" , 5 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_ERROR ; } 3850 else if ( iLen >= 8 && strncmp( pBuf, "CONNECT " , 8 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_CONNECT_X ; } 3851 else if ( iLen == 11 && strncmp( pBuf, "NO DAILTONE", 11 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_DAILTONE ; } 3852 else if ( iLen == 4 && strncmp( pBuf, "BUSY" , 4 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_BUSY ; } 3853 else if ( iLen == 9 && strncmp( pBuf, "NO ANSWER" , 9 ) == 0 ) { up->iModemEvent = MODEM_EVENT_RESP_NO_ANSWER ; } 3854 else { up->iModemEvent = MODEM_EVENT_RESP_UNKNOWN ; } 3855 3856#ifdef DEBUG 3857 if ( debug ) { 3858 char sResp [ 40 ] ; 3859 size_t iCopyLen ; 3860 iCopyLen = ( iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ; 3861 strncpy( sResp, pBuf, iLen <= sizeof(sResp)-1 ? iLen : sizeof(sResp)-1 ) ; 3862 sResp[iCopyLen] = 0 ; 3863 printf ( "refclock_jjy.c : modem_receive : iLen=%zu pBuf=[%s] iModemEvent=%d\n", iCopyLen, sResp, up->iModemEvent ) ; 3864 } 3865#endif 3866 modem_control ( peer, pp, up ) ; 3867 3868 return 0 ; 3869 3870} 3871 3872/**************************************************************************************************/ 3873 3874static void 3875modem_timer ( int unit, struct peer *peer ) 3876{ 3877 3878 struct refclockproc *pp ; 3879 struct jjyunit *up ; 3880 3881 pp = peer->procptr ; 3882 up = pp->unitptr ; 3883 3884 DEBUG_MODEM_PRINTF( "modem_timer" ) ; 3885 3886 if ( iModemSilentTimeout[up->iModemState] != 0 ) { 3887 up->iModemSilentTimer++ ; 3888 if ( iModemSilentTimeout[up->iModemState] <= up->iModemSilentTimer ) { 3889 up->iModemEvent = MODEM_EVENT_SILENT ; 3890 modem_control ( peer, pp, up ) ; 3891 } 3892 } 3893 3894 if ( iModemStateTimeout[up->iModemState] != 0 ) { 3895 up->iModemStateTimer++ ; 3896 if ( iModemStateTimeout[up->iModemState] <= up->iModemStateTimer ) { 3897 up->iModemEvent = MODEM_EVENT_TIMEOUT ; 3898 modem_control ( peer, pp, up ) ; 3899 } 3900 } 3901 3902} 3903 3904/**************************************************************************************************/ 3905 3906static void 3907modem_control ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3908{ 3909 3910 int rc ; 3911 short iPostEvent = MODEM_EVENT_NULL ; 3912 3913 DEBUG_MODEM_PRINTF( "modem_control" ) ; 3914 3915 rc = (*pModemHandler[up->iModemEvent][up->iModemState])( peer, pp, up ) ; 3916 3917 if ( rc == CHANGE_MODEM_STATE ) { 3918 iPostEvent = iModemPostEvent[up->iModemEvent][up->iModemState] ; 3919#ifdef DEBUG 3920 if ( debug ) { 3921 printf( "refclock_jjy.c : modem_control : iModemState=%d -> %d iPostEvent=%d\n", 3922 up->iModemState, iModemNextState[up->iModemEvent][up->iModemState], iPostEvent ) ; 3923 } 3924#endif 3925 3926 if ( up->iModemState != iModemNextState[up->iModemEvent][up->iModemState] ) { 3927 up->iModemSilentCount = 0 ; 3928 up->iModemStateTimer = 0 ; 3929 up->iModemCommandSeq = 0 ; 3930 } 3931 3932 up->iModemState = iModemNextState[up->iModemEvent][up->iModemState] ; 3933 } 3934 3935 if ( iPostEvent != MODEM_EVENT_NULL ) { 3936 up->iModemEvent = iPostEvent ; 3937 modem_control ( peer, pp, up ) ; 3938 } 3939 3940 up->iModemEvent = MODEM_EVENT_NULL ; 3941 3942} 3943 3944/******************************/ 3945static int 3946modem_disc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3947{ 3948 3949 DEBUG_MODEM_PRINTF( "modem_disc_ignore" ) ; 3950 3951 return STAY_MODEM_STATE ; 3952 3953} 3954 3955/******************************/ 3956static int 3957modem_disc_init ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3958{ 3959 3960 DEBUG_MODEM_PRINTF( "modem_disc_init" ) ; 3961 3962 return CHANGE_MODEM_STATE ; 3963 3964} 3965 3966/******************************/ 3967static int 3968modem_init_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3969{ 3970 3971 DEBUG_MODEM_PRINTF( "modem_init_ignore" ) ; 3972 3973 return STAY_MODEM_STATE ; 3974 3975} 3976 3977/******************************/ 3978static int 3979modem_init_start ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3980{ 3981 3982 DEBUG_MODEM_PRINTF( "modem_init_start" ) ; 3983 3984 up->iModemCommandSeq = 0 ; 3985 3986#ifdef DEBUG 3987 if ( debug ) { 3988 printf( "refclock_jjy.c : modem_init_start : call modem_init_resp00\n" ) ; 3989 } 3990#endif 3991 3992 return modem_init_resp00( peer, pp, up ) ; 3993 3994} 3995 3996/******************************/ 3997static int 3998modem_init_resp00 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 3999{ 4000 4001 const char * pCmd ; 4002 char cBuf [ 46 ] ; 4003 int iCmdLen ; 4004 int iErrorCorrection, iSpeakerSwitch, iSpeakerVolume ; 4005 int iNextModemState = STAY_MODEM_STATE ; 4006 4007 DEBUG_MODEM_PRINTF( "modem_init_resp00" ) ; 4008 4009 up->iModemCommandSeq++ ; 4010 4011 switch ( up->iModemCommandSeq ) { 4012 4013 case 1 : 4014 /* En = Echoback 0:Off 1:On */ 4015 /* Qn = Result codes 0:On 1:Off */ 4016 /* Vn = Result codes 0:Numeric 1:Text */ 4017 pCmd = "ATE0Q0V1\r\n" ; 4018 break ; 4019 4020 case 2 : 4021 /* Mn = Speaker switch 0:Off 1:On until remote carrier detected 2:On */ 4022 if ( ( pp->sloppyclockflag & CLK_FLAG3 ) == 0 ) { 4023 /* fudge 127.127.40.n flag3 0 */ 4024 iSpeakerSwitch = 0 ; 4025 } else { 4026 /* fudge 127.127.40.n flag3 1 */ 4027 iSpeakerSwitch = 2 ; 4028 } 4029 4030 /* Ln = Speaker volume 0:Very low 1:Low 2:Middle 3:High */ 4031 if ( ( pp->sloppyclockflag & CLK_FLAG4 ) == 0 ) { 4032 /* fudge 127.127.40.n flag4 0 */ 4033 iSpeakerVolume = 1 ; 4034 } else { 4035 /* fudge 127.127.40.n flag4 1 */ 4036 iSpeakerVolume = 2 ; 4037 } 4038 4039 pCmd = cBuf ; 4040 snprintf( cBuf, sizeof(cBuf), "ATM%dL%d\r\n", iSpeakerSwitch, iSpeakerVolume ) ; 4041 break ; 4042 4043 case 3 : 4044 /* &Kn = Flow control 4:XON/XOFF */ 4045 pCmd = "AT&K4\r\n" ; 4046 break ; 4047 4048 case 4 : 4049 /* +MS = Protocol V22B:1200,2400bps�iV.22bis) */ 4050 pCmd = "AT+MS=V22B\r\n" ; 4051 break ; 4052 4053 case 5 : 4054 /* %Cn = Data compression 0:No data compression */ 4055 pCmd = "AT%C0\r\n" ; 4056 break ; 4057 4058 case 6 : 4059 /* \Nn = Error correction 0:Normal mode 1:Direct mode 2:V42,MNP 3:V42,MNP,Normal */ 4060 if ( ( pp->sloppyclockflag & CLK_FLAG2 ) == 0 ) { 4061 /* fudge 127.127.40.n flag2 0 */ 4062 iErrorCorrection = 0 ; 4063 } else { 4064 /* fudge 127.127.40.n flag2 1 */ 4065 iErrorCorrection = 3 ; 4066 } 4067 4068 pCmd = cBuf ; 4069 snprintf( cBuf, sizeof(cBuf), "AT\\N%d\r\n", iErrorCorrection ) ; 4070 break ; 4071 4072 case 7 : 4073 /* Hn = Hook 0:Hook-On ( Disconnect ) 1:Hook-Off ( Connect ) */ 4074 pCmd = "ATH1\r\n" ; 4075 break ; 4076 4077 case 8 : 4078 /* Initialize completion */ 4079 pCmd = NULL ; 4080 iNextModemState = CHANGE_MODEM_STATE ; 4081 break ; 4082 4083 default : 4084 pCmd = NULL ; 4085 break ; 4086 4087 } 4088 4089 if ( pCmd != NULL ) { 4090 4091 iCmdLen = strlen( pCmd ) ; 4092 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4093 refclock_report( peer, CEVNT_FAULT ) ; 4094 } 4095 4096 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4097 4098 } 4099 4100 return iNextModemState ; 4101 4102} 4103 4104/******************************/ 4105static int 4106modem_init_resp04 ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4107{ 4108 4109 DEBUG_MODEM_PRINTF( "modem_init_resp04" ) ; 4110 4111 return modem_init_resp00( peer, pp, up ) ; 4112 4113} 4114 4115/******************************/ 4116static int 4117modem_init_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4118{ 4119 4120 DEBUG_MODEM_PRINTF( "modem_init_disc" ) ; 4121#ifdef DEBUG 4122 if ( debug ) { 4123 printf( "refclock_jjy.c : modem_init_disc : call modem_esc_disc\n" ) ; 4124 } 4125#endif 4126 4127 return CHANGE_MODEM_STATE ; 4128 4129} 4130 4131/******************************/ 4132static int 4133modem_dial_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4134{ 4135 4136 DEBUG_MODEM_PRINTF( "modem_dial_ignore" ) ; 4137 4138 return STAY_MODEM_STATE ; 4139 4140} 4141 4142/******************************/ 4143static int 4144modem_dial_dialout ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4145{ 4146 4147 char sCmd [ 46 ] ; 4148 int iCmdLen ; 4149 char cToneOrPulse ; 4150 4151 DEBUG_MODEM_PRINTF( "modem_dial_dialout" ) ; 4152 4153 /* Tone or Pulse */ 4154 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 4155 /* fudge 127.127.40.n flag1 0 */ 4156 cToneOrPulse = 'T' ; 4157 } else { 4158 /* fudge 127.127.40.n flag1 1 */ 4159 cToneOrPulse = 'P' ; 4160 } 4161 4162 /* Connect ( Dial number ) */ 4163 snprintf( sCmd, sizeof(sCmd), "ATDW%c%s\r\n", cToneOrPulse, *sys_phone ) ; 4164 4165 /* Send command */ 4166 iCmdLen = strlen( sCmd ) ; 4167 if ( write( pp->io.fd, sCmd, iCmdLen ) != iCmdLen ) { 4168 refclock_report( peer, CEVNT_FAULT ) ; 4169 } 4170 4171 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, sCmd ) ; 4172 4173 return STAY_MODEM_STATE ; 4174 4175} 4176 4177/******************************/ 4178static int 4179modem_dial_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4180{ 4181 4182 DEBUG_MODEM_PRINTF( "modem_dial_escape" ) ; 4183#ifdef DEBUG 4184 if ( debug ) { 4185 printf( "refclock_jjy.c : modem_dial_escape : call modem_conn_escape\n" ) ; 4186 } 4187#endif 4188 4189 return modem_conn_escape( peer, pp, up ) ; 4190 4191} 4192 4193/******************************/ 4194static int 4195modem_dial_connect ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4196{ 4197 4198 DEBUG_MODEM_PRINTF( "modem_dial_connect" ) ; 4199 4200 return CHANGE_MODEM_STATE ; 4201 4202} 4203 4204/******************************/ 4205static int 4206modem_dial_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4207{ 4208 4209 DEBUG_MODEM_PRINTF( "modem_dial_disc" ) ; 4210#ifdef DEBUG 4211 if ( debug ) { 4212 printf( "refclock_jjy.c : modem_dial_disc : call modem_esc_disc\n" ) ; 4213 } 4214#endif 4215 4216 modem_esc_disc( peer, pp, up ) ; 4217 4218 return CHANGE_MODEM_STATE ; 4219 4220} 4221 4222/******************************/ 4223static int 4224modem_conn_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4225{ 4226 4227 DEBUG_MODEM_PRINTF( "modem_conn_ignore" ) ; 4228 4229 return STAY_MODEM_STATE ; 4230 4231} 4232 4233/******************************/ 4234static int 4235modem_conn_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4236{ 4237 4238 DEBUG_MODEM_PRINTF( "modem_conn_escape" ) ; 4239 4240 return CHANGE_MODEM_STATE ; 4241 4242} 4243 4244/******************************/ 4245static int 4246modem_esc_ignore ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4247{ 4248 4249 DEBUG_MODEM_PRINTF( "modem_esc_ignore" ) ; 4250 4251 return STAY_MODEM_STATE ; 4252 4253} 4254 4255/******************************/ 4256static int 4257modem_esc_escape ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4258{ 4259 4260 const char * pCmd ; 4261 int iCmdLen ; 4262 4263 DEBUG_MODEM_PRINTF( "modem_esc_escape" ) ; 4264 4265 /* Escape command ( Go to command mode ) */ 4266 pCmd = "+++" ; 4267 4268 /* Send command */ 4269 iCmdLen = strlen( pCmd ) ; 4270 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4271 refclock_report( peer, CEVNT_FAULT ) ; 4272 } 4273 4274 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4275 4276 return STAY_MODEM_STATE ; 4277 4278} 4279 4280/******************************/ 4281static int 4282modem_esc_data ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4283{ 4284 4285 DEBUG_MODEM_PRINTF( "modem_esc_data" ) ; 4286 4287 up->iModemSilentTimer = 0 ; 4288 4289 return STAY_MODEM_STATE ; 4290 4291} 4292 4293/******************************/ 4294static int 4295modem_esc_silent ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4296{ 4297 4298 DEBUG_MODEM_PRINTF( "modem_esc_silent" ) ; 4299 4300 up->iModemSilentCount ++ ; 4301 4302 if ( up->iModemSilentCount < iModemStateTimeout[up->iModemState] / iModemSilentTimeout[up->iModemState] ) { 4303#ifdef DEBUG 4304 if ( debug ) { 4305 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_escape\n" ) ; 4306 } 4307#endif 4308 modem_esc_escape( peer, pp, up ) ; 4309 up->iModemSilentTimer = 0 ; 4310 return STAY_MODEM_STATE ; 4311 } 4312 4313#ifdef DEBUG 4314 if ( debug ) { 4315 printf( "refclock_jjy.c : modem_esc_silent : call modem_esc_disc\n" ) ; 4316 } 4317#endif 4318 return modem_esc_disc( peer, pp, up ) ; 4319 4320} 4321/******************************/ 4322static int 4323modem_esc_disc ( struct peer *peer, struct refclockproc *pp, struct jjyunit *up ) 4324{ 4325 4326 const char * pCmd ; 4327 int iCmdLen ; 4328 4329 DEBUG_MODEM_PRINTF( "modem_esc_disc" ) ; 4330 4331 /* Disconnect */ 4332 pCmd = "ATH0\r\n" ; 4333 4334 /* Send command */ 4335 iCmdLen = strlen( pCmd ) ; 4336 if ( write( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 4337 refclock_report( peer, CEVNT_FAULT ) ; 4338 } 4339 4340 jjy_write_clockstats( peer, JJY_CLOCKSTATS_MARK_SEND, pCmd ) ; 4341 4342 return CHANGE_MODEM_STATE ; 4343 4344} 4345 4346/*################################################################################################*/ 4347/*################################################################################################*/ 4348/*## ##*/ 4349/*## jjy_write_clockstats ##*/ 4350/*## ##*/ 4351/*################################################################################################*/ 4352/*################################################################################################*/ 4353 4354static void 4355jjy_write_clockstats ( struct peer *peer, int iMark, const char *pData ) 4356{ 4357 4358 char sLog [ 100 ] ; 4359 const char * pMark ; 4360 int iMarkLen, iDataLen ; 4361 4362 switch ( iMark ) { 4363 case JJY_CLOCKSTATS_MARK_JJY : 4364 pMark = "JJY " ; 4365 break ; 4366 case JJY_CLOCKSTATS_MARK_SEND : 4367 pMark = "--> " ; 4368 break ; 4369 case JJY_CLOCKSTATS_MARK_RECEIVE : 4370 pMark = "<-- " ; 4371 break ; 4372 case JJY_CLOCKSTATS_MARK_INFORMATION : 4373 pMark = "--- " ; 4374 break ; 4375 case JJY_CLOCKSTATS_MARK_ATTENTION : 4376 pMark = "=== " ; 4377 break ; 4378 case JJY_CLOCKSTATS_MARK_WARNING : 4379 pMark = "-W- " ; 4380 break ; 4381 case JJY_CLOCKSTATS_MARK_ERROR : 4382 pMark = "-X- " ; 4383 break ; 4384 default : 4385 pMark = "" ; 4386 break ; 4387 } 4388 4389 iDataLen = strlen( pData ) ; 4390 iMarkLen = strlen( pMark ) ; 4391 strcpy( sLog, pMark ) ; /* Harmless because of enough length */ 4392 printableString( sLog+iMarkLen, sizeof(sLog)-iMarkLen, pData, iDataLen ) ; 4393 4394#ifdef DEBUG 4395 if ( debug ) { 4396 printf( "refclock_jjy.c : clockstats : %s\n", sLog ) ; 4397 } 4398#endif 4399 record_clock_stats( &peer->srcadr, sLog ) ; 4400 4401} 4402 4403/*################################################################################################*/ 4404/*################################################################################################*/ 4405/*## ##*/ 4406/*## printableString ##*/ 4407/*## ##*/ 4408/*################################################################################################*/ 4409/*################################################################################################*/ 4410 4411static void 4412printableString ( char *sOutput, int iOutputLen, const char *sInput, int iInputLen ) 4413{ 4414 const char *printableControlChar[] = { 4415 "<NUL>", "<SOH>", "<STX>", "<ETX>", 4416 "<EOT>", "<ENQ>", "<ACK>", "<BEL>", 4417 "<BS>" , "<HT>" , "<LF>" , "<VT>" , 4418 "<FF>" , "<CR>" , "<SO>" , "<SI>" , 4419 "<DLE>", "<DC1>", "<DC2>", "<DC3>", 4420 "<DC4>", "<NAK>", "<SYN>", "<ETB>", 4421 "<CAN>", "<EM>" , "<SUB>", "<ESC>", 4422 "<FS>" , "<GS>" , "<RS>" , "<US>" , 4423 " " } ; 4424 4425 size_t i, j, n ; 4426 size_t InputLen; 4427 size_t OutputLen; 4428 4429 InputLen = (size_t)iInputLen; 4430 OutputLen = (size_t)iOutputLen; 4431 for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) { 4432 if ( isprint( (unsigned char)sInput[i] ) ) { 4433 n = 1 ; 4434 if ( j + 1 >= OutputLen ) 4435 break ; 4436 sOutput[j] = sInput[i] ; 4437 } else if ( ( sInput[i] & 0xFF ) < 4438 COUNTOF(printableControlChar) ) { 4439 n = strlen( printableControlChar[sInput[i] & 0xFF] ) ; 4440 if ( j + n + 1 >= OutputLen ) 4441 break ; 4442 strlcpy( sOutput + j, 4443 printableControlChar[sInput[i] & 0xFF], 4444 OutputLen - j ) ; 4445 } else { 4446 n = 5 ; 4447 if ( j + n + 1 >= OutputLen ) 4448 break ; 4449 snprintf( sOutput + j, OutputLen - j, "<x%X>", 4450 sInput[i] & 0xFF ) ; 4451 } 4452 j += n ; 4453 } 4454 4455 sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ; 4456 4457} 4458 4459/**************************************************************************************************/ 4460 4461#else 4462int refclock_jjy_bs ; 4463#endif /* REFCLOCK */ 4464