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