1 /* 2 * refclock_jjy - clock driver for JJY receivers 3 */ 4 5 /**********************************************************************/ 6 /* */ 7 /* Copyright (C) 2001-2011, Takao Abe. All rights reserved. */ 8 /* */ 9 /* Permission to use, copy, modify, and distribute this software */ 10 /* and its documentation for any purpose is hereby granted */ 11 /* without fee, provided that the following conditions are met: */ 12 /* */ 13 /* One retains the entire copyright notice properly, and both the */ 14 /* copyright notice and this license. in the documentation and/or */ 15 /* other materials provided with the distribution. */ 16 /* */ 17 /* This software and the name of the author must not be used to */ 18 /* endorse or promote products derived from this software without */ 19 /* prior written permission. */ 20 /* */ 21 /* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESSED OR IMPLIED */ 22 /* WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, THE */ 23 /* IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS FOR A */ 24 /* PARTICULAR PURPOSE. */ 25 /* IN NO EVENT SHALL THE AUTHOR TAKAO ABE BE LIABLE FOR ANY DIRECT, */ 26 /* INDIRECT, GENERAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 27 /* ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */ 28 /* GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS */ 29 /* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ 30 /* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ( INCLUDING */ 31 /* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF */ 32 /* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 33 /* */ 34 /* This driver is developed in my private time, and is opened as */ 35 /* voluntary contributions for the NTP. */ 36 /* The manufacturer of the JJY receiver has not participated in */ 37 /* a development of this driver. */ 38 /* The manufacturer does not warrant anything about this driver, */ 39 /* and is not liable for anything about this driver. */ 40 /* */ 41 /**********************************************************************/ 42 /* */ 43 /* Author Takao Abe */ 44 /* Email takao_abe@xurb.jp */ 45 /* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */ 46 /* */ 47 /* The email address abetakao@bea.hi-ho.ne.jp is never read */ 48 /* from 2010, because a few filtering rule are provided by the */ 49 /* "hi-ho.ne.jp", and lots of spam mail are reached. */ 50 /* New email address for supporting the refclock_jjy is */ 51 /* takao_abe@xurb.jp */ 52 /* */ 53 /**********************************************************************/ 54 /* */ 55 /* History */ 56 /* */ 57 /* 2001/07/15 */ 58 /* [New] Support the Tristate Ltd. JJY receiver */ 59 /* */ 60 /* 2001/08/04 */ 61 /* [Change] Log to clockstats even if bad reply */ 62 /* [Fix] PRECISION = (-3) (about 100 ms) */ 63 /* [Add] Support the C-DEX Co.Ltd. JJY receiver */ 64 /* */ 65 /* 2001/12/04 */ 66 /* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */ 67 /* */ 68 /* 2002/07/12 */ 69 /* [Fix] Portability for FreeBSD ( patched by the user ) */ 70 /* */ 71 /* 2004/10/31 */ 72 /* [Change] Command send timing for the Tristate Ltd. JJY receiver */ 73 /* JJY-01 ( Firmware version 2.01 ) */ 74 /* Thanks to Andy Taki for testing under FreeBSD */ 75 /* */ 76 /* 2004/11/28 */ 77 /* [Add] Support the Echo Keisokuki LT-2000 receiver */ 78 /* */ 79 /* 2006/11/04 */ 80 /* [Fix] C-DEX JST2000 */ 81 /* Thanks to Hideo Kuramatsu for the patch */ 82 /* */ 83 /* 2009/04/05 */ 84 /* [Add] Support the CITIZEN T.I.C JJY-200 receiver */ 85 /* */ 86 /* 2010/11/20 */ 87 /* [Change] Bug 1618 ( Harmless ) */ 88 /* Code clean up ( Remove unreachable codes ) in */ 89 /* jjy_start() */ 90 /* [Change] Change clockstats format of the Tristate JJY01/02 */ 91 /* Issues more command to get the status of the receiver */ 92 /* when "fudge 127.127.40.X flag1 1" is specified */ 93 /* ( DATE,STIM -> DCST,STUS,DATE,STIM ) */ 94 /* */ 95 /* 2011/04/30 */ 96 /* [Add] Support the Tristate Ltd. TS-GPSclock-01 */ 97 /* */ 98 /**********************************************************************/ 99 100 #ifdef HAVE_CONFIG_H 101 #include <config.h> 102 #endif 103 104 #if defined(REFCLOCK) && defined(CLOCK_JJY) 105 106 #include <stdio.h> 107 #include <ctype.h> 108 #include <string.h> 109 #include <sys/time.h> 110 #include <time.h> 111 112 #include "ntpd.h" 113 #include "ntp_io.h" 114 #include "ntp_tty.h" 115 #include "ntp_refclock.h" 116 #include "ntp_calendar.h" 117 #include "ntp_stdlib.h" 118 119 /**********************************************************************/ 120 /* */ 121 /* The Tristate Ltd. JJY receiver JJY01 */ 122 /* */ 123 /* Command Response Remarks */ 124 /* ------------ ---------------------- --------------------- */ 125 /* dcst<CR><LF> VALID|INVALID<CR><LF> */ 126 /* stus<CR><LF> ADJUSTED|UNADJUSTED<CR><LF> */ 127 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */ 128 /* time<CR><LF> HH:MM:SS<CR><LF> Not used by this driver */ 129 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */ 130 /* */ 131 /* During synchronization after a receiver is turned on, */ 132 /* It replies the past time from 2000/01/01 00:00:00. */ 133 /* The function "refclock_process" checks the time and tells */ 134 /* as an insanity time. */ 135 /* */ 136 /**********************************************************************/ 137 /* */ 138 /* The C-DEX Co. Ltd. JJY receiver JST2000 */ 139 /* */ 140 /* Command Response Remarks */ 141 /* ------------ ---------------------- --------------------- */ 142 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */ 143 /* */ 144 /**********************************************************************/ 145 /* */ 146 /* The Echo Keisokuki Co. Ltd. JJY receiver LT2000 */ 147 /* */ 148 /* Command Response Remarks */ 149 /* ------------ ---------------------- --------------------- */ 150 /* # Mode 1 (Request&Send) */ 151 /* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */ 152 /* C Mode 2 (Continuous) */ 153 /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */ 154 /* <SUB> Second signal */ 155 /* */ 156 /**********************************************************************/ 157 /* */ 158 /* The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 */ 159 /* */ 160 /* Command Response Remarks */ 161 /* ------------ ---------------------- --------------------- */ 162 /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 163 /* XX: OK|NG|ER */ 164 /* W: 0(Monday)-6(Sunday) */ 165 /* */ 166 /**********************************************************************/ 167 /* */ 168 /* The Tristate Ltd. GPS clock TS-GPSCLOCK-01 */ 169 /* */ 170 /* This clock has NMEA mode and command/respose mode. */ 171 /* When this jjy driver are used, set to command/respose mode */ 172 /* of this clock by the onboard switch SW4, and make sure the */ 173 /* LED-Y is tured on. */ 174 /* Other than this JJY driver, the refclock driver type 20, */ 175 /* generic NMEA driver, works with the NMEA mode of this clock. */ 176 /* */ 177 /* Command Response Remarks */ 178 /* ------------ ---------------------- --------------------- */ 179 /* stus<CR><LF> *R|*G|*U|+U<CR><LF> */ 180 /* date<CR><LF> YY/MM/DD<CR><LF> */ 181 /* time<CR><LF> HH:MM:SS<CR><LF> */ 182 /* */ 183 /**********************************************************************/ 184 185 /* 186 * Interface definitions 187 */ 188 #define DEVICE "/dev/jjy%d" /* device name and unit */ 189 #define SPEED232 B9600 /* uart speed (9600 baud) */ 190 #define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */ 191 #define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */ 192 #define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */ 193 #define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */ 194 #define SPEED232_TRISTATE_GPSCLOCK01 B38400 /* USB speed (38400 baud) */ 195 #define REFID "JJY" /* reference ID */ 196 #define DESCRIPTION "JJY Receiver" 197 #define PRECISION (-3) /* precision assumed (about 100 ms) */ 198 199 /* 200 * JJY unit control structure 201 */ 202 struct jjyunit { 203 char unittype ; /* UNITTYPE_XXXXXXXXXX */ 204 short operationmode ; /* Echo Keisokuki LT-2000 : 1 or 2 */ 205 short version ; 206 short linediscipline ; /* LDISC_CLK or LDISC_RAW */ 207 char bPollFlag ; /* Set by jjy_pool and Reset by jjy_receive */ 208 int linecount ; 209 int lineerror ; 210 int year, month, day, hour, minute, second, msecond ; 211 /* LDISC_RAW only */ 212 #define MAX_LINECOUNT 8 213 #define MAX_RAWBUF 64 214 int lineexpect ; 215 int charexpect [ MAX_LINECOUNT ] ; 216 int charcount ; 217 char rawbuf [ MAX_RAWBUF ] ; 218 }; 219 220 #define UNITTYPE_TRISTATE_JJY01 1 221 #define UNITTYPE_CDEX_JST2000 2 222 #define UNITTYPE_ECHOKEISOKUKI_LT2000 3 223 #define UNITTYPE_CITIZENTIC_JJY200 4 224 #define UNITTYPE_TRISTATE_GPSCLOCK01 5 225 226 /* 227 * Function prototypes 228 */ 229 230 static int jjy_start (int, struct peer *); 231 static void jjy_shutdown (int, struct peer *); 232 233 static void jjy_poll (int, struct peer *); 234 static void jjy_poll_tristate_jjy01 (int, struct peer *); 235 static void jjy_poll_cdex_jst2000 (int, struct peer *); 236 static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *); 237 static void jjy_poll_citizentic_jjy200 (int, struct peer *); 238 static void jjy_poll_tristate_gpsclock01 (int, struct peer *); 239 240 static void jjy_receive (struct recvbuf *); 241 static int jjy_receive_tristate_jjy01 (struct recvbuf *); 242 static int jjy_receive_cdex_jst2000 (struct recvbuf *); 243 static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *); 244 static int jjy_receive_citizentic_jjy200 (struct recvbuf *); 245 static int jjy_receive_tristate_gpsclock01 (struct recvbuf *); 246 247 static void printableString ( char*, int, char*, int ) ; 248 249 /* 250 * Transfer vector 251 */ 252 struct refclock refclock_jjy = { 253 jjy_start, /* start up driver */ 254 jjy_shutdown, /* shutdown driver */ 255 jjy_poll, /* transmit poll message */ 256 noentry, /* not used */ 257 noentry, /* not used */ 258 noentry, /* not used */ 259 NOFLAGS /* not used */ 260 }; 261 262 /* 263 * Start up driver return code 264 */ 265 #define RC_START_SUCCESS 1 266 #define RC_START_ERROR 0 267 268 /* 269 * Local constants definition 270 */ 271 272 #define MAX_LOGTEXT 64 273 274 /* 275 * Tristate JJY01/JJY02 constants definition 276 */ 277 278 #define TS_JJY01_COMMAND_NUMBER_DATE 1 279 #define TS_JJY01_COMMAND_NUMBER_TIME 2 280 #define TS_JJY01_COMMAND_NUMBER_STIM 3 281 #define TS_JJY01_COMMAND_NUMBER_STUS 4 282 #define TS_JJY01_COMMAND_NUMBER_DCST 5 283 284 #define TS_JJY01_REPLY_DATE "yyyy/mm/dd www\r\n" 285 #define TS_JJY01_REPLY_STIM "hh:mm:ss\r\n" 286 #define TS_JJY01_REPLY_STUS_YES "adjusted\r\n" 287 #define TS_JJY01_REPLY_STUS_NO "unadjusted\r\n" 288 #define TS_JJY01_REPLY_DCST_VALID "valid\r\n" 289 #define TS_JJY01_REPLY_DCST_INVALID "invalid\r\n" 290 291 #define TS_JJY01_REPLY_LENGTH_DATE 14 /* Length without <CR><LF> */ 292 #define TS_JJY01_REPLY_LENGTH_STIM 8 /* Length without <CR><LF> */ 293 #define TS_JJY01_REPLY_LENGTH_STUS_YES 8 /* Length without <CR><LF> */ 294 #define TS_JJY01_REPLY_LENGTH_STUS_NO 10 /* Length without <CR><LF> */ 295 #define TS_JJY01_REPLY_LENGTH_DCST_VALID 5 /* Length without <CR><LF> */ 296 #define TS_JJY01_REPLY_LENGTH_DCST_INVALID 7 /* Length without <CR><LF> */ 297 298 static struct 299 { 300 const char commandNumber ; 301 const char *commandLog ; 302 const char *command ; 303 int commandLength ; 304 } tristate_jjy01_command_sequence[] = 305 { 306 /* dcst<CR><LF> -> VALID<CR><LF> or INVALID<CR><LF> */ 307 { TS_JJY01_COMMAND_NUMBER_DCST, "dcst", "dcst\r\n", 6 }, 308 /* stus<CR><LF> -> ADJUSTED<CR><LF> or UNADJUSTED<CR><LF> */ 309 { TS_JJY01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 }, 310 /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */ 311 { TS_JJY01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 }, 312 /* stim<CR><LF> -> HH:MM:SS<CR><LF> */ 313 { TS_JJY01_COMMAND_NUMBER_STIM, "stim", "stim\r\n", 6 }, 314 /* End of command */ 315 { 0, NULL, NULL, 0 } 316 } ; 317 318 /* 319 * Tristate TS-GPSCLOCK01 constants definition 320 */ 321 322 #define TS_GPSCLOCK01_COMMAND_NUMBER_DATE 1 323 #define TS_GPSCLOCK01_COMMAND_NUMBER_TIME 2 324 #define TS_GPSCLOCK01_COMMAND_NUMBER_STUS 4 325 326 #define TS_GPSCLOCK01_REPLY_DATE "yyyy/mm/dd\r\n" 327 #define TS_GPSCLOCK01_REPLY_TIME "hh:mm:ss\r\n" 328 #define TS_GPSCLOCK01_REPLY_STUS_RTC "*R\r\n" 329 #define TS_GPSCLOCK01_REPLY_STUS_GPS "*G\r\n" 330 #define TS_GPSCLOCK01_REPLY_STUS_UTC "*U\r\n" 331 #define TS_GPSCLOCK01_REPLY_STUS_PPS "+U\r\n" 332 333 #define TS_GPSCLOCK01_REPLY_LENGTH_DATE 10 /* Length without <CR><LF> */ 334 #define TS_GPSCLOCK01_REPLY_LENGTH_TIME 8 /* Length without <CR><LF> */ 335 #define TS_GPSCLOCK01_REPLY_LENGTH_STUS 2 /* Length without <CR><LF> */ 336 337 static struct 338 { 339 char commandNumber ; 340 const char *commandLog ; 341 const char *command ; 342 int commandLength ; 343 } tristate_gpsclock01_command_sequence[] = 344 { 345 /* stus<CR><LF> -> *R<CR><LF> or *G<CR><LF> or *U<CR><LF> or +U<CR><LF> */ 346 { TS_GPSCLOCK01_COMMAND_NUMBER_STUS, "stus", "stus\r\n", 6 }, 347 /* date<CR><LF> -> YYYY/MM/DD WWW<CR><LF> */ 348 { TS_GPSCLOCK01_COMMAND_NUMBER_DATE, "date", "date\r\n", 6 }, 349 /* time<CR><LF> -> HH:MM:SS<CR><LF> */ 350 { TS_GPSCLOCK01_COMMAND_NUMBER_TIME, "time", "time\r\n", 6 }, 351 /* End of command */ 352 { 0, NULL, NULL, 0 } 353 } ; 354 355 /**************************************************************************************************/ 356 /* jjy_start - open the devices and initialize data for processing */ 357 /**************************************************************************************************/ 358 static int 359 jjy_start ( int unit, struct peer *peer ) 360 { 361 362 struct jjyunit *up ; 363 struct refclockproc *pp ; 364 int fd ; 365 char *pDeviceName ; 366 short iDiscipline ; 367 int iSpeed232 ; 368 369 char sLogText [ MAX_LOGTEXT ] , sDevText [ MAX_LOGTEXT ] ; 370 371 #ifdef DEBUG 372 if ( debug ) { 373 printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ; 374 printf ( DEVICE, unit ) ; 375 printf ( "\n" ) ; 376 } 377 #endif 378 snprintf ( sDevText, sizeof(sDevText), DEVICE, unit ) ; 379 snprintf ( sLogText, sizeof(sLogText), "*Initialze* %s mode=%d", sDevText, peer->ttl ) ; 380 record_clock_stats ( &peer->srcadr, sLogText ) ; 381 382 /* 383 * Open serial port 384 */ 385 pDeviceName = emalloc ( strlen(DEVICE) + 10 ); 386 snprintf ( pDeviceName, strlen(DEVICE) + 10, DEVICE, unit ) ; 387 388 /* 389 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf 390 */ 391 switch ( peer->ttl ) { 392 case 0 : 393 case 1 : 394 iDiscipline = LDISC_CLK ; 395 iSpeed232 = SPEED232_TRISTATE_JJY01 ; 396 break ; 397 case 2 : 398 iDiscipline = LDISC_RAW ; 399 iSpeed232 = SPEED232_CDEX_JST2000 ; 400 break ; 401 case 3 : 402 iDiscipline = LDISC_CLK ; 403 iSpeed232 = SPEED232_ECHOKEISOKUKI_LT2000 ; 404 break ; 405 case 4 : 406 iDiscipline = LDISC_CLK ; 407 iSpeed232 = SPEED232_CITIZENTIC_JJY200 ; 408 break ; 409 case 5 : 410 iDiscipline = LDISC_CLK ; 411 iSpeed232 = SPEED232_TRISTATE_GPSCLOCK01 ; 412 break ; 413 default : 414 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", 415 ntoa(&peer->srcadr), peer->ttl ) ; 416 free ( (void*) pDeviceName ) ; 417 return RC_START_ERROR ; 418 } 419 420 fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ; 421 if ( fd <= 0 ) { 422 free ( (void*) pDeviceName ) ; 423 return RC_START_ERROR ; 424 } 425 free ( (void*) pDeviceName ) ; 426 427 /* 428 * Allocate and initialize unit structure 429 */ 430 up = emalloc (sizeof(*up)); 431 memset ( up, 0, sizeof(*up) ) ; 432 up->linediscipline = iDiscipline ; 433 434 /* 435 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf 436 */ 437 switch ( peer->ttl ) { 438 case 0 : 439 /* 440 * The mode 0 is a default clock type at this time. 441 * But this will be change to auto-detect mode in the future. 442 */ 443 case 1 : 444 up->unittype = UNITTYPE_TRISTATE_JJY01 ; 445 up->version = 100 ; 446 /* 2010/11/20 */ 447 /* Command sequence is defined by the struct tristate_jjy01_command_sequence, */ 448 /* and the following 3 lines are not used in the mode LDISC_CLK. */ 449 /* up->lineexpect = 2 ; */ 450 /* up->charexpect[0] = 14 ; */ /* YYYY/MM/DD WWW<CR><LF> */ 451 /* up->charexpect[1] = 8 ; */ /* HH:MM:SS<CR><LF> */ 452 break ; 453 case 2 : 454 up->unittype = UNITTYPE_CDEX_JST2000 ; 455 up->lineexpect = 1 ; 456 up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */ 457 break ; 458 case 3 : 459 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ; 460 up->operationmode = 2 ; /* Mode 2 : Continuous mode */ 461 up->lineexpect = 1 ; 462 switch ( up->operationmode ) { 463 case 1 : 464 up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */ 465 break ; 466 case 2 : 467 up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */ 468 break ; 469 } 470 break ; 471 case 4 : 472 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ; 473 up->lineexpect = 1 ; 474 up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 475 break ; 476 case 5 : 477 up->unittype = UNITTYPE_TRISTATE_GPSCLOCK01 ; 478 break ; 479 480 /* 2010/11/20 */ 481 /* The "default:" section of this switch block is never executed, */ 482 /* because the former switch block traps the same "default:" case. */ 483 /* This "default:" section codes are removed to avoid spending time */ 484 /* in the future looking, though the codes are functionally harmless. */ 485 486 } 487 488 pp = peer->procptr ; 489 pp->unitptr = up ; 490 pp->io.clock_recv = jjy_receive ; 491 pp->io.srcclock = peer ; 492 pp->io.datalen = 0 ; 493 pp->io.fd = fd ; 494 if ( ! io_addclock(&pp->io) ) { 495 close ( fd ) ; 496 pp->io.fd = -1 ; 497 free ( up ) ; 498 pp->unitptr = NULL ; 499 return RC_START_ERROR ; 500 } 501 502 /* 503 * Initialize miscellaneous variables 504 */ 505 peer->precision = PRECISION ; 506 pp->clockdesc = DESCRIPTION ; 507 memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ; 508 509 return RC_START_SUCCESS ; 510 511 } 512 513 514 /**************************************************************************************************/ 515 /* jjy_shutdown - shutdown the clock */ 516 /**************************************************************************************************/ 517 static void 518 jjy_shutdown ( int unit, struct peer *peer ) 519 { 520 521 struct jjyunit *up; 522 struct refclockproc *pp; 523 524 pp = peer->procptr ; 525 up = pp->unitptr ; 526 if ( -1 != pp->io.fd ) 527 io_closeclock ( &pp->io ) ; 528 if ( NULL != up ) 529 free ( up ) ; 530 531 } 532 533 534 /**************************************************************************************************/ 535 /* jjy_receive - receive data from the serial interface */ 536 /**************************************************************************************************/ 537 static void 538 jjy_receive ( struct recvbuf *rbufp ) 539 { 540 541 struct jjyunit *up ; 542 struct refclockproc *pp ; 543 struct peer *peer; 544 545 l_fp tRecvTimestamp; /* arrival timestamp */ 546 int rc ; 547 char sLogText [ MAX_LOGTEXT ] ; 548 int i, bCntrlChar ; 549 550 /* 551 * Initialize pointers and read the timecode and timestamp 552 */ 553 peer = rbufp->recv_peer ; 554 pp = peer->procptr ; 555 up = pp->unitptr ; 556 557 /* 558 * Get next input line 559 */ 560 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ; 561 562 if ( up->linediscipline == LDISC_RAW ) { 563 /* 564 * The reply with <STX> and <ETX> may give a blank line 565 */ 566 if ( pp->lencode == 0 && up->charcount == 0 ) return ; 567 /* 568 * Copy received charaters to temporary buffer 569 */ 570 for ( i = 0 ; 571 i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; 572 i ++ , up->charcount ++ ) { 573 up->rawbuf[up->charcount] = pp->a_lastcode[i] ; 574 } 575 while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) { 576 for ( i = 0 ; i < up->charcount - 1 ; i ++ ) 577 up->rawbuf[i] = up->rawbuf[i+1] ; 578 up->charcount -- ; 579 } 580 bCntrlChar = 0 ; 581 for ( i = 0 ; i < up->charcount ; i ++ ) { 582 if ( up->rawbuf[i] < ' ' ) { 583 bCntrlChar = 1 ; 584 break ; 585 } 586 } 587 if ( pp->lencode > 0 && up->linecount < up->lineexpect ) { 588 if ( bCntrlChar == 0 && 589 up->charcount < up->charexpect[up->linecount] ) 590 return ; 591 } 592 up->rawbuf[up->charcount] = 0 ; 593 } else { 594 /* 595 * The reply with <CR><LF> gives a blank line 596 */ 597 if ( pp->lencode == 0 ) return ; 598 } 599 /* 600 * We get down to business 601 */ 602 603 #ifdef DEBUG 604 if ( debug ) { 605 if ( up->linediscipline == LDISC_RAW ) { 606 printableString( sLogText, MAX_LOGTEXT, up->rawbuf, up->charcount ) ; 607 } else { 608 printableString( sLogText, MAX_LOGTEXT, pp->a_lastcode, pp->lencode ) ; 609 } 610 printf ( "jjy_receive (refclock_jjy.c) : [%s]\n", sLogText ) ; 611 } 612 #endif 613 614 pp->lastrec = tRecvTimestamp ; 615 616 up->linecount ++ ; 617 618 if ( up->lineerror != 0 ) return ; 619 620 switch ( up->unittype ) { 621 622 case UNITTYPE_TRISTATE_JJY01 : 623 rc = jjy_receive_tristate_jjy01 ( rbufp ) ; 624 break ; 625 626 case UNITTYPE_CDEX_JST2000 : 627 rc = jjy_receive_cdex_jst2000 ( rbufp ) ; 628 break ; 629 630 case UNITTYPE_ECHOKEISOKUKI_LT2000 : 631 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ; 632 break ; 633 634 case UNITTYPE_CITIZENTIC_JJY200 : 635 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ; 636 break ; 637 638 case UNITTYPE_TRISTATE_GPSCLOCK01 : 639 rc = jjy_receive_tristate_gpsclock01 ( rbufp ) ; 640 break ; 641 642 default : 643 rc = 0 ; 644 break ; 645 646 } 647 648 if ( up->linediscipline == LDISC_RAW ) { 649 if ( up->linecount <= up->lineexpect && 650 up->charcount > up->charexpect[up->linecount-1] ) { 651 for ( i = 0 ; 652 i < up->charcount - up->charexpect[up->linecount-1] ; 653 i ++ ) { 654 up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ; 655 } 656 up->charcount -= up->charexpect[up->linecount-1] ; 657 } else { 658 up->charcount = 0 ; 659 } 660 } 661 662 if ( rc == 0 ) { 663 return ; 664 } 665 666 up->bPollFlag = 0 ; 667 668 if ( up->lineerror != 0 ) { 669 refclock_report ( peer, CEVNT_BADREPLY ) ; 670 strlcpy ( sLogText, "BAD REPLY [", 671 sizeof( sLogText ) ) ; 672 if ( up->linediscipline == LDISC_RAW ) { 673 strlcat ( sLogText, up->rawbuf, 674 sizeof( sLogText ) ) ; 675 } else { 676 strlcat ( sLogText, pp->a_lastcode, 677 sizeof( sLogText ) ) ; 678 } 679 sLogText[MAX_LOGTEXT-1] = 0 ; 680 if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) 681 strlcat ( sLogText, "]", 682 sizeof( sLogText ) ) ; 683 record_clock_stats ( &peer->srcadr, sLogText ) ; 684 return ; 685 } 686 687 pp->year = up->year ; 688 pp->day = ymd2yd ( up->year, up->month, up->day ) ; 689 pp->hour = up->hour ; 690 pp->minute = up->minute ; 691 pp->second = up->second ; 692 pp->nsec = up->msecond * 1000000; 693 694 /* 695 * JST to UTC 696 */ 697 pp->hour -= 9 ; 698 if ( pp->hour < 0 ) { 699 pp->hour += 24 ; 700 pp->day -- ; 701 if ( pp->day < 1 ) { 702 pp->year -- ; 703 pp->day = ymd2yd ( pp->year, 12, 31 ) ; 704 } 705 } 706 #ifdef DEBUG 707 if ( debug ) { 708 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST ", 709 up->year, up->month, up->day, up->hour, 710 up->minute, up->second, up->msecond/100 ) ; 711 printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n", 712 pp->year, pp->day, pp->hour, pp->minute, 713 pp->second, (int)(pp->nsec/100000000) ) ; 714 } 715 #endif 716 717 /* 718 * Process the new sample in the median filter and determine the 719 * timecode timestamp. 720 */ 721 722 snprintf ( sLogText, sizeof(sLogText), 723 "%04d/%02d/%02d %02d:%02d:%02d.%1d JST", 724 up->year, up->month, up->day, 725 up->hour, up->minute, up->second, up->msecond/100 ) ; 726 record_clock_stats ( &peer->srcadr, sLogText ) ; 727 728 if ( ! refclock_process ( pp ) ) { 729 refclock_report(peer, CEVNT_BADTIME); 730 return ; 731 } 732 733 pp->lastref = pp->lastrec; 734 refclock_receive(peer); 735 736 } 737 738 /**************************************************************************************************/ 739 740 static int 741 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp ) 742 { 743 #ifdef DEBUG 744 static const char *sFunctionName = "jjy_receive_tristate_jjy01" ; 745 #endif 746 747 struct jjyunit *up ; 748 struct refclockproc *pp ; 749 struct peer *peer; 750 751 char *pBuf ; 752 int iLen ; 753 int rc ; 754 755 int bOverMidnight = 0 ; 756 757 char sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ; 758 759 const char *pCmd ; 760 int iCmdLen ; 761 762 /* 763 * Initialize pointers and read the timecode and timestamp 764 */ 765 peer = rbufp->recv_peer ; 766 pp = peer->procptr ; 767 up = pp->unitptr ; 768 769 if ( up->linediscipline == LDISC_RAW ) { 770 pBuf = up->rawbuf ; 771 iLen = up->charcount ; 772 } else { 773 pBuf = pp->a_lastcode ; 774 iLen = pp->lencode ; 775 } 776 777 switch ( tristate_jjy01_command_sequence[up->linecount-1].commandNumber ) { 778 779 case TS_JJY01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD WWW */ 780 781 if ( iLen != TS_JJY01_REPLY_LENGTH_DATE ) { 782 up->lineerror = 1 ; 783 break ; 784 } 785 786 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, 787 &up->month, &up->day ) ; 788 if ( rc != 3 || up->year < 2000 || up->month < 1 || 789 up->month > 12 || up->day < 1 || up->day > 31 ) { 790 up->lineerror = 1 ; 791 break ; 792 } 793 794 /*** Start of modification on 2004/10/31 ***/ 795 /* 796 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source. 797 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay. 798 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously, 799 * so this driver issues the second command "stim" after the reply of the first command "date". 800 */ 801 802 /*** 2010/11/20 ***/ 803 /* 804 * Codes of a next command issue are moved to the end of this function. 805 */ 806 807 /*** End of modification ***/ 808 809 break ; 810 811 case TS_JJY01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 812 case TS_JJY01_COMMAND_NUMBER_STIM : /* HH:MM:SS */ 813 814 if ( iLen != TS_JJY01_REPLY_LENGTH_STIM ) { 815 up->lineerror = 1 ; 816 break ; 817 } 818 819 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, 820 &up->minute, &up->second ) ; 821 if ( rc != 3 || up->hour > 23 || up->minute > 59 || 822 up->second > 60 ) { 823 up->lineerror = 1 ; 824 break ; 825 } 826 827 up->msecond = 0 ; 828 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) { 829 /* 830 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver separately, 831 * and the JJY receiver replies a date and time separately. 832 * Just after midnight transitions, we ignore this time. 833 */ 834 bOverMidnight = 1 ; 835 } 836 break ; 837 838 case TS_JJY01_COMMAND_NUMBER_STUS : 839 840 if ( ( iLen == TS_JJY01_REPLY_LENGTH_STUS_YES 841 && strncmp( pBuf, TS_JJY01_REPLY_STUS_YES, 842 TS_JJY01_REPLY_LENGTH_STUS_YES ) == 0 ) 843 || ( iLen == TS_JJY01_REPLY_LENGTH_STUS_NO 844 && strncmp( pBuf, TS_JJY01_REPLY_STUS_NO, 845 TS_JJY01_REPLY_LENGTH_STUS_NO ) == 0 ) ) { 846 /* Good */ 847 } else { 848 up->lineerror = 1 ; 849 break ; 850 } 851 852 break ; 853 854 case TS_JJY01_COMMAND_NUMBER_DCST : 855 856 if ( ( iLen == TS_JJY01_REPLY_LENGTH_DCST_VALID 857 && strncmp( pBuf, TS_JJY01_REPLY_DCST_VALID, 858 TS_JJY01_REPLY_LENGTH_DCST_VALID ) == 0 ) 859 || ( iLen == TS_JJY01_REPLY_LENGTH_DCST_INVALID 860 && strncmp( pBuf, TS_JJY01_REPLY_DCST_INVALID, 861 TS_JJY01_REPLY_LENGTH_DCST_INVALID ) == 0 ) ) { 862 /* Good */ 863 } else { 864 up->lineerror = 1 ; 865 break ; 866 } 867 868 break ; 869 870 default : /* Unexpected reply */ 871 872 up->lineerror = 1 ; 873 break ; 874 875 } 876 877 /* Clockstats Log */ 878 879 printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ; 880 snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s", 881 up->linecount, 882 tristate_jjy01_command_sequence[up->linecount-1].commandLog, 883 ( up->lineerror == 0 ) 884 ? ( ( bOverMidnight == 0 ) 885 ? 'O' 886 : 'S' ) 887 : 'X', 888 sReplyText ) ; 889 record_clock_stats ( &peer->srcadr, sLogText ) ; 890 891 /* Check before issue next command */ 892 893 if ( up->lineerror != 0 ) { 894 /* Do not issue next command */ 895 return 0 ; 896 } 897 898 if ( bOverMidnight != 0 ) { 899 /* Do not issue next command */ 900 return 0 ; 901 } 902 903 if ( tristate_jjy01_command_sequence[up->linecount].command == NULL ) { 904 /* Command sequence completed */ 905 return 1 ; 906 } 907 908 /* Issue next command */ 909 910 #ifdef DEBUG 911 if ( debug ) { 912 printf ( "%s (refclock_jjy.c) : send '%s'\n", 913 sFunctionName, tristate_jjy01_command_sequence[up->linecount].commandLog ) ; 914 } 915 #endif 916 917 pCmd = tristate_jjy01_command_sequence[up->linecount].command ; 918 iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ; 919 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 920 refclock_report ( peer, CEVNT_FAULT ) ; 921 } 922 923 return 0 ; 924 925 } 926 927 /**************************************************************************************************/ 928 929 static int 930 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp ) 931 { 932 #ifdef DEBUG 933 static const char *sFunctionName = "jjy_receive_cdex_jst2000" ; 934 #endif 935 936 struct jjyunit *up ; 937 struct refclockproc *pp ; 938 struct peer *peer; 939 940 char *pBuf ; 941 int iLen ; 942 int rc ; 943 944 /* 945 * Initialize pointers and read the timecode and timestamp 946 */ 947 peer = rbufp->recv_peer ; 948 pp = peer->procptr ; 949 up = pp->unitptr ; 950 951 if ( up->linediscipline == LDISC_RAW ) { 952 pBuf = up->rawbuf ; 953 iLen = up->charcount ; 954 } else { 955 pBuf = pp->a_lastcode ; 956 iLen = pp->lencode ; 957 } 958 959 switch ( up->linecount ) { 960 961 case 1 : /* JYYMMDD HHMMSSS */ 962 963 if ( iLen != 15 ) { 964 #ifdef DEBUG 965 if ( debug >= 2 ) { 966 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", 967 sFunctionName, iLen ) ; 968 } 969 #endif 970 up->lineerror = 1 ; 971 break ; 972 } 973 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d", 974 &up->year, &up->month, &up->day, 975 &up->hour, &up->minute, &up->second, 976 &up->msecond ) ; 977 if ( rc != 7 || up->month < 1 || up->month > 12 || 978 up->day < 1 || up->day > 31 || up->hour > 23 || 979 up->minute > 59 || up->second > 60 ) { 980 #ifdef DEBUG 981 if ( debug >= 2 ) { 982 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", 983 sFunctionName, rc, up->year, 984 up->month, up->day, up->hour, 985 up->minute, up->second, 986 up->msecond ) ; 987 } 988 #endif 989 up->lineerror = 1 ; 990 break ; 991 } 992 up->year += 2000 ; 993 up->msecond *= 100 ; 994 break ; 995 996 default : /* Unexpected reply */ 997 998 up->lineerror = 1 ; 999 break ; 1000 1001 } 1002 1003 return 1 ; 1004 1005 } 1006 1007 /**************************************************************************************************/ 1008 1009 static int 1010 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp ) 1011 { 1012 #ifdef DEBUG 1013 static const char *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ; 1014 #endif 1015 1016 struct jjyunit *up ; 1017 struct refclockproc *pp ; 1018 struct peer *peer; 1019 1020 char *pBuf ; 1021 int iLen ; 1022 int rc ; 1023 int i, ibcc, ibcc1, ibcc2 ; 1024 1025 /* 1026 * Initialize pointers and read the timecode and timestamp 1027 */ 1028 peer = rbufp->recv_peer ; 1029 pp = peer->procptr ; 1030 up = pp->unitptr ; 1031 1032 if ( up->linediscipline == LDISC_RAW ) { 1033 pBuf = up->rawbuf ; 1034 iLen = up->charcount ; 1035 } else { 1036 pBuf = pp->a_lastcode ; 1037 iLen = pp->lencode ; 1038 } 1039 1040 switch ( up->linecount ) { 1041 1042 case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */ 1043 1044 if ( ( up->operationmode == 1 && iLen != 15 ) || 1045 ( up->operationmode == 2 && iLen != 17 ) ) { 1046 #ifdef DEBUG 1047 if ( debug >= 2 ) { 1048 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", 1049 sFunctionName, iLen ) ; 1050 } 1051 #endif 1052 if ( up->operationmode == 1 ) { 1053 #ifdef DEBUG 1054 if ( debug ) { 1055 printf ( "%s (refclock_jjy.c) : send '#'\n", __func__ ) ; 1056 } 1057 #endif 1058 if ( write ( pp->io.fd, "#",1 ) != 1 ) { 1059 refclock_report ( peer, CEVNT_FAULT ) ; 1060 } 1061 } 1062 up->lineerror = 1 ; 1063 break ; 1064 } 1065 1066 if ( up->operationmode == 1 ) { 1067 1068 for ( i = ibcc = 0 ; i < 13 ; i ++ ) 1069 ibcc ^= pBuf[i] ; 1070 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ; 1071 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ; 1072 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) { 1073 #ifdef DEBUG 1074 if ( debug >= 2 ) { 1075 printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", 1076 sFunctionName, 1077 pBuf[13] & 0xFF, 1078 pBuf[14] & 0xFF, 1079 ibcc1, ibcc2 ) ; 1080 } 1081 #endif 1082 up->lineerror = 1 ; 1083 break ; 1084 } 1085 1086 } 1087 1088 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d", 1089 &up->year, &up->month, &up->day, 1090 &up->hour, &up->minute, &up->second ) ; 1091 if ( rc != 6 || up->month < 1 || up->month > 12 || 1092 up->day < 1 || up->day > 31 || up->hour > 23 || 1093 up->minute > 59 || up->second > 60 ) { 1094 #ifdef DEBUG 1095 if ( debug >= 2 ) { 1096 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", 1097 sFunctionName, rc, up->year, 1098 up->month, up->day, up->hour, 1099 up->minute, up->second ) ; 1100 } 1101 #endif 1102 up->lineerror = 1 ; 1103 break ; 1104 } 1105 1106 up->year += 2000 ; 1107 1108 if ( up->operationmode == 2 ) { 1109 1110 /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */ 1111 up->msecond = 500 ; 1112 pp->second -- ; 1113 if ( pp->second < 0 ) { 1114 pp->second = 59 ; 1115 pp->minute -- ; 1116 if ( pp->minute < 0 ) { 1117 pp->minute = 59 ; 1118 pp->hour -- ; 1119 if ( pp->hour < 0 ) { 1120 pp->hour = 23 ; 1121 pp->day -- ; 1122 if ( pp->day < 1 ) { 1123 pp->year -- ; 1124 pp->day = ymd2yd ( pp->year, 12, 31 ) ; 1125 } 1126 } 1127 } 1128 } 1129 1130 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */ 1131 #ifdef DEBUG 1132 if ( debug ) { 1133 printf ( "%s (refclock_jjy.c) : send '#'\n", 1134 sFunctionName ) ; 1135 } 1136 #endif 1137 if ( write ( pp->io.fd, "#",1 ) != 1 ) { 1138 refclock_report ( peer, CEVNT_FAULT ) ; 1139 } 1140 1141 } 1142 1143 break ; 1144 1145 default : /* Unexpected reply */ 1146 1147 #ifdef DEBUG 1148 if ( debug ) { 1149 printf ( "%s (refclock_jjy.c) : send '#'\n", 1150 sFunctionName ) ; 1151 } 1152 #endif 1153 if ( write ( pp->io.fd, "#",1 ) != 1 ) { 1154 refclock_report ( peer, CEVNT_FAULT ) ; 1155 } 1156 1157 up->lineerror = 1 ; 1158 break ; 1159 1160 } 1161 1162 return 1 ; 1163 1164 } 1165 1166 /**************************************************************************************************/ 1167 1168 static int 1169 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp ) 1170 { 1171 #ifdef DEBUG 1172 static const char *sFunctionName = "jjy_receive_citizentic_jjy200" ; 1173 #endif 1174 1175 struct jjyunit *up ; 1176 struct refclockproc *pp ; 1177 struct peer *peer; 1178 1179 char *pBuf ; 1180 int iLen ; 1181 int rc ; 1182 char cApostrophe, sStatus[3] ; 1183 int iWeekday ; 1184 1185 /* 1186 * Initialize pointers and read the timecode and timestamp 1187 */ 1188 peer = rbufp->recv_peer ; 1189 pp = peer->procptr ; 1190 up = pp->unitptr ; 1191 1192 if ( up->linediscipline == LDISC_RAW ) { 1193 pBuf = up->rawbuf ; 1194 iLen = up->charcount ; 1195 } else { 1196 pBuf = pp->a_lastcode ; 1197 iLen = pp->lencode ; 1198 } 1199 1200 /* 1201 * JJY-200 sends a timestamp every second. 1202 * So, a timestamp is ignored unless it is right after polled. 1203 */ 1204 if ( ! up->bPollFlag ) 1205 return 0 ; 1206 1207 switch ( up->linecount ) { 1208 1209 case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 1210 1211 if ( iLen != 23 ) { 1212 #ifdef DEBUG 1213 if ( debug >= 2 ) { 1214 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", 1215 sFunctionName, iLen ) ; 1216 } 1217 #endif 1218 up->lineerror = 1 ; 1219 break ; 1220 } 1221 1222 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d", 1223 &cApostrophe, sStatus, &up->year, 1224 &up->month, &up->day, &iWeekday, 1225 &up->hour, &up->minute, &up->second ) ; 1226 sStatus[2] = 0 ; 1227 if ( rc != 9 || cApostrophe != '\'' || 1228 strcmp( sStatus, "OK" ) != 0 || up->month < 1 || 1229 up->month > 12 || up->day < 1 || up->day > 31 || 1230 iWeekday > 6 || up->hour > 23 || up->minute > 59 || 1231 up->second > 60 ) { 1232 #ifdef DEBUG 1233 if ( debug >= 2 ) { 1234 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", 1235 sFunctionName, rc, cApostrophe, 1236 sStatus, up->year, up->month, 1237 up->day, iWeekday, up->hour, 1238 up->minute, up->second ) ; 1239 } 1240 #endif 1241 up->lineerror = 1 ; 1242 break ; 1243 } 1244 1245 up->year += 2000 ; 1246 up->msecond = 0 ; 1247 1248 break ; 1249 1250 default : /* Unexpected reply */ 1251 1252 up->lineerror = 1 ; 1253 break ; 1254 1255 } 1256 1257 return 1 ; 1258 1259 } 1260 1261 /**************************************************************************************************/ 1262 1263 static int 1264 jjy_receive_tristate_gpsclock01 ( struct recvbuf *rbufp ) 1265 { 1266 #ifdef DEBUG 1267 static const char *sFunctionName = "jjy_receive_tristate_gpsclock01" ; 1268 #endif 1269 1270 struct jjyunit *up ; 1271 struct refclockproc *pp ; 1272 struct peer *peer; 1273 1274 char *pBuf ; 1275 int iLen ; 1276 int rc ; 1277 1278 int bOverMidnight = 0 ; 1279 1280 char sLogText [ MAX_LOGTEXT ], sReplyText [ MAX_LOGTEXT ] ; 1281 1282 const char *pCmd ; 1283 int iCmdLen ; 1284 1285 /* 1286 * Initialize pointers and read the timecode and timestamp 1287 */ 1288 peer = rbufp->recv_peer ; 1289 pp = peer->procptr ; 1290 up = pp->unitptr ; 1291 1292 if ( up->linediscipline == LDISC_RAW ) { 1293 pBuf = up->rawbuf ; 1294 iLen = up->charcount ; 1295 } else { 1296 pBuf = pp->a_lastcode ; 1297 iLen = pp->lencode ; 1298 } 1299 1300 /* 1301 * Ignore NMEA data stream 1302 */ 1303 if ( iLen > 5 1304 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 1305 #ifdef DEBUG 1306 if ( debug ) { 1307 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 1308 sFunctionName, pBuf ) ; 1309 } 1310 #endif 1311 return 0 ; 1312 } 1313 1314 /* 1315 * Skip command prompt '$Cmd>' from the TS-GPSclock-01 1316 */ 1317 if ( iLen == 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 1318 return 0 ; 1319 } else if ( iLen > 5 && strncmp( pBuf, "$Cmd>", 5 ) == 0 ) { 1320 pBuf += 5 ; 1321 iLen -= 5 ; 1322 } 1323 1324 /* 1325 * Ignore NMEA data stream after command prompt 1326 */ 1327 if ( iLen > 5 1328 && ( strncmp( pBuf, "$GP", 3 ) == 0 || strncmp( pBuf, "$PFEC", 5 ) == 0 ) ) { 1329 #ifdef DEBUG 1330 if ( debug ) { 1331 printf ( "%s (refclock_jjy.c) : Skip NMEA stream [%s]\n", 1332 sFunctionName, pBuf ) ; 1333 } 1334 #endif 1335 return 0 ; 1336 } 1337 1338 switch ( tristate_gpsclock01_command_sequence[up->linecount-1].commandNumber ) { 1339 1340 case TS_GPSCLOCK01_COMMAND_NUMBER_DATE : /* YYYY/MM/DD */ 1341 1342 if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_DATE ) { 1343 up->lineerror = 1 ; 1344 break ; 1345 } 1346 1347 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ; 1348 if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || 1349 up->day < 1 || up->day > 31 ) { 1350 up->lineerror = 1 ; 1351 break ; 1352 } 1353 1354 break ; 1355 1356 case TS_GPSCLOCK01_COMMAND_NUMBER_TIME : /* HH:MM:SS */ 1357 1358 if ( iLen != TS_GPSCLOCK01_REPLY_LENGTH_TIME ) { 1359 up->lineerror = 1 ; 1360 break ; 1361 } 1362 1363 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ; 1364 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 1365 up->lineerror = 1 ; 1366 break ; 1367 } 1368 1369 up->msecond = 0 ; 1370 1371 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) { 1372 /* 1373 * The command "date" and "time" were sent to the JJY receiver separately, 1374 * and the JJY receiver replies a date and time separately. 1375 * Just after midnight transitions, we ignore this time. 1376 */ 1377 bOverMidnight = 1 ; 1378 } 1379 1380 break ; 1381 1382 case TS_GPSCLOCK01_COMMAND_NUMBER_STUS : 1383 1384 if ( iLen == TS_GPSCLOCK01_REPLY_LENGTH_STUS 1385 && ( strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_RTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 1386 || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_GPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 1387 || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_UTC, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 1388 || strncmp( pBuf, TS_GPSCLOCK01_REPLY_STUS_PPS, TS_GPSCLOCK01_REPLY_LENGTH_STUS ) == 0 ) ) { 1389 /* Good */ 1390 } else { 1391 up->lineerror = 1 ; 1392 break ; 1393 } 1394 1395 break ; 1396 1397 default : /* Unexpected reply */ 1398 1399 up->lineerror = 1 ; 1400 break ; 1401 1402 } 1403 1404 /* Clockstats Log */ 1405 1406 printableString( sReplyText, sizeof(sReplyText), pBuf, iLen ) ; 1407 snprintf ( sLogText, sizeof(sLogText), "%d: %s -> %c: %s", 1408 up->linecount, 1409 tristate_gpsclock01_command_sequence[up->linecount-1].commandLog, 1410 ( up->lineerror == 0 ) 1411 ? ( ( bOverMidnight == 0 ) 1412 ? 'O' 1413 : 'S' ) 1414 : 'X', 1415 sReplyText ) ; 1416 record_clock_stats ( &peer->srcadr, sLogText ) ; 1417 1418 /* Check before issue next command */ 1419 1420 if ( up->lineerror != 0 ) { 1421 /* Do not issue next command */ 1422 return 0 ; 1423 } 1424 1425 if ( bOverMidnight != 0 ) { 1426 /* Do not issue next command */ 1427 return 0 ; 1428 } 1429 1430 if ( tristate_gpsclock01_command_sequence[up->linecount].command == NULL ) { 1431 /* Command sequence completed */ 1432 return 1 ; 1433 } 1434 1435 /* Issue next command */ 1436 1437 #ifdef DEBUG 1438 if ( debug ) { 1439 printf ( "%s (refclock_jjy.c) : send '%s'\n", 1440 sFunctionName, tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ; 1441 } 1442 #endif 1443 1444 pCmd = tristate_gpsclock01_command_sequence[up->linecount].command ; 1445 iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ; 1446 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1447 refclock_report ( peer, CEVNT_FAULT ) ; 1448 } 1449 1450 return 0 ; 1451 1452 } 1453 1454 /**************************************************************************************************/ 1455 /* jjy_poll - called by the transmit procedure */ 1456 /**************************************************************************************************/ 1457 static void 1458 jjy_poll ( int unit, struct peer *peer ) 1459 { 1460 1461 struct jjyunit *up; 1462 struct refclockproc *pp; 1463 1464 pp = peer->procptr; 1465 up = pp->unitptr ; 1466 1467 if ( pp->polls > 0 && up->linecount == 0 ) { 1468 /* 1469 * No reply for last command 1470 */ 1471 refclock_report ( peer, CEVNT_TIMEOUT ) ; 1472 } 1473 1474 #ifdef DEBUG 1475 if ( debug ) { 1476 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ; 1477 } 1478 #endif 1479 1480 pp->polls ++ ; 1481 1482 up->bPollFlag = 1 ; 1483 up->linecount = 0 ; 1484 up->lineerror = 0 ; 1485 up->charcount = 0 ; 1486 1487 switch ( up->unittype ) { 1488 1489 case UNITTYPE_TRISTATE_JJY01 : 1490 jjy_poll_tristate_jjy01 ( unit, peer ) ; 1491 break ; 1492 1493 case UNITTYPE_CDEX_JST2000 : 1494 jjy_poll_cdex_jst2000 ( unit, peer ) ; 1495 break ; 1496 1497 case UNITTYPE_ECHOKEISOKUKI_LT2000 : 1498 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ; 1499 break ; 1500 1501 case UNITTYPE_CITIZENTIC_JJY200 : 1502 jjy_poll_citizentic_jjy200 ( unit, peer ) ; 1503 break ; 1504 1505 case UNITTYPE_TRISTATE_GPSCLOCK01 : 1506 jjy_poll_tristate_gpsclock01 ( unit, peer ) ; 1507 break ; 1508 1509 default : 1510 break ; 1511 1512 } 1513 1514 } 1515 1516 /**************************************************************************************************/ 1517 1518 static void 1519 jjy_poll_tristate_jjy01 ( int unit, struct peer *peer ) 1520 { 1521 #ifdef DEBUG 1522 static const char *sFunctionName = "jjy_poll_tristate_jjy01" ; 1523 #endif 1524 1525 struct jjyunit *up; 1526 struct refclockproc *pp; 1527 1528 const char *pCmd ; 1529 int iCmdLen ; 1530 1531 pp = peer->procptr; 1532 up = pp->unitptr ; 1533 1534 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 1535 up->linecount = 2 ; 1536 } 1537 1538 #ifdef DEBUG 1539 if ( debug ) { 1540 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n", 1541 sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 1542 up->linecount ) ; 1543 } 1544 #endif 1545 1546 /* 1547 * Send a first command 1548 */ 1549 1550 #ifdef DEBUG 1551 if ( debug ) { 1552 printf ( "%s (refclock_jjy.c) : send '%s'\n", 1553 sFunctionName, 1554 tristate_jjy01_command_sequence[up->linecount].commandLog ) ; 1555 } 1556 #endif 1557 1558 pCmd = tristate_jjy01_command_sequence[up->linecount].command ; 1559 iCmdLen = tristate_jjy01_command_sequence[up->linecount].commandLength ; 1560 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1561 refclock_report ( peer, CEVNT_FAULT ) ; 1562 } 1563 1564 } 1565 1566 /**************************************************************************************************/ 1567 1568 static void 1569 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer ) 1570 { 1571 1572 struct refclockproc *pp; 1573 1574 pp = peer->procptr; 1575 1576 /* 1577 * Send "<ENQ>1J<ETX>" command 1578 */ 1579 1580 #ifdef DEBUG 1581 if ( debug ) { 1582 printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ; 1583 } 1584 #endif 1585 1586 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) { 1587 refclock_report ( peer, CEVNT_FAULT ) ; 1588 } 1589 1590 } 1591 1592 /**************************************************************************************************/ 1593 1594 static void 1595 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer ) 1596 { 1597 1598 struct jjyunit *up; 1599 struct refclockproc *pp; 1600 1601 char sCmd[2] ; 1602 1603 pp = peer->procptr; 1604 up = pp->unitptr ; 1605 1606 /* 1607 * Send "T" or "C" command 1608 */ 1609 1610 switch ( up->operationmode ) { 1611 case 1 : sCmd[0] = 'T' ; break ; 1612 case 2 : sCmd[0] = 'C' ; break ; 1613 } 1614 sCmd[1] = 0 ; 1615 1616 #ifdef DEBUG 1617 if ( debug ) { 1618 printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ; 1619 } 1620 #endif 1621 1622 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) { 1623 refclock_report ( peer, CEVNT_FAULT ) ; 1624 } 1625 1626 } 1627 1628 /**************************************************************************************************/ 1629 1630 static void 1631 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer ) 1632 { 1633 1634 /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */ 1635 1636 } 1637 1638 /**************************************************************************************************/ 1639 1640 static void 1641 jjy_poll_tristate_gpsclock01 ( int unit, struct peer *peer ) 1642 { 1643 #ifdef DEBUG 1644 static const char *sFunctionName = "jjy_poll_tristate_gpsclock01" ; 1645 #endif 1646 1647 struct jjyunit *up; 1648 struct refclockproc *pp; 1649 1650 const char *pCmd ; 1651 int iCmdLen ; 1652 1653 pp = peer->procptr; 1654 up = pp->unitptr ; 1655 1656 if ( ( pp->sloppyclockflag & CLK_FLAG1 ) == 0 ) { 1657 up->linecount = 1 ; 1658 } 1659 1660 #ifdef DEBUG 1661 if ( debug ) { 1662 printf ( "%s (refclock_jjy.c) : flag1=%X CLK_FLAG1=%X up->linecount=%d\n", 1663 sFunctionName, pp->sloppyclockflag, CLK_FLAG1, 1664 up->linecount ) ; 1665 } 1666 #endif 1667 1668 /* 1669 * Send a first command 1670 */ 1671 1672 #ifdef DEBUG 1673 if ( debug ) { 1674 printf ( "%s (refclock_jjy.c) : send '%s'\n", 1675 sFunctionName, 1676 tristate_gpsclock01_command_sequence[up->linecount].commandLog ) ; 1677 } 1678 #endif 1679 1680 pCmd = tristate_gpsclock01_command_sequence[up->linecount].command ; 1681 iCmdLen = tristate_gpsclock01_command_sequence[up->linecount].commandLength ; 1682 if ( write ( pp->io.fd, pCmd, iCmdLen ) != iCmdLen ) { 1683 refclock_report ( peer, CEVNT_FAULT ) ; 1684 } 1685 1686 } 1687 1688 /**************************************************************************************************/ 1689 1690 static void 1691 printableString ( char *sOutput, int iOutputLen, char *sInput, int iInputLen ) 1692 { 1693 const char *printableControlChar[] = { 1694 "<NUL>", "<SOH>", "<STX>", "<ETX>", 1695 "<EOT>", "<ENQ>", "<ACK>", "<BEL>", 1696 "<BS>" , "<HT>" , "<LF>" , "<VT>" , 1697 "<FF>" , "<CR>" , "<SO>" , "<SI>" , 1698 "<DLE>", "<DC1>", "<DC2>", "<DC3>", 1699 "<DC4>", "<NAK>", "<SYN>", "<ETB>", 1700 "<CAN>", "<EM>" , "<SUB>", "<ESC>", 1701 "<FS>" , "<GS>" , "<RS>" , "<US>" , 1702 " " } ; 1703 1704 size_t i, j, n ; 1705 size_t InputLen; 1706 size_t OutputLen; 1707 1708 InputLen = (size_t)iInputLen; 1709 OutputLen = (size_t)iOutputLen; 1710 for ( i = j = 0 ; i < InputLen && j < OutputLen ; i ++ ) { 1711 if ( isprint( (unsigned char)sInput[i] ) ) { 1712 n = 1 ; 1713 if ( j + 1 >= OutputLen ) 1714 break ; 1715 sOutput[j] = sInput[i] ; 1716 } else if ( ( sInput[i] & 0xFF ) < 1717 COUNTOF(printableControlChar) ) { 1718 n = strlen( printableControlChar[sInput[i] & 0xFF] ) ; 1719 if ( j + n + 1 >= OutputLen ) 1720 break ; 1721 strlcpy( sOutput + j, 1722 printableControlChar[sInput[i] & 0xFF], 1723 OutputLen - j ) ; 1724 } else { 1725 n = 5 ; 1726 if ( j + n + 1 >= OutputLen ) 1727 break ; 1728 snprintf( sOutput + j, OutputLen - j, "<x%X>", 1729 sInput[i] & 0xFF ) ; 1730 } 1731 j += n ; 1732 } 1733 1734 sOutput[min(j, (size_t)iOutputLen - 1)] = '\0' ; 1735 1736 } 1737 1738 /**************************************************************************************************/ 1739 1740 #else 1741 int refclock_jjy_bs ; 1742 #endif /* REFCLOCK */ 1743