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