📄 refclock_oncore.c
字号:
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * * refclock_oncore.c * * Driver for some of the various the Motorola Oncore GPS receivers. * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate * than the others. * The receivers without position hold (GT, GT+) will be less accurate. * * Tested with: * * (UT) (VP) * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P * SOFTWARE VER # 2 SOFTWARE VER # 8 * SOFTWARE REV # 2 SOFTWARE REV # 8 * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 * MODEL # R1121N1114 MODEL # B4121P1155 * HWDR P/N # 1 HDWR P/N # _ * SERIAL # R0010A SERIAL # SSG0226478 * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 * OPTIONS LIST IB * * (Basic) (M12) * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A * SOFTWARE VER # 5 SOFTWARE VER # 1 * SOFTWARE REV # 0 SOFTWARE REV # 3 * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000 * MODEL # A11121P116 MODEL # P143T12NR1 * HDWR P/N # _ HWDR P/N # 1 * SERIAL # SSG0049809 SERIAL # P003UD * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27 * OPTIONS LIST AB * * -------------------------------------------------------------------------- * Reg.Clemens (Mar 2004) * Support for interfaces other than PPSAPI removed, for Solaris, SunOS, * SCO, you now need to use one of the timepps.h files in the root dir. * this driver will 'grab' it for you if you dont have one in /usr/include * -------------------------------------------------------------------------- * This code uses the two devices * /dev/oncore.serial.n * /dev/oncore.pps.n * which may be linked to the same device. * and can read initialization data from the file * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where * n or N are the unit number, viz 127.127.30.N. * -------------------------------------------------------------------------- * Reg.Clemens <reg@dwf.com> Sep98. * Original code written for FreeBSD. * With these mods it works on FreeBSD, SunOS, Solaris and Linux * (SunOS 4.1.3 + ppsclock) * (Solaris7 + MU4) * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). * * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the * state machine state) are printed to CLOCKSTATS if that file is enabled * in /etc/ntp.conf. * * -------------------------------------------------------------------------- * * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) * doing an average of 10000 valid 2D and 3D fixes is what the automatic * site survey mode does. Looking at the output from the receiver * it seems like it is only using 3D fixes. * When we do it ourselves, take 10000 3D fixes. */#define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m *//* * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a * "STATUS" line in the oncore config file, which contains the most recent * copy of all types of messages we recognize. This file can be mmap(2)'ed * by monitoring and statistics programs. * * See separate HTML documentation for this option. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#if defined(REFCLOCK) && defined(CLOCK_ONCORE)#include "ntpd.h"#include "ntp_io.h"#include "ntp_unixtime.h"#include "ntp_refclock.h"#include "ntp_stdlib.h"#include <stdio.h>#include <ctype.h>#include <sys/stat.h>#ifdef ONCORE_SHMEM_STATUS# ifdef HAVE_SYS_MMAN_H# include <sys/mman.h># ifndef MAP_FAILED# define MAP_FAILED ((u_char *) -1)# endif /* MAP_FAILED */# endif /* HAVE_SYS_MMAN_H */#endif /* ONCORE_SHMEM_STATUS */#ifdef HAVE_PPSAPI# include "ppsapi_timepps.h"#endif#ifdef HAVE_SYS_SIO_H# include <sys/sio.h>#endif#ifdef HAVE_SYS_TERMIOS_H# include <sys/termios.h>#endifenum receive_state { ONCORE_NO_IDEA, ONCORE_CHECK_ID, ONCORE_CHECK_CHAN, ONCORE_HAVE_CHAN, ONCORE_RESET_SENT, ONCORE_TEST_SENT, ONCORE_INIT, ONCORE_ALMANAC, ONCORE_RUN};enum site_survey_state { ONCORE_SS_UNKNOWN, ONCORE_SS_TESTING, ONCORE_SS_HW, ONCORE_SS_SW, ONCORE_SS_DONE};enum antenna_state { ONCORE_ANTENNA_UNKNOWN = -1, ONCORE_ANTENNA_OK = 0, ONCORE_ANTENNA_OC = 1, ONCORE_ANTENNA_UC = 2, ONCORE_ANTENNA_NV = 3};/* Model Name, derived from the @@Cj message. * Used to initialize some variables. */enum oncore_model { ONCORE_BASIC, ONCORE_PVT6, ONCORE_VP, ONCORE_UT, ONCORE_UTPLUS, ONCORE_GT, ONCORE_GTPLUS, ONCORE_SL, ONCORE_M12, ONCORE_UNKNOWN};/* the bits that describe these properties are in the same place * on the VP/UT, but have moved on the M12. As such we extract * them, and use them from this struct. * */struct RSM { u_char posn0D; u_char posn2D; u_char posn3D; u_char bad_almanac; u_char bad_fix;};/* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to * see what mode it is in. The bits on the M12 are multiplexed with * other messages, so we have to 'keep' the last known mode here. */enum posn_mode { MODE_UNKNOWN, MODE_0D, MODE_2D, MODE_3D};struct instance { int unit; /* 127.127.30.unit */ struct refclockproc *pp; struct peer *peer; int ttyfd; /* TTY file descriptor */ int ppsfd; /* PPS file descriptor */ int shmemfd; /* Status shm descriptor */ pps_handle_t pps_h; pps_params_t pps_p; enum receive_state o_state; /* Receive state */ enum posn_mode mode; /* 0D, 2D, 3D */ enum site_survey_state site_survey; /* Site Survey state */ enum antenna_state ant_state; /* antenna state */ int Bj_day; u_long delay; /* ns */ long offset; /* ns */ u_char *shmem; char *shmem_fname; u_int shmem_Cb; u_int shmem_Ba; u_int shmem_Ea; u_int shmem_Ha; u_char shmem_reset; u_char shmem_Posn; u_char shmem_bad_Ea; u_char almanac_from_shmem; double ss_lat; double ss_long; double ss_ht; double dH; int ss_count; u_char posn_set; enum oncore_model model; u_int version; u_int revision; u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */ /* the following 7 are all timing counters */ u_char traim_delay; /* seconds counter, waiting for reply */ u_char count; /* cycles thru Ea before starting */ u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */ u_char count2; /* cycles thru Ea after count, to check for @@Ea */ u_char count3; /* cycles thru Ea checking for # channels */ u_char count4; /* cycles thru leap after Gj to issue Bj */ u_char pollcnt; u_char timeout; /* count to retry Cj after Fa self-test */ struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ u_char printed; u_char polled; u_long ev_serial; int Rcvptr; u_char Rcvbuf[500]; u_char BEHa[160]; /* Ba, Ea or Ha */ u_char BEHn[80]; /* Bn , En , or Hn */ u_char Cj[300]; u_char Ag; /* Satellite mask angle */ u_char saw_At; u_char saw_Ay; u_char saw_Az; s_char saw_Gj; u_char have_dH; u_char init_type; s_char saw_tooth; s_char chan_in; /* chan number from INPUT, will always use it */ u_char chan_id; /* chan number determined from part number */ u_char chan_ck; /* chan number determined by sending commands to hardware */ s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */ s_char traim_id; /* TRAIM determined from part number */ u_char traim_ck; /* TRAIM determined by sending commands to hardware */ u_char once; /* one pass code at top of BaEaHa */ s_char assert; u_char hardpps;};#define rcvbuf instance->Rcvbuf#define rcvptr instance->Rcvptrstatic int oncore_start P((int, struct peer *));static void oncore_poll P((int, struct peer *));static void oncore_shutdown P((int, struct peer *));static void oncore_consume P((struct instance *));static void oncore_read_config P((struct instance *));static void oncore_receive P((struct recvbuf *));static int oncore_ppsapi P((struct instance *));static void oncore_get_timestamp P((struct instance *, long, long));static void oncore_init_shmem P((struct instance *));static void oncore_antenna_report P((struct instance *, enum antenna_state));static void oncore_chan_test P((struct instance *));static void oncore_check_almanac P((struct instance *));static void oncore_check_antenna P((struct instance *));static void oncore_check_leap_sec P((struct instance *));static int oncore_checksum_ok P((u_char *, int));static void oncore_compute_dH P((struct instance *));static void oncore_load_almanac P((struct instance *));static void oncore_print_Cb P((struct instance *, u_char *));/* static void oncore_print_array P((u_char *, int)); */static void oncore_print_posn P((struct instance *));static void oncore_sendmsg P((int, u_char *, size_t));static void oncore_set_posn P((struct instance *));static void oncore_set_traim P((struct instance *));static void oncore_shmem_get_3D P((struct instance *));static void oncore_ss P((struct instance *));static int oncore_wait_almanac P((struct instance *));static void oncore_msg_any P((struct instance *, u_char *, size_t, int));static void oncore_msg_Adef P((struct instance *, u_char *, size_t));static void oncore_msg_Ag P((struct instance *, u_char *, size_t));static void oncore_msg_As P((struct instance *, u_char *, size_t));static void oncore_msg_At P((struct instance *, u_char *, size_t));static void oncore_msg_Ay P((struct instance *, u_char *, size_t));static void oncore_msg_Az P((struct instance *, u_char *, size_t));static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t));static void oncore_msg_Bd P((struct instance *, u_char *, size_t));static void oncore_msg_Bj P((struct instance *, u_char *, size_t));static void oncore_msg_BnEnHn P((struct instance *, u_char *, size_t));static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t));static void oncore_msg_Cb P((struct instance *, u_char *, size_t));static void oncore_msg_Cf P((struct instance *, u_char *, size_t));static void oncore_msg_Cj P((struct instance *, u_char *, size_t));static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t));static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t));static void oncore_msg_Ga P((struct instance *, u_char *, size_t));static void oncore_msg_Gb P((struct instance *, u_char *, size_t));static void oncore_msg_Gj P((struct instance *, u_char *, size_t));static void oncore_msg_Sz P((struct instance *, u_char *, size_t));struct refclock refclock_oncore = { oncore_start, /* start up driver */ oncore_shutdown, /* shut down driver */ oncore_poll, /* transmit poll message */ noentry, /* not used */ noentry, /* not used */ noentry, /* not used */ NOFLAGS /* not used */};/* * Understanding the next bit here is not easy unless you have a manual * for the the various Oncore Models. */static struct msg_desc { const char flag[3]; const int len; void (*handler) P((struct instance *, u_char *, size_t)); const char *fmt; int shmem;} oncore_messages[] = { /* Ea and En first since they're most common */ { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" }, { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" }, { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" }, { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, { "Hn", 78, oncore_msg_BnEnHn, "" }, { "Ab", 10, 0, "" }, { "Ac", 11, 0, "" }, { "Ad", 11, oncore_msg_Adef, "" }, { "Ae", 11, oncore_msg_Adef, "" }, { "Af", 15, oncore_msg_Adef, "" }, { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */ { "As", 20, oncore_msg_As, "" }, { "At", 8, oncore_msg_At, "" }, { "Au", 12, 0, "" }, { "Av", 8, 0, "" }, { "Aw", 8, 0, "" }, { "Ay", 11, oncore_msg_Ay, "" }, { "Az", 11, oncore_msg_Az, "" }, { "AB", 8, 0, "" }, { "Bb", 92, 0, "" }, { "Bd", 23, oncore_msg_Bd, "" }, { "Bj", 8, oncore_msg_Bj, "" }, { "Ca", 9, oncore_msg_CaFaIa, "" }, { "Cb", 33, oncore_msg_Cb, "" }, { "Cf", 7, oncore_msg_Cf, "" }, { "Cg", 8, 0, "" }, { "Ch", 9, 0, "" }, { "Cj", 294, oncore_msg_Cj, "" }, { "Ek", 71, 0, "" }, { "Fa", 9, oncore_msg_CaFaIa, "" }, { "Ga", 20, oncore_msg_Ga, "" }, { "Gb", 17, oncore_msg_Gb, "" }, { "Gc", 8, 0, "" }, { "Gd", 8, 0, "" }, { "Ge", 8, 0, "" }, { "Gj", 21, oncore_msg_Gj, "" }, { "Ia", 10, oncore_msg_CaFaIa, "" }, { "Sz", 8, oncore_msg_Sz, "" }, { {0}, 7, 0, "" }};static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */static u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 6/8/12 Posn Hold Parameters */static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */ 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */ 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -