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 14290001Sglebius * 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 * -------------------------------------------------------------------------- 55290001Sglebius * Reg Clemens (June 2009) 56290001Sglebius * BUG[1220] OK, big patch, but mostly done mechanically. Change direct calls to write 57290001Sglebius * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog. 58290001Sglebius * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New 59290001Sglebius * routine oncore_log. 60290001Sglebius * -------------------------------------------------------------------------- 61290001Sglebius * Reg Clemens (June 2009) 62290001Sglebius * BUG[1218] The comment on where the oncore driver gets its input file does not 63290001Sglebius * agree with the code. Change the comment. 64290001Sglebius * -------------------------------------------------------------------------- 65290001Sglebius * Reg Clemens (June 2009) 66290001Sglebius * change exit statements to return(0) in main program. I had assumed that if the 67290001Sglebius * PPS driver did not start for some reason, we shuould stop NTPD itelf. Others 68290001Sglebius * disagree. We now give an ERR log message and stop this driver. 69290001Sglebius * -------------------------------------------------------------------------- 70290001Sglebius * Reg Clemens (June 2009) 71290001Sglebius * A bytes available message for the input subsystem (Debug message). 72290001Sglebius * -------------------------------------------------------------------------- 73290001Sglebius * Reg Clemens (Nov 2008) 74290001Sglebius * This code adds a message for TRAIM messages. Users often worry about the 75290001Sglebius * driver not starting up, and it is often because of signal strength being low. 76290001Sglebius * Low signal strength will give TRAIM messages. 77290001Sglebius * -------------------------------------------------------------------------- 78290001Sglebius * Reg Clemens (Nov 2008) 79290001Sglebius * Add waiting on Almanac Message. 80290001Sglebius * -------------------------------------------------------------------------- 81290001Sglebius * Reg Clemens (Nov 2008) 82290001Sglebius * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs 83290001Sglebius * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command 84290001Sglebius * that says 'Leap Pending'. As documented it only becomes true in the month 85290001Sglebius * before the leap second is to be applied, but in practice at least some of 86290001Sglebius * the receivers turn this indicator on as soon as the message is posted, which 87290001Sglebius * can be 6months early. As such, we use the Bj command to turn on the 88290001Sglebius * instance->pp->leap indicator but only run this test in December and June for 89290001Sglebius * updates on 1Jan and 1July. 90290001Sglebius * 91290001Sglebius * The @@Gj command exists in later ONCOREs, and it gives the exact date 92290001Sglebius * and size of the Leap Update. It can be emulated in the VP using the @@Bl 93290001Sglebius * command which reads the raw Satellite Broadcast Messages. 94290001Sglebius * We use these two commands to print informative messages in the clockstats 95290001Sglebius * file once per day as soon as the message appears on the satellites. 96290001Sglebius * -------------------------------------------------------------------------- 97182007Sroberto * Reg Clemens (Feb 2006) 98182007Sroberto * Fix some gcc4 compiler complaints 99182007Sroberto * Fix possible segfault in oncore_init_shmem 100182007Sroberto * change all (possible) fprintf(stderr, to record_clock_stats 101182007Sroberto * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct 102182007Sroberto * immediately after new Almanac Read. 103182007Sroberto * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it> 104182007Sroberto * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or 105182007Sroberto * the new one. Compiles depending on timepps.h seen. 106182007Sroberto * -------------------------------------------------------------------------- 107182007Sroberto * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds 108182007Sroberto * (the oncore driver was setting the wrong ntpd variable) 109182007Sroberto * -------------------------------------------------------------------------- 110182007Sroberto * Reg.Clemens (Mar 2004) 111182007Sroberto * Support for interfaces other than PPSAPI removed, for Solaris, SunOS, 112182007Sroberto * SCO, you now need to use one of the timepps.h files in the root dir. 113182007Sroberto * this driver will 'grab' it for you if you dont have one in /usr/include 114182007Sroberto * -------------------------------------------------------------------------- 11554359Sroberto * This code uses the two devices 11682498Sroberto * /dev/oncore.serial.n 11782498Sroberto * /dev/oncore.pps.n 11854359Sroberto * which may be linked to the same device. 11954359Sroberto * and can read initialization data from the file 12082498Sroberto * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where 12182498Sroberto * n or N are the unit number, viz 127.127.30.N. 12254359Sroberto * -------------------------------------------------------------------------- 12354359Sroberto * Reg.Clemens <reg@dwf.com> Sep98. 12454359Sroberto * Original code written for FreeBSD. 12582498Sroberto * With these mods it works on FreeBSD, SunOS, Solaris and Linux 12682498Sroberto * (SunOS 4.1.3 + ppsclock) 12782498Sroberto * (Solaris7 + MU4) 12882498Sroberto * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). 12954359Sroberto * 13054359Sroberto * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the 13154359Sroberto * state machine state) are printed to CLOCKSTATS if that file is enabled 13254359Sroberto * in /etc/ntp.conf. 13354359Sroberto * 13454359Sroberto * -------------------------------------------------------------------------- 13582498Sroberto * 13654359Sroberto * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) 13754359Sroberto * doing an average of 10000 valid 2D and 3D fixes is what the automatic 13854359Sroberto * site survey mode does. Looking at the output from the receiver 13954359Sroberto * it seems like it is only using 3D fixes. 14054359Sroberto * When we do it ourselves, take 10000 3D fixes. 14154359Sroberto */ 14254359Sroberto 14354359Sroberto#define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ 14454359Sroberto 14556746Sroberto/* 14656746Sroberto * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a 14756746Sroberto * "STATUS" line in the oncore config file, which contains the most recent 14882498Sroberto * copy of all types of messages we recognize. This file can be mmap(2)'ed 14956746Sroberto * by monitoring and statistics programs. 15082498Sroberto * 15182498Sroberto * See separate HTML documentation for this option. 15256746Sroberto */ 15356746Sroberto 15454359Sroberto#ifdef HAVE_CONFIG_H 15554359Sroberto#include <config.h> 15654359Sroberto#endif 15754359Sroberto 158182007Sroberto#if defined(REFCLOCK) && defined(CLOCK_ONCORE) 15954359Sroberto 16082498Sroberto#include "ntpd.h" 16182498Sroberto#include "ntp_io.h" 16282498Sroberto#include "ntp_unixtime.h" 16382498Sroberto#include "ntp_refclock.h" 164290001Sglebius#include "ntp_calendar.h" 16582498Sroberto#include "ntp_stdlib.h" 16682498Sroberto 16754359Sroberto#include <stdio.h> 168290001Sglebius#include <stdarg.h> 16954359Sroberto#include <ctype.h> 17054359Sroberto#include <sys/stat.h> 17156746Sroberto#ifdef ONCORE_SHMEM_STATUS 17256746Sroberto# ifdef HAVE_SYS_MMAN_H 17356746Sroberto# include <sys/mman.h> 17456746Sroberto# ifndef MAP_FAILED 17556746Sroberto# define MAP_FAILED ((u_char *) -1) 176182007Sroberto# endif /* MAP_FAILED */ 17756746Sroberto# endif /* HAVE_SYS_MMAN_H */ 17856746Sroberto#endif /* ONCORE_SHMEM_STATUS */ 17954359Sroberto 18054359Sroberto#ifdef HAVE_PPSAPI 181182007Sroberto# include "ppsapi_timepps.h" 18254359Sroberto#endif 18354359Sroberto 184290001Sglebiusstruct Bl { 185290001Sglebius int dt_ls; 186290001Sglebius int dt_lsf; 187290001Sglebius int WN; 188290001Sglebius int DN; 189290001Sglebius int WN_lsf; 190290001Sglebius int DN_lsf; 191290001Sglebius int wn_flg; 192290001Sglebius int lsf_flg; 193290001Sglebius int Bl_day; 194290001Sglebius} Bl; 19556746Sroberto 19654359Srobertoenum receive_state { 19754359Sroberto ONCORE_NO_IDEA, 198132451Sroberto ONCORE_CHECK_ID, 199132451Sroberto ONCORE_CHECK_CHAN, 200132451Sroberto ONCORE_HAVE_CHAN, 20154359Sroberto ONCORE_RESET_SENT, 20254359Sroberto ONCORE_TEST_SENT, 20382498Sroberto ONCORE_INIT, 20454359Sroberto ONCORE_ALMANAC, 20554359Sroberto ONCORE_RUN 20654359Sroberto}; 20754359Sroberto 20854359Srobertoenum site_survey_state { 20954359Sroberto ONCORE_SS_UNKNOWN, 21082498Sroberto ONCORE_SS_TESTING, 21154359Sroberto ONCORE_SS_HW, 21254359Sroberto ONCORE_SS_SW, 21354359Sroberto ONCORE_SS_DONE 21454359Sroberto}; 21554359Sroberto 216132451Srobertoenum antenna_state { 217132451Sroberto ONCORE_ANTENNA_UNKNOWN = -1, 218132451Sroberto ONCORE_ANTENNA_OK = 0, 219132451Sroberto ONCORE_ANTENNA_OC = 1, 220132451Sroberto ONCORE_ANTENNA_UC = 2, 221132451Sroberto ONCORE_ANTENNA_NV = 3 222132451Sroberto}; 223132451Sroberto 22482498Sroberto/* Model Name, derived from the @@Cj message. 22582498Sroberto * Used to initialize some variables. 22682498Sroberto */ 22782498Sroberto 22882498Srobertoenum oncore_model { 22982498Sroberto ONCORE_BASIC, 23082498Sroberto ONCORE_PVT6, 23182498Sroberto ONCORE_VP, 23282498Sroberto ONCORE_UT, 23382498Sroberto ONCORE_UTPLUS, 23482498Sroberto ONCORE_GT, 23582498Sroberto ONCORE_GTPLUS, 23682498Sroberto ONCORE_SL, 23782498Sroberto ONCORE_M12, 23882498Sroberto ONCORE_UNKNOWN 23982498Sroberto}; 24082498Sroberto 24182498Sroberto/* the bits that describe these properties are in the same place 24282498Sroberto * on the VP/UT, but have moved on the M12. As such we extract 24382498Sroberto * them, and use them from this struct. 24482498Sroberto * 24582498Sroberto */ 24682498Sroberto 24782498Srobertostruct RSM { 24882498Sroberto u_char posn0D; 24982498Sroberto u_char posn2D; 25082498Sroberto u_char posn3D; 25182498Sroberto u_char bad_almanac; 25282498Sroberto u_char bad_fix; 25382498Sroberto}; 25482498Sroberto 25582498Sroberto/* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to 25682498Sroberto * see what mode it is in. The bits on the M12 are multiplexed with 25782498Sroberto * other messages, so we have to 'keep' the last known mode here. 25882498Sroberto */ 25982498Sroberto 26082498Srobertoenum posn_mode { 26182498Sroberto MODE_UNKNOWN, 26282498Sroberto MODE_0D, 26382498Sroberto MODE_2D, 26482498Sroberto MODE_3D 26582498Sroberto}; 26682498Sroberto 26754359Srobertostruct instance { 26854359Sroberto int unit; /* 127.127.30.unit */ 26982498Sroberto struct refclockproc *pp; 27082498Sroberto struct peer *peer; 27182498Sroberto 27254359Sroberto int ttyfd; /* TTY file descriptor */ 27354359Sroberto int ppsfd; /* PPS file descriptor */ 274132451Sroberto int shmemfd; /* Status shm descriptor */ 27554359Sroberto pps_handle_t pps_h; 27654359Sroberto pps_params_t pps_p; 27754359Sroberto enum receive_state o_state; /* Receive state */ 27882498Sroberto enum posn_mode mode; /* 0D, 2D, 3D */ 27954359Sroberto enum site_survey_state site_survey; /* Site Survey state */ 280132451Sroberto enum antenna_state ant_state; /* antenna state */ 28154359Sroberto 28254359Sroberto int Bj_day; 28354359Sroberto 28482498Sroberto u_long delay; /* ns */ 28554359Sroberto long offset; /* ns */ 28654359Sroberto 28782498Sroberto u_char *shmem; 28882498Sroberto char *shmem_fname; 28982498Sroberto u_int shmem_Cb; 29082498Sroberto u_int shmem_Ba; 29182498Sroberto u_int shmem_Ea; 29282498Sroberto u_int shmem_Ha; 29382498Sroberto u_char shmem_reset; 29482498Sroberto u_char shmem_Posn; 295132451Sroberto u_char shmem_bad_Ea; 296132451Sroberto u_char almanac_from_shmem; 29782498Sroberto 29854359Sroberto double ss_lat; 29954359Sroberto double ss_long; 30054359Sroberto double ss_ht; 30182498Sroberto double dH; 30254359Sroberto int ss_count; 30382498Sroberto u_char posn_set; 30454359Sroberto 30582498Sroberto enum oncore_model model; 30682498Sroberto u_int version; 30782498Sroberto u_int revision; 30882498Sroberto 30982498Sroberto u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ 310182007Sroberto s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */ 311132451Sroberto /* the following 7 are all timing counters */ 31282498Sroberto u_char traim_delay; /* seconds counter, waiting for reply */ 313132451Sroberto u_char count; /* cycles thru Ea before starting */ 314132451Sroberto u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */ 315132451Sroberto u_char count2; /* cycles thru Ea after count, to check for @@Ea */ 316132451Sroberto u_char count3; /* cycles thru Ea checking for # channels */ 317132451Sroberto u_char count4; /* cycles thru leap after Gj to issue Bj */ 318182007Sroberto u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */ 319182007Sroberto u_char count5_set; /* only set count5 once */ 320290001Sglebius u_char counta; /* count for waiting on almanac message */ 321132451Sroberto u_char pollcnt; 322132451Sroberto u_char timeout; /* count to retry Cj after Fa self-test */ 323290001Sglebius u_char max_len; /* max length message seen by oncore_log, for debugging */ 324290001Sglebius u_char max_count; /* count for message statistics */ 32582498Sroberto 32682498Sroberto struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ 327290001Sglebius struct Bl Bl; /* Satellite Broadcast Data Message */ 32882498Sroberto u_char printed; 32982498Sroberto u_char polled; 330132451Sroberto u_long ev_serial; 331290001Sglebius unsigned Rcvptr; 33254359Sroberto u_char Rcvbuf[500]; 333132451Sroberto u_char BEHa[160]; /* Ba, Ea or Ha */ 334132451Sroberto u_char BEHn[80]; /* Bn , En , or Hn */ 33554359Sroberto u_char Cj[300]; 336132451Sroberto u_char Ag; /* Satellite mask angle */ 337132451Sroberto u_char saw_At; 338132451Sroberto u_char saw_Ay; 339132451Sroberto u_char saw_Az; 340290001Sglebius s_char saw_Bj; 341132451Sroberto s_char saw_Gj; 34282498Sroberto u_char have_dH; 34354359Sroberto u_char init_type; 34454359Sroberto s_char saw_tooth; 345132451Sroberto s_char chan_in; /* chan number from INPUT, will always use it */ 346132451Sroberto u_char chan_id; /* chan number determined from part number */ 347132451Sroberto u_char chan_ck; /* chan number determined by sending commands to hardware */ 348182007Sroberto s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */ 349132451Sroberto s_char traim_id; /* TRAIM determined from part number */ 350132451Sroberto u_char traim_ck; /* TRAIM determined by sending commands to hardware */ 351132451Sroberto u_char once; /* one pass code at top of BaEaHa */ 35282498Sroberto s_char assert; 353132451Sroberto u_char hardpps; 354290001Sglebius s_char pps_control; /* PPS control, M12 only */ 355290001Sglebius s_char pps_control_msg_seen; 35654359Sroberto}; 35754359Sroberto 35854359Sroberto#define rcvbuf instance->Rcvbuf 35954359Sroberto#define rcvptr instance->Rcvptr 36054359Sroberto 361290001Sglebiusstatic int oncore_start (int, struct peer *); 362290001Sglebiusstatic void oncore_poll (int, struct peer *); 363290001Sglebiusstatic void oncore_shutdown (int, struct peer *); 364290001Sglebiusstatic void oncore_consume (struct instance *); 365290001Sglebiusstatic void oncore_read_config (struct instance *); 366290001Sglebiusstatic void oncore_receive (struct recvbuf *); 367290001Sglebiusstatic int oncore_ppsapi (struct instance *); 368290001Sglebiusstatic void oncore_get_timestamp (struct instance *, long, long); 369290001Sglebiusstatic void oncore_init_shmem (struct instance *); 37054359Sroberto 371290001Sglebiusstatic void oncore_antenna_report (struct instance *, enum antenna_state); 372290001Sglebiusstatic void oncore_chan_test (struct instance *); 373290001Sglebiusstatic void oncore_check_almanac (struct instance *); 374290001Sglebiusstatic void oncore_check_antenna (struct instance *); 375290001Sglebiusstatic void oncore_check_leap_sec (struct instance *); 376290001Sglebiusstatic int oncore_checksum_ok (u_char *, int); 377290001Sglebiusstatic void oncore_compute_dH (struct instance *); 378290001Sglebiusstatic void oncore_load_almanac (struct instance *); 379290001Sglebiusstatic void oncore_log (struct instance *, int, const char *); 380290001Sglebiusstatic int oncore_log_f (struct instance *, int, const char *, ...) 381290001Sglebius NTP_PRINTF(3, 4); 382290001Sglebiusstatic void oncore_print_Cb (struct instance *, u_char *); 383290001Sglebius/* static void oncore_print_array (u_char *, int); */ 384290001Sglebiusstatic void oncore_print_posn (struct instance *); 385290001Sglebiusstatic void oncore_sendmsg (struct instance *, u_char *, size_t); 386290001Sglebiusstatic void oncore_set_posn (struct instance *); 387290001Sglebiusstatic void oncore_set_traim (struct instance *); 388290001Sglebiusstatic void oncore_shmem_get_3D (struct instance *); 389290001Sglebiusstatic void oncore_ss (struct instance *); 390290001Sglebiusstatic int oncore_wait_almanac (struct instance *); 391132451Sroberto 392290001Sglebiusstatic void oncore_msg_any (struct instance *, u_char *, size_t, int); 393290001Sglebiusstatic void oncore_msg_Adef (struct instance *, u_char *, size_t); 394290001Sglebiusstatic void oncore_msg_Ag (struct instance *, u_char *, size_t); 395290001Sglebiusstatic void oncore_msg_As (struct instance *, u_char *, size_t); 396290001Sglebiusstatic void oncore_msg_At (struct instance *, u_char *, size_t); 397290001Sglebiusstatic void oncore_msg_Ay (struct instance *, u_char *, size_t); 398290001Sglebiusstatic void oncore_msg_Az (struct instance *, u_char *, size_t); 399290001Sglebiusstatic void oncore_msg_BaEaHa (struct instance *, u_char *, size_t); 400290001Sglebiusstatic void oncore_msg_Bd (struct instance *, u_char *, size_t); 401290001Sglebiusstatic void oncore_msg_Bj (struct instance *, u_char *, size_t); 402290001Sglebiusstatic void oncore_msg_Bl (struct instance *, u_char *, size_t); 403290001Sglebiusstatic void oncore_msg_BnEnHn (struct instance *, u_char *, size_t); 404290001Sglebiusstatic void oncore_msg_CaFaIa (struct instance *, u_char *, size_t); 405290001Sglebiusstatic void oncore_msg_Cb (struct instance *, u_char *, size_t); 406290001Sglebiusstatic void oncore_msg_Cf (struct instance *, u_char *, size_t); 407290001Sglebiusstatic void oncore_msg_Cj (struct instance *, u_char *, size_t); 408290001Sglebiusstatic void oncore_msg_Cj_id (struct instance *, u_char *, size_t); 409290001Sglebiusstatic void oncore_msg_Cj_init (struct instance *, u_char *, size_t); 410290001Sglebiusstatic void oncore_msg_Ga (struct instance *, u_char *, size_t); 411290001Sglebiusstatic void oncore_msg_Gb (struct instance *, u_char *, size_t); 412290001Sglebiusstatic void oncore_msg_Gc (struct instance *, u_char *, size_t); 413290001Sglebiusstatic void oncore_msg_Gj (struct instance *, u_char *, size_t); 414290001Sglebiusstatic void oncore_msg_Sz (struct instance *, u_char *, size_t); 41554359Sroberto 41654359Srobertostruct refclock refclock_oncore = { 41754359Sroberto oncore_start, /* start up driver */ 41854359Sroberto oncore_shutdown, /* shut down driver */ 41954359Sroberto oncore_poll, /* transmit poll message */ 42054359Sroberto noentry, /* not used */ 42154359Sroberto noentry, /* not used */ 422182007Sroberto noentry, /* not used */ 42354359Sroberto NOFLAGS /* not used */ 42454359Sroberto}; 42554359Sroberto 42654359Sroberto/* 42754359Sroberto * Understanding the next bit here is not easy unless you have a manual 42882498Sroberto * for the the various Oncore Models. 42954359Sroberto */ 43054359Sroberto 43156746Srobertostatic struct msg_desc { 43254359Sroberto const char flag[3]; 43354359Sroberto const int len; 434290001Sglebius void (*handler) (struct instance *, u_char *, size_t); 43554359Sroberto const char *fmt; 43656746Sroberto int shmem; 43754359Sroberto} oncore_messages[] = { 43882498Sroberto /* Ea and En first since they're most common */ 439290001Sglebius { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC", 0 }, 440290001Sglebius { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC", 0 }, 441290001Sglebius { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC", 0 }, 442290001Sglebius { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC", 0 }, 443290001Sglebius { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC", 0 }, 444290001Sglebius { "Hn", 78, oncore_msg_BnEnHn, "", 0 }, 445290001Sglebius { "Ab", 10, 0, "", 0 }, 446290001Sglebius { "Ac", 11, 0, "", 0 }, 447290001Sglebius { "Ad", 11, oncore_msg_Adef, "", 0 }, 448290001Sglebius { "Ae", 11, oncore_msg_Adef, "", 0 }, 449290001Sglebius { "Af", 15, oncore_msg_Adef, "", 0 }, 450290001Sglebius { "Ag", 8, oncore_msg_Ag, "", 0 }, /* Satellite mask angle */ 451290001Sglebius { "As", 20, oncore_msg_As, "", 0 }, 452290001Sglebius { "At", 8, oncore_msg_At, "", 0 }, 453290001Sglebius { "Au", 12, 0, "", 0 }, 454290001Sglebius { "Av", 8, 0, "", 0 }, 455290001Sglebius { "Aw", 8, 0, "", 0 }, 456290001Sglebius { "Ay", 11, oncore_msg_Ay, "", 0 }, 457290001Sglebius { "Az", 11, oncore_msg_Az, "", 0 }, 458290001Sglebius { "AB", 8, 0, "", 0 }, 459290001Sglebius { "Bb", 92, 0, "", 0 }, 460290001Sglebius { "Bd", 23, oncore_msg_Bd, "", 0 }, 461290001Sglebius { "Bj", 8, oncore_msg_Bj, "", 0 }, 462290001Sglebius { "Bl", 41, oncore_msg_Bl, "", 0 }, 463290001Sglebius { "Ca", 9, oncore_msg_CaFaIa, "", 0 }, 464290001Sglebius { "Cb", 33, oncore_msg_Cb, "", 0 }, 465290001Sglebius { "Cf", 7, oncore_msg_Cf, "", 0 }, 466290001Sglebius { "Cg", 8, 0, "", 0 }, 467290001Sglebius { "Ch", 9, 0, "", 0 }, 468290001Sglebius { "Cj", 294, oncore_msg_Cj, "", 0 }, 469290001Sglebius { "Ek", 71, 0, "", 0 }, 470290001Sglebius { "Fa", 9, oncore_msg_CaFaIa, "", 0 }, 471290001Sglebius { "Ga", 20, oncore_msg_Ga, "", 0 }, 472290001Sglebius { "Gb", 17, oncore_msg_Gb, "", 0 }, 473290001Sglebius { "Gc", 8, oncore_msg_Gc, "", 0 }, 474290001Sglebius { "Gd", 8, 0, "", 0 }, 475290001Sglebius { "Ge", 8, 0, "", 0 }, 476290001Sglebius { "Gj", 21, oncore_msg_Gj, "", 0 }, 477290001Sglebius { "Ia", 10, oncore_msg_CaFaIa, "", 0 }, 478290001Sglebius { "Sz", 8, oncore_msg_Sz, "", 0 }, 479290001Sglebius { {0}, 7, 0, "", 0 } 48054359Sroberto}; 48154359Sroberto 48254359Sroberto 483132451Srobertostatic u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */ 484132451Srobertostatic u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */ 485132451Srobertostatic u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */ 486132451Srobertostatic u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */ 487132451Srobertostatic u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */ 488132451Srobertostatic u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */ 489132451Srobertostatic u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */ 490132451Srobertostatic u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */ 491132451Srobertostatic u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */ 492132451Srobertostatic 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 */ 493132451Srobertostatic u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */ 494132451Sroberto 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */ 495132451Sroberto 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */ 496132451Srobertostatic u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */ 497132451Srobertostatic u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */ 498132451Srobertostatic u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */ 499132451Srobertostatic u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */ 500132451Srobertostatic u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */ 501132451Srobertostatic u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */ 502132451Srobertostatic u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */ 503132451Srobertostatic u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */ 504132451Srobertostatic u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */ 505132451Srobertostatic u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */ 506132451Srobertostatic u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */ 507132451Srobertostatic u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */ 508132451Srobertostatic u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */ 509132451Srobertostatic u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */ 510132451Srobertostatic u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */ 511132451Srobertostatic u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */ 512132451Srobertostatic u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */ 513132451Srobertostatic u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */ 514290001Sglebiusstatic u_char oncore_cmd_Bl[] = { 'B', 'l', 1 }; /* VP Satellite Broadcast Data Msg */ 515132451Srobertostatic 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 */ 516182007Srobertostatic 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 */ 517182007Srobertostatic 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 */ 518132451Srobertostatic u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */ 519132451Srobertostatic u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */ 520132451Srobertostatic u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */ 521132451Srobertostatic u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */ 522132451Srobertostatic u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */ 523132451Srobertostatic u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */ 524132451Srobertostatic u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */ 525132451Srobertostatic 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 */ 526182007Srobertostatic 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 */ 527182007Srobertostatic 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 */ 528132451Srobertostatic u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */ 529132451Srobertostatic u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */ 530132451Srobertostatic u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */ 531132451Sroberto 0xff, 0xff, 0xff, 0xff, /* */ 532132451Sroberto 0xff, 0xff, 0xff, 0xff, 0xff }; /* */ 533132451Srobertostatic u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */ 534290001Sglebiusstatic u_char oncore_cmd_Gc[] = { 'G', 'c', 0 }; /* 12 PPS Control: Off, On, 1+satellite,TRAIM */ 535132451Srobertostatic u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */ 536132451Srobertostatic u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */ 537132451Srobertostatic u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */ 538132451Srobertostatic u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */ 539132451Srobertostatic u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */ 540132451Srobertostatic u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */ 541132451Srobertostatic u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */ 542132451Srobertostatic u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */ 543132451Srobertostatic u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */ 544132451Srobertostatic u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */ 545132451Srobertostatic u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */ 546132451Srobertostatic u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */ 54754359Sroberto 548132451Sroberto/* it appears that as of 1997/1998, the UT had As,At, but not Au,Av 549132451Sroberto * the GT had Au,Av, but not As,At 550132451Sroberto * This was as of v2.0 of both firmware sets. possibly 1.3 for UT. 551132451Sroberto * Bj in UT at v1.3 552132451Sroberto * dont see Bd in UT/GT thru 1999 553132451Sroberto * Gj in UT as of 3.0, 1999 , Bj as of 1.3 55454359Sroberto */ 55554359Sroberto 556182007Sroberto#define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ 557182007Sroberto#define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ 55854359Sroberto 55954359Sroberto#define SPEED B9600 /* Oncore Binary speed (9600 bps) */ 56054359Sroberto 56154359Sroberto/* 56254359Sroberto * Assemble and disassemble 32bit signed quantities from a buffer. 56354359Sroberto * 56454359Sroberto */ 56554359Sroberto 56654359Sroberto /* to buffer, int w, u_char *buf */ 56782498Sroberto#define w32_buf(buf,w) { u_int i_tmp; \ 56854359Sroberto i_tmp = (w<0) ? (~(-w)+1) : (w); \ 56954359Sroberto (buf)[0] = (i_tmp >> 24) & 0xff; \ 57054359Sroberto (buf)[1] = (i_tmp >> 16) & 0xff; \ 57154359Sroberto (buf)[2] = (i_tmp >> 8) & 0xff; \ 57254359Sroberto (buf)[3] = (i_tmp ) & 0xff; \ 57354359Sroberto } 57454359Sroberto 57554359Sroberto#define w32(buf) (((buf)[0]&0xff) << 24 | \ 57654359Sroberto ((buf)[1]&0xff) << 16 | \ 57754359Sroberto ((buf)[2]&0xff) << 8 | \ 57854359Sroberto ((buf)[3]&0xff) ) 57954359Sroberto 58054359Sroberto /* from buffer, char *buf, result to an int */ 58154359Sroberto#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) 58254359Sroberto 58356746Sroberto 58454359Sroberto/* 58554359Sroberto * oncore_start - initialize data for processing 58654359Sroberto */ 58782498Sroberto 58854359Srobertostatic int 58954359Srobertooncore_start( 59054359Sroberto int unit, 59154359Sroberto struct peer *peer 59254359Sroberto ) 59354359Sroberto{ 594182007Sroberto#define STRING_LEN 32 59554359Sroberto register struct instance *instance; 59654359Sroberto struct refclockproc *pp; 597290001Sglebius int fd1, fd2; 598290001Sglebius char device1[STRING_LEN], device2[STRING_LEN]; 599290001Sglebius#ifndef SYS_WINNT 60054359Sroberto struct stat stat1, stat2; 601290001Sglebius#endif 60254359Sroberto 603132451Sroberto /* create instance structure for this unit */ 604132451Sroberto 605290001Sglebius instance = emalloc(sizeof(*instance)); 606290001Sglebius memset(instance, 0, sizeof(*instance)); 607132451Sroberto 608132451Sroberto /* initialize miscellaneous variables */ 60954359Sroberto 61054359Sroberto pp = peer->procptr; 61182498Sroberto instance->pp = pp; 61282498Sroberto instance->unit = unit; 61382498Sroberto instance->peer = peer; 614132451Sroberto instance->assert = 1; 615132451Sroberto instance->once = 1; 61682498Sroberto 61754359Sroberto instance->Bj_day = -1; 61882498Sroberto instance->traim = -1; 619132451Sroberto instance->traim_in = -1; 620132451Sroberto instance->chan_in = -1; 621290001Sglebius instance->pps_control = -1; /* PPS control, M12 only */ 622290001Sglebius instance->pps_control_msg_seen = -1; /* Have seen response to Gc msg */ 62382498Sroberto instance->model = ONCORE_UNKNOWN; 62482498Sroberto instance->mode = MODE_UNKNOWN; 62582498Sroberto instance->site_survey = ONCORE_SS_UNKNOWN; 626132451Sroberto instance->Ag = 0xff; /* Satellite mask angle, unset by user */ 627132451Sroberto instance->ant_state = ONCORE_ANTENNA_UNKNOWN; 62854359Sroberto 629290001Sglebius peer->flags &= ~FLAG_PPS; /* PPS not active yet */ 63082498Sroberto peer->precision = -26; 63182498Sroberto peer->minpoll = 4; 63282498Sroberto peer->maxpoll = 4; 63382498Sroberto pp->clockdesc = "Motorola Oncore GPS Receiver"; 63482498Sroberto memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); 63582498Sroberto 636290001Sglebius oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING"); 637182007Sroberto instance->o_state = ONCORE_NO_IDEA; 638290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_NO_IDEA"); 63954359Sroberto 640182007Sroberto /* Now open files. 641182007Sroberto * This is a bit complicated, a we dont want to open the same file twice 642182007Sroberto * (its a problem on some OS), and device2 may not exist for the new PPS 643182007Sroberto */ 644182007Sroberto 645290001Sglebius (void)snprintf(device1, sizeof(device1), DEVICE1, unit); 646290001Sglebius (void)snprintf(device2, sizeof(device2), DEVICE2, unit); 647182007Sroberto 648182007Sroberto /* OPEN DEVICES */ 649182007Sroberto /* opening different devices for fd1 and fd2 presents no problems */ 650182007Sroberto /* opening the SAME device twice, seems to be OS dependent. 651182007Sroberto (a) on Linux (no streams) no problem 652182007Sroberto (b) on SunOS (and possibly Solaris, untested), (streams) 653182007Sroberto never see the line discipline. 654182007Sroberto Since things ALWAYS work if we only open the device once, we check 655182007Sroberto to see if the two devices are in fact the same, then proceed to 656182007Sroberto do one open or two. 657290001Sglebius 658290001Sglebius For use with linuxPPS we assume that the N_TTY file has been opened 659290001Sglebius and that the line discipline has been changed to N_PPS by another 660290001Sglebius program (say ppsldisc) so that the two files expected by the oncore 661290001Sglebius driver can be opened. 662290001Sglebius 663290001Sglebius Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do 664290001Sglebius the stat below without error even though the file has already had its 665290001Sglebius line discipline changed by another process. 666290001Sglebius 667290001Sglebius The Windows port of ntpd arranges to return duplicate handles for 668290001Sglebius multiple opens of the same serial device, and doesn't have inodes 669290001Sglebius for serial handles, so we just open both on Windows. 670182007Sroberto */ 671290001Sglebius#ifndef SYS_WINNT 672182007Sroberto if (stat(device1, &stat1)) { 673290001Sglebius oncore_log_f(instance, LOG_ERR, "Can't stat fd1 (%s)", 674290001Sglebius device1); 675290001Sglebius return(0); /* exit, no file, can't start driver */ 67654359Sroberto } 67754359Sroberto 678182007Sroberto if (stat(device2, &stat2)) { 679290001Sglebius stat2.st_dev = stat2.st_ino = -2; 680290001Sglebius oncore_log_f(instance, LOG_ERR, "Can't stat fd2 (%s) %d %m", 681290001Sglebius device2, errno); 682182007Sroberto } 683290001Sglebius#endif /* !SYS_WINNT */ 684132451Sroberto 685290001Sglebius fd1 = refclock_open(device1, SPEED, LDISC_RAW); 686290001Sglebius if (fd1 <= 0) { 687290001Sglebius oncore_log_f(instance, LOG_ERR, "Can't open fd1 (%s)", 688290001Sglebius device1); 689290001Sglebius return(0); /* exit, can't open file, can't start driver */ 690132451Sroberto } 691132451Sroberto 692290001Sglebius /* for LINUX the PPS device is the result of a line discipline. 693290001Sglebius It seems simplest to let an external program create the appropriate 694290001Sglebius /dev/pps<n> file, and only check (carefully) for its existance here 695290001Sglebius */ 696290001Sglebius 697290001Sglebius#ifndef SYS_WINNT 698182007Sroberto if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */ 699182007Sroberto fd2 = fd1; 700290001Sglebius else 701290001Sglebius#endif /* !SYS_WINNT */ 702290001Sglebius { /* different devices here */ 703290001Sglebius if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) { 704290001Sglebius oncore_log_f(instance, LOG_ERR, 705290001Sglebius "Can't open fd2 (%s)", device2); 706290001Sglebius return(0); /* exit, can't open PPS file, can't start driver */ 707182007Sroberto } 708182007Sroberto } 709182007Sroberto 710290001Sglebius /* open ppsapi source */ 711182007Sroberto 712290001Sglebius if (time_pps_create(fd2, &instance->pps_h) < 0) { 713290001Sglebius oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel"); 714290001Sglebius return(0); /* exit, don't find PPSAPI in kernel */ 715182007Sroberto } 716182007Sroberto 717182007Sroberto /* continue initialization */ 718182007Sroberto 719182007Sroberto instance->ttyfd = fd1; 720182007Sroberto instance->ppsfd = fd2; 721182007Sroberto 722182007Sroberto /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */ 723182007Sroberto 724182007Sroberto oncore_read_config(instance); 725182007Sroberto 726132451Sroberto if (!oncore_ppsapi(instance)) 727132451Sroberto return(0); 728132451Sroberto 729132451Sroberto pp->io.clock_recv = oncore_receive; 730290001Sglebius pp->io.srcclock = peer; 731132451Sroberto pp->io.datalen = 0; 732132451Sroberto pp->io.fd = fd1; 733132451Sroberto if (!io_addclock(&pp->io)) { 734290001Sglebius oncore_log(instance, LOG_ERR, "can't do io_addclock"); 735290001Sglebius close(fd1); 736290001Sglebius pp->io.fd = -1; 737132451Sroberto free(instance); 738132451Sroberto return (0); 739132451Sroberto } 740290001Sglebius pp->unitptr = instance; 741132451Sroberto 742132451Sroberto#ifdef ONCORE_SHMEM_STATUS 743132451Sroberto /* 744132451Sroberto * Before starting ONCORE, lets setup SHMEM 745132451Sroberto * This will include merging an old SHMEM into the new one if 746132451Sroberto * an old one is found. 747132451Sroberto */ 748132451Sroberto 749132451Sroberto oncore_init_shmem(instance); 750132451Sroberto#endif 751132451Sroberto 752132451Sroberto /* 753132451Sroberto * This will return the Model of the Oncore receiver. 754132451Sroberto * and start the Initialization loop in oncore_msg_Cj. 755132451Sroberto */ 756132451Sroberto 757132451Sroberto instance->o_state = ONCORE_CHECK_ID; 758290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID"); 759132451Sroberto 760132451Sroberto instance->timeout = 4; 761290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ 762290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 763132451Sroberto 764132451Sroberto instance->pollcnt = 2; 765132451Sroberto return (1); 766132451Sroberto} 767132451Sroberto 768132451Sroberto 769132451Sroberto/* 770132451Sroberto * oncore_shutdown - shut down the clock 771132451Sroberto */ 772132451Sroberto 773132451Srobertostatic void 774132451Srobertooncore_shutdown( 775132451Sroberto int unit, 776132451Sroberto struct peer *peer 777132451Sroberto ) 778132451Sroberto{ 779132451Sroberto register struct instance *instance; 780132451Sroberto struct refclockproc *pp; 781132451Sroberto 782132451Sroberto pp = peer->procptr; 783290001Sglebius instance = pp->unitptr; 784132451Sroberto 785290001Sglebius if (pp->io.fd != -1) 786290001Sglebius io_closeclock(&pp->io); 787132451Sroberto 788290001Sglebius if (instance != NULL) { 789290001Sglebius time_pps_destroy (instance->pps_h); 790182007Sroberto 791290001Sglebius close(instance->ttyfd); 792182007Sroberto 793290001Sglebius if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd)) 794290001Sglebius close(instance->ppsfd); 795182007Sroberto 796290001Sglebius if (instance->shmemfd) 797290001Sglebius close(instance->shmemfd); 798182007Sroberto 799290001Sglebius free(instance); 800290001Sglebius } 801132451Sroberto} 802132451Sroberto 803132451Sroberto 804132451Sroberto 805132451Sroberto/* 806132451Sroberto * oncore_poll - called by the transmit procedure 807132451Sroberto */ 808132451Sroberto 809132451Srobertostatic void 810132451Srobertooncore_poll( 811132451Sroberto int unit, 812132451Sroberto struct peer *peer 813132451Sroberto ) 814132451Sroberto{ 815132451Sroberto struct instance *instance; 816132451Sroberto 817290001Sglebius instance = peer->procptr->unitptr; 818132451Sroberto if (instance->timeout) { 819132451Sroberto instance->timeout--; 820132451Sroberto if (instance->timeout == 0) { 821290001Sglebius oncore_log(instance, LOG_ERR, 822290001Sglebius "Oncore: No response from @@Cj, shutting down driver"); 823132451Sroberto oncore_shutdown(unit, peer); 824132451Sroberto } else { 825290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 826290001Sglebius oncore_log(instance, LOG_WARNING, "Oncore: Resend @@Cj"); 827132451Sroberto } 828132451Sroberto return; 829132451Sroberto } 830132451Sroberto 831132451Sroberto if (!instance->pollcnt) 832132451Sroberto refclock_report(peer, CEVNT_TIMEOUT); 833132451Sroberto else 834132451Sroberto instance->pollcnt--; 835132451Sroberto peer->procptr->polls++; 836132451Sroberto instance->polled = 1; 837132451Sroberto} 838132451Sroberto 839132451Sroberto 840132451Sroberto 841132451Sroberto/* 842132451Sroberto * Initialize PPSAPI 843132451Sroberto */ 844132451Sroberto 845132451Srobertostatic int 846132451Srobertooncore_ppsapi( 847132451Sroberto struct instance *instance 848132451Sroberto ) 849132451Sroberto{ 850182007Sroberto int cap, mode, mode1; 851290001Sglebius const char *cp; 852132451Sroberto 853182007Sroberto if (time_pps_getcap(instance->pps_h, &cap) < 0) { 854290001Sglebius oncore_log_f(instance, LOG_ERR, "time_pps_getcap failed: %m"); 85556746Sroberto return (0); 85656746Sroberto } 85756746Sroberto 85856746Sroberto if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { 859290001Sglebius oncore_log_f(instance, LOG_ERR, "time_pps_getparams failed: %m"); 86056746Sroberto return (0); 86156746Sroberto } 86256746Sroberto 86356746Sroberto /* nb. only turn things on, if someone else has turned something 86482498Sroberto * on before we get here, leave it alone! 86556746Sroberto */ 86656746Sroberto 867182007Sroberto if (instance->assert) { 868290001Sglebius cp = "Assert"; 869182007Sroberto mode = PPS_CAPTUREASSERT; 870182007Sroberto mode1 = PPS_OFFSETASSERT; 87154359Sroberto } else { 872290001Sglebius cp = "Clear"; 873182007Sroberto mode = PPS_CAPTURECLEAR; 874182007Sroberto mode1 = PPS_OFFSETCLEAR; 87554359Sroberto } 876290001Sglebius oncore_log_f(instance, LOG_INFO, "Initializing timing to %s.", 877290001Sglebius cp); 87856746Sroberto 879182007Sroberto if (!(mode & cap)) { 880290001Sglebius oncore_log_f(instance, LOG_ERR, 881290001Sglebius "Can't set timing to %s, exiting...", cp); 882182007Sroberto return(0); 883182007Sroberto } 884182007Sroberto 885182007Sroberto if (!(mode1 & cap)) { 886290001Sglebius oncore_log_f(instance, LOG_NOTICE, 887290001Sglebius "Can't set %s, this will increase jitter.", 888290001Sglebius cp); 889182007Sroberto mode1 = 0; 890182007Sroberto } 891182007Sroberto 892182007Sroberto /* only set what is legal */ 893182007Sroberto 894182007Sroberto instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap; 895182007Sroberto 89654359Sroberto if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { 897290001Sglebius oncore_log_f(instance, LOG_ERR, "ONCORE: time_pps_setparams fails %m"); 898290001Sglebius return(0); /* exit, can't do time_pps_setparans on PPS file */ 89954359Sroberto } 90056746Sroberto 901132451Sroberto /* If HARDPPS is on, we tell kernel */ 90282498Sroberto 903132451Sroberto if (instance->hardpps) { 904132451Sroberto int i; 90582498Sroberto 906290001Sglebius oncore_log(instance, LOG_INFO, "HARDPPS Set."); 907182007Sroberto 908132451Sroberto if (instance->assert) 909132451Sroberto i = PPS_CAPTUREASSERT; 910132451Sroberto else 911132451Sroberto i = PPS_CAPTURECLEAR; 91282498Sroberto 913182007Sroberto /* we know that 'i' is legal from above */ 914182007Sroberto 915182007Sroberto if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, 916182007Sroberto PPS_TSFMT_TSPEC) < 0) { 917290001Sglebius oncore_log_f(instance, LOG_ERR, "time_pps_kcbind failed: %m"); 918290001Sglebius oncore_log(instance, LOG_ERR, "HARDPPS failed, abort..."); 919182007Sroberto return (0); 92056746Sroberto } 921290001Sglebius 922290001Sglebius hardpps_enable = 1; 92354359Sroberto } 924132451Sroberto return(1); 925132451Sroberto} 92656746Sroberto 927132451Sroberto 928132451Sroberto 929132451Sroberto#ifdef ONCORE_SHMEM_STATUS 930132451Srobertostatic void 931132451Srobertooncore_init_shmem( 932132451Sroberto struct instance *instance 933132451Sroberto ) 934132451Sroberto{ 935290001Sglebius int l, fd; 936182007Sroberto u_char *cp, *cp1, *buf, *shmem_old; 937132451Sroberto struct msg_desc *mp; 938132451Sroberto struct stat sbuf; 939290001Sglebius size_t i, n, n1, shmem_length, shmem_old_size; 940132451Sroberto 941290001Sglebius /* 942132451Sroberto * The first thing we do is see if there is an instance->shmem_fname file (still) 943132451Sroberto * out there from a previous run. If so, we copy it in and use it to initialize 944132451Sroberto * shmem (so we won't lose our almanac if we need it). 945132451Sroberto */ 946132451Sroberto 947132451Sroberto shmem_old = 0; 948182007Sroberto shmem_old_size = 0; 949132451Sroberto if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0) 950290001Sglebius oncore_log(instance, LOG_WARNING, "ONCORE: Can't open SHMEM file"); 951132451Sroberto else { 952132451Sroberto fstat(fd, &sbuf); 953132451Sroberto shmem_old_size = sbuf.st_size; 954182007Sroberto if (shmem_old_size != 0) { 955290001Sglebius shmem_old = emalloc((unsigned) sbuf.st_size); 956290001Sglebius read(fd, shmem_old, shmem_old_size); 957132451Sroberto } 958132451Sroberto close(fd); 95954359Sroberto } 96054359Sroberto 961132451Sroberto /* OK, we now create the NEW SHMEM. */ 962132451Sroberto 963132451Sroberto if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { 964290001Sglebius oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem"); 965182007Sroberto if (shmem_old) 966182007Sroberto free(shmem_old); 967182007Sroberto 968132451Sroberto return; 969132451Sroberto } 970132451Sroberto 971132451Sroberto /* see how big it needs to be */ 972132451Sroberto 973132451Sroberto n = 1; 974132451Sroberto for (mp=oncore_messages; mp->flag[0]; mp++) { 975132451Sroberto mp->shmem = n; 976132451Sroberto /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ 977132451Sroberto if (!strcmp(mp->flag, "Cb")) { 978132451Sroberto instance->shmem_Cb = n; 979132451Sroberto n += (mp->len + 3) * 34; 980132451Sroberto } 981132451Sroberto if (!strcmp(mp->flag, "Ba")) { 982132451Sroberto instance->shmem_Ba = n; 983132451Sroberto n += (mp->len + 3) * 3; 984132451Sroberto } 985132451Sroberto if (!strcmp(mp->flag, "Ea")) { 986132451Sroberto instance->shmem_Ea = n; 987132451Sroberto n += (mp->len + 3) * 3; 988132451Sroberto } 989132451Sroberto if (!strcmp(mp->flag, "Ha")) { 990132451Sroberto instance->shmem_Ha = n; 991132451Sroberto n += (mp->len + 3) * 3; 992132451Sroberto } 993132451Sroberto n += (mp->len + 3); 994132451Sroberto } 995132451Sroberto shmem_length = n + 2; 996132451Sroberto 997290001Sglebius buf = emalloc(shmem_length); 998132451Sroberto memset(buf, 0, shmem_length); 999132451Sroberto 1000132451Sroberto /* next build the new SHMEM buffer in memory */ 1001132451Sroberto 1002132451Sroberto for (mp=oncore_messages; mp->flag[0]; mp++) { 1003132451Sroberto l = mp->shmem; 1004132451Sroberto buf[l + 0] = mp->len >> 8; 1005132451Sroberto buf[l + 1] = mp->len & 0xff; 1006132451Sroberto buf[l + 2] = 0; 1007132451Sroberto buf[l + 3] = '@'; 1008132451Sroberto buf[l + 4] = '@'; 1009132451Sroberto buf[l + 5] = mp->flag[0]; 1010132451Sroberto buf[l + 6] = mp->flag[1]; 1011132451Sroberto if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { 1012132451Sroberto if (!strcmp(mp->flag, "Cb")) 1013132451Sroberto n = 35; 1014132451Sroberto else 1015132451Sroberto n = 4; 1016132451Sroberto for (i=1; i<n; i++) { 1017132451Sroberto buf[l + i * (mp->len+3) + 0] = mp->len >> 8; 1018132451Sroberto buf[l + i * (mp->len+3) + 1] = mp->len & 0xff; 1019132451Sroberto buf[l + i * (mp->len+3) + 2] = 0; 1020132451Sroberto buf[l + i * (mp->len+3) + 3] = '@'; 1021132451Sroberto buf[l + i * (mp->len+3) + 4] = '@'; 1022132451Sroberto buf[l + i * (mp->len+3) + 5] = mp->flag[0]; 1023132451Sroberto buf[l + i * (mp->len+3) + 6] = mp->flag[1]; 1024132451Sroberto } 1025132451Sroberto } 1026132451Sroberto } 1027132451Sroberto 1028132451Sroberto /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem) 1029182007Sroberto * copying the data in shmem_old to buf. 1030182007Sroberto * When we are done we write it out and free both buffers. 1031182007Sroberto * If the structure sizes dont agree, I will not copy. 1032182007Sroberto * This could be due to an addition/deletion or a problem with the disk file. 103354359Sroberto */ 103454359Sroberto 1035132451Sroberto if (shmem_old) { 1036182007Sroberto if (shmem_old_size == shmem_length) { 1037182007Sroberto for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) { 1038182007Sroberto n1 = 256*(*(cp1-3)) + *(cp1-2); 1039182007Sroberto if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4)) 1040182007Sroberto break; 104154359Sroberto 1042182007Sroberto memcpy(cp, cp1, (size_t) n); 1043182007Sroberto } 1044132451Sroberto } 1045132451Sroberto free(shmem_old); 1046132451Sroberto } 1047132451Sroberto 1048132451Sroberto i = write(instance->shmemfd, buf, shmem_length); 1049132451Sroberto free(buf); 1050132451Sroberto 1051132451Sroberto if (i != shmem_length) { 1052290001Sglebius oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem"); 1053132451Sroberto close(instance->shmemfd); 1054132451Sroberto return; 1055132451Sroberto } 1056132451Sroberto 1057132451Sroberto instance->shmem = (u_char *) mmap(0, shmem_length, 1058132451Sroberto PROT_READ | PROT_WRITE, 1059132451Sroberto#ifdef MAP_HASSEMAPHORE 1060132451Sroberto MAP_HASSEMAPHORE | 1061132451Sroberto#endif 1062132451Sroberto MAP_SHARED, instance->shmemfd, (off_t)0); 1063132451Sroberto 1064132451Sroberto if (instance->shmem == (u_char *)MAP_FAILED) { 1065132451Sroberto instance->shmem = 0; 1066132451Sroberto close(instance->shmemfd); 1067132451Sroberto return; 1068132451Sroberto } 1069132451Sroberto 1070290001Sglebius oncore_log_f(instance, LOG_NOTICE, 1071290001Sglebius "SHMEM (size = %ld) is CONFIGURED and available as %s", 1072290001Sglebius (u_long) shmem_length, instance->shmem_fname); 107354359Sroberto} 1074132451Sroberto#endif /* ONCORE_SHMEM_STATUS */ 107554359Sroberto 107656746Sroberto 107756746Sroberto 107854359Sroberto/* 107954359Sroberto * Read Input file if it exists. 108054359Sroberto */ 108182498Sroberto 108254359Srobertostatic void 108354359Srobertooncore_read_config( 108454359Sroberto struct instance *instance 108554359Sroberto ) 108654359Sroberto{ 108754359Sroberto/* 108882498Sroberto * First we try to open the configuration file 1089290001Sglebius * /etc/ntp.oncore.N 109082498Sroberto * where N is the unit number viz 127.127.30.N. 109182498Sroberto * If we don't find it we try 1092290001Sglebius * /etc/ntp.oncoreN 109382498Sroberto * and then 109482498Sroberto * /etc/ntp.oncore 109554359Sroberto * 109682498Sroberto * If we don't find any then we don't have the cable delay or PPS offset 109754359Sroberto * and we choose MODE (4) below. 109854359Sroberto * 109954359Sroberto * Five Choices for MODE 110054359Sroberto * (0) ONCORE is preinitialized, don't do anything to change it. 110154359Sroberto * nb, DON'T set 0D mode, DON'T set Delay, position... 110254359Sroberto * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. 110354359Sroberto * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, 110454359Sroberto * lock this in, go to 0D mode. 110554359Sroberto * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. 110654359Sroberto * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, 110754359Sroberto * lock this in, go to 0D mode. 110854359Sroberto * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] 110954359Sroberto * then this position is set as the INITIAL position of the ONCORE. 111054359Sroberto * This can reduce the time to first fix. 111154359Sroberto * ------------------------------------------------------------------------------- 111254359Sroberto * Note that an Oncore UT without a battery backup retains NO information if it is 111354359Sroberto * power cycled, with a Battery Backup it remembers the almanac, etc. 111454359Sroberto * For an Oncore VP, there is an eeprom that will contain this data, along with the 111554359Sroberto * option of Battery Backup. 111654359Sroberto * So a UT without Battery Backup is equivalent to doing a HARD RESET on each 111754359Sroberto * power cycle, since there is nowhere to store the data. 111854359Sroberto * ------------------------------------------------------------------------------- 111954359Sroberto * 112054359Sroberto * If we open one or the other of the files, we read it looking for 1121132451Sroberto * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS, 1122132451Sroberto * STATUS, POSN3D, POSN2D, CHAN, TRAIM 112354359Sroberto * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must 112454359Sroberto * be present or mode reverts to (2,4). 112554359Sroberto * 112654359Sroberto * Read input file. 112754359Sroberto * 112854359Sroberto * # is comment to end of line 112954359Sroberto * = allowed between 1st and 2nd fields. 113054359Sroberto * 113154359Sroberto * Expect to see one line with 'MODE' as first field, followed by an integer 113254359Sroberto * in the range 0-4 (default = 4). 113354359Sroberto * 113454359Sroberto * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. 113554359Sroberto * All numbers are floating point. 113654359Sroberto * DDD.ddd 113754359Sroberto * DDD MMM.mmm 113854359Sroberto * DDD MMM SSS.sss 113954359Sroberto * 114082498Sroberto * Expect to see one line with 'HT' as first field, 114182498Sroberto * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' 114282498Sroberto * for feet or meters. HT is the height above the GPS ellipsoid. 1143132451Sroberto * If the receiver reports height in both GPS and MSL, then we will report 114482498Sroberto * the difference GPS-MSL on the clockstats file. 114554359Sroberto * 114682498Sroberto * There is an optional line, starting with DELAY, followed 114754359Sroberto * by 1 or two fields. The first is a number (a time) the second is 114854359Sroberto * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 114982498Sroberto * DELAY is cable delay, typically a few tens of ns. 115082498Sroberto * 115182498Sroberto * There is an optional line, starting with OFFSET, followed 115282498Sroberto * by 1 or two fields. The first is a number (a time) the second is 115382498Sroberto * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 115482498Sroberto * OFFSET is the offset of the PPS pulse from 0. (only fully implemented 115554359Sroberto * with the PPSAPI, we need to be able to tell the Kernel about this 115654359Sroberto * offset if the Kernel PLL is in use, but can only do this presently 115754359Sroberto * when using the PPSAPI interface. If not using the Kernel PLL, 115854359Sroberto * then there is no problem. 115954359Sroberto * 116082498Sroberto * There is an optional line, with either ASSERT or CLEAR on it, which 116154359Sroberto * determine which transition of the PPS signal is used for timing by the 116254359Sroberto * PPSAPI. If neither is present, then ASSERT is assumed. 1163132451Sroberto * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input. 1164132451Sroberto * For Flag2, ASSERT=0, and hence is default. 116554359Sroberto * 1166132451Sroberto * There is an optional line, with HARDPPS on it. Including this line causes 1167290001Sglebius * the PPS signal to control the kernel PLL. 1168132451Sroberto * HARDPPS can also be set with FLAG3 of the ntp.conf input. 1169132451Sroberto * For Flag3, 0 is disabled, and the default. 1170132451Sroberto * 1171132451Sroberto * There are three options that have to do with using the shared memory option. 1172132451Sroberto * First, to enable the option there must be a SHMEM line with a file name. 117382498Sroberto * The file name is the file associated with the shared memory. 117482498Sroberto * 1175132451Sroberto * In shared memory, there is one 'record' for each returned variable. 1176132451Sroberto * For the @@Ea data there are three 'records' containing position data. 1177132451Sroberto * There will always be data in the record corresponding to the '0D' @@Ea record, 1178132451Sroberto * and the user has a choice of filling the '3D' record by specifying POSN3D, 1179132451Sroberto * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D' 1180132451Sroberto * record is filled once every 15s. 118182498Sroberto * 118282498Sroberto * Two additional variables that can be set are CHAN and TRAIM. These should be 118382498Sroberto * set correctly by the code examining the @@Cj record, but we bring them out here 1184132451Sroberto * to allow the user to override either the # of channels, or the existence of TRAIM. 118582498Sroberto * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be 118682498Sroberto * followed by YES or NO. 118782498Sroberto * 1188132451Sroberto * There is an optional line with MASK on it followed by one integer field in the 1189132451Sroberto * range 0 to 89. This sets the satellite mask angle and will determine the minimum 1190132451Sroberto * elevation angle for satellites to be tracked by the receiver. The default value 1191132451Sroberto * is 10 deg for the VP and 0 deg for all other receivers. 1192132451Sroberto * 1193290001Sglebius * There is an optional line with PPSCONTROL on it (only valid for M12 or M12+T 1194290001Sglebius * receivers, the option is read, but ignored for all others) 1195290001Sglebius * and it is followed by: 1196290001Sglebius * ON Turn PPS on. This is the default and the default for other 1197290001Sglebius * oncore receivers. The PPS is on even if not tracking 1198290001Sglebius * any satellites. 1199290001Sglebius * SATELLITE Turns PPS on if tracking at least 1 satellite, else off. 1200290001Sglebius * TRAIM Turns PPS on or off controlled by TRAIM. 1201290001Sglebius * The OFF option is NOT implemented, since the Oncore driver will not work 1202290001Sglebius * without the PPS signal. 1203290001Sglebius * 120454359Sroberto * So acceptable input would be 120554359Sroberto * # these are my coordinates (RWC) 120654359Sroberto * LON -106 34.610 120754359Sroberto * LAT 35 08.999 120854359Sroberto * HT 1589 # could equally well say HT 5215 FT 120954359Sroberto * DELAY 60 ns 121054359Sroberto */ 121154359Sroberto 121254359Sroberto FILE *fd; 1213290001Sglebius char *cc, *ca, line[100], units[2], device[64]; 1214290001Sglebius const char *dirs[] = { "/etc/ntp", "/etc", 0 }; 1215290001Sglebius const char *cp, **cpp; 1216132451Sroberto int i, sign, lat_flg, long_flg, ht_flg, mode, mask; 121754359Sroberto double f1, f2, f3; 121854359Sroberto 1219182007Sroberto fd = NULL; /* just to shutup gcc complaint */ 1220182007Sroberto for (cpp=dirs; *cpp; cpp++) { 1221182007Sroberto cp = *cpp; 1222290001Sglebius snprintf(device, sizeof(device), "%s/ntp.oncore.%d", 1223290001Sglebius cp, instance->unit); /* try "ntp.oncore.0 */ 1224182007Sroberto if ((fd=fopen(device, "r"))) 1225182007Sroberto break; 1226290001Sglebius snprintf(device, sizeof(device), "%s/ntp.oncore%d", 1227290001Sglebius cp, instance->unit); /* try "ntp.oncore0" */ 1228182007Sroberto if ((fd=fopen(device, "r"))) 1229182007Sroberto break; 1230290001Sglebius snprintf(device, sizeof(device), "%s/ntp.oncore", cp); 1231290001Sglebius if ((fd=fopen(device, "r"))) /* last try "ntp.oncore" */ 1232182007Sroberto break; 123382498Sroberto } 123454359Sroberto 1235182007Sroberto if (!fd) { /* no inputfile, default to the works ... */ 1236182007Sroberto instance->init_type = 4; 1237182007Sroberto return; 1238182007Sroberto } 1239182007Sroberto 1240132451Sroberto mode = mask = 0; 124154359Sroberto lat_flg = long_flg = ht_flg = 0; 124254359Sroberto while (fgets(line, 100, fd)) { 1243290001Sglebius char *cpw; 124456746Sroberto 124556746Sroberto /* Remove comments */ 1246290001Sglebius if ((cpw = strchr(line, '#'))) 1247290001Sglebius *cpw = '\0'; 124882498Sroberto 124956746Sroberto /* Remove trailing space */ 125056746Sroberto for (i = strlen(line); 1251290001Sglebius i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]); 125256746Sroberto ) 125356746Sroberto line[--i] = '\0'; 125456746Sroberto 125556746Sroberto /* Remove leading space */ 1256290001Sglebius for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++) 125756746Sroberto continue; 125856746Sroberto 125956746Sroberto /* Stop if nothing left */ 126056746Sroberto if (!*cc) 126156746Sroberto continue; 126256746Sroberto 126382498Sroberto /* Uppercase the command and find the arg */ 126456746Sroberto for (ca = cc; *ca; ca++) { 1265290001Sglebius if (isascii((unsigned char)*ca)) { 1266290001Sglebius if (islower((unsigned char)*ca)) { 1267290001Sglebius *ca = toupper((unsigned char)*ca); 1268290001Sglebius } else if (isspace((unsigned char)*ca) || (*ca == '=')) 126982498Sroberto break; 127056746Sroberto } 127156746Sroberto } 127282498Sroberto 127382498Sroberto /* Remove space (and possible =) leading the arg */ 1274290001Sglebius for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++) 127556746Sroberto continue; 127656746Sroberto 127782498Sroberto if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { 1278290001Sglebius instance->shmem_fname = estrdup(ca); 127956746Sroberto continue; 128056746Sroberto } 128156746Sroberto 128256746Sroberto /* Uppercase argument as well */ 1283290001Sglebius for (cpw = ca; *cpw; cpw++) 1284290001Sglebius if (isascii((unsigned char)*cpw) && islower((unsigned char)*cpw)) 1285290001Sglebius *cpw = toupper((unsigned char)*cpw); 128656746Sroberto 128782498Sroberto if (!strncmp(cc, "LAT", (size_t) 3)) { 128854359Sroberto f1 = f2 = f3 = 0; 128956746Sroberto sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 129054359Sroberto sign = 1; 129154359Sroberto if (f1 < 0) { 129254359Sroberto f1 = -f1; 129354359Sroberto sign = -1; 129454359Sroberto } 129554359Sroberto instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 129654359Sroberto lat_flg++; 129782498Sroberto } else if (!strncmp(cc, "LON", (size_t) 3)) { 129854359Sroberto f1 = f2 = f3 = 0; 129956746Sroberto sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 130054359Sroberto sign = 1; 130154359Sroberto if (f1 < 0) { 130254359Sroberto f1 = -f1; 130354359Sroberto sign = -1; 130454359Sroberto } 130554359Sroberto instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 130654359Sroberto long_flg++; 130782498Sroberto } else if (!strncmp(cc, "HT", (size_t) 2)) { 130854359Sroberto f1 = 0; 130954359Sroberto units[0] = '\0'; 131056746Sroberto sscanf(ca, "%lf %1s", &f1, units); 131154359Sroberto if (units[0] == 'F') 131254359Sroberto f1 = 0.3048 * f1; 131354359Sroberto instance->ss_ht = 100 * f1; /* cm */ 131454359Sroberto ht_flg++; 131582498Sroberto } else if (!strncmp(cc, "DELAY", (size_t) 5)) { 131654359Sroberto f1 = 0; 131754359Sroberto units[0] = '\0'; 131856746Sroberto sscanf(ca, "%lf %1s", &f1, units); 131954359Sroberto if (units[0] == 'N') 132054359Sroberto ; 132154359Sroberto else if (units[0] == 'U') 132254359Sroberto f1 = 1000 * f1; 132354359Sroberto else if (units[0] == 'M') 132454359Sroberto f1 = 1000000 * f1; 132554359Sroberto else 132654359Sroberto f1 = 1000000000 * f1; 132754359Sroberto if (f1 < 0 || f1 > 1.e9) 132854359Sroberto f1 = 0; 1329290001Sglebius if (f1 < 0 || f1 > 999999) 1330290001Sglebius oncore_log_f(instance, LOG_WARNING, 1331290001Sglebius "PPS Cable delay of %fns out of Range, ignored", 1332290001Sglebius f1); 1333290001Sglebius else 133482498Sroberto instance->delay = f1; /* delay in ns */ 133582498Sroberto } else if (!strncmp(cc, "OFFSET", (size_t) 6)) { 133654359Sroberto f1 = 0; 133754359Sroberto units[0] = '\0'; 133856746Sroberto sscanf(ca, "%lf %1s", &f1, units); 133954359Sroberto if (units[0] == 'N') 134054359Sroberto ; 134154359Sroberto else if (units[0] == 'U') 134254359Sroberto f1 = 1000 * f1; 134354359Sroberto else if (units[0] == 'M') 134454359Sroberto f1 = 1000000 * f1; 134554359Sroberto else 134654359Sroberto f1 = 1000000000 * f1; 134754359Sroberto if (f1 < 0 || f1 > 1.e9) 134854359Sroberto f1 = 0; 1349290001Sglebius if (f1 < 0 || f1 > 999999999.) 1350290001Sglebius oncore_log_f(instance, LOG_WARNING, 1351290001Sglebius "PPS Offset of %fns out of Range, ignored", 1352290001Sglebius f1); 1353290001Sglebius else 135482498Sroberto instance->offset = f1; /* offset in ns */ 135582498Sroberto } else if (!strncmp(cc, "MODE", (size_t) 4)) { 135656746Sroberto sscanf(ca, "%d", &mode); 135754359Sroberto if (mode < 0 || mode > 4) 135854359Sroberto mode = 4; 135982498Sroberto } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { 136054359Sroberto instance->assert = 1; 136182498Sroberto } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { 136254359Sroberto instance->assert = 0; 1363132451Sroberto } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) { 1364132451Sroberto instance->hardpps = 1; 136582498Sroberto } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { 136682498Sroberto instance->shmem_Posn = 2; 136782498Sroberto } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { 136882498Sroberto instance->shmem_Posn = 3; 136982498Sroberto } else if (!strncmp(cc, "CHAN", (size_t) 4)) { 137082498Sroberto sscanf(ca, "%d", &i); 137182498Sroberto if ((i == 6) || (i == 8) || (i == 12)) 1372132451Sroberto instance->chan_in = i; 137382498Sroberto } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { 1374132451Sroberto instance->traim_in = 1; /* so TRAIM alone is YES */ 137582498Sroberto if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ 1376132451Sroberto instance->traim_in = 0; 1377132451Sroberto } else if (!strncmp(cc, "MASK", (size_t) 4)) { 1378132451Sroberto sscanf(ca, "%d", &mask); 1379132451Sroberto if (mask > -1 && mask < 90) 1380132451Sroberto instance->Ag = mask; /* Satellite mask angle */ 1381290001Sglebius } else if (!strncmp(cc,"PPSCONTROL",10)) { /* pps control M12 only */ 1382290001Sglebius if (!strcmp(ca,"ON") || !strcmp(ca, "CONTINUOUS")) { 1383290001Sglebius instance->pps_control = 1; /* PPS always on */ 1384290001Sglebius } else if (!strcmp(ca,"SATELLITE")) { 1385290001Sglebius instance->pps_control = 2; /* PPS on when satellite is available */ 1386290001Sglebius } else if (!strcmp(ca,"TRAIM")) { 1387290001Sglebius instance->pps_control = 3; /* PPS on when TRAIM status is OK */ 1388290001Sglebius } else { 1389290001Sglebius oncore_log_f(instance, LOG_WARNING, 1390290001Sglebius "Unknown value \"%s\" for PPSCONTROL, ignored", 1391290001Sglebius cc); 1392290001Sglebius } 139354359Sroberto } 139454359Sroberto } 139554359Sroberto fclose(fd); 139654359Sroberto 139754359Sroberto /* 139854359Sroberto * OK, have read all of data file, and extracted the good stuff. 139954359Sroberto * If lat/long/ht specified they ALL must be specified for mode = (1,3). 140054359Sroberto */ 140154359Sroberto 140254359Sroberto instance->posn_set = 1; 1403132451Sroberto if (!( lat_flg && long_flg && ht_flg )) { 1404290001Sglebius oncore_log_f(instance, LOG_WARNING, 1405290001Sglebius "ONCORE: incomplete data on %s", device); 140654359Sroberto instance->posn_set = 0; 140782498Sroberto if (mode == 1 || mode == 3) { 1408290001Sglebius oncore_log_f(instance, LOG_WARNING, 1409290001Sglebius "Input Mode = %d, but no/incomplete position, mode set to %d", 1410290001Sglebius mode, mode+1); 141182498Sroberto mode++; 141282498Sroberto } 141354359Sroberto } 141482498Sroberto instance->init_type = mode; 141582498Sroberto 1416290001Sglebius oncore_log_f(instance, LOG_INFO, "Input mode = %d", mode); 141754359Sroberto} 141854359Sroberto 141954359Sroberto 142054359Sroberto 142154359Sroberto/* 1422132451Sroberto * move data from NTP to buffer (toss the extra in the unlikely case it won't fit) 142354359Sroberto */ 142482498Sroberto 142554359Srobertostatic void 142654359Srobertooncore_receive( 142754359Sroberto struct recvbuf *rbufp 142854359Sroberto ) 142954359Sroberto{ 143082498Sroberto size_t i; 143154359Sroberto u_char *p; 143254359Sroberto struct peer *peer; 143354359Sroberto struct instance *instance; 143454359Sroberto 1435290001Sglebius peer = rbufp->recv_peer; 1436290001Sglebius instance = peer->procptr->unitptr; 143754359Sroberto p = (u_char *) &rbufp->recv_space; 143854359Sroberto 1439290001Sglebius#ifdef ONCORE_VERBOSE_RECEIVE 144054359Sroberto if (debug > 4) { 144154359Sroberto int i; 1442290001Sglebius char Msg[120], Msg2[10]; 1443290001Sglebius 1444290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1445290001Sglebius ">>> %d bytes available", 1446290001Sglebius rbufp->recv_length); 1447290001Sglebius strlcpy(Msg, ">>>", sizeof(Msg)); 1448290001Sglebius for (i = 0; i < rbufp->recv_length; i++) { 1449290001Sglebius snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]); 1450290001Sglebius strlcat(Msg, Msg2, sizeof(Msg)); 1451290001Sglebius } 1452290001Sglebius oncore_log(instance, LOG_DEBUG, Msg); 1453290001Sglebius 1454290001Sglebius strlcpy(Msg, ">>>", sizeof(Msg)); 1455290001Sglebius for (i = 0; i < rbufp->recv_length; i++) { 1456290001Sglebius snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]); 1457290001Sglebius strlcat(Msg, Msg2, sizeof(Msg)); 1458290001Sglebius } 1459290001Sglebius oncore_log(instance, LOG_DEBUG, Msg); 146054359Sroberto } 146154359Sroberto#endif 146254359Sroberto 146354359Sroberto i = rbufp->recv_length; 146454359Sroberto if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf]) 146554359Sroberto i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ 146654359Sroberto memcpy(rcvbuf+rcvptr, p, i); 146754359Sroberto rcvptr += i; 146854359Sroberto oncore_consume(instance); 146954359Sroberto} 147054359Sroberto 147154359Sroberto 147254359Sroberto 147354359Sroberto/* 147454359Sroberto * Deal with any complete messages 147554359Sroberto */ 147682498Sroberto 147754359Srobertostatic void 147854359Srobertooncore_consume( 147954359Sroberto struct instance *instance 148054359Sroberto ) 148154359Sroberto{ 1482290001Sglebius unsigned i, m, l; 148354359Sroberto 148454359Sroberto while (rcvptr >= 7) { 148554359Sroberto if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { 148654359Sroberto /* We're not in sync, lets try to get there */ 148754359Sroberto for (i=1; i < rcvptr-1; i++) 148854359Sroberto if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') 148954359Sroberto break; 1490290001Sglebius#ifdef ONCORE_VERBOSE_CONSUME 149154359Sroberto if (debug > 4) 1492290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1493290001Sglebius ">>> skipping %d chars", 1494290001Sglebius i); 1495182007Sroberto#endif 149654359Sroberto if (i != rcvptr) 149782498Sroberto memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i)); 149854359Sroberto rcvptr -= i; 149982498Sroberto continue; 150054359Sroberto } 150154359Sroberto 150254359Sroberto /* Ok, we have a header now */ 150354359Sroberto l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; 150454359Sroberto for(m=0; m<l; m++) 150582498Sroberto if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2)) 150654359Sroberto break; 150782498Sroberto if (m == l) { 1508290001Sglebius#ifdef ONCORE_VERBOSE_CONSUME 150982498Sroberto if (debug > 4) 1510290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1511290001Sglebius ">>> Unknown MSG, skipping 4 (%c%c)", 1512290001Sglebius rcvbuf[2], rcvbuf[3]); 1513182007Sroberto#endif 151482498Sroberto memcpy(rcvbuf, rcvbuf+4, (size_t) 4); 151582498Sroberto rcvptr -= 4; 151682498Sroberto continue; 151782498Sroberto } 151882498Sroberto 151954359Sroberto l = oncore_messages[m].len; 1520290001Sglebius#ifdef ONCORE_VERBOSE_CONSUME 152154359Sroberto if (debug > 3) 1522290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1523290001Sglebius "GOT: %c%c %d of %d entry %d", 1524290001Sglebius instance->unit, rcvbuf[2], 1525290001Sglebius rcvbuf[3], rcvptr, l, m); 152654359Sroberto#endif 152754359Sroberto /* Got the entire message ? */ 152854359Sroberto 152954359Sroberto if (rcvptr < l) 153054359Sroberto return; 153154359Sroberto 153282498Sroberto /* are we at the end of message? should be <Cksum><CR><LF> */ 153354359Sroberto 153482498Sroberto if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') { 1535290001Sglebius#ifdef ONCORE_VERBOSE_CONSUME 153682498Sroberto if (debug) 1537290001Sglebius oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message"); 1538182007Sroberto#endif 153982498Sroberto } else { /* check the CheckSum */ 1540132451Sroberto if (oncore_checksum_ok(rcvbuf, l)) { 154182498Sroberto if (instance->shmem != NULL) { 154282498Sroberto instance->shmem[oncore_messages[m].shmem + 2]++; 154382498Sroberto memcpy(instance->shmem + oncore_messages[m].shmem + 3, 154482498Sroberto rcvbuf, (size_t) l); 154582498Sroberto } 154682498Sroberto oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m); 154782498Sroberto if (oncore_messages[m].handler) 154882498Sroberto oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3)); 1549182007Sroberto } 1550290001Sglebius#ifdef ONCORE_VERBOSE_CONSUME 1551182007Sroberto else if (debug) { 1552290001Sglebius char Msg[120], Msg2[10]; 1553290001Sglebius 1554290001Sglebius oncore_log(instance, LOG_ERR, "Checksum mismatch!"); 1555290001Sglebius snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]); 1556290001Sglebius for (i = 4; i < l; i++) { 1557290001Sglebius snprintf(Msg2, sizeof(Msg2), 1558290001Sglebius "%03o ", rcvbuf[i]); 1559290001Sglebius strlcat(Msg, Msg2, sizeof(Msg)); 1560290001Sglebius } 1561290001Sglebius oncore_log(instance, LOG_DEBUG, Msg); 156282498Sroberto } 1563182007Sroberto#endif 156454359Sroberto } 156554359Sroberto 156654359Sroberto if (l != rcvptr) 156782498Sroberto memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); 156854359Sroberto rcvptr -= l; 156954359Sroberto } 157054359Sroberto} 157154359Sroberto 157254359Sroberto 157354359Sroberto 157454359Srobertostatic void 1575132451Srobertooncore_get_timestamp( 1576132451Sroberto struct instance *instance, 1577132451Sroberto long dt1, /* tick offset THIS time step */ 1578132451Sroberto long dt2 /* tick offset NEXT time step */ 157954359Sroberto ) 158054359Sroberto{ 1581132451Sroberto int Rsm; 1582182007Sroberto u_long j; 1583132451Sroberto l_fp ts, ts_tmp; 1584132451Sroberto double dmy; 1585132451Sroberto#ifdef HAVE_STRUCT_TIMESPEC 1586132451Sroberto struct timespec *tsp = 0; 1587132451Sroberto#else 1588132451Sroberto struct timeval *tsp = 0; 1589132451Sroberto#endif 1590132451Sroberto int current_mode; 1591132451Sroberto pps_params_t current_params; 1592132451Sroberto struct timespec timeout; 1593290001Sglebius struct peer *peer; 1594132451Sroberto pps_info_t pps_i; 1595290001Sglebius char Msg[160]; 159654359Sroberto 1597290001Sglebius peer = instance->peer; 1598290001Sglebius 1599132451Sroberto#if 1 1600132451Sroberto /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru. 1601132451Sroberto * If we have Finished the SiteSurvey, then we fall thru for the 14/15 1602132451Sroberto * times we get here in 0D mode (the 1/15 is in 3D for SHMEM). 1603132451Sroberto * This gives good time, which gets better when the SS is done. 1604132451Sroberto */ 1605132451Sroberto 1606290001Sglebius if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) { 1607132451Sroberto#else 1608132451Sroberto /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */ 1609132451Sroberto 1610290001Sglebius if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) { 1611132451Sroberto#endif 1612290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1613132451Sroberto return; 1614290001Sglebius } 1615132451Sroberto 1616132451Sroberto /* Don't do anything without an almanac to define the GPS->UTC delta */ 1617132451Sroberto 1618290001Sglebius if (instance->rsm.bad_almanac) { 1619290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1620132451Sroberto return; 1621290001Sglebius } 1622132451Sroberto 1623182007Sroberto /* Once the Almanac is valid, the M12+T does not produce valid UTC 1624182007Sroberto * immediately. 1625182007Sroberto * Wait for UTC offset decode valid, then wait one message more 1626182007Sroberto * so we are not off by 13 seconds after reset. 1627182007Sroberto */ 1628182007Sroberto 1629182007Sroberto if (instance->count5) { 1630182007Sroberto instance->count5--; 1631290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1632182007Sroberto return; 1633182007Sroberto } 1634182007Sroberto 1635132451Sroberto j = instance->ev_serial; 1636132451Sroberto timeout.tv_sec = 0; 1637132451Sroberto timeout.tv_nsec = 0; 1638132451Sroberto if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, 1639132451Sroberto &timeout) < 0) { 1640290001Sglebius oncore_log_f(instance, LOG_ERR, 1641290001Sglebius "time_pps_fetch failed %m"); 1642290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1643132451Sroberto return; 1644132451Sroberto } 1645132451Sroberto 1646132451Sroberto if (instance->assert) { 1647132451Sroberto tsp = &pps_i.assert_timestamp; 1648132451Sroberto 1649290001Sglebius#ifdef ONCORE_VERBOSE_GET_TIMESTAMP 1650132451Sroberto if (debug > 2) { 1651290001Sglebius u_long i; 1652290001Sglebius 1653132451Sroberto i = (u_long) pps_i.assert_sequence; 1654182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC 1655290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1656290001Sglebius "serial/j (%lu, %lu) %ld.%09ld", i, 1657290001Sglebius j, (long)tsp->tv_sec, 1658290001Sglebius (long)tsp->tv_nsec); 1659182007Sroberto# else 1660290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1661290001Sglebius "serial/j (%lu, %lu) %ld.%06ld", i, 1662290001Sglebius j, (long)tsp->tv_sec, 1663290001Sglebius (long)tsp->tv_usec); 1664182007Sroberto# endif 1665182007Sroberto } 1666132451Sroberto#endif 1667132451Sroberto 1668132451Sroberto if (pps_i.assert_sequence == j) { 1669290001Sglebius oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps"); 1670290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1671132451Sroberto return; 1672132451Sroberto } 1673290001Sglebius 1674132451Sroberto instance->ev_serial = pps_i.assert_sequence; 1675132451Sroberto } else { 1676132451Sroberto tsp = &pps_i.clear_timestamp; 1677132451Sroberto 1678290001Sglebius#if 0 1679132451Sroberto if (debug > 2) { 1680290001Sglebius u_long i; 1681290001Sglebius 1682132451Sroberto i = (u_long) pps_i.clear_sequence; 1683182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC 1684290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1685290001Sglebius "serial/j (%lu, %lu) %ld.%09ld", i, 1686290001Sglebius j, (long)tsp->tv_sec, 1687290001Sglebius (long)tsp->tv_nsec); 1688182007Sroberto# else 1689290001Sglebius oncore_log_f(instance, LOG_DEBUG, 1690290001Sglebius "serial/j (%lu, %lu) %ld.%06ld", i, 1691290001Sglebius j, (long)tsp->tv_sec, 1692290001Sglebius (long)tsp->tv_usec); 1693182007Sroberto# endif 1694182007Sroberto } 1695132451Sroberto#endif 1696132451Sroberto 1697132451Sroberto if (pps_i.clear_sequence == j) { 1698290001Sglebius oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps"); 1699290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1700132451Sroberto return; 1701132451Sroberto } 1702132451Sroberto instance->ev_serial = pps_i.clear_sequence; 1703132451Sroberto } 1704132451Sroberto 1705132451Sroberto /* convert timespec -> ntp l_fp */ 1706132451Sroberto 1707132451Sroberto dmy = tsp->tv_nsec; 1708132451Sroberto dmy /= 1e9; 1709182007Sroberto ts.l_uf = dmy * 4294967296.0; 1710132451Sroberto ts.l_ui = tsp->tv_sec; 1711182007Sroberto 1712132451Sroberto#if 0 1713132451Sroberto alternate code for previous 4 lines is 1714132451Sroberto dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1715132451Sroberto DTOLFP(dmy, &ts); 1716132451Sroberto dmy = tsp->tv_sec; /* integer part */ 1717132451Sroberto DTOLFP(dmy, &ts_tmp); 1718132451Sroberto L_ADD(&ts, &ts_tmp); 1719132451Sroberto or more simply 1720132451Sroberto dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1721132451Sroberto DTOLFP(dmy, &ts); 1722132451Sroberto ts.l_ui = tsp->tv_sec; 1723132451Sroberto#endif /* 0 */ 1724132451Sroberto 1725132451Sroberto /* now have timestamp in ts */ 1726132451Sroberto /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ 1727182007Sroberto /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */ 1728182007Sroberto /* we just try to add them in and dont test for that here */ 1729132451Sroberto 1730132451Sroberto /* saw_tooth not really necessary if using TIMEVAL */ 1731132451Sroberto /* since its only precise to us, but do it anyway. */ 1732132451Sroberto 1733132451Sroberto /* offset in ns, and is positive (late), we subtract */ 1734132451Sroberto /* to put the PPS time transition back where it belongs */ 1735132451Sroberto 1736132451Sroberto /* must hand the offset for the NEXT sec off to the Kernel to do */ 1737132451Sroberto /* the addition, so that the Kernel PLL sees the offset too */ 1738132451Sroberto 1739132451Sroberto if (instance->assert) 1740132451Sroberto instance->pps_p.assert_offset.tv_nsec = -dt2; 1741132451Sroberto else 1742132451Sroberto instance->pps_p.clear_offset.tv_nsec = -dt2; 1743132451Sroberto 1744132451Sroberto /* The following code is necessary, and not just a time_pps_setparams, 1745132451Sroberto * using the saved instance->pps_p, since some other process on the 1746132451Sroberto * machine may have diddled with the mode bits (say adding something 1747132451Sroberto * that it needs). We take what is there and ADD what we need. 1748132451Sroberto * [[ The results from the time_pps_getcap is unlikely to change so 1749132451Sroberto * we could probably just save it, but I choose to do the call ]] 1750132451Sroberto * Unfortunately, there is only ONE set of mode bits in the kernel per 1751132451Sroberto * interface, and not one set for each open handle. 1752132451Sroberto * 1753132451Sroberto * There is still a race condition here where we might mess up someone 1754132451Sroberto * elses mode, but if he is being careful too, he should survive. 1755132451Sroberto */ 1756132451Sroberto 1757132451Sroberto if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { 1758290001Sglebius oncore_log_f(instance, LOG_ERR, 1759290001Sglebius "time_pps_getcap failed: %m"); 1760290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1761132451Sroberto return; 1762132451Sroberto } 1763132451Sroberto 1764132451Sroberto if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { 1765290001Sglebius oncore_log_f(instance, LOG_ERR, 1766290001Sglebius "time_pps_getparams failed: %m"); 1767290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1768132451Sroberto return; 1769132451Sroberto } 1770132451Sroberto 1771132451Sroberto /* or current and mine */ 1772132451Sroberto current_params.mode |= instance->pps_p.mode; 1773132451Sroberto /* but only set whats legal */ 1774132451Sroberto current_params.mode &= current_mode; 1775132451Sroberto 1776132451Sroberto current_params.assert_offset.tv_sec = 0; 1777132451Sroberto current_params.assert_offset.tv_nsec = -dt2; 1778132451Sroberto current_params.clear_offset.tv_sec = 0; 1779132451Sroberto current_params.clear_offset.tv_nsec = -dt2; 1780132451Sroberto 1781132451Sroberto if (time_pps_setparams(instance->pps_h, ¤t_params)) 1782290001Sglebius oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams"); 1783132451Sroberto 1784132451Sroberto /* have time from UNIX origin, convert to NTP origin. */ 1785132451Sroberto 1786132451Sroberto ts.l_ui += JAN_1970; 1787132451Sroberto instance->pp->lastrec = ts; 1788132451Sroberto 1789132451Sroberto /* print out information about this timestamp (long line) */ 1790132451Sroberto 1791132451Sroberto ts_tmp = ts; 1792132451Sroberto ts_tmp.l_ui = 0; /* zero integer part */ 1793132451Sroberto LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ 1794132451Sroberto j = 1.0e9*dmy; /* then to integer ns */ 1795132451Sroberto 1796132451Sroberto Rsm = 0; 1797132451Sroberto if (instance->chan == 6) 1798132451Sroberto Rsm = instance->BEHa[64]; 1799132451Sroberto else if (instance->chan == 8) 1800132451Sroberto Rsm = instance->BEHa[72]; 1801132451Sroberto else if (instance->chan == 12) 1802132451Sroberto Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]); 1803132451Sroberto 1804132451Sroberto if (instance->chan == 6 || instance->chan == 8) { 1805182007Sroberto char f1[5], f2[5], f3[5], f4[5]; 1806182007Sroberto if (instance->traim) { 1807290001Sglebius snprintf(f1, sizeof(f1), "%d", 1808290001Sglebius instance->BEHn[21]); 1809290001Sglebius snprintf(f2, sizeof(f2), "%d", 1810290001Sglebius instance->BEHn[22]); 1811290001Sglebius snprintf(f3, sizeof(f3), "%2d", 1812290001Sglebius instance->BEHn[23] * 256 + 1813290001Sglebius instance->BEHn[24]); 1814290001Sglebius snprintf(f4, sizeof(f4), "%3d", 1815290001Sglebius (s_char)instance->BEHn[25]); 1816182007Sroberto } else { 1817290001Sglebius strlcpy(f1, "x", sizeof(f1)); 1818290001Sglebius strlcpy(f2, "x", sizeof(f2)); 1819290001Sglebius strlcpy(f3, "xx", sizeof(f3)); 1820290001Sglebius strlcpy(f4, "xxx", sizeof(f4)); 1821182007Sroberto } 1822290001Sglebius snprintf(Msg, sizeof(Msg), /* MAX length 128, currently at 127 */ 1823182007Sroberto "%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", 1824132451Sroberto ts.l_ui, j, 1825132451Sroberto instance->pp->year, instance->pp->day, 1826132451Sroberto instance->pp->hour, instance->pp->minute, instance->pp->second, 1827132451Sroberto (long) tsp->tv_sec % 60, 1828132451Sroberto Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]), 1829132451Sroberto /*rsat dop */ 1830182007Sroberto instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2, 1831182007Sroberto /* nsat visible, nsat tracked, traim,traim,traim */ 1832182007Sroberto f3, f4, 1833182007Sroberto /* sigma neg-sawtooth */ 1834132451Sroberto /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53], 1835132451Sroberto instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69] 1836132451Sroberto ); /* will be 0 for 6 chan */ 1837132451Sroberto } else if (instance->chan == 12) { 1838182007Sroberto char f1[5], f2[5], f3[5], f4[5]; 1839182007Sroberto if (instance->traim) { 1840290001Sglebius snprintf(f1, sizeof(f1), "%d", 1841290001Sglebius instance->BEHn[6]); 1842290001Sglebius snprintf(f2, sizeof(f2), "%d", 1843290001Sglebius instance->BEHn[7]); 1844290001Sglebius snprintf(f3, sizeof(f3), "%d", 1845290001Sglebius instance->BEHn[12] * 256 + 1846290001Sglebius instance->BEHn[13]); 1847290001Sglebius snprintf(f4, sizeof(f4), "%3d", 1848290001Sglebius (s_char)instance->BEHn[14]); 1849182007Sroberto } else { 1850290001Sglebius strlcpy(f1, "x", sizeof(f1)); 1851290001Sglebius strlcpy(f2, "x", sizeof(f2)); 1852290001Sglebius strlcpy(f3, "xx", sizeof(f3)); 1853290001Sglebius strlcpy(f4, "xxx", sizeof(f4)); 1854182007Sroberto } 1855290001Sglebius snprintf(Msg, sizeof(Msg), 1856182007Sroberto "%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", 1857132451Sroberto ts.l_ui, j, 1858132451Sroberto instance->pp->year, instance->pp->day, 1859132451Sroberto instance->pp->hour, instance->pp->minute, instance->pp->second, 1860132451Sroberto (long) tsp->tv_sec % 60, 1861132451Sroberto Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]), 1862132451Sroberto /*rsat dop */ 1863182007Sroberto instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2, 1864182007Sroberto /* nsat visible, nsat tracked traim,traim,traim */ 1865182007Sroberto f3, f4, 1866182007Sroberto /* sigma neg-sawtooth */ 1867132451Sroberto /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76], 1868132451Sroberto instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100], 1869132451Sroberto instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124] 1870132451Sroberto ); 1871132451Sroberto } 1872132451Sroberto 1873182007Sroberto /* and some things I dont understand (magic ntp things) */ 1874132451Sroberto 1875132451Sroberto if (!refclock_process(instance->pp)) { 1876132451Sroberto refclock_report(instance->peer, CEVNT_BADTIME); 1877290001Sglebius peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1878132451Sroberto return; 1879132451Sroberto } 1880132451Sroberto 1881290001Sglebius oncore_log(instance, LOG_INFO, Msg); /* this is long message above */ 1882132451Sroberto instance->pollcnt = 2; 1883132451Sroberto 1884132451Sroberto if (instance->polled) { 1885132451Sroberto instance->polled = 0; 1886182007Sroberto /* instance->pp->dispersion = instance->pp->skew = 0; */ 1887132451Sroberto instance->pp->lastref = instance->pp->lastrec; 1888132451Sroberto refclock_receive(instance->peer); 1889132451Sroberto } 1890290001Sglebius peer->flags |= FLAG_PPS; 189154359Sroberto} 189254359Sroberto 189354359Sroberto 1894132451Sroberto/*************** oncore_msg_XX routines start here *******************/ 189554359Sroberto 1896132451Sroberto 189782498Sroberto/* 189882498Sroberto * print Oncore response message. 189982498Sroberto */ 190082498Sroberto 190154359Srobertostatic void 190254359Srobertooncore_msg_any( 190354359Sroberto struct instance *instance, 190454359Sroberto u_char *buf, 190582498Sroberto size_t len, 190654359Sroberto int idx 190754359Sroberto ) 190854359Sroberto{ 1909290001Sglebius#ifdef ONCORE_VERBOSE_MSG_ANY 191054359Sroberto int i; 191154359Sroberto const char *fmt = oncore_messages[idx].fmt; 191254359Sroberto const char *p; 1913290001Sglebius char *q; 1914290001Sglebius char *qlim; 191582498Sroberto#ifdef HAVE_GETCLOCK 191682498Sroberto struct timespec ts; 191782498Sroberto#endif 191854359Sroberto struct timeval tv; 1919290001Sglebius char Msg[120], Msg2[10]; 192054359Sroberto 192154359Sroberto if (debug > 3) { 1922182007Sroberto# ifdef HAVE_GETCLOCK 1923132451Sroberto (void) getclock(TIMEOFDAY, &ts); 1924132451Sroberto tv.tv_sec = ts.tv_sec; 1925132451Sroberto tv.tv_usec = ts.tv_nsec / 1000; 1926182007Sroberto# else 192754359Sroberto GETTIMEOFDAY(&tv, 0); 1928182007Sroberto# endif 1929290001Sglebius oncore_log(instance, LOG_DEBUG, "%ld.%06ld", 1930290001Sglebius (long)tv.tv_sec, (long)tv.tv_usec); 193154359Sroberto 193254359Sroberto if (!*fmt) { 1933290001Sglebius snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2], 1934290001Sglebius buf[3]); 1935290001Sglebius for(i = 2; i < len && i < 2400 ; i++) { 1936290001Sglebius snprintf(Msg2, sizeof(Msg2), "%02x", 1937290001Sglebius buf[i]); 1938290001Sglebius strlcat(Msg, Msg2, sizeof(Msg)); 1939290001Sglebius } 1940290001Sglebius oncore_log(instance, LOG_DEBUG, Msg); 194154359Sroberto return; 194254359Sroberto } else { 1943290001Sglebius strlcpy(Msg, "##", sizeof(Msg)); 1944290001Sglebius qlim = Msg + sizeof(Msg) - 3; 1945290001Sglebius for (p = fmt, q = Msg + 2; q < qlim && *p; ) { 1946290001Sglebius *q++ = *p++; 1947290001Sglebius *q++ = '_'; 194854359Sroberto } 1949290001Sglebius *q = '\0'; 1950290001Sglebius oncore_log(instance, LOG_DEBUG, Msg); 1951290001Sglebius snprintf(Msg, sizeof(Msg), "%c%c", buf[2], 1952290001Sglebius buf[3]); 195354359Sroberto i = 4; 195454359Sroberto for (p = fmt; *p; p++) { 1955290001Sglebius snprintf(Msg2, "%02x", buf[i++]); 1956290001Sglebius strlcat(Msg, Msg2, sizeof(Msg)); 195754359Sroberto } 1958290001Sglebius oncore_log(instance, LOG_DEBUG, Msg); 195954359Sroberto } 196054359Sroberto } 1961182007Sroberto#endif 196254359Sroberto} 196354359Sroberto 196454359Sroberto 196554359Sroberto 1966132451Sroberto/* Latitude, Longitude, Height */ 196782498Sroberto 196856746Srobertostatic void 1969132451Srobertooncore_msg_Adef( 197056746Sroberto struct instance *instance, 197156746Sroberto u_char *buf, 197282498Sroberto size_t len 197356746Sroberto ) 197456746Sroberto{ 1975132451Sroberto} 197656746Sroberto 197756746Sroberto 197856746Sroberto 1979132451Sroberto/* Mask Angle */ 198082498Sroberto 1981132451Srobertostatic void 1982132451Srobertooncore_msg_Ag( 1983132451Sroberto struct instance *instance, 1984132451Sroberto u_char *buf, 1985132451Sroberto size_t len 1986132451Sroberto ) 1987290001Sglebius{ 1988290001Sglebius const char *cp; 198982498Sroberto 1990290001Sglebius cp = "set to"; 1991290001Sglebius if (instance->o_state == ONCORE_RUN) 1992290001Sglebius cp = "is"; 199354359Sroberto 1994290001Sglebius instance->Ag = buf[4]; 1995290001Sglebius oncore_log_f(instance, LOG_INFO, 1996290001Sglebius "Satellite mask angle %s %d degrees", cp, 1997290001Sglebius (int)instance->Ag); 1998132451Sroberto} 199954359Sroberto 2000132451Sroberto 2001132451Sroberto 200282498Sroberto/* 2003132451Sroberto * get Position hold position 200456746Sroberto */ 200556746Sroberto 200654359Srobertostatic void 2007132451Srobertooncore_msg_As( 200854359Sroberto struct instance *instance, 200954359Sroberto u_char *buf, 201082498Sroberto size_t len 201154359Sroberto ) 201254359Sroberto{ 2013132451Sroberto instance->ss_lat = buf_w32(&buf[4]); 2014132451Sroberto instance->ss_long = buf_w32(&buf[8]); 2015132451Sroberto instance->ss_ht = buf_w32(&buf[12]); 201654359Sroberto 2017132451Sroberto /* Print out Position */ 2018132451Sroberto oncore_print_posn(instance); 201954359Sroberto} 202054359Sroberto 202154359Sroberto 202254359Sroberto 2023132451Sroberto/* 2024132451Sroberto * Try to use Oncore UT+ Auto Survey Feature 2025132451Sroberto * If its not there (VP), set flag to do it ourselves. 202654359Sroberto */ 202782498Sroberto 202854359Srobertostatic void 2029132451Srobertooncore_msg_At( 203054359Sroberto struct instance *instance, 203154359Sroberto u_char *buf, 203282498Sroberto size_t len 203354359Sroberto ) 203454359Sroberto{ 2035132451Sroberto instance->saw_At = 1; 2036132451Sroberto if (instance->site_survey == ONCORE_SS_TESTING) { 2037132451Sroberto if (buf[4] == 2) { 2038290001Sglebius oncore_log(instance, LOG_NOTICE, 2039132451Sroberto "Initiating hardware 3D site survey"); 204054359Sroberto 2041290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW"); 2042132451Sroberto instance->site_survey = ONCORE_SS_HW; 2043132451Sroberto } 204456746Sroberto } 2045132451Sroberto} 204682498Sroberto 204782498Sroberto 204882498Sroberto 2049132451Sroberto/* 2050132451Sroberto * get PPS Offset 2051132451Sroberto * Nb. @@Ay is not supported for early UT (no plus) model 2052132451Sroberto */ 205382498Sroberto 2054132451Srobertostatic void 2055132451Srobertooncore_msg_Ay( 2056132451Sroberto struct instance *instance, 2057132451Sroberto u_char *buf, 2058132451Sroberto size_t len 2059132451Sroberto ) 2060132451Sroberto{ 2061132451Sroberto if (instance->saw_Ay) 2062132451Sroberto return; 206382498Sroberto 2064132451Sroberto instance->saw_Ay = 1; 206582498Sroberto 2066132451Sroberto instance->offset = buf_w32(&buf[4]); 206782498Sroberto 2068290001Sglebius oncore_log_f(instance, LOG_INFO, "PPS Offset is set to %ld ns", 2069290001Sglebius instance->offset); 2070132451Sroberto} 207182498Sroberto 207282498Sroberto 207382498Sroberto 2074132451Sroberto/* 2075132451Sroberto * get Cable Delay 2076132451Sroberto */ 207782498Sroberto 2078132451Srobertostatic void 2079132451Srobertooncore_msg_Az( 2080132451Sroberto struct instance *instance, 2081132451Sroberto u_char *buf, 2082132451Sroberto size_t len 2083132451Sroberto ) 2084132451Sroberto{ 2085132451Sroberto if (instance->saw_Az) 2086132451Sroberto return; 208782498Sroberto 2088132451Sroberto instance->saw_Az = 1; 208956746Sroberto 2090132451Sroberto instance->delay = buf_w32(&buf[4]); 209154359Sroberto 2092290001Sglebius oncore_log_f(instance, LOG_INFO, "Cable delay is set to %ld ns", 2093290001Sglebius instance->delay); 209482498Sroberto} 209582498Sroberto 209682498Sroberto 209782498Sroberto 2098132451Sroberto/* Ba, Ea and Ha come here, these contain Position */ 2099132451Sroberto 210082498Srobertostatic void 2101132451Srobertooncore_msg_BaEaHa( 210282498Sroberto struct instance *instance, 210382498Sroberto u_char *buf, 210482498Sroberto size_t len 210582498Sroberto ) 210682498Sroberto{ 2107132451Sroberto const char *cp; 2108132451Sroberto int mode; 210982498Sroberto 2110132451Sroberto /* OK, we are close to the RUN state now. 2111132451Sroberto * But we have a few more items to initialize first. 2112132451Sroberto * 2113132451Sroberto * At the beginning of this routine there are several 'timers'. 2114132451Sroberto * We enter this routine 1/sec, and since the upper levels of NTP have usurped 2115132451Sroberto * the use of timers, we use the 1/sec entry to do things that 2116132451Sroberto * we would normally do with timers... 211782498Sroberto */ 211882498Sroberto 2119132451Sroberto if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */ 2120132451Sroberto if (buf[2] == 'B') { /* 6chan */ 2121132451Sroberto if (instance->chan_ck < 6) instance->chan_ck = 6; 2122132451Sroberto } else if (buf[2] == 'E') { /* 8chan */ 2123132451Sroberto if (instance->chan_ck < 8) instance->chan_ck = 8; 2124132451Sroberto } else if (buf[2] == 'H') { /* 12chan */ 2125132451Sroberto if (instance->chan_ck < 12) instance->chan_ck = 12; 2126132451Sroberto } 212782498Sroberto 2128132451Sroberto if (instance->count3++ < 5) 2129132451Sroberto return; 213082498Sroberto 2131132451Sroberto instance->count3 = 0; 2132132451Sroberto 2133132451Sroberto if (instance->chan_in != -1) /* set in Input */ 2134132451Sroberto instance->chan = instance->chan_in; 2135132451Sroberto else /* set from test */ 2136132451Sroberto instance->chan = instance->chan_ck; 2137132451Sroberto 2138290001Sglebius oncore_log_f(instance, LOG_INFO, "Input says chan = %d", 2139290001Sglebius instance->chan_in); 2140290001Sglebius oncore_log_f(instance, LOG_INFO, "Model # says chan = %d", 2141290001Sglebius instance->chan_id); 2142290001Sglebius oncore_log_f(instance, LOG_INFO, "Testing says chan = %d", 2143290001Sglebius instance->chan_ck); 2144290001Sglebius oncore_log_f(instance, LOG_INFO, "Using chan = %d", 2145290001Sglebius instance->chan); 2146132451Sroberto 2147132451Sroberto instance->o_state = ONCORE_HAVE_CHAN; 2148290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN"); 2149132451Sroberto 2150132451Sroberto instance->timeout = 4; 2151290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 2152132451Sroberto return; 215382498Sroberto } 215482498Sroberto 2155132451Sroberto if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) 2156132451Sroberto return; 2157132451Sroberto 2158182007Sroberto /* PAUSE 5sec - make sure results are stable, before using position */ 2159132451Sroberto 2160132451Sroberto if (instance->count) { 2161182007Sroberto if (instance->count++ < 5) 2162132451Sroberto return; 2163132451Sroberto instance->count = 0; 216482498Sroberto } 216554359Sroberto 2166132451Sroberto memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */ 216754359Sroberto 2168290001Sglebius /* check if we saw a response to Gc (M12 or M12+T */ 2169290001Sglebius 2170290001Sglebius if (instance->pps_control_msg_seen != -2) { 2171290001Sglebius if ((instance->pps_control_msg_seen == -1) && (instance->pps_control != -1)) { 2172290001Sglebius oncore_log(instance, LOG_INFO, "PPSCONTROL set, but not implemented (not M12)"); 2173290001Sglebius } 2174290001Sglebius instance->pps_control_msg_seen = -2; 2175290001Sglebius } 2176290001Sglebius 2177182007Sroberto /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */ 217882498Sroberto 2179132451Sroberto oncore_check_almanac(instance); 2180132451Sroberto oncore_check_antenna(instance); 2181132451Sroberto 2182182007Sroberto /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */ 2183132451Sroberto /* When we have an almanac, we will start the Bn/En/@@Hn messages */ 2184132451Sroberto 2185132451Sroberto if (instance->o_state == ONCORE_ALMANAC) 2186132451Sroberto if (oncore_wait_almanac(instance)) 2187132451Sroberto return; 2188132451Sroberto 2189132451Sroberto /* do some things once when we get this far in BaEaHa */ 2190132451Sroberto 2191132451Sroberto if (instance->once) { 2192132451Sroberto instance->once = 0; 2193132451Sroberto instance->count2 = 1; 2194132451Sroberto 2195132451Sroberto /* Have we seen an @@At (position hold) command response */ 2196132451Sroberto /* if not, message out */ 2197132451Sroberto 2198132451Sroberto if (instance->chan != 12 && !instance->saw_At) { 2199290001Sglebius oncore_log(instance, LOG_NOTICE, 2200290001Sglebius "Not Good, no @@At command (no Position Hold), must be a GT/GT+"); 2201290001Sglebius oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 2202132451Sroberto } 2203132451Sroberto 2204132451Sroberto /* have an Almanac, can start the SiteSurvey 2205132451Sroberto * (actually only need to get past the almanac_load where we diddle with At 2206132451Sroberto * command,- we can't change it after we start the HW_SS below 2207132451Sroberto */ 2208132451Sroberto 2209132451Sroberto mode = instance->init_type; 2210132451Sroberto switch (mode) { 2211132451Sroberto case 0: /* NO initialization, don't change anything */ 2212132451Sroberto case 1: /* Use given Position */ 2213132451Sroberto case 3: 2214132451Sroberto instance->site_survey = ONCORE_SS_DONE; 2215290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 221682498Sroberto break; 2217132451Sroberto 221882498Sroberto case 2: 2219132451Sroberto case 4: /* Site Survey */ 2220290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING"); 2221132451Sroberto instance->site_survey = ONCORE_SS_TESTING; 2222132451Sroberto instance->count1 = 1; 2223132451Sroberto if (instance->chan == 12) 2224290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */ 2225132451Sroberto else 2226290001Sglebius oncore_sendmsg(instance, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */ 2227132451Sroberto break; 2228132451Sroberto } 222982498Sroberto 2230132451Sroberto /* Read back PPS Offset for Output */ 2231132451Sroberto /* Nb. This will fail silently for early UT (no plus) and M12 models */ 223282498Sroberto 2233290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); 223482498Sroberto 2235132451Sroberto /* Read back Cable Delay for Output */ 223682498Sroberto 2237290001Sglebius oncore_sendmsg(instance, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); 2238132451Sroberto 2239132451Sroberto /* Read back Satellite Mask Angle for Output */ 2240132451Sroberto 2241290001Sglebius oncore_sendmsg(instance, oncore_cmd_Agx, sizeof(oncore_cmd_Agx)); 2242132451Sroberto } 2243132451Sroberto 2244132451Sroberto 2245182007Sroberto /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is 2246182007Sroberto * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey) 2247182007Sroberto * We must do the Gd3, and then wait a cycle or two for things to settle, 2248182007Sroberto * then check Ha[130]&0x10 to see if a SS is in progress. 2249182007Sroberto * We will set SW if HW has not been set after an appropriate delay. 2250182007Sroberto */ 2251132451Sroberto 2252182007Sroberto if (instance->site_survey == ONCORE_SS_TESTING) { 2253182007Sroberto if (instance->chan == 12) { 2254182007Sroberto if (instance->count1) { 2255182007Sroberto if (instance->count1++ > 5 || instance->BEHa[130]&0x10) { 2256182007Sroberto instance->count1 = 0; 2257182007Sroberto if (instance->BEHa[130]&0x10) { 2258290001Sglebius oncore_log(instance, LOG_NOTICE, 2259182007Sroberto "Initiating hardware 3D site survey"); 2260132451Sroberto 2261290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW"); 2262182007Sroberto instance->site_survey = ONCORE_SS_HW; 2263182007Sroberto } else { 2264290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW"); 2265182007Sroberto instance->site_survey = ONCORE_SS_SW; 2266182007Sroberto } 2267132451Sroberto } 226882498Sroberto } 2269182007Sroberto } else { 2270182007Sroberto if (instance->count1) { 2271182007Sroberto if (instance->count1++ > 5) { 2272182007Sroberto instance->count1 = 0; 2273182007Sroberto /* 2274182007Sroberto * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec 2275182007Sroberto * wait after the @@At2/@@Gd3 command we have not changed the state to 2276182007Sroberto * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then 2277182007Sroberto * the variable would have been changed by now. 2278182007Sroberto * There are three possibilities: 2279182007Sroberto * 6/8chan 2280182007Sroberto * (a) We did not get a response to the @@At0 or @@At2 commands, 2281182007Sroberto * and it must be a GT/GT+/SL with no position hold mode. 2282182007Sroberto * We will have to do it ourselves. 2283182007Sroberto * (b) We saw the @@At0, @@At2 commands, but @@At2 failed, 2284182007Sroberto * must be a VP or older UT which doesn't have Site Survey mode. 2285182007Sroberto * We will have to do it ourselves. 2286182007Sroberto * 12chan 2287182007Sroberto * (c) We saw the @@Gd command, and saw H[13]*0x10 2288182007Sroberto * We will have to do it ourselves (done above) 2289182007Sroberto */ 2290182007Sroberto 2291290001Sglebius oncore_log_f(instance, LOG_INFO, 2292290001Sglebius "Initiating software 3D site survey (%d samples)", 2293290001Sglebius POS_HOLD_AVERAGE); 2294182007Sroberto 2295290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW"); 2296182007Sroberto instance->site_survey = ONCORE_SS_SW; 2297182007Sroberto 2298182007Sroberto instance->ss_lat = instance->ss_long = instance->ss_ht = 0; 2299182007Sroberto if (instance->chan == 12) 2300290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */ 2301182007Sroberto else { 2302290001Sglebius oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ 2303290001Sglebius oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */ 2304182007Sroberto } 2305182007Sroberto } 2306182007Sroberto } 230782498Sroberto } 230882498Sroberto } 230982498Sroberto 2310132451Sroberto /* check the mode we are in 0/2/3D */ 231182498Sroberto 2312132451Sroberto if (instance->chan == 6) { 2313132451Sroberto if (instance->BEHa[64]&0x8) 2314132451Sroberto instance->mode = MODE_0D; 2315132451Sroberto else if (instance->BEHa[64]&0x10) 2316132451Sroberto instance->mode = MODE_2D; 2317132451Sroberto else if (instance->BEHa[64]&0x20) 2318132451Sroberto instance->mode = MODE_3D; 2319132451Sroberto } else if (instance->chan == 8) { 2320132451Sroberto if (instance->BEHa[72]&0x8) 2321132451Sroberto instance->mode = MODE_0D; 2322132451Sroberto else if (instance->BEHa[72]&0x10) 2323132451Sroberto instance->mode = MODE_2D; 2324132451Sroberto else if (instance->BEHa[72]&0x20) 2325132451Sroberto instance->mode = MODE_3D; 2326132451Sroberto } else if (instance->chan == 12) { 2327132451Sroberto int bits; 232854359Sroberto 2329132451Sroberto bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 2330132451Sroberto if (bits == 0x4) 2331132451Sroberto instance->mode = MODE_0D; 2332132451Sroberto else if (bits == 0x6) 2333132451Sroberto instance->mode = MODE_2D; 2334132451Sroberto else if (bits == 0x7) 2335132451Sroberto instance->mode = MODE_3D; 2336132451Sroberto } 233754359Sroberto 2338132451Sroberto /* copy the record to the (extra) location in SHMEM */ 2339132451Sroberto 2340132451Sroberto if (instance->shmem) { 2341132451Sroberto int i; 2342132451Sroberto u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */ 2343132451Sroberto 2344132451Sroberto switch(instance->chan) { 2345132451Sroberto case 6: smp = &instance->shmem[instance->shmem_Ba]; break; 2346132451Sroberto case 8: smp = &instance->shmem[instance->shmem_Ea]; break; 2347132451Sroberto case 12: smp = &instance->shmem[instance->shmem_Ha]; break; 2348182007Sroberto default: smp = (u_char *) NULL; break; 234954359Sroberto } 2350132451Sroberto 2351132451Sroberto switch (instance->mode) { 2352132451Sroberto case MODE_0D: i = 1; break; /* 0D, Position Hold */ 2353132451Sroberto case MODE_2D: i = 2; break; /* 2D, Altitude Hold */ 2354132451Sroberto case MODE_3D: i = 3; break; /* 3D fix */ 2355132451Sroberto default: i = 0; break; 2356132451Sroberto } 2357132451Sroberto 2358182007Sroberto if (i && smp != NULL) { 2359132451Sroberto i *= (len+6); 2360132451Sroberto smp[i + 2]++; 2361132451Sroberto memcpy(&smp[i+3], buf, (size_t) (len+3)); 2362132451Sroberto } 236354359Sroberto } 236454359Sroberto 2365132451Sroberto /* 2366182007Sroberto * check if traim timer active 2367132451Sroberto * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond 2368132451Sroberto */ 236954359Sroberto 2370132451Sroberto if (instance->traim_delay) { 2371132451Sroberto if (instance->traim_delay++ > 5) { 2372132451Sroberto instance->traim = 0; 2373132451Sroberto instance->traim_delay = 0; 2374132451Sroberto cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; 2375290001Sglebius oncore_log(instance, LOG_INFO, cp); 2376132451Sroberto 2377132451Sroberto oncore_set_traim(instance); 2378132451Sroberto } else 2379132451Sroberto return; 2380132451Sroberto 2381132451Sroberto } 2382132451Sroberto 2383132451Sroberto /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */ 2384132451Sroberto 2385132451Sroberto if (!instance->have_dH && !instance->traim_delay) 2386132451Sroberto oncore_compute_dH(instance); 2387132451Sroberto 2388132451Sroberto /* 2389132451Sroberto * must be ONCORE_RUN if we are here. 2390132451Sroberto * Have # chan and TRAIM by now. 2391132451Sroberto */ 2392132451Sroberto 2393132451Sroberto instance->pp->year = buf[6]*256+buf[7]; 2394132451Sroberto instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); 2395132451Sroberto instance->pp->hour = buf[8]; 2396132451Sroberto instance->pp->minute = buf[9]; 2397132451Sroberto instance->pp->second = buf[10]; 2398132451Sroberto 2399132451Sroberto /* 2400132451Sroberto * Are we doing a Hardware or Software Site Survey? 2401132451Sroberto */ 2402132451Sroberto 2403132451Sroberto if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW) 2404132451Sroberto oncore_ss(instance); 2405132451Sroberto 2406132451Sroberto /* see if we ever saw a response from the @@Ayx above */ 2407132451Sroberto 2408132451Sroberto if (instance->count2) { 2409132451Sroberto if (instance->count2++ > 5) { /* this delay to check on @@Ay command */ 2410132451Sroberto instance->count2 = 0; 2411132451Sroberto 2412132451Sroberto /* Have we seen an Ay (1PPS time offset) command response */ 2413132451Sroberto /* if not, and non-zero offset, zero the offset, and send message */ 2414132451Sroberto 2415132451Sroberto if (!instance->saw_Ay && instance->offset) { 2416290001Sglebius oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored"); 241782498Sroberto instance->offset = 0; 241882498Sroberto } 241982498Sroberto } 242054359Sroberto } 242154359Sroberto 2422132451Sroberto /* 2423132451Sroberto * Check the leap second status once per day. 2424132451Sroberto */ 242554359Sroberto 2426132451Sroberto oncore_check_leap_sec(instance); 242754359Sroberto 2428132451Sroberto /* 2429132451Sroberto * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 2430132451Sroberto */ 2431132451Sroberto 2432132451Sroberto if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) 2433132451Sroberto oncore_shmem_get_3D(instance); 2434132451Sroberto 2435132451Sroberto if (!instance->traim) /* NO traim, no BnEnHn, go get tick */ 2436132451Sroberto oncore_get_timestamp(instance, instance->offset, instance->offset); 243754359Sroberto} 243854359Sroberto 243954359Sroberto 244054359Sroberto 2441132451Sroberto/* Almanac Status */ 2442132451Sroberto 2443132451Srobertostatic void 2444132451Srobertooncore_msg_Bd( 2445132451Sroberto struct instance *instance, 2446132451Sroberto u_char *buf, 2447132451Sroberto size_t len 2448132451Sroberto ) 2449132451Sroberto{ 2450290001Sglebius oncore_log_f(instance, LOG_NOTICE, 2451290001Sglebius "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x", 2452290001Sglebius ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], 2453290001Sglebius buf[7], w32(&buf[8])); 2454132451Sroberto} 2455132451Sroberto 2456132451Sroberto 2457132451Sroberto 2458132451Sroberto/* get leap-second warning message */ 2459132451Sroberto 246082498Sroberto/* 2461132451Sroberto * @@Bj does NOT behave as documented in current Oncore firmware. 2462132451Sroberto * It turns on the LEAP indicator when the data is set, and does not, 2463132451Sroberto * as documented, wait until the beginning of the month when the 2464132451Sroberto * leap second will occur. 2465132451Sroberto * Since this firmware bug will never be fixed in all the outstanding Oncore receivers 2466132451Sroberto * @@Bj is only called in June/December. 246782498Sroberto */ 246882498Sroberto 246954359Srobertostatic void 2470132451Srobertooncore_msg_Bj( 247154359Sroberto struct instance *instance, 247254359Sroberto u_char *buf, 247382498Sroberto size_t len 247454359Sroberto ) 247554359Sroberto{ 2476132451Sroberto const char *cp; 247782498Sroberto 2478290001Sglebius instance->saw_Bj = 1; 2479290001Sglebius 2480132451Sroberto switch(buf[4]) { 2481132451Sroberto case 1: 2482182007Sroberto instance->pp->leap = LEAP_ADDSECOND; 2483182007Sroberto cp = "Set pp.leap to LEAP_ADDSECOND"; 2484132451Sroberto break; 2485132451Sroberto case 2: 2486182007Sroberto instance->pp->leap = LEAP_DELSECOND; 2487182007Sroberto cp = "Set pp.leap to LEAP_DELSECOND"; 2488132451Sroberto break; 2489132451Sroberto case 0: 2490132451Sroberto default: 2491182007Sroberto instance->pp->leap = LEAP_NOWARNING; 2492182007Sroberto cp = "Set pp.leap to LEAP_NOWARNING"; 2493132451Sroberto break; 2494132451Sroberto } 2495290001Sglebius oncore_log(instance, LOG_NOTICE, cp); 2496132451Sroberto} 249782498Sroberto 2498132451Sroberto 2499132451Sroberto 2500132451Srobertostatic void 2501290001Sglebiusoncore_msg_Bl( 2502290001Sglebius struct instance *instance, 2503290001Sglebius u_char *buf, 2504290001Sglebius size_t len 2505290001Sglebius ) 2506290001Sglebius{ 2507290001Sglebius int subframe, valid, page, i, j, tow; 2508290001Sglebius int day_now, day_lsf; 2509290001Sglebius const char *cp; 2510290001Sglebius enum { 2511290001Sglebius WARN_NOT_YET, 2512290001Sglebius WARN_0, 2513290001Sglebius WARN_PLUS, 2514290001Sglebius WARN_MINUS 2515290001Sglebius } warn; 2516290001Sglebius 2517290001Sglebius day_now = day_lsf = 0; 2518290001Sglebius cp = NULL; /* keep gcc happy */ 2519290001Sglebius 2520290001Sglebius subframe = buf[6] & 017; 2521290001Sglebius valid = (buf[6] >> 4) & 017; 2522290001Sglebius page = buf[7]; 2523290001Sglebius 2524290001Sglebius if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) { 2525290001Sglebius instance->Bl.dt_ls = buf[32]; 2526290001Sglebius instance->Bl.WN_lsf = buf[33]; 2527290001Sglebius instance->Bl.DN_lsf = buf[34]; 2528290001Sglebius instance->Bl.dt_lsf = buf[35]; 2529290001Sglebius instance->Bl.lsf_flg++; 2530290001Sglebius } 2531290001Sglebius if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) { 2532290001Sglebius i = (buf[7+7]<<8) + buf[7+8]; 2533290001Sglebius instance->Bl.WN = i >> 6; 2534290001Sglebius tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6]; 2535290001Sglebius tow >>= 7; 2536290001Sglebius tow = tow & 0377777; 2537290001Sglebius tow <<= 2; 2538290001Sglebius instance->Bl.DN = tow/57600L + 1; 2539290001Sglebius instance->Bl.wn_flg++; 2540290001Sglebius } 2541290001Sglebius if (instance->Bl.wn_flg && instance->Bl.lsf_flg) { 2542290001Sglebius instance->Bl.wn_flg = instance->Bl.lsf_flg = 0; 2543290001Sglebius oncore_cmd_Bl[2] = 0; 2544290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl); 2545290001Sglebius oncore_cmd_Bl[2] = 1; 2546290001Sglebius 2547290001Sglebius i = instance->Bl.WN&01400; 2548290001Sglebius instance->Bl.WN_lsf |= i; 2549290001Sglebius 2550290001Sglebius /* have everything I need, doit */ 2551290001Sglebius 2552290001Sglebius i = (instance->Bl.WN_lsf - instance->Bl.WN); 2553290001Sglebius if (i < 0) 2554290001Sglebius i += 1024; 2555290001Sglebius day_now = instance->Bl.DN; 2556290001Sglebius day_lsf = 7*i + instance->Bl.DN_lsf; 2557290001Sglebius 2558290001Sglebius /* ignore if in past or more than a month in future */ 2559290001Sglebius 2560290001Sglebius warn = WARN_NOT_YET; 2561290001Sglebius if (day_lsf >= day_now && day_lsf - day_now < 32) { 2562290001Sglebius /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */ 2563290001Sglebius if (day_lsf - day_now < 28 || instance->BEHa[5] < 20) { 2564290001Sglebius i = instance->Bl.dt_lsf - instance->Bl.dt_ls; 2565290001Sglebius switch (i) { 2566290001Sglebius case -1: 2567290001Sglebius warn = WARN_MINUS; 2568290001Sglebius break; 2569290001Sglebius case 0: 2570290001Sglebius warn = WARN_0; 2571290001Sglebius break; 2572290001Sglebius case 1: 2573290001Sglebius warn = WARN_PLUS; 2574290001Sglebius break; 2575290001Sglebius } 2576290001Sglebius } 2577290001Sglebius } 2578290001Sglebius 2579290001Sglebius switch (warn) { 2580290001Sglebius case WARN_0: 2581290001Sglebius case WARN_NOT_YET: 2582290001Sglebius instance->peer->leap = LEAP_NOWARNING; 2583290001Sglebius cp = "Set peer.leap to LEAP_NOWARNING"; 2584290001Sglebius break; 2585290001Sglebius case WARN_MINUS: 2586290001Sglebius instance->peer->leap = LEAP_DELSECOND; 2587290001Sglebius cp = "Set peer.leap to LEAP_DELSECOND"; 2588290001Sglebius break; 2589290001Sglebius case WARN_PLUS: 2590290001Sglebius instance->peer->leap = LEAP_ADDSECOND; 2591290001Sglebius cp = "Set peer.leap to LEAP_ADDSECOND"; 2592290001Sglebius break; 2593290001Sglebius } 2594290001Sglebius oncore_log(instance, LOG_NOTICE, cp); 2595290001Sglebius 2596290001Sglebius i = instance->Bl.dt_lsf-instance->Bl.dt_ls; 2597290001Sglebius if (i) { 2598290001Sglebius j = (i >= 0) ? i : -i; /* abs(i) */ 2599290001Sglebius oncore_log_f(instance, LOG_NOTICE, 2600290001Sglebius "see Leap_Second (%c%d) in %d days", 2601290001Sglebius ((i >= 0) ? '+' : '-'), j, 2602290001Sglebius day_lsf-day_now); 2603290001Sglebius } 2604290001Sglebius } 2605290001Sglebius 2606290001Sglebius/* 2607290001Sglebius * Reg only wants the following output for "deeper" driver debugging. 2608290001Sglebius * See Bug 2142 and Bug 1866 2609290001Sglebius */ 2610290001Sglebius#if 0 2611290001Sglebius oncore_log_f(instance, LOG_DEBUG, 2612290001Sglebius "dt_ls = %d dt_lsf = %d WN = %d DN = %d WN_lsf = %d DNlsf = %d wn_flg = %d lsf_flg = %d Bl_day = %d", 2613290001Sglebius instance->Bl.dt_ls, instance->Bl.dt_lsf, 2614290001Sglebius instance->Bl.WN, instance->Bl.DN, 2615290001Sglebius instance->Bl.WN_lsf, instance->Bl.DN_lsf, 2616290001Sglebius instance->Bl.wn_flg, instance->Bl.lsf_flg, 2617290001Sglebius instance->Bl.Bl_day); 2618290001Sglebius#endif 2619290001Sglebius} 2620290001Sglebius 2621290001Sglebius 2622290001Sglebiusstatic void 2623132451Srobertooncore_msg_BnEnHn( 2624132451Sroberto struct instance *instance, 2625132451Sroberto u_char *buf, 2626132451Sroberto size_t len 2627132451Sroberto ) 2628132451Sroberto{ 2629132451Sroberto long dt1, dt2; 2630132451Sroberto 2631132451Sroberto if (instance->o_state != ONCORE_RUN) 2632132451Sroberto return; 2633132451Sroberto 2634132451Sroberto if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */ 2635132451Sroberto instance->traim_ck = 1; 2636132451Sroberto instance->traim_delay = 0; 2637290001Sglebius oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON"); 2638132451Sroberto 2639132451Sroberto oncore_set_traim(instance); 264082498Sroberto } 2641132451Sroberto 2642132451Sroberto memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */ 2643132451Sroberto 2644182007Sroberto if (!instance->traim) /* BnEnHn will be turned off in any case */ 2645182007Sroberto return; 2646182007Sroberto 2647132451Sroberto /* If Time RAIM doesn't like it, don't trust it */ 2648132451Sroberto 2649132451Sroberto if (buf[2] == 'H') { 2650290001Sglebius if (instance->BEHn[6]) { /* bad TRAIM */ 2651290001Sglebius oncore_log(instance, LOG_WARNING, "BAD TRAIM"); 2652132451Sroberto return; 2653290001Sglebius } 2654132451Sroberto 2655132451Sroberto dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2656182007Sroberto instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */ 2657132451Sroberto dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2658132451Sroberto } else { 2659132451Sroberto if (instance->BEHn[21]) /* bad TRAIM */ 2660132451Sroberto return; 2661132451Sroberto 2662132451Sroberto dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2663182007Sroberto instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */ 2664132451Sroberto dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2665132451Sroberto } 2666132451Sroberto 2667132451Sroberto oncore_get_timestamp(instance, dt1, dt2); 266882498Sroberto} 266982498Sroberto 267082498Sroberto 267182498Sroberto 267282498Sroberto/* Here for @@Ca, @@Fa and @@Ia messages */ 267382498Sroberto 2674132451Sroberto/* These are Self test Commands for 6, 8, and 12 chan receivers. 2675132451Sroberto * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE. 2676132451Sroberto * It was found that under some circumstances the following 267782498Sroberto * command would fail if issued immediately after the return from the 267882498Sroberto * @@Fa, but a 2sec delay seemed to fix things. Since simply calling 2679132451Sroberto * sleep(2) is wasteful, and may cause trouble for some OS's, repeating 2680132451Sroberto * itimer, we set a flag, and test it at the next POLL. If it hasn't 268182498Sroberto * been cleared, we reissue the @@Cj that is issued below. 268282498Sroberto * Note that we do a @@Cj at the beginning, and again here. 268382498Sroberto * The first is to get the info, the 2nd is just used as a safe command 268482498Sroberto * after the @@Fa for all Oncores (and it was in this posn in the 268582498Sroberto * original code). 268682498Sroberto */ 268782498Sroberto 268882498Srobertostatic void 268982498Srobertooncore_msg_CaFaIa( 269082498Sroberto struct instance *instance, 269182498Sroberto u_char *buf, 269282498Sroberto size_t len 269382498Sroberto ) 269482498Sroberto{ 2695132451Sroberto int i; 269682498Sroberto 269782498Sroberto if (instance->o_state == ONCORE_TEST_SENT) { 2698132451Sroberto enum antenna_state antenna; 269982498Sroberto 270082498Sroberto instance->timeout = 0; 270182498Sroberto 2702290001Sglebius#if ONCORE_VERBOSE_SELF_TEST 270382498Sroberto if (debug > 2) { 270482498Sroberto if (buf[2] == 'I') 2705290001Sglebius oncore_log_f(instance, LOG_DEBUG, 2706290001Sglebius ">>@@%ca %x %x %x", buf[2], 2707290001Sglebius buf[4], buf[5], buf[6]); 270882498Sroberto else 2709290001Sglebius oncore_log_f(instance, LOG_DEBUG, 2710290001Sglebius ">>@@%ca %x %x", buf[2], 2711290001Sglebius buf[4], buf[5]); 271282498Sroberto } 2713182007Sroberto#endif 271482498Sroberto 2715132451Sroberto antenna = (buf[4] & 0xc0) >> 6; 271682498Sroberto buf[4] &= ~0xc0; 271782498Sroberto 2718132451Sroberto i = buf[4] || buf[5]; 2719132451Sroberto if (buf[2] == 'I') i = i || buf[6]; 2720132451Sroberto if (i) { 2721290001Sglebius if (buf[2] == 'I') 2722290001Sglebius oncore_log_f(instance, LOG_ERR, 2723290001Sglebius "self test failed: result %02x %02x %02x", 2724290001Sglebius buf[4], buf[5], buf[6]); 2725290001Sglebius else 2726290001Sglebius oncore_log_f(instance, LOG_ERR, 2727290001Sglebius "self test failed: result %02x %02x", 2728290001Sglebius buf[4], buf[5]); 2729132451Sroberto 2730290001Sglebius oncore_log(instance, LOG_ERR, 2731290001Sglebius "ONCORE: self test failed, shutting down driver"); 2732290001Sglebius 2733132451Sroberto refclock_report(instance->peer, CEVNT_FAULT); 273482498Sroberto oncore_shutdown(instance->unit, instance->peer); 273582498Sroberto return; 273682498Sroberto } 273782498Sroberto 2738132451Sroberto /* report the current antenna state */ 273982498Sroberto 2740132451Sroberto oncore_antenna_report(instance, antenna); 274182498Sroberto 274282498Sroberto instance->o_state = ONCORE_INIT; 2743290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT"); 2744132451Sroberto 2745132451Sroberto instance->timeout = 4; 2746290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 274782498Sroberto } 274882498Sroberto} 274982498Sroberto 275082498Sroberto 275182498Sroberto 2752132451Sroberto/* 2753132451Sroberto * Demultiplex the almanac into shmem 2754132451Sroberto */ 275582498Sroberto 275682498Srobertostatic void 2757132451Srobertooncore_msg_Cb( 275882498Sroberto struct instance *instance, 275982498Sroberto u_char *buf, 276082498Sroberto size_t len 276182498Sroberto ) 276282498Sroberto{ 2763132451Sroberto int i; 276454359Sroberto 2765132451Sroberto if (instance->shmem == NULL) 2766132451Sroberto return; 276782498Sroberto 2768132451Sroberto if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26) 2769132451Sroberto i = buf[5]; 2770132451Sroberto else if (buf[4] == 4 && buf[5] <= 5) 2771132451Sroberto i = buf[5] + 24; 2772132451Sroberto else if (buf[4] == 4 && buf[5] <= 10) 2773132451Sroberto i = buf[5] + 23; 2774132451Sroberto else if (buf[4] == 4 && buf[5] == 25) 2775132451Sroberto i = 34; 2776132451Sroberto else { 2777290001Sglebius oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC"); 277854359Sroberto return; 2779132451Sroberto } 278054359Sroberto 2781132451Sroberto i *= 36; 2782132451Sroberto instance->shmem[instance->shmem_Cb + i + 2]++; 2783132451Sroberto memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); 278454359Sroberto 2785290001Sglebius#ifdef ONCORE_VERBOSE_MSG_CB 2786290001Sglebius oncore_log_f(instance, LOG_DEBUG, "See Cb [%d,%d]", buf[4], 2787290001Sglebius buf[5]); 2788132451Sroberto#endif 2789132451Sroberto} 279082498Sroberto 279182498Sroberto 2792132451Sroberto 2793132451Sroberto/* 2794132451Sroberto * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup 2795132451Sroberto * not so for VP (eeprom) or any unit with a battery 2796132451Sroberto */ 2797132451Sroberto 2798132451Srobertostatic void 2799132451Srobertooncore_msg_Cf( 2800132451Sroberto struct instance *instance, 2801132451Sroberto u_char *buf, 2802132451Sroberto size_t len 2803132451Sroberto ) 2804132451Sroberto{ 2805132451Sroberto if (instance->o_state == ONCORE_RESET_SENT) { 2806290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 2807132451Sroberto /* Reset set VP to IDLE */ 2808132451Sroberto instance->o_state = ONCORE_TEST_SENT; 2809290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 2810132451Sroberto 2811290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 281282498Sroberto } 2813132451Sroberto} 281482498Sroberto 281582498Sroberto 281682498Sroberto 2817132451Sroberto/* 2818132451Sroberto * This is the Grand Central Station for the Preliminary Initialization. 2819132451Sroberto * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running. 2820132451Sroberto * 2821132451Sroberto * We do an @@Cj whenever we need a safe command for all Oncores. 2822132451Sroberto * The @@Cj gets us back here where we can switch to the next phase of setup. 2823132451Sroberto * 2824132451Sroberto * o Once at the very beginning (in start) to get the Model number. 2825132451Sroberto * This info is printed, but no longer used. 2826132451Sroberto * o Again after we have determined the number of Channels in the receiver. 2827132451Sroberto * o And once later after we have done a reset and test, (which may hang), 2828132451Sroberto * as we are about to initialize the Oncore and start it running. 2829132451Sroberto * o We have one routine below for each case. 2830132451Sroberto */ 283182498Sroberto 2832132451Srobertostatic void 2833132451Srobertooncore_msg_Cj( 2834132451Sroberto struct instance *instance, 2835132451Sroberto u_char *buf, 2836132451Sroberto size_t len 2837132451Sroberto ) 2838132451Sroberto{ 2839132451Sroberto int mode; 284082498Sroberto 2841132451Sroberto memcpy(instance->Cj, buf, len); 284282498Sroberto 2843132451Sroberto instance->timeout = 0; 2844132451Sroberto if (instance->o_state == ONCORE_CHECK_ID) { 2845132451Sroberto oncore_msg_Cj_id(instance, buf, len); 2846132451Sroberto oncore_chan_test(instance); 2847132451Sroberto } else if (instance->o_state == ONCORE_HAVE_CHAN) { 2848132451Sroberto mode = instance->init_type; 2849132451Sroberto if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */ 2850132451Sroberto instance->o_state = ONCORE_RESET_SENT; 2851290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT"); 2852290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); 2853132451Sroberto } else { 2854132451Sroberto instance->o_state = ONCORE_TEST_SENT; 2855290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 285682498Sroberto } 285782498Sroberto } 285882498Sroberto 2859132451Sroberto if (instance->o_state == ONCORE_TEST_SENT) { 2860132451Sroberto if (instance->chan == 6) 2861290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); 2862132451Sroberto else if (instance->chan == 8) 2863290001Sglebius oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); 2864132451Sroberto else if (instance->chan == 12) 2865290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); 2866132451Sroberto } else if (instance->o_state == ONCORE_INIT) 2867132451Sroberto oncore_msg_Cj_init(instance, buf, len); 2868132451Sroberto} 286982498Sroberto 287082498Sroberto 287182498Sroberto 2872132451Sroberto/* The information on determining a Oncore 'Model', viz VP, UT, etc, from 2873132451Sroberto * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> 2874132451Sroberto * and from Motorola. Until recently Rick was the only source of 2875132451Sroberto * this information as Motorola didn't give the information out. 2876132451Sroberto * 2877132451Sroberto * Determine the Type from the Model #, this determines #chan and if TRAIM is 2878132451Sroberto * available. 2879132451Sroberto * 2880132451Sroberto * The Information from this routine is NO LONGER USED. 2881132451Sroberto * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED 2882132451Sroberto */ 288382498Sroberto 2884132451Srobertostatic void 2885132451Srobertooncore_msg_Cj_id( 2886132451Sroberto struct instance *instance, 2887132451Sroberto u_char *buf, 2888132451Sroberto size_t len 2889132451Sroberto ) 2890132451Sroberto{ 2891290001Sglebius char *cp2, Model[21]; 2892290001Sglebius const char *cp, *cp1; 2893132451Sroberto 2894132451Sroberto /* Write Receiver ID message to clockstats file */ 2895132451Sroberto 2896132451Sroberto instance->Cj[294] = '\0'; 2897290001Sglebius for (cp= (char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { 2898290001Sglebius char *cpw = strchr(cp, '\r'); 2899290001Sglebius if (!cpw) 2900290001Sglebius cpw = (char *)&instance->Cj[294]; 2901290001Sglebius *cpw = '\0'; 2902290001Sglebius oncore_log(instance, LOG_NOTICE, cp); 2903290001Sglebius *cpw = '\r'; 2904290001Sglebius cp = cpw+2; 290582498Sroberto } 290682498Sroberto 2907132451Sroberto /* next, the Firmware Version and Revision numbers */ 290882498Sroberto 2909182007Sroberto instance->version = atoi((char *) &instance->Cj[83]); 2910182007Sroberto instance->revision = atoi((char *) &instance->Cj[111]); 291182498Sroberto 2912132451Sroberto /* from model number decide which Oncore this is, 2913132451Sroberto and then the number of channels */ 291482498Sroberto 2915182007Sroberto for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ 2916132451Sroberto ; 2917132451Sroberto cp1 = cp; 2918132451Sroberto cp2 = Model; 2919290001Sglebius for (; !isspace((unsigned char)*cp) && cp-cp1 < 20; cp++, cp2++) 2920132451Sroberto *cp2 = *cp; 2921132451Sroberto *cp2 = '\0'; 2922132451Sroberto 2923132451Sroberto cp = 0; 2924132451Sroberto if (!strncmp(Model, "PVT6", (size_t) 4)) { 2925132451Sroberto cp = "PVT6"; 2926132451Sroberto instance->model = ONCORE_PVT6; 2927132451Sroberto } else if (Model[0] == 'A') { 2928132451Sroberto cp = "Basic"; 2929132451Sroberto instance->model = ONCORE_BASIC; 2930132451Sroberto } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { 2931132451Sroberto cp = "VP"; 2932132451Sroberto instance->model = ONCORE_VP; 2933132451Sroberto } else if (Model[0] == 'P') { 2934132451Sroberto cp = "M12"; 2935132451Sroberto instance->model = ONCORE_M12; 2936132451Sroberto } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') { 2937132451Sroberto if (Model[5] == 'N') { 2938132451Sroberto cp = "GT"; 2939132451Sroberto instance->model = ONCORE_GT; 2940132451Sroberto } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { 2941132451Sroberto cp = "GT+"; 2942132451Sroberto instance->model = ONCORE_GTPLUS; 2943132451Sroberto } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { 2944132451Sroberto cp = "UT"; 2945132451Sroberto instance->model = ONCORE_UT; 2946132451Sroberto } else if (Model[1] == '5' && Model[5] == 'G') { 2947132451Sroberto cp = "UT+"; 2948132451Sroberto instance->model = ONCORE_UTPLUS; 2949132451Sroberto } else if (Model[1] == '6' && Model[5] == 'G') { 2950132451Sroberto cp = "SL"; 2951132451Sroberto instance->model = ONCORE_SL; 2952132451Sroberto } else { 2953132451Sroberto cp = "Unknown"; 2954132451Sroberto instance->model = ONCORE_UNKNOWN; 295554359Sroberto } 2956132451Sroberto } else { 2957132451Sroberto cp = "Unknown"; 2958132451Sroberto instance->model = ONCORE_UNKNOWN; 295954359Sroberto } 296054359Sroberto 2961132451Sroberto /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */ 296254359Sroberto 2963290001Sglebius oncore_log_f(instance, LOG_INFO, 2964290001Sglebius "This looks like an Oncore %s with version %d.%d firmware.", 2965290001Sglebius cp, instance->version, instance->revision); 296682498Sroberto 2967132451Sroberto instance->chan_id = 8; /* default */ 2968132451Sroberto if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2969132451Sroberto instance->chan_id = 6; 2970132451Sroberto else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2971132451Sroberto instance->chan_id = 8; 2972132451Sroberto else if (instance->model == ONCORE_M12) 2973132451Sroberto instance->chan_id = 12; 297482498Sroberto 2975132451Sroberto instance->traim_id = 0; /* default */ 2976132451Sroberto if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2977132451Sroberto instance->traim_id = 0; 2978132451Sroberto else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2979132451Sroberto instance->traim_id = 1; 2980132451Sroberto else if (instance->model == ONCORE_M12) 2981132451Sroberto instance->traim_id = -1; 298282498Sroberto 2983290001Sglebius oncore_log_f(instance, LOG_INFO, "Channels = %d, TRAIM = %s", 2984290001Sglebius instance->chan_id, 2985290001Sglebius ((instance->traim_id < 0) 2986290001Sglebius ? "UNKNOWN" 2987290001Sglebius : (instance->traim_id > 0) 2988290001Sglebius ? "ON" 2989290001Sglebius : "OFF")); 2990132451Sroberto} 2991132451Sroberto 2992132451Sroberto 2993132451Sroberto 2994132451Sroberto/* OK, know type of Oncore, have possibly reset it, and have tested it. 2995132451Sroberto * We know the number of channels. 2996132451Sroberto * We will determine whether we have TRAIM before we actually start. 2997132451Sroberto * Now initialize. 2998132451Sroberto */ 2999132451Sroberto 3000132451Srobertostatic void 3001132451Srobertooncore_msg_Cj_init( 3002132451Sroberto struct instance *instance, 3003132451Sroberto u_char *buf, 3004132451Sroberto size_t len 3005132451Sroberto ) 3006132451Sroberto{ 3007290001Sglebius u_char Cmd[20]; 3008132451Sroberto int mode; 3009132451Sroberto 3010132451Sroberto 3011132451Sroberto /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to 3012132451Sroberto * start again if we go from 0D -> 3D, then loses them again when we 3013132451Sroberto * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. 3014132451Sroberto * For NOW we will turn this aspect of filling SHMEM off for the M12 301582498Sroberto */ 301682498Sroberto 3017132451Sroberto if (instance->chan == 12) { 3018132451Sroberto instance->shmem_bad_Ea = 1; 3019290001Sglebius oncore_log_f(instance, LOG_NOTICE, 3020290001Sglebius "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", 3021290001Sglebius instance->version, instance->revision); 302254359Sroberto } 302354359Sroberto 3024290001Sglebius oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 3025290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */ 3026290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */ 3027290001Sglebius oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */ 3028290001Sglebius oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */ 3029290001Sglebius oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */ 3030290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */ 303182498Sroberto 3032132451Sroberto mode = instance->init_type; 303382498Sroberto 3034132451Sroberto /* If there is Position input in the Config file 3035132451Sroberto * and mode = (1,3) set it as posn hold posn, goto 0D mode. 3036132451Sroberto * or mode = (2,4) set it as INITIAL position, and do Site Survey. 303782498Sroberto */ 303854359Sroberto 3039132451Sroberto if (instance->posn_set) { 3040290001Sglebius oncore_log(instance, LOG_INFO, "Setting Posn from input data"); 3041132451Sroberto oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */ 3042132451Sroberto } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */ 3043132451Sroberto if (instance->chan != 12) 3044290001Sglebius oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx)); 304582498Sroberto 3046132451Sroberto if (mode != 0) { 3047132451Sroberto /* cable delay in ns */ 3048132451Sroberto memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az)); 3049290001Sglebius w32_buf(&Cmd[-2+4], (int)instance->delay); 3050290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */ 305182498Sroberto 3052132451Sroberto /* PPS offset in ns */ 3053290001Sglebius memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */ 3054290001Sglebius w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */ 3055290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ay)); 3056132451Sroberto 3057132451Sroberto /* Satellite mask angle */ 3058132451Sroberto 3059132451Sroberto if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */ 3060132451Sroberto memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag)); 3061132451Sroberto Cmd[-2+4] = instance->Ag; 3062290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ag)); 3063132451Sroberto } 306482498Sroberto } 306582498Sroberto 3066132451Sroberto /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s 3067132451Sroberto * now we're really running 3068132451Sroberto * these were ALL started in the chan test, 3069132451Sroberto * However, if we had mode=3,4 then commands got turned off, so we turn 3070132451Sroberto * them on again here just in case 307154359Sroberto */ 307254359Sroberto 3073132451Sroberto if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */ 3074290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 3075290001Sglebius oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 3076290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 3077290001Sglebius oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3078290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba )); 3079132451Sroberto } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */ 3080290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 3081290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 3082290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 3083290001Sglebius oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3084290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea )); 3085132451Sroberto } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */ 3086290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 3087290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 3088290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 3089290001Sglebius oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 3090290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha )); 3091290001Sglebius oncore_cmd_Gc[2] = (instance->pps_control < 0) ? 1 : instance->pps_control; 3092290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* PPS off/continuous/Tracking 1+sat/TRAIM */ 309354359Sroberto } 309454359Sroberto 3095132451Sroberto instance->count = 1; 3096132451Sroberto instance->o_state = ONCORE_ALMANAC; 3097290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC"); 3098132451Sroberto} 309982498Sroberto 310054359Sroberto 310154359Sroberto 3102132451Sroberto/* 12chan position */ 310354359Sroberto 3104132451Srobertostatic void 3105132451Srobertooncore_msg_Ga( 3106132451Sroberto struct instance *instance, 3107132451Sroberto u_char *buf, 3108132451Sroberto size_t len 3109132451Sroberto ) 3110132451Sroberto{ 3111132451Sroberto long lat, lon, ht; 3112132451Sroberto double Lat, Lon, Ht; 311354359Sroberto 311454359Sroberto 3115132451Sroberto lat = buf_w32(&buf[4]); 3116132451Sroberto lon = buf_w32(&buf[8]); 3117132451Sroberto ht = buf_w32(&buf[12]); /* GPS ellipsoid */ 311854359Sroberto 3119132451Sroberto Lat = lat; 3120132451Sroberto Lon = lon; 3121132451Sroberto Ht = ht; 312254359Sroberto 3123132451Sroberto Lat /= 3600000; 3124132451Sroberto Lon /= 3600000; 3125132451Sroberto Ht /= 100; 3126132451Sroberto 3127290001Sglebius oncore_log_f(instance, LOG_NOTICE, 3128290001Sglebius "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, 3129290001Sglebius Lon, Ht); 3130132451Sroberto 3131132451Sroberto instance->ss_lat = lat; 3132132451Sroberto instance->ss_long = lon; 3133132451Sroberto instance->ss_ht = ht; 313454359Sroberto 3135132451Sroberto oncore_print_posn(instance); 3136132451Sroberto} 313782498Sroberto 313882498Sroberto 313982498Sroberto 3140132451Sroberto/* 12 chan time/date */ 314182498Sroberto 3142132451Srobertostatic void 3143132451Srobertooncore_msg_Gb( 3144132451Sroberto struct instance *instance, 3145132451Sroberto u_char *buf, 3146132451Sroberto size_t len 3147132451Sroberto ) 3148132451Sroberto{ 3149290001Sglebius const char * gmts; 3150132451Sroberto int mo, d, y, h, m, s, gmth, gmtm; 315182498Sroberto 3152132451Sroberto mo = buf[4]; 3153132451Sroberto d = buf[5]; 3154132451Sroberto y = 256*buf[6]+buf[7]; 3155132451Sroberto 3156132451Sroberto h = buf[8]; 3157132451Sroberto m = buf[9]; 3158132451Sroberto s = buf[10]; 3159132451Sroberto 3160132451Sroberto gmts = ((buf[11] == 0) ? "+" : "-"); 3161132451Sroberto gmth = buf[12]; 3162132451Sroberto gmtm = buf[13]; 3163132451Sroberto 3164290001Sglebius oncore_log_f(instance, LOG_NOTICE, 3165290001Sglebius "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)", 3166290001Sglebius d, months[mo-1], y, h, m, s, gmts, gmth, gmtm); 316754359Sroberto} 316854359Sroberto 316954359Sroberto 317054359Sroberto 3171290001Sglebius/* Response to PPS Control message (M12 and M12+T only ) */ 3172290001Sglebius 3173290001Sglebiusstatic void 3174290001Sglebiusoncore_msg_Gc( 3175290001Sglebius struct instance *instance, 3176290001Sglebius u_char *buf, 3177290001Sglebius size_t len 3178290001Sglebius ) 3179290001Sglebius{ 3180290001Sglebius const char *tbl[] = {"OFF", "ON", "SATELLITE", "TRAIM" }; 3181290001Sglebius 3182290001Sglebius instance->pps_control_msg_seen = 1; 3183290001Sglebius oncore_log_f(instance, LOG_INFO, "PPS Control set to %s", 3184290001Sglebius tbl[buf[4]]); 3185290001Sglebius} 3186290001Sglebius 3187290001Sglebius 3188290001Sglebius 3189132451Sroberto/* Leap Second for M12, gives all info from satellite message */ 3190132451Sroberto/* also in UT v3.0 */ 319182498Sroberto 319282498Srobertostatic void 3193132451Srobertooncore_msg_Gj( 319482498Sroberto struct instance *instance, 3195132451Sroberto u_char *buf, 3196132451Sroberto size_t len 319782498Sroberto ) 319882498Sroberto{ 3199290001Sglebius static const char * insrem[2] = { 3200290001Sglebius "removed", 3201290001Sglebius "inserted" 3202290001Sglebius }; 3203290001Sglebius 3204132451Sroberto int dt; 3205290001Sglebius const char *cp; 320654359Sroberto 3207132451Sroberto instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */ 320854359Sroberto 3209132451Sroberto /* print the message to verify whats there */ 321054359Sroberto 3211132451Sroberto dt = buf[5] - buf[4]; 321254359Sroberto 3213290001Sglebius oncore_log_f(instance, LOG_INFO, 3214290001Sglebius "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", 3215290001Sglebius buf[4], buf[5], 256 * buf[6] + buf[7], buf[8], 3216290001Sglebius buf[9], buf[10], 3217290001Sglebius (buf[14] + 256 * 3218290001Sglebius (buf[13] + 256 * (buf[12] + 256 * buf[11]))), 3219290001Sglebius buf[15], buf[16], buf[17]); 322054359Sroberto 3221290001Sglebius /* There seems to be eternal confusion about when a leap second 3222290001Sglebius * takes place. It's the second *before* the new TAI offset 3223290001Sglebius * becomes effective. But since the ONCORE receiver tells us 3224290001Sglebius * just that, we would have to do some time/date calculations to 3225290001Sglebius * get the actual leap second -- that is, the one that is 3226290001Sglebius * deleted or inserted. 3227290001Sglebius * 3228290001Sglebius * Going through all this for a simple log is probably overkill, 3229290001Sglebius * so for fixing bug#1050 the message output is changed to 3230290001Sglebius * reflect the fact that it tells the second after the leap 3231290001Sglebius * second. 3232290001Sglebius */ 3233290001Sglebius if (dt) 3234290001Sglebius oncore_log_f(instance, LOG_NOTICE, 3235290001Sglebius "Leap second %s (%d) before %04u-%02u-%02u/%02u:%02u:%02u", 3236290001Sglebius insrem[(dt > 0)], dt, 3237290001Sglebius 256u * buf[6] + buf[7], buf[8], buf[9], 3238290001Sglebius buf[15], buf[16], buf[17]); 3239290001Sglebius 3240132451Sroberto /* Only raise warning within a month of the leap second */ 324154359Sroberto 3242182007Sroberto instance->pp->leap = LEAP_NOWARNING; 3243182007Sroberto cp = "Set pp.leap to LEAP_NOWARNING"; 324454359Sroberto 3245132451Sroberto if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */ 3246132451Sroberto buf[8] == instance->BEHa[4]) { /* month */ 3247132451Sroberto if (dt) { 3248132451Sroberto if (dt < 0) { 3249182007Sroberto instance->pp->leap = LEAP_DELSECOND; 3250182007Sroberto cp = "Set pp.leap to LEAP_DELSECOND"; 3251132451Sroberto } else { 3252182007Sroberto instance->pp->leap = LEAP_ADDSECOND; 3253182007Sroberto cp = "Set pp.leap to LEAP_ADDSECOND"; 3254132451Sroberto } 325554359Sroberto } 3256132451Sroberto } 3257290001Sglebius oncore_log(instance, LOG_INFO, cp); 3258132451Sroberto} 325954359Sroberto 326054359Sroberto 326154359Sroberto 3262132451Sroberto/* Power on failure */ 326354359Sroberto 3264132451Srobertostatic void 3265132451Srobertooncore_msg_Sz( 3266132451Sroberto struct instance *instance, 3267132451Sroberto u_char *buf, 3268132451Sroberto size_t len 3269132451Sroberto ) 3270132451Sroberto{ 3271132451Sroberto if (instance && instance->peer) { 3272290001Sglebius oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On"); 3273132451Sroberto oncore_shutdown(instance->unit, instance->peer); 327454359Sroberto } 3275132451Sroberto} 327654359Sroberto 3277132451Sroberto/************** Small Subroutines ***************/ 327854359Sroberto 327954359Sroberto 3280132451Srobertostatic void 3281132451Srobertooncore_antenna_report( 3282132451Sroberto struct instance *instance, 3283132451Sroberto enum antenna_state new_state) 3284132451Sroberto{ 3285290001Sglebius const char *cp; 3286132451Sroberto 3287132451Sroberto if (instance->ant_state == new_state) 328854359Sroberto return; 328954359Sroberto 3290132451Sroberto switch (new_state) { 3291132451Sroberto case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break; 3292132451Sroberto case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break; 3293132451Sroberto case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break; 3294132451Sroberto case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break; 3295132451Sroberto default: cp = "GPS antenna: ?"; break; 329656746Sroberto } 329754359Sroberto 3298132451Sroberto instance->ant_state = new_state; 3299290001Sglebius oncore_log(instance, LOG_NOTICE, cp); 3300132451Sroberto} 330154359Sroberto 330254359Sroberto 330354359Sroberto 3304132451Srobertostatic void 3305132451Srobertooncore_chan_test( 3306132451Sroberto struct instance *instance 3307132451Sroberto ) 3308132451Sroberto{ 3309132451Sroberto /* subroutine oncore_Cj_id has determined the number of channels from the 3310132451Sroberto * model number of the attached oncore. This is not always correct since 3311132451Sroberto * the oncore could have non-standard firmware. Here we check (independently) by 3312132451Sroberto * trying a 6, 8, and 12 chan command, and see which responds. 3313132451Sroberto * Caution: more than one CAN respond. 331482498Sroberto * 3315132451Sroberto * This #chan is used by the code rather than that calculated from the model number. 331682498Sroberto */ 331782498Sroberto 3318132451Sroberto instance->o_state = ONCORE_CHECK_CHAN; 3319290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN"); 332054359Sroberto 3321132451Sroberto instance->count3 = 1; 3322290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); 3323290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); 3324290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); 3325132451Sroberto} 332682498Sroberto 332782498Sroberto 332882498Sroberto 3329132451Sroberto/* check for a GOOD Almanac, have we got one yet? */ 333054359Sroberto 3331132451Srobertostatic void 3332132451Srobertooncore_check_almanac( 3333132451Sroberto struct instance *instance 3334132451Sroberto ) 3335132451Sroberto{ 3336132451Sroberto if (instance->chan == 6) { 3337132451Sroberto instance->rsm.bad_almanac = instance->BEHa[64]&0x1; 3338132451Sroberto instance->rsm.bad_fix = instance->BEHa[64]&0x52; 3339132451Sroberto } else if (instance->chan == 8) { 3340132451Sroberto instance->rsm.bad_almanac = instance->BEHa[72]&0x1; 3341132451Sroberto instance->rsm.bad_fix = instance->BEHa[72]&0x52; 3342132451Sroberto } else if (instance->chan == 12) { 3343182007Sroberto int bits1, bits2, bits3; 3344132451Sroberto 3345132451Sroberto bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 3346132451Sroberto bits2 = instance->BEHa[130]; 3347132451Sroberto instance->rsm.bad_almanac = (bits2 & 0x80); 3348132451Sroberto instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); 3349132451Sroberto /* too few sat Bad Geom */ 3350182007Sroberto 3351182007Sroberto bits3 = instance->BEHa[141]; /* UTC parameters */ 3352182007Sroberto if (!instance->count5_set && (bits3 & 0xC0)) { 3353290001Sglebius instance->count5 = 4; /* was 2 [Bug 1766] */ 3354182007Sroberto instance->count5_set = 1; 3355182007Sroberto } 3356290001Sglebius#ifdef ONCORE_VERBOSE_CHECK_ALMANAC 3357290001Sglebius oncore_log_f(instance, LOG_DEBUG, 3358290001Sglebius "DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x", 3359290001Sglebius instance->BEHa[129], instance->BEHa[130], 3360290001Sglebius bits1, bits2, bits3, 3361290001Sglebius instance->mode == MODE_0D, 3362290001Sglebius instance->mode == MODE_2D, 3363290001Sglebius instance->mode == MODE_3D, 3364290001Sglebius instance->rsm.bad_almanac, 3365290001Sglebius instance->rsm.bad_fix); 3366290001Sglebius } 336754359Sroberto#endif 3368132451Sroberto } 3369132451Sroberto} 337054359Sroberto 337154359Sroberto 337254359Sroberto 3373132451Sroberto/* check the antenna for changes (did it get unplugged?) */ 337454359Sroberto 3375132451Srobertostatic void 3376132451Srobertooncore_check_antenna( 3377132451Sroberto struct instance *instance 3378132451Sroberto ) 3379132451Sroberto{ 3380132451Sroberto enum antenna_state antenna; /* antenna state */ 338182498Sroberto 3382132451Sroberto antenna = instance->ant_state; 3383132451Sroberto if (instance->chan == 12) 3384132451Sroberto antenna = (instance->BEHa[130] & 0x6 ) >> 1; 3385132451Sroberto else 3386132451Sroberto antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */ 338754359Sroberto 3388132451Sroberto oncore_antenna_report (instance, antenna); 3389132451Sroberto} 3390132451Sroberto 3391132451Sroberto 3392132451Sroberto 3393132451Sroberto/* 3394132451Sroberto * Check the leap second status once per day. 3395132451Sroberto * 3396132451Sroberto * Note that the ONCORE firmware for the Bj command is wrong at 3397132451Sroberto * least in the VP. 3398132451Sroberto * It starts advertising a LEAP SECOND as soon as the GPS satellite 3399132451Sroberto * data message (page 18, subframe 4) is updated to a date in the 3400132451Sroberto * future, and does not wait for the month that it will occur. 3401132451Sroberto * The event will usually be advertised several months in advance. 3402132451Sroberto * Since there is a one bit flag, there is no way to tell if it is 3403132451Sroberto * this month, or when... 3404132451Sroberto * 3405132451Sroberto * As such, we have the workaround below, of only checking for leap 3406132451Sroberto * seconds with the Bj command in June/December. 3407132451Sroberto * 3408132451Sroberto * The Gj command gives more information, and we can tell in which 3409132451Sroberto * month to apply the correction. 3410132451Sroberto * 3411132451Sroberto * Note that with the VP we COULD read the raw data message, and 3412132451Sroberto * interpret it ourselves, but since this is specific to this receiver 3413132451Sroberto * only, and the above workaround is adequate, we don't bother. 3414132451Sroberto */ 3415132451Sroberto 3416132451Srobertostatic void 3417132451Srobertooncore_check_leap_sec( 3418132451Sroberto struct instance *instance 3419132451Sroberto ) 3420132451Sroberto{ 3421290001Sglebius oncore_cmd_Bl[2] = 1; /* just to be sure */ 3422290001Sglebius if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */ 3423132451Sroberto instance->Bj_day = instance->BEHa[5]; 3424132451Sroberto 3425132451Sroberto if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */ 3426132451Sroberto if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) 3427290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3428290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl)); 3429132451Sroberto return; 3430132451Sroberto } 3431132451Sroberto 3432132451Sroberto if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */ 3433132451Sroberto instance->count4 = 1; 3434132451Sroberto 3435290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); 343654359Sroberto return; 343754359Sroberto } 343854359Sroberto 3439132451Sroberto /* Gj works for some 6/8 chan UT and the M12 */ 3440132451Sroberto /* if no response from Gj in 5 sec, we try Bj */ 3441132451Sroberto /* which isnt implemented in all the GT/UT either */ 344254359Sroberto 3443132451Sroberto if (instance->count4) { /* delay, waiting for Gj response */ 3444132451Sroberto if (instance->saw_Gj == 1) 3445132451Sroberto instance->count4 = 0; 3446132451Sroberto else if (instance->count4++ > 5) { /* delay, waiting for Gj response */ 3447132451Sroberto instance->saw_Gj = -1; /* didnt see it, will use Bj */ 3448132451Sroberto instance->count4 = 0; 3449290001Sglebius if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) { 3450290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3451290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl)); 3452290001Sglebius } 3453132451Sroberto } 345454359Sroberto } 345554359Sroberto} 345654359Sroberto 345754359Sroberto 345854359Sroberto 3459132451Sroberto/* check the message checksum, 3460132451Sroberto * buf points to START of message ( @@ ) 3461132451Sroberto * len is length WITH CR/LF. 346254359Sroberto */ 346382498Sroberto 3464132451Srobertostatic int 3465132451Srobertooncore_checksum_ok( 346654359Sroberto u_char *buf, 3467132451Sroberto int len 346854359Sroberto ) 346954359Sroberto{ 3470132451Sroberto int i, j; 347154359Sroberto 3472132451Sroberto j = 0; 3473132451Sroberto for (i = 2; i < len-3; i++) 3474132451Sroberto j ^= buf[i]; 347554359Sroberto 3476132451Sroberto return(j == buf[len-3]); 3477132451Sroberto} 347854359Sroberto 347954359Sroberto 348054359Sroberto 348154359Srobertostatic void 3482132451Srobertooncore_compute_dH( 3483132451Sroberto struct instance *instance 348454359Sroberto ) 348554359Sroberto{ 3486132451Sroberto int GPS, MSL; 348754359Sroberto 3488132451Sroberto /* Here calculate dH = GPS - MSL for output message */ 3489132451Sroberto /* also set Altitude Hold mode if GT */ 3490132451Sroberto 3491132451Sroberto instance->have_dH = 1; 3492132451Sroberto if (instance->chan == 12) { 3493132451Sroberto GPS = buf_w32(&instance->BEHa[39]); 3494132451Sroberto MSL = buf_w32(&instance->BEHa[43]); 3495132451Sroberto } else { 3496132451Sroberto GPS = buf_w32(&instance->BEHa[23]); 3497132451Sroberto MSL = buf_w32(&instance->BEHa[27]); 349854359Sroberto } 3499132451Sroberto instance->dH = GPS - MSL; 3500132451Sroberto instance->dH /= 100.; 3501132451Sroberto 3502132451Sroberto /* if MSL is not set, the calculation is meaningless */ 3503132451Sroberto 3504290001Sglebius if (MSL) /* not set ! */ 3505290001Sglebius oncore_log_f(instance, LOG_INFO, 3506290001Sglebius "dH = (GPS - MSL) = %.2fm", instance->dH); 350754359Sroberto} 350854359Sroberto 350954359Sroberto 3510132451Sroberto 3511132451Sroberto/* 3512132451Sroberto * try loading Almanac from shmem (where it was copied from shmem_old 3513132451Sroberto */ 3514132451Sroberto 351582498Srobertostatic void 3516132451Srobertooncore_load_almanac( 3517132451Sroberto struct instance *instance 351882498Sroberto ) 351982498Sroberto{ 3520132451Sroberto u_char *cp, Cmd[20]; 3521132451Sroberto int n; 3522132451Sroberto struct timeval tv; 3523132451Sroberto struct tm *tm; 352454359Sroberto 3525132451Sroberto if (!instance->shmem) 3526132451Sroberto return; 352782498Sroberto 3528290001Sglebius#ifndef ONCORE_VERBOSE_LOAD_ALMANAC 3529290001Sglebius for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 3530290001Sglebius cp += (n + 3)) { 3531182007Sroberto if (!strncmp((char *) cp, "@@Cb", 4) && 3532132451Sroberto oncore_checksum_ok(cp, 33) && 3533132451Sroberto (*(cp+4) == 4 || *(cp+4) == 5)) { 3534132451Sroberto write(instance->ttyfd, cp, n); 3535132451Sroberto oncore_print_Cb(instance, cp); 3536132451Sroberto } 3537132451Sroberto } 3538290001Sglebius#else /* ONCORE_VERBOSE_LOAD_ALMANAC follows */ 3539290001Sglebius for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 3540290001Sglebius cp += (n+3)) { 3541290001Sglebius oncore_log_f(instance, LOG_DEBUG, "See %c%c%c%c %d", 3542290001Sglebius *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4)); 3543132451Sroberto 3544132451Sroberto if (!strncmp(cp, "@@Cb", 4)) { 3545132451Sroberto oncore_print_Cb(instance, cp); 3546132451Sroberto if (oncore_checksum_ok(cp, 33)) { 3547132451Sroberto if (*(cp+4) == 4 || *(cp+4) == 5) { 3548290001Sglebius oncore_log(instance, LOG_DEBUG, "GOOD SF"); 3549132451Sroberto write(instance->ttyfd, cp, n); 3550132451Sroberto } else 3551290001Sglebius oncore_log(instance, LOG_DEBUG, "BAD SF"); 3552132451Sroberto } else 3553290001Sglebius oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM"); 3554132451Sroberto } 355582498Sroberto } 3556132451Sroberto#endif 355782498Sroberto 3558132451Sroberto /* Must load position and time or the Almanac doesn't do us any good */ 355982498Sroberto 3560132451Sroberto if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */ 3561290001Sglebius oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM"); 3562132451Sroberto for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { 3563182007Sroberto if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) || 3564182007Sroberto (instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) || 3565182007Sroberto (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) { 3566132451Sroberto int ii, jj, kk; 356782498Sroberto 3568132451Sroberto instance->posn_set = 1; 3569132451Sroberto ii = buf_w32(cp + 15); 3570132451Sroberto jj = buf_w32(cp + 19); 3571132451Sroberto kk = buf_w32(cp + 23); 3572290001Sglebius#ifdef ONCORE_VERBOSE_LOAD_ALMANAC 3573290001Sglebius oncore_log_f(instance, LOG_DEBUG, 3574290001Sglebius "SHMEM posn = %ld (%d, %d, %d)", 3575290001Sglebius (long)(cp-instance->shmem), 3576290001Sglebius ii, jj, kk); 3577182007Sroberto#endif 3578132451Sroberto if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */ 3579132451Sroberto instance->ss_lat = ii; 3580132451Sroberto instance->ss_long = jj; 3581132451Sroberto instance->ss_ht = kk; 3582132451Sroberto } 358382498Sroberto } 358482498Sroberto } 358582498Sroberto } 3586132451Sroberto oncore_set_posn(instance); 3587132451Sroberto 3588132451Sroberto /* and set time to time from Computer clock */ 3589132451Sroberto 3590290001Sglebius GETTIMEOFDAY(&tv, 0); 3591132451Sroberto tm = gmtime((const time_t *) &tv.tv_sec); 3592290001Sglebius 3593290001Sglebius#ifdef ONCORE_VERBOSE_LOAD_ALMANAC 3594290001Sglebius oncore_log_f(instance, LOG_DEBUG, "DATE %d %d %d, %d %d %d", 3595290001Sglebius 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, 3596290001Sglebius tm->tm_hour, tm->tm_min, tm->tm_sec); 3597132451Sroberto#endif 3598132451Sroberto if (instance->chan == 12) { 3599132451Sroberto memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb)); 3600182007Sroberto Cmd[-2+4] = tm->tm_mon + 1; 3601132451Sroberto Cmd[-2+5] = tm->tm_mday; 3602132451Sroberto Cmd[-2+6] = (1900+tm->tm_year)/256; 3603132451Sroberto Cmd[-2+7] = (1900+tm->tm_year)%256; 3604132451Sroberto Cmd[-2+8] = tm->tm_hour; 3605132451Sroberto Cmd[-2+9] = tm->tm_min; 3606132451Sroberto Cmd[-2+10] = tm->tm_sec; 3607132451Sroberto Cmd[-2+11] = 0; 3608132451Sroberto Cmd[-2+12] = 0; 3609132451Sroberto Cmd[-2+13] = 0; 3610290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Gb)); 3611132451Sroberto } else { 3612132451Sroberto /* First set GMT offset to zero */ 3613132451Sroberto 3614290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab)); 3615132451Sroberto 3616132451Sroberto memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac)); 3617182007Sroberto Cmd[-2+4] = tm->tm_mon + 1; 3618132451Sroberto Cmd[-2+5] = tm->tm_mday; 3619132451Sroberto Cmd[-2+6] = (1900+tm->tm_year)/256; 3620132451Sroberto Cmd[-2+7] = (1900+tm->tm_year)%256; 3621290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ac)); 3622132451Sroberto 3623132451Sroberto memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa)); 3624132451Sroberto Cmd[-2+4] = tm->tm_hour; 3625132451Sroberto Cmd[-2+5] = tm->tm_min; 3626132451Sroberto Cmd[-2+6] = tm->tm_sec; 3627290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Aa)); 3628132451Sroberto } 3629132451Sroberto 3630290001Sglebius oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac"); 363182498Sroberto} 363282498Sroberto 363382498Sroberto 363482498Sroberto 3635132451Sroberto/* Almanac data input */ 363682498Sroberto 363754359Srobertostatic void 3638132451Srobertooncore_print_Cb( 363954359Sroberto struct instance *instance, 3640132451Sroberto u_char *cp 364154359Sroberto ) 364254359Sroberto{ 3643290001Sglebius#ifdef ONCORE_VERBOSE_CB 3644132451Sroberto int ii; 3645290001Sglebius char Msg[160], Msg2[10]; 364654359Sroberto 3647290001Sglebius oncore_log_f(instance, LOG_DEBUG, "DEBUG: See: %c%c%c%c", *(cp), 3648290001Sglebius *(cp+1), *(cp+2), *(cp+3)); 364954359Sroberto 3650290001Sglebius snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4), 3651290001Sglebius *(cp+5)); 3652290001Sglebius for (ii = 0; ii < 33; ii++) { 3653290001Sglebius snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii)); 3654290001Sglebius strlcat(Msg, Msg2, sizeof(Msg)); 3655290001Sglebius } 3656290001Sglebius oncore_log(instance, LOG_DEBUG, Msg); 3657290001Sglebius 3658290001Sglebius oncore_log_f(instance, LOG_DEBUG, "Debug: Cb: [%d,%d]", *(cp+4), 3659290001Sglebius *(cp+5)); 3660132451Sroberto#endif 3661132451Sroberto} 366254359Sroberto 3663132451Sroberto 3664132451Sroberto#if 0 3665132451Srobertostatic void 3666132451Srobertooncore_print_array( 3667132451Sroberto u_char *cp, 3668132451Sroberto int n 3669132451Sroberto ) 3670132451Sroberto{ 3671132451Sroberto int jj, i, j, nn; 3672132451Sroberto 3673132451Sroberto nn = 0; 3674132451Sroberto printf("\nTOP\n"); 3675132451Sroberto jj = n/16; 3676132451Sroberto for (j=0; j<jj; j++) { 3677132451Sroberto printf("%4d: ", nn); 3678132451Sroberto nn += 16; 3679132451Sroberto for (i=0; i<16; i++) 3680132451Sroberto printf(" %o", *cp++); 3681132451Sroberto printf("\n"); 3682132451Sroberto } 368382498Sroberto} 3684132451Sroberto#endif 368554359Sroberto 368654359Sroberto 368782498Srobertostatic void 3688132451Srobertooncore_print_posn( 368982498Sroberto struct instance *instance 369082498Sroberto ) 369182498Sroberto{ 3692290001Sglebius char ew, ns; 369382498Sroberto double xd, xm, xs, yd, ym, ys, hm, hft; 369482498Sroberto int idx, idy, is, imx, imy; 369582498Sroberto long lat, lon; 369654359Sroberto 3697290001Sglebius oncore_log(instance, LOG_INFO, "Posn:"); 369854359Sroberto ew = 'E'; 369954359Sroberto lon = instance->ss_long; 370054359Sroberto if (lon < 0) { 370154359Sroberto ew = 'W'; 370254359Sroberto lon = -lon; 370354359Sroberto } 370454359Sroberto 370554359Sroberto ns = 'N'; 370654359Sroberto lat = instance->ss_lat; 370754359Sroberto if (lat < 0) { 370854359Sroberto ns = 'S'; 370954359Sroberto lat = -lat; 371054359Sroberto } 371154359Sroberto 371254359Sroberto hm = instance->ss_ht/100.; 371354359Sroberto hft= hm/0.3048; 371454359Sroberto 371554359Sroberto xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ 371654359Sroberto yd = lon/3600000.; 3717290001Sglebius oncore_log_f(instance, LOG_INFO, 3718290001Sglebius "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", 3719290001Sglebius ns, xd, ew, yd, hm, hft); 372054359Sroberto 372154359Sroberto idx = xd; 372254359Sroberto idy = yd; 372354359Sroberto imx = lat%3600000; 372454359Sroberto imy = lon%3600000; 372554359Sroberto xm = imx/60000.; 372654359Sroberto ym = imy/60000.; 3727290001Sglebius oncore_log_f(instance, LOG_INFO, 3728290001Sglebius "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", 3729290001Sglebius ns, idx, xm, ew, idy, ym, hm, hft); 373054359Sroberto 373154359Sroberto imx = xm; 373254359Sroberto imy = ym; 373354359Sroberto is = lat%60000; 373454359Sroberto xs = is/1000.; 373554359Sroberto is = lon%60000; 373654359Sroberto ys = is/1000.; 3737290001Sglebius oncore_log_f(instance, LOG_INFO, 3738290001Sglebius "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", 3739290001Sglebius ns, idx, imx, xs, ew, idy, imy, ys, hm, hft); 374056746Sroberto} 374154359Sroberto 374254359Sroberto 374354359Sroberto 374456746Sroberto/* 3745132451Sroberto * write message to Oncore. 374656746Sroberto */ 374782498Sroberto 374856746Srobertostatic void 3749132451Srobertooncore_sendmsg( 3750290001Sglebius struct instance *instance, 3751132451Sroberto u_char *ptr, 375282498Sroberto size_t len 375356746Sroberto ) 375456746Sroberto{ 3755290001Sglebius int fd; 3756132451Sroberto u_char cs = 0; 375756746Sroberto 3758290001Sglebius fd = instance->ttyfd; 3759290001Sglebius#ifdef ONCORE_VERBOSE_SENDMSG 3760290001Sglebius if (debug > 4) { 3761290001Sglebius oncore_log_f(instance, LOG_DEBUG, "ONCORE: Send @@%c%c %d", 3762290001Sglebius ptr[0], ptr[1], (int)len); 3763290001Sglebius } 3764182007Sroberto#endif 3765132451Sroberto write(fd, "@@", (size_t) 2); 3766132451Sroberto write(fd, ptr, len); 3767132451Sroberto while (len--) 3768132451Sroberto cs ^= *ptr++; 3769132451Sroberto write(fd, &cs, (size_t) 1); 3770132451Sroberto write(fd, "\r\n", (size_t) 2); 3771132451Sroberto} 377256746Sroberto 377356746Sroberto 377456746Sroberto 3775132451Srobertostatic void 3776132451Srobertooncore_set_posn( 3777132451Sroberto struct instance *instance 3778132451Sroberto ) 3779132451Sroberto{ 3780132451Sroberto int mode; 3781182007Sroberto u_char Cmd[20]; 3782132451Sroberto 3783132451Sroberto /* Turn OFF position hold, it needs to be off to set position (for some units), 3784132451Sroberto will get set ON in @@Ea later */ 3785132451Sroberto 3786132451Sroberto if (instance->chan == 12) 3787290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */ 3788132451Sroberto else { 3789290001Sglebius oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */ 3790290001Sglebius oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */ 3791132451Sroberto } 3792132451Sroberto 3793132451Sroberto mode = instance->init_type; 3794132451Sroberto 3795132451Sroberto if (mode != 0) { /* first set posn hold position */ 3796132451Sroberto memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */ 3797132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3798132451Sroberto w32_buf(&Cmd[-2+8], (int) instance->ss_long); 3799132451Sroberto w32_buf(&Cmd[-2+12], (int) instance->ss_ht); 3800132451Sroberto Cmd[-2+16] = 0; 3801290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */ 3802132451Sroberto 3803132451Sroberto memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au)); 3804132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 3805132451Sroberto Cmd[-2+8] = 0; 3806290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */ 3807132451Sroberto 3808132451Sroberto /* next set current position */ 3809132451Sroberto 3810132451Sroberto if (instance->chan == 12) { 3811132451Sroberto memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga)); 3812132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3813132451Sroberto w32_buf(&Cmd[-2+8], (int) instance->ss_long); 3814132451Sroberto w32_buf(&Cmd[-2+12],(int) instance->ss_ht); 3815132451Sroberto Cmd[-2+16] = 0; 3816290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */ 3817132451Sroberto } else { 3818132451Sroberto memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad)); 3819132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 3820290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */ 3821132451Sroberto 3822132451Sroberto memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae)); 3823132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_long); 3824290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */ 3825132451Sroberto 3826132451Sroberto memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af)); 3827132451Sroberto w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 3828132451Sroberto Cmd[-2+8] = 0; 3829290001Sglebius oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */ 3830132451Sroberto } 3831132451Sroberto 3832132451Sroberto /* Finally, turn on position hold */ 3833132451Sroberto 3834132451Sroberto if (instance->chan == 12) 3835290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); 3836132451Sroberto else 3837290001Sglebius oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); 3838132451Sroberto } 3839132451Sroberto} 3840132451Sroberto 3841132451Sroberto 3842132451Sroberto 3843132451Srobertostatic void 3844132451Srobertooncore_set_traim( 3845132451Sroberto struct instance *instance 3846132451Sroberto ) 3847132451Sroberto{ 3848132451Sroberto if (instance->traim_in != -1) /* set in Input */ 3849132451Sroberto instance->traim = instance->traim_in; 3850132451Sroberto else 3851132451Sroberto instance->traim = instance->traim_ck; 3852132451Sroberto 3853290001Sglebius oncore_log_f(instance, LOG_INFO, "Input says TRAIM = %d", 3854290001Sglebius instance->traim_in); 3855290001Sglebius oncore_log_f(instance, LOG_INFO, "Model # says TRAIM = %d", 3856290001Sglebius instance->traim_id); 3857290001Sglebius oncore_log_f(instance, LOG_INFO, "Testing says TRAIM = %d", 3858290001Sglebius instance->traim_ck); 3859290001Sglebius oncore_log_f(instance, LOG_INFO, "Using TRAIM = %d", 3860290001Sglebius instance->traim); 3861132451Sroberto 3862132451Sroberto if (instance->traim_ck == 1 && instance->traim == 0) { 3863132451Sroberto /* if it should be off, and I turned it on during testing, 3864132451Sroberto then turn it off again */ 3865132451Sroberto if (instance->chan == 6) 3866290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx)); 3867132451Sroberto else if (instance->chan == 8) 3868290001Sglebius oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx)); 3869132451Sroberto else /* chan == 12 */ 3870290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0)); 3871290001Sglebius oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3872132451Sroberto } 387356746Sroberto} 387454359Sroberto 387556746Sroberto 387656746Sroberto 387756746Sroberto/* 3878132451Sroberto * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 387956746Sroberto */ 388082498Sroberto 388156746Srobertostatic void 3882132451Srobertooncore_shmem_get_3D( 3883132451Sroberto struct instance *instance 388456746Sroberto ) 388556746Sroberto{ 3886132451Sroberto if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */ 3887132451Sroberto instance->shmem_reset = 1; 3888132451Sroberto if (instance->chan == 12) { 3889132451Sroberto if (instance->shmem_Posn == 2) 3890290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ 3891132451Sroberto else 3892290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ 3893132451Sroberto } else { 3894132451Sroberto if (instance->saw_At) { /* out of 0D -> 3D mode */ 3895290001Sglebius oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); 3896132451Sroberto if (instance->shmem_Posn == 2) /* 3D -> 2D mode */ 3897290001Sglebius oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 3898132451Sroberto } else 3899290001Sglebius oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 3900132451Sroberto } 3901132451Sroberto } else if (instance->shmem_reset || (instance->mode != MODE_0D)) { 3902132451Sroberto instance->shmem_reset = 0; 3903132451Sroberto if (instance->chan == 12) 3904290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */ 3905132451Sroberto else { 3906132451Sroberto if (instance->saw_At) { 3907132451Sroberto if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */ 3908290001Sglebius oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 3909290001Sglebius oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ 3910132451Sroberto } else 3911290001Sglebius oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 3912132451Sroberto } 3913132451Sroberto } 3914132451Sroberto} 391556746Sroberto 391656746Sroberto 391756746Sroberto 3918132451Sroberto/* 3919132451Sroberto * Here we do the Software SiteSurvey. 3920132451Sroberto * We have to average our own position for the Position Hold Mode 3921132451Sroberto * We use Heights from the GPS ellipsoid. 3922132451Sroberto * We check for the END of either HW or SW SiteSurvey. 3923132451Sroberto */ 392456746Sroberto 392582498Srobertostatic void 3926132451Srobertooncore_ss( 3927132451Sroberto struct instance *instance 392882498Sroberto ) 392982498Sroberto{ 3930132451Sroberto double lat, lon, ht; 393182498Sroberto 3932132451Sroberto 3933132451Sroberto if (instance->site_survey == ONCORE_SS_HW) { 3934132451Sroberto /* 3935132451Sroberto * Check to see if Hardware SiteSurvey has Finished. 3936132451Sroberto */ 3937132451Sroberto 3938132451Sroberto if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) || 3939132451Sroberto (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) { 3940290001Sglebius oncore_log(instance, LOG_INFO, "Now in 0D mode"); 3941132451Sroberto 3942132451Sroberto if (instance->chan == 12) 3943290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax)); 3944132451Sroberto else 3945290001Sglebius oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); 3946132451Sroberto 3947290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 3948132451Sroberto instance->site_survey = ONCORE_SS_DONE; 3949132451Sroberto } 3950132451Sroberto } else { 3951132451Sroberto /* 3952132451Sroberto * Must be a Software Site Survey. 3953132451Sroberto */ 3954132451Sroberto 3955132451Sroberto if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ 3956132451Sroberto return; 3957132451Sroberto 3958132451Sroberto if (instance->mode != MODE_3D) /* Use only 3D Fixes */ 3959132451Sroberto return; 3960132451Sroberto 3961132451Sroberto instance->ss_lat += buf_w32(&instance->BEHa[15]); 3962132451Sroberto instance->ss_long += buf_w32(&instance->BEHa[19]); 3963132451Sroberto instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */ 3964132451Sroberto instance->ss_count++; 3965132451Sroberto 3966132451Sroberto if (instance->ss_count != POS_HOLD_AVERAGE) 3967132451Sroberto return; 3968132451Sroberto 3969132451Sroberto instance->ss_lat /= POS_HOLD_AVERAGE; 3970132451Sroberto instance->ss_long /= POS_HOLD_AVERAGE; 3971132451Sroberto instance->ss_ht /= POS_HOLD_AVERAGE; 3972132451Sroberto 3973290001Sglebius oncore_log_f(instance, LOG_NOTICE, 3974290001Sglebius "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)", 3975290001Sglebius instance->ss_lat, instance->ss_long, 3976290001Sglebius instance->ss_ht); 3977132451Sroberto lat = instance->ss_lat/3600000.; 3978132451Sroberto lon = instance->ss_long/3600000.; 3979132451Sroberto ht = instance->ss_ht/100; 3980290001Sglebius oncore_log_f(instance, LOG_NOTICE, 3981290001Sglebius "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)", 3982290001Sglebius lat, lon, ht); 3983132451Sroberto 3984132451Sroberto oncore_set_posn(instance); 3985132451Sroberto 3986290001Sglebius oncore_log(instance, LOG_INFO, "Now in 0D mode"); 3987132451Sroberto 3988290001Sglebius oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 3989132451Sroberto instance->site_survey = ONCORE_SS_DONE; 399082498Sroberto } 399182498Sroberto} 399282498Sroberto 3993132451Sroberto 3994132451Sroberto 3995132451Srobertostatic int 3996132451Srobertooncore_wait_almanac( 3997132451Sroberto struct instance *instance 3998132451Sroberto ) 3999132451Sroberto{ 4000132451Sroberto if (instance->rsm.bad_almanac) { 4001290001Sglebius instance->counta++; 4002290001Sglebius if (instance->counta%5 == 0) 4003290001Sglebius oncore_log(instance, LOG_INFO, "Waiting for Almanac"); 4004132451Sroberto 4005132451Sroberto /* 4006132451Sroberto * If we get here (first time) then we don't have an almanac in memory. 4007132451Sroberto * Check if we have a SHMEM, and if so try to load whatever is there. 4008132451Sroberto */ 4009132451Sroberto 4010132451Sroberto if (!instance->almanac_from_shmem) { 4011132451Sroberto instance->almanac_from_shmem = 1; 4012132451Sroberto oncore_load_almanac(instance); 4013132451Sroberto } 4014132451Sroberto return(1); 4015132451Sroberto } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn 4016132451Sroberto commands, and can finally check for TRAIM. Again, we set a delay 4017132451Sroberto (5sec) and wait for things to settle down */ 4018132451Sroberto 4019132451Sroberto if (instance->chan == 6) 4020290001Sglebius oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); 4021132451Sroberto else if (instance->chan == 8) 4022290001Sglebius oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En)); 4023132451Sroberto else if (instance->chan == 12) { 4024290001Sglebius oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */ 4025290001Sglebius oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */ 4026290001Sglebius oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */ 4027132451Sroberto } 4028132451Sroberto instance->traim_delay = 1; 4029132451Sroberto 4030290001Sglebius oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC"); 4031132451Sroberto 4032132451Sroberto instance->o_state = ONCORE_RUN; 4033290001Sglebius oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN"); 4034132451Sroberto } 4035132451Sroberto return(0); 4036132451Sroberto} 4037132451Sroberto 4038132451Sroberto 4039132451Sroberto 4040290001Sglebiusstatic void 4041290001Sglebiusoncore_log ( 4042290001Sglebius struct instance *instance, 4043290001Sglebius int log_level, 4044290001Sglebius const char *msg 4045290001Sglebius ) 4046290001Sglebius{ 4047290001Sglebius msyslog(log_level, "ONCORE[%d]: %s", instance->unit, msg); 4048290001Sglebius mprintf_clock_stats(&instance->peer->srcadr, "ONCORE[%d]: %s", 4049290001Sglebius instance->unit, msg); 4050290001Sglebius} 4051290001Sglebius 4052290001Sglebius 4053290001Sglebiusstatic int 4054290001Sglebiusoncore_log_f( 4055290001Sglebius struct instance * instance, 4056290001Sglebius int log_level, 4057290001Sglebius const char * fmt, 4058290001Sglebius ... 4059290001Sglebius ) 4060290001Sglebius{ 4061290001Sglebius va_list ap; 4062290001Sglebius int rc; 4063290001Sglebius char msg[512]; 4064290001Sglebius 4065290001Sglebius va_start(ap, fmt); 4066290001Sglebius rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 4067290001Sglebius va_end(ap); 4068290001Sglebius oncore_log(instance, log_level, msg); 4069290001Sglebius 4070290001Sglebius#ifdef ONCORE_VERBOSE_ONCORE_LOG 4071290001Sglebius instance->max_len = max(strlen(msg), instance->max_len); 4072290001Sglebius instance->max_count++; 4073290001Sglebius if (instance->max_count % 100 == 0) 4074290001Sglebius oncore_log_f(instance, LOG_INFO, 4075290001Sglebius "Max Message Length so far is %d", 4076290001Sglebius instance->max_len); 4077290001Sglebius#endif 4078290001Sglebius return rc; 4079290001Sglebius} 4080290001Sglebius 408154359Sroberto#else 408254359Srobertoint refclock_oncore_bs; 4083290001Sglebius#endif /* REFCLOCK && CLOCK_ONCORE */ 4084