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