1 /* $NetBSD: refclock_jjy.c,v 1.1.1.1 2009/12/13 16:55:50 kardel Exp $ */ 2 3 /* 4 * refclock_jjy - clock driver for JJY receivers 5 */ 6 7 /**********************************************************************/ 8 /* */ 9 /* Copyright (C) 2001-2004, 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 abetakao@bea.hi-ho.ne.jp */ 47 /* Homepage http://www.bea.hi-ho.ne.jp/abetakao/ */ 48 /* */ 49 /**********************************************************************/ 50 /* */ 51 /* History */ 52 /* */ 53 /* 2001/07/15 */ 54 /* [New] Support the Tristate Ltd. JJY receiver */ 55 /* */ 56 /* 2001/08/04 */ 57 /* [Change] Log to clockstats even if bad reply */ 58 /* [Fix] PRECISION = (-3) (about 100 ms) */ 59 /* [Add] Support the C-DEX Co.Ltd. JJY receiver */ 60 /* */ 61 /* 2001/12/04 */ 62 /* [Fix] C-DEX JST2000 ( fukusima@goto.info.waseda.ac.jp ) */ 63 /* */ 64 /* 2002/07/12 */ 65 /* [Fix] Portability for FreeBSD ( patched by the user ) */ 66 /* */ 67 /* 2004/10/31 */ 68 /* [Change] Command send timing for the Tristate Ltd. JJY receiver */ 69 /* JJY-01 ( Firmware version 2.01 ) */ 70 /* Thanks to Andy Taki for testing under FreeBSD */ 71 /* */ 72 /* 2004/11/28 */ 73 /* [Add] Support the Echo Keisokuki LT-2000 receiver */ 74 /* */ 75 /* 2006/11/04 */ 76 /* [Fix] C-DEX JST2000 */ 77 /* Thanks to Hideo Kuramatsu for the patch */ 78 /* */ 79 /* 2009/04/05 */ 80 /* [Add] Support the CITIZEN T.I.C JJY-200 receiver */ 81 /* */ 82 /**********************************************************************/ 83 84 #ifdef HAVE_CONFIG_H 85 #include <config.h> 86 #endif 87 88 #if defined(REFCLOCK) && defined(CLOCK_JJY) 89 90 #include <stdio.h> 91 #include <ctype.h> 92 #include <string.h> 93 #include <sys/time.h> 94 #include <time.h> 95 96 #include "ntpd.h" 97 #include "ntp_io.h" 98 #include "ntp_tty.h" 99 #include "ntp_refclock.h" 100 #include "ntp_calendar.h" 101 #include "ntp_stdlib.h" 102 103 /**********************************************************************/ 104 /* */ 105 /* The Tristate Ltd. JJY receiver JJY01 */ 106 /* */ 107 /* Command Response Remarks */ 108 /* ------------ ---------------------- --------------------- */ 109 /* date<CR><LF> YYYY/MM/DD XXX<CR><LF> */ 110 /* time<CR><LF> HH:MM:SS<CR><LF> */ 111 /* stim<CR><LF> HH:MM:SS<CR><LF> Reply at just second */ 112 /* */ 113 /* During synchronization after a receiver is turned on, */ 114 /* It replies the past time from 2000/01/01 00:00:00. */ 115 /* The function "refclock_process" checks the time and tells */ 116 /* as an insanity time. */ 117 /* */ 118 /**********************************************************************/ 119 /* */ 120 /* The C-DEX Co. Ltd. JJY receiver JST2000 */ 121 /* */ 122 /* Command Response Remarks */ 123 /* ------------ ---------------------- --------------------- */ 124 /* <ENQ>1J<ETX> <STX>JYYMMDD HHMMSSS<ETX> */ 125 /* */ 126 /**********************************************************************/ 127 /* */ 128 /* The Echo Keisokuki Co. Ltd. JJY receiver LT2000 */ 129 /* */ 130 /* Command Response Remarks */ 131 /* ------------ ---------------------- --------------------- */ 132 /* # Mode 1 (Request&Send) */ 133 /* T YYMMDDWHHMMSS<BCC1><BCC2><CR> */ 134 /* C Mode 2 (Continuous) */ 135 /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */ 136 /* <SUB> Second signal */ 137 /* */ 138 /**********************************************************************/ 139 /* */ 140 /* The CITIZEN T.I.C CO., LTD. JJY receiver JJY200 */ 141 /* */ 142 /* Command Response Remarks */ 143 /* ------------ ---------------------- --------------------- */ 144 /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 145 /* XX: OK|NG|ER */ 146 /* W: 0(Monday)-6(Sunday) */ 147 /* */ 148 /**********************************************************************/ 149 150 /* 151 * Interface definitions 152 */ 153 #define DEVICE "/dev/jjy%d" /* device name and unit */ 154 #define SPEED232 B9600 /* uart speed (9600 baud) */ 155 #define SPEED232_TRISTATE_JJY01 B9600 /* UART speed (9600 baud) */ 156 #define SPEED232_CDEX_JST2000 B9600 /* UART speed (9600 baud) */ 157 #define SPEED232_ECHOKEISOKUKI_LT2000 B9600 /* UART speed (9600 baud) */ 158 #define SPEED232_CITIZENTIC_JJY200 B4800 /* UART speed (4800 baud) */ 159 #define REFID "JJY" /* reference ID */ 160 #define DESCRIPTION "JJY Receiver" 161 #define PRECISION (-3) /* precision assumed (about 100 ms) */ 162 163 /* 164 * JJY unit control structure 165 */ 166 struct jjyunit { 167 char unittype ; /* UNITTYPE_XXXXXXXXXX */ 168 short operationmode ; /* Echo Keisokuki LT-2000 : 1 or 2 */ 169 short version ; 170 short linediscipline ; /* LDISC_CLK or LDISC_RAW */ 171 char bPollFlag ; /* Set by jjy_pool and Reset by jjy_receive */ 172 int linecount ; 173 int lineerror ; 174 int year, month, day, hour, minute, second, msecond ; 175 /* LDISC_RAW only */ 176 #define MAX_LINECOUNT 8 177 #define MAX_RAWBUF 64 178 int lineexpect ; 179 int charexpect [ MAX_LINECOUNT ] ; 180 int charcount ; 181 char rawbuf [ MAX_RAWBUF ] ; 182 }; 183 184 #define UNITTYPE_TRISTATE_JJY01 1 185 #define UNITTYPE_CDEX_JST2000 2 186 #define UNITTYPE_ECHOKEISOKUKI_LT2000 3 187 #define UNITTYPE_CITIZENTIC_JJY200 4 188 189 /* 190 * Function prototypes 191 */ 192 static int jjy_start (int, struct peer *); 193 static void jjy_shutdown (int, struct peer *); 194 static void jjy_poll (int, struct peer *); 195 static void jjy_poll_tristate_jjy01 (int, struct peer *); 196 static void jjy_poll_cdex_jst2000 (int, struct peer *); 197 static void jjy_poll_echokeisokuki_lt2000 (int, struct peer *); 198 static void jjy_poll_citizentic_jjy200 (int, struct peer *); 199 static void jjy_receive (struct recvbuf *); 200 static int jjy_receive_tristate_jjy01 (struct recvbuf *); 201 static int jjy_receive_cdex_jst2000 (struct recvbuf *); 202 static int jjy_receive_echokeisokuki_lt2000 (struct recvbuf *); 203 static int jjy_receive_citizentic_jjy200 (struct recvbuf *); 204 205 /* 206 * Transfer vector 207 */ 208 struct refclock refclock_jjy = { 209 jjy_start, /* start up driver */ 210 jjy_shutdown, /* shutdown driver */ 211 jjy_poll, /* transmit poll message */ 212 noentry, /* not used */ 213 noentry, /* not used */ 214 noentry, /* not used */ 215 NOFLAGS /* not used */ 216 }; 217 218 /* 219 * Start up driver return code 220 */ 221 #define RC_START_SUCCESS 1 222 #define RC_START_ERROR 0 223 224 /* 225 * Local constants definition 226 */ 227 228 #define MAX_LOGTEXT 64 229 230 231 /**************************************************************************************************/ 232 /* jjy_start - open the devices and initialize data for processing */ 233 /**************************************************************************************************/ 234 static int 235 jjy_start ( int unit, struct peer *peer ) 236 { 237 238 struct jjyunit *up ; 239 struct refclockproc *pp ; 240 int fd ; 241 char *pDeviceName ; 242 short iDiscipline ; 243 int iSpeed232 ; 244 245 #ifdef DEBUG 246 if ( debug ) { 247 printf ( "jjy_start (refclock_jjy.c) : %s mode=%d ", ntoa(&peer->srcadr), peer->ttl ) ; 248 printf ( DEVICE, unit ) ; 249 printf ( "\n" ) ; 250 } 251 #endif 252 /* 253 * Open serial port 254 */ 255 if ( ! ( pDeviceName = (char*) emalloc ( strlen(DEVICE) + 10 ) ) ) { 256 return RC_START_ERROR ; 257 } 258 sprintf ( pDeviceName, DEVICE, unit ) ; 259 260 /* 261 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf 262 */ 263 switch ( peer->ttl ) { 264 case 0 : 265 case 1 : 266 iDiscipline = LDISC_CLK ; 267 iSpeed232 = SPEED232_TRISTATE_JJY01 ; 268 break ; 269 case 2 : 270 iDiscipline = LDISC_RAW ; 271 iSpeed232 = SPEED232_CDEX_JST2000 ; 272 break ; 273 case 3 : 274 iDiscipline = LDISC_CLK ; 275 iSpeed232 = SPEED232_ECHOKEISOKUKI_LT2000 ; 276 break ; 277 case 4 : 278 iDiscipline = LDISC_CLK ; 279 iSpeed232 = SPEED232_CITIZENTIC_JJY200 ; 280 break ; 281 default : 282 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", 283 ntoa(&peer->srcadr), peer->ttl ) ; 284 free ( (void*) pDeviceName ) ; 285 return RC_START_ERROR ; 286 } 287 288 if ( ! ( fd = refclock_open ( pDeviceName, iSpeed232, iDiscipline ) ) ) { 289 free ( (void*) pDeviceName ) ; 290 return RC_START_ERROR ; 291 } 292 free ( (void*) pDeviceName ) ; 293 294 /* 295 * Allocate and initialize unit structure 296 */ 297 if ( ! ( up = (struct jjyunit *) emalloc (sizeof(struct jjyunit)) ) ) { 298 close ( fd ) ; 299 return RC_START_ERROR ; 300 } 301 302 memset ( (char*)up, 0, sizeof(struct jjyunit) ) ; 303 up->linediscipline = iDiscipline ; 304 305 /* 306 * peer->ttl is a mode number specified by "127.127.40.X mode N" in the ntp.conf 307 */ 308 switch ( peer->ttl ) { 309 case 0 : 310 /* 311 * The mode 0 is a default clock type at this time. 312 * But this will be change to auto-detect mode in the future. 313 */ 314 case 1 : 315 up->unittype = UNITTYPE_TRISTATE_JJY01 ; 316 up->version = 100 ; 317 up->lineexpect = 2 ; 318 up->charexpect[0] = 14 ; /* YYYY/MM/DD WWW<CR><LF> */ 319 up->charexpect[1] = 8 ; /* HH:MM:SS<CR><LF> */ 320 break ; 321 case 2 : 322 up->unittype = UNITTYPE_CDEX_JST2000 ; 323 up->lineexpect = 1 ; 324 up->charexpect[0] = 15 ; /* <STX>JYYMMDD HHMMSSS<ETX> */ 325 break ; 326 case 3 : 327 up->unittype = UNITTYPE_ECHOKEISOKUKI_LT2000 ; 328 up->operationmode = 2 ; /* Mode 2 : Continuous mode */ 329 up->lineexpect = 1 ; 330 switch ( up->operationmode ) { 331 case 1 : 332 up->charexpect[0] = 15 ; /* YYMMDDWHHMMSS<BCC1><BCC2><CR> */ 333 break ; 334 case 2 : 335 up->charexpect[0] = 17 ; /* YYMMDDWHHMMSS<ST1><ST2><ST3><ST4><CR> */ 336 break ; 337 } 338 break ; 339 case 4 : 340 up->unittype = UNITTYPE_CITIZENTIC_JJY200 ; 341 up->lineexpect = 1 ; 342 up->charexpect[0] = 23 ; /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 343 break ; 344 default : 345 msyslog ( LOG_ERR, "JJY receiver [ %s mode %d ] : Unsupported mode", 346 ntoa(&peer->srcadr), peer->ttl ) ; 347 close ( fd ) ; 348 free ( (void*) up ) ; 349 return RC_START_ERROR ; 350 } 351 352 pp = peer->procptr ; 353 pp->unitptr = (caddr_t) up ; 354 pp->io.clock_recv = jjy_receive ; 355 pp->io.srcclock = (caddr_t) peer ; 356 pp->io.datalen = 0 ; 357 pp->io.fd = fd ; 358 if ( ! io_addclock(&pp->io) ) { 359 close ( fd ) ; 360 free ( (void*) up ) ; 361 return RC_START_ERROR ; 362 } 363 364 /* 365 * Initialize miscellaneous variables 366 */ 367 peer->precision = PRECISION ; 368 peer->burst = 1 ; 369 pp->clockdesc = DESCRIPTION ; 370 memcpy ( (char*)&pp->refid, REFID, strlen(REFID) ) ; 371 372 return RC_START_SUCCESS ; 373 374 } 375 376 377 /**************************************************************************************************/ 378 /* jjy_shutdown - shutdown the clock */ 379 /**************************************************************************************************/ 380 static void 381 jjy_shutdown ( int unit, struct peer *peer ) 382 { 383 384 struct jjyunit *up; 385 struct refclockproc *pp; 386 387 pp = peer->procptr ; 388 up = (struct jjyunit *) pp->unitptr ; 389 io_closeclock ( &pp->io ) ; 390 free ( (void*) up ) ; 391 392 } 393 394 395 /**************************************************************************************************/ 396 /* jjy_receive - receive data from the serial interface */ 397 /**************************************************************************************************/ 398 static void 399 jjy_receive ( struct recvbuf *rbufp ) 400 { 401 402 struct jjyunit *up ; 403 struct refclockproc *pp ; 404 struct peer *peer; 405 406 l_fp tRecvTimestamp; /* arrival timestamp */ 407 int rc ; 408 char sLogText [ MAX_LOGTEXT ] ; 409 int i, bCntrlChar ; 410 411 /* 412 * Initialize pointers and read the timecode and timestamp 413 */ 414 peer = (struct peer *) rbufp->recv_srcclock ; 415 pp = peer->procptr ; 416 up = (struct jjyunit *) pp->unitptr ; 417 418 /* 419 * Get next input line 420 */ 421 pp->lencode = refclock_gtlin ( rbufp, pp->a_lastcode, BMAX, &tRecvTimestamp ) ; 422 423 if ( up->linediscipline == LDISC_RAW ) { 424 /* 425 * The reply with <STX> and <ETX> may give a blank line 426 */ 427 if ( pp->lencode == 0 && up->charcount == 0 ) return ; 428 /* 429 * Copy received charaters to temporary buffer 430 */ 431 for ( i = 0 ; i < pp->lencode && up->charcount < MAX_RAWBUF - 2 ; i ++ , up->charcount ++ ) { 432 up->rawbuf[up->charcount] = pp->a_lastcode[i] ; 433 } 434 while ( up->charcount > 0 && up->rawbuf[0] < ' ' ) { 435 for ( i = 0 ; i < up->charcount - 1 ; i ++ ) up->rawbuf[i] = up->rawbuf[i+1] ; 436 up->charcount -- ; 437 } 438 bCntrlChar = 0 ; 439 for ( i = 0 ; i < up->charcount ; i ++ ) { 440 if ( up->rawbuf[i] < ' ' ) { 441 bCntrlChar = 1 ; 442 break ; 443 } 444 } 445 if ( pp->lencode > 0 && up->linecount < up->lineexpect ) { 446 if ( bCntrlChar == 0 && up->charcount < up->charexpect[up->linecount] ) return ; 447 } 448 up->rawbuf[up->charcount] = 0 ; 449 } else { 450 /* 451 * The reply with <CR><LF> gives a blank line 452 */ 453 if ( pp->lencode == 0 ) return ; 454 } 455 /* 456 * We get down to business 457 */ 458 459 pp->lastrec = tRecvTimestamp ; 460 461 up->linecount ++ ; 462 463 if ( up->lineerror != 0 ) return ; 464 465 switch ( up->unittype ) { 466 467 case UNITTYPE_TRISTATE_JJY01 : 468 rc = jjy_receive_tristate_jjy01 ( rbufp ) ; 469 break ; 470 471 case UNITTYPE_CDEX_JST2000 : 472 rc = jjy_receive_cdex_jst2000 ( rbufp ) ; 473 break ; 474 475 case UNITTYPE_ECHOKEISOKUKI_LT2000 : 476 rc = jjy_receive_echokeisokuki_lt2000 ( rbufp ) ; 477 break ; 478 479 case UNITTYPE_CITIZENTIC_JJY200 : 480 rc = jjy_receive_citizentic_jjy200 ( rbufp ) ; 481 break ; 482 483 default : 484 rc = 0 ; 485 break ; 486 487 } 488 489 if ( up->linediscipline == LDISC_RAW ) { 490 if ( up->linecount <= up->lineexpect && up->charcount > up->charexpect[up->linecount-1] ) { 491 for ( i = 0 ; i < up->charcount - up->charexpect[up->linecount-1] ; i ++ ) { 492 up->rawbuf[i] = up->rawbuf[i+up->charexpect[up->linecount-1]] ; 493 } 494 up->charcount -= up->charexpect[up->linecount-1] ; 495 } else { 496 up->charcount = 0 ; 497 } 498 } 499 500 if ( rc == 0 ) return ; 501 502 up->bPollFlag = 0 ; 503 504 if ( up->lineerror != 0 ) { 505 refclock_report ( peer, CEVNT_BADREPLY ) ; 506 strcpy ( sLogText, "BAD REPLY [" ) ; 507 if ( up->linediscipline == LDISC_RAW ) { 508 strncat ( sLogText, up->rawbuf, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ; 509 } else { 510 strncat ( sLogText, pp->a_lastcode, MAX_LOGTEXT - strlen ( sLogText ) - 1 ) ; 511 } 512 sLogText[MAX_LOGTEXT-1] = 0 ; 513 if ( strlen ( sLogText ) < MAX_LOGTEXT - 2 ) strcat ( sLogText, "]" ) ; 514 record_clock_stats ( &peer->srcadr, sLogText ) ; 515 return ; 516 } 517 518 pp->year = up->year ; 519 pp->day = ymd2yd ( up->year, up->month, up->day ) ; 520 pp->hour = up->hour ; 521 pp->minute = up->minute ; 522 pp->second = up->second ; 523 pp->nsec = up->msecond * 1000000; 524 525 /* 526 * JST to UTC 527 */ 528 pp->hour -= 9 ; 529 if ( pp->hour < 0 ) { 530 pp->hour += 24 ; 531 pp->day -- ; 532 if ( pp->day < 1 ) { 533 pp->year -- ; 534 pp->day = ymd2yd ( pp->year, 12, 31 ) ; 535 } 536 } 537 #ifdef DEBUG 538 if ( debug ) { 539 printf ( "jjy_receive (refclock_jjy.c) : %04d/%02d/%02d %02d:%02d:%02d.%1d JST ", 540 up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ; 541 printf ( "( %04d/%03d %02d:%02d:%02d.%1d UTC )\n", 542 pp->year, pp->day, pp->hour, pp->minute, pp->second, (int)(pp->nsec/100000000) ) ; 543 } 544 #endif 545 546 /* 547 * Process the new sample in the median filter and determine the 548 * timecode timestamp. 549 */ 550 551 sprintf ( sLogText, "%04d/%02d/%02d %02d:%02d:%02d.%1d JST", 552 up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond/100 ) ; 553 record_clock_stats ( &peer->srcadr, sLogText ) ; 554 555 if ( ! refclock_process ( pp ) ) { 556 refclock_report(peer, CEVNT_BADTIME); 557 return ; 558 } 559 560 pp->lastref = pp->lastrec; 561 refclock_receive(peer); 562 563 } 564 565 /**************************************************************************************************/ 566 567 static int 568 jjy_receive_tristate_jjy01 ( struct recvbuf *rbufp ) 569 { 570 571 static char *sFunctionName = "jjy_receive_tristate_jjy01" ; 572 573 struct jjyunit *up ; 574 struct refclockproc *pp ; 575 struct peer *peer; 576 577 char *pBuf ; 578 int iLen ; 579 int rc ; 580 581 /* 582 * Initialize pointers and read the timecode and timestamp 583 */ 584 peer = (struct peer *) rbufp->recv_srcclock ; 585 pp = peer->procptr ; 586 up = (struct jjyunit *) pp->unitptr ; 587 588 if ( up->linediscipline == LDISC_RAW ) { 589 pBuf = up->rawbuf ; 590 iLen = up->charcount ; 591 } else { 592 pBuf = pp->a_lastcode ; 593 iLen = pp->lencode ; 594 } 595 596 switch ( up->linecount ) { 597 598 case 1 : /* YYYY/MM/DD WWW */ 599 600 if ( iLen != 14 ) { 601 #ifdef DEBUG 602 if ( debug >= 2 ) { 603 printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ; 604 } 605 #endif 606 up->lineerror = 1 ; 607 break ; 608 } 609 rc = sscanf ( pBuf, "%4d/%2d/%2d", &up->year, &up->month, &up->day ) ; 610 if ( rc != 3 || up->year < 2000 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 ) { 611 #ifdef DEBUG 612 if ( debug >= 2 ) { 613 printf ( "%s (refclock_jjy.c) : Date error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ; 614 } 615 #endif 616 up->lineerror = 1 ; 617 break ; 618 } 619 620 /*** Start of modification on 2004/10/31 */ 621 /* 622 * Following codes are moved from the function jjy_poll_tristate_jjy01 in this source. 623 * The Tristate JJY-01 ( Firmware version 1.01 ) accepts "time" and "stim" commands without any delay. 624 * But the JJY-01 ( Firmware version 2.01 ) does not accept these commands continuously, 625 * so this driver issues the second command "stim" after the reply of the first command "date". 626 */ 627 628 /* 629 * Send "stim<CR><LF>" or "time<CR><LF>" command 630 */ 631 632 633 if ( up->version >= 100 ) { 634 #ifdef DEBUG 635 if ( debug ) { 636 printf ( "%s (refclock_jjy.c) : send 'stim<CR><LF>'\n", sFunctionName ) ; 637 } 638 #endif 639 if ( write ( pp->io.fd, "stim\r\n",6 ) != 6 ) { 640 refclock_report ( peer, CEVNT_FAULT ) ; 641 } 642 } else { 643 #ifdef DEBUG 644 if ( debug ) { 645 printf ( "%s (refclock_jjy.c) : send 'time<CR><LF>'\n", sFunctionName ) ; 646 } 647 #endif 648 if ( write ( pp->io.fd, "time\r\n",6 ) != 6 ) { 649 refclock_report ( peer, CEVNT_FAULT ) ; 650 } 651 } 652 /*** End of modification ***/ 653 654 return 0 ; 655 656 case 2 : /* HH:MM:SS */ 657 658 if ( iLen != 8 ) { 659 #ifdef DEBUG 660 if ( debug >= 2 ) { 661 printf ( "%s (refclock_jjy.c) : Reply length error ( up->linecount=%d iLen=%d )\n", sFunctionName, up->linecount, iLen ) ; 662 } 663 #endif 664 up->lineerror = 1 ; 665 break ; 666 } 667 rc = sscanf ( pBuf, "%2d:%2d:%2d", &up->hour, &up->minute, &up->second ) ; 668 if ( rc != 3 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 669 #ifdef DEBUG 670 if ( debug >= 2 ) { 671 printf ( "%s (refclock_jjy.c) : Time error ( up->linecount=%d )\n", sFunctionName, up->linecount ) ; 672 } 673 #endif 674 up->lineerror = 1 ; 675 break ; 676 } 677 up->msecond = 0 ; 678 if ( up->hour == 0 && up->minute == 0 && up->second <= 2 ) { 679 /* 680 * The command "date" and "time" ( or "stim" ) were sent to the JJY receiver continuously. 681 * But the JJY receiver replies a date and time separately. 682 * Just after midnight transitions, we ignore this time. 683 */ 684 return 0 ; 685 } 686 break ; 687 688 default : /* Unexpected reply */ 689 690 up->lineerror = 1 ; 691 break ; 692 693 } 694 695 return 1 ; 696 697 } 698 699 /**************************************************************************************************/ 700 701 static int 702 jjy_receive_cdex_jst2000 ( struct recvbuf *rbufp ) 703 { 704 705 static char *sFunctionName = "jjy_receive_cdex_jst2000" ; 706 707 struct jjyunit *up ; 708 struct refclockproc *pp ; 709 struct peer *peer; 710 711 char *pBuf ; 712 int iLen ; 713 int rc ; 714 715 /* 716 * Initialize pointers and read the timecode and timestamp 717 */ 718 peer = (struct peer *) rbufp->recv_srcclock ; 719 pp = peer->procptr ; 720 up = (struct jjyunit *) pp->unitptr ; 721 722 if ( up->linediscipline == LDISC_RAW ) { 723 pBuf = up->rawbuf ; 724 iLen = up->charcount ; 725 } else { 726 pBuf = pp->a_lastcode ; 727 iLen = pp->lencode ; 728 } 729 730 switch ( up->linecount ) { 731 732 case 1 : /* JYYMMDD HHMMSSS */ 733 734 if ( iLen != 15 ) { 735 #ifdef DEBUG 736 if ( debug >= 2 ) { 737 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ; 738 } 739 #endif 740 up->lineerror = 1 ; 741 break ; 742 } 743 rc = sscanf ( pBuf, "J%2d%2d%2d%*1d%2d%2d%2d%1d", 744 &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second, &up->msecond ) ; 745 if ( rc != 7 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 746 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 747 #ifdef DEBUG 748 if ( debug >= 2 ) { 749 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d.%1d ]\n", sFunctionName, 750 rc, up->year, up->month, up->day, up->hour, up->minute, up->second, up->msecond ) ; 751 } 752 #endif 753 up->lineerror = 1 ; 754 break ; 755 } 756 up->year += 2000 ; 757 up->msecond *= 100 ; 758 break ; 759 760 default : /* Unexpected reply */ 761 762 up->lineerror = 1 ; 763 break ; 764 765 } 766 767 return 1 ; 768 769 } 770 771 /**************************************************************************************************/ 772 773 static int 774 jjy_receive_echokeisokuki_lt2000 ( struct recvbuf *rbufp ) 775 { 776 777 static char *sFunctionName = "jjy_receive_echokeisokuki_lt2000" ; 778 779 struct jjyunit *up ; 780 struct refclockproc *pp ; 781 struct peer *peer; 782 783 char *pBuf ; 784 int iLen ; 785 int rc ; 786 int i, ibcc, ibcc1, ibcc2 ; 787 788 /* 789 * Initialize pointers and read the timecode and timestamp 790 */ 791 peer = (struct peer *) rbufp->recv_srcclock ; 792 pp = peer->procptr ; 793 up = (struct jjyunit *) pp->unitptr ; 794 795 if ( up->linediscipline == LDISC_RAW ) { 796 pBuf = up->rawbuf ; 797 iLen = up->charcount ; 798 } else { 799 pBuf = pp->a_lastcode ; 800 iLen = pp->lencode ; 801 } 802 803 switch ( up->linecount ) { 804 805 case 1 : /* YYMMDDWHHMMSS<BCC1><BCC2> or YYMMDDWHHMMSS<ST1><ST2><ST3><ST4> */ 806 807 if ( ( up->operationmode == 1 && iLen != 15 ) || ( up->operationmode == 2 && iLen != 17 ) ) { 808 #ifdef DEBUG 809 if ( debug >= 2 ) { 810 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ; 811 } 812 #endif 813 if ( up->operationmode == 1 ) { 814 #ifdef DEBUG 815 if ( debug ) { 816 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ; 817 } 818 #endif 819 if ( write ( pp->io.fd, "#",1 ) != 1 ) { 820 refclock_report ( peer, CEVNT_FAULT ) ; 821 } 822 } 823 up->lineerror = 1 ; 824 break ; 825 } 826 827 if ( up->operationmode == 1 ) { 828 829 for ( i = ibcc = 0 ; i < 13 ; i ++ ) ibcc ^= pBuf[i] ; 830 ibcc1 = 0x30 | ( ( ibcc >> 4 ) & 0xF ) ; 831 ibcc2 = 0x30 | ( ( ibcc ) & 0xF ) ; 832 if ( pBuf[13] != ibcc1 || pBuf[14] != ibcc2 ) { 833 #ifdef DEBUG 834 if ( debug >= 2 ) { 835 printf ( "%s (refclock_jjy.c) : BCC error ( Recv=%02X,%02X / Calc=%02X,%02X)\n", sFunctionName, pBuf[13]&0xFF, pBuf[14]&0xFF, ibcc1, ibcc2 ) ; 836 } 837 #endif 838 up->lineerror = 1 ; 839 break ; 840 } 841 842 } 843 844 rc = sscanf ( pBuf, "%2d%2d%2d%*1d%2d%2d%2d", 845 &up->year, &up->month, &up->day, &up->hour, &up->minute, &up->second ) ; 846 if ( rc != 6 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 847 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 848 #ifdef DEBUG 849 if ( debug >= 2 ) { 850 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %02d %02d %02d * %02d %02d %02d ]\n", sFunctionName, 851 rc, up->year, up->month, up->day, up->hour, up->minute, up->second ) ; 852 } 853 #endif 854 up->lineerror = 1 ; 855 break ; 856 } 857 858 up->year += 2000 ; 859 860 if ( up->operationmode == 2 ) { 861 862 /* A time stamp comes on every 0.5 seccond in the mode 2 of the LT-2000. */ 863 up->msecond = 500 ; 864 pp->second -- ; 865 if ( pp->second < 0 ) { 866 pp->second = 59 ; 867 pp->minute -- ; 868 if ( pp->minute < 0 ) { 869 pp->minute = 59 ; 870 pp->hour -- ; 871 if ( pp->hour < 0 ) { 872 pp->hour = 23 ; 873 pp->day -- ; 874 if ( pp->day < 1 ) { 875 pp->year -- ; 876 pp->day = ymd2yd ( pp->year, 12, 31 ) ; 877 } 878 } 879 } 880 } 881 882 /* Switch from mode 2 to mode 1 in order to restraint of useless time stamp. */ 883 #ifdef DEBUG 884 if ( debug ) { 885 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ; 886 } 887 #endif 888 if ( write ( pp->io.fd, "#",1 ) != 1 ) { 889 refclock_report ( peer, CEVNT_FAULT ) ; 890 } 891 892 } 893 894 break ; 895 896 default : /* Unexpected reply */ 897 898 #ifdef DEBUG 899 if ( debug ) { 900 printf ( "%s (refclock_jjy.c) : send '#'\n", sFunctionName ) ; 901 } 902 #endif 903 if ( write ( pp->io.fd, "#",1 ) != 1 ) { 904 refclock_report ( peer, CEVNT_FAULT ) ; 905 } 906 907 up->lineerror = 1 ; 908 break ; 909 910 } 911 912 return 1 ; 913 914 } 915 916 /**************************************************************************************************/ 917 918 static int 919 jjy_receive_citizentic_jjy200 ( struct recvbuf *rbufp ) 920 { 921 922 static char *sFunctionName = "jjy_receive_citizentic_jjy200" ; 923 924 struct jjyunit *up ; 925 struct refclockproc *pp ; 926 struct peer *peer; 927 928 char *pBuf ; 929 int iLen ; 930 int rc ; 931 char cApostrophe, sStatus[3] ; 932 int iWeekday ; 933 934 /* 935 * Initialize pointers and read the timecode and timestamp 936 */ 937 peer = (struct peer *) rbufp->recv_srcclock ; 938 pp = peer->procptr ; 939 up = (struct jjyunit *) pp->unitptr ; 940 941 if ( up->linediscipline == LDISC_RAW ) { 942 pBuf = up->rawbuf ; 943 iLen = up->charcount ; 944 } else { 945 pBuf = pp->a_lastcode ; 946 iLen = pp->lencode ; 947 } 948 949 /* 950 * JJY-200 sends a timestamp every second. 951 * So, a timestamp is ignored unless it is right after polled. 952 */ 953 if ( ! up->bPollFlag ) return 0 ; 954 955 switch ( up->linecount ) { 956 957 case 1 : /* 'XX YY/MM/DD W HH:MM:SS<CR> */ 958 959 if ( iLen != 23 ) { 960 #ifdef DEBUG 961 if ( debug >= 2 ) { 962 printf ( "%s (refclock_jjy.c) : Reply length error ( iLen=%d )\n", sFunctionName, iLen ) ; 963 } 964 #endif 965 up->lineerror = 1 ; 966 break ; 967 } 968 969 rc = sscanf ( pBuf, "%c%2s %2d/%2d/%2d %1d %2d:%2d:%2d", 970 &cApostrophe, sStatus, 971 &up->year, &up->month, &up->day, &iWeekday, &up->hour, &up->minute, &up->second ) ; 972 sStatus[2] = 0 ; 973 if ( rc != 9 || cApostrophe != '\'' || strcmp( sStatus, "OK" ) != 0 974 || up->month < 1 || up->month > 12 || up->day < 1 || up->day > 31 975 || iWeekday > 6 976 || up->hour > 23 || up->minute > 59 || up->second > 60 ) { 977 #ifdef DEBUG 978 if ( debug >= 2 ) { 979 printf ( "%s (refclock_jjy.c) : Time error (rc=%d) [ %c %2s %02d %02d %02d %d %02d %02d %02d ]\n", sFunctionName, 980 rc, cApostrophe, sStatus, up->year, up->month, up->day, iWeekday, up->hour, up->minute, up->second ) ; 981 } 982 #endif 983 up->lineerror = 1 ; 984 break ; 985 } 986 987 up->year += 2000 ; 988 up->msecond = 0 ; 989 990 break ; 991 992 default : /* Unexpected reply */ 993 994 up->lineerror = 1 ; 995 break ; 996 997 } 998 999 return 1 ; 1000 1001 } 1002 1003 /**************************************************************************************************/ 1004 /* jjy_poll - called by the transmit procedure */ 1005 /**************************************************************************************************/ 1006 static void 1007 jjy_poll ( int unit, struct peer *peer ) 1008 { 1009 1010 struct jjyunit *up; 1011 struct refclockproc *pp; 1012 1013 pp = peer->procptr; 1014 up = (struct jjyunit *) pp->unitptr ; 1015 1016 if ( pp->polls > 0 && up->linecount == 0 ) { 1017 /* 1018 * No reply for last command 1019 */ 1020 refclock_report ( peer, CEVNT_TIMEOUT ) ; 1021 } 1022 1023 #ifdef DEBUG 1024 if ( debug ) { 1025 printf ( "jjy_poll (refclock_jjy.c) : %ld\n", pp->polls ) ; 1026 } 1027 #endif 1028 1029 pp->polls ++ ; 1030 1031 up->bPollFlag = 1 ; 1032 up->linecount = 0 ; 1033 up->lineerror = 0 ; 1034 up->charcount = 0 ; 1035 1036 switch ( up->unittype ) { 1037 1038 case UNITTYPE_TRISTATE_JJY01 : 1039 jjy_poll_tristate_jjy01 ( unit, peer ) ; 1040 break ; 1041 1042 case UNITTYPE_CDEX_JST2000 : 1043 jjy_poll_cdex_jst2000 ( unit, peer ) ; 1044 break ; 1045 1046 case UNITTYPE_ECHOKEISOKUKI_LT2000 : 1047 jjy_poll_echokeisokuki_lt2000 ( unit, peer ) ; 1048 break ; 1049 1050 case UNITTYPE_CITIZENTIC_JJY200 : 1051 jjy_poll_citizentic_jjy200 ( unit, peer ) ; 1052 break ; 1053 1054 default : 1055 break ; 1056 1057 } 1058 1059 } 1060 1061 /**************************************************************************************************/ 1062 1063 static void 1064 jjy_poll_tristate_jjy01 ( int unit, struct peer *peer ) 1065 { 1066 1067 struct refclockproc *pp; 1068 1069 pp = peer->procptr; 1070 1071 /* 1072 * Send "date<CR><LF>" command 1073 */ 1074 1075 #ifdef DEBUG 1076 if ( debug ) { 1077 printf ( "jjy_poll_tristate_jjy01 (refclock_jjy.c) : send 'date<CR><LF>'\n" ) ; 1078 } 1079 #endif 1080 1081 if ( write ( pp->io.fd, "date\r\n",6 ) != 6 ) { 1082 refclock_report ( peer, CEVNT_FAULT ) ; 1083 } 1084 1085 } 1086 1087 /**************************************************************************************************/ 1088 1089 static void 1090 jjy_poll_cdex_jst2000 ( int unit, struct peer *peer ) 1091 { 1092 1093 struct refclockproc *pp; 1094 1095 pp = peer->procptr; 1096 1097 /* 1098 * Send "<ENQ>1J<ETX>" command 1099 */ 1100 1101 #ifdef DEBUG 1102 if ( debug ) { 1103 printf ( "jjy_poll_cdex_jst2000 (refclock_jjy.c) : send '<ENQ>1J<ETX>'\n" ) ; 1104 } 1105 #endif 1106 1107 if ( write ( pp->io.fd, "\0051J\003", 4 ) != 4 ) { 1108 refclock_report ( peer, CEVNT_FAULT ) ; 1109 } 1110 1111 } 1112 1113 /**************************************************************************************************/ 1114 1115 static void 1116 jjy_poll_echokeisokuki_lt2000 ( int unit, struct peer *peer ) 1117 { 1118 1119 struct jjyunit *up; 1120 struct refclockproc *pp; 1121 1122 char sCmd[2] ; 1123 1124 pp = peer->procptr; 1125 up = (struct jjyunit *) pp->unitptr ; 1126 1127 /* 1128 * Send "T" or "C" command 1129 */ 1130 1131 switch ( up->operationmode ) { 1132 case 1 : sCmd[0] = 'T' ; break ; 1133 case 2 : sCmd[0] = 'C' ; break ; 1134 } 1135 sCmd[1] = 0 ; 1136 1137 #ifdef DEBUG 1138 if ( debug ) { 1139 printf ( "jjy_poll_echokeisokuki_lt2000 (refclock_jjy.c) : send '%s'\n", sCmd ) ; 1140 } 1141 #endif 1142 1143 if ( write ( pp->io.fd, sCmd, 1 ) != 1 ) { 1144 refclock_report ( peer, CEVNT_FAULT ) ; 1145 } 1146 1147 } 1148 1149 /**************************************************************************************************/ 1150 1151 static void 1152 jjy_poll_citizentic_jjy200 ( int unit, struct peer *peer ) 1153 { 1154 1155 /* Do nothing ( up->bPollFlag is set by the jjy_poll ) */ 1156 1157 } 1158 1159 #else 1160 int refclock_jjy_bs ; 1161 #endif /* REFCLOCK */ 1162