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