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