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