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