Annotation of embedaddon/ntp/ntpd/refclock_fg.c, revision 1.1.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>