PageRenderTime 56ms CodeModel.GetById 9ms app.highlight 41ms RepoModel.GetById 2ms app.codeStats 0ms

/contrib/ntp/ntpd/refclock_fg.c

https://bitbucket.org/freebsd/freebsd-head/
C | 345 lines | 197 code | 59 blank | 89 comment | 29 complexity | ac0c4b91c0b9bf73dba9fff7cf7f64b6 MD5 | raw file
  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 */
 36static	int 	fg_init 		P((int));
 37static	int 	fg_start 		P((int, struct peer *));
 38static	void	fg_shutdown		P((int, struct peer *));
 39static	void	fg_poll		P((int, struct peer *));
 40static  void    fg_receive     P((struct recvbuf *));
 41
 42/* 
 43 * Forum Graphic unit control structure
 44 */
 45
 46struct 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 */
 55static char fginit[] = { 0x10, 0x48, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 560, 0, 0, 0, 0, 0, 0, 0, 0 };
 57static char fgdate[] = { 0x10, 0x44, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 580, 0, 0, 0, 0, 0, 0, 0, 0 };
 59
 60/*
 61 * Transfer vector
 62 */
 63struct  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
 77static int
 78fg_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 */
 92static int
 93fg_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 */
160static void
161fg_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 */
179static void
180fg_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 */
221static void
222fg_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
344int refclock_fg_bs;
345#endif /* REFCLOCK */