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
neoclock4x_start(int unit,struct peer * peer)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
neoclock4x_shutdown(int unit,struct peer * peer)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
neoclock4x_receive(struct recvbuf * rbufp)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
neoclock4x_poll(int unit,struct peer * peer)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
neoclock4x_control(int unit,const struct refclockstat * in,struct refclockstat * out,struct peer * peer)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
neol_hexatoi_len(const char str[],int * result,int maxlen)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
neol_atoi_len(const char str[],int * result,int maxlen)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
neol_mktime(int year,int mon,int day,int hour,int min,int sec)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
neol_localtime(unsigned long utc,int * year,int * month,int * day,int * hour,int * min,int * sec)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
neol_jdn_to_ymd(unsigned long jdn,int * yy,int * mm,int * dd)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
neol_query_firmware(int fd,int unit,char * firmware,size_t maxlen)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
neol_check_firmware(int unit,const char * firmware,char * firmwaretag)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 NONEMPTY_TRANSLATION_UNIT
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