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