📄 refclock_mx4200.c
字号:
/* * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66. * * Copyright (c) 1992 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. *//* * Modified: Marc Brett <marc.brett@westgeo.com> Sept, 1999. * * 1. Added support for alternate PPS schemes, with code mostly * copied from the Oncore driver (Thanks, Poul-Henning Kamp). * This code runs on SunOS 4.1.3 with ppsclock-1.6a1 and Solaris 7. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#if defined(REFCLOCK) && defined(CLOCK_MX4200) && 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 "mx4200.h"#ifdef HAVE_SYS_TERMIOS_H# include <sys/termios.h>#endif#ifdef HAVE_SYS_PPSCLOCK_H# include <sys/ppsclock.h>#endif#include "ntp_sprintf.h"#ifndef HAVE_STRUCT_PPSCLOCKEVstruct ppsclockev {# ifdef HAVE_STRUCT_TIMESPEC struct timespec tv;# else struct timeval tv;# endif u_int serial;};#endif /* ! HAVE_STRUCT_PPSCLOCKEV */#ifdef HAVE_PPSAPI# include "ppsapi_timepps.h"#endif /* HAVE_PPSAPI *//* * This driver supports the Magnavox Model MX 4200 GPS Receiver * 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's likely that other compatible Magnavox receivers such as the * MX 4200D, MX 9212, MX 9012R, MX 9112 will be supported by this code. *//* * Check this every time you edit the code! */#define YEAR_LAST_MODIFIED 2000/* * GPS Definitions */#define DEVICE "/dev/gps%d" /* device name and unit */#define SPEED232 B4800 /* baud *//* * Radio interface parameters */#define PRECISION (-18) /* precision assumed (about 4 us) */#define REFID "GPS\0" /* reference id */#define DESCRIPTION "Magnavox MX4200 GPS Receiver" /* who we are */#define DEFFUDGETIME 0 /* default fudge time (ms) */#define SLEEPTIME 32 /* seconds to wait for reconfig to complete *//* * Position Averaging. */#define INTERVAL 1 /* Interval between position measurements (s) */#define AVGING_TIME 24 /* Number of hours to average */#define NOT_INITIALIZED -9999. /* initial pivot longitude *//* * MX4200 unit control structure. */struct mx4200unit { u_int pollcnt; /* poll message counter */ u_int polled; /* Hand in a time sample? */ u_int lastserial; /* last pps serial number */ struct ppsclockev ppsev; /* PPS control structure */ double avg_lat; /* average latitude */ double avg_lon; /* average longitude */ double avg_alt; /* average height */ double central_meridian; /* central meridian */ double N_fixes; /* Number of position measurements */ int last_leap; /* leap second warning */ u_int moving; /* mobile platform? */ u_long sloppyclockflag; /* fudge flags */ u_int known; /* position known yet? */ u_long clamp_time; /* when to stop postion averaging */ u_long log_time; /* when to print receiver status */ pps_handle_t pps_h; pps_params_t pps_p; pps_info_t pps_i;};static char pmvxg[] = "PMVXG";/* XXX should be somewhere else */#ifdef __GNUC__#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)#ifndef __attribute__#define __attribute__(args)#endif /* __attribute__ */#endif /* __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) */#else#ifndef __attribute__#define __attribute__(args)#endif /* __attribute__ */#endif /* __GNUC__ *//* XXX end *//* * Function prototypes */static int mx4200_start P((int, struct peer *));static void mx4200_shutdown P((int, struct peer *));static void mx4200_receive P((struct recvbuf *));static void mx4200_poll P((int, struct peer *));static char * mx4200_parse_t P((struct peer *));static char * mx4200_parse_p P((struct peer *));static char * mx4200_parse_s P((struct peer *));#ifdef QSORT_USES_VOID_Pint mx4200_cmpl_fp P((const void *, const void *));#elseint mx4200_cmpl_fp P((const l_fp *, const l_fp *));#endif /* not QSORT_USES_VOID_P */static int mx4200_config P((struct peer *));static void mx4200_ref P((struct peer *));static void mx4200_send P((struct peer *, char *, ...)) __attribute__ ((format (printf, 2, 3)));static u_char mx4200_cksum P((char *, int));static int mx4200_jday P((int, int, int));static void mx4200_debug P((struct peer *, char *, ...)) __attribute__ ((format (printf, 2, 3)));static int mx4200_pps P((struct peer *));/* * Transfer vector */struct refclock refclock_mx4200 = { mx4200_start, /* start up driver */ mx4200_shutdown, /* shut down driver */ mx4200_poll, /* transmit poll message */ noentry, /* not used (old mx4200_control) */ noentry, /* initialize driver (not used) */ noentry, /* not used (old mx4200_buginfo) */ NOFLAGS /* not used */};/* * mx4200_start - open the devices and initialize data for processing */static intmx4200_start( int unit, struct peer *peer ){ register struct mx4200unit *up; struct refclockproc *pp; int fd; char gpsdev[20]; /* * Open serial port */ (void)sprintf(gpsdev, DEVICE, unit); if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_PPS))) { return (0); } /* * Allocate unit structure */ if (!(up = (struct mx4200unit *) emalloc(sizeof(struct mx4200unit)))) { perror("emalloc"); (void) close(fd); return (0); } memset((char *)up, 0, sizeof(struct mx4200unit)); pp = peer->procptr; pp->io.clock_recv = mx4200_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { (void) close(fd); free(up); return (0); } pp->unitptr = (caddr_t)up; /* * Initialize miscellaneous variables */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); /* Ensure the receiver is properly configured */ return mx4200_config(peer);}/* * mx4200_shutdown - shut down the clock */static voidmx4200_shutdown( int unit, struct peer *peer ){ register struct mx4200unit *up; struct refclockproc *pp; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; io_closeclock(&pp->io); free(up);}/* * mx4200_config - Configure the receiver */static intmx4200_config( struct peer *peer ){ char tr_mode; int add_mode; register struct mx4200unit *up; struct refclockproc *pp; int mode; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; /* * Initialize the unit variables * * STRANGE BEHAVIOUR WARNING: The fudge flags are not available * at the time mx4200_start is called. These are set later, * and so the code must be prepared to handle changing flags. */ up->sloppyclockflag = pp->sloppyclockflag; if (pp->sloppyclockflag & CLK_FLAG2) { up->moving = 1; /* Receiver on mobile platform */ msyslog(LOG_DEBUG, "mx4200_config: mobile platform"); } else { up->moving = 0; /* Static Installation */ } up->pollcnt = 2; up->polled = 0; up->known = 0; up->avg_lat = 0.0; up->avg_lon = 0.0; up->avg_alt = 0.0; up->central_meridian = NOT_INITIALIZED; up->N_fixes = 0.0; up->last_leap = 0; /* LEAP_NOWARNING */ up->clamp_time = current_time + (AVGING_TIME * 60 * 60); up->log_time = current_time + SLEEPTIME; if (time_pps_create(pp->io.fd, &up->pps_h) < 0) { perror("time_pps_create"); msyslog(LOG_ERR, "mx4200_config: time_pps_create failed: %m"); return (0); } if (time_pps_getcap(up->pps_h, &mode) < 0) { msyslog(LOG_ERR, "mx4200_config: time_pps_getcap failed: %m"); return (0); } if (time_pps_getparams(up->pps_h, &up->pps_p) < 0) { msyslog(LOG_ERR, "mx4200_config: time_pps_getparams failed: %m"); return (0); } /* nb. only turn things on, if someone else has turned something * on before we get here, leave it alone! */ up->pps_p.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC; up->pps_p.mode &= mode; /* only set what is legal */ if (time_pps_setparams(up->pps_h, &up->pps_p) < 0) { perror("time_pps_setparams"); msyslog(LOG_ERR, "mx4200_config: time_pps_setparams failed: %m"); exit(1); } if (time_pps_kcbind(up->pps_h, PPS_KC_HARDPPS, PPS_CAPTUREASSERT, PPS_TSFMT_TSPEC) < 0) { perror("time_pps_kcbind"); msyslog(LOG_ERR, "mx4200_config: time_pps_kcbind failed: %m"); exit(1); } /* * "007" Control Port Configuration * Zero the output list (do it twice to flush possible junk) */ mx4200_send(peer, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, /* control port output block Label */ 1); /* clear current output control list (1=yes) */ /* add/delete sentences from list */ /* must be null */ /* sentence output rate (sec) */ /* precision for position output */ /* nmea version for cga & gll output */ /* pass-through control */ mx4200_send(peer, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, 1); /* * Request software configuration so we can syslog the firmware version */ mx4200_send(peer, "%s,%03d", "CDGPQ", PMVXG_D_SOFTCONF); /* * "001" Initialization/Mode Control, Part A * Where ARE we? */ mx4200_send(peer, "%s,%03d,,,,,,,,,,", pmvxg, PMVXG_S_INITMODEA); /* day of month */ /* month of year */ /* year */ /* gmt */ /* latitude DDMM.MMMM */ /* north/south */ /* longitude DDDMM.MMMM */ /* east/west */ /* height */ /* Altitude Reference 1=MSL */ /* * "001" Initialization/Mode Control, Part B * Start off in 2d/3d coast mode, holding altitude to last known * value if only 3 satellites available. */ mx4200_send(peer, "%s,%03d,%d,,%.1f,%.1f,%d,%d,%d,%c,%d", pmvxg, PMVXG_S_INITMODEB, 3, /* 2d/3d coast */ /* reserved */ 0.1, /* hor accel fact as per Steve (m/s**2) */ 0.1, /* ver accel fact as per Steve (m/s**2) */ 10, /* vdop */ 10, /* hdop limit as per Steve */ 5, /* elevation limit as per Steve (deg) */ 'U', /* time output mode (UTC) */ 0); /* local time offset from gmt (HHHMM) */ /* * "023" Time Recovery Configuration * Get UTC time from a stationary receiver. * (Set field 1 'D' == dynamic if we are on a moving platform). * (Set field 1 'S' == static if we are not moving). * (Set field 1 'K' == known position if we can initialize lat/lon/alt). */ if (pp->sloppyclockflag & CLK_FLAG2) up->moving = 1; /* Receiver on mobile platform */ else up->moving = 0; /* Static Installation */ up->pollcnt = 2; if (up->moving) { /* dynamic: solve for pos, alt, time, while moving */ tr_mode = 'D'; } else { /* static: solve for pos, alt, time, while stationary */ tr_mode = 'S'; } mx4200_send(peer, "%s,%03d,%c,%c,%c,%d,%d,%d,", pmvxg, PMVXG_S_TRECOVCONF, tr_mode, /* time recovery mode (see above ) */ 'U', /* synchronize to UTC */ 'A', /* always output a time pulse */ 500, /* max time error in ns */ 0, /* user bias in ns */ 1); /* output "830" sentences to control port */ /* Multi-satellite mode */ /* * Output position information (to calculate fixed installation * location) only if we are not moving */ if (up->moving) { add_mode = 2; /* delete from list */ } else { add_mode = 1; /* add to list */ } /* * "007" Control Port Configuration * Output "021" position, height, velocity reports */ mx4200_send(peer, "%s,%03d,%03d,%d,%d,,%d,,,", pmvxg, PMVXG_S_PORTCONF, PMVXG_D_PHV, /* control port output block Label */ 0, /* clear current output control list (0=no) */ add_mode, /* add/delete sentences from list (1=add, 2=del) */ /* must be null */ INTERVAL); /* sentence output rate (sec) */ /* precision for position output */ /* nmea version for cga & gll output */ /* pass-through control */ return (1);}/* * mx4200_ref - Reconfigure unit as a reference station at a known position. */static voidmx4200_ref( struct peer *peer ){ register struct mx4200unit *up; struct refclockproc *pp; double minute, lat, lon, alt; char lats[16], lons[16]; char nsc, ewc; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; /* Should never happen! */ if (up->moving) return; /* * Set up to output status information in the near future */ up->log_time = current_time + SLEEPTIME; /* * "007" Control Port Configuration * Stop outputting "021" position, height, velocity reports */ mx4200_send(peer, "%s,%03d,%03d,%d,%d,,,,,", pmvxg, PMVXG_S_PORTCONF, PMVXG_D_PHV, /* control port output block Label */ 0, /* clear current output control list (0=no) */ 2); /* add/delete sentences from list (2=delete) */ /* must be null */ /* sentence output rate (sec) */ /* precision for position output */ /* nmea version for cga & gll output */ /* pass-through control */ /* * "001" Initialization/Mode Control, Part B * Put receiver in fully-constrained 2d nav mode */ mx4200_send(peer, "%s,%03d,%d,,%.1f,%.1f,%d,%d,%d,%c,%d", pmvxg, PMVXG_S_INITMODEB, 2, /* 2d nav */ /* reserved */ 0.1, /* hor accel fact as per Steve (m/s**2) */ 0.1, /* ver accel fact as per Steve (m/s**2) */ 10, /* vdop */ 10, /* hdop limit as per Steve */ 5, /* elevation limit as per Steve (deg) */ 'U', /* time output mode (UTC) */ 0); /* local time offset from gmt (HHHMM) */ /* * "023" Time Recovery Configuration * Get UTC time from a stationary receiver. Solve for time only. * This should improve the time resolution dramatically. */ mx4200_send(peer, "%s,%03d,%c,%c,%c,%d,%d,%d,", pmvxg, PMVXG_S_TRECOVCONF, 'K', /* known position: solve for time only */ 'U', /* synchronize to UTC */ 'A', /* always output a time pulse */ 500, /* max time error in ns */ 0, /* user bias in ns */ 1); /* output "830" sentences to control port */ /* Multi-satellite mode */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -