aboutsummaryrefslogtreecommitdiff
path: root/contrib/ntp/ntpd/refclock_fg.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd/refclock_fg.c')
-rw-r--r--contrib/ntp/ntpd/refclock_fg.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/refclock_fg.c b/contrib/ntp/ntpd/refclock_fg.c
new file mode 100644
index 000000000000..f1320b010d9e
--- /dev/null
+++ b/contrib/ntp/ntpd/refclock_fg.c
@@ -0,0 +1,350 @@
+/*
+ * refclock_fg - clock driver for the Forum Graphic GPS datating station
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined(REFCLOCK) && defined(CLOCK_FG)
+
+#include <time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_calendar.h"
+#include "ntp_stdlib.h"
+
+/*
+ * This driver supports the Forum Graphic GPS dating station.
+ * More information about FG GPS is available on http://www.forumgraphic.com
+ * Contact das@amt.ru for any question about this driver.
+ */
+
+/*
+ * Interface definitions
+ */
+#define DEVICE "/dev/fgclock%d"
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
+#define REFID "GPS"
+#define DESCRIPTION "Forum Graphic GPS dating station"
+#define LENFG 26 /* timecode length */
+#define SPEED232 B9600 /* uart speed (9600 baud) */
+
+/*
+ * Function prototypes
+ */
+static int fg_init P((int));
+static int fg_start P((int, struct peer *));
+static void fg_shutdown P((int, struct peer *));
+static void fg_poll P((int, struct peer *));
+static void fg_receive P((struct recvbuf *));
+
+/*
+ * Forum Graphic unit control structure
+ */
+
+struct fgunit {
+ int pollnum; /* Use peer.poll instead? */
+ int status; /* Hug to check status information on GPS */
+ int y2kwarn; /* Y2K bug */
+};
+
+/*
+ * Queries definition
+ */
+static char fginit[] = { 0x10, 0x48, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static char fgdate[] = { 0x10, 0x44, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_fg = {
+ fg_start, /* start up driver */
+ fg_shutdown, /* shut down driver */
+ fg_poll, /* transmit poll message */
+ noentry, /* not used */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used */
+ NOFLAGS /* not used */
+};
+
+/*
+ * fg_init - Initialization of FG GPS.
+ */
+
+static int
+fg_init(
+ int fd
+ )
+{
+ if (write(fd, fginit, LENFG) != LENFG)
+ return 0;
+
+ return (1);
+
+}
+
+/*
+ * fg_start - open the device and initialize data for processing
+ */
+static int
+fg_start(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct refclockproc *pp;
+ struct fgunit *up;
+ int fd;
+ char device[20];
+
+
+ /*
+ * Open device file for reading.
+ */
+ (void)sprintf(device, DEVICE, unit);
+
+#ifdef DEBUG
+ if (debug)
+ printf ("starting FG with device %s\n",device);
+#endif
+ if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ return (0);
+
+ /*
+ * Allocate and initialize unit structure
+ */
+
+ if (!(up = (struct fgunit *)
+ emalloc(sizeof(struct fgunit)))) {
+ (void) close(fd);
+ return (0);
+ }
+ memset((char *)up, 0, sizeof(struct fgunit));
+ pp = peer->procptr;
+ pp->unitptr = (caddr_t)up;
+ pp->io.clock_recv = fg_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ return (0);
+ }
+
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 3);
+ up->pollnum = 0;
+
+ /*
+ * Setup dating station to use GPS receiver.
+ * GPS receiver should work before this operation.
+ */
+ if(!fg_init(pp->io.fd))
+ refclock_report(peer, CEVNT_FAULT);
+
+ return (1);
+}
+
+
+/*
+ * fg_shutdown - shut down the clock
+ */
+static void
+fg_shutdown(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct refclockproc *pp;
+ struct fgunit *up;
+
+ pp = peer->procptr;
+ up = (struct fgunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
+}
+
+
+/*
+ * fg_poll - called by the transmit procedure
+ */
+static void
+fg_poll(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+
+ /*
+ * Time to poll the clock. The FG clock responds to a
+ * "<DLE>D<DLE><CR>" by returning a timecode in the format specified
+ * above. If nothing is heard from the clock for two polls,
+ * declare a timeout and keep going.
+ */
+
+ if (write(pp->io.fd, fgdate, LENFG) != LENFG)
+ refclock_report(peer, CEVNT_FAULT);
+ else
+ pp->polls++;
+
+ if (peer->burst > 0)
+ return;
+ /*
+ if (pp->coderecv == pp->codeproc) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ return;
+ }
+ */
+ peer->burst = NSTAGE;
+
+ record_clock_stats(&peer->srcadr, pp->a_lastcode);
+
+
+ return;
+
+}
+
+/*
+ * fg_receive - receive data from the serial interface
+ */
+static void
+fg_receive(
+ struct recvbuf *rbufp
+ )
+{
+ struct refclockproc *pp;
+ struct fgunit *up;
+ struct peer *peer;
+ char *bpt;
+
+ /*
+ * Initialize pointers and read the timecode and timestamp
+ * We can't use gtlin function because we need bynary data in buf */
+
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct fgunit *)pp->unitptr;
+
+ /*
+ * Below hug to implement receiving of status information
+ */
+ if(!up->pollnum)
+ {
+ up->pollnum++;
+ return;
+ }
+
+
+ if (rbufp->recv_length < (LENFG-2))
+ {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return; /* The reply is invalid discard it. */
+ }
+
+ /* Below I trying to find a correct reply in buffer.
+ * Sometime GPS reply located in the beginnig of buffer,
+ * sometime you can find it with some offset.
+ */
+
+ bpt = (char *)rbufp->recv_space.X_recv_buffer;
+ while(*bpt != '')
+ bpt++;
+
+#define BP2(x) ( bpt[x] & 15 )
+#define BP1(x) (( bpt[x] & 240 ) >> 4)
+
+ pp->year = BP1(2)*10 + BP2(2);
+
+ if(pp->year == 94)
+ {
+ refclock_report(peer, CEVNT_BADREPLY);
+ if(!fg_init(pp->io.fd))
+ refclock_report(peer, CEVNT_FAULT);
+ return;
+ /* GPS is just powered up. The date is invalid -
+ discarding it. Initilize GPS one more time */
+ /* Sorry - this driver will broken in 2094 ;) */
+ }
+
+ if (pp->year < 99)
+ pp->year += 100;
+
+ pp->year += 1900;
+ pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4);
+
+/*
+ After Jan, 10 2000 Forum Graphic GPS receiver had a very strange
+ benahour. It doubles day number for an hours in replys after 10:10:10 UTC
+ and doubles min every hour at HH:10:ss for a minute.
+ Hope it is a problem of my unit only and not a Y2K problem of FG GPS.
+ Below small code to avoid such situation.
+*/
+ if(up->y2kwarn > 10)
+ pp->hour = BP1(6)*10 + BP2(6);
+ else
+ pp->hour = BP1(5)*10 + BP2(5);
+
+ if((up->y2kwarn > 10) && (pp->hour == 10))
+ {
+ pp->minute = BP1(7)*10 + BP2(7);
+ pp->second = BP1(8)*10 + BP2(8);
+ pp->msec = BP1(9)*10 + BP2(9);
+ pp->usec = BP1(10);
+ } else {
+ pp->hour = BP1(5)*10 + BP2(5);
+ pp->minute = BP1(6)*10 + BP2(6);
+ pp->second = BP1(7)*10 + BP2(7);
+ pp->msec = BP1(8)*10 + BP2(8);
+ pp->usec = BP1(9);
+ }
+
+ if((pp->hour == 10) && (pp->minute == 10))
+ {
+ up->y2kwarn++;
+ }
+
+ sprintf(pp->a_lastcode, "%d %d %d %d %d", pp->year, pp->day, pp->hour, pp->minute, pp->second);
+ pp->lencode = strlen(pp->a_lastcode);
+ /*get_systime(&pp->lastrec);*/
+
+#ifdef DEBUG
+ if (debug)
+ printf ("fg: time is %04d/%03d %02d:%02d:%02d UTC\n",
+ pp->year, pp->day, pp->hour, pp->minute, pp->second);
+#endif
+
+ if (peer->stratum <= 1)
+ peer->refid = pp->refid;
+ pp->disp = (10e-6);
+ pp->lastrec = rbufp->recv_time; /* Is it better then get_systime()? */
+ /* pp->leap = LEAP_NOWARNING; */
+
+ /*
+ * Process the new sample in the median filter and determine the
+ * timecode timestamp.
+ */
+
+ if (!refclock_process(pp))
+ refclock_report(peer, CEVNT_BADTIME);
+
+ refclock_receive(peer);
+ return;
+}
+
+
+#else
+int refclock_fg_bs;
+#endif /* REFCLOCK */