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