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