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