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