]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/ntpd/refclock_neoclock4x.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / ntpd / refclock_neoclock4x.c
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(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