1/* $NetBSD: refclock_neoclock4x.c,v 1.12 2020/05/27 23:52:19 christos Exp $ */ 2 3/* 4 * 5 * Refclock_neoclock4x.c 6 * - NeoClock4X driver for DCF77 or FIA Timecode 7 * 8 * Date: 2009-12-04 v1.16 9 * 10 * see http://www.linum.com/redir/jump/id=neoclock4x&action=redir 11 * for details about the NeoClock4X device 12 * 13 */ 14 15#ifdef HAVE_CONFIG_H 16# include "config.h" 17#endif 18 19#if defined(REFCLOCK) && (defined(CLOCK_NEOCLOCK4X)) 20 21#include <unistd.h> 22#include <sys/time.h> 23#include <sys/types.h> 24#include <termios.h> 25#include <sys/ioctl.h> 26#include <ctype.h> 27 28#include "ntpd.h" 29#include "ntp_io.h" 30#include "ntp_control.h" 31#include "ntp_refclock.h" 32#include "ntp_unixtime.h" 33#include "ntp_stdlib.h" 34 35#if defined HAVE_SYS_MODEM_H 36# include <sys/modem.h> 37# ifndef __QNXNTO__ 38# define TIOCMSET MCSETA 39# define TIOCMGET MCGETA 40# define TIOCM_RTS MRTS 41# endif 42#endif 43 44#ifdef HAVE_TERMIOS_H 45# ifdef TERMIOS_NEEDS__SVID3 46# define _SVID3 47# endif 48# include <termios.h> 49# ifdef TERMIOS_NEEDS__SVID3 50# undef _SVID3 51# endif 52#endif 53 54#ifdef HAVE_SYS_IOCTL_H 55# include <sys/ioctl.h> 56#endif 57 58/* 59 * NTP version 4.20 change the pp->msec field to pp->nsec. 60 * To allow to support older ntp versions with this sourcefile 61 * you can define NTP_PRE_420 to allow this driver to compile 62 * with ntp version back to 4.1.2. 63 * 64 */ 65#if 0 66#define NTP_PRE_420 67#endif 68 69/* 70 * If you want the driver for whatever reason to not use 71 * the TX line to send anything to your NeoClock4X 72 * device you must tell the NTP refclock driver which 73 * firmware you NeoClock4X device uses. 74 * 75 * If you want to enable this feature change the "#if 0" 76 * line to "#if 1" and make sure that the defined firmware 77 * matches the firmware off your NeoClock4X receiver! 78 * 79 */ 80 81#if 0 82#define NEOCLOCK4X_FIRMWARE NEOCLOCK4X_FIRMWARE_VERSION_A 83#endif 84 85/* at this time only firmware version A is known */ 86#define NEOCLOCK4X_FIRMWARE_VERSION_A 'A' 87 88#define NEOCLOCK4X_TIMECODELEN 37 89 90#define NEOCLOCK4X_OFFSET_SERIAL 3 91#define NEOCLOCK4X_OFFSET_RADIOSIGNAL 9 92#define NEOCLOCK4X_OFFSET_DAY 12 93#define NEOCLOCK4X_OFFSET_MONTH 14 94#define NEOCLOCK4X_OFFSET_YEAR 16 95#define NEOCLOCK4X_OFFSET_HOUR 18 96#define NEOCLOCK4X_OFFSET_MINUTE 20 97#define NEOCLOCK4X_OFFSET_SECOND 22 98#define NEOCLOCK4X_OFFSET_HSEC 24 99#define NEOCLOCK4X_OFFSET_DOW 26 100#define NEOCLOCK4X_OFFSET_TIMESOURCE 28 101#define NEOCLOCK4X_OFFSET_DSTSTATUS 29 102#define NEOCLOCK4X_OFFSET_QUARZSTATUS 30 103#define NEOCLOCK4X_OFFSET_ANTENNA1 31 104#define NEOCLOCK4X_OFFSET_ANTENNA2 33 105#define NEOCLOCK4X_OFFSET_CRC 35 106 107#define NEOCLOCK4X_DRIVER_VERSION "1.16 (2009-12-04)" 108 109#define NSEC_TO_MILLI 1000000 110 111struct neoclock4x_unit { 112 l_fp laststamp; /* last receive timestamp */ 113 short unit; /* NTP refclock unit number */ 114 u_long polled; /* flag to detect noreplies */ 115 char leap_status; /* leap second flag */ 116 int recvnow; 117 118 char firmware[80]; 119 char firmwaretag; 120 char serial[7]; 121 char radiosignal[4]; 122 char timesource; 123 char dststatus; 124 char quarzstatus; 125 int antenna1; 126 int antenna2; 127 int utc_year; 128 int utc_month; 129 int utc_day; 130 int utc_hour; 131 int utc_minute; 132 int utc_second; 133 int utc_msec; 134}; 135 136static int neoclock4x_start (int, struct peer *); 137static void neoclock4x_shutdown (int, struct peer *); 138static void neoclock4x_receive (struct recvbuf *); 139static void neoclock4x_poll (int, struct peer *); 140static void neoclock4x_control (int, const struct refclockstat *, struct refclockstat *, struct peer *); 141 142static int neol_atoi_len (const char str[], int *, int); 143static int neol_hexatoi_len (const char str[], int *, int); 144static void neol_jdn_to_ymd (unsigned long, int *, int *, int *); 145static void neol_localtime (unsigned long, int* , int*, int*, int*, int*, int*); 146static unsigned long neol_mktime (int, int, int, int, int, int); 147#if !defined(NEOCLOCK4X_FIRMWARE) 148static int neol_query_firmware (int, int, char *, size_t); 149static int neol_check_firmware (int, const char*, char *); 150#endif 151 152struct refclock refclock_neoclock4x = { 153 neoclock4x_start, /* start up driver */ 154 neoclock4x_shutdown, /* shut down driver */ 155 neoclock4x_poll, /* transmit poll message */ 156 neoclock4x_control, 157 noentry, /* initialize driver (not used) */ 158 noentry, /* not used */ 159 NOFLAGS /* not used */ 160}; 161 162static int 163neoclock4x_start(int unit, 164 struct peer *peer) 165{ 166 struct neoclock4x_unit *up; 167 struct refclockproc *pp; 168 int fd; 169 char dev[20]; 170 int sl232; 171#if defined(HAVE_TERMIOS) 172 struct termios termsettings; 173#endif 174#if !defined(NEOCLOCK4X_FIRMWARE) 175 int tries; 176#endif 177 178 (void) snprintf(dev, sizeof(dev)-1, "/dev/neoclock4x-%d", unit); 179 180 /* LDISC_STD, LDISC_RAW 181 * Open serial port. Use CLK line discipline, if available. 182 */ 183 fd = refclock_open(dev, B2400, LDISC_STD); 184 if(fd <= 0) 185 { 186 return (0); 187 } 188 189#if defined(HAVE_TERMIOS) 190 191#if 1 192 if(tcgetattr(fd, &termsettings) < 0) 193 { 194 msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit); 195 (void) close(fd); 196 return (0); 197 } 198 199 /* 2400 Baud 8N2 */ 200 termsettings.c_iflag = IGNBRK | IGNPAR | ICRNL; 201 termsettings.c_oflag = 0; 202 termsettings.c_cflag = CS8 | CSTOPB | CLOCAL | CREAD; 203 (void)cfsetispeed(&termsettings, (u_int)B2400); 204 (void)cfsetospeed(&termsettings, (u_int)B2400); 205 206 if(tcsetattr(fd, TCSANOW, &termsettings) < 0) 207 { 208 msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit); 209 (void) close(fd); 210 return (0); 211 } 212 213#else 214 if(tcgetattr(fd, &termsettings) < 0) 215 { 216 msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit); 217 (void) close(fd); 218 return (0); 219 } 220 221 /* 2400 Baud 8N2 */ 222 termsettings.c_cflag &= ~PARENB; 223 termsettings.c_cflag |= CSTOPB; 224 termsettings.c_cflag &= ~CSIZE; 225 termsettings.c_cflag |= CS8; 226 227 if(tcsetattr(fd, TCSANOW, &termsettings) < 0) 228 { 229 msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit); 230 (void) close(fd); 231 return (0); 232 } 233#endif 234 235#elif defined(HAVE_SYSV_TTYS) 236 if(ioctl(fd, TCGETA, &termsettings) < 0) 237 { 238 msyslog(LOG_CRIT, "NeoClock4X(%d): (TCGETA) can't query serial port settings: %m", unit); 239 (void) close(fd); 240 return (0); 241 } 242 243 /* 2400 Baud 8N2 */ 244 termsettings.c_cflag &= ~PARENB; 245 termsettings.c_cflag |= CSTOPB; 246 termsettings.c_cflag &= ~CSIZE; 247 termsettings.c_cflag |= CS8; 248 249 if(ioctl(fd, TCSETA, &termsettings) < 0) 250 { 251 msyslog(LOG_CRIT, "NeoClock4X(%d): (TSGETA) can't set serial port 2400 8N2: %m", unit); 252 (void) close(fd); 253 return (0); 254 } 255#else 256 msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set port to 2400 8N2 with this OS!", unit); 257 (void) close(fd); 258 return (0); 259#endif 260 261#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 262 /* turn on RTS, and DTR for power supply */ 263 /* NeoClock4x is powered from serial line */ 264 if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1) 265 { 266 msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit); 267 (void) close(fd); 268 return (0); 269 } 270#ifdef TIOCM_RTS 271 sl232 = sl232 | TIOCM_DTR | TIOCM_RTS; /* turn on RTS, and DTR for power supply */ 272#else 273 sl232 = sl232 | CIOCM_DTR | CIOCM_RTS; /* turn on RTS, and DTR for power supply */ 274#endif 275 if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1) 276 { 277 msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit); 278 (void) close(fd); 279 return (0); 280 } 281#else 282 msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set DTR/RTS to power NeoClock4X with this OS!", 283 unit); 284 (void) close(fd); 285 return (0); 286#endif 287 288 up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit)); 289 if(!(up)) 290 { 291 msyslog(LOG_ERR, "NeoClock4X(%d): can't allocate memory for: %m",unit); 292 (void) close(fd); 293 return (0); 294 } 295 296 memset((char *)up, 0, sizeof(struct neoclock4x_unit)); 297 pp = peer->procptr; 298 pp->clockdesc = "NeoClock4X"; 299 pp->unitptr = up; 300 pp->io.clock_recv = neoclock4x_receive; 301 pp->io.srcclock = peer; 302 pp->io.datalen = 0; 303 pp->io.fd = fd; 304 /* 305 * no fudge time is given by user! 306 * use 169.583333 ms to compensate the serial line delay 307 * formula is: 308 * 2400 Baud / 11 bit = 218.18 charaters per second 309 * (NeoClock4X timecode len) 310 */ 311 pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0; 312 313 /* 314 * Initialize miscellaneous variables 315 */ 316 peer->precision = -10; 317 memcpy((char *)&pp->refid, "neol", 4); 318 319 up->leap_status = 0; 320 up->unit = unit; 321 strlcpy(up->firmware, "?", sizeof(up->firmware)); 322 up->firmwaretag = '?'; 323 strlcpy(up->serial, "?", sizeof(up->serial)); 324 strlcpy(up->radiosignal, "?", sizeof(up->radiosignal)); 325 up->timesource = '?'; 326 up->dststatus = '?'; 327 up->quarzstatus = '?'; 328 up->antenna1 = -1; 329 up->antenna2 = -1; 330 up->utc_year = 0; 331 up->utc_month = 0; 332 up->utc_day = 0; 333 up->utc_hour = 0; 334 up->utc_minute = 0; 335 up->utc_second = 0; 336 up->utc_msec = 0; 337 338#if defined(NEOCLOCK4X_FIRMWARE) 339#if NEOCLOCK4X_FIRMWARE == NEOCLOCK4X_FIRMWARE_VERSION_A 340 strlcpy(up->firmware, "(c) 2002 NEOL S.A. FRANCE / L0.01 NDF:A:* (compile time)", 341 sizeof(up->firmware)); 342 up->firmwaretag = 'A'; 343#else 344 msyslog(LOG_EMERG, "NeoClock4X(%d): unknown firmware defined at compile time for NeoClock4X", 345 unit); 346 (void) close(fd); 347 pp->io.fd = -1; 348 free(pp->unitptr); 349 pp->unitptr = NULL; 350 return (0); 351#endif 352#else 353 for(tries=0; tries < 5; tries++) 354 { 355 NLOG(NLOG_CLOCKINFO) 356 msyslog(LOG_INFO, "NeoClock4X(%d): checking NeoClock4X firmware version (%d/5)", unit, tries); 357 /* wait 3 seconds for receiver to power up */ 358 sleep(3); 359 if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware))) 360 { 361 break; 362 } 363 } 364 365 /* can I handle this firmware version? */ 366 if(!neol_check_firmware(up->unit, up->firmware, &up->firmwaretag)) 367 { 368 (void) close(fd); 369 pp->io.fd = -1; 370 free(pp->unitptr); 371 pp->unitptr = NULL; 372 return (0); 373 } 374#endif 375 376 if(!io_addclock(&pp->io)) 377 { 378 msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m", unit); 379 (void) close(fd); 380 pp->io.fd = -1; 381 free(pp->unitptr); 382 pp->unitptr = NULL; 383 return (0); 384 } 385 386 NLOG(NLOG_CLOCKINFO) 387 msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit); 388 389 return (1); 390} 391 392static void 393neoclock4x_shutdown(int unit, 394 struct peer *peer) 395{ 396 struct neoclock4x_unit *up; 397 struct refclockproc *pp; 398 int sl232; 399 400 if(NULL != peer) 401 { 402 pp = peer->procptr; 403 if(pp != NULL) 404 { 405 up = pp->unitptr; 406 if(up != NULL) 407 { 408 if(-1 != pp->io.fd) 409 { 410#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 411 /* turn on RTS, and DTR for power supply */ 412 /* NeoClock4x is powered from serial line */ 413 if(ioctl(pp->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 414 { 415 msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", 416 unit); 417 } 418#ifdef TIOCM_RTS 419 /* turn on RTS, and DTR for power supply */ 420 sl232 &= ~(TIOCM_DTR | TIOCM_RTS); 421#else 422 /* turn on RTS, and DTR for power supply */ 423 sl232 &= ~(CIOCM_DTR | CIOCM_RTS); 424#endif 425 if(ioctl(pp->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 426 { 427 msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", 428 unit); 429 } 430#endif 431 io_closeclock(&pp->io); 432 } 433 free(up); 434 pp->unitptr = NULL; 435 } 436 } 437 } 438 439 msyslog(LOG_ERR, "NeoClock4X(%d): shutdown", unit); 440 441 NLOG(NLOG_CLOCKINFO) 442 msyslog(LOG_INFO, "NeoClock4X(%d): receiver shutdown done", unit); 443} 444 445static void 446neoclock4x_receive(struct recvbuf *rbufp) 447{ 448 struct neoclock4x_unit *up; 449 struct refclockproc *pp; 450 struct peer *peer; 451 unsigned long calc_utc; 452 int day; 453 int month; /* ddd conversion */ 454 int c; 455 int dsec; 456 unsigned char calc_chksum; 457 int recv_chksum; 458 459 peer = rbufp->recv_peer; 460 pp = peer->procptr; 461 up = pp->unitptr; 462 463 /* wait till poll interval is reached */ 464 if(0 == up->recvnow) 465 return; 466 467 /* reset poll interval flag */ 468 up->recvnow = 0; 469 470 /* read last received timecode */ 471 pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); 472 pp->leap = LEAP_NOWARNING; 473 474 if(NEOCLOCK4X_TIMECODELEN != pp->lencode) 475 { 476 NLOG(NLOG_CLOCKEVENT) 477 msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s", 478 up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode); 479 refclock_report(peer, CEVNT_BADREPLY); 480 return; 481 } 482 483 neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2); 484 485 /* calculate checksum */ 486 calc_chksum = 0; 487 for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++) 488 { 489 calc_chksum += pp->a_lastcode[c]; 490 } 491 if(recv_chksum != calc_chksum) 492 { 493 NLOG(NLOG_CLOCKEVENT) 494 msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s", 495 up->unit, pp->a_lastcode); 496 refclock_report(peer, CEVNT_BADREPLY); 497 return; 498 } 499 500 /* Allow synchronization even is quartz clock is 501 * never initialized. 502 * WARNING: This is dangerous! 503 */ 504 up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS]; 505 if(0==(pp->sloppyclockflag & CLK_FLAG2)) 506 { 507 if('I' != up->quarzstatus) 508 { 509 NLOG(NLOG_CLOCKEVENT) 510 msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s", 511 up->unit, pp->a_lastcode); 512 pp->leap = LEAP_NOTINSYNC; 513 refclock_report(peer, CEVNT_BADDATE); 514 return; 515 } 516 } 517 if('I' != up->quarzstatus) 518 { 519 NLOG(NLOG_CLOCKEVENT) 520 msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s", 521 up->unit, pp->a_lastcode); 522 } 523 524 /* 525 * If NeoClock4X is not synchronized to a radio clock 526 * check if we're allowed to synchronize with the quartz 527 * clock. 528 */ 529 up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE]; 530 if(0==(pp->sloppyclockflag & CLK_FLAG2)) 531 { 532 if('A' != up->timesource) 533 { 534 /* not allowed to sync with quartz clock */ 535 if(0==(pp->sloppyclockflag & CLK_FLAG1)) 536 { 537 refclock_report(peer, CEVNT_BADTIME); 538 pp->leap = LEAP_NOTINSYNC; 539 return; 540 } 541 } 542 } 543 544 /* this should only used when first install is done */ 545 if(pp->sloppyclockflag & CLK_FLAG4) 546 { 547 msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s", 548 up->unit, pp->a_lastcode); 549 } 550 551 /* 123456789012345678901234567890123456789012345 */ 552 /* S/N123456DCF1004021010001202ASX1213CR\r\n */ 553 554 neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2); 555 neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2); 556 neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2); 557 neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2); 558 neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2); 559 neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2); 560 neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2); 561#if defined(NTP_PRE_420) 562 pp->msec = dsec * 10; /* convert 1/100s from neoclock to real miliseconds */ 563#else 564 pp->nsec = dsec * 10 * NSEC_TO_MILLI; /* convert 1/100s from neoclock to nanoseconds */ 565#endif 566 567 memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3); 568 up->radiosignal[3] = 0; 569 memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6); 570 up->serial[6] = 0; 571 up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS]; 572 neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2); 573 neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2); 574 575 /* 576 Validate received values at least enough to prevent internal 577 array-bounds problems, etc. 578 */ 579 if((pp->hour < 0) || (pp->hour > 23) || 580 (pp->minute < 0) || (pp->minute > 59) || 581 (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || 582 (day < 1) || (day > 31) || 583 (month < 1) || (month > 12) || 584 (pp->year < 0) || (pp->year > 99)) { 585 /* Data out of range. */ 586 NLOG(NLOG_CLOCKEVENT) 587 msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s", 588 up->unit, pp->a_lastcode); 589 refclock_report(peer, CEVNT_BADDATE); 590 return; 591 } 592 593 /* Year-2000 check not needed anymore. Same problem 594 * will arise at 2099 but what should we do...? 595 * 596 * wrap 2-digit date into 4-digit 597 * 598 * if(pp->year < YEAR_PIVOT) 599 * { 600 * pp->year += 100; 601 * } 602 */ 603 pp->year += 2000; 604 605 /* adjust NeoClock4X local time to UTC */ 606 calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second); 607 calc_utc -= 3600; 608 /* adjust NeoClock4X daylight saving time if needed */ 609 if('S' == up->dststatus) 610 calc_utc -= 3600; 611 neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second); 612 613 /* 614 some preparations 615 */ 616 pp->day = ymd2yd(pp->year, month, day); 617 pp->leap = 0; 618 619 if(pp->sloppyclockflag & CLK_FLAG4) 620 { 621 msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03ld", 622 up->unit, 623 pp->year, month, day, 624 pp->hour, pp->minute, pp->second, 625#if defined(NTP_PRE_420) 626 pp->msec 627#else 628 pp->nsec/NSEC_TO_MILLI 629#endif 630 ); 631 } 632 633 up->utc_year = pp->year; 634 up->utc_month = month; 635 up->utc_day = day; 636 up->utc_hour = pp->hour; 637 up->utc_minute = pp->minute; 638 up->utc_second = pp->second; 639#if defined(NTP_PRE_420) 640 up->utc_msec = pp->msec; 641#else 642 up->utc_msec = pp->nsec/NSEC_TO_MILLI; 643#endif 644 645 if(!refclock_process(pp)) 646 { 647 NLOG(NLOG_CLOCKEVENT) 648 msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit); 649 refclock_report(peer, CEVNT_FAULT); 650 return; 651 } 652 refclock_receive(peer); 653 654 /* report good status */ 655 refclock_report(peer, CEVNT_NOMINAL); 656 657 record_clock_stats(&peer->srcadr, pp->a_lastcode); 658} 659 660static void 661neoclock4x_poll(int unit, 662 struct peer *peer) 663{ 664 struct neoclock4x_unit *up; 665 struct refclockproc *pp; 666 667 pp = peer->procptr; 668 up = pp->unitptr; 669 670 pp->polls++; 671 up->recvnow = 1; 672} 673 674static void 675neoclock4x_control(int unit, 676 const struct refclockstat *in, 677 struct refclockstat *out, 678 struct peer *peer) 679{ 680 struct neoclock4x_unit *up; 681 struct refclockproc *pp; 682 683 if(NULL == peer) 684 { 685 msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); 686 return; 687 } 688 689 pp = peer->procptr; 690 if(NULL == pp) 691 { 692 msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); 693 return; 694 } 695 696 up = pp->unitptr; 697 if(NULL == up) 698 { 699 msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); 700 return; 701 } 702 703 if(NULL != in) 704 { 705 /* check to see if a user supplied time offset is given */ 706 if(in->haveflags & CLK_HAVETIME1) 707 { 708 pp->fudgetime1 = in->fudgetime1; 709 NLOG(NLOG_CLOCKINFO) 710 msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.", 711 unit, pp->fudgetime1); 712 } 713 714 /* notify */ 715 if(pp->sloppyclockflag & CLK_FLAG1) 716 { 717 NLOG(NLOG_CLOCKINFO) 718 msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is used to synchronize time if radio clock has no reception.", unit); 719 } 720 else 721 { 722 NLOG(NLOG_CLOCKINFO) 723 msyslog(LOG_NOTICE, "NeoClock4X(%d): time is only adjusted with radio signal reception.", unit); 724 } 725 } 726 727 if(NULL != out) 728 { 729 char *tt; 730 /* the 199 here is almost 2x the max string */ 731 char tmpbuf[199]; 732 733 out->kv_list = (struct ctl_var *)0; 734 out->type = REFCLK_NEOCLOCK4X; 735 736 snprintf(tmpbuf, sizeof(tmpbuf)-1, 737 "%04d-%02d-%02d %02d:%02d:%02d.%03d", 738 up->utc_year, up->utc_month, up->utc_day, 739 up->utc_hour, up->utc_minute, up->utc_second, 740 up->utc_msec); 741 tt = add_var(&out->kv_list, sizeof(tmpbuf)-1, RO|DEF); 742 snprintf(tt, sizeof(tmpbuf)-1, "calc_utc=\"%s\"", tmpbuf); 743 744 tt = add_var(&out->kv_list, 40, RO|DEF); 745 snprintf(tt, 39, "radiosignal=\"%s\"", up->radiosignal); 746 tt = add_var(&out->kv_list, 40, RO|DEF); 747 snprintf(tt, 39, "antenna1=\"%d\"", up->antenna1); 748 tt = add_var(&out->kv_list, 40, RO|DEF); 749 snprintf(tt, 39, "antenna2=\"%d\"", up->antenna2); 750 tt = add_var(&out->kv_list, 40, RO|DEF); 751 if('A' == up->timesource) 752 snprintf(tt, 39, "timesource=\"radio\""); 753 else if('C' == up->timesource) 754 snprintf(tt, 39, "timesource=\"quartz\""); 755 else 756 snprintf(tt, 39, "timesource=\"unknown\""); 757 tt = add_var(&out->kv_list, 40, RO|DEF); 758 if('I' == up->quarzstatus) 759 snprintf(tt, 39, "quartzstatus=\"synchronized\""); 760 else if('X' == up->quarzstatus) 761 snprintf(tt, 39, "quartzstatus=\"not synchronized\""); 762 else 763 snprintf(tt, 39, "quartzstatus=\"unknown\""); 764 tt = add_var(&out->kv_list, 40, RO|DEF); 765 if('S' == up->dststatus) 766 snprintf(tt, 39, "dststatus=\"summer\""); 767 else if('W' == up->dststatus) 768 snprintf(tt, 39, "dststatus=\"winter\""); 769 else 770 snprintf(tt, 39, "dststatus=\"unknown\""); 771 /* the 99 below is greater than 80 the max string */ 772 tt = add_var(&out->kv_list, 80, RO|DEF); 773 snprintf(tt, 99, "firmware=\"%s\"", up->firmware); 774 tt = add_var(&out->kv_list, 40, RO|DEF); 775 snprintf(tt, 39, "firmwaretag=\"%c\"", up->firmwaretag); 776 tt = add_var(&out->kv_list, 80, RO|DEF); 777 snprintf(tt, 99, "driver version=\"%s\"", NEOCLOCK4X_DRIVER_VERSION); 778 tt = add_var(&out->kv_list, 80, RO|DEF); 779 snprintf(tt, 99, "serialnumber=\"%s\"", up->serial); 780 } 781} 782 783static int 784neol_hexatoi_len(const char str[], 785 int *result, 786 int maxlen) 787{ 788 int hexdigit; 789 int i; 790 int n = 0; 791 792 for(i=0; isxdigit((unsigned char)str[i]) && i < maxlen; i++) 793 { 794 hexdigit = isdigit((unsigned char)str[i]) ? toupper((unsigned char)str[i]) - '0' : toupper((unsigned char)str[i]) - 'A' + 10; 795 n = 16 * n + hexdigit; 796 } 797 *result = n; 798 return (n); 799} 800 801static int 802neol_atoi_len(const char str[], 803 int *result, 804 int maxlen) 805{ 806 int digit; 807 int i; 808 int n = 0; 809 810 for(i=0; isdigit((unsigned char)str[i]) && i < maxlen; i++) 811 { 812 digit = str[i] - '0'; 813 n = 10 * n + digit; 814 } 815 *result = n; 816 return (n); 817} 818 819/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. 820 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 821 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. 822 * 823 * [For the Julian calendar (which was used in Russia before 1917, 824 * Britain & colonies before 1752, anywhere else before 1582, 825 * and is still in use by some communities) leave out the 826 * -year/100+year/400 terms, and add 10.] 827 * 828 * This algorithm was first published by Gauss (I think). 829 * 830 * WARNING: this function will overflow on 2106-02-07 06:28:16 on 831 * machines were long is 32-bit! (However, as time_t is signed, we 832 * will already get problems at other places on 2038-01-19 03:14:08) 833 */ 834static unsigned long 835neol_mktime(int year, 836 int mon, 837 int day, 838 int hour, 839 int min, 840 int sec) 841{ 842 if (0 >= (int) (mon -= 2)) { /* 1..12 . 11,12,1..10 */ 843 mon += 12; /* Puts Feb last since it has leap day */ 844 year -= 1; 845 } 846 return ((( 847 (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + 848 year*365 - 719499 849 )*24 + hour /* now have hours */ 850 )*60 + min /* now have minutes */ 851 )*60 + sec; /* finally seconds */ 852} 853 854static void 855neol_localtime(unsigned long utc, 856 int* year, 857 int* month, 858 int* day, 859 int* hour, 860 int* min, 861 int* sec) 862{ 863 *sec = utc % 60; 864 utc /= 60; 865 *min = utc % 60; 866 utc /= 60; 867 *hour = utc % 24; 868 utc /= 24; 869 870 /* JDN Date 1/1/1970 */ 871 neol_jdn_to_ymd(utc + 2440588L, year, month, day); 872} 873 874static void 875neol_jdn_to_ymd(unsigned long jdn, 876 int *yy, 877 int *mm, 878 int *dd) 879{ 880 unsigned long x, z, m, d, y; 881 unsigned long daysPer400Years = 146097UL; 882 unsigned long fudgedDaysPer4000Years = 1460970UL + 31UL; 883 884 x = jdn + 68569UL; 885 z = 4UL * x / daysPer400Years; 886 x = x - (daysPer400Years * z + 3UL) / 4UL; 887 y = 4000UL * (x + 1) / fudgedDaysPer4000Years; 888 x = x - 1461UL * y / 4UL + 31UL; 889 m = 80UL * x / 2447UL; 890 d = x - 2447UL * m / 80UL; 891 x = m / 11UL; 892 m = m + 2UL - 12UL * x; 893 y = 100UL * (z - 49UL) + y + x; 894 895 *yy = (int)y; 896 *mm = (int)m; 897 *dd = (int)d; 898} 899 900#if !defined(NEOCLOCK4X_FIRMWARE) 901static int 902neol_query_firmware(int fd, 903 int unit, 904 char *firmware, 905 size_t maxlen) 906{ 907 char tmpbuf[256]; 908 size_t len; 909 int lastsearch; 910 unsigned char c; 911 int last_c_was_crlf; 912 int last_crlf_conv_len; 913 int init; 914 int read_errors; 915 int flag = 0; 916 int chars_read; 917 918 /* wait a little bit */ 919 sleep(1); 920 if(-1 != write(fd, "V", 1)) 921 { 922 /* wait a little bit */ 923 sleep(1); 924 memset(tmpbuf, 0x00, sizeof(tmpbuf)); 925 926 len = 0; 927 lastsearch = 0; 928 last_c_was_crlf = 0; 929 last_crlf_conv_len = 0; 930 init = 1; 931 read_errors = 0; 932 chars_read = 0; 933 for(;;) 934 { 935 if(read_errors > 5) 936 { 937 msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit); 938 strlcpy(tmpbuf, "unknown due to timeout", sizeof(tmpbuf)); 939 break; 940 } 941 if(chars_read > 500) 942 { 943 msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (garbage)", unit); 944 strlcpy(tmpbuf, "unknown due to garbage input", sizeof(tmpbuf)); 945 break; 946 } 947 if(-1 == read(fd, &c, 1)) 948 { 949 if(EAGAIN != errno) 950 { 951 msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %m", unit); 952 read_errors++; 953 } 954 else 955 { 956 sleep(1); 957 } 958 continue; 959 } 960 else 961 { 962 chars_read++; 963 } 964 965 if(init) 966 { 967 if(0xA9 != c) /* wait for (c) char in input stream */ 968 continue; 969 970 strlcpy(tmpbuf, "(c)", sizeof(tmpbuf)); 971 len = 3; 972 init = 0; 973 continue; 974 } 975 976#if 0 977 msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c); 978#endif 979 980 if(0x0A == c || 0x0D == c) 981 { 982 if(last_c_was_crlf) 983 { 984 char *ptr; 985 ptr = strstr(&tmpbuf[lastsearch], "S/N"); 986 if(NULL != ptr) 987 { 988 tmpbuf[last_crlf_conv_len] = 0; 989 flag = 1; 990 break; 991 } 992 /* convert \n to / */ 993 last_crlf_conv_len = len; 994 tmpbuf[len++] = ' '; 995 tmpbuf[len++] = '/'; 996 tmpbuf[len++] = ' '; 997 lastsearch = len; 998 } 999 last_c_was_crlf = 1; 1000 } 1001 else 1002 { 1003 last_c_was_crlf = 0; 1004 if(0x00 != c) 1005 tmpbuf[len++] = (char) c; 1006 } 1007 tmpbuf[len] = '\0'; 1008 if (len > sizeof(tmpbuf)-5) 1009 break; 1010 } 1011 } 1012 else 1013 { 1014 msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit); 1015 strlcpy(tmpbuf, "unknown error", sizeof(tmpbuf)); 1016 } 1017 if (strlcpy(firmware, tmpbuf, maxlen) >= maxlen) 1018 strlcpy(firmware, "buffer too small", maxlen); 1019 1020 if(flag) 1021 { 1022 NLOG(NLOG_CLOCKINFO) 1023 msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware); 1024 1025 if(strstr(firmware, "/R2")) 1026 { 1027 msyslog(LOG_INFO, "NeoClock4X(%d): Your NeoClock4X uses the new R2 firmware release. Please note the changed LED behaviour.", unit); 1028 } 1029 1030 } 1031 1032 return (flag); 1033} 1034 1035static int 1036neol_check_firmware(int unit, 1037 const char *firmware, 1038 char *firmwaretag) 1039{ 1040 char *ptr; 1041 1042 *firmwaretag = '?'; 1043 ptr = strstr(firmware, "NDF:"); 1044 if(NULL != ptr) 1045 { 1046 if((strlen(firmware) - strlen(ptr)) >= 7) 1047 { 1048 if(':' == *(ptr+5) && '*' == *(ptr+6)) 1049 *firmwaretag = *(ptr+4); 1050 } 1051 } 1052 1053 if('A' != *firmwaretag) 1054 { 1055 msyslog(LOG_CRIT, "NeoClock4X(%d): firmware version \"%c\" not supported with this driver version!", unit, *firmwaretag); 1056 return (0); 1057 } 1058 1059 return (1); 1060} 1061#endif 1062 1063#else 1064int refclock_neoclock4x_bs; 1065#endif /* REFCLOCK */ 1066 1067/* 1068 * History: 1069 * refclock_neoclock4x.c 1070 * 1071 * 2002/04/27 cjh 1072 * Revision 1.0 first release 1073 * 1074 * 2002/07/15 cjh 1075 * preparing for bitkeeper reposity 1076 * 1077 * 2002/09/09 cjh 1078 * Revision 1.1 1079 * - don't assume sprintf returns an int anymore 1080 * - change the way the firmware version is read 1081 * - some customers would like to put a device called 1082 * data diode to the NeoClock4X device to disable 1083 * the write line. We need to now the firmware 1084 * version even in this case. We made a compile time 1085 * definition in this case. The code was previously 1086 * only available on request. 1087 * 1088 * 2003/01/08 cjh 1089 * Revision 1.11 1090 * - changing xprinf to xnprinf to avoid buffer overflows 1091 * - change some logic 1092 * - fixed memory leaks if drivers can't initialize 1093 * 1094 * 2003/01/10 cjh 1095 * Revision 1.12 1096 * - replaced ldiv 1097 * - add code to support FreeBSD 1098 * 1099 * 2003/07/07 cjh 1100 * Revision 1.13 1101 * - fix reporting of clock status 1102 * changes. previously a bad clock 1103 * status was never reset. 1104 * 1105 * 2004/04/07 cjh 1106 * Revision 1.14 1107 * - open serial port in a way 1108 * AIX and some other OS can 1109 * handle much better 1110 * 1111 * 2006/01/11 cjh 1112 * Revision 1.15 1113 * - remove some unsued #ifdefs 1114 * - fix nsec calculation, closes #499 1115 * 1116 * 2009/12/04 cjh 1117 * Revision 1.16 1118 * - change license to ntp COPYRIGHT notice. This should allow Debian 1119 * to add this refclock driver in further releases. 1120 * - detect R2 hardware 1121 * 1122 */ 1123 1124 1125 1126 1127 1128 1129