diff options
author | roberto <roberto@FreeBSD.org> | 2000-01-28 14:55:50 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 2000-01-28 14:55:50 +0000 |
commit | b5b40f9e420899251189775800d9f74092925299 (patch) | |
tree | 98efdf1b74d6ecb7828bb502a0350116eeb2fd3c /contrib/ntp/ntpd/refclock_fg.c | |
parent | ef64b99e8412f2273dd2e8b3291c2f78ffc4667f (diff) | |
download | FreeBSD-src-b5b40f9e420899251189775800d9f74092925299.zip FreeBSD-src-b5b40f9e420899251189775800d9f74092925299.tar.gz |
Virgin import of ntpd 4.0.99b
Diffstat (limited to 'contrib/ntp/ntpd/refclock_fg.c')
-rw-r--r-- | contrib/ntp/ntpd/refclock_fg.c | 350 |
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 0000000..f1320b0 --- /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 */ |