154359Sroberto/* 254359Sroberto * ---------------------------------------------------------------------------- 354359Sroberto * "THE BEER-WARE LICENSE" (Revision 42): 454359Sroberto * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 554359Sroberto * can do whatever you want with this stuff. If we meet some day, and you think 654359Sroberto * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 754359Sroberto * ---------------------------------------------------------------------------- 854359Sroberto * 954359Sroberto * refclock_oncore.c 1054359Sroberto * 1154359Sroberto * Driver for some of the various the Motorola Oncore GPS receivers. 12132451Sroberto * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T 13132451Sroberto * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate 14132451Sroberto * than the others. 1582498Sroberto * The receivers without position hold (GT, GT+) will be less accurate. 1654359Sroberto * 1754359Sroberto * Tested with: 1854359Sroberto * 1954359Sroberto * (UT) (VP) 2054359Sroberto * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. 2154359Sroberto * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P 2254359Sroberto * SOFTWARE VER # 2 SOFTWARE VER # 8 2354359Sroberto * SOFTWARE REV # 2 SOFTWARE REV # 8 2454359Sroberto * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 2554359Sroberto * MODEL # R1121N1114 MODEL # B4121P1155 2654359Sroberto * HWDR P/N # 1 HDWR P/N # _ 2754359Sroberto * SERIAL # R0010A SERIAL # SSG0226478 2854359Sroberto * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 2954359Sroberto * OPTIONS LIST IB 3054359Sroberto * 3182498Sroberto * (Basic) (M12) 32132451Sroberto * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. 33132451Sroberto * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A 34132451Sroberto * SOFTWARE VER # 5 SOFTWARE VER # 1 35132451Sroberto * SOFTWARE REV # 0 SOFTWARE REV # 3 36132451Sroberto * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000 37132451Sroberto * MODEL # A11121P116 MODEL # P143T12NR1 3882498Sroberto * HDWR P/N # _ HWDR P/N # 1 39132451Sroberto * SERIAL # SSG0049809 SERIAL # P003UD 40132451Sroberto * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27 41132451Sroberto * OPTIONS LIST AB 4282498Sroberto * 43182007Sroberto * (M12+T) (M12+T later version) 44182007Sroberto * COPYRIGHT 1991-2002 MOTOROLA INC. COPYRIGHT 1991-2003 MOTOROLA INC. 45182007Sroberto * SFTW P/N # 61-G10268A SFTW P/N # 61-G10268A 46182007Sroberto * SOFTWARE VER # 2 SOFTWARE VER # 2 47182007Sroberto * SOFTWARE REV # 0 SOFTWARE REV # 1 48182007Sroberto * SOFTWARE DATE AUG 14 2002 SOFTWARE DATE APR 16 2003 49182007Sroberto * MODEL # P283T12T11 MODEL # P273T12T12 50182007Sroberto * HWDR P/N # 2 HWDR P/N # 2 51182007Sroberto * SERIAL # P04DC2 SERIAL # P05Z7Z 52182007Sroberto * MANUFACTUR DATE 2J17 MANUFACTUR DATE 3G15 53182007Sroberto * 5454359Sroberto * -------------------------------------------------------------------------- 55182007Sroberto * Reg Clemens (Feb 2006) 56182007Sroberto * Fix some gcc4 compiler complaints 57182007Sroberto * Fix possible segfault in oncore_init_shmem 58182007Sroberto * change all (possible) fprintf(stderr, to record_clock_stats 59182007Sroberto * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct 60182007Sroberto * immediately after new Almanac Read. 61182007Sroberto * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it> 62182007Sroberto * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or 63182007Sroberto * the new one. Compiles depending on timepps.h seen. 64182007Sroberto * -------------------------------------------------------------------------- 65182007Sroberto * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds 66182007Sroberto * (the oncore driver was setting the wrong ntpd variable) 67182007Sroberto * -------------------------------------------------------------------------- 68182007Sroberto * Reg.Clemens (Mar 2004) 69182007Sroberto * Support for interfaces other than PPSAPI removed, for Solaris, SunOS, 70182007Sroberto * SCO, you now need to use one of the timepps.h files in the root dir. 71182007Sroberto * this driver will 'grab' it for you if you dont have one in /usr/include 72182007Sroberto * -------------------------------------------------------------------------- 7354359Sroberto * This code uses the two devices 7482498Sroberto * /dev/oncore.serial.n 7582498Sroberto * /dev/oncore.pps.n 7654359Sroberto * which may be linked to the same device. 7754359Sroberto * and can read initialization data from the file 7882498Sroberto * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where 7982498Sroberto * n or N are the unit number, viz 127.127.30.N. 8054359Sroberto * -------------------------------------------------------------------------- 8154359Sroberto * Reg.Clemens <reg@dwf.com> Sep98. 8254359Sroberto * Original code written for FreeBSD. 8382498Sroberto * With these mods it works on FreeBSD, SunOS, Solaris and Linux 8482498Sroberto * (SunOS 4.1.3 + ppsclock) 8582498Sroberto * (Solaris7 + MU4) 8682498Sroberto * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). 8754359Sroberto * 8854359Sroberto * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the 8954359Sroberto * state machine state) are printed to CLOCKSTATS if that file is enabled 9054359Sroberto * in /etc/ntp.conf. 9154359Sroberto * 9254359Sroberto * -------------------------------------------------------------------------- 9382498Sroberto * 9454359Sroberto * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) 9554359Sroberto * doing an average of 10000 valid 2D and 3D fixes is what the automatic 9654359Sroberto * site survey mode does. Looking at the output from the receiver 9754359Sroberto * it seems like it is only using 3D fixes. 9854359Sroberto * When we do it ourselves, take 10000 3D fixes. 9954359Sroberto */ 10054359Sroberto 10154359Sroberto#define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ 10254359Sroberto 10356746Sroberto/* 10456746Sroberto * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a 10556746Sroberto * "STATUS" line in the oncore config file, which contains the most recent 10682498Sroberto * copy of all types of messages we recognize. This file can be mmap(2)'ed 10756746Sroberto * by monitoring and statistics programs. 10882498Sroberto * 10982498Sroberto * See separate HTML documentation for this option. 11056746Sroberto */ 11156746Sroberto 11254359Sroberto#ifdef HAVE_CONFIG_H 11354359Sroberto#include <config.h> 11454359Sroberto#endif 11554359Sroberto 116182007Sroberto#if defined(REFCLOCK) && defined(CLOCK_ONCORE) 11754359Sroberto 11882498Sroberto#include "ntpd.h" 11982498Sroberto#include "ntp_io.h" 12082498Sroberto#include "ntp_unixtime.h" 12182498Sroberto#include "ntp_refclock.h" 12282498Sroberto#include "ntp_stdlib.h" 12382498Sroberto 12454359Sroberto#include <stdio.h> 12554359Sroberto#include <ctype.h> 12654359Sroberto#include <sys/stat.h> 12756746Sroberto#ifdef ONCORE_SHMEM_STATUS 12856746Sroberto# ifdef HAVE_SYS_MMAN_H 12956746Sroberto# include <sys/mman.h> 13056746Sroberto# ifndef MAP_FAILED 13156746Sroberto# define MAP_FAILED ((u_char *) -1) 132182007Sroberto# endif /* MAP_FAILED */ 13356746Sroberto# endif /* HAVE_SYS_MMAN_H */ 13456746Sroberto#endif /* ONCORE_SHMEM_STATUS */ 13554359Sroberto 13654359Sroberto#ifdef HAVE_PPSAPI 137182007Sroberto# include "ppsapi_timepps.h" 13854359Sroberto#endif 13954359Sroberto 14056746Sroberto#ifdef HAVE_SYS_SIO_H 14156746Sroberto# include <sys/sio.h> 14256746Sroberto#endif 14356746Sroberto 14454359Srobertoenum receive_state { 14554359Sroberto ONCORE_NO_IDEA, 146132451Sroberto ONCORE_CHECK_ID, 147132451Sroberto ONCORE_CHECK_CHAN, 148132451Sroberto ONCORE_HAVE_CHAN, 14954359Sroberto ONCORE_RESET_SENT, 15054359Sroberto ONCORE_TEST_SENT, 15182498Sroberto ONCORE_INIT, 15254359Sroberto ONCORE_ALMANAC, 15354359Sroberto ONCORE_RUN 15454359Sroberto}; 15554359Sroberto 15654359Srobertoenum site_survey_state { 15754359Sroberto ONCORE_SS_UNKNOWN, 15882498Sroberto ONCORE_SS_TESTING, 15954359Sroberto ONCORE_SS_HW, 16054359Sroberto ONCORE_SS_SW, 16154359Sroberto ONCORE_SS_DONE 16254359Sroberto}; 16354359Sroberto 164132451Srobertoenum antenna_state { 165132451Sroberto ONCORE_ANTENNA_UNKNOWN = -1, 166132451Sroberto ONCORE_ANTENNA_OK = 0, 167132451Sroberto ONCORE_ANTENNA_OC = 1, 168132451Sroberto ONCORE_ANTENNA_UC = 2, 169132451Sroberto ONCORE_ANTENNA_NV = 3 170132451Sroberto}; 171132451Sroberto 17282498Sroberto/* Model Name, derived from the @@Cj message. 17382498Sroberto * Used to initialize some variables. 17482498Sroberto */ 17582498Sroberto 17682498Srobertoenum oncore_model { 17782498Sroberto ONCORE_BASIC, 17882498Sroberto ONCORE_PVT6, 17982498Sroberto ONCORE_VP, 18082498Sroberto ONCORE_UT, 18182498Sroberto ONCORE_UTPLUS, 18282498Sroberto ONCORE_GT, 18382498Sroberto ONCORE_GTPLUS, 18482498Sroberto ONCORE_SL, 18582498Sroberto ONCORE_M12, 18682498Sroberto ONCORE_UNKNOWN 18782498Sroberto}; 18882498Sroberto 18982498Sroberto/* the bits that describe these properties are in the same place 19082498Sroberto * on the VP/UT, but have moved on the M12. As such we extract 19182498Sroberto * them, and use them from this struct. 19282498Sroberto * 19382498Sroberto */ 19482498Sroberto 19582498Srobertostruct RSM { 19682498Sroberto u_char posn0D; 19782498Sroberto u_char posn2D; 19882498Sroberto u_char posn3D; 19982498Sroberto u_char bad_almanac; 20082498Sroberto u_char bad_fix; 20182498Sroberto}; 20282498Sroberto 20382498Sroberto/* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to 20482498Sroberto * see what mode it is in. The bits on the M12 are multiplexed with 20582498Sroberto * other messages, so we have to 'keep' the last known mode here. 20682498Sroberto */ 20782498Sroberto 20882498Srobertoenum posn_mode { 20982498Sroberto MODE_UNKNOWN, 21082498Sroberto MODE_0D, 21182498Sroberto MODE_2D, 21282498Sroberto MODE_3D 21382498Sroberto}; 21482498Sroberto 21554359Srobertostruct instance { 21654359Sroberto int unit; /* 127.127.30.unit */ 21782498Sroberto struct refclockproc *pp; 21882498Sroberto struct peer *peer; 21982498Sroberto 22054359Sroberto int ttyfd; /* TTY file descriptor */ 22154359Sroberto int ppsfd; /* PPS file descriptor */ 222132451Sroberto int shmemfd; /* Status shm descriptor */ 22354359Sroberto pps_handle_t pps_h; 22454359Sroberto pps_params_t pps_p; 22554359Sroberto enum receive_state o_state; /* Receive state */ 22682498Sroberto enum posn_mode mode; /* 0D, 2D, 3D */ 22754359Sroberto enum site_survey_state site_survey; /* Site Survey state */ 228132451Sroberto enum antenna_state ant_state; /* antenna state */ 22954359Sroberto 23054359Sroberto int Bj_day; 23154359Sroberto 23282498Sroberto u_long delay; /* ns */ 23354359Sroberto long offset; /* ns */ 23454359Sroberto 23582498Sroberto u_char *shmem; 23682498Sroberto char *shmem_fname; 23782498Sroberto u_int shmem_Cb; 23882498Sroberto u_int shmem_Ba; 23982498Sroberto u_int shmem_Ea; 24082498Sroberto u_int shmem_Ha; 24182498Sroberto u_char shmem_reset; 24282498Sroberto u_char shmem_Posn; 243132451Sroberto u_char shmem_bad_Ea; 244132451Sroberto u_char almanac_from_shmem; 24582498Sroberto 24654359Sroberto double ss_lat; 24754359Sroberto double ss_long; 24854359Sroberto double ss_ht; 24982498Sroberto double dH; 25054359Sroberto int ss_count; 25182498Sroberto u_char posn_set; 25254359Sroberto 25382498Sroberto enum oncore_model model; 25482498Sroberto u_int version; 25582498Sroberto u_int revision; 25682498Sroberto 25782498Sroberto u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ 258182007Sroberto s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */ 259132451Sroberto /* the following 7 are all timing counters */ 26082498Sroberto u_char traim_delay; /* seconds counter, waiting for reply */ 261132451Sroberto u_char count; /* cycles thru Ea before starting */ 262132451Sroberto u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */ 263132451Sroberto u_char count2; /* cycles thru Ea after count, to check for @@Ea */ 264132451Sroberto u_char count3; /* cycles thru Ea checking for # channels */ 265132451Sroberto u_char count4; /* cycles thru leap after Gj to issue Bj */ 266182007Sroberto u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */ 267182007Sroberto u_char count5_set; /* only set count5 once */ 268132451Sroberto u_char pollcnt; 269132451Sroberto u_char timeout; /* count to retry Cj after Fa self-test */ 27082498Sroberto 27182498Sroberto struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ 27282498Sroberto u_char printed; 27382498Sroberto u_char polled; 274132451Sroberto u_long ev_serial; 27554359Sroberto int Rcvptr; 27654359Sroberto u_char Rcvbuf[500]; 277132451Sroberto u_char BEHa[160]; /* Ba, Ea or Ha */ 278132451Sroberto u_char BEHn[80]; /* Bn , En , or Hn */ 27954359Sroberto u_char Cj[300]; 280132451Sroberto u_char Ag; /* Satellite mask angle */ 281132451Sroberto u_char saw_At; 282132451Sroberto u_char saw_Ay; 283132451Sroberto u_char saw_Az; 284132451Sroberto s_char saw_Gj; 28582498Sroberto u_char have_dH; 28654359Sroberto u_char init_type; 28754359Sroberto s_char saw_tooth; 288132451Sroberto s_char chan_in; /* chan number from INPUT, will always use it */ 289132451Sroberto u_char chan_id; /* chan number determined from part number */ 290132451Sroberto u_char chan_ck; /* chan number determined by sending commands to hardware */ 291182007Sroberto s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */ 292132451Sroberto s_char traim_id; /* TRAIM determined from part number */ 293132451Sroberto u_char traim_ck; /* TRAIM determined by sending commands to hardware */ 294132451Sroberto u_char once; /* one pass code at top of BaEaHa */ 29582498Sroberto s_char assert; 296132451Sroberto u_char hardpps; 29754359Sroberto}; 29854359Sroberto 29954359Sroberto#define rcvbuf instance->Rcvbuf 30054359Sroberto#define rcvptr instance->Rcvptr 30154359Sroberto 302132451Srobertostatic int oncore_start P((int, struct peer *)); 303132451Srobertostatic void oncore_poll P((int, struct peer *)); 304132451Srobertostatic void oncore_shutdown P((int, struct peer *)); 305132451Srobertostatic void oncore_consume P((struct instance *)); 306132451Srobertostatic void oncore_read_config P((struct instance *)); 307132451Srobertostatic void oncore_receive P((struct recvbuf *)); 308132451Srobertostatic int oncore_ppsapi P((struct instance *)); 309132451Srobertostatic void oncore_get_timestamp P((struct instance *, long, long)); 310132451Srobertostatic void oncore_init_shmem P((struct instance *)); 31154359Sroberto 312132451Srobertostatic void oncore_antenna_report P((struct instance *, enum antenna_state)); 313132451Srobertostatic void oncore_chan_test P((struct instance *)); 314132451Srobertostatic void oncore_check_almanac P((struct instance *)); 315132451Srobertostatic void oncore_check_antenna P((struct instance *)); 316132451Srobertostatic void oncore_check_leap_sec P((struct instance *)); 317132451Srobertostatic int oncore_checksum_ok P((u_char *, int)); 318132451Srobertostatic void oncore_compute_dH P((struct instance *)); 319132451Srobertostatic void oncore_load_almanac P((struct instance *)); 320132451Srobertostatic void oncore_print_Cb P((struct instance *, u_char *)); 321132451Sroberto/* static void oncore_print_array P((u_char *, int)); */ 322132451Srobertostatic void oncore_print_posn P((struct instance *)); 323132451Srobertostatic void oncore_sendmsg P((int, u_char *, size_t)); 324132451Srobertostatic void oncore_set_posn P((struct instance *)); 325132451Srobertostatic void oncore_set_traim P((struct instance *)); 326132451Srobertostatic void oncore_shmem_get_3D P((struct instance *)); 327132451Srobertostatic void oncore_ss P((struct instance *)); 328132451Srobertostatic int oncore_wait_almanac P((struct instance *)); 329132451Sroberto 33082498Srobertostatic void oncore_msg_any P((struct instance *, u_char *, size_t, int)); 331132451Srobertostatic void oncore_msg_Adef P((struct instance *, u_char *, size_t)); 332132451Srobertostatic void oncore_msg_Ag P((struct instance *, u_char *, size_t)); 33382498Srobertostatic void oncore_msg_As P((struct instance *, u_char *, size_t)); 33482498Srobertostatic void oncore_msg_At P((struct instance *, u_char *, size_t)); 33582498Srobertostatic void oncore_msg_Ay P((struct instance *, u_char *, size_t)); 33682498Srobertostatic void oncore_msg_Az P((struct instance *, u_char *, size_t)); 33782498Srobertostatic void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t)); 338132451Srobertostatic void oncore_msg_Bd P((struct instance *, u_char *, size_t)); 33982498Srobertostatic void oncore_msg_Bj P((struct instance *, u_char *, size_t)); 340132451Srobertostatic void oncore_msg_BnEnHn P((struct instance *, u_char *, size_t)); 34182498Srobertostatic void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t)); 34282498Srobertostatic void oncore_msg_Cb P((struct instance *, u_char *, size_t)); 34382498Srobertostatic void oncore_msg_Cf P((struct instance *, u_char *, size_t)); 34482498Srobertostatic void oncore_msg_Cj P((struct instance *, u_char *, size_t)); 34582498Srobertostatic void oncore_msg_Cj_id P((struct instance *, u_char *, size_t)); 34682498Srobertostatic void oncore_msg_Cj_init P((struct instance *, u_char *, size_t)); 347132451Srobertostatic void oncore_msg_Ga P((struct instance *, u_char *, size_t)); 348132451Srobertostatic void oncore_msg_Gb P((struct instance *, u_char *, size_t)); 34982498Srobertostatic void oncore_msg_Gj P((struct instance *, u_char *, size_t)); 35082498Srobertostatic void oncore_msg_Sz P((struct instance *, u_char *, size_t)); 35154359Sroberto 35254359Srobertostruct refclock refclock_oncore = { 35354359Sroberto oncore_start, /* start up driver */ 35454359Sroberto oncore_shutdown, /* shut down driver */ 35554359Sroberto oncore_poll, /* transmit poll message */ 35654359Sroberto noentry, /* not used */ 35754359Sroberto noentry, /* not used */ 358182007Sroberto noentry, /* not used */ 35954359Sroberto NOFLAGS /* not used */ 36054359Sroberto}; 36154359Sroberto 36254359Sroberto/* 36354359Sroberto * Understanding the next bit here is not easy unless you have a manual 36482498Sroberto * for the the various Oncore Models. 36554359Sroberto */ 36654359Sroberto 36756746Srobertostatic struct msg_desc { 36854359Sroberto const char flag[3]; 36954359Sroberto const int len; 37082498Sroberto void (*handler) P((struct instance *, u_char *, size_t)); 37154359Sroberto const char *fmt; 37256746Sroberto int shmem; 37354359Sroberto} oncore_messages[] = { 37482498Sroberto /* Ea and En first since they're most common */ 37582498Sroberto { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, 37682498Sroberto { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" }, 37782498Sroberto { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" }, 378132451Sroberto { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" }, 379132451Sroberto { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, 380132451Sroberto { "Hn", 78, oncore_msg_BnEnHn, "" }, 38182498Sroberto { "Ab", 10, 0, "" }, 38282498Sroberto { "Ac", 11, 0, "" }, 383132451Sroberto { "Ad", 11, oncore_msg_Adef, "" }, 384132451Sroberto { "Ae", 11, oncore_msg_Adef, "" }, 385132451Sroberto { "Af", 15, oncore_msg_Adef, "" }, 386132451Sroberto { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */ 38782498Sroberto { "As", 20, oncore_msg_As, "" }, 38882498Sroberto { "At", 8, oncore_msg_At, "" }, 38982498Sroberto { "Au", 12, 0, "" }, 39082498Sroberto { "Av", 8, 0, "" }, 39182498Sroberto { "Aw", 8, 0, "" }, 39282498Sroberto { "Ay", 11, oncore_msg_Ay, "" }, 39382498Sroberto { "Az", 11, oncore_msg_Az, "" }, 39482498Sroberto { "AB", 8, 0, "" }, 39582498Sroberto { "Bb", 92, 0, "" }, 396132451Sroberto { "Bd", 23, oncore_msg_Bd, "" }, 39782498Sroberto { "Bj", 8, oncore_msg_Bj, "" }, 39882498Sroberto { "Ca", 9, oncore_msg_CaFaIa, "" }, 39982498Sroberto { "Cb", 33, oncore_msg_Cb, "" }, 40082498Sroberto { "Cf", 7, oncore_msg_Cf, "" }, 40182498Sroberto { "Cg", 8, 0, "" }, 40282498Sroberto { "Ch", 9, 0, "" }, 40382498Sroberto { "Cj", 294, oncore_msg_Cj, "" }, 40482498Sroberto { "Ek", 71, 0, "" }, 40582498Sroberto { "Fa", 9, oncore_msg_CaFaIa, "" }, 406132451Sroberto { "Ga", 20, oncore_msg_Ga, "" }, 407132451Sroberto { "Gb", 17, oncore_msg_Gb, "" }, 408132451Sroberto { "Gc", 8, 0, "" }, 409182007Sroberto { "Gd", 8, 0, "" }, 410132451Sroberto { "Ge", 8, 0, "" }, 41182498Sroberto { "Gj", 21, oncore_msg_Gj, "" }, 41282498Sroberto { "Ia", 10, oncore_msg_CaFaIa, "" }, 41382498Sroberto { "Sz", 8, oncore_msg_Sz, "" }, 41482498Sroberto { {0}, 7, 0, "" } 41554359Sroberto}; 41654359Sroberto 41754359Sroberto 418132451Srobertostatic u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */ 419132451Srobertostatic u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */ 420132451Srobertostatic u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */ 421132451Srobertostatic u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */ 422132451Srobertostatic u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */ 423132451Srobertostatic u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */ 424132451Srobertostatic u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */ 425132451Srobertostatic u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */ 426132451Srobertostatic u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */ 427132451Srobertostatic 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 */ 428132451Srobertostatic u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */ 429132451Sroberto 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */ 430132451Sroberto 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */ 431132451Srobertostatic u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */ 432132451Srobertostatic u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */ 433132451Srobertostatic u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */ 434132451Srobertostatic u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */ 435132451Srobertostatic u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */ 436132451Srobertostatic u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */ 437132451Srobertostatic u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */ 438132451Srobertostatic u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */ 439132451Srobertostatic u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */ 440132451Srobertostatic u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */ 441132451Srobertostatic u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */ 442132451Srobertostatic u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */ 443132451Srobertostatic u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */ 444132451Srobertostatic u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */ 445132451Srobertostatic u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */ 446132451Srobertostatic u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */ 447132451Srobertostatic u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */ 448132451Srobertostatic u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */ 449132451Srobertostatic u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim on */ 450182007Srobertostatic u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on, traim on */ 451182007Srobertostatic u_char oncore_cmd_Bnx[] = { 'B', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim off */ 452132451Srobertostatic u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */ 453132451Srobertostatic u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */ 454132451Srobertostatic u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */ 455132451Srobertostatic u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */ 456132451Srobertostatic u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */ 457132451Srobertostatic u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */ 458132451Srobertostatic u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */ 459132451Srobertostatic u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg off, traim on */ 460182007Srobertostatic u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on, traim on */ 461182007Srobertostatic u_char oncore_cmd_Enx[] = { 'E', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg off, traim off */ 462132451Srobertostatic u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */ 463132451Srobertostatic u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */ 464132451Srobertostatic u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */ 465132451Sroberto 0xff, 0xff, 0xff, 0xff, /* */ 466132451Sroberto 0xff, 0xff, 0xff, 0xff, 0xff }; /* */ 467132451Srobertostatic u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */ 468132451Srobertostatic u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */ 469132451Srobertostatic u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */ 470132451Srobertostatic u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */ 471132451Srobertostatic u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */ 472132451Srobertostatic u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */ 473132451Srobertostatic u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */ 474132451Srobertostatic u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */ 475132451Srobertostatic u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */ 476132451Srobertostatic u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */ 477132451Srobertostatic u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */ 478132451Srobertostatic u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */ 479132451Srobertostatic u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */ 480132451Srobertostatic u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */ 48154359Sroberto 482132451Sroberto/* it appears that as of 1997/1998, the UT had As,At, but not Au,Av 483132451Sroberto * the GT had Au,Av, but not As,At 484132451Sroberto * This was as of v2.0 of both firmware sets. possibly 1.3 for UT. 485132451Sroberto * Bj in UT at v1.3 486132451Sroberto * dont see Bd in UT/GT thru 1999 487132451Sroberto * Gj in UT as of 3.0, 1999 , Bj as of 1.3 48854359Sroberto */ 48954359Sroberto 490132451Srobertostatic char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", 491132451Sroberto "Aug", "Sep", "Oct", "Nov", "Dec" }; 49282498Sroberto 493182007Sroberto#define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ 494182007Sroberto#define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ 49554359Sroberto 49654359Sroberto#define SPEED B9600 /* Oncore Binary speed (9600 bps) */ 49754359Sroberto 49854359Sroberto/* 49954359Sroberto * Assemble and disassemble 32bit signed quantities from a buffer. 50054359Sroberto * 50154359Sroberto */ 50254359Sroberto 50354359Sroberto /* to buffer, int w, u_char *buf */ 50482498Sroberto#define w32_buf(buf,w) { u_int i_tmp; \ 50554359Sroberto i_tmp = (w<0) ? (~(-w)+1) : (w); \ 50654359Sroberto (buf)[0] = (i_tmp >> 24) & 0xff; \ 50754359Sroberto (buf)[1] = (i_tmp >> 16) & 0xff; \ 50854359Sroberto (buf)[2] = (i_tmp >> 8) & 0xff; \ 50954359Sroberto (buf)[3] = (i_tmp ) & 0xff; \ 51054359Sroberto } 51154359Sroberto 51254359Sroberto#define w32(buf) (((buf)[0]&0xff) << 24 | \ 51354359Sroberto ((buf)[1]&0xff) << 16 | \ 51454359Sroberto ((buf)[2]&0xff) << 8 | \ 51554359Sroberto ((buf)[3]&0xff) ) 51654359Sroberto 51754359Sroberto /* from buffer, char *buf, result to an int */ 51854359Sroberto#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) 51954359Sroberto 52056746Sroberto 52154359Sroberto/* 52254359Sroberto * oncore_start - initialize data for processing 52354359Sroberto */ 52482498Sroberto 52554359Srobertostatic int 52654359Srobertooncore_start( 52754359Sroberto int unit, 52854359Sroberto struct peer *peer 52954359Sroberto ) 53054359Sroberto{ 531182007Sroberto#define STRING_LEN 32 53254359Sroberto register struct instance *instance; 53354359Sroberto struct refclockproc *pp; 534182007Sroberto int fd1, fd2, num; 535182007Sroberto char device1[STRING_LEN], device2[STRING_LEN], Msg[160]; 53654359Sroberto const char *cp; 53754359Sroberto struct stat stat1, stat2; 53854359Sroberto 539132451Sroberto /* create instance structure for this unit */ 540132451Sroberto 541132451Sroberto if (!(instance = (struct instance *) malloc(sizeof *instance))) { 542132451Sroberto perror("malloc"); 543132451Sroberto return (0); 544132451Sroberto } 545132451Sroberto memset((char *) instance, 0, sizeof *instance); 546132451Sroberto 547132451Sroberto /* initialize miscellaneous variables */ 54854359Sroberto 54954359Sroberto pp = peer->procptr; 55082498Sroberto pp->unitptr = (caddr_t) instance; 55182498Sroberto instance->pp = pp; 55282498Sroberto instance->unit = unit; 55382498Sroberto instance->peer = peer; 554132451Sroberto instance->assert = 1; 555132451Sroberto instance->once = 1; 55682498Sroberto 55754359Sroberto instance->Bj_day = -1; 55882498Sroberto instance->traim = -1; 559132451Sroberto instance->traim_in = -1; 560132451Sroberto instance->chan_in = -1; 56182498Sroberto instance->model = ONCORE_UNKNOWN; 56282498Sroberto instance->mode = MODE_UNKNOWN; 56382498Sroberto instance->site_survey = ONCORE_SS_UNKNOWN; 564132451Sroberto instance->Ag = 0xff; /* Satellite mask angle, unset by user */ 565132451Sroberto instance->ant_state = ONCORE_ANTENNA_UNKNOWN; 56654359Sroberto 56782498Sroberto peer->precision = -26; 56882498Sroberto peer->minpoll = 4; 56982498Sroberto peer->maxpoll = 4; 57082498Sroberto pp->clockdesc = "Motorola Oncore GPS Receiver"; 57182498Sroberto memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); 57282498Sroberto 573182007Sroberto cp = "ONCORE DRIVER -- CONFIGURING"; 574182007Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 57554359Sroberto 576182007Sroberto instance->o_state = ONCORE_NO_IDEA; 577182007Sroberto cp = "state = ONCORE_NO_IDEA"; 578182007Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 57954359Sroberto 580182007Sroberto /* Now open files. 581182007Sroberto * This is a bit complicated, a we dont want to open the same file twice 582182007Sroberto * (its a problem on some OS), and device2 may not exist for the new PPS 583182007Sroberto */ 584182007Sroberto 585182007Sroberto (void)sprintf(device1, DEVICE1, unit); 586182007Sroberto (void)sprintf(device2, DEVICE2, unit); 587182007Sroberto 588182007Sroberto /* OPEN DEVICES */ 589182007Sroberto /* opening different devices for fd1 and fd2 presents no problems */ 590182007Sroberto /* opening the SAME device twice, seems to be OS dependent. 591182007Sroberto (a) on Linux (no streams) no problem 592182007Sroberto (b) on SunOS (and possibly Solaris, untested), (streams) 593182007Sroberto never see the line discipline. 594182007Sroberto Since things ALWAYS work if we only open the device once, we check 595182007Sroberto to see if the two devices are in fact the same, then proceed to 596182007Sroberto do one open or two. 597182007Sroberto */ 598182007Sroberto 599182007Sroberto if (stat(device1, &stat1)) { 600182007Sroberto sprintf(Msg, "Can't stat fd1 (%s)\n", device1); 601182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 602182007Sroberto exit(1); 60354359Sroberto } 60454359Sroberto 605182007Sroberto if (stat(device2, &stat2)) { 606182007Sroberto sprintf(Msg, "Can't stat fd2 (%s)\n", device2); 607182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 608182007Sroberto exit(1); 609182007Sroberto } 610132451Sroberto 611182007Sroberto if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) { 612182007Sroberto sprintf(Msg, "Can't open fd1 (%s)\n", device1); 613182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 614182007Sroberto exit(1); 615132451Sroberto } 616132451Sroberto 617182007Sroberto if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */ 618182007Sroberto fd2 = fd1; 619182007Sroberto else { /* different devices here */ 620182007Sroberto if ((fd2=open(device2, O_RDWR)) < 0) { 621182007Sroberto sprintf(Msg, "Can't open fd2 (%s)\n", device2); 622182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 623182007Sroberto exit(1); 624182007Sroberto } 625182007Sroberto } 626182007Sroberto num = fd2; 627182007Sroberto 628182007Sroberto /* open ppsapi soure */ 629182007Sroberto 630182007Sroberto if (time_pps_create(num, &instance->pps_h) < 0) { 631182007Sroberto record_clock_stats(&(instance->peer->srcadr), "PPSAPI not found in kernel"); 632182007Sroberto return(0); 633182007Sroberto } 634182007Sroberto 635182007Sroberto /* continue initialization */ 636182007Sroberto 637182007Sroberto instance->ttyfd = fd1; 638182007Sroberto instance->ppsfd = fd2; 639182007Sroberto 640182007Sroberto /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */ 641182007Sroberto 642182007Sroberto oncore_read_config(instance); 643182007Sroberto 644132451Sroberto if (!oncore_ppsapi(instance)) 645132451Sroberto return(0); 646132451Sroberto 647132451Sroberto pp->io.clock_recv = oncore_receive; 648132451Sroberto pp->io.srcclock = (caddr_t)peer; 649132451Sroberto pp->io.datalen = 0; 650132451Sroberto pp->io.fd = fd1; 651132451Sroberto if (!io_addclock(&pp->io)) { 652182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: io_addclock"); 653132451Sroberto (void) close(fd1); 654132451Sroberto free(instance); 655132451Sroberto return (0); 656132451Sroberto } 657132451Sroberto 658132451Sroberto#ifdef ONCORE_SHMEM_STATUS 659132451Sroberto /* 660132451Sroberto * Before starting ONCORE, lets setup SHMEM 661132451Sroberto * This will include merging an old SHMEM into the new one if 662132451Sroberto * an old one is found. 663132451Sroberto */ 664132451Sroberto 665132451Sroberto oncore_init_shmem(instance); 666132451Sroberto#endif 667132451Sroberto 668132451Sroberto /* 669132451Sroberto * This will return the Model of the Oncore receiver. 670132451Sroberto * and start the Initialization loop in oncore_msg_Cj. 671132451Sroberto */ 672132451Sroberto 673132451Sroberto instance->o_state = ONCORE_CHECK_ID; 674132451Sroberto cp = "state = ONCORE_CHECK_ID"; 675132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 676132451Sroberto 677132451Sroberto instance->timeout = 4; 678132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ 679132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 680132451Sroberto 681132451Sroberto instance->pollcnt = 2; 682132451Sroberto return (1); 683132451Sroberto} 684132451Sroberto 685132451Sroberto 686132451Sroberto/* 687132451Sroberto * oncore_shutdown - shut down the clock 688132451Sroberto */ 689132451Sroberto 690132451Srobertostatic void 691132451Srobertooncore_shutdown( 692132451Sroberto int unit, 693132451Sroberto struct peer *peer 694132451Sroberto ) 695132451Sroberto{ 696132451Sroberto register struct instance *instance; 697132451Sroberto struct refclockproc *pp; 698132451Sroberto 699132451Sroberto pp = peer->procptr; 700132451Sroberto instance = (struct instance *) pp->unitptr; 701132451Sroberto 702132451Sroberto io_closeclock(&pp->io); 703132451Sroberto 704182007Sroberto time_pps_destroy (instance->pps_h); 705182007Sroberto 706132451Sroberto close(instance->ttyfd); 707182007Sroberto 708182007Sroberto if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd)) 709182007Sroberto close(instance->ppsfd); 710182007Sroberto 711132451Sroberto if (instance->shmemfd) 712132451Sroberto close(instance->shmemfd); 713182007Sroberto 714132451Sroberto free(instance); 715132451Sroberto} 716132451Sroberto 717132451Sroberto 718132451Sroberto 719132451Sroberto/* 720132451Sroberto * oncore_poll - called by the transmit procedure 721132451Sroberto */ 722132451Sroberto 723132451Srobertostatic void 724132451Srobertooncore_poll( 725132451Sroberto int unit, 726132451Sroberto struct peer *peer 727132451Sroberto ) 728132451Sroberto{ 729132451Sroberto struct instance *instance; 730132451Sroberto 731132451Sroberto instance = (struct instance *) peer->procptr->unitptr; 732132451Sroberto if (instance->timeout) { 733132451Sroberto char *cp; 734132451Sroberto 735132451Sroberto instance->timeout--; 736132451Sroberto if (instance->timeout == 0) { 737132451Sroberto cp = "Oncore: No response from @@Cj, shutting down driver"; 738132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 739132451Sroberto oncore_shutdown(unit, peer); 740132451Sroberto } else { 741132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 742132451Sroberto cp = "Oncore: Resend @@Cj"; 743132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 744132451Sroberto } 745132451Sroberto return; 746132451Sroberto } 747132451Sroberto 748132451Sroberto if (!instance->pollcnt) 749132451Sroberto refclock_report(peer, CEVNT_TIMEOUT); 750132451Sroberto else 751132451Sroberto instance->pollcnt--; 752132451Sroberto peer->procptr->polls++; 753132451Sroberto instance->polled = 1; 754132451Sroberto} 755132451Sroberto 756132451Sroberto 757132451Sroberto 758132451Sroberto/* 759132451Sroberto * Initialize PPSAPI 760132451Sroberto */ 761132451Sroberto 762132451Srobertostatic int 763132451Srobertooncore_ppsapi( 764132451Sroberto struct instance *instance 765132451Sroberto ) 766132451Sroberto{ 767182007Sroberto int cap, mode, mode1; 768182007Sroberto char *cp, Msg[160]; 769132451Sroberto 770182007Sroberto if (time_pps_getcap(instance->pps_h, &cap) < 0) { 771182007Sroberto msyslog(LOG_ERR, "time_pps_getcap failed: %m"); 77256746Sroberto return (0); 77356746Sroberto } 77456746Sroberto 77556746Sroberto if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { 776182007Sroberto msyslog(LOG_ERR, "time_pps_getparams failed: %m"); 77756746Sroberto return (0); 77856746Sroberto } 77956746Sroberto 78056746Sroberto /* nb. only turn things on, if someone else has turned something 78182498Sroberto * on before we get here, leave it alone! 78256746Sroberto */ 78356746Sroberto 784182007Sroberto if (instance->assert) { 785182007Sroberto cp = "Assert."; 786182007Sroberto mode = PPS_CAPTUREASSERT; 787182007Sroberto mode1 = PPS_OFFSETASSERT; 78854359Sroberto } else { 789182007Sroberto cp = "Clear."; 790182007Sroberto mode = PPS_CAPTURECLEAR; 791182007Sroberto mode1 = PPS_OFFSETCLEAR; 79254359Sroberto } 793182007Sroberto sprintf(Msg, "Initializing timeing to %s.", cp); 794182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 79556746Sroberto 796182007Sroberto if (!(mode & cap)) { 797182007Sroberto sprintf(Msg, "Can't set timeing to %s, exiting...", cp); 798182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 799182007Sroberto return(0); 800182007Sroberto } 801182007Sroberto 802182007Sroberto if (!(mode1 & cap)) { 803182007Sroberto sprintf(Msg, "Can't set PPS_%sCLEAR, this will increase jitter.", cp); 804182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 805182007Sroberto mode1 = 0; 806182007Sroberto } 807182007Sroberto 808182007Sroberto /* only set what is legal */ 809182007Sroberto 810182007Sroberto instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap; 811182007Sroberto 81254359Sroberto if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { 813182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: time_pps_setparams fails"); 81454359Sroberto exit(1); 81554359Sroberto } 81656746Sroberto 817132451Sroberto /* If HARDPPS is on, we tell kernel */ 81882498Sroberto 819132451Sroberto if (instance->hardpps) { 820132451Sroberto int i; 82182498Sroberto 822182007Sroberto record_clock_stats(&(instance->peer->srcadr), "HARDPPS Set."); 823182007Sroberto 824132451Sroberto if (instance->assert) 825132451Sroberto i = PPS_CAPTUREASSERT; 826132451Sroberto else 827132451Sroberto i = PPS_CAPTURECLEAR; 82882498Sroberto 829182007Sroberto /* we know that 'i' is legal from above */ 830182007Sroberto 831182007Sroberto if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, 832182007Sroberto PPS_TSFMT_TSPEC) < 0) { 833182007Sroberto msyslog(LOG_ERR, "time_pps_kcbind failed: %m"); 834182007Sroberto record_clock_stats(&(instance->peer->srcadr), "HARDPPS failed, abort..."); 835182007Sroberto return (0); 83656746Sroberto } 837182007Sroberto pps_enable = 1; 83854359Sroberto } 839132451Sroberto return(1); 840132451Sroberto} 84156746Sroberto 842132451Sroberto 843132451Sroberto 844132451Sroberto#ifdef ONCORE_SHMEM_STATUS 845132451Srobertostatic void 846132451Srobertooncore_init_shmem( 847132451Sroberto struct instance *instance 848132451Sroberto ) 849132451Sroberto{ 850132451Sroberto int i, l, n, fd, shmem_old_size, n1; 851182007Sroberto char Msg[160]; 852182007Sroberto u_char *cp, *cp1, *buf, *shmem_old; 853132451Sroberto struct msg_desc *mp; 854132451Sroberto struct stat sbuf; 855132451Sroberto size_t shmem_length; 856132451Sroberto 857132451Sroberto /* 858132451Sroberto * The first thing we do is see if there is an instance->shmem_fname file (still) 859132451Sroberto * out there from a previous run. If so, we copy it in and use it to initialize 860132451Sroberto * shmem (so we won't lose our almanac if we need it). 861132451Sroberto */ 862132451Sroberto 863132451Sroberto shmem_old = 0; 864182007Sroberto shmem_old_size = 0; 865132451Sroberto if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0) 866182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open SHMEM file"); 867132451Sroberto else { 868132451Sroberto fstat(fd, &sbuf); 869132451Sroberto shmem_old_size = sbuf.st_size; 870182007Sroberto if (shmem_old_size != 0) { 871182007Sroberto shmem_old = (u_char *) malloc((unsigned) sbuf.st_size); 872182007Sroberto if (shmem_old == NULL) 873182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem_old"); 874182007Sroberto else 875182007Sroberto read(fd, shmem_old, shmem_old_size); 876132451Sroberto } 877132451Sroberto close(fd); 87854359Sroberto } 87954359Sroberto 880132451Sroberto /* OK, we now create the NEW SHMEM. */ 881132451Sroberto 882132451Sroberto if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { 883182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open shmem"); 884182007Sroberto if (shmem_old) 885182007Sroberto free(shmem_old); 886182007Sroberto 887132451Sroberto return; 888132451Sroberto } 889132451Sroberto 890132451Sroberto /* see how big it needs to be */ 891132451Sroberto 892132451Sroberto n = 1; 893132451Sroberto for (mp=oncore_messages; mp->flag[0]; mp++) { 894132451Sroberto mp->shmem = n; 895132451Sroberto /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ 896132451Sroberto if (!strcmp(mp->flag, "Cb")) { 897132451Sroberto instance->shmem_Cb = n; 898132451Sroberto n += (mp->len + 3) * 34; 899132451Sroberto } 900132451Sroberto if (!strcmp(mp->flag, "Ba")) { 901132451Sroberto instance->shmem_Ba = n; 902132451Sroberto n += (mp->len + 3) * 3; 903132451Sroberto } 904132451Sroberto if (!strcmp(mp->flag, "Ea")) { 905132451Sroberto instance->shmem_Ea = n; 906132451Sroberto n += (mp->len + 3) * 3; 907132451Sroberto } 908132451Sroberto if (!strcmp(mp->flag, "Ha")) { 909132451Sroberto instance->shmem_Ha = n; 910132451Sroberto n += (mp->len + 3) * 3; 911132451Sroberto } 912132451Sroberto n += (mp->len + 3); 913132451Sroberto } 914132451Sroberto shmem_length = n + 2; 915132451Sroberto 916132451Sroberto buf = malloc(shmem_length); 917132451Sroberto if (buf == NULL) { 918182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem"); 919132451Sroberto close(instance->shmemfd); 920182007Sroberto if (shmem_old) 921182007Sroberto free(shmem_old); 922182007Sroberto 923132451Sroberto return; 924132451Sroberto } 925132451Sroberto 926132451Sroberto memset(buf, 0, shmem_length); 927132451Sroberto 928132451Sroberto /* next build the new SHMEM buffer in memory */ 929132451Sroberto 930132451Sroberto for (mp=oncore_messages; mp->flag[0]; mp++) { 931132451Sroberto l = mp->shmem; 932132451Sroberto buf[l + 0] = mp->len >> 8; 933132451Sroberto buf[l + 1] = mp->len & 0xff; 934132451Sroberto buf[l + 2] = 0; 935132451Sroberto buf[l + 3] = '@'; 936132451Sroberto buf[l + 4] = '@'; 937132451Sroberto buf[l + 5] = mp->flag[0]; 938132451Sroberto buf[l + 6] = mp->flag[1]; 939132451Sroberto if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { 940132451Sroberto if (!strcmp(mp->flag, "Cb")) 941132451Sroberto n = 35; 942132451Sroberto else 943132451Sroberto n = 4; 944132451Sroberto for (i=1; i<n; i++) { 945132451Sroberto buf[l + i * (mp->len+3) + 0] = mp->len >> 8; 946132451Sroberto buf[l + i * (mp->len+3) + 1] = mp->len & 0xff; 947132451Sroberto buf[l + i * (mp->len+3) + 2] = 0; 948132451Sroberto buf[l + i * (mp->len+3) + 3] = '@'; 949132451Sroberto buf[l + i * (mp->len+3) + 4] = '@'; 950132451Sroberto buf[l + i * (mp->len+3) + 5] = mp->flag[0]; 951132451Sroberto buf[l + i * (mp->len+3) + 6] = mp->flag[1]; 952132451Sroberto } 953132451Sroberto } 954132451Sroberto } 955132451Sroberto 956132451Sroberto /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem) 957182007Sroberto * copying the data in shmem_old to buf. 958182007Sroberto * When we are done we write it out and free both buffers. 959182007Sroberto * If the structure sizes dont agree, I will not copy. 960182007Sroberto * This could be due to an addition/deletion or a problem with the disk file. 96154359Sroberto */ 96254359Sroberto 963132451Sroberto if (shmem_old) { 964182007Sroberto if (shmem_old_size == shmem_length) { 965182007Sroberto for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) { 966182007Sroberto n1 = 256*(*(cp1-3)) + *(cp1-2); 967182007Sroberto if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4)) 968182007Sroberto break; 96954359Sroberto 970182007Sroberto memcpy(cp, cp1, (size_t) n); 971182007Sroberto } 972132451Sroberto } 973132451Sroberto free(shmem_old); 974132451Sroberto } 975132451Sroberto 976132451Sroberto i = write(instance->shmemfd, buf, shmem_length); 977132451Sroberto free(buf); 978132451Sroberto 979132451Sroberto if (i != shmem_length) { 980182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: error writing shmem"); 981132451Sroberto close(instance->shmemfd); 982132451Sroberto return; 983132451Sroberto } 984132451Sroberto 985132451Sroberto instance->shmem = (u_char *) mmap(0, shmem_length, 986132451Sroberto PROT_READ | PROT_WRITE, 987132451Sroberto#ifdef MAP_HASSEMAPHORE 988132451Sroberto MAP_HASSEMAPHORE | 989132451Sroberto#endif 990132451Sroberto MAP_SHARED, instance->shmemfd, (off_t)0); 991132451Sroberto 992132451Sroberto if (instance->shmem == (u_char *)MAP_FAILED) { 993132451Sroberto instance->shmem = 0; 994132451Sroberto close(instance->shmemfd); 995132451Sroberto return; 996132451Sroberto } 997132451Sroberto 998182007Sroberto sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s", 999182007Sroberto (u_long) shmem_length, instance->shmem_fname); 1000132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 100154359Sroberto} 1002132451Sroberto#endif /* ONCORE_SHMEM_STATUS */ 100354359Sroberto 100456746Sroberto 100556746Sroberto 100654359Sroberto/* 100754359Sroberto * Read Input file if it exists. 100854359Sroberto */ 100982498Sroberto 101054359Srobertostatic void 101154359Srobertooncore_read_config( 101254359Sroberto struct instance *instance 101354359Sroberto ) 101454359Sroberto{ 101554359Sroberto/* 101682498Sroberto * First we try to open the configuration file 101782498Sroberto * /etc/oncoreN 101882498Sroberto * where N is the unit number viz 127.127.30.N. 101982498Sroberto * If we don't find it we try 102082498Sroberto * /etc/ntp.oncore.N 102182498Sroberto * and then 102282498Sroberto * /etc/ntp.oncore 102354359Sroberto * 102482498Sroberto * If we don't find any then we don't have the cable delay or PPS offset 102554359Sroberto * and we choose MODE (4) below. 102654359Sroberto * 102754359Sroberto * Five Choices for MODE 102854359Sroberto * (0) ONCORE is preinitialized, don't do anything to change it. 102954359Sroberto * nb, DON'T set 0D mode, DON'T set Delay, position... 103054359Sroberto * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. 103154359Sroberto * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, 103254359Sroberto * lock this in, go to 0D mode. 103354359Sroberto * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. 103454359Sroberto * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, 103554359Sroberto * lock this in, go to 0D mode. 103654359Sroberto * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] 103754359Sroberto * then this position is set as the INITIAL position of the ONCORE. 103854359Sroberto * This can reduce the time to first fix. 103954359Sroberto * ------------------------------------------------------------------------------- 104054359Sroberto * Note that an Oncore UT without a battery backup retains NO information if it is 104154359Sroberto * power cycled, with a Battery Backup it remembers the almanac, etc. 104254359Sroberto * For an Oncore VP, there is an eeprom that will contain this data, along with the 104354359Sroberto * option of Battery Backup. 104454359Sroberto * So a UT without Battery Backup is equivalent to doing a HARD RESET on each 104554359Sroberto * power cycle, since there is nowhere to store the data. 104654359Sroberto * ------------------------------------------------------------------------------- 104754359Sroberto * 104854359Sroberto * If we open one or the other of the files, we read it looking for 1049132451Sroberto * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS, 1050132451Sroberto * STATUS, POSN3D, POSN2D, CHAN, TRAIM 105154359Sroberto * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must 105254359Sroberto * be present or mode reverts to (2,4). 105354359Sroberto * 105454359Sroberto * Read input file. 105554359Sroberto * 105654359Sroberto * # is comment to end of line 105754359Sroberto * = allowed between 1st and 2nd fields. 105854359Sroberto * 105954359Sroberto * Expect to see one line with 'MODE' as first field, followed by an integer 106054359Sroberto * in the range 0-4 (default = 4). 106154359Sroberto * 106254359Sroberto * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. 106354359Sroberto * All numbers are floating point. 106454359Sroberto * DDD.ddd 106554359Sroberto * DDD MMM.mmm 106654359Sroberto * DDD MMM SSS.sss 106754359Sroberto * 106882498Sroberto * Expect to see one line with 'HT' as first field, 106982498Sroberto * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' 107082498Sroberto * for feet or meters. HT is the height above the GPS ellipsoid. 1071132451Sroberto * If the receiver reports height in both GPS and MSL, then we will report 107282498Sroberto * the difference GPS-MSL on the clockstats file. 107354359Sroberto * 107482498Sroberto * There is an optional line, starting with DELAY, followed 107554359Sroberto * by 1 or two fields. The first is a number (a time) the second is 107654359Sroberto * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 107782498Sroberto * DELAY is cable delay, typically a few tens of ns. 107882498Sroberto * 107982498Sroberto * There is an optional line, starting with OFFSET, followed 108082498Sroberto * by 1 or two fields. The first is a number (a time) the second is 108182498Sroberto * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 108282498Sroberto * OFFSET is the offset of the PPS pulse from 0. (only fully implemented 108354359Sroberto * with the PPSAPI, we need to be able to tell the Kernel about this 108454359Sroberto * offset if the Kernel PLL is in use, but can only do this presently 108554359Sroberto * when using the PPSAPI interface. If not using the Kernel PLL, 108654359Sroberto * then there is no problem. 108754359Sroberto * 108882498Sroberto * There is an optional line, with either ASSERT or CLEAR on it, which 108954359Sroberto * determine which transition of the PPS signal is used for timing by the 109054359Sroberto * PPSAPI. If neither is present, then ASSERT is assumed. 1091132451Sroberto * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input. 1092132451Sroberto * For Flag2, ASSERT=0, and hence is default. 109354359Sroberto * 1094132451Sroberto * There is an optional line, with HARDPPS on it. Including this line causes 1095132451Sroberto * the PPS signal to control the kernel PLL. 1096132451Sroberto * HARDPPS can also be set with FLAG3 of the ntp.conf input. 1097132451Sroberto * For Flag3, 0 is disabled, and the default. 1098132451Sroberto * 1099132451Sroberto * There are three options that have to do with using the shared memory option. 1100132451Sroberto * First, to enable the option there must be a SHMEM line with a file name. 110182498Sroberto * The file name is the file associated with the shared memory. 110282498Sroberto * 1103132451Sroberto * In shared memory, there is one 'record' for each returned variable. 1104132451Sroberto * For the @@Ea data there are three 'records' containing position data. 1105132451Sroberto * There will always be data in the record corresponding to the '0D' @@Ea record, 1106132451Sroberto * and the user has a choice of filling the '3D' record by specifying POSN3D, 1107132451Sroberto * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D' 1108132451Sroberto * record is filled once every 15s. 110982498Sroberto * 111082498Sroberto * Two additional variables that can be set are CHAN and TRAIM. These should be 111182498Sroberto * set correctly by the code examining the @@Cj record, but we bring them out here 1112132451Sroberto * to allow the user to override either the # of channels, or the existence of TRAIM. 111382498Sroberto * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be 111482498Sroberto * followed by YES or NO. 111582498Sroberto * 1116132451Sroberto * There is an optional line with MASK on it followed by one integer field in the 1117132451Sroberto * range 0 to 89. This sets the satellite mask angle and will determine the minimum 1118132451Sroberto * elevation angle for satellites to be tracked by the receiver. The default value 1119132451Sroberto * is 10 deg for the VP and 0 deg for all other receivers. 1120132451Sroberto * 112154359Sroberto * So acceptable input would be 112254359Sroberto * # these are my coordinates (RWC) 112354359Sroberto * LON -106 34.610 112454359Sroberto * LAT 35 08.999 112554359Sroberto * HT 1589 # could equally well say HT 5215 FT 112654359Sroberto * DELAY 60 ns 112754359Sroberto */ 112854359Sroberto 112954359Sroberto FILE *fd; 1130182007Sroberto char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp; 1131182007Sroberto char *dirs[] = { "/etc/ntp", "/etc", 0 }; 1132132451Sroberto int i, sign, lat_flg, long_flg, ht_flg, mode, mask; 113354359Sroberto double f1, f2, f3; 113454359Sroberto 1135182007Sroberto fd = NULL; /* just to shutup gcc complaint */ 1136182007Sroberto for (cpp=dirs; *cpp; cpp++) { 1137182007Sroberto cp = *cpp; 1138182007Sroberto sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */ 1139182007Sroberto if ((fd=fopen(device, "r"))) 1140182007Sroberto break; 1141182007Sroberto sprintf(device, "%s/ntp.oncore%d", cp, instance->unit); /* try "ntp.oncore0" */ 1142182007Sroberto if ((fd=fopen(device, "r"))) 1143182007Sroberto break; 1144182007Sroberto sprintf(device, "%s/ntp.oncore", cp); /* and finally "ntp.oncore" */ 1145182007Sroberto if ((fd=fopen(device, "r"))) 1146182007Sroberto break; 114782498Sroberto } 114854359Sroberto 1149182007Sroberto if (!fd) { /* no inputfile, default to the works ... */ 1150182007Sroberto instance->init_type = 4; 1151182007Sroberto return; 1152182007Sroberto } 1153182007Sroberto 1154132451Sroberto mode = mask = 0; 115554359Sroberto lat_flg = long_flg = ht_flg = 0; 115654359Sroberto while (fgets(line, 100, fd)) { 115756746Sroberto 115856746Sroberto /* Remove comments */ 115956746Sroberto if ((cp = strchr(line, '#'))) 116054359Sroberto *cp = '\0'; 116182498Sroberto 116256746Sroberto /* Remove trailing space */ 116356746Sroberto for (i = strlen(line); 116456746Sroberto i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]); 116556746Sroberto ) 116656746Sroberto line[--i] = '\0'; 116756746Sroberto 116856746Sroberto /* Remove leading space */ 116956746Sroberto for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++) 117056746Sroberto continue; 117156746Sroberto 117256746Sroberto /* Stop if nothing left */ 117356746Sroberto if (!*cc) 117456746Sroberto continue; 117556746Sroberto 117682498Sroberto /* Uppercase the command and find the arg */ 117756746Sroberto for (ca = cc; *ca; ca++) { 117882498Sroberto if (isascii((int)*ca)) { 117982498Sroberto if (islower((int)*ca)) { 118082498Sroberto *ca = toupper(*ca); 118182498Sroberto } else if (isspace((int)*ca) || (*ca == '=')) 118282498Sroberto break; 118356746Sroberto } 118456746Sroberto } 118582498Sroberto 118682498Sroberto /* Remove space (and possible =) leading the arg */ 118782498Sroberto for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++) 118856746Sroberto continue; 118956746Sroberto 119082498Sroberto if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { 119182498Sroberto i = strlen(ca); 119282498Sroberto instance->shmem_fname = (char *) malloc((unsigned) (i+1)); 119382498Sroberto strcpy(instance->shmem_fname, ca); 119456746Sroberto continue; 119556746Sroberto } 119656746Sroberto 119756746Sroberto /* Uppercase argument as well */ 119856746Sroberto for (cp = ca; *cp; cp++) 119956746Sroberto if (isascii((int)*cp) && islower((int)*cp)) 120056746Sroberto *cp = toupper(*cp); 120156746Sroberto 120282498Sroberto if (!strncmp(cc, "LAT", (size_t) 3)) { 120354359Sroberto f1 = f2 = f3 = 0; 120456746Sroberto sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 120554359Sroberto sign = 1; 120654359Sroberto if (f1 < 0) { 120754359Sroberto f1 = -f1; 120854359Sroberto sign = -1; 120954359Sroberto } 121054359Sroberto instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 121154359Sroberto lat_flg++; 121282498Sroberto } else if (!strncmp(cc, "LON", (size_t) 3)) { 121354359Sroberto f1 = f2 = f3 = 0; 121456746Sroberto sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 121554359Sroberto sign = 1; 121654359Sroberto if (f1 < 0) { 121754359Sroberto f1 = -f1; 121854359Sroberto sign = -1; 121954359Sroberto } 122054359Sroberto instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 122154359Sroberto long_flg++; 122282498Sroberto } else if (!strncmp(cc, "HT", (size_t) 2)) { 122354359Sroberto f1 = 0; 122454359Sroberto units[0] = '\0'; 122556746Sroberto sscanf(ca, "%lf %1s", &f1, units); 122654359Sroberto if (units[0] == 'F') 122754359Sroberto f1 = 0.3048 * f1; 122854359Sroberto instance->ss_ht = 100 * f1; /* cm */ 122954359Sroberto ht_flg++; 123082498Sroberto } else if (!strncmp(cc, "DELAY", (size_t) 5)) { 123154359Sroberto f1 = 0; 123254359Sroberto units[0] = '\0'; 123356746Sroberto sscanf(ca, "%lf %1s", &f1, units); 123454359Sroberto if (units[0] == 'N') 123554359Sroberto ; 123654359Sroberto else if (units[0] == 'U') 123754359Sroberto f1 = 1000 * f1; 123854359Sroberto else if (units[0] == 'M') 123954359Sroberto f1 = 1000000 * f1; 124054359Sroberto else 124154359Sroberto f1 = 1000000000 * f1; 124254359Sroberto if (f1 < 0 || f1 > 1.e9) 124354359Sroberto f1 = 0; 124482498Sroberto if (f1 < 0 || f1 > 999999) { 124582498Sroberto sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1); 124682498Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 124782498Sroberto } else 124882498Sroberto instance->delay = f1; /* delay in ns */ 124982498Sroberto } else if (!strncmp(cc, "OFFSET", (size_t) 6)) { 125054359Sroberto f1 = 0; 125154359Sroberto units[0] = '\0'; 125256746Sroberto sscanf(ca, "%lf %1s", &f1, units); 125354359Sroberto if (units[0] == 'N') 125454359Sroberto ; 125554359Sroberto else if (units[0] == 'U') 125654359Sroberto f1 = 1000 * f1; 125754359Sroberto else if (units[0] == 'M') 125854359Sroberto f1 = 1000000 * f1; 125954359Sroberto else 126054359Sroberto f1 = 1000000000 * f1; 126154359Sroberto if (f1 < 0 || f1 > 1.e9) 126254359Sroberto f1 = 0; 126382498Sroberto if (f1 < 0 || f1 > 999999999.) { 126482498Sroberto sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1); 126582498Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 126682498Sroberto } else 126782498Sroberto instance->offset = f1; /* offset in ns */ 126882498Sroberto } else if (!strncmp(cc, "MODE", (size_t) 4)) { 126956746Sroberto sscanf(ca, "%d", &mode); 127054359Sroberto if (mode < 0 || mode > 4) 127154359Sroberto mode = 4; 127282498Sroberto } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { 127354359Sroberto instance->assert = 1; 127482498Sroberto } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { 127554359Sroberto instance->assert = 0; 1276132451Sroberto } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) { 1277132451Sroberto instance->hardpps = 1; 127882498Sroberto } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { 127982498Sroberto instance->shmem_Posn = 2; 128082498Sroberto } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { 128182498Sroberto instance->shmem_Posn = 3; 128282498Sroberto } else if (!strncmp(cc, "CHAN", (size_t) 4)) { 128382498Sroberto sscanf(ca, "%d", &i); 128482498Sroberto if ((i == 6) || (i == 8) || (i == 12)) 1285132451Sroberto instance->chan_in = i; 128682498Sroberto } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { 1287132451Sroberto instance->traim_in = 1; /* so TRAIM alone is YES */ 128882498Sroberto if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ 1289132451Sroberto instance->traim_in = 0; 1290132451Sroberto } else if (!strncmp(cc, "MASK", (size_t) 4)) { 1291132451Sroberto sscanf(ca, "%d", &mask); 1292132451Sroberto if (mask > -1 && mask < 90) 1293132451Sroberto instance->Ag = mask; /* Satellite mask angle */ 129454359Sroberto } 129554359Sroberto } 129654359Sroberto fclose(fd); 129754359Sroberto 129854359Sroberto /* 129954359Sroberto * OK, have read all of data file, and extracted the good stuff. 130054359Sroberto * If lat/long/ht specified they ALL must be specified for mode = (1,3). 130154359Sroberto */ 130254359Sroberto 130354359Sroberto instance->posn_set = 1; 1304132451Sroberto if (!( lat_flg && long_flg && ht_flg )) { 1305182007Sroberto printf("ONCORE: incomplete data on %s\n", device); 130654359Sroberto instance->posn_set = 0; 130782498Sroberto if (mode == 1 || mode == 3) { 130882498Sroberto sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1); 130982498Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 131082498Sroberto mode++; 131182498Sroberto } 131254359Sroberto } 131382498Sroberto instance->init_type = mode; 131482498Sroberto 131582498Sroberto sprintf(Msg, "Input mode = %d", mode); 131682498Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 131754359Sroberto} 131854359Sroberto 131954359Sroberto 132054359Sroberto 132154359Sroberto/* 1322132451Sroberto * move data from NTP to buffer (toss the extra in the unlikely case it won't fit) 132354359Sroberto */ 132482498Sroberto 132554359Srobertostatic void 132654359Srobertooncore_receive( 132754359Sroberto struct recvbuf *rbufp 132854359Sroberto ) 132954359Sroberto{ 133082498Sroberto size_t i; 133154359Sroberto u_char *p; 133254359Sroberto struct peer *peer; 133354359Sroberto struct instance *instance; 133454359Sroberto 133554359Sroberto peer = (struct peer *)rbufp->recv_srcclock; 133654359Sroberto instance = (struct instance *) peer->procptr->unitptr; 133754359Sroberto p = (u_char *) &rbufp->recv_space; 133854359Sroberto 133954359Sroberto#if 0 134054359Sroberto if (debug > 4) { 134154359Sroberto int i; 134254359Sroberto printf("ONCORE: >>>"); 134354359Sroberto for(i=0; i<rbufp->recv_length; i++) 134454359Sroberto printf("%02x ", p[i]); 134554359Sroberto printf("\n"); 134654359Sroberto printf("ONCORE: >>>"); 134754359Sroberto for(i=0; i<rbufp->recv_length; i++) 134854359Sroberto printf("%03o ", p[i]); 134954359Sroberto printf("\n"); 135054359Sroberto } 135154359Sroberto#endif 135254359Sroberto 135354359Sroberto i = rbufp->recv_length; 135454359Sroberto if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf]) 135554359Sroberto i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ 135654359Sroberto memcpy(rcvbuf+rcvptr, p, i); 135754359Sroberto rcvptr += i; 135854359Sroberto oncore_consume(instance); 135954359Sroberto} 136054359Sroberto 136154359Sroberto 136254359Sroberto 136354359Sroberto/* 136454359Sroberto * Deal with any complete messages 136554359Sroberto */ 136682498Sroberto 136754359Srobertostatic void 136854359Srobertooncore_consume( 136954359Sroberto struct instance *instance 137054359Sroberto ) 137154359Sroberto{ 1372132451Sroberto int i, m; 137356746Sroberto unsigned l; 137454359Sroberto 137554359Sroberto while (rcvptr >= 7) { 137654359Sroberto if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { 137754359Sroberto /* We're not in sync, lets try to get there */ 137854359Sroberto for (i=1; i < rcvptr-1; i++) 137954359Sroberto if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') 138054359Sroberto break; 1381182007Sroberto#ifdef DEBUG 138254359Sroberto if (debug > 4) 138382498Sroberto printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i); 1384182007Sroberto#endif 138554359Sroberto if (i != rcvptr) 138682498Sroberto memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i)); 138754359Sroberto rcvptr -= i; 138882498Sroberto continue; 138954359Sroberto } 139054359Sroberto 139154359Sroberto /* Ok, we have a header now */ 139254359Sroberto l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; 139354359Sroberto for(m=0; m<l; m++) 139482498Sroberto if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2)) 139554359Sroberto break; 139682498Sroberto if (m == l) { 1397182007Sroberto#ifdef DEBUG 139882498Sroberto if (debug > 4) 139982498Sroberto printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]); 1400182007Sroberto#endif 140182498Sroberto memcpy(rcvbuf, rcvbuf+4, (size_t) 4); 140282498Sroberto rcvptr -= 4; 140382498Sroberto continue; 140482498Sroberto } 140582498Sroberto 140654359Sroberto l = oncore_messages[m].len; 140754359Sroberto#if 0 140854359Sroberto if (debug > 3) 140982498Sroberto printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m); 141054359Sroberto#endif 141154359Sroberto /* Got the entire message ? */ 141254359Sroberto 141354359Sroberto if (rcvptr < l) 141454359Sroberto return; 141554359Sroberto 141682498Sroberto /* are we at the end of message? should be <Cksum><CR><LF> */ 141754359Sroberto 141882498Sroberto if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') { 1419182007Sroberto#ifdef DEBUG 142082498Sroberto if (debug) 142182498Sroberto printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit); 1422182007Sroberto#endif 142382498Sroberto } else { /* check the CheckSum */ 1424132451Sroberto if (oncore_checksum_ok(rcvbuf, l)) { 142582498Sroberto if (instance->shmem != NULL) { 142682498Sroberto instance->shmem[oncore_messages[m].shmem + 2]++; 142782498Sroberto memcpy(instance->shmem + oncore_messages[m].shmem + 3, 142882498Sroberto rcvbuf, (size_t) l); 142982498Sroberto } 143082498Sroberto oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m); 143182498Sroberto if (oncore_messages[m].handler) 143282498Sroberto oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3)); 1433182007Sroberto } 1434182007Sroberto#ifdef DEBUG 1435182007Sroberto else if (debug) { 1436132451Sroberto printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit); 143782498Sroberto printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]); 143882498Sroberto for (i=4; i<l; i++) 143982498Sroberto printf("%03o ", rcvbuf[i]); 144082498Sroberto printf("\n"); 144182498Sroberto } 1442182007Sroberto#endif 144354359Sroberto } 144454359Sroberto 144554359Sroberto if (l != rcvptr) 144682498Sroberto memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); 144754359Sroberto rcvptr -= l; 144854359Sroberto } 144954359Sroberto} 145054359Sroberto 145154359Sroberto 145254359Sroberto 145354359Srobertostatic void 1454132451Srobertooncore_get_timestamp( 1455132451Sroberto struct instance *instance, 1456132451Sroberto long dt1, /* tick offset THIS time step */ 1457132451Sroberto long dt2 /* tick offset NEXT time step */ 145854359Sroberto ) 145954359Sroberto{ 1460132451Sroberto int Rsm; 1461182007Sroberto u_long j; 1462132451Sroberto l_fp ts, ts_tmp; 1463132451Sroberto double dmy; 1464132451Sroberto#ifdef HAVE_STRUCT_TIMESPEC 1465132451Sroberto struct timespec *tsp = 0; 1466132451Sroberto#else 1467132451Sroberto struct timeval *tsp = 0; 1468132451Sroberto#endif 1469132451Sroberto int current_mode; 1470182007Sroberto u_long i; 1471132451Sroberto pps_params_t current_params; 1472132451Sroberto struct timespec timeout; 1473132451Sroberto pps_info_t pps_i; 147454359Sroberto 1475132451Sroberto#if 1 1476132451Sroberto /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru. 1477132451Sroberto * If we have Finished the SiteSurvey, then we fall thru for the 14/15 1478132451Sroberto * times we get here in 0D mode (the 1/15 is in 3D for SHMEM). 1479132451Sroberto * This gives good time, which gets better when the SS is done. 1480132451Sroberto */ 1481132451Sroberto 1482132451Sroberto if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) 1483132451Sroberto#else 1484132451Sroberto /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */ 1485132451Sroberto 1486132451Sroberto if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) 1487132451Sroberto#endif 1488132451Sroberto return; 1489132451Sroberto 1490132451Sroberto /* Don't do anything without an almanac to define the GPS->UTC delta */ 1491132451Sroberto 1492132451Sroberto if (instance->rsm.bad_almanac) 1493132451Sroberto return; 1494132451Sroberto 1495182007Sroberto /* Once the Almanac is valid, the M12+T does not produce valid UTC 1496182007Sroberto * immediately. 1497182007Sroberto * Wait for UTC offset decode valid, then wait one message more 1498182007Sroberto * so we are not off by 13 seconds after reset. 1499182007Sroberto */ 1500182007Sroberto 1501182007Sroberto if (instance->count5) { 1502182007Sroberto instance->count5--; 1503182007Sroberto return; 1504182007Sroberto } 1505182007Sroberto 1506132451Sroberto j = instance->ev_serial; 1507132451Sroberto timeout.tv_sec = 0; 1508132451Sroberto timeout.tv_nsec = 0; 1509132451Sroberto if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, 1510132451Sroberto &timeout) < 0) { 1511132451Sroberto printf("ONCORE: time_pps_fetch failed\n"); 1512132451Sroberto return; 1513132451Sroberto } 1514132451Sroberto 1515132451Sroberto if (instance->assert) { 1516132451Sroberto tsp = &pps_i.assert_timestamp; 1517132451Sroberto 1518182007Sroberto#ifdef DEBUG 1519132451Sroberto if (debug > 2) { 1520132451Sroberto i = (u_long) pps_i.assert_sequence; 1521182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC 1522132451Sroberto printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", 1523132451Sroberto instance->unit, i, j, 1524132451Sroberto (long)tsp->tv_sec, (long)tsp->tv_nsec); 1525182007Sroberto# else 1526132451Sroberto printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", 1527132451Sroberto instance->unit, i, j, 1528132451Sroberto (long)tsp->tv_sec, (long)tsp->tv_usec); 1529182007Sroberto# endif 1530182007Sroberto } 1531132451Sroberto#endif 1532132451Sroberto 1533132451Sroberto if (pps_i.assert_sequence == j) { 1534132451Sroberto printf("ONCORE: oncore_get_timestamp, error serial pps\n"); 1535132451Sroberto return; 1536132451Sroberto } 1537132451Sroberto instance->ev_serial = pps_i.assert_sequence; 1538132451Sroberto } else { 1539132451Sroberto tsp = &pps_i.clear_timestamp; 1540132451Sroberto 1541182007Sroberto#ifdef DEBUG 1542132451Sroberto if (debug > 2) { 1543132451Sroberto i = (u_long) pps_i.clear_sequence; 1544182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC 1545132451Sroberto printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", 1546132451Sroberto instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec); 1547182007Sroberto# else 1548132451Sroberto printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", 1549132451Sroberto instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec); 1550182007Sroberto# endif 1551182007Sroberto } 1552132451Sroberto#endif 1553132451Sroberto 1554132451Sroberto if (pps_i.clear_sequence == j) { 1555132451Sroberto printf("ONCORE: oncore_get_timestamp, error serial pps\n"); 1556132451Sroberto return; 1557132451Sroberto } 1558132451Sroberto instance->ev_serial = pps_i.clear_sequence; 1559132451Sroberto } 1560132451Sroberto 1561132451Sroberto /* convert timespec -> ntp l_fp */ 1562132451Sroberto 1563132451Sroberto dmy = tsp->tv_nsec; 1564132451Sroberto dmy /= 1e9; 1565182007Sroberto ts.l_uf = dmy * 4294967296.0; 1566132451Sroberto ts.l_ui = tsp->tv_sec; 1567182007Sroberto 1568132451Sroberto#if 0 1569132451Sroberto alternate code for previous 4 lines is 1570132451Sroberto dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1571132451Sroberto DTOLFP(dmy, &ts); 1572132451Sroberto dmy = tsp->tv_sec; /* integer part */ 1573132451Sroberto DTOLFP(dmy, &ts_tmp); 1574132451Sroberto L_ADD(&ts, &ts_tmp); 1575132451Sroberto or more simply 1576132451Sroberto dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1577132451Sroberto DTOLFP(dmy, &ts); 1578132451Sroberto ts.l_ui = tsp->tv_sec; 1579132451Sroberto#endif /* 0 */ 1580132451Sroberto 1581132451Sroberto /* now have timestamp in ts */ 1582132451Sroberto /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ 1583182007Sroberto /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */ 1584182007Sroberto /* we just try to add them in and dont test for that here */ 1585132451Sroberto 1586132451Sroberto /* saw_tooth not really necessary if using TIMEVAL */ 1587132451Sroberto /* since its only precise to us, but do it anyway. */ 1588132451Sroberto 1589132451Sroberto /* offset in ns, and is positive (late), we subtract */ 1590132451Sroberto /* to put the PPS time transition back where it belongs */ 1591132451Sroberto 1592132451Sroberto /* must hand the offset for the NEXT sec off to the Kernel to do */ 1593132451Sroberto /* the addition, so that the Kernel PLL sees the offset too */ 1594132451Sroberto 1595132451Sroberto if (instance->assert) 1596132451Sroberto instance->pps_p.assert_offset.tv_nsec = -dt2; 1597132451Sroberto else 1598132451Sroberto instance->pps_p.clear_offset.tv_nsec = -dt2; 1599132451Sroberto 1600132451Sroberto /* The following code is necessary, and not just a time_pps_setparams, 1601132451Sroberto * using the saved instance->pps_p, since some other process on the 1602132451Sroberto * machine may have diddled with the mode bits (say adding something 1603132451Sroberto * that it needs). We take what is there and ADD what we need. 1604132451Sroberto * [[ The results from the time_pps_getcap is unlikely to change so 1605132451Sroberto * we could probably just save it, but I choose to do the call ]] 1606132451Sroberto * Unfortunately, there is only ONE set of mode bits in the kernel per 1607132451Sroberto * interface, and not one set for each open handle. 1608132451Sroberto * 1609132451Sroberto * There is still a race condition here where we might mess up someone 1610132451Sroberto * elses mode, but if he is being careful too, he should survive. 1611132451Sroberto */ 1612132451Sroberto 1613132451Sroberto if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { 1614182007Sroberto msyslog(LOG_ERR, "time_pps_getcap failed: %m"); 1615132451Sroberto return; 1616132451Sroberto } 1617132451Sroberto 1618132451Sroberto if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { 1619182007Sroberto msyslog(LOG_ERR, "time_pps_getparams failed: %m"); 1620132451Sroberto return; 1621132451Sroberto } 1622132451Sroberto 1623132451Sroberto /* or current and mine */ 1624132451Sroberto current_params.mode |= instance->pps_p.mode; 1625132451Sroberto /* but only set whats legal */ 1626132451Sroberto current_params.mode &= current_mode; 1627132451Sroberto 1628132451Sroberto current_params.assert_offset.tv_sec = 0; 1629132451Sroberto current_params.assert_offset.tv_nsec = -dt2; 1630132451Sroberto current_params.clear_offset.tv_sec = 0; 1631132451Sroberto current_params.clear_offset.tv_nsec = -dt2; 1632132451Sroberto 1633132451Sroberto if (time_pps_setparams(instance->pps_h, ¤t_params)) 1634182007Sroberto record_clock_stats(&(instance->peer->srcadr), "ONCORE: Error doing time_pps_setparams"); 1635132451Sroberto 1636132451Sroberto /* have time from UNIX origin, convert to NTP origin. */ 1637132451Sroberto 1638132451Sroberto ts.l_ui += JAN_1970; 1639132451Sroberto instance->pp->lastrec = ts; 1640132451Sroberto 1641132451Sroberto /* print out information about this timestamp (long line) */ 1642132451Sroberto 1643132451Sroberto ts_tmp = ts; 1644132451Sroberto ts_tmp.l_ui = 0; /* zero integer part */ 1645132451Sroberto LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ 1646132451Sroberto j = 1.0e9*dmy; /* then to integer ns */ 1647132451Sroberto 1648132451Sroberto Rsm = 0; 1649132451Sroberto if (instance->chan == 6) 1650132451Sroberto Rsm = instance->BEHa[64]; 1651132451Sroberto else if (instance->chan == 8) 1652132451Sroberto Rsm = instance->BEHa[72]; 1653132451Sroberto else if (instance->chan == 12) 1654132451Sroberto Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]); 1655132451Sroberto 1656132451Sroberto if (instance->chan == 6 || instance->chan == 8) { 1657182007Sroberto char f1[5], f2[5], f3[5], f4[5]; 1658182007Sroberto if (instance->traim) { 1659182007Sroberto sprintf(f1, "%d", instance->BEHn[21]); 1660182007Sroberto sprintf(f2, "%d", instance->BEHn[22]); 1661182007Sroberto sprintf(f3, "%2d", instance->BEHn[23]*256+instance->BEHn[24]); 1662182007Sroberto sprintf(f4, "%3d", (s_char) instance->BEHn[25]); 1663182007Sroberto } else { 1664182007Sroberto strcpy(f1, "x"); 1665182007Sroberto strcpy(f2, "x"); 1666182007Sroberto strcpy(f3, "xx"); 1667182007Sroberto strcpy(f4, "xxx"); 1668182007Sroberto } 1669182007Sroberto sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 121 */ 1670182007Sroberto "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d", 1671132451Sroberto ts.l_ui, j, 1672132451Sroberto instance->pp->year, instance->pp->day, 1673132451Sroberto instance->pp->hour, instance->pp->minute, instance->pp->second, 1674132451Sroberto (long) tsp->tv_sec % 60, 1675132451Sroberto Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]), 1676132451Sroberto /*rsat dop */ 1677182007Sroberto instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2, 1678182007Sroberto /* nsat visible, nsat tracked, traim,traim,traim */ 1679182007Sroberto f3, f4, 1680182007Sroberto /* sigma neg-sawtooth */ 1681132451Sroberto /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53], 1682132451Sroberto instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69] 1683132451Sroberto ); /* will be 0 for 6 chan */ 1684132451Sroberto } else if (instance->chan == 12) { 1685182007Sroberto char f1[5], f2[5], f3[5], f4[5]; 1686182007Sroberto if (instance->traim) { 1687182007Sroberto sprintf(f1, "%d", instance->BEHn[6]); 1688182007Sroberto sprintf(f2, "%d", instance->BEHn[7]); 1689182007Sroberto sprintf(f3, "%d", instance->BEHn[12]*256+instance->BEHn[13]); 1690182007Sroberto sprintf(f4, "%3d", (s_char) instance->BEHn[14]); 1691182007Sroberto } else { 1692182007Sroberto strcpy(f1, "x"); 1693182007Sroberto strcpy(f2, "x"); 1694182007Sroberto strcpy(f3, "x"); 1695182007Sroberto strcpy(f4, "xxx"); 1696182007Sroberto } 1697132451Sroberto sprintf(instance->pp->a_lastcode, 1698182007Sroberto "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d%d%d%d%d", 1699132451Sroberto ts.l_ui, j, 1700132451Sroberto instance->pp->year, instance->pp->day, 1701132451Sroberto instance->pp->hour, instance->pp->minute, instance->pp->second, 1702132451Sroberto (long) tsp->tv_sec % 60, 1703132451Sroberto Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]), 1704132451Sroberto /*rsat dop */ 1705182007Sroberto instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2, 1706182007Sroberto /* nsat visible, nsat tracked traim,traim,traim */ 1707182007Sroberto f3, f4, 1708182007Sroberto /* sigma neg-sawtooth */ 1709132451Sroberto /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76], 1710132451Sroberto instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100], 1711132451Sroberto instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124] 1712132451Sroberto ); 1713132451Sroberto } 1714132451Sroberto 1715182007Sroberto#ifdef DEBUG 1716132451Sroberto if (debug > 2) { 1717132451Sroberto int n; 1718182007Sroberto 1719132451Sroberto n = strlen(instance->pp->a_lastcode); 1720132451Sroberto printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode); 1721132451Sroberto } 1722182007Sroberto#endif 1723132451Sroberto 1724182007Sroberto /* and some things I dont understand (magic ntp things) */ 1725132451Sroberto 1726132451Sroberto if (!refclock_process(instance->pp)) { 1727132451Sroberto refclock_report(instance->peer, CEVNT_BADTIME); 1728132451Sroberto return; 1729132451Sroberto } 1730132451Sroberto 1731132451Sroberto record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode); 1732132451Sroberto instance->pollcnt = 2; 1733132451Sroberto 1734132451Sroberto if (instance->polled) { 1735132451Sroberto instance->polled = 0; 1736182007Sroberto /* instance->pp->dispersion = instance->pp->skew = 0; */ 1737132451Sroberto instance->pp->lastref = instance->pp->lastrec; 1738132451Sroberto refclock_receive(instance->peer); 1739132451Sroberto } 174054359Sroberto} 174154359Sroberto 174254359Sroberto 1743132451Sroberto/*************** oncore_msg_XX routines start here *******************/ 174454359Sroberto 1745132451Sroberto 174682498Sroberto/* 174782498Sroberto * print Oncore response message. 174882498Sroberto */ 174982498Sroberto 175054359Srobertostatic void 175154359Srobertooncore_msg_any( 175254359Sroberto struct instance *instance, 175354359Sroberto u_char *buf, 175482498Sroberto size_t len, 175554359Sroberto int idx 175654359Sroberto ) 175754359Sroberto{ 175854359Sroberto int i; 175954359Sroberto const char *fmt = oncore_messages[idx].fmt; 176054359Sroberto const char *p; 176182498Sroberto#ifdef HAVE_GETCLOCK 176282498Sroberto struct timespec ts; 176382498Sroberto#endif 176454359Sroberto struct timeval tv; 176554359Sroberto 1766182007Sroberto#ifdef DEBUG 176754359Sroberto if (debug > 3) { 1768182007Sroberto# ifdef HAVE_GETCLOCK 1769132451Sroberto (void) getclock(TIMEOFDAY, &ts); 1770132451Sroberto tv.tv_sec = ts.tv_sec; 1771132451Sroberto tv.tv_usec = ts.tv_nsec / 1000; 1772182007Sroberto# else 177354359Sroberto GETTIMEOFDAY(&tv, 0); 1774182007Sroberto# endif 177582498Sroberto printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec); 177654359Sroberto 177754359Sroberto if (!*fmt) { 177854359Sroberto printf(">>@@%c%c ", buf[2], buf[3]); 177954359Sroberto for(i=2; i < len && i < 2400 ; i++) 178054359Sroberto printf("%02x", buf[i]); 178154359Sroberto printf("\n"); 178254359Sroberto return; 178354359Sroberto } else { 178454359Sroberto printf("##"); 178554359Sroberto for (p = fmt; *p; p++) { 178654359Sroberto putchar(*p); 178754359Sroberto putchar('_'); 178854359Sroberto } 178954359Sroberto printf("\n%c%c", buf[2], buf[3]); 179054359Sroberto i = 4; 179154359Sroberto for (p = fmt; *p; p++) { 179254359Sroberto printf("%02x", buf[i++]); 179354359Sroberto } 179454359Sroberto printf("\n"); 179554359Sroberto } 179654359Sroberto } 1797182007Sroberto#endif 179854359Sroberto} 179954359Sroberto 180054359Sroberto 180154359Sroberto 1802132451Sroberto/* Latitude, Longitude, Height */ 180382498Sroberto 180456746Srobertostatic void 1805132451Srobertooncore_msg_Adef( 180656746Sroberto struct instance *instance, 180756746Sroberto u_char *buf, 180882498Sroberto size_t len 180956746Sroberto ) 181056746Sroberto{ 1811132451Sroberto} 181256746Sroberto 181356746Sroberto 181456746Sroberto 1815132451Sroberto/* Mask Angle */ 181682498Sroberto 1817132451Srobertostatic void 1818132451Srobertooncore_msg_Ag( 1819132451Sroberto struct instance *instance, 1820132451Sroberto u_char *buf, 1821132451Sroberto size_t len 1822132451Sroberto ) 1823132451Sroberto{ char Msg[160], *cp; 182482498Sroberto 1825132451Sroberto cp = "set to"; 1826132451Sroberto if (instance->o_state == ONCORE_RUN) 1827132451Sroberto cp = "is"; 182854359Sroberto 1829132451Sroberto instance->Ag = buf[4]; 1830132451Sroberto sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag); 1831132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 1832132451Sroberto} 183354359Sroberto 1834132451Sroberto 1835132451Sroberto 183682498Sroberto/* 1837132451Sroberto * get Position hold position 183856746Sroberto */ 183956746Sroberto 184054359Srobertostatic void 1841132451Srobertooncore_msg_As( 184254359Sroberto struct instance *instance, 184354359Sroberto u_char *buf, 184482498Sroberto size_t len 184554359Sroberto ) 184654359Sroberto{ 1847132451Sroberto instance->ss_lat = buf_w32(&buf[4]); 1848132451Sroberto instance->ss_long = buf_w32(&buf[8]); 1849132451Sroberto instance->ss_ht = buf_w32(&buf[12]); 185054359Sroberto 1851132451Sroberto /* Print out Position */ 1852132451Sroberto oncore_print_posn(instance); 185354359Sroberto} 185454359Sroberto 185554359Sroberto 185654359Sroberto 1857132451Sroberto/* 1858132451Sroberto * Try to use Oncore UT+ Auto Survey Feature 1859132451Sroberto * If its not there (VP), set flag to do it ourselves. 186054359Sroberto */ 186182498Sroberto 186254359Srobertostatic void 1863132451Srobertooncore_msg_At( 186454359Sroberto struct instance *instance, 186554359Sroberto u_char *buf, 186682498Sroberto size_t len 186754359Sroberto ) 186854359Sroberto{ 1869132451Sroberto char *cp; 187054359Sroberto 1871132451Sroberto instance->saw_At = 1; 1872132451Sroberto if (instance->site_survey == ONCORE_SS_TESTING) { 1873132451Sroberto if (buf[4] == 2) { 1874132451Sroberto record_clock_stats(&(instance->peer->srcadr), 1875132451Sroberto "Initiating hardware 3D site survey"); 187654359Sroberto 1877132451Sroberto cp = "SSstate = ONCORE_SS_HW"; 1878132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 1879132451Sroberto instance->site_survey = ONCORE_SS_HW; 1880132451Sroberto } 188156746Sroberto } 1882132451Sroberto} 188382498Sroberto 188482498Sroberto 188582498Sroberto 1886132451Sroberto/* 1887132451Sroberto * get PPS Offset 1888132451Sroberto * Nb. @@Ay is not supported for early UT (no plus) model 1889132451Sroberto */ 189082498Sroberto 1891132451Srobertostatic void 1892132451Srobertooncore_msg_Ay( 1893132451Sroberto struct instance *instance, 1894132451Sroberto u_char *buf, 1895132451Sroberto size_t len 1896132451Sroberto ) 1897132451Sroberto{ 1898132451Sroberto char Msg[120]; 189982498Sroberto 1900132451Sroberto if (instance->saw_Ay) 1901132451Sroberto return; 190282498Sroberto 1903132451Sroberto instance->saw_Ay = 1; 190482498Sroberto 1905132451Sroberto instance->offset = buf_w32(&buf[4]); 190682498Sroberto 1907132451Sroberto sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset); 190882498Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 1909132451Sroberto} 191082498Sroberto 191182498Sroberto 191282498Sroberto 1913132451Sroberto/* 1914132451Sroberto * get Cable Delay 1915132451Sroberto */ 191682498Sroberto 1917132451Srobertostatic void 1918132451Srobertooncore_msg_Az( 1919132451Sroberto struct instance *instance, 1920132451Sroberto u_char *buf, 1921132451Sroberto size_t len 1922132451Sroberto ) 1923132451Sroberto{ 1924132451Sroberto char Msg[120]; 192582498Sroberto 1926132451Sroberto if (instance->saw_Az) 1927132451Sroberto return; 192882498Sroberto 1929132451Sroberto instance->saw_Az = 1; 193056746Sroberto 1931132451Sroberto instance->delay = buf_w32(&buf[4]); 193254359Sroberto 1933132451Sroberto sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); 1934132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 193582498Sroberto} 193682498Sroberto 193782498Sroberto 193882498Sroberto 1939132451Sroberto/* Ba, Ea and Ha come here, these contain Position */ 1940132451Sroberto 194182498Srobertostatic void 1942132451Srobertooncore_msg_BaEaHa( 194382498Sroberto struct instance *instance, 194482498Sroberto u_char *buf, 194582498Sroberto size_t len 194682498Sroberto ) 194782498Sroberto{ 1948132451Sroberto const char *cp; 1949132451Sroberto char Msg[160]; 1950132451Sroberto int mode; 195182498Sroberto 1952132451Sroberto /* OK, we are close to the RUN state now. 1953132451Sroberto * But we have a few more items to initialize first. 1954132451Sroberto * 1955132451Sroberto * At the beginning of this routine there are several 'timers'. 1956132451Sroberto * We enter this routine 1/sec, and since the upper levels of NTP have usurped 1957132451Sroberto * the use of timers, we use the 1/sec entry to do things that 1958132451Sroberto * we would normally do with timers... 195982498Sroberto */ 196082498Sroberto 1961132451Sroberto if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */ 1962132451Sroberto if (buf[2] == 'B') { /* 6chan */ 1963132451Sroberto if (instance->chan_ck < 6) instance->chan_ck = 6; 1964132451Sroberto } else if (buf[2] == 'E') { /* 8chan */ 1965132451Sroberto if (instance->chan_ck < 8) instance->chan_ck = 8; 1966132451Sroberto } else if (buf[2] == 'H') { /* 12chan */ 1967132451Sroberto if (instance->chan_ck < 12) instance->chan_ck = 12; 1968132451Sroberto } 196982498Sroberto 1970132451Sroberto if (instance->count3++ < 5) 1971132451Sroberto return; 197282498Sroberto 1973132451Sroberto instance->count3 = 0; 1974132451Sroberto 1975132451Sroberto if (instance->chan_in != -1) /* set in Input */ 1976132451Sroberto instance->chan = instance->chan_in; 1977132451Sroberto else /* set from test */ 1978132451Sroberto instance->chan = instance->chan_ck; 1979132451Sroberto 1980132451Sroberto sprintf(Msg, "Input says chan = %d", instance->chan_in); 1981132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 1982132451Sroberto sprintf(Msg, "Model # says chan = %d", instance->chan_id); 1983132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 1984132451Sroberto sprintf(Msg, "Testing says chan = %d", instance->chan_ck); 1985132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 1986132451Sroberto sprintf(Msg, "Using chan = %d", instance->chan); 1987132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 1988132451Sroberto 1989132451Sroberto instance->o_state = ONCORE_HAVE_CHAN; 1990132451Sroberto cp = "state = ONCORE_HAVE_CHAN"; 1991132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 1992132451Sroberto 1993132451Sroberto instance->timeout = 4; 1994132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 1995132451Sroberto return; 199682498Sroberto } 199782498Sroberto 1998132451Sroberto if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) 1999132451Sroberto return; 2000132451Sroberto 2001182007Sroberto /* PAUSE 5sec - make sure results are stable, before using position */ 2002132451Sroberto 2003132451Sroberto if (instance->count) { 2004182007Sroberto if (instance->count++ < 5) 2005132451Sroberto return; 2006132451Sroberto instance->count = 0; 200782498Sroberto } 200854359Sroberto 2009132451Sroberto memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */ 201054359Sroberto 2011182007Sroberto /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */ 201282498Sroberto 2013132451Sroberto oncore_check_almanac(instance); 2014132451Sroberto oncore_check_antenna(instance); 2015132451Sroberto 2016182007Sroberto /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */ 2017132451Sroberto /* When we have an almanac, we will start the Bn/En/@@Hn messages */ 2018132451Sroberto 2019132451Sroberto if (instance->o_state == ONCORE_ALMANAC) 2020132451Sroberto if (oncore_wait_almanac(instance)) 2021132451Sroberto return; 2022132451Sroberto 2023132451Sroberto /* do some things once when we get this far in BaEaHa */ 2024132451Sroberto 2025132451Sroberto if (instance->once) { 2026132451Sroberto instance->once = 0; 2027132451Sroberto instance->count2 = 1; 2028132451Sroberto 2029132451Sroberto /* Have we seen an @@At (position hold) command response */ 2030132451Sroberto /* if not, message out */ 2031132451Sroberto 2032132451Sroberto if (instance->chan != 12 && !instance->saw_At) { 2033132451Sroberto cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+"; 2034132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2035132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 2036132451Sroberto } 2037132451Sroberto 2038132451Sroberto /* have an Almanac, can start the SiteSurvey 2039132451Sroberto * (actually only need to get past the almanac_load where we diddle with At 2040132451Sroberto * command,- we can't change it after we start the HW_SS below 2041132451Sroberto */ 2042132451Sroberto 2043132451Sroberto mode = instance->init_type; 2044132451Sroberto switch (mode) { 2045132451Sroberto case 0: /* NO initialization, don't change anything */ 2046132451Sroberto case 1: /* Use given Position */ 2047132451Sroberto case 3: 2048132451Sroberto instance->site_survey = ONCORE_SS_DONE; 2049132451Sroberto cp = "SSstate = ONCORE_SS_DONE"; 2050132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 205182498Sroberto break; 2052132451Sroberto 205382498Sroberto case 2: 2054132451Sroberto case 4: /* Site Survey */ 2055132451Sroberto cp = "SSstate = ONCORE_SS_TESTING"; 2056132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2057132451Sroberto instance->site_survey = ONCORE_SS_TESTING; 2058132451Sroberto instance->count1 = 1; 2059132451Sroberto if (instance->chan == 12) 2060132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */ 2061132451Sroberto else 2062132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */ 2063132451Sroberto break; 2064132451Sroberto } 206582498Sroberto 2066132451Sroberto /* Read back PPS Offset for Output */ 2067132451Sroberto /* Nb. This will fail silently for early UT (no plus) and M12 models */ 206882498Sroberto 2069132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); 207082498Sroberto 2071132451Sroberto /* Read back Cable Delay for Output */ 207282498Sroberto 2073132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); 2074132451Sroberto 2075132451Sroberto /* Read back Satellite Mask Angle for Output */ 2076132451Sroberto 2077132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx, sizeof(oncore_cmd_Agx)); 2078132451Sroberto } 2079132451Sroberto 2080132451Sroberto 2081182007Sroberto /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is 2082182007Sroberto * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey) 2083182007Sroberto * We must do the Gd3, and then wait a cycle or two for things to settle, 2084182007Sroberto * then check Ha[130]&0x10 to see if a SS is in progress. 2085182007Sroberto * We will set SW if HW has not been set after an appropriate delay. 2086182007Sroberto */ 2087132451Sroberto 2088182007Sroberto if (instance->site_survey == ONCORE_SS_TESTING) { 2089182007Sroberto if (instance->chan == 12) { 2090182007Sroberto if (instance->count1) { 2091182007Sroberto if (instance->count1++ > 5 || instance->BEHa[130]&0x10) { 2092182007Sroberto instance->count1 = 0; 2093182007Sroberto if (instance->BEHa[130]&0x10) { 2094182007Sroberto record_clock_stats(&(instance->peer->srcadr), 2095182007Sroberto "Initiating hardware 3D site survey"); 2096132451Sroberto 2097182007Sroberto record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_HW"); 2098182007Sroberto instance->site_survey = ONCORE_SS_HW; 2099182007Sroberto } else { 2100182007Sroberto record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW"); 2101182007Sroberto instance->site_survey = ONCORE_SS_SW; 2102182007Sroberto } 2103132451Sroberto } 210482498Sroberto } 2105182007Sroberto } else { 2106182007Sroberto if (instance->count1) { 2107182007Sroberto if (instance->count1++ > 5) { 2108182007Sroberto instance->count1 = 0; 2109182007Sroberto /* 2110182007Sroberto * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec 2111182007Sroberto * wait after the @@At2/@@Gd3 command we have not changed the state to 2112182007Sroberto * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then 2113182007Sroberto * the variable would have been changed by now. 2114182007Sroberto * There are three possibilities: 2115182007Sroberto * 6/8chan 2116182007Sroberto * (a) We did not get a response to the @@At0 or @@At2 commands, 2117182007Sroberto * and it must be a GT/GT+/SL with no position hold mode. 2118182007Sroberto * We will have to do it ourselves. 2119182007Sroberto * (b) We saw the @@At0, @@At2 commands, but @@At2 failed, 2120182007Sroberto * must be a VP or older UT which doesn't have Site Survey mode. 2121182007Sroberto * We will have to do it ourselves. 2122182007Sroberto * 12chan 2123182007Sroberto * (c) We saw the @@Gd command, and saw H[13]*0x10 2124182007Sroberto * We will have to do it ourselves (done above) 2125182007Sroberto */ 2126182007Sroberto 2127182007Sroberto sprintf(Msg, "Initiating software 3D site survey (%d samples)", 2128182007Sroberto POS_HOLD_AVERAGE); 2129182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 2130182007Sroberto 2131182007Sroberto record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW"); 2132182007Sroberto instance->site_survey = ONCORE_SS_SW; 2133182007Sroberto 2134182007Sroberto instance->ss_lat = instance->ss_long = instance->ss_ht = 0; 2135182007Sroberto if (instance->chan == 12) 2136182007Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */ 2137182007Sroberto else { 2138182007Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ 2139182007Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */ 2140182007Sroberto } 2141182007Sroberto } 2142182007Sroberto } 214382498Sroberto } 214482498Sroberto } 214582498Sroberto 2146132451Sroberto /* check the mode we are in 0/2/3D */ 214782498Sroberto 2148132451Sroberto if (instance->chan == 6) { 2149132451Sroberto if (instance->BEHa[64]&0x8) 2150132451Sroberto instance->mode = MODE_0D; 2151132451Sroberto else if (instance->BEHa[64]&0x10) 2152132451Sroberto instance->mode = MODE_2D; 2153132451Sroberto else if (instance->BEHa[64]&0x20) 2154132451Sroberto instance->mode = MODE_3D; 2155132451Sroberto } else if (instance->chan == 8) { 2156132451Sroberto if (instance->BEHa[72]&0x8) 2157132451Sroberto instance->mode = MODE_0D; 2158132451Sroberto else if (instance->BEHa[72]&0x10) 2159132451Sroberto instance->mode = MODE_2D; 2160132451Sroberto else if (instance->BEHa[72]&0x20) 2161132451Sroberto instance->mode = MODE_3D; 2162132451Sroberto } else if (instance->chan == 12) { 2163132451Sroberto int bits; 216454359Sroberto 2165132451Sroberto bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 2166132451Sroberto if (bits == 0x4) 2167132451Sroberto instance->mode = MODE_0D; 2168132451Sroberto else if (bits == 0x6) 2169132451Sroberto instance->mode = MODE_2D; 2170132451Sroberto else if (bits == 0x7) 2171132451Sroberto instance->mode = MODE_3D; 2172132451Sroberto } 217354359Sroberto 2174132451Sroberto /* copy the record to the (extra) location in SHMEM */ 2175132451Sroberto 2176132451Sroberto if (instance->shmem) { 2177132451Sroberto int i; 2178132451Sroberto u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */ 2179132451Sroberto 2180132451Sroberto switch(instance->chan) { 2181132451Sroberto case 6: smp = &instance->shmem[instance->shmem_Ba]; break; 2182132451Sroberto case 8: smp = &instance->shmem[instance->shmem_Ea]; break; 2183132451Sroberto case 12: smp = &instance->shmem[instance->shmem_Ha]; break; 2184182007Sroberto default: smp = (u_char *) NULL; break; 218554359Sroberto } 2186132451Sroberto 2187132451Sroberto switch (instance->mode) { 2188132451Sroberto case MODE_0D: i = 1; break; /* 0D, Position Hold */ 2189132451Sroberto case MODE_2D: i = 2; break; /* 2D, Altitude Hold */ 2190132451Sroberto case MODE_3D: i = 3; break; /* 3D fix */ 2191132451Sroberto default: i = 0; break; 2192132451Sroberto } 2193132451Sroberto 2194182007Sroberto if (i && smp != NULL) { 2195132451Sroberto i *= (len+6); 2196132451Sroberto smp[i + 2]++; 2197132451Sroberto memcpy(&smp[i+3], buf, (size_t) (len+3)); 2198132451Sroberto } 219954359Sroberto } 220054359Sroberto 2201132451Sroberto /* 2202182007Sroberto * check if traim timer active 2203132451Sroberto * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond 2204132451Sroberto */ 220554359Sroberto 2206132451Sroberto if (instance->traim_delay) { 2207132451Sroberto if (instance->traim_delay++ > 5) { 2208132451Sroberto instance->traim = 0; 2209132451Sroberto instance->traim_delay = 0; 2210132451Sroberto cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; 2211132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2212132451Sroberto 2213132451Sroberto oncore_set_traim(instance); 2214132451Sroberto } else 2215132451Sroberto return; 2216132451Sroberto 2217132451Sroberto } 2218132451Sroberto 2219132451Sroberto /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */ 2220132451Sroberto 2221132451Sroberto if (!instance->have_dH && !instance->traim_delay) 2222132451Sroberto oncore_compute_dH(instance); 2223132451Sroberto 2224132451Sroberto /* 2225132451Sroberto * must be ONCORE_RUN if we are here. 2226132451Sroberto * Have # chan and TRAIM by now. 2227132451Sroberto */ 2228132451Sroberto 2229132451Sroberto instance->pp->year = buf[6]*256+buf[7]; 2230132451Sroberto instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); 2231132451Sroberto instance->pp->hour = buf[8]; 2232132451Sroberto instance->pp->minute = buf[9]; 2233132451Sroberto instance->pp->second = buf[10]; 2234132451Sroberto 2235132451Sroberto /* 2236132451Sroberto * Are we doing a Hardware or Software Site Survey? 2237132451Sroberto */ 2238132451Sroberto 2239132451Sroberto if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW) 2240132451Sroberto oncore_ss(instance); 2241132451Sroberto 2242132451Sroberto /* see if we ever saw a response from the @@Ayx above */ 2243132451Sroberto 2244132451Sroberto if (instance->count2) { 2245132451Sroberto if (instance->count2++ > 5) { /* this delay to check on @@Ay command */ 2246132451Sroberto instance->count2 = 0; 2247132451Sroberto 2248132451Sroberto /* Have we seen an Ay (1PPS time offset) command response */ 2249132451Sroberto /* if not, and non-zero offset, zero the offset, and send message */ 2250132451Sroberto 2251132451Sroberto if (!instance->saw_Ay && instance->offset) { 2252132451Sroberto cp = "No @@Ay command, PPS OFFSET ignored"; 225382498Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 225482498Sroberto instance->offset = 0; 225582498Sroberto } 225682498Sroberto } 225754359Sroberto } 225854359Sroberto 2259132451Sroberto /* 2260132451Sroberto * Check the leap second status once per day. 2261132451Sroberto */ 226254359Sroberto 2263132451Sroberto oncore_check_leap_sec(instance); 226454359Sroberto 2265132451Sroberto /* 2266132451Sroberto * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 2267132451Sroberto */ 2268132451Sroberto 2269132451Sroberto if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) 2270132451Sroberto oncore_shmem_get_3D(instance); 2271132451Sroberto 2272132451Sroberto if (!instance->traim) /* NO traim, no BnEnHn, go get tick */ 2273132451Sroberto oncore_get_timestamp(instance, instance->offset, instance->offset); 227454359Sroberto} 227554359Sroberto 227654359Sroberto 227754359Sroberto 2278132451Sroberto/* Almanac Status */ 2279132451Sroberto 2280132451Srobertostatic void 2281132451Srobertooncore_msg_Bd( 2282132451Sroberto struct instance *instance, 2283132451Sroberto u_char *buf, 2284132451Sroberto size_t len 2285132451Sroberto ) 2286132451Sroberto{ 2287132451Sroberto char Msg[160]; 2288132451Sroberto 2289132451Sroberto sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x", 2290132451Sroberto ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) ); 2291132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 2292132451Sroberto} 2293132451Sroberto 2294132451Sroberto 2295132451Sroberto 2296132451Sroberto/* get leap-second warning message */ 2297132451Sroberto 229882498Sroberto/* 2299132451Sroberto * @@Bj does NOT behave as documented in current Oncore firmware. 2300132451Sroberto * It turns on the LEAP indicator when the data is set, and does not, 2301132451Sroberto * as documented, wait until the beginning of the month when the 2302132451Sroberto * leap second will occur. 2303132451Sroberto * Since this firmware bug will never be fixed in all the outstanding Oncore receivers 2304132451Sroberto * @@Bj is only called in June/December. 230582498Sroberto */ 230682498Sroberto 230754359Srobertostatic void 2308132451Srobertooncore_msg_Bj( 230954359Sroberto struct instance *instance, 231054359Sroberto u_char *buf, 231182498Sroberto size_t len 231254359Sroberto ) 231354359Sroberto{ 2314132451Sroberto const char *cp; 231582498Sroberto 2316132451Sroberto switch(buf[4]) { 2317132451Sroberto case 1: 2318182007Sroberto instance->pp->leap = LEAP_ADDSECOND; 2319182007Sroberto cp = "Set pp.leap to LEAP_ADDSECOND"; 2320132451Sroberto break; 2321132451Sroberto case 2: 2322182007Sroberto instance->pp->leap = LEAP_DELSECOND; 2323182007Sroberto cp = "Set pp.leap to LEAP_DELSECOND"; 2324132451Sroberto break; 2325132451Sroberto case 0: 2326132451Sroberto default: 2327182007Sroberto instance->pp->leap = LEAP_NOWARNING; 2328182007Sroberto cp = "Set pp.leap to LEAP_NOWARNING"; 2329132451Sroberto break; 2330132451Sroberto } 2331132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2332132451Sroberto} 233382498Sroberto 2334132451Sroberto 2335132451Sroberto 2336132451Srobertostatic void 2337132451Srobertooncore_msg_BnEnHn( 2338132451Sroberto struct instance *instance, 2339132451Sroberto u_char *buf, 2340132451Sroberto size_t len 2341132451Sroberto ) 2342132451Sroberto{ 2343132451Sroberto long dt1, dt2; 2344132451Sroberto char *cp; 2345132451Sroberto 2346132451Sroberto if (instance->o_state != ONCORE_RUN) 2347132451Sroberto return; 2348132451Sroberto 2349132451Sroberto if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */ 2350132451Sroberto instance->traim_ck = 1; 2351132451Sroberto instance->traim_delay = 0; 2352132451Sroberto cp = "ONCORE: Detected TRAIM, TRAIM = ON"; 2353132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2354132451Sroberto 2355132451Sroberto oncore_set_traim(instance); 235682498Sroberto } 2357132451Sroberto 2358132451Sroberto memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */ 2359132451Sroberto 2360182007Sroberto if (!instance->traim) /* BnEnHn will be turned off in any case */ 2361182007Sroberto return; 2362182007Sroberto 2363132451Sroberto /* If Time RAIM doesn't like it, don't trust it */ 2364132451Sroberto 2365132451Sroberto if (buf[2] == 'H') { 2366132451Sroberto if (instance->BEHn[6]) /* bad TRAIM */ 2367132451Sroberto return; 2368132451Sroberto 2369132451Sroberto dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2370182007Sroberto instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */ 2371132451Sroberto dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2372132451Sroberto } else { 2373132451Sroberto if (instance->BEHn[21]) /* bad TRAIM */ 2374132451Sroberto return; 2375132451Sroberto 2376132451Sroberto dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2377182007Sroberto instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */ 2378132451Sroberto dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2379132451Sroberto } 2380132451Sroberto 2381132451Sroberto oncore_get_timestamp(instance, dt1, dt2); 238282498Sroberto} 238382498Sroberto 238482498Sroberto 238582498Sroberto 238682498Sroberto/* Here for @@Ca, @@Fa and @@Ia messages */ 238782498Sroberto 2388132451Sroberto/* These are Self test Commands for 6, 8, and 12 chan receivers. 2389132451Sroberto * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE. 2390132451Sroberto * It was found that under some circumstances the following 239182498Sroberto * command would fail if issued immediately after the return from the 239282498Sroberto * @@Fa, but a 2sec delay seemed to fix things. Since simply calling 2393132451Sroberto * sleep(2) is wasteful, and may cause trouble for some OS's, repeating 2394132451Sroberto * itimer, we set a flag, and test it at the next POLL. If it hasn't 239582498Sroberto * been cleared, we reissue the @@Cj that is issued below. 239682498Sroberto * Note that we do a @@Cj at the beginning, and again here. 239782498Sroberto * The first is to get the info, the 2nd is just used as a safe command 239882498Sroberto * after the @@Fa for all Oncores (and it was in this posn in the 239982498Sroberto * original code). 240082498Sroberto */ 240182498Sroberto 240282498Srobertostatic void 240382498Srobertooncore_msg_CaFaIa( 240482498Sroberto struct instance *instance, 240582498Sroberto u_char *buf, 240682498Sroberto size_t len 240782498Sroberto ) 240882498Sroberto{ 240982498Sroberto char *cp; 2410132451Sroberto int i; 241182498Sroberto 241282498Sroberto if (instance->o_state == ONCORE_TEST_SENT) { 2413132451Sroberto enum antenna_state antenna; 241482498Sroberto 241582498Sroberto instance->timeout = 0; 241682498Sroberto 2417182007Sroberto#ifdef DEBUG 241882498Sroberto if (debug > 2) { 241982498Sroberto if (buf[2] == 'I') 242082498Sroberto printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]); 242182498Sroberto else 242282498Sroberto printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]); 242382498Sroberto } 2424182007Sroberto#endif 242582498Sroberto 2426132451Sroberto antenna = (buf[4] & 0xc0) >> 6; 242782498Sroberto buf[4] &= ~0xc0; 242882498Sroberto 2429132451Sroberto i = buf[4] || buf[5]; 2430132451Sroberto if (buf[2] == 'I') i = i || buf[6]; 2431132451Sroberto if (i) { 2432132451Sroberto if (buf[2] == 'I') { 2433132451Sroberto msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x", 2434132451Sroberto instance->unit, buf[4], buf[5], buf[6]); 2435132451Sroberto } else { 2436132451Sroberto msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x", 2437132451Sroberto instance->unit, buf[4], buf[5]); 2438132451Sroberto } 2439132451Sroberto cp = "ONCORE: self test failed, shutting down driver"; 2440132451Sroberto record_clock_stats(&instance->peer->srcadr, cp); 2441132451Sroberto 2442132451Sroberto refclock_report(instance->peer, CEVNT_FAULT); 244382498Sroberto oncore_shutdown(instance->unit, instance->peer); 244482498Sroberto return; 244582498Sroberto } 244682498Sroberto 2447132451Sroberto /* report the current antenna state */ 244882498Sroberto 2449132451Sroberto oncore_antenna_report(instance, antenna); 245082498Sroberto 245182498Sroberto instance->o_state = ONCORE_INIT; 245282498Sroberto cp = "state = ONCORE_INIT"; 245382498Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2454132451Sroberto 2455132451Sroberto instance->timeout = 4; 2456132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 245782498Sroberto } 245882498Sroberto} 245982498Sroberto 246082498Sroberto 246182498Sroberto 2462132451Sroberto/* 2463132451Sroberto * Demultiplex the almanac into shmem 2464132451Sroberto */ 246582498Sroberto 246682498Srobertostatic void 2467132451Srobertooncore_msg_Cb( 246882498Sroberto struct instance *instance, 246982498Sroberto u_char *buf, 247082498Sroberto size_t len 247182498Sroberto ) 247282498Sroberto{ 2473132451Sroberto int i; 247454359Sroberto 2475132451Sroberto if (instance->shmem == NULL) 2476132451Sroberto return; 247782498Sroberto 2478132451Sroberto if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26) 2479132451Sroberto i = buf[5]; 2480132451Sroberto else if (buf[4] == 4 && buf[5] <= 5) 2481132451Sroberto i = buf[5] + 24; 2482132451Sroberto else if (buf[4] == 4 && buf[5] <= 10) 2483132451Sroberto i = buf[5] + 23; 2484132451Sroberto else if (buf[4] == 4 && buf[5] == 25) 2485132451Sroberto i = 34; 2486132451Sroberto else { 2487132451Sroberto char *cp; 248882498Sroberto 2489132451Sroberto cp = "Cb: Response is NO ALMANAC"; 2490132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 249154359Sroberto return; 2492132451Sroberto } 249354359Sroberto 2494132451Sroberto i *= 36; 2495132451Sroberto instance->shmem[instance->shmem_Cb + i + 2]++; 2496132451Sroberto memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); 249754359Sroberto 2498132451Sroberto#if 1 2499132451Sroberto { 2500132451Sroberto char Msg[160]; 2501132451Sroberto sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]); 2502132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 250382498Sroberto } 2504132451Sroberto#endif 2505132451Sroberto} 250682498Sroberto 250782498Sroberto 2508132451Sroberto 2509132451Sroberto/* 2510132451Sroberto * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup 2511132451Sroberto * not so for VP (eeprom) or any unit with a battery 2512132451Sroberto */ 2513132451Sroberto 2514132451Srobertostatic void 2515132451Srobertooncore_msg_Cf( 2516132451Sroberto struct instance *instance, 2517132451Sroberto u_char *buf, 2518132451Sroberto size_t len 2519132451Sroberto ) 2520132451Sroberto{ 2521132451Sroberto const char *cp; 2522132451Sroberto 2523132451Sroberto if (instance->o_state == ONCORE_RESET_SENT) { 2524132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 2525132451Sroberto /* Reset set VP to IDLE */ 2526132451Sroberto instance->o_state = ONCORE_TEST_SENT; 2527132451Sroberto cp = "state = ONCORE_TEST_SENT"; 2528132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2529132451Sroberto 2530132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 253182498Sroberto } 2532132451Sroberto} 253382498Sroberto 253482498Sroberto 253582498Sroberto 2536132451Sroberto/* 2537132451Sroberto * This is the Grand Central Station for the Preliminary Initialization. 2538132451Sroberto * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running. 2539132451Sroberto * 2540132451Sroberto * We do an @@Cj whenever we need a safe command for all Oncores. 2541132451Sroberto * The @@Cj gets us back here where we can switch to the next phase of setup. 2542132451Sroberto * 2543132451Sroberto * o Once at the very beginning (in start) to get the Model number. 2544132451Sroberto * This info is printed, but no longer used. 2545132451Sroberto * o Again after we have determined the number of Channels in the receiver. 2546132451Sroberto * o And once later after we have done a reset and test, (which may hang), 2547132451Sroberto * as we are about to initialize the Oncore and start it running. 2548132451Sroberto * o We have one routine below for each case. 2549132451Sroberto */ 255082498Sroberto 2551132451Srobertostatic void 2552132451Srobertooncore_msg_Cj( 2553132451Sroberto struct instance *instance, 2554132451Sroberto u_char *buf, 2555132451Sroberto size_t len 2556132451Sroberto ) 2557132451Sroberto{ 2558132451Sroberto int mode; 2559132451Sroberto char *cp; 256082498Sroberto 2561132451Sroberto memcpy(instance->Cj, buf, len); 256282498Sroberto 2563132451Sroberto instance->timeout = 0; 2564132451Sroberto if (instance->o_state == ONCORE_CHECK_ID) { 2565132451Sroberto oncore_msg_Cj_id(instance, buf, len); 2566132451Sroberto oncore_chan_test(instance); 2567132451Sroberto } else if (instance->o_state == ONCORE_HAVE_CHAN) { 2568132451Sroberto mode = instance->init_type; 2569132451Sroberto if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */ 2570132451Sroberto instance->o_state = ONCORE_RESET_SENT; 2571132451Sroberto cp = "state = ONCORE_RESET_SENT"; 257282498Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2573132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); 2574132451Sroberto } else { 2575132451Sroberto instance->o_state = ONCORE_TEST_SENT; 2576132451Sroberto cp = "state = ONCORE_TEST_SENT"; 2577132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 257882498Sroberto } 257982498Sroberto } 258082498Sroberto 2581132451Sroberto if (instance->o_state == ONCORE_TEST_SENT) { 2582132451Sroberto if (instance->chan == 6) 2583132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); 2584132451Sroberto else if (instance->chan == 8) 2585132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); 2586132451Sroberto else if (instance->chan == 12) 2587132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); 2588132451Sroberto } else if (instance->o_state == ONCORE_INIT) 2589132451Sroberto oncore_msg_Cj_init(instance, buf, len); 2590132451Sroberto} 259182498Sroberto 259282498Sroberto 259382498Sroberto 2594132451Sroberto/* The information on determining a Oncore 'Model', viz VP, UT, etc, from 2595132451Sroberto * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> 2596132451Sroberto * and from Motorola. Until recently Rick was the only source of 2597132451Sroberto * this information as Motorola didn't give the information out. 2598132451Sroberto * 2599132451Sroberto * Determine the Type from the Model #, this determines #chan and if TRAIM is 2600132451Sroberto * available. 2601132451Sroberto * 2602132451Sroberto * The Information from this routine is NO LONGER USED. 2603132451Sroberto * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED 2604132451Sroberto */ 260582498Sroberto 2606132451Srobertostatic void 2607132451Srobertooncore_msg_Cj_id( 2608132451Sroberto struct instance *instance, 2609132451Sroberto u_char *buf, 2610132451Sroberto size_t len 2611132451Sroberto ) 2612132451Sroberto{ 2613132451Sroberto char *cp, *cp1, *cp2, Model[21], Msg[160]; 2614132451Sroberto 2615132451Sroberto /* Write Receiver ID message to clockstats file */ 2616132451Sroberto 2617132451Sroberto instance->Cj[294] = '\0'; 2618132451Sroberto for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { 2619132451Sroberto cp1 = strchr(cp, '\r'); 2620132451Sroberto if (!cp1) 2621132451Sroberto cp1 = (char *)&instance->Cj[294]; 2622132451Sroberto *cp1 = '\0'; 2623132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2624132451Sroberto *cp1 = '\r'; 2625132451Sroberto cp = cp1+2; 262682498Sroberto } 262782498Sroberto 2628132451Sroberto /* next, the Firmware Version and Revision numbers */ 262982498Sroberto 2630182007Sroberto instance->version = atoi((char *) &instance->Cj[83]); 2631182007Sroberto instance->revision = atoi((char *) &instance->Cj[111]); 263282498Sroberto 2633132451Sroberto /* from model number decide which Oncore this is, 2634132451Sroberto and then the number of channels */ 263582498Sroberto 2636182007Sroberto for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ 2637132451Sroberto ; 2638132451Sroberto cp1 = cp; 2639132451Sroberto cp2 = Model; 2640132451Sroberto for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++) 2641132451Sroberto *cp2 = *cp; 2642132451Sroberto *cp2 = '\0'; 2643132451Sroberto 2644132451Sroberto cp = 0; 2645132451Sroberto if (!strncmp(Model, "PVT6", (size_t) 4)) { 2646132451Sroberto cp = "PVT6"; 2647132451Sroberto instance->model = ONCORE_PVT6; 2648132451Sroberto } else if (Model[0] == 'A') { 2649132451Sroberto cp = "Basic"; 2650132451Sroberto instance->model = ONCORE_BASIC; 2651132451Sroberto } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { 2652132451Sroberto cp = "VP"; 2653132451Sroberto instance->model = ONCORE_VP; 2654132451Sroberto } else if (Model[0] == 'P') { 2655132451Sroberto cp = "M12"; 2656132451Sroberto instance->model = ONCORE_M12; 2657132451Sroberto } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') { 2658132451Sroberto if (Model[5] == 'N') { 2659132451Sroberto cp = "GT"; 2660132451Sroberto instance->model = ONCORE_GT; 2661132451Sroberto } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { 2662132451Sroberto cp = "GT+"; 2663132451Sroberto instance->model = ONCORE_GTPLUS; 2664132451Sroberto } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { 2665132451Sroberto cp = "UT"; 2666132451Sroberto instance->model = ONCORE_UT; 2667132451Sroberto } else if (Model[1] == '5' && Model[5] == 'G') { 2668132451Sroberto cp = "UT+"; 2669132451Sroberto instance->model = ONCORE_UTPLUS; 2670132451Sroberto } else if (Model[1] == '6' && Model[5] == 'G') { 2671132451Sroberto cp = "SL"; 2672132451Sroberto instance->model = ONCORE_SL; 2673132451Sroberto } else { 2674132451Sroberto cp = "Unknown"; 2675132451Sroberto instance->model = ONCORE_UNKNOWN; 267654359Sroberto } 2677132451Sroberto } else { 2678132451Sroberto cp = "Unknown"; 2679132451Sroberto instance->model = ONCORE_UNKNOWN; 268054359Sroberto } 268154359Sroberto 2682132451Sroberto /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */ 268354359Sroberto 2684132451Sroberto sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision); 2685132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 268682498Sroberto 2687132451Sroberto instance->chan_id = 8; /* default */ 2688132451Sroberto if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2689132451Sroberto instance->chan_id = 6; 2690132451Sroberto else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2691132451Sroberto instance->chan_id = 8; 2692132451Sroberto else if (instance->model == ONCORE_M12) 2693132451Sroberto instance->chan_id = 12; 269482498Sroberto 2695132451Sroberto instance->traim_id = 0; /* default */ 2696132451Sroberto if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2697132451Sroberto instance->traim_id = 0; 2698132451Sroberto else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2699132451Sroberto instance->traim_id = 1; 2700132451Sroberto else if (instance->model == ONCORE_M12) 2701132451Sroberto instance->traim_id = -1; 270282498Sroberto 2703132451Sroberto sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id, 2704132451Sroberto ((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF"))); 2705132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 2706132451Sroberto} 2707132451Sroberto 2708132451Sroberto 2709132451Sroberto 2710132451Sroberto/* OK, know type of Oncore, have possibly reset it, and have tested it. 2711132451Sroberto * We know the number of channels. 2712132451Sroberto * We will determine whether we have TRAIM before we actually start. 2713132451Sroberto * Now initialize. 2714132451Sroberto */ 2715132451Sroberto 2716132451Srobertostatic void 2717132451Srobertooncore_msg_Cj_init( 2718132451Sroberto struct instance *instance, 2719132451Sroberto u_char *buf, 2720132451Sroberto size_t len 2721132451Sroberto ) 2722132451Sroberto{ 2723182007Sroberto char *cp, Msg[160]; 2724182007Sroberto u_char Cmd[20]; 2725132451Sroberto int mode; 2726132451Sroberto 2727132451Sroberto 2728132451Sroberto /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to 2729132451Sroberto * start again if we go from 0D -> 3D, then loses them again when we 2730132451Sroberto * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. 2731132451Sroberto * For NOW we will turn this aspect of filling SHMEM off for the M12 273282498Sroberto */ 273382498Sroberto 2734132451Sroberto if (instance->chan == 12) { 2735132451Sroberto instance->shmem_bad_Ea = 1; 2736132451Sroberto sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision); 2737132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 273854359Sroberto } 273954359Sroberto 2740132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 2741132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */ 2742132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */ 2743132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */ 2744132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */ 2745132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */ 2746132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */ 274782498Sroberto 2748132451Sroberto mode = instance->init_type; 274982498Sroberto 2750132451Sroberto /* If there is Position input in the Config file 2751132451Sroberto * and mode = (1,3) set it as posn hold posn, goto 0D mode. 2752132451Sroberto * or mode = (2,4) set it as INITIAL position, and do Site Survey. 275382498Sroberto */ 275454359Sroberto 2755132451Sroberto if (instance->posn_set) { 2756132451Sroberto record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data"); 2757132451Sroberto oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */ 2758132451Sroberto } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */ 2759132451Sroberto if (instance->chan != 12) 2760132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx)); 276182498Sroberto 2762132451Sroberto if (mode != 0) { 2763132451Sroberto /* cable delay in ns */ 2764132451Sroberto memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az)); 2765132451Sroberto w32_buf(&Cmd[-2+4], instance->delay); 2766132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */ 276782498Sroberto 2768132451Sroberto /* PPS offset in ns */ 2769132451Sroberto if (instance->offset) { 2770132451Sroberto memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */ 2771132451Sroberto w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */ 2772132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay)); 277382498Sroberto } 2774132451Sroberto 2775132451Sroberto /* Satellite mask angle */ 2776132451Sroberto 2777132451Sroberto if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */ 2778132451Sroberto memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag)); 2779132451Sroberto Cmd[-2+4] = instance->Ag; 2780132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ag)); 2781132451Sroberto } 278282498Sroberto } 278382498Sroberto 2784132451Sroberto /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s 2785132451Sroberto * now we're really running 2786132451Sroberto * these were ALL started in the chan test, 2787132451Sroberto * However, if we had mode=3,4 then commands got turned off, so we turn 2788132451Sroberto * them on again here just in case 278954359Sroberto */ 279054359Sroberto 2791132451Sroberto if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */ 2792132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 2793132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 2794132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 2795132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 2796132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba )); 2797132451Sroberto } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */ 2798132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 2799132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 2800132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 2801132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 2802132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea )); 2803132451Sroberto } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */ 2804132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 2805132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 2806132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 2807132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 2808132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha )); 280954359Sroberto } 281054359Sroberto 2811132451Sroberto instance->count = 1; 2812132451Sroberto instance->o_state = ONCORE_ALMANAC; 2813132451Sroberto cp = "state = ONCORE_ALMANAC"; 2814132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2815132451Sroberto} 281682498Sroberto 281754359Sroberto 281854359Sroberto 2819132451Sroberto/* 12chan position */ 282054359Sroberto 2821132451Srobertostatic void 2822132451Srobertooncore_msg_Ga( 2823132451Sroberto struct instance *instance, 2824132451Sroberto u_char *buf, 2825132451Sroberto size_t len 2826132451Sroberto ) 2827132451Sroberto{ 2828132451Sroberto char Msg[160]; 2829132451Sroberto long lat, lon, ht; 2830132451Sroberto double Lat, Lon, Ht; 283154359Sroberto 283254359Sroberto 2833132451Sroberto lat = buf_w32(&buf[4]); 2834132451Sroberto lon = buf_w32(&buf[8]); 2835132451Sroberto ht = buf_w32(&buf[12]); /* GPS ellipsoid */ 283654359Sroberto 2837132451Sroberto Lat = lat; 2838132451Sroberto Lon = lon; 2839132451Sroberto Ht = ht; 284054359Sroberto 2841132451Sroberto Lat /= 3600000; 2842132451Sroberto Lon /= 3600000; 2843132451Sroberto Ht /= 100; 2844132451Sroberto 2845132451Sroberto 2846132451Sroberto sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, Lon, Ht); 284756746Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 284856746Sroberto 2849132451Sroberto instance->ss_lat = lat; 2850132451Sroberto instance->ss_long = lon; 2851132451Sroberto instance->ss_ht = ht; 285254359Sroberto 2853132451Sroberto oncore_print_posn(instance); 2854132451Sroberto} 285582498Sroberto 285682498Sroberto 285782498Sroberto 2858132451Sroberto/* 12 chan time/date */ 285982498Sroberto 2860132451Srobertostatic void 2861132451Srobertooncore_msg_Gb( 2862132451Sroberto struct instance *instance, 2863132451Sroberto u_char *buf, 2864132451Sroberto size_t len 2865132451Sroberto ) 2866132451Sroberto{ 2867132451Sroberto char Msg[160], *gmts; 2868132451Sroberto int mo, d, y, h, m, s, gmth, gmtm; 286982498Sroberto 2870132451Sroberto mo = buf[4]; 2871132451Sroberto d = buf[5]; 2872132451Sroberto y = 256*buf[6]+buf[7]; 2873132451Sroberto 2874132451Sroberto h = buf[8]; 2875132451Sroberto m = buf[9]; 2876132451Sroberto s = buf[10]; 2877132451Sroberto 2878132451Sroberto gmts = ((buf[11] == 0) ? "+" : "-"); 2879132451Sroberto gmth = buf[12]; 2880132451Sroberto gmtm = buf[13]; 2881132451Sroberto 2882132451Sroberto sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)", 2883182007Sroberto d, Month[mo-1], y, h, m, s, gmts, gmth, gmtm); 2884132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 288554359Sroberto} 288654359Sroberto 288754359Sroberto 288854359Sroberto 2889132451Sroberto/* Leap Second for M12, gives all info from satellite message */ 2890132451Sroberto/* also in UT v3.0 */ 289182498Sroberto 289282498Srobertostatic void 2893132451Srobertooncore_msg_Gj( 289482498Sroberto struct instance *instance, 2895132451Sroberto u_char *buf, 2896132451Sroberto size_t len 289782498Sroberto ) 289882498Sroberto{ 2899132451Sroberto int dt; 2900132451Sroberto char Msg[160], *cp; 290154359Sroberto 2902132451Sroberto instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */ 290354359Sroberto 2904132451Sroberto /* print the message to verify whats there */ 290554359Sroberto 2906132451Sroberto dt = buf[5] - buf[4]; 290754359Sroberto 2908132451Sroberto#if 1 2909132451Sroberto sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", 2910132451Sroberto instance->unit, 2911132451Sroberto buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10], 2912132451Sroberto (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))), 2913132451Sroberto buf[15], buf[16], buf[17]); 2914132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 2915132451Sroberto#endif 2916132451Sroberto if (dt) { 2917132451Sroberto sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d", 2918132451Sroberto instance->unit, 2919182007Sroberto dt, buf[9], Month[buf[8]-1], 256*buf[6]+buf[7], 2920132451Sroberto buf[15], buf[16], buf[17]); 2921132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 292254359Sroberto } 292354359Sroberto 2924132451Sroberto /* Only raise warning within a month of the leap second */ 292554359Sroberto 2926182007Sroberto instance->pp->leap = LEAP_NOWARNING; 2927182007Sroberto cp = "Set pp.leap to LEAP_NOWARNING"; 292854359Sroberto 2929132451Sroberto if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */ 2930132451Sroberto buf[8] == instance->BEHa[4]) { /* month */ 2931132451Sroberto if (dt) { 2932132451Sroberto if (dt < 0) { 2933182007Sroberto instance->pp->leap = LEAP_DELSECOND; 2934182007Sroberto cp = "Set pp.leap to LEAP_DELSECOND"; 2935132451Sroberto } else { 2936182007Sroberto instance->pp->leap = LEAP_ADDSECOND; 2937182007Sroberto cp = "Set pp.leap to LEAP_ADDSECOND"; 2938132451Sroberto } 293954359Sroberto } 2940132451Sroberto } 2941132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2942132451Sroberto} 294354359Sroberto 294454359Sroberto 294554359Sroberto 2946132451Sroberto/* Power on failure */ 294754359Sroberto 2948132451Srobertostatic void 2949132451Srobertooncore_msg_Sz( 2950132451Sroberto struct instance *instance, 2951132451Sroberto u_char *buf, 2952132451Sroberto size_t len 2953132451Sroberto ) 2954132451Sroberto{ 2955132451Sroberto const char *cp; 2956132451Sroberto 2957132451Sroberto cp = "Oncore: System Failure at Power On"; 2958132451Sroberto if (instance && instance->peer) { 2959132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 2960132451Sroberto oncore_shutdown(instance->unit, instance->peer); 296154359Sroberto } 2962132451Sroberto} 296354359Sroberto 2964132451Sroberto/************** Small Subroutines ***************/ 296554359Sroberto 296654359Sroberto 2967132451Srobertostatic void 2968132451Srobertooncore_antenna_report( 2969132451Sroberto struct instance *instance, 2970132451Sroberto enum antenna_state new_state) 2971132451Sroberto{ 2972132451Sroberto char *cp; 2973132451Sroberto 2974132451Sroberto if (instance->ant_state == new_state) 297554359Sroberto return; 297654359Sroberto 2977132451Sroberto switch (new_state) { 2978132451Sroberto case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break; 2979132451Sroberto case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break; 2980132451Sroberto case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break; 2981132451Sroberto case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break; 2982132451Sroberto default: cp = "GPS antenna: ?"; break; 298356746Sroberto } 298454359Sroberto 2985132451Sroberto instance->ant_state = new_state; 2986132451Sroberto record_clock_stats(&instance->peer->srcadr, cp); 2987132451Sroberto} 298854359Sroberto 298954359Sroberto 299054359Sroberto 2991132451Srobertostatic void 2992132451Srobertooncore_chan_test( 2993132451Sroberto struct instance *instance 2994132451Sroberto ) 2995132451Sroberto{ 2996132451Sroberto char *cp; 299782498Sroberto 2998132451Sroberto /* subroutine oncore_Cj_id has determined the number of channels from the 2999132451Sroberto * model number of the attached oncore. This is not always correct since 3000132451Sroberto * the oncore could have non-standard firmware. Here we check (independently) by 3001132451Sroberto * trying a 6, 8, and 12 chan command, and see which responds. 3002132451Sroberto * Caution: more than one CAN respond. 300382498Sroberto * 3004132451Sroberto * This #chan is used by the code rather than that calculated from the model number. 300582498Sroberto */ 300682498Sroberto 3007132451Sroberto instance->o_state = ONCORE_CHECK_CHAN; 3008132451Sroberto cp = "state = ONCORE_CHECK_CHAN"; 3009132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 301054359Sroberto 3011132451Sroberto instance->count3 = 1; 3012132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); 3013132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); 3014132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); 3015132451Sroberto} 301682498Sroberto 301782498Sroberto 301882498Sroberto 3019132451Sroberto/* check for a GOOD Almanac, have we got one yet? */ 302054359Sroberto 3021132451Srobertostatic void 3022132451Srobertooncore_check_almanac( 3023132451Sroberto struct instance *instance 3024132451Sroberto ) 3025132451Sroberto{ 3026132451Sroberto if (instance->chan == 6) { 3027132451Sroberto instance->rsm.bad_almanac = instance->BEHa[64]&0x1; 3028132451Sroberto instance->rsm.bad_fix = instance->BEHa[64]&0x52; 3029132451Sroberto } else if (instance->chan == 8) { 3030132451Sroberto instance->rsm.bad_almanac = instance->BEHa[72]&0x1; 3031132451Sroberto instance->rsm.bad_fix = instance->BEHa[72]&0x52; 3032132451Sroberto } else if (instance->chan == 12) { 3033182007Sroberto int bits1, bits2, bits3; 3034132451Sroberto 3035132451Sroberto bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 3036132451Sroberto bits2 = instance->BEHa[130]; 3037132451Sroberto instance->rsm.bad_almanac = (bits2 & 0x80); 3038132451Sroberto instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); 3039132451Sroberto /* too few sat Bad Geom */ 3040182007Sroberto 3041182007Sroberto bits3 = instance->BEHa[141]; /* UTC parameters */ 3042182007Sroberto if (!instance->count5_set && (bits3 & 0xC0)) { 3043182007Sroberto instance->count5 = 2; 3044182007Sroberto instance->count5_set = 1; 3045182007Sroberto } 3046132451Sroberto#if 0 3047182007Sroberto{ 3048182007Sroberto char Msg[160]; 3049182007Sroberto 3050182007Sroberto sprintf(Msg, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x\n", 3051132451Sroberto instance->unit, 3052182007Sroberto instance->BEHa[129], instance->BEHa[130], bits1, bits2, bits3, instance->mode == MODE_0D, 3053132451Sroberto instance->mode == MODE_2D, instance->mode == MODE_3D, 3054132451Sroberto instance->rsm.bad_almanac, instance->rsm.bad_fix); 3055182007Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3056182007Sroberto} 305754359Sroberto#endif 3058132451Sroberto } 3059132451Sroberto} 306054359Sroberto 306154359Sroberto 306254359Sroberto 3063132451Sroberto/* check the antenna for changes (did it get unplugged?) */ 306454359Sroberto 3065132451Srobertostatic void 3066132451Srobertooncore_check_antenna( 3067132451Sroberto struct instance *instance 3068132451Sroberto ) 3069132451Sroberto{ 3070132451Sroberto enum antenna_state antenna; /* antenna state */ 307182498Sroberto 3072132451Sroberto antenna = instance->ant_state; 3073132451Sroberto if (instance->chan == 12) 3074132451Sroberto antenna = (instance->BEHa[130] & 0x6 ) >> 1; 3075132451Sroberto else 3076132451Sroberto antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */ 307754359Sroberto 3078132451Sroberto oncore_antenna_report (instance, antenna); 3079132451Sroberto} 3080132451Sroberto 3081132451Sroberto 3082132451Sroberto 3083132451Sroberto/* 3084132451Sroberto * Check the leap second status once per day. 3085132451Sroberto * 3086132451Sroberto * Note that the ONCORE firmware for the Bj command is wrong at 3087132451Sroberto * least in the VP. 3088132451Sroberto * It starts advertising a LEAP SECOND as soon as the GPS satellite 3089132451Sroberto * data message (page 18, subframe 4) is updated to a date in the 3090132451Sroberto * future, and does not wait for the month that it will occur. 3091132451Sroberto * The event will usually be advertised several months in advance. 3092132451Sroberto * Since there is a one bit flag, there is no way to tell if it is 3093132451Sroberto * this month, or when... 3094132451Sroberto * 3095132451Sroberto * As such, we have the workaround below, of only checking for leap 3096132451Sroberto * seconds with the Bj command in June/December. 3097132451Sroberto * 3098132451Sroberto * The Gj command gives more information, and we can tell in which 3099132451Sroberto * month to apply the correction. 3100132451Sroberto * 3101132451Sroberto * Note that with the VP we COULD read the raw data message, and 3102132451Sroberto * interpret it ourselves, but since this is specific to this receiver 3103132451Sroberto * only, and the above workaround is adequate, we don't bother. 3104132451Sroberto */ 3105132451Sroberto 3106132451Srobertostatic void 3107132451Srobertooncore_check_leap_sec( 3108132451Sroberto struct instance *instance 3109132451Sroberto ) 3110132451Sroberto{ 3111132451Sroberto if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */ 3112132451Sroberto instance->Bj_day = instance->BEHa[5]; 3113132451Sroberto 3114132451Sroberto if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */ 3115132451Sroberto if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) 3116132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3117132451Sroberto return; 3118132451Sroberto } 3119132451Sroberto 3120132451Sroberto if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */ 3121132451Sroberto instance->count4 = 1; 3122132451Sroberto 3123132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); 312454359Sroberto return; 312554359Sroberto } 312654359Sroberto 3127132451Sroberto /* Gj works for some 6/8 chan UT and the M12 */ 3128132451Sroberto /* if no response from Gj in 5 sec, we try Bj */ 3129132451Sroberto /* which isnt implemented in all the GT/UT either */ 313054359Sroberto 3131132451Sroberto if (instance->count4) { /* delay, waiting for Gj response */ 3132132451Sroberto if (instance->saw_Gj == 1) 3133132451Sroberto instance->count4 = 0; 3134132451Sroberto else if (instance->count4++ > 5) { /* delay, waiting for Gj response */ 3135132451Sroberto instance->saw_Gj = -1; /* didnt see it, will use Bj */ 3136132451Sroberto instance->count4 = 0; 3137132451Sroberto if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) 3138132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3139132451Sroberto } 314054359Sroberto } 314154359Sroberto} 314254359Sroberto 314354359Sroberto 314454359Sroberto 3145132451Sroberto/* check the message checksum, 3146132451Sroberto * buf points to START of message ( @@ ) 3147132451Sroberto * len is length WITH CR/LF. 314854359Sroberto */ 314982498Sroberto 3150132451Srobertostatic int 3151132451Srobertooncore_checksum_ok( 315254359Sroberto u_char *buf, 3153132451Sroberto int len 315454359Sroberto ) 315554359Sroberto{ 3156132451Sroberto int i, j; 315754359Sroberto 3158132451Sroberto j = 0; 3159132451Sroberto for (i = 2; i < len-3; i++) 3160132451Sroberto j ^= buf[i]; 316154359Sroberto 3162132451Sroberto return(j == buf[len-3]); 3163132451Sroberto} 316454359Sroberto 316554359Sroberto 316654359Sroberto 316754359Srobertostatic void 3168132451Srobertooncore_compute_dH( 3169132451Sroberto struct instance *instance 317054359Sroberto ) 317154359Sroberto{ 3172132451Sroberto int GPS, MSL; 3173132451Sroberto char Msg[160]; 317454359Sroberto 3175132451Sroberto /* Here calculate dH = GPS - MSL for output message */ 3176132451Sroberto /* also set Altitude Hold mode if GT */ 3177132451Sroberto 3178132451Sroberto instance->have_dH = 1; 3179132451Sroberto if (instance->chan == 12) { 3180132451Sroberto GPS = buf_w32(&instance->BEHa[39]); 3181132451Sroberto MSL = buf_w32(&instance->BEHa[43]); 3182132451Sroberto } else { 3183132451Sroberto GPS = buf_w32(&instance->BEHa[23]); 3184132451Sroberto MSL = buf_w32(&instance->BEHa[27]); 318554359Sroberto } 3186132451Sroberto instance->dH = GPS - MSL; 3187132451Sroberto instance->dH /= 100.; 3188132451Sroberto 3189132451Sroberto /* if MSL is not set, the calculation is meaningless */ 3190132451Sroberto 3191132451Sroberto if (MSL) { /* not set ! */ 3192132451Sroberto sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH); 3193132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3194132451Sroberto } 319554359Sroberto} 319654359Sroberto 319754359Sroberto 3198132451Sroberto 3199132451Sroberto/* 3200132451Sroberto * try loading Almanac from shmem (where it was copied from shmem_old 3201132451Sroberto */ 3202132451Sroberto 320382498Srobertostatic void 3204132451Srobertooncore_load_almanac( 3205132451Sroberto struct instance *instance 320682498Sroberto ) 320782498Sroberto{ 3208132451Sroberto u_char *cp, Cmd[20]; 3209132451Sroberto int n; 3210132451Sroberto struct timeval tv; 3211132451Sroberto struct tm *tm; 321254359Sroberto 3213132451Sroberto if (!instance->shmem) 3214132451Sroberto return; 321582498Sroberto 321682498Sroberto#if 1 3217132451Sroberto for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { 3218182007Sroberto if (!strncmp((char *) cp, "@@Cb", 4) && 3219132451Sroberto oncore_checksum_ok(cp, 33) && 3220132451Sroberto (*(cp+4) == 4 || *(cp+4) == 5)) { 3221132451Sroberto write(instance->ttyfd, cp, n); 3222132451Sroberto#if 1 3223132451Sroberto oncore_print_Cb(instance, cp); 322482498Sroberto#endif 3225132451Sroberto } 3226132451Sroberto } 3227132451Sroberto#else 3228132451Sroberto/************DEBUG************/ 3229132451Sroberto for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { 3230132451Sroberto char Msg[160]; 3231132451Sroberto 3232132451Sroberto sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4)); 323382498Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3234132451Sroberto 3235132451Sroberto if (!strncmp(cp, "@@Cb", 4)) { 3236132451Sroberto oncore_print_Cb(instance, cp); 3237132451Sroberto if (oncore_checksum_ok(cp, 33)) { 3238132451Sroberto if (*(cp+4) == 4 || *(cp+4) == 5) { 3239132451Sroberto record_clock_stats(&(instance->peer->srcadr), "GOOD SF"); 3240132451Sroberto write(instance->ttyfd, cp, n); 3241132451Sroberto } else 3242132451Sroberto record_clock_stats(&(instance->peer->srcadr), "BAD SF"); 3243132451Sroberto } else 3244132451Sroberto record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM"); 3245132451Sroberto } 324682498Sroberto } 3247132451Sroberto/************DEBUG************/ 3248132451Sroberto#endif 324982498Sroberto 3250132451Sroberto /* Must load position and time or the Almanac doesn't do us any good */ 325182498Sroberto 3252132451Sroberto if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */ 3253132451Sroberto record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM"); 3254132451Sroberto for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { 3255182007Sroberto if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) || 3256182007Sroberto (instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) || 3257182007Sroberto (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) { 3258132451Sroberto int ii, jj, kk; 325982498Sroberto 3260132451Sroberto instance->posn_set = 1; 3261132451Sroberto ii = buf_w32(cp + 15); 3262132451Sroberto jj = buf_w32(cp + 19); 3263132451Sroberto kk = buf_w32(cp + 23); 3264182007Sroberto#if 0 3265132451Sroberto{ 3266132451Srobertochar Msg[160]; 3267182007Srobertosprintf(Msg, "SHMEM posn = %ld (%d, %d, %d)", (long) (cp-instance->shmem), ii, jj, kk); 3268132451Srobertorecord_clock_stats(&(instance->peer->srcadr), Msg); 3269132451Sroberto} 3270182007Sroberto#endif 3271132451Sroberto if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */ 3272132451Sroberto instance->ss_lat = ii; 3273132451Sroberto instance->ss_long = jj; 3274132451Sroberto instance->ss_ht = kk; 3275132451Sroberto } 327682498Sroberto } 327782498Sroberto } 327882498Sroberto } 3279132451Sroberto oncore_set_posn(instance); 3280132451Sroberto 3281132451Sroberto /* and set time to time from Computer clock */ 3282132451Sroberto 3283132451Sroberto gettimeofday(&tv, 0); 3284132451Sroberto tm = gmtime((const time_t *) &tv.tv_sec); 3285132451Sroberto#if 1 3286132451Sroberto { 3287132451Sroberto char Msg[160]; 3288132451Sroberto sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday, 3289132451Sroberto tm->tm_hour, tm->tm_min, tm->tm_sec); 3290132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3291132451Sroberto } 3292132451Sroberto#endif 3293132451Sroberto if (instance->chan == 12) { 3294132451Sroberto memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb)); 3295182007Sroberto Cmd[-2+4] = tm->tm_mon + 1; 3296132451Sroberto Cmd[-2+5] = tm->tm_mday; 3297132451Sroberto Cmd[-2+6] = (1900+tm->tm_year)/256; 3298132451Sroberto Cmd[-2+7] = (1900+tm->tm_year)%256; 3299132451Sroberto Cmd[-2+8] = tm->tm_hour; 3300132451Sroberto Cmd[-2+9] = tm->tm_min; 3301132451Sroberto Cmd[-2+10] = tm->tm_sec; 3302132451Sroberto Cmd[-2+11] = 0; 3303132451Sroberto Cmd[-2+12] = 0; 3304132451Sroberto Cmd[-2+13] = 0; 3305132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Gb)); 3306132451Sroberto } else { 3307132451Sroberto /* First set GMT offset to zero */ 3308132451Sroberto 3309132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab, sizeof(oncore_cmd_Ab)); 3310132451Sroberto 3311132451Sroberto memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac)); 3312182007Sroberto Cmd[-2+4] = tm->tm_mon + 1; 3313132451Sroberto Cmd[-2+5] = tm->tm_mday; 3314132451Sroberto Cmd[-2+6] = (1900+tm->tm_year)/256; 3315132451Sroberto Cmd[-2+7] = (1900+tm->tm_year)%256; 3316132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ac)); 3317132451Sroberto 3318132451Sroberto memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa)); 3319132451Sroberto Cmd[-2+4] = tm->tm_hour; 3320132451Sroberto Cmd[-2+5] = tm->tm_min; 3321132451Sroberto Cmd[-2+6] = tm->tm_sec; 3322132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Aa)); 3323132451Sroberto } 3324132451Sroberto 3325132451Sroberto record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac"); 332682498Sroberto} 332782498Sroberto 332882498Sroberto 332982498Sroberto 3330132451Sroberto/* Almanac data input */ 333182498Sroberto 333254359Srobertostatic void 3333132451Srobertooncore_print_Cb( 333454359Sroberto struct instance *instance, 3335132451Sroberto u_char *cp 333654359Sroberto ) 333754359Sroberto{ 3338132451Sroberto#if 0 3339132451Sroberto int ii; 3340132451Sroberto char Msg[160]; 334154359Sroberto 3342132451Sroberto printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3)); 3343132451Sroberto printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5)); 3344132451Sroberto for(ii=0; ii<33; ii++) 3345132451Sroberto printf(" %d", *(cp+ii)); 3346132451Sroberto printf("\n"); 334754359Sroberto 3348132451Sroberto sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5)); 3349132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3350132451Sroberto#endif 3351132451Sroberto} 335254359Sroberto 3353132451Sroberto 3354132451Sroberto#if 0 3355132451Srobertostatic void 3356132451Srobertooncore_print_array( 3357132451Sroberto u_char *cp, 3358132451Sroberto int n 3359132451Sroberto ) 3360132451Sroberto{ 3361132451Sroberto int jj, i, j, nn; 3362132451Sroberto 3363132451Sroberto nn = 0; 3364132451Sroberto printf("\nTOP\n"); 3365132451Sroberto jj = n/16; 3366132451Sroberto for (j=0; j<jj; j++) { 3367132451Sroberto printf("%4d: ", nn); 3368132451Sroberto nn += 16; 3369132451Sroberto for (i=0; i<16; i++) 3370132451Sroberto printf(" %o", *cp++); 3371132451Sroberto printf("\n"); 3372132451Sroberto } 337382498Sroberto} 3374132451Sroberto#endif 337554359Sroberto 337654359Sroberto 337782498Srobertostatic void 3378132451Srobertooncore_print_posn( 337982498Sroberto struct instance *instance 338082498Sroberto ) 338182498Sroberto{ 338282498Sroberto char Msg[120], ew, ns; 338382498Sroberto double xd, xm, xs, yd, ym, ys, hm, hft; 338482498Sroberto int idx, idy, is, imx, imy; 338582498Sroberto long lat, lon; 338654359Sroberto 338754359Sroberto record_clock_stats(&(instance->peer->srcadr), "Posn:"); 338854359Sroberto ew = 'E'; 338954359Sroberto lon = instance->ss_long; 339054359Sroberto if (lon < 0) { 339154359Sroberto ew = 'W'; 339254359Sroberto lon = -lon; 339354359Sroberto } 339454359Sroberto 339554359Sroberto ns = 'N'; 339654359Sroberto lat = instance->ss_lat; 339754359Sroberto if (lat < 0) { 339854359Sroberto ns = 'S'; 339954359Sroberto lat = -lat; 340054359Sroberto } 340154359Sroberto 340254359Sroberto hm = instance->ss_ht/100.; 340354359Sroberto hft= hm/0.3048; 340454359Sroberto 340554359Sroberto xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ 340654359Sroberto yd = lon/3600000.; 340782498Sroberto sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft); 340854359Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 340954359Sroberto 341054359Sroberto idx = xd; 341154359Sroberto idy = yd; 341254359Sroberto imx = lat%3600000; 341354359Sroberto imy = lon%3600000; 341454359Sroberto xm = imx/60000.; 341554359Sroberto ym = imy/60000.; 3416132451Sroberto sprintf(Msg, 3417132451Sroberto "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft); 341854359Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 341954359Sroberto 342054359Sroberto imx = xm; 342154359Sroberto imy = ym; 342254359Sroberto is = lat%60000; 342354359Sroberto xs = is/1000.; 342454359Sroberto is = lon%60000; 342554359Sroberto ys = is/1000.; 3426132451Sroberto sprintf(Msg, 3427132451Sroberto "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft); 342854359Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 342956746Sroberto} 343054359Sroberto 343154359Sroberto 343254359Sroberto 343356746Sroberto/* 3434132451Sroberto * write message to Oncore. 343556746Sroberto */ 343682498Sroberto 343756746Srobertostatic void 3438132451Srobertooncore_sendmsg( 3439132451Sroberto int fd, 3440132451Sroberto u_char *ptr, 344182498Sroberto size_t len 344256746Sroberto ) 344356746Sroberto{ 3444132451Sroberto u_char cs = 0; 344556746Sroberto 3446182007Sroberto#ifdef DEBUG 3447132451Sroberto if (debug > 4) 3448132451Sroberto printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len); 3449182007Sroberto#endif 3450132451Sroberto write(fd, "@@", (size_t) 2); 3451132451Sroberto write(fd, ptr, len); 3452132451Sroberto while (len--) 3453132451Sroberto cs ^= *ptr++; 3454132451Sroberto write(fd, &cs, (size_t) 1); 3455132451Sroberto write(fd, "\r\n", (size_t) 2); 3456132451Sroberto} 345756746Sroberto 345856746Sroberto 345956746Sroberto 3460132451Srobertostatic void 3461132451Srobertooncore_set_posn( 3462132451Sroberto struct instance *instance 3463132451Sroberto ) 3464132451Sroberto{ 3465132451Sroberto int mode; 3466182007Sroberto u_char Cmd[20]; 3467132451Sroberto 3468132451Sroberto /* Turn OFF position hold, it needs to be off to set position (for some units), 3469132451Sroberto will get set ON in @@Ea later */ 3470132451Sroberto 3471132451Sroberto if (instance->chan == 12) 3472132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */ 3473132451Sroberto else { 3474132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */ 3475132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */ 3476132451Sroberto } 3477132451Sroberto 3478132451Sroberto mode = instance->init_type; 3479132451Sroberto 3480132451Sroberto if (mode != 0) { /* first set posn hold position */ 3481132451Sroberto memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */ 3482132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3483132451Sroberto w32_buf(&Cmd[-2+8], (int) instance->ss_long); 3484132451Sroberto w32_buf(&Cmd[-2+12], (int) instance->ss_ht); 3485132451Sroberto Cmd[-2+16] = 0; 3486132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */ 3487132451Sroberto 3488132451Sroberto memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au)); 3489132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 3490132451Sroberto Cmd[-2+8] = 0; 3491132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */ 3492132451Sroberto 3493132451Sroberto /* next set current position */ 3494132451Sroberto 3495132451Sroberto if (instance->chan == 12) { 3496132451Sroberto memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga)); 3497132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3498132451Sroberto w32_buf(&Cmd[-2+8], (int) instance->ss_long); 3499132451Sroberto w32_buf(&Cmd[-2+12],(int) instance->ss_ht); 3500132451Sroberto Cmd[-2+16] = 0; 3501132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */ 3502132451Sroberto } else { 3503132451Sroberto memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad)); 3504132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3505132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */ 3506132451Sroberto 3507132451Sroberto memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae)); 3508132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_long); 3509132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */ 3510132451Sroberto 3511132451Sroberto memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af)); 3512132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 3513132451Sroberto Cmd[-2+8] = 0; 3514132451Sroberto oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */ 3515132451Sroberto } 3516132451Sroberto 3517132451Sroberto /* Finally, turn on position hold */ 3518132451Sroberto 3519132451Sroberto if (instance->chan == 12) 3520132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); 3521132451Sroberto else 3522132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); 3523132451Sroberto } 3524132451Sroberto} 3525132451Sroberto 3526132451Sroberto 3527132451Sroberto 3528132451Srobertostatic void 3529132451Srobertooncore_set_traim( 3530132451Sroberto struct instance *instance 3531132451Sroberto ) 3532132451Sroberto{ 3533132451Sroberto char Msg[160]; 3534132451Sroberto 3535132451Sroberto if (instance->traim_in != -1) /* set in Input */ 3536132451Sroberto instance->traim = instance->traim_in; 3537132451Sroberto else 3538132451Sroberto instance->traim = instance->traim_ck; 3539132451Sroberto 3540132451Sroberto sprintf(Msg, "Input says TRAIM = %d", instance->traim_in); 354154359Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3542132451Sroberto sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id); 3543132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3544132451Sroberto sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck); 3545132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3546132451Sroberto sprintf(Msg, "Using TRAIM = %d", instance->traim); 3547132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3548132451Sroberto 3549132451Sroberto if (instance->traim_ck == 1 && instance->traim == 0) { 3550132451Sroberto /* if it should be off, and I turned it on during testing, 3551132451Sroberto then turn it off again */ 3552132451Sroberto if (instance->chan == 6) 3553132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx)); 3554132451Sroberto else if (instance->chan == 8) 3555132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx)); 3556132451Sroberto else /* chan == 12 */ 3557132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0)); 3558182007Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3559132451Sroberto } 356056746Sroberto} 356154359Sroberto 356256746Sroberto 356356746Sroberto 356456746Sroberto/* 3565132451Sroberto * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 356656746Sroberto */ 356782498Sroberto 356856746Srobertostatic void 3569132451Srobertooncore_shmem_get_3D( 3570132451Sroberto struct instance *instance 357156746Sroberto ) 357256746Sroberto{ 3573132451Sroberto if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */ 3574132451Sroberto instance->shmem_reset = 1; 3575132451Sroberto if (instance->chan == 12) { 3576132451Sroberto if (instance->shmem_Posn == 2) 3577132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ 3578132451Sroberto else 3579132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ 3580132451Sroberto } else { 3581132451Sroberto if (instance->saw_At) { /* out of 0D -> 3D mode */ 3582132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); 3583132451Sroberto if (instance->shmem_Posn == 2) /* 3D -> 2D mode */ 3584132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 3585132451Sroberto } else 3586132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 3587132451Sroberto } 3588132451Sroberto } else if (instance->shmem_reset || (instance->mode != MODE_0D)) { 3589132451Sroberto instance->shmem_reset = 0; 3590132451Sroberto if (instance->chan == 12) 3591132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */ 3592132451Sroberto else { 3593132451Sroberto if (instance->saw_At) { 3594132451Sroberto if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */ 3595132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 3596132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ 3597132451Sroberto } else 3598132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 3599132451Sroberto } 3600132451Sroberto } 3601132451Sroberto} 360256746Sroberto 360356746Sroberto 360456746Sroberto 3605132451Sroberto/* 3606132451Sroberto * Here we do the Software SiteSurvey. 3607132451Sroberto * We have to average our own position for the Position Hold Mode 3608132451Sroberto * We use Heights from the GPS ellipsoid. 3609132451Sroberto * We check for the END of either HW or SW SiteSurvey. 3610132451Sroberto */ 361156746Sroberto 361282498Srobertostatic void 3613132451Srobertooncore_ss( 3614132451Sroberto struct instance *instance 361582498Sroberto ) 361682498Sroberto{ 3617132451Sroberto char *cp, Msg[160]; 3618132451Sroberto double lat, lon, ht; 361982498Sroberto 3620132451Sroberto 3621132451Sroberto if (instance->site_survey == ONCORE_SS_HW) { 3622132451Sroberto /* 3623132451Sroberto * Check to see if Hardware SiteSurvey has Finished. 3624132451Sroberto */ 3625132451Sroberto 3626132451Sroberto if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) || 3627132451Sroberto (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) { 3628132451Sroberto record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); 3629132451Sroberto 3630132451Sroberto if (instance->chan == 12) 3631132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax)); 3632132451Sroberto else 3633132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); 3634132451Sroberto 3635132451Sroberto cp = "SSstate = ONCORE_SS_DONE"; 3636132451Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 3637132451Sroberto instance->site_survey = ONCORE_SS_DONE; 3638132451Sroberto } 3639132451Sroberto } else { 3640132451Sroberto /* 3641132451Sroberto * Must be a Software Site Survey. 3642132451Sroberto */ 3643132451Sroberto 3644132451Sroberto if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ 3645132451Sroberto return; 3646132451Sroberto 3647132451Sroberto if (instance->mode != MODE_3D) /* Use only 3D Fixes */ 3648132451Sroberto return; 3649132451Sroberto 3650132451Sroberto instance->ss_lat += buf_w32(&instance->BEHa[15]); 3651132451Sroberto instance->ss_long += buf_w32(&instance->BEHa[19]); 3652132451Sroberto instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */ 3653132451Sroberto instance->ss_count++; 3654132451Sroberto 3655132451Sroberto if (instance->ss_count != POS_HOLD_AVERAGE) 3656132451Sroberto return; 3657132451Sroberto 3658132451Sroberto instance->ss_lat /= POS_HOLD_AVERAGE; 3659132451Sroberto instance->ss_long /= POS_HOLD_AVERAGE; 3660132451Sroberto instance->ss_ht /= POS_HOLD_AVERAGE; 3661132451Sroberto 3662132451Sroberto sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)", 3663132451Sroberto instance->ss_lat, instance->ss_long, instance->ss_ht); 3664132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3665132451Sroberto lat = instance->ss_lat/3600000.; 3666132451Sroberto lon = instance->ss_long/3600000.; 3667132451Sroberto ht = instance->ss_ht/100; 3668132451Sroberto sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)", 3669132451Sroberto lat, lon, ht); 3670132451Sroberto record_clock_stats(&(instance->peer->srcadr), Msg); 3671132451Sroberto 3672132451Sroberto oncore_set_posn(instance); 3673132451Sroberto 3674132451Sroberto record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); 3675132451Sroberto 3676132451Sroberto cp = "SSstate = ONCORE_SS_DONE"; 367782498Sroberto record_clock_stats(&(instance->peer->srcadr), cp); 3678132451Sroberto instance->site_survey = ONCORE_SS_DONE; 367982498Sroberto } 368082498Sroberto} 368182498Sroberto 3682132451Sroberto 3683132451Sroberto 3684132451Srobertostatic int 3685132451Srobertooncore_wait_almanac( 3686132451Sroberto struct instance *instance 3687132451Sroberto ) 3688132451Sroberto{ 3689132451Sroberto if (instance->rsm.bad_almanac) { 3690182007Sroberto#ifdef DEBUG 3691132451Sroberto if (debug) 3692132451Sroberto printf("ONCORE[%d]: waiting for almanac\n", instance->unit); 3693182007Sroberto#endif 3694132451Sroberto 3695132451Sroberto /* 3696132451Sroberto * If we get here (first time) then we don't have an almanac in memory. 3697132451Sroberto * Check if we have a SHMEM, and if so try to load whatever is there. 3698132451Sroberto */ 3699132451Sroberto 3700132451Sroberto if (!instance->almanac_from_shmem) { 3701132451Sroberto instance->almanac_from_shmem = 1; 3702132451Sroberto oncore_load_almanac(instance); 3703132451Sroberto } 3704132451Sroberto return(1); 3705132451Sroberto } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn 3706132451Sroberto commands, and can finally check for TRAIM. Again, we set a delay 3707132451Sroberto (5sec) and wait for things to settle down */ 3708132451Sroberto 3709132451Sroberto if (instance->chan == 6) 3710132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); 3711132451Sroberto else if (instance->chan == 8) 3712132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En)); 3713132451Sroberto else if (instance->chan == 12) { 3714132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */ 3715132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */ 3716132451Sroberto oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */ 3717132451Sroberto } 3718132451Sroberto instance->traim_delay = 1; 3719132451Sroberto 3720132451Sroberto record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC"); 3721132451Sroberto 3722132451Sroberto instance->o_state = ONCORE_RUN; 3723132451Sroberto record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN"); 3724132451Sroberto } 3725132451Sroberto return(0); 3726132451Sroberto} 3727132451Sroberto 3728132451Sroberto 3729132451Sroberto 373054359Sroberto#else 373154359Srobertoint refclock_oncore_bs; 373254359Sroberto#endif /* REFCLOCK */ 3733