Annotation of embedaddon/ntp/ntpd/refclock_jupiter.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1997, 1998, 2003
3: * The Regents of the University of California. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Lawrence Berkeley Laboratory.
17: * 4. The name of the University may not be used to endorse or promote
18: * products derived from this software without specific prior
19: * written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: #ifdef HAVE_CONFIG_H
35: # include <config.h>
36: #endif
37:
38: #if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI)
39:
40: #include "ntpd.h"
41: #include "ntp_io.h"
42: #include "ntp_refclock.h"
43: #include "ntp_unixtime.h"
44: #include "ntp_stdlib.h"
45:
46: #include <stdio.h>
47: #include <ctype.h>
48:
49: #include "jupiter.h"
50:
51: #ifdef HAVE_PPSAPI
52: # include "ppsapi_timepps.h"
53: #endif
54:
55: #ifdef XNTP_BIG_ENDIAN
56: #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
57: #define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
58: #else
59: #define getshort(s) (s)
60: #define putshort(s) (s)
61: #endif
62:
63: /* XXX */
64: #ifdef sun
65: char *strerror(int);
66: #endif
67:
68: /*
69: * This driver supports the Rockwell Jupiter GPS Receiver board
70: * adapted to precision timing applications. It requires the
71: * ppsclock line discipline or streams module described in the
72: * Line Disciplines and Streams Drivers page. It also requires a
73: * gadget box and 1-PPS level converter, such as described in the
74: * Pulse-per-second (PPS) Signal Interfacing page.
75: *
76: * It may work (with minor modifications) with other Rockwell GPS
77: * receivers such as the CityTracker.
78: */
79:
80: /*
81: * GPS Definitions
82: */
83: #define DEVICE "/dev/gps%d" /* device name and unit */
84: #define SPEED232 B9600 /* baud */
85:
86: /*
87: * Radio interface parameters
88: */
89: #define PRECISION (-18) /* precision assumed (about 4 us) */
90: #define REFID "GPS\0" /* reference id */
91: #define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */
92: #define DEFFUDGETIME 0 /* default fudge time (ms) */
93:
94: /* Unix timestamp for the GPS epoch: January 6, 1980 */
95: #define GPS_EPOCH 315964800
96:
97: /* Double short to unsigned int */
98: #define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
99:
100: /* Double short to signed int */
101: #define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
102:
103: /* One week's worth of seconds */
104: #define WEEKSECS (7 * 24 * 60 * 60)
105:
106: /*
107: * Jupiter unit control structure.
108: */
109: struct instance {
110: struct peer *peer; /* peer */
111: u_int pollcnt; /* poll message counter */
112: u_int polled; /* Hand in a time sample? */
113: #ifdef HAVE_PPSAPI
114: pps_params_t pps_params; /* pps parameters */
115: pps_info_t pps_info; /* last pps data */
116: pps_handle_t pps_handle; /* pps handle */
117: u_int assert; /* pps edge to use */
118: u_int hardpps; /* enable kernel mode */
119: struct timespec ts; /* last timestamp */
120: #endif
121: l_fp limit;
122: u_int gpos_gweek; /* Current GPOS GPS week number */
123: u_int gpos_sweek; /* Current GPOS GPS seconds into week */
124: u_int gweek; /* current GPS week number */
125: u_int32 lastsweek; /* last seconds into GPS week */
126: time_t timecode; /* current ntp timecode */
127: u_int32 stime; /* used to detect firmware bug */
128: int wantid; /* don't reconfig on channel id msg */
129: u_int moving; /* mobile platform? */
130: u_char sloppyclockflag; /* fudge flags */
131: u_short sbuf[512]; /* local input buffer */
132: int ssize; /* space used in sbuf */
133: };
134:
135: /*
136: * Function prototypes
137: */
138: static void jupiter_canmsg (struct instance *, u_int);
139: static u_short jupiter_cksum (u_short *, u_int);
140: static int jupiter_config (struct instance *);
141: static void jupiter_debug (struct peer *, char *, char *, ...)
142: __attribute__ ((format (printf, 3, 4)));
143: static char * jupiter_parse_t (struct instance *, u_short *);
144: static char * jupiter_parse_gpos (struct instance *, u_short *);
145: static void jupiter_platform (struct instance *, u_int);
146: static void jupiter_poll (int, struct peer *);
147: static void jupiter_control (int, struct refclockstat *, struct
148: refclockstat *, struct peer *);
149: #ifdef HAVE_PPSAPI
150: static int jupiter_ppsapi (struct instance *);
151: static int jupiter_pps (struct instance *);
152: #endif /* HAVE_PPSAPI */
153: static int jupiter_recv (struct instance *);
154: static void jupiter_receive (struct recvbuf *rbufp);
155: static void jupiter_reqmsg (struct instance *, u_int, u_int);
156: static void jupiter_reqonemsg (struct instance *, u_int);
157: static char * jupiter_send (struct instance *, struct jheader *);
158: static void jupiter_shutdown (int, struct peer *);
159: static int jupiter_start (int, struct peer *);
160:
161: /*
162: * Transfer vector
163: */
164: struct refclock refclock_jupiter = {
165: jupiter_start, /* start up driver */
166: jupiter_shutdown, /* shut down driver */
167: jupiter_poll, /* transmit poll message */
168: jupiter_control, /* (clock control) */
169: noentry, /* (clock init) */
170: noentry, /* (clock buginfo) */
171: NOFLAGS /* not used */
172: };
173:
174: /*
175: * jupiter_start - open the devices and initialize data for processing
176: */
177: static int
178: jupiter_start(
179: int unit,
180: struct peer *peer
181: )
182: {
183: struct refclockproc *pp;
184: struct instance *instance;
185: int fd = -1;
186: char gpsdev[20];
187:
188: /*
189: * Open serial port
190: */
191: snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
192: fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
193: if (fd == 0) {
194: jupiter_debug(peer, "jupiter_start", "open %s: %s",
195: gpsdev, strerror(errno));
196: return (0);
197: }
198:
199: /* Allocate unit structure */
200: instance = emalloc(sizeof(*instance));
201: memset(instance, 0, sizeof(*instance));
202: instance->peer = peer;
203: pp = peer->procptr;
204: pp->io.clock_recv = jupiter_receive;
205: pp->io.srcclock = (caddr_t)peer;
206: pp->io.datalen = 0;
207: pp->io.fd = fd;
208: if (!io_addclock(&pp->io)) {
209: close(fd);
210: free(instance);
211: return (0);
212: }
213: pp->unitptr = (caddr_t)instance;
214:
215: /*
216: * Initialize miscellaneous variables
217: */
218: peer->precision = PRECISION;
219: pp->clockdesc = DESCRIPTION;
220: memcpy((char *)&pp->refid, REFID, 4);
221:
222: #ifdef HAVE_PPSAPI
223: instance->assert = 1;
224: instance->hardpps = 0;
225: /*
226: * Start the PPSAPI interface if it is there. Default to use
227: * the assert edge and do not enable the kernel hardpps.
228: */
229: if (time_pps_create(fd, &instance->pps_handle) < 0) {
230: instance->pps_handle = 0;
231: msyslog(LOG_ERR,
232: "refclock_jupiter: time_pps_create failed: %m");
233: }
234: else if (!jupiter_ppsapi(instance))
235: goto clean_up;
236: #endif /* HAVE_PPSAPI */
237:
238: /* Ensure the receiver is properly configured */
239: if (!jupiter_config(instance))
240: goto clean_up;
241:
242: return (1);
243:
244: clean_up:
245: jupiter_shutdown(unit, peer);
246: pp->unitptr = 0;
247: return (0);
248: }
249:
250: /*
251: * jupiter_shutdown - shut down the clock
252: */
253: static void
254: jupiter_shutdown(int unit, struct peer *peer)
255: {
256: struct instance *instance;
257: struct refclockproc *pp;
258:
259: pp = peer->procptr;
260: instance = (struct instance *)pp->unitptr;
261: if (!instance)
262: return;
263:
264: #ifdef HAVE_PPSAPI
265: if (instance->pps_handle) {
266: time_pps_destroy(instance->pps_handle);
267: instance->pps_handle = 0;
268: }
269: #endif /* HAVE_PPSAPI */
270:
271: io_closeclock(&pp->io);
272: free(instance);
273: }
274:
275: /*
276: * jupiter_config - Configure the receiver
277: */
278: static int
279: jupiter_config(struct instance *instance)
280: {
281: jupiter_debug(instance->peer, "jupiter_config", "init receiver");
282:
283: /*
284: * Initialize the unit variables
285: */
286: instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag;
287: instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2);
288: if (instance->moving)
289: jupiter_debug(instance->peer, "jupiter_config",
290: "mobile platform");
291:
292: instance->pollcnt = 2;
293: instance->polled = 0;
294: instance->gpos_gweek = 0;
295: instance->gpos_sweek = 0;
296: instance->gweek = 0;
297: instance->lastsweek = 2 * WEEKSECS;
298: instance->timecode = 0;
299: instance->stime = 0;
300: instance->ssize = 0;
301:
302: /* Stop outputting all messages */
303: jupiter_canmsg(instance, JUPITER_ALL);
304:
305: /* Request the receiver id so we can syslog the firmware version */
306: jupiter_reqonemsg(instance, JUPITER_O_ID);
307:
308: /* Flag that this the id was requested (so we don't get called again) */
309: instance->wantid = 1;
310:
311: /* Request perodic time mark pulse messages */
312: jupiter_reqmsg(instance, JUPITER_O_PULSE, 1);
313:
314: /* Request perodic geodetic position status */
315: jupiter_reqmsg(instance, JUPITER_O_GPOS, 1);
316:
317: /* Set application platform type */
318: if (instance->moving)
319: jupiter_platform(instance, JUPITER_I_PLAT_MED);
320: else
321: jupiter_platform(instance, JUPITER_I_PLAT_LOW);
322:
323: return (1);
324: }
325:
326: #ifdef HAVE_PPSAPI
327: /*
328: * Initialize PPSAPI
329: */
330: int
331: jupiter_ppsapi(
332: struct instance *instance /* unit structure pointer */
333: )
334: {
335: int capability;
336:
337: if (time_pps_getcap(instance->pps_handle, &capability) < 0) {
338: msyslog(LOG_ERR,
339: "refclock_jupiter: time_pps_getcap failed: %m");
340: return (0);
341: }
342: memset(&instance->pps_params, 0, sizeof(pps_params_t));
343: if (!instance->assert)
344: instance->pps_params.mode = capability & PPS_CAPTURECLEAR;
345: else
346: instance->pps_params.mode = capability & PPS_CAPTUREASSERT;
347: if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
348: msyslog(LOG_ERR,
349: "refclock_jupiter: invalid capture edge %d",
350: instance->assert);
351: return (0);
352: }
353: instance->pps_params.mode |= PPS_TSFMT_TSPEC;
354: if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) {
355: msyslog(LOG_ERR,
356: "refclock_jupiter: time_pps_setparams failed: %m");
357: return (0);
358: }
359: if (instance->hardpps) {
360: if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS,
361: instance->pps_params.mode & ~PPS_TSFMT_TSPEC,
362: PPS_TSFMT_TSPEC) < 0) {
363: msyslog(LOG_ERR,
364: "refclock_jupiter: time_pps_kcbind failed: %m");
365: return (0);
366: }
367: pps_enable = 1;
368: }
369: /* instance->peer->precision = PPS_PRECISION; */
370:
371: #if DEBUG
372: if (debug) {
373: time_pps_getparams(instance->pps_handle, &instance->pps_params);
374: jupiter_debug(instance->peer, "refclock_jupiter",
375: "pps capability 0x%x version %d mode 0x%x kern %d",
376: capability, instance->pps_params.api_version,
377: instance->pps_params.mode, instance->hardpps);
378: }
379: #endif
380:
381: return (1);
382: }
383:
384: /*
385: * Get PPSAPI timestamps.
386: *
387: * Return 0 on failure and 1 on success.
388: */
389: static int
390: jupiter_pps(struct instance *instance)
391: {
392: pps_info_t pps_info;
393: struct timespec timeout, ts;
394: double dtemp;
395: l_fp tstmp;
396:
397: /*
398: * Convert the timespec nanoseconds field to ntp l_fp units.
399: */
400: if (instance->pps_handle == 0)
401: return 1;
402: timeout.tv_sec = 0;
403: timeout.tv_nsec = 0;
404: memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t));
405: if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info,
406: &timeout) < 0)
407: return 1;
408: if (instance->pps_params.mode & PPS_CAPTUREASSERT) {
409: if (pps_info.assert_sequence ==
410: instance->pps_info.assert_sequence)
411: return 1;
412: ts = instance->pps_info.assert_timestamp;
413: } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) {
414: if (pps_info.clear_sequence ==
415: instance->pps_info.clear_sequence)
416: return 1;
417: ts = instance->pps_info.clear_timestamp;
418: } else {
419: return 1;
420: }
421: if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec))
422: return 1;
423: instance->ts = ts;
424:
425: tstmp.l_ui = ts.tv_sec + JAN_1970;
426: dtemp = ts.tv_nsec * FRAC / 1e9;
427: tstmp.l_uf = (u_int32)dtemp;
428: instance->peer->procptr->lastrec = tstmp;
429: return 0;
430: }
431: #endif /* HAVE_PPSAPI */
432:
433: /*
434: * jupiter_poll - jupiter watchdog routine
435: */
436: static void
437: jupiter_poll(int unit, struct peer *peer)
438: {
439: struct instance *instance;
440: struct refclockproc *pp;
441:
442: pp = peer->procptr;
443: instance = (struct instance *)pp->unitptr;
444:
445: /*
446: * You don't need to poll this clock. It puts out timecodes
447: * once per second. If asked for a timestamp, take note.
448: * The next time a timecode comes in, it will be fed back.
449: */
450:
451: /*
452: * If we haven't had a response in a while, reset the receiver.
453: */
454: if (instance->pollcnt > 0) {
455: instance->pollcnt--;
456: } else {
457: refclock_report(peer, CEVNT_TIMEOUT);
458:
459: /* Request the receiver id to trigger a reconfig */
460: jupiter_reqonemsg(instance, JUPITER_O_ID);
461: instance->wantid = 0;
462: }
463:
464: /*
465: * polled every 64 seconds. Ask jupiter_receive to hand in
466: * a timestamp.
467: */
468: instance->polled = 1;
469: pp->polls++;
470: }
471:
472: /*
473: * jupiter_control - fudge control
474: */
475: static void
476: jupiter_control(
477: int unit, /* unit (not used) */
478: struct refclockstat *in, /* input parameters (not used) */
479: struct refclockstat *out, /* output parameters (not used) */
480: struct peer *peer /* peer structure pointer */
481: )
482: {
483: struct refclockproc *pp;
484: struct instance *instance;
485: u_char sloppyclockflag;
486:
487: pp = peer->procptr;
488: instance = (struct instance *)pp->unitptr;
489:
490: DTOLFP(pp->fudgetime2, &instance->limit);
491: /* Force positive value. */
492: if (L_ISNEG(&instance->limit))
493: L_NEG(&instance->limit);
494:
495: #ifdef HAVE_PPSAPI
496: instance->assert = !(pp->sloppyclockflag & CLK_FLAG3);
497: jupiter_ppsapi(instance);
498: #endif /* HAVE_PPSAPI */
499:
500: sloppyclockflag = instance->sloppyclockflag;
501: instance->sloppyclockflag = pp->sloppyclockflag;
502: if ((instance->sloppyclockflag & CLK_FLAG2) !=
503: (sloppyclockflag & CLK_FLAG2)) {
504: jupiter_debug(peer,
505: "jupiter_control",
506: "mode switch: reset receiver");
507: jupiter_config(instance);
508: return;
509: }
510: }
511:
512: /*
513: * jupiter_receive - receive gps data
514: * Gag me!
515: */
516: static void
517: jupiter_receive(struct recvbuf *rbufp)
518: {
519: int bpcnt, cc, size, ppsret;
520: time_t last_timecode;
521: u_int32 laststime;
522: char *cp;
523: u_char *bp;
524: u_short *sp;
525: struct jid *ip;
526: struct jheader *hp;
527: struct peer *peer;
528: struct refclockproc *pp;
529: struct instance *instance;
530: l_fp tstamp;
531:
532: /* Initialize pointers and read the timecode and timestamp */
533: peer = (struct peer *)rbufp->recv_srcclock;
534: pp = peer->procptr;
535: instance = (struct instance *)pp->unitptr;
536:
537: bp = (u_char *)rbufp->recv_buffer;
538: bpcnt = rbufp->recv_length;
539:
540: /* This shouldn't happen */
541: if (bpcnt > sizeof(instance->sbuf) - instance->ssize)
542: bpcnt = sizeof(instance->sbuf) - instance->ssize;
543:
544: /* Append to input buffer */
545: memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt);
546: instance->ssize += bpcnt;
547:
548: /* While there's at least a header and we parse an intact message */
549: while (instance->ssize > sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) {
550: instance->pollcnt = 2;
551:
552: tstamp = rbufp->recv_time;
553: hp = (struct jheader *)instance->sbuf;
554: sp = (u_short *)(hp + 1);
555: size = cc - sizeof(*hp);
556: switch (getshort(hp->id)) {
557:
558: case JUPITER_O_PULSE:
559: if (size != sizeof(struct jpulse)) {
560: jupiter_debug(peer,
561: "jupiter_receive", "pulse: len %d != %u",
562: size, (int)sizeof(struct jpulse));
563: refclock_report(peer, CEVNT_BADREPLY);
564: break;
565: }
566:
567: /*
568: * There appears to be a firmware bug related
569: * to the pulse message; in addition to the one
570: * per second messages, we get an extra pulse
571: * message once an hour (on the anniversary of
572: * the cold start). It seems to come 200 ms
573: * after the one requested. So if we've seen a
574: * pulse message in the last 210 ms, we skip
575: * this one.
576: */
577: laststime = instance->stime;
578: instance->stime = DS2UI(((struct jpulse *)sp)->stime);
579: if (laststime != 0 && instance->stime - laststime <= 21) {
580: jupiter_debug(peer, "jupiter_receive",
581: "avoided firmware bug (stime %.2f, laststime %.2f)",
582: (double)instance->stime * 0.01, (double)laststime * 0.01);
583: break;
584: }
585:
586: /* Retrieve pps timestamp */
587: ppsret = jupiter_pps(instance);
588:
589: /*
590: * Add one second if msg received early
591: * (i.e. before limit, a.k.a. fudgetime2) in
592: * the second.
593: */
594: L_SUB(&tstamp, &pp->lastrec);
595: if (!L_ISGEQ(&tstamp, &instance->limit))
596: ++pp->lastrec.l_ui;
597:
598: /* Parse timecode (even when there's no pps) */
599: last_timecode = instance->timecode;
600: if ((cp = jupiter_parse_t(instance, sp)) != NULL) {
601: jupiter_debug(peer,
602: "jupiter_receive", "pulse: %s", cp);
603: break;
604: }
605:
606: /* Bail if we didn't get a pps timestamp */
607: if (ppsret)
608: break;
609:
610: /* Bail if we don't have the last timecode yet */
611: if (last_timecode == 0)
612: break;
613:
614: /* Add the new sample to a median filter */
615: tstamp.l_ui = JAN_1970 + last_timecode;
616: tstamp.l_uf = 0;
617:
618: refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1);
619:
620: /*
621: * The clock will blurt a timecode every second
622: * but we only want one when polled. If we
623: * havn't been polled, bail out.
624: */
625: if (!instance->polled)
626: break;
627: instance->polled = 0;
628:
629: /*
630: * It's a live one! Remember this time.
631: */
632:
633: pp->lastref = pp->lastrec;
634: refclock_receive(peer);
635:
636: /*
637: * If we get here - what we got from the clock is
638: * OK, so say so
639: */
640: refclock_report(peer, CEVNT_NOMINAL);
641:
642: /*
643: * We have succeeded in answering the poll.
644: * Turn off the flag and return
645: */
646: instance->polled = 0;
647: break;
648:
649: case JUPITER_O_GPOS:
650: if (size != sizeof(struct jgpos)) {
651: jupiter_debug(peer,
652: "jupiter_receive", "gpos: len %d != %u",
653: size, (int)sizeof(struct jgpos));
654: refclock_report(peer, CEVNT_BADREPLY);
655: break;
656: }
657:
658: if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) {
659: jupiter_debug(peer,
660: "jupiter_receive", "gpos: %s", cp);
661: break;
662: }
663: break;
664:
665: case JUPITER_O_ID:
666: if (size != sizeof(struct jid)) {
667: jupiter_debug(peer,
668: "jupiter_receive", "id: len %d != %u",
669: size, (int)sizeof(struct jid));
670: refclock_report(peer, CEVNT_BADREPLY);
671: break;
672: }
673: /*
674: * If we got this message because the Jupiter
675: * just powered instance, it needs to be reconfigured.
676: */
677: ip = (struct jid *)sp;
678: jupiter_debug(peer,
679: "jupiter_receive", "%s chan ver %s, %s (%s)",
680: ip->chans, ip->vers, ip->date, ip->opts);
681: msyslog(LOG_DEBUG,
682: "jupiter_receive: %s chan ver %s, %s (%s)",
683: ip->chans, ip->vers, ip->date, ip->opts);
684: if (instance->wantid)
685: instance->wantid = 0;
686: else {
687: jupiter_debug(peer,
688: "jupiter_receive", "reset receiver");
689: jupiter_config(instance);
690: /*
691: * Restore since jupiter_config() just
692: * zeroed it
693: */
694: instance->ssize = cc;
695: }
696: break;
697:
698: default:
699: jupiter_debug(peer,
700: "jupiter_receive", "unknown message id %d",
701: getshort(hp->id));
702: break;
703: }
704: instance->ssize -= cc;
705: if (instance->ssize < 0) {
706: fprintf(stderr, "jupiter_recv: negative ssize!\n");
707: abort();
708: } else if (instance->ssize > 0)
709: memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize);
710: }
711: }
712:
713: static char *
714: jupiter_parse_t(struct instance *instance, u_short *sp)
715: {
716: struct tm *tm;
717: char *cp;
718: struct jpulse *jp;
719: u_int32 sweek;
720: time_t last_timecode;
721: u_short flags;
722:
723: jp = (struct jpulse *)sp;
724:
725: /* The timecode is presented as seconds into the current GPS week */
726: sweek = DS2UI(jp->sweek) % WEEKSECS;
727:
728: /*
729: * If we don't know the current GPS week, calculate it from the
730: * current time. (It's too bad they didn't include this
731: * important value in the pulse message). We'd like to pick it
732: * up from one of the other messages like gpos or chan but they
733: * don't appear to be synchronous with time keeping and changes
734: * too soon (something like 10 seconds before the new GPS
735: * week).
736: *
737: * If we already know the current GPS week, increment it when
738: * we wrap into a new week.
739: */
740: if (instance->gweek == 0) {
741: if (!instance->gpos_gweek) {
742: return ("jupiter_parse_t: Unknown gweek");
743: }
744:
745: instance->gweek = instance->gpos_gweek;
746:
747: /*
748: * Fix warps. GPOS has GPS time and PULSE has UTC.
749: * Plus, GPOS need not be completely in synch with
750: * the PPS signal.
751: */
752: if (instance->gpos_sweek >= sweek) {
753: if ((instance->gpos_sweek - sweek) > WEEKSECS / 2)
754: ++instance->gweek;
755: }
756: else {
757: if ((sweek - instance->gpos_sweek) > WEEKSECS / 2)
758: --instance->gweek;
759: }
760: }
761: else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) {
762: ++instance->gweek;
763: jupiter_debug(instance->peer,
764: "jupiter_parse_t", "NEW gps week %u", instance->gweek);
765: }
766:
767: /*
768: * See if the sweek stayed the same (this happens when there is
769: * no pps pulse).
770: *
771: * Otherwise, look for time warps:
772: *
773: * - we have stored at least one lastsweek and
774: * - the sweek didn't increase by one and
775: * - we didn't wrap to a new GPS week
776: *
777: * Then we warped.
778: */
779: if (instance->lastsweek == sweek)
780: jupiter_debug(instance->peer,
781: "jupiter_parse_t", "gps sweek not incrementing (%d)",
782: sweek);
783: else if (instance->lastsweek != 2 * WEEKSECS &&
784: instance->lastsweek + 1 != sweek &&
785: !(sweek == 0 && instance->lastsweek == WEEKSECS - 1))
786: jupiter_debug(instance->peer,
787: "jupiter_parse_t", "gps sweek jumped (was %d, now %d)",
788: instance->lastsweek, sweek);
789: instance->lastsweek = sweek;
790:
791: /* This timecode describes next pulse */
792: last_timecode = instance->timecode;
793: instance->timecode =
794: GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek;
795:
796: if (last_timecode == 0)
797: /* XXX debugging */
798: jupiter_debug(instance->peer,
799: "jupiter_parse_t", "UTC <none> (gweek/sweek %u/%u)",
800: instance->gweek, sweek);
801: else {
802: /* XXX debugging */
803: tm = gmtime(&last_timecode);
804: cp = asctime(tm);
805:
806: jupiter_debug(instance->peer,
807: "jupiter_parse_t", "UTC %.24s (gweek/sweek %u/%u)",
808: cp, instance->gweek, sweek);
809:
810: /* Billboard last_timecode (which is now the current time) */
811: instance->peer->procptr->year = tm->tm_year + 1900;
812: instance->peer->procptr->day = tm->tm_yday + 1;
813: instance->peer->procptr->hour = tm->tm_hour;
814: instance->peer->procptr->minute = tm->tm_min;
815: instance->peer->procptr->second = tm->tm_sec;
816: }
817:
818: flags = getshort(jp->flags);
819:
820: /* Toss if not designated "valid" by the gps */
821: if ((flags & JUPITER_O_PULSE_VALID) == 0) {
822: refclock_report(instance->peer, CEVNT_BADTIME);
823: return ("time mark not valid");
824: }
825:
826: /* We better be sync'ed to UTC... */
827: if ((flags & JUPITER_O_PULSE_UTC) == 0) {
828: refclock_report(instance->peer, CEVNT_BADTIME);
829: return ("time mark not sync'ed to UTC");
830: }
831:
832: return (NULL);
833: }
834:
835: static char *
836: jupiter_parse_gpos(struct instance *instance, u_short *sp)
837: {
838: struct jgpos *jg;
839: time_t t;
840: struct tm *tm;
841: char *cp;
842:
843: jg = (struct jgpos *)sp;
844:
845: if (jg->navval != 0) {
846: /*
847: * Solution not valid. Use caution and refuse
848: * to determine GPS week from this message.
849: */
850: instance->gpos_gweek = 0;
851: instance->gpos_sweek = 0;
852: return ("Navigation solution not valid");
853: }
854:
855: instance->gpos_gweek = jg->gweek;
856: instance->gpos_sweek = DS2UI(jg->sweek);
857: while(instance->gpos_sweek >= WEEKSECS) {
858: instance->gpos_sweek -= WEEKSECS;
859: ++instance->gpos_gweek;
860: }
861: instance->gweek = 0;
862:
863: t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek;
864: tm = gmtime(&t);
865: cp = asctime(tm);
866:
867: jupiter_debug(instance->peer,
868: "jupiter_parse_g", "GPS %.24s (gweek/sweek %u/%u)",
869: cp, instance->gpos_gweek, instance->gpos_sweek);
870: return (NULL);
871: }
872:
873: /*
874: * jupiter_debug - print debug messages
875: */
876: #if defined(__STDC__) || defined(SYS_WINNT)
877: static void
878: jupiter_debug(struct peer *peer, char *function, char *fmt, ...)
879: #else
880: static void
881: jupiter_debug(peer, function, fmt, va_alist)
882: struct peer *peer;
883: char *function;
884: char *fmt;
885: #endif /* __STDC__ */
886: {
887: char buffer[200];
888: va_list ap;
889:
890: #if defined(__STDC__) || defined(SYS_WINNT)
891: va_start(ap, fmt);
892: #else
893: va_start(ap);
894: #endif /* __STDC__ */
895: /*
896: * Print debug message to stdout
897: * In the future, we may want to get get more creative...
898: */
899: vsnprintf(buffer, sizeof(buffer), fmt, ap);
900: record_clock_stats(&(peer->srcadr), buffer);
901: #ifdef DEBUG
902: if (debug) {
903: fprintf(stdout, "%s: ", function);
904: fprintf(stdout, buffer);
905: fprintf(stdout, "\n");
906: fflush(stdout);
907: }
908: #endif
909:
910: va_end(ap);
911: }
912:
913: /* Checksum and transmit a message to the Jupiter */
914: static char *
915: jupiter_send(struct instance *instance, struct jheader *hp)
916: {
917: u_int len, size;
918: int cc;
919: u_short *sp;
920: static char errstr[132];
921:
922: size = sizeof(*hp);
923: hp->hsum = putshort(jupiter_cksum((u_short *)hp,
924: (size / sizeof(u_short)) - 1));
925: len = getshort(hp->len);
926: if (len > 0) {
927: sp = (u_short *)(hp + 1);
928: sp[len] = putshort(jupiter_cksum(sp, len));
929: size += (len + 1) * sizeof(u_short);
930: }
931:
932: if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) {
933: snprintf(errstr, sizeof(errstr), "write: %s", strerror(errno));
934: return (errstr);
935: } else if (cc != size) {
936: snprintf(errstr, sizeof(errstr), "short write (%d != %d)", cc, size);
937: return (errstr);
938: }
939: return (NULL);
940: }
941:
942: /* Request periodic message output */
943: static struct {
944: struct jheader jheader;
945: struct jrequest jrequest;
946: } reqmsg = {
947: { putshort(JUPITER_SYNC), 0,
948: putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1),
949: 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK |
950: JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 },
951: { 0, 0, 0, 0 }
952: };
953:
954: /* An interval of zero means to output on trigger */
955: static void
956: jupiter_reqmsg(struct instance *instance, u_int id,
957: u_int interval)
958: {
959: struct jheader *hp;
960: struct jrequest *rp;
961: char *cp;
962:
963: hp = &reqmsg.jheader;
964: hp->id = putshort(id);
965: rp = &reqmsg.jrequest;
966: rp->trigger = putshort(interval == 0);
967: rp->interval = putshort(interval);
968: if ((cp = jupiter_send(instance, hp)) != NULL)
969: jupiter_debug(instance->peer, "jupiter_reqmsg", "%u: %s", id, cp);
970: }
971:
972: /* Cancel periodic message output */
973: static struct jheader canmsg = {
974: putshort(JUPITER_SYNC), 0, 0, 0,
975: JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC,
976: 0
977: };
978:
979: static void
980: jupiter_canmsg(struct instance *instance, u_int id)
981: {
982: struct jheader *hp;
983: char *cp;
984:
985: hp = &canmsg;
986: hp->id = putshort(id);
987: if ((cp = jupiter_send(instance, hp)) != NULL)
988: jupiter_debug(instance->peer, "jupiter_canmsg", "%u: %s", id, cp);
989: }
990:
991: /* Request a single message output */
992: static struct jheader reqonemsg = {
993: putshort(JUPITER_SYNC), 0, 0, 0,
994: JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY,
995: 0
996: };
997:
998: static void
999: jupiter_reqonemsg(struct instance *instance, u_int id)
1000: {
1001: struct jheader *hp;
1002: char *cp;
1003:
1004: hp = &reqonemsg;
1005: hp->id = putshort(id);
1006: if ((cp = jupiter_send(instance, hp)) != NULL)
1007: jupiter_debug(instance->peer, "jupiter_reqonemsg", "%u: %s", id, cp);
1008: }
1009:
1010: /* Set the platform dynamics */
1011: static struct {
1012: struct jheader jheader;
1013: struct jplat jplat;
1014: } platmsg = {
1015: { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT),
1016: putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0,
1017: JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 },
1018: { 0, 0, 0 }
1019: };
1020:
1021: static void
1022: jupiter_platform(struct instance *instance, u_int platform)
1023: {
1024: struct jheader *hp;
1025: struct jplat *pp;
1026: char *cp;
1027:
1028: hp = &platmsg.jheader;
1029: pp = &platmsg.jplat;
1030: pp->platform = putshort(platform);
1031: if ((cp = jupiter_send(instance, hp)) != NULL)
1032: jupiter_debug(instance->peer, "jupiter_platform", "%u: %s", platform, cp);
1033: }
1034:
1035: /* Checksum "len" shorts */
1036: static u_short
1037: jupiter_cksum(u_short *sp, u_int len)
1038: {
1039: u_short sum, x;
1040:
1041: sum = 0;
1042: while (len-- > 0) {
1043: x = *sp++;
1044: sum += getshort(x);
1045: }
1046: return (~sum + 1);
1047: }
1048:
1049: /* Return the size of the next message (or zero if we don't have it all yet) */
1050: static int
1051: jupiter_recv(struct instance *instance)
1052: {
1053: int n, len, size, cc;
1054: struct jheader *hp;
1055: u_char *bp;
1056: u_short *sp;
1057:
1058: /* Must have at least a header's worth */
1059: cc = sizeof(*hp);
1060: size = instance->ssize;
1061: if (size < cc)
1062: return (0);
1063:
1064: /* Search for the sync short if missing */
1065: sp = instance->sbuf;
1066: hp = (struct jheader *)sp;
1067: if (getshort(hp->sync) != JUPITER_SYNC) {
1068: /* Wasn't at the front, sync up */
1069: jupiter_debug(instance->peer, "jupiter_recv", "syncing");
1070: bp = (u_char *)sp;
1071: n = size;
1072: while (n >= 2) {
1073: if (bp[0] != (JUPITER_SYNC & 0xff)) {
1074: /*
1075: jupiter_debug(instance->peer, "{0x%x}", bp[0]);
1076: */
1077: ++bp;
1078: --n;
1079: continue;
1080: }
1081: if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff))
1082: break;
1083: /*
1084: jupiter_debug(instance->peer, "{0x%x 0x%x}", bp[0], bp[1]);
1085: */
1086: bp += 2;
1087: n -= 2;
1088: }
1089: /*
1090: jupiter_debug(instance->peer, "\n");
1091: */
1092: /* Shuffle data to front of input buffer */
1093: if (n > 0)
1094: memcpy(sp, bp, n);
1095: size = n;
1096: instance->ssize = size;
1097: if (size < cc || hp->sync != JUPITER_SYNC)
1098: return (0);
1099: }
1100:
1101: if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) !=
1102: getshort(hp->hsum)) {
1103: jupiter_debug(instance->peer, "jupiter_recv", "bad header checksum!");
1104: /* This is drastic but checksum errors should be rare */
1105: instance->ssize = 0;
1106: return (0);
1107: }
1108:
1109: /* Check for a payload */
1110: len = getshort(hp->len);
1111: if (len > 0) {
1112: n = (len + 1) * sizeof(u_short);
1113: /* Not enough data yet */
1114: if (size < cc + n)
1115: return (0);
1116:
1117: /* Check payload checksum */
1118: sp = (u_short *)(hp + 1);
1119: if (jupiter_cksum(sp, len) != getshort(sp[len])) {
1120: jupiter_debug(instance->peer,
1121: "jupiter_recv", "bad payload checksum!");
1122: /* This is drastic but checksum errors should be rare */
1123: instance->ssize = 0;
1124: return (0);
1125: }
1126: cc += n;
1127: }
1128: return (cc);
1129: }
1130:
1131: #else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
1132: int refclock_jupiter_bs;
1133: #endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>