Annotation of embedaddon/ntp/ntpd/refclock_fg.c, revision 1.1
1.1 ! misho 1: /*
! 2: * refclock_fg - clock driver for the Forum Graphic GPS datating station
! 3: */
! 4:
! 5: #ifdef HAVE_CONFIG_H
! 6: # include <config.h>
! 7: #endif
! 8:
! 9: #if defined(REFCLOCK) && defined(CLOCK_FG)
! 10:
! 11: #include "ntpd.h"
! 12: #include "ntp_io.h"
! 13: #include "ntp_refclock.h"
! 14: #include "ntp_calendar.h"
! 15: #include "ntp_stdlib.h"
! 16:
! 17: /*
! 18: * This driver supports the Forum Graphic GPS dating station.
! 19: * More information about FG GPS is available on http://www.forumgraphic.com
! 20: * Contact das@amt.ru for any question about this driver.
! 21: */
! 22:
! 23: /*
! 24: * Interface definitions
! 25: */
! 26: #define DEVICE "/dev/fgclock%d"
! 27: #define PRECISION (-10) /* precision assumed (about 1 ms) */
! 28: #define REFID "GPS"
! 29: #define DESCRIPTION "Forum Graphic GPS dating station"
! 30: #define LENFG 26 /* timecode length */
! 31: #define SPEED232 B9600 /* uart speed (9600 baud) */
! 32:
! 33: /*
! 34: * Function prototypes
! 35: */
! 36: static int fg_init (int);
! 37: static int fg_start (int, struct peer *);
! 38: static void fg_shutdown (int, struct peer *);
! 39: static void fg_poll (int, struct peer *);
! 40: static void fg_receive (struct recvbuf *);
! 41:
! 42: /*
! 43: * Forum Graphic unit control structure
! 44: */
! 45:
! 46: struct fgunit {
! 47: int pollnum; /* Use peer.poll instead? */
! 48: int status; /* Hug to check status information on GPS */
! 49: int y2kwarn; /* Y2K bug */
! 50: };
! 51:
! 52: /*
! 53: * Queries definition
! 54: */
! 55: static char fginit[] = { 0x10, 0x48, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 56: 0, 0, 0, 0, 0, 0, 0, 0, 0 };
! 57: static char fgdate[] = { 0x10, 0x44, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 58: 0, 0, 0, 0, 0, 0, 0, 0, 0 };
! 59:
! 60: /*
! 61: * Transfer vector
! 62: */
! 63: struct refclock refclock_fg = {
! 64: fg_start, /* start up driver */
! 65: fg_shutdown, /* shut down driver */
! 66: fg_poll, /* transmit poll message */
! 67: noentry, /* not used */
! 68: noentry, /* initialize driver (not used) */
! 69: noentry, /* not used */
! 70: NOFLAGS /* not used */
! 71: };
! 72:
! 73: /*
! 74: * fg_init - Initialization of FG GPS.
! 75: */
! 76:
! 77: static int
! 78: fg_init(
! 79: int fd
! 80: )
! 81: {
! 82: if (write(fd, fginit, LENFG) != LENFG)
! 83: return 0;
! 84:
! 85: return (1);
! 86:
! 87: }
! 88:
! 89: /*
! 90: * fg_start - open the device and initialize data for processing
! 91: */
! 92: static int
! 93: fg_start(
! 94: int unit,
! 95: struct peer *peer
! 96: )
! 97: {
! 98: struct refclockproc *pp;
! 99: struct fgunit *up;
! 100: int fd;
! 101: char device[20];
! 102:
! 103:
! 104: /*
! 105: * Open device file for reading.
! 106: */
! 107: (void)sprintf(device, DEVICE, unit);
! 108:
! 109: #ifdef DEBUG
! 110: if (debug)
! 111: printf ("starting FG with device %s\n",device);
! 112: #endif
! 113: if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
! 114: return (0);
! 115:
! 116: /*
! 117: * Allocate and initialize unit structure
! 118: */
! 119:
! 120: if (!(up = (struct fgunit *)
! 121: emalloc(sizeof(struct fgunit)))) {
! 122: (void) close(fd);
! 123: return (0);
! 124: }
! 125: memset((char *)up, 0, sizeof(struct fgunit));
! 126: pp = peer->procptr;
! 127: pp->unitptr = (caddr_t)up;
! 128: pp->io.clock_recv = fg_receive;
! 129: pp->io.srcclock = (caddr_t)peer;
! 130: pp->io.datalen = 0;
! 131: pp->io.fd = fd;
! 132: if (!io_addclock(&pp->io)) {
! 133: (void) close(fd);
! 134: return (0);
! 135: }
! 136:
! 137:
! 138: /*
! 139: * Initialize miscellaneous variables
! 140: */
! 141: peer->precision = PRECISION;
! 142: pp->clockdesc = DESCRIPTION;
! 143: memcpy((char *)&pp->refid, REFID, 3);
! 144: up->pollnum = 0;
! 145:
! 146: /*
! 147: * Setup dating station to use GPS receiver.
! 148: * GPS receiver should work before this operation.
! 149: */
! 150: if(!fg_init(pp->io.fd))
! 151: refclock_report(peer, CEVNT_FAULT);
! 152:
! 153: return (1);
! 154: }
! 155:
! 156:
! 157: /*
! 158: * fg_shutdown - shut down the clock
! 159: */
! 160: static void
! 161: fg_shutdown(
! 162: int unit,
! 163: struct peer *peer
! 164: )
! 165: {
! 166: struct refclockproc *pp;
! 167: struct fgunit *up;
! 168:
! 169: pp = peer->procptr;
! 170: up = (struct fgunit *)pp->unitptr;
! 171: io_closeclock(&pp->io);
! 172: free(up);
! 173: }
! 174:
! 175:
! 176: /*
! 177: * fg_poll - called by the transmit procedure
! 178: */
! 179: static void
! 180: fg_poll(
! 181: int unit,
! 182: struct peer *peer
! 183: )
! 184: {
! 185: struct refclockproc *pp;
! 186:
! 187: pp = peer->procptr;
! 188:
! 189: /*
! 190: * Time to poll the clock. The FG clock responds to a
! 191: * "<DLE>D<DLE><CR>" by returning a timecode in the format specified
! 192: * above. If nothing is heard from the clock for two polls,
! 193: * declare a timeout and keep going.
! 194: */
! 195:
! 196: if (write(pp->io.fd, fgdate, LENFG) != LENFG)
! 197: refclock_report(peer, CEVNT_FAULT);
! 198: else
! 199: pp->polls++;
! 200:
! 201: if (peer->burst > 0)
! 202: return;
! 203: /*
! 204: if (pp->coderecv == pp->codeproc) {
! 205: refclock_report(peer, CEVNT_TIMEOUT);
! 206: return;
! 207: }
! 208: */
! 209: peer->burst = NSTAGE;
! 210:
! 211: record_clock_stats(&peer->srcadr, pp->a_lastcode);
! 212:
! 213:
! 214: return;
! 215:
! 216: }
! 217:
! 218: /*
! 219: * fg_receive - receive data from the serial interface
! 220: */
! 221: static void
! 222: fg_receive(
! 223: struct recvbuf *rbufp
! 224: )
! 225: {
! 226: struct refclockproc *pp;
! 227: struct fgunit *up;
! 228: struct peer *peer;
! 229: char *bpt;
! 230:
! 231: /*
! 232: * Initialize pointers and read the timecode and timestamp
! 233: * We can't use gtlin function because we need bynary data in buf */
! 234:
! 235: peer = (struct peer *)rbufp->recv_srcclock;
! 236: pp = peer->procptr;
! 237: up = (struct fgunit *)pp->unitptr;
! 238:
! 239: /*
! 240: * Below hug to implement receiving of status information
! 241: */
! 242: if(!up->pollnum)
! 243: {
! 244: up->pollnum++;
! 245: return;
! 246: }
! 247:
! 248:
! 249: if (rbufp->recv_length < (LENFG-2))
! 250: {
! 251: refclock_report(peer, CEVNT_BADREPLY);
! 252: return; /* The reply is invalid discard it. */
! 253: }
! 254:
! 255: /* Below I trying to find a correct reply in buffer.
! 256: * Sometime GPS reply located in the beginnig of buffer,
! 257: * sometime you can find it with some offset.
! 258: */
! 259:
! 260: bpt = (char *)rbufp->recv_space.X_recv_buffer;
! 261: while(*bpt != '')
! 262: bpt++;
! 263:
! 264: #define BP2(x) ( bpt[x] & 15 )
! 265: #define BP1(x) (( bpt[x] & 240 ) >> 4)
! 266:
! 267: pp->year = BP1(2)*10 + BP2(2);
! 268:
! 269: if(pp->year == 94)
! 270: {
! 271: refclock_report(peer, CEVNT_BADREPLY);
! 272: if(!fg_init(pp->io.fd))
! 273: refclock_report(peer, CEVNT_FAULT);
! 274: return;
! 275: /* GPS is just powered up. The date is invalid -
! 276: discarding it. Initilize GPS one more time */
! 277: /* Sorry - this driver will broken in 2094 ;) */
! 278: }
! 279:
! 280: if (pp->year < 99)
! 281: pp->year += 100;
! 282:
! 283: pp->year += 1900;
! 284: pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4);
! 285:
! 286: /*
! 287: After Jan, 10 2000 Forum Graphic GPS receiver had a very strange
! 288: benahour. It doubles day number for an hours in replys after 10:10:10 UTC
! 289: and doubles min every hour at HH:10:ss for a minute.
! 290: Hope it is a problem of my unit only and not a Y2K problem of FG GPS.
! 291: Below small code to avoid such situation.
! 292: */
! 293: if(up->y2kwarn > 10)
! 294: pp->hour = BP1(6)*10 + BP2(6);
! 295: else
! 296: pp->hour = BP1(5)*10 + BP2(5);
! 297:
! 298: if((up->y2kwarn > 10) && (pp->hour == 10))
! 299: {
! 300: pp->minute = BP1(7)*10 + BP2(7);
! 301: pp->second = BP1(8)*10 + BP2(8);
! 302: pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000;
! 303: pp->nsec += BP1(10) * 1000;
! 304: } else {
! 305: pp->hour = BP1(5)*10 + BP2(5);
! 306: pp->minute = BP1(6)*10 + BP2(6);
! 307: pp->second = BP1(7)*10 + BP2(7);
! 308: pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000;
! 309: pp->nsec += BP1(9) * 1000;
! 310: }
! 311:
! 312: if((pp->hour == 10) && (pp->minute == 10))
! 313: {
! 314: up->y2kwarn++;
! 315: }
! 316:
! 317: sprintf(pp->a_lastcode, "%d %d %d %d %d", pp->year, pp->day, pp->hour, pp->minute, pp->second);
! 318: pp->lencode = strlen(pp->a_lastcode);
! 319: /*get_systime(&pp->lastrec);*/
! 320:
! 321: #ifdef DEBUG
! 322: if (debug)
! 323: printf ("fg: time is %04d/%03d %02d:%02d:%02d UTC\n",
! 324: pp->year, pp->day, pp->hour, pp->minute, pp->second);
! 325: #endif
! 326: pp->disp = (10e-6);
! 327: pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */
! 328: /* pp->leap = LEAP_NOWARNING; */
! 329:
! 330: /*
! 331: * Process the new sample in the median filter and determine the
! 332: * timecode timestamp.
! 333: */
! 334:
! 335: if (!refclock_process(pp))
! 336: refclock_report(peer, CEVNT_BADTIME);
! 337: pp->lastref = pp->lastrec;
! 338: refclock_receive(peer);
! 339: return;
! 340: }
! 341:
! 342:
! 343: #else
! 344: int refclock_fg_bs;
! 345: #endif /* REFCLOCK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>