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