📄 refclock_jupiter.c
字号:
/* * Copyright (c) 1997, 1998, 2003 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory. * 4. The name of the University may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI)#include "ntpd.h"#include "ntp_io.h"#include "ntp_refclock.h"#include "ntp_unixtime.h"#include "ntp_stdlib.h"#include <stdio.h>#include <ctype.h>#include "jupiter.h"#ifdef HAVE_PPSAPI# include "ppsapi_timepps.h"#endif#ifdef XNTP_BIG_ENDIAN#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))#else#define getshort(s) (s)#define putshort(s) (s)#endif/* XXX */#ifdef sunchar *strerror(int);#endif/* * This driver supports the Rockwell Jupiter GPS Receiver board * adapted to precision timing applications. It requires the * ppsclock line discipline or streams module described in the * Line Disciplines and Streams Drivers page. It also requires a * gadget box and 1-PPS level converter, such as described in the * Pulse-per-second (PPS) Signal Interfacing page. * * It may work (with minor modifications) with other Rockwell GPS * receivers such as the CityTracker. *//* * GPS Definitions */#define DEVICE "/dev/gps%d" /* device name and unit */#define SPEED232 B9600 /* baud *//* * Radio interface parameters */#define PRECISION (-18) /* precision assumed (about 4 us) */#define REFID "GPS\0" /* reference id */#define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */#define DEFFUDGETIME 0 /* default fudge time (ms) *//* Unix timestamp for the GPS epoch: January 6, 1980 */#define GPS_EPOCH 315964800/* Double short to unsigned int */#define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))/* Double short to signed int */#define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))/* One week's worth of seconds */#define WEEKSECS (7 * 24 * 60 * 60)/* * Jupiter unit control structure. */struct instance { struct peer *peer; /* peer */ u_int pollcnt; /* poll message counter */ u_int polled; /* Hand in a time sample? */#ifdef HAVE_PPSAPI pps_params_t pps_params; /* pps parameters */ pps_info_t pps_info; /* last pps data */ pps_handle_t pps_handle; /* pps handle */ u_int assert; /* pps edge to use */ u_int hardpps; /* enable kernel mode */ struct timespec ts; /* last timestamp */#endif l_fp limit; u_int gpos_gweek; /* Current GPOS GPS week number */ u_int gpos_sweek; /* Current GPOS GPS seconds into week */ u_int gweek; /* current GPS week number */ u_int32 lastsweek; /* last seconds into GPS week */ time_t timecode; /* current ntp timecode */ u_int32 stime; /* used to detect firmware bug */ int wantid; /* don't reconfig on channel id msg */ u_int moving; /* mobile platform? */ u_char sloppyclockflag; /* fudge flags */ u_short sbuf[512]; /* local input buffer */ int ssize; /* space used in sbuf */};/* * Function prototypes */static void jupiter_canmsg P((struct instance *, u_int));static u_short jupiter_cksum P((u_short *, u_int));static int jupiter_config P((struct instance *));static void jupiter_debug P((struct peer *, char *, char *, ...)) __attribute__ ((format (printf, 3, 4)));static char * jupiter_parse_t P((struct instance *, u_short *));static char * jupiter_parse_gpos P((struct instance *, u_short *));static void jupiter_platform P((struct instance *, u_int));static void jupiter_poll P((int, struct peer *));static void jupiter_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));#ifdef HAVE_PPSAPIstatic int jupiter_ppsapi P((struct instance *));static int jupiter_pps P((struct instance *));#endif /* HAVE_PPSAPI */static int jupiter_recv P((struct instance *));static void jupiter_receive P((struct recvbuf *rbufp));static void jupiter_reqmsg P((struct instance *, u_int, u_int));static void jupiter_reqonemsg P((struct instance *, u_int));static char * jupiter_send P((struct instance *, struct jheader *));static void jupiter_shutdown P((int, struct peer *));static int jupiter_start P((int, struct peer *));/* * Transfer vector */struct refclock refclock_jupiter = { jupiter_start, /* start up driver */ jupiter_shutdown, /* shut down driver */ jupiter_poll, /* transmit poll message */ jupiter_control, /* (clock control) */ noentry, /* (clock init) */ noentry, /* (clock buginfo) */ NOFLAGS /* not used */};/* * jupiter_start - open the devices and initialize data for processing */static intjupiter_start( int unit, struct peer *peer ){ struct refclockproc *pp; struct instance *instance; int fd = -1; char gpsdev[20]; /* * Open serial port */ (void)sprintf(gpsdev, DEVICE, unit); fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); if (fd == 0) { jupiter_debug(peer, "jupiter_start", "open %s: %s", gpsdev, strerror(errno)); return (0); } /* Allocate unit structure */ if ((instance = (struct instance *) emalloc(sizeof(struct instance))) == NULL) { (void) close(fd); return (0); } memset((char *)instance, 0, sizeof(struct instance)); instance->peer = peer; pp = peer->procptr; pp->io.clock_recv = jupiter_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { (void) close(fd); free(instance); return (0); } pp->unitptr = (caddr_t)instance; /* * Initialize miscellaneous variables */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4);#ifdef HAVE_PPSAPI instance->assert = 1; instance->hardpps = 0; /* * Start the PPSAPI interface if it is there. Default to use * the assert edge and do not enable the kernel hardpps. */ if (time_pps_create(fd, &instance->pps_handle) < 0) { instance->pps_handle = 0; msyslog(LOG_ERR, "refclock_jupiter: time_pps_create failed: %m"); } else if (!jupiter_ppsapi(instance)) goto clean_up;#endif /* HAVE_PPSAPI */ /* Ensure the receiver is properly configured */ if (!jupiter_config(instance)) goto clean_up; return (1);clean_up: jupiter_shutdown(unit, peer); pp->unitptr = 0; return (0);}/* * jupiter_shutdown - shut down the clock */static voidjupiter_shutdown(int unit, struct peer *peer){ struct instance *instance; struct refclockproc *pp; pp = peer->procptr; instance = (struct instance *)pp->unitptr; if (!instance) return;#ifdef HAVE_PPSAPI if (instance->pps_handle) { time_pps_destroy(instance->pps_handle); instance->pps_handle = 0; }#endif /* HAVE_PPSAPI */ io_closeclock(&pp->io); free(instance);}/* * jupiter_config - Configure the receiver */static intjupiter_config(struct instance *instance){ jupiter_debug(instance->peer, "jupiter_config", "init receiver"); /* * Initialize the unit variables */ instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag; instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2); if (instance->moving) jupiter_debug(instance->peer, "jupiter_config", "mobile platform"); instance->pollcnt = 2; instance->polled = 0; instance->gpos_gweek = 0; instance->gpos_sweek = 0; instance->gweek = 0; instance->lastsweek = 2 * WEEKSECS; instance->timecode = 0; instance->stime = 0; instance->ssize = 0; /* Stop outputting all messages */ jupiter_canmsg(instance, JUPITER_ALL); /* Request the receiver id so we can syslog the firmware version */ jupiter_reqonemsg(instance, JUPITER_O_ID); /* Flag that this the id was requested (so we don't get called again) */ instance->wantid = 1; /* Request perodic time mark pulse messages */ jupiter_reqmsg(instance, JUPITER_O_PULSE, 1); /* Request perodic geodetic position status */ jupiter_reqmsg(instance, JUPITER_O_GPOS, 1); /* Set application platform type */ if (instance->moving) jupiter_platform(instance, JUPITER_I_PLAT_MED); else jupiter_platform(instance, JUPITER_I_PLAT_LOW); return (1);}#ifdef HAVE_PPSAPI/* * Initialize PPSAPI */intjupiter_ppsapi( struct instance *instance /* unit structure pointer */ ){ int capability; if (time_pps_getcap(instance->pps_handle, &capability) < 0) { msyslog(LOG_ERR, "refclock_jupiter: time_pps_getcap failed: %m"); return (0); } memset(&instance->pps_params, 0, sizeof(pps_params_t)); if (!instance->assert) instance->pps_params.mode = capability & PPS_CAPTURECLEAR; else instance->pps_params.mode = capability & PPS_CAPTUREASSERT; if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { msyslog(LOG_ERR, "refclock_jupiter: invalid capture edge %d", instance->assert); return (0); } instance->pps_params.mode |= PPS_TSFMT_TSPEC; if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) { msyslog(LOG_ERR, "refclock_jupiter: time_pps_setparams failed: %m"); return (0); } if (instance->hardpps) { if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS, instance->pps_params.mode & ~PPS_TSFMT_TSPEC, PPS_TSFMT_TSPEC) < 0) { msyslog(LOG_ERR, "refclock_jupiter: time_pps_kcbind failed: %m"); return (0); } pps_enable = 1; }/* instance->peer->precision = PPS_PRECISION; */#if DEBUG if (debug) { time_pps_getparams(instance->pps_handle, &instance->pps_params); jupiter_debug(instance->peer, "refclock_jupiter", "pps capability 0x%x version %d mode 0x%x kern %d", capability, instance->pps_params.api_version, instance->pps_params.mode, instance->hardpps); }#endif return (1);}/* * Get PPSAPI timestamps. * * Return 0 on failure and 1 on success. */static intjupiter_pps(struct instance *instance){ pps_info_t pps_info; struct timespec timeout, ts; double dtemp; l_fp tstmp; /* * Convert the timespec nanoseconds field to ntp l_fp units. */ if (instance->pps_handle == 0) return 1; timeout.tv_sec = 0; timeout.tv_nsec = 0; memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t)); if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info, &timeout) < 0) return 1; if (instance->pps_params.mode & PPS_CAPTUREASSERT) { if (pps_info.assert_sequence == instance->pps_info.assert_sequence) return 1; ts = instance->pps_info.assert_timestamp; } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) { if (pps_info.clear_sequence == instance->pps_info.clear_sequence) return 1; ts = instance->pps_info.clear_timestamp; } else { return 1; } if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec)) return 1; instance->ts = ts; tstmp.l_ui = ts.tv_sec + JAN_1970; dtemp = ts.tv_nsec * FRAC / 1e9; tstmp.l_uf = (u_int32)dtemp; instance->peer->procptr->lastrec = tstmp; return 0;}#endif /* HAVE_PPSAPI *//* * jupiter_poll - jupiter watchdog routine */static voidjupiter_poll(int unit, struct peer *peer){ struct instance *instance; struct refclockproc *pp; pp = peer->procptr; instance = (struct instance *)pp->unitptr; /* * You don't need to poll this clock. It puts out timecodes * once per second. If asked for a timestamp, take note. * The next time a timecode comes in, it will be fed back. */ /* * If we haven't had a response in a while, reset the receiver. */ if (instance->pollcnt > 0) { instance->pollcnt--; } else { refclock_report(peer, CEVNT_TIMEOUT); /* Request the receiver id to trigger a reconfig */ jupiter_reqonemsg(instance, JUPITER_O_ID); instance->wantid = 0; } /* * polled every 64 seconds. Ask jupiter_receive to hand in * a timestamp. */ instance->polled = 1; pp->polls++;}/* * jupiter_control - fudge control */static voidjupiter_control( int unit, /* unit (not used) */ struct refclockstat *in, /* input parameters (not used) */ struct refclockstat *out, /* output parameters (not used) */ struct peer *peer /* peer structure pointer */ ){ struct refclockproc *pp; struct instance *instance; u_char sloppyclockflag; pp = peer->procptr; instance = (struct instance *)pp->unitptr; DTOLFP(pp->fudgetime2, &instance->limit); /* Force positive value. */ if (L_ISNEG(&instance->limit)) L_NEG(&instance->limit);#ifdef HAVE_PPSAPI instance->assert = !(pp->sloppyclockflag & CLK_FLAG3); jupiter_ppsapi(instance);#endif /* HAVE_PPSAPI */ sloppyclockflag = instance->sloppyclockflag; instance->sloppyclockflag = pp->sloppyclockflag; if ((instance->sloppyclockflag & CLK_FLAG2) != (sloppyclockflag & CLK_FLAG2)) { jupiter_debug(peer, "jupiter_control", "mode switch: reset receiver"); jupiter_config(instance); return; }}/* * jupiter_receive - receive gps data * Gag me! */static voidjupiter_receive(struct recvbuf *rbufp){ int bpcnt, cc, size, ppsret; time_t last_timecode; u_int32 laststime; char *cp; u_char *bp; u_short *sp; struct jid *ip; struct jheader *hp; struct peer *peer; struct refclockproc *pp; struct instance *instance; l_fp tstamp; /* Initialize pointers and read the timecode and timestamp */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; instance = (struct instance *)pp->unitptr; bp = (u_char *)rbufp->recv_buffer; bpcnt = rbufp->recv_length; /* This shouldn't happen */ if (bpcnt > sizeof(instance->sbuf) - instance->ssize) bpcnt = sizeof(instance->sbuf) - instance->ssize; /* Append to input buffer */ memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt); instance->ssize += bpcnt; /* While there's at least a header and we parse an intact message */ while (instance->ssize > sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) { instance->pollcnt = 2; tstamp = rbufp->recv_time; hp = (struct jheader *)instance->sbuf; sp = (u_short *)(hp + 1); size = cc - sizeof(*hp); switch (getshort(hp->id)) { case JUPITER_O_PULSE: if (size != sizeof(struct jpulse)) { jupiter_debug(peer, "jupiter_receive", "pulse: len %d != %u", size, (int)sizeof(struct jpulse)); refclock_report(peer, CEVNT_BADREPLY); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -