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 14285612Sdelphij * 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 * -------------------------------------------------------------------------- 55285612Sdelphij * Reg Clemens (June 2009) 56285612Sdelphij * BUG[1220] OK, big patch, but mostly done mechanically. Change direct calls to write 57285612Sdelphij * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog. 58285612Sdelphij * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New 59285612Sdelphij * routine oncore_log. 60285612Sdelphij * -------------------------------------------------------------------------- 61285612Sdelphij * Reg Clemens (June 2009) 62285612Sdelphij * BUG[1218] The comment on where the oncore driver gets its input file does not 63285612Sdelphij * agree with the code. Change the comment. 64285612Sdelphij * -------------------------------------------------------------------------- 65285612Sdelphij * Reg Clemens (June 2009) 66285612Sdelphij * change exit statements to return(0) in main program. I had assumed that if the 67285612Sdelphij * PPS driver did not start for some reason, we shuould stop NTPD itelf. Others 68285612Sdelphij * disagree. We now give an ERR log message and stop this driver. 69285612Sdelphij * -------------------------------------------------------------------------- 70285612Sdelphij * Reg Clemens (June 2009) 71285612Sdelphij * A bytes available message for the input subsystem (Debug message). 72285612Sdelphij * -------------------------------------------------------------------------- 73285612Sdelphij * Reg Clemens (Nov 2008) 74285612Sdelphij * This code adds a message for TRAIM messages. Users often worry about the 75285612Sdelphij * driver not starting up, and it is often because of signal strength being low. 76285612Sdelphij * Low signal strength will give TRAIM messages. 77285612Sdelphij * -------------------------------------------------------------------------- 78285612Sdelphij * Reg Clemens (Nov 2008) 79285612Sdelphij * Add waiting on Almanac Message. 80285612Sdelphij * -------------------------------------------------------------------------- 81285612Sdelphij * Reg Clemens (Nov 2008) 82285612Sdelphij * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs 83285612Sdelphij * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command 84285612Sdelphij * that says 'Leap Pending'. As documented it only becomes true in the month 85285612Sdelphij * before the leap second is to be applied, but in practice at least some of 86285612Sdelphij * the receivers turn this indicator on as soon as the message is posted, which 87285612Sdelphij * can be 6months early. As such, we use the Bj command to turn on the 88285612Sdelphij * instance->pp->leap indicator but only run this test in December and June for 89285612Sdelphij * updates on 1Jan and 1July. 90285612Sdelphij * 91285612Sdelphij * The @@Gj command exists in later ONCOREs, and it gives the exact date 92285612Sdelphij * and size of the Leap Update. It can be emulated in the VP using the @@Bl 93285612Sdelphij * command which reads the raw Satellite Broadcast Messages. 94285612Sdelphij * We use these two commands to print informative messages in the clockstats 95285612Sdelphij * file once per day as soon as the message appears on the satellites. 96285612Sdelphij * -------------------------------------------------------------------------- 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" 164285612Sdelphij#include "ntp_calendar.h" 16582498Sroberto#include "ntp_stdlib.h" 16682498Sroberto 16754359Sroberto#include <stdio.h> 168285612Sdelphij#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 184285612Sdelphijstruct Bl { 185285612Sdelphij int dt_ls; 186285612Sdelphij int dt_lsf; 187285612Sdelphij int WN; 188285612Sdelphij int DN; 189285612Sdelphij int WN_lsf; 190285612Sdelphij int DN_lsf; 191285612Sdelphij int wn_flg; 192285612Sdelphij int lsf_flg; 193285612Sdelphij int Bl_day; 194285612Sdelphij} 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 */ 320285612Sdelphij 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 */ 323285612Sdelphij u_char max_len; /* max length message seen by oncore_log, for debugging */ 324285612Sdelphij u_char max_count; /* count for message statistics */ 32582498Sroberto 32682498Sroberto struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ 327285612Sdelphij struct Bl Bl; /* Satellite Broadcast Data Message */ 32882498Sroberto u_char printed; 32982498Sroberto u_char polled; 330132451Sroberto u_long ev_serial; 331285612Sdelphij 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; 340285612Sdelphij 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; 354285612Sdelphij s_char pps_control; /* PPS control, M12 only */ 355285612Sdelphij s_char pps_control_msg_seen; 35654359Sroberto}; 35754359Sroberto 35854359Sroberto#define rcvbuf instance->Rcvbuf 35954359Sroberto#define rcvptr instance->Rcvptr 36054359Sroberto 361285612Sdelphijstatic int oncore_start (int, struct peer *); 362285612Sdelphijstatic void oncore_poll (int, struct peer *); 363285612Sdelphijstatic void oncore_shutdown (int, struct peer *); 364285612Sdelphijstatic void oncore_consume (struct instance *); 365285612Sdelphijstatic void oncore_read_config (struct instance *); 366285612Sdelphijstatic void oncore_receive (struct recvbuf *); 367285612Sdelphijstatic int oncore_ppsapi (struct instance *); 368285612Sdelphijstatic void oncore_get_timestamp (struct instance *, long, long); 369285612Sdelphijstatic void oncore_init_shmem (struct instance *); 37054359Sroberto 371285612Sdelphijstatic void oncore_antenna_report (struct instance *, enum antenna_state); 372285612Sdelphijstatic void oncore_chan_test (struct instance *); 373285612Sdelphijstatic void oncore_check_almanac (struct instance *); 374285612Sdelphijstatic void oncore_check_antenna (struct instance *); 375285612Sdelphijstatic void oncore_check_leap_sec (struct instance *); 376285612Sdelphijstatic int oncore_checksum_ok (u_char *, int); 377285612Sdelphijstatic void oncore_compute_dH (struct instance *); 378285612Sdelphijstatic void oncore_load_almanac (struct instance *); 379285612Sdelphijstatic void oncore_log (struct instance *, int, const char *); 380285612Sdelphijstatic int oncore_log_f (struct instance *, int, const char *, ...) 381285612Sdelphij NTP_PRINTF(3, 4); 382285612Sdelphijstatic void oncore_print_Cb (struct instance *, u_char *); 383285612Sdelphij/* static void oncore_print_array (u_char *, int); */ 384285612Sdelphijstatic void oncore_print_posn (struct instance *); 385285612Sdelphijstatic void oncore_sendmsg (struct instance *, u_char *, size_t); 386285612Sdelphijstatic void oncore_set_posn (struct instance *); 387285612Sdelphijstatic void oncore_set_traim (struct instance *); 388285612Sdelphijstatic void oncore_shmem_get_3D (struct instance *); 389285612Sdelphijstatic void oncore_ss (struct instance *); 390285612Sdelphijstatic int oncore_wait_almanac (struct instance *); 391132451Sroberto 392285612Sdelphijstatic void oncore_msg_any (struct instance *, u_char *, size_t, int); 393285612Sdelphijstatic void oncore_msg_Adef (struct instance *, u_char *, size_t); 394285612Sdelphijstatic void oncore_msg_Ag (struct instance *, u_char *, size_t); 395285612Sdelphijstatic void oncore_msg_As (struct instance *, u_char *, size_t); 396285612Sdelphijstatic void oncore_msg_At (struct instance *, u_char *, size_t); 397285612Sdelphijstatic void oncore_msg_Ay (struct instance *, u_char *, size_t); 398285612Sdelphijstatic void oncore_msg_Az (struct instance *, u_char *, size_t); 399285612Sdelphijstatic void oncore_msg_BaEaHa (struct instance *, u_char *, size_t); 400285612Sdelphijstatic void oncore_msg_Bd (struct instance *, u_char *, size_t); 401285612Sdelphijstatic void oncore_msg_Bj (struct instance *, u_char *, size_t); 402285612Sdelphijstatic void oncore_msg_Bl (struct instance *, u_char *, size_t); 403285612Sdelphijstatic void oncore_msg_BnEnHn (struct instance *, u_char *, size_t); 404285612Sdelphijstatic void oncore_msg_CaFaIa (struct instance *, u_char *, size_t); 405285612Sdelphijstatic void oncore_msg_Cb (struct instance *, u_char *, size_t); 406285612Sdelphijstatic void oncore_msg_Cf (struct instance *, u_char *, size_t); 407285612Sdelphijstatic void oncore_msg_Cj (struct instance *, u_char *, size_t); 408285612Sdelphijstatic void oncore_msg_Cj_id (struct instance *, u_char *, size_t); 409285612Sdelphijstatic void oncore_msg_Cj_init (struct instance *, u_char *, size_t); 410285612Sdelphijstatic void oncore_msg_Ga (struct instance *, u_char *, size_t); 411285612Sdelphijstatic void oncore_msg_Gb (struct instance *, u_char *, size_t); 412285612Sdelphijstatic void oncore_msg_Gc (struct instance *, u_char *, size_t); 413285612Sdelphijstatic void oncore_msg_Gj (struct instance *, u_char *, size_t); 414285612Sdelphijstatic 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; 434285612Sdelphij 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 */ 439285612Sdelphij { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC", 0 }, 440285612Sdelphij { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC", 0 }, 441285612Sdelphij { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC", 0 }, 442285612Sdelphij { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC", 0 }, 443285612Sdelphij { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC", 0 }, 444285612Sdelphij { "Hn", 78, oncore_msg_BnEnHn, "", 0 }, 445285612Sdelphij { "Ab", 10, 0, "", 0 }, 446285612Sdelphij { "Ac", 11, 0, "", 0 }, 447285612Sdelphij { "Ad", 11, oncore_msg_Adef, "", 0 }, 448285612Sdelphij { "Ae", 11, oncore_msg_Adef, "", 0 }, 449285612Sdelphij { "Af", 15, oncore_msg_Adef, "", 0 }, 450285612Sdelphij { "Ag", 8, oncore_msg_Ag, "", 0 }, /* Satellite mask angle */ 451285612Sdelphij { "As", 20, oncore_msg_As, "", 0 }, 452285612Sdelphij { "At", 8, oncore_msg_At, "", 0 }, 453285612Sdelphij { "Au", 12, 0, "", 0 }, 454285612Sdelphij { "Av", 8, 0, "", 0 }, 455285612Sdelphij { "Aw", 8, 0, "", 0 }, 456285612Sdelphij { "Ay", 11, oncore_msg_Ay, "", 0 }, 457285612Sdelphij { "Az", 11, oncore_msg_Az, "", 0 }, 458285612Sdelphij { "AB", 8, 0, "", 0 }, 459285612Sdelphij { "Bb", 92, 0, "", 0 }, 460285612Sdelphij { "Bd", 23, oncore_msg_Bd, "", 0 }, 461285612Sdelphij { "Bj", 8, oncore_msg_Bj, "", 0 }, 462285612Sdelphij { "Bl", 41, oncore_msg_Bl, "", 0 }, 463285612Sdelphij { "Ca", 9, oncore_msg_CaFaIa, "", 0 }, 464285612Sdelphij { "Cb", 33, oncore_msg_Cb, "", 0 }, 465285612Sdelphij { "Cf", 7, oncore_msg_Cf, "", 0 }, 466285612Sdelphij { "Cg", 8, 0, "", 0 }, 467285612Sdelphij { "Ch", 9, 0, "", 0 }, 468285612Sdelphij { "Cj", 294, oncore_msg_Cj, "", 0 }, 469285612Sdelphij { "Ek", 71, 0, "", 0 }, 470285612Sdelphij { "Fa", 9, oncore_msg_CaFaIa, "", 0 }, 471285612Sdelphij { "Ga", 20, oncore_msg_Ga, "", 0 }, 472285612Sdelphij { "Gb", 17, oncore_msg_Gb, "", 0 }, 473285612Sdelphij { "Gc", 8, oncore_msg_Gc, "", 0 }, 474285612Sdelphij { "Gd", 8, 0, "", 0 }, 475285612Sdelphij { "Ge", 8, 0, "", 0 }, 476285612Sdelphij { "Gj", 21, oncore_msg_Gj, "", 0 }, 477285612Sdelphij { "Ia", 10, oncore_msg_CaFaIa, "", 0 }, 478285612Sdelphij { "Sz", 8, oncore_msg_Sz, "", 0 }, 479285612Sdelphij { {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 */ 514285612Sdelphijstatic 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 */ 534285612Sdelphijstatic 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; 597285612Sdelphij int fd1, fd2; 598285612Sdelphij char device1[STRING_LEN], device2[STRING_LEN]; 599285612Sdelphij#ifndef SYS_WINNT 60054359Sroberto struct stat stat1, stat2; 601285612Sdelphij#endif 60254359Sroberto 603132451Sroberto /* create instance structure for this unit */ 604132451Sroberto 605285612Sdelphij instance = emalloc(sizeof(*instance)); 606285612Sdelphij 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; 621285612Sdelphij instance->pps_control = -1; /* PPS control, M12 only */ 622285612Sdelphij 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 629285612Sdelphij 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 636285612Sdelphij oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING"); 637182007Sroberto instance->o_state = ONCORE_NO_IDEA; 638285612Sdelphij 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 645285612Sdelphij (void)snprintf(device1, sizeof(device1), DEVICE1, unit); 646285612Sdelphij (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. 657285612Sdelphij 658285612Sdelphij For use with linuxPPS we assume that the N_TTY file has been opened 659285612Sdelphij and that the line discipline has been changed to N_PPS by another 660285612Sdelphij program (say ppsldisc) so that the two files expected by the oncore 661285612Sdelphij driver can be opened. 662285612Sdelphij 663285612Sdelphij Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do 664285612Sdelphij the stat below without error even though the file has already had its 665285612Sdelphij line discipline changed by another process. 666285612Sdelphij 667285612Sdelphij The Windows port of ntpd arranges to return duplicate handles for 668285612Sdelphij multiple opens of the same serial device, and doesn't have inodes 669285612Sdelphij for serial handles, so we just open both on Windows. 670182007Sroberto */ 671285612Sdelphij#ifndef SYS_WINNT 672182007Sroberto if (stat(device1, &stat1)) { 673285612Sdelphij oncore_log_f(instance, LOG_ERR, "Can't stat fd1 (%s)", 674285612Sdelphij device1); 675285612Sdelphij return(0); /* exit, no file, can't start driver */ 67654359Sroberto } 67754359Sroberto 678182007Sroberto if (stat(device2, &stat2)) { 679285612Sdelphij stat2.st_dev = stat2.st_ino = -2; 680285612Sdelphij oncore_log_f(instance, LOG_ERR, "Can't stat fd2 (%s) %d %m", 681285612Sdelphij device2, errno); 682182007Sroberto } 683285612Sdelphij#endif /* !SYS_WINNT */ 684132451Sroberto 685285612Sdelphij fd1 = refclock_open(device1, SPEED, LDISC_RAW); 686285612Sdelphij if (fd1 <= 0) { 687285612Sdelphij oncore_log_f(instance, LOG_ERR, "Can't open fd1 (%s)", 688285612Sdelphij device1); 689285612Sdelphij return(0); /* exit, can't open file, can't start driver */ 690132451Sroberto } 691132451Sroberto 692285612Sdelphij /* for LINUX the PPS device is the result of a line discipline. 693285612Sdelphij It seems simplest to let an external program create the appropriate 694285612Sdelphij /dev/pps<n> file, and only check (carefully) for its existance here 695285612Sdelphij */ 696285612Sdelphij 697285612Sdelphij#ifndef SYS_WINNT 698182007Sroberto if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */ 699182007Sroberto fd2 = fd1; 700285612Sdelphij else 701285612Sdelphij#endif /* !SYS_WINNT */ 702285612Sdelphij { /* different devices here */ 703285612Sdelphij if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) { 704285612Sdelphij oncore_log_f(instance, LOG_ERR, 705285612Sdelphij "Can't open fd2 (%s)", device2); 706285612Sdelphij return(0); /* exit, can't open PPS file, can't start driver */ 707182007Sroberto } 708182007Sroberto } 709182007Sroberto 710285612Sdelphij /* open ppsapi source */ 711182007Sroberto 712285612Sdelphij if (time_pps_create(fd2, &instance->pps_h) < 0) { 713285612Sdelphij oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel"); 714285612Sdelphij 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; 730285612Sdelphij pp->io.srcclock = peer; 731132451Sroberto pp->io.datalen = 0; 732132451Sroberto pp->io.fd = fd1; 733132451Sroberto if (!io_addclock(&pp->io)) { 734285612Sdelphij oncore_log(instance, LOG_ERR, "can't do io_addclock"); 735285612Sdelphij close(fd1); 736285612Sdelphij pp->io.fd = -1; 737132451Sroberto free(instance); 738132451Sroberto return (0); 739132451Sroberto } 740285612Sdelphij 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; 758285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID"); 759132451Sroberto 760132451Sroberto instance->timeout = 4; 761285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ 762285612Sdelphij 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; 783285612Sdelphij instance = pp->unitptr; 784132451Sroberto 785285612Sdelphij if (pp->io.fd != -1) 786285612Sdelphij io_closeclock(&pp->io); 787132451Sroberto 788285612Sdelphij if (instance != NULL) { 789285612Sdelphij time_pps_destroy (instance->pps_h); 790182007Sroberto 791285612Sdelphij close(instance->ttyfd); 792182007Sroberto 793285612Sdelphij if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd)) 794285612Sdelphij close(instance->ppsfd); 795182007Sroberto 796285612Sdelphij if (instance->shmemfd) 797285612Sdelphij close(instance->shmemfd); 798182007Sroberto 799285612Sdelphij free(instance); 800285612Sdelphij } 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 817285612Sdelphij instance = peer->procptr->unitptr; 818132451Sroberto if (instance->timeout) { 819132451Sroberto instance->timeout--; 820132451Sroberto if (instance->timeout == 0) { 821285612Sdelphij oncore_log(instance, LOG_ERR, 822285612Sdelphij "Oncore: No response from @@Cj, shutting down driver"); 823132451Sroberto oncore_shutdown(unit, peer); 824132451Sroberto } else { 825285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 826285612Sdelphij 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; 851285612Sdelphij const char *cp; 852132451Sroberto 853182007Sroberto if (time_pps_getcap(instance->pps_h, &cap) < 0) { 854285612Sdelphij 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) { 859285612Sdelphij 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) { 868285612Sdelphij cp = "Assert"; 869182007Sroberto mode = PPS_CAPTUREASSERT; 870182007Sroberto mode1 = PPS_OFFSETASSERT; 87154359Sroberto } else { 872285612Sdelphij cp = "Clear"; 873182007Sroberto mode = PPS_CAPTURECLEAR; 874182007Sroberto mode1 = PPS_OFFSETCLEAR; 87554359Sroberto } 876285612Sdelphij oncore_log_f(instance, LOG_INFO, "Initializing timing to %s.", 877285612Sdelphij cp); 87856746Sroberto 879182007Sroberto if (!(mode & cap)) { 880285612Sdelphij oncore_log_f(instance, LOG_ERR, 881285612Sdelphij "Can't set timing to %s, exiting...", cp); 882182007Sroberto return(0); 883182007Sroberto } 884182007Sroberto 885182007Sroberto if (!(mode1 & cap)) { 886285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 887285612Sdelphij "Can't set %s, this will increase jitter.", 888285612Sdelphij 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) { 897285612Sdelphij oncore_log_f(instance, LOG_ERR, "ONCORE: time_pps_setparams fails %m"); 898285612Sdelphij 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 906285612Sdelphij 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) { 917285612Sdelphij oncore_log_f(instance, LOG_ERR, "time_pps_kcbind failed: %m"); 918285612Sdelphij oncore_log(instance, LOG_ERR, "HARDPPS failed, abort..."); 919182007Sroberto return (0); 92056746Sroberto } 921285612Sdelphij 922285612Sdelphij 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{ 935285612Sdelphij int l, fd; 936182007Sroberto u_char *cp, *cp1, *buf, *shmem_old; 937132451Sroberto struct msg_desc *mp; 938132451Sroberto struct stat sbuf; 939285612Sdelphij size_t i, n, n1, shmem_length, shmem_old_size; 940132451Sroberto 941285612Sdelphij /* 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) 950285612Sdelphij 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) { 955285612Sdelphij shmem_old = emalloc((unsigned) sbuf.st_size); 956285612Sdelphij 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) { 964285612Sdelphij 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 997285612Sdelphij 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) { 1052285612Sdelphij 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 1070285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 1071285612Sdelphij "SHMEM (size = %ld) is CONFIGURED and available as %s", 1072285612Sdelphij (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 1089285612Sdelphij * /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 1092285612Sdelphij * /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 1167285612Sdelphij * 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 * 1193285612Sdelphij * There is an optional line with PPSCONTROL on it (only valid for M12 or M12+T 1194285612Sdelphij * receivers, the option is read, but ignored for all others) 1195285612Sdelphij * and it is followed by: 1196285612Sdelphij * ON Turn PPS on. This is the default and the default for other 1197285612Sdelphij * oncore receivers. The PPS is on even if not tracking 1198285612Sdelphij * any satellites. 1199285612Sdelphij * SATELLITE Turns PPS on if tracking at least 1 satellite, else off. 1200285612Sdelphij * TRAIM Turns PPS on or off controlled by TRAIM. 1201285612Sdelphij * The OFF option is NOT implemented, since the Oncore driver will not work 1202285612Sdelphij * without the PPS signal. 1203285612Sdelphij * 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; 1213285612Sdelphij char *cc, *ca, line[100], units[2], device[64]; 1214285612Sdelphij const char *dirs[] = { "/etc/ntp", "/etc", 0 }; 1215285612Sdelphij 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; 1222285612Sdelphij snprintf(device, sizeof(device), "%s/ntp.oncore.%d", 1223285612Sdelphij cp, instance->unit); /* try "ntp.oncore.0 */ 1224182007Sroberto if ((fd=fopen(device, "r"))) 1225182007Sroberto break; 1226285612Sdelphij snprintf(device, sizeof(device), "%s/ntp.oncore%d", 1227285612Sdelphij cp, instance->unit); /* try "ntp.oncore0" */ 1228182007Sroberto if ((fd=fopen(device, "r"))) 1229182007Sroberto break; 1230285612Sdelphij snprintf(device, sizeof(device), "%s/ntp.oncore", cp); 1231285612Sdelphij 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)) { 1243285612Sdelphij char *cpw; 124456746Sroberto 124556746Sroberto /* Remove comments */ 1246285612Sdelphij if ((cpw = strchr(line, '#'))) 1247285612Sdelphij *cpw = '\0'; 124882498Sroberto 124956746Sroberto /* Remove trailing space */ 125056746Sroberto for (i = strlen(line); 1251285612Sdelphij i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]); 125256746Sroberto ) 125356746Sroberto line[--i] = '\0'; 125456746Sroberto 125556746Sroberto /* Remove leading space */ 1256285612Sdelphij 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++) { 1265285612Sdelphij if (isascii((unsigned char)*ca)) { 1266285612Sdelphij if (islower((unsigned char)*ca)) { 1267285612Sdelphij *ca = toupper((unsigned char)*ca); 1268285612Sdelphij } else if (isspace((unsigned char)*ca) || (*ca == '=')) 126982498Sroberto break; 127056746Sroberto } 127156746Sroberto } 127282498Sroberto 127382498Sroberto /* Remove space (and possible =) leading the arg */ 1274285612Sdelphij 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)) { 1278285612Sdelphij instance->shmem_fname = estrdup(ca); 127956746Sroberto continue; 128056746Sroberto } 128156746Sroberto 128256746Sroberto /* Uppercase argument as well */ 1283285612Sdelphij for (cpw = ca; *cpw; cpw++) 1284285612Sdelphij if (isascii((unsigned char)*cpw) && islower((unsigned char)*cpw)) 1285285612Sdelphij *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; 1329285612Sdelphij if (f1 < 0 || f1 > 999999) 1330285612Sdelphij oncore_log_f(instance, LOG_WARNING, 1331285612Sdelphij "PPS Cable delay of %fns out of Range, ignored", 1332285612Sdelphij f1); 1333285612Sdelphij 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; 1349285612Sdelphij if (f1 < 0 || f1 > 999999999.) 1350285612Sdelphij oncore_log_f(instance, LOG_WARNING, 1351285612Sdelphij "PPS Offset of %fns out of Range, ignored", 1352285612Sdelphij f1); 1353285612Sdelphij 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 */ 1381285612Sdelphij } else if (!strncmp(cc,"PPSCONTROL",10)) { /* pps control M12 only */ 1382285612Sdelphij if (!strcmp(ca,"ON") || !strcmp(ca, "CONTINUOUS")) { 1383285612Sdelphij instance->pps_control = 1; /* PPS always on */ 1384285612Sdelphij } else if (!strcmp(ca,"SATELLITE")) { 1385285612Sdelphij instance->pps_control = 2; /* PPS on when satellite is available */ 1386285612Sdelphij } else if (!strcmp(ca,"TRAIM")) { 1387285612Sdelphij instance->pps_control = 3; /* PPS on when TRAIM status is OK */ 1388285612Sdelphij } else { 1389285612Sdelphij oncore_log_f(instance, LOG_WARNING, 1390285612Sdelphij "Unknown value \"%s\" for PPSCONTROL, ignored", 1391285612Sdelphij cc); 1392285612Sdelphij } 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 )) { 1404285612Sdelphij oncore_log_f(instance, LOG_WARNING, 1405285612Sdelphij "ONCORE: incomplete data on %s", device); 140654359Sroberto instance->posn_set = 0; 140782498Sroberto if (mode == 1 || mode == 3) { 1408285612Sdelphij oncore_log_f(instance, LOG_WARNING, 1409285612Sdelphij "Input Mode = %d, but no/incomplete position, mode set to %d", 1410285612Sdelphij mode, mode+1); 141182498Sroberto mode++; 141282498Sroberto } 141354359Sroberto } 141482498Sroberto instance->init_type = mode; 141582498Sroberto 1416285612Sdelphij 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 1435285612Sdelphij peer = rbufp->recv_peer; 1436285612Sdelphij instance = peer->procptr->unitptr; 143754359Sroberto p = (u_char *) &rbufp->recv_space; 143854359Sroberto 1439285612Sdelphij#ifdef ONCORE_VERBOSE_RECEIVE 144054359Sroberto if (debug > 4) { 144154359Sroberto int i; 1442285612Sdelphij char Msg[120], Msg2[10]; 1443285612Sdelphij 1444285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1445285612Sdelphij ">>> %d bytes available", 1446285612Sdelphij rbufp->recv_length); 1447285612Sdelphij strlcpy(Msg, ">>>", sizeof(Msg)); 1448285612Sdelphij for (i = 0; i < rbufp->recv_length; i++) { 1449285612Sdelphij snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]); 1450285612Sdelphij strlcat(Msg, Msg2, sizeof(Msg)); 1451285612Sdelphij } 1452285612Sdelphij oncore_log(instance, LOG_DEBUG, Msg); 1453285612Sdelphij 1454285612Sdelphij strlcpy(Msg, ">>>", sizeof(Msg)); 1455285612Sdelphij for (i = 0; i < rbufp->recv_length; i++) { 1456285612Sdelphij snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]); 1457285612Sdelphij strlcat(Msg, Msg2, sizeof(Msg)); 1458285612Sdelphij } 1459285612Sdelphij oncore_log(instance, LOG_DEBUG, Msg); 146054359Sroberto } 146154359Sroberto#endif 146254359Sroberto 146354359Sroberto i = rbufp->recv_length; 1464316722Sdelphij if ((size_t)rcvptr + i >= 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{ 1482285612Sdelphij 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; 1490285612Sdelphij#ifdef ONCORE_VERBOSE_CONSUME 149154359Sroberto if (debug > 4) 1492285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1493285612Sdelphij ">>> skipping %d chars", 1494285612Sdelphij 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) { 1508285612Sdelphij#ifdef ONCORE_VERBOSE_CONSUME 150982498Sroberto if (debug > 4) 1510285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1511285612Sdelphij ">>> Unknown MSG, skipping 4 (%c%c)", 1512285612Sdelphij 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; 1520285612Sdelphij#ifdef ONCORE_VERBOSE_CONSUME 152154359Sroberto if (debug > 3) 1522285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1523285612Sdelphij "GOT: %c%c %d of %d entry %d", 1524285612Sdelphij instance->unit, rcvbuf[2], 1525285612Sdelphij 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') { 1535285612Sdelphij#ifdef ONCORE_VERBOSE_CONSUME 153682498Sroberto if (debug) 1537285612Sdelphij 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 } 1550285612Sdelphij#ifdef ONCORE_VERBOSE_CONSUME 1551182007Sroberto else if (debug) { 1552285612Sdelphij char Msg[120], Msg2[10]; 1553285612Sdelphij 1554285612Sdelphij oncore_log(instance, LOG_ERR, "Checksum mismatch!"); 1555285612Sdelphij snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]); 1556285612Sdelphij for (i = 4; i < l; i++) { 1557285612Sdelphij snprintf(Msg2, sizeof(Msg2), 1558285612Sdelphij "%03o ", rcvbuf[i]); 1559285612Sdelphij strlcat(Msg, Msg2, sizeof(Msg)); 1560285612Sdelphij } 1561285612Sdelphij 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; 1593285612Sdelphij struct peer *peer; 1594132451Sroberto pps_info_t pps_i; 1595285612Sdelphij char Msg[160]; 159654359Sroberto 1597285612Sdelphij peer = instance->peer; 1598285612Sdelphij 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 1606285612Sdelphij 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 1610285612Sdelphij if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) { 1611132451Sroberto#endif 1612285612Sdelphij peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1613132451Sroberto return; 1614285612Sdelphij } 1615132451Sroberto 1616132451Sroberto /* Don't do anything without an almanac to define the GPS->UTC delta */ 1617132451Sroberto 1618285612Sdelphij if (instance->rsm.bad_almanac) { 1619285612Sdelphij peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1620132451Sroberto return; 1621285612Sdelphij } 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--; 1631285612Sdelphij 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) { 1640285612Sdelphij oncore_log_f(instance, LOG_ERR, 1641285612Sdelphij "time_pps_fetch failed %m"); 1642285612Sdelphij peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1643132451Sroberto return; 1644132451Sroberto } 1645132451Sroberto 1646132451Sroberto if (instance->assert) { 1647132451Sroberto tsp = &pps_i.assert_timestamp; 1648132451Sroberto 1649285612Sdelphij#ifdef ONCORE_VERBOSE_GET_TIMESTAMP 1650132451Sroberto if (debug > 2) { 1651285612Sdelphij u_long i; 1652285612Sdelphij 1653132451Sroberto i = (u_long) pps_i.assert_sequence; 1654182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC 1655285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1656285612Sdelphij "serial/j (%lu, %lu) %ld.%09ld", i, 1657285612Sdelphij j, (long)tsp->tv_sec, 1658285612Sdelphij (long)tsp->tv_nsec); 1659182007Sroberto# else 1660285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1661285612Sdelphij "serial/j (%lu, %lu) %ld.%06ld", i, 1662285612Sdelphij j, (long)tsp->tv_sec, 1663285612Sdelphij (long)tsp->tv_usec); 1664182007Sroberto# endif 1665182007Sroberto } 1666132451Sroberto#endif 1667132451Sroberto 1668132451Sroberto if (pps_i.assert_sequence == j) { 1669285612Sdelphij oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps"); 1670285612Sdelphij peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1671132451Sroberto return; 1672132451Sroberto } 1673285612Sdelphij 1674132451Sroberto instance->ev_serial = pps_i.assert_sequence; 1675132451Sroberto } else { 1676132451Sroberto tsp = &pps_i.clear_timestamp; 1677132451Sroberto 1678285612Sdelphij#if 0 1679132451Sroberto if (debug > 2) { 1680285612Sdelphij u_long i; 1681285612Sdelphij 1682132451Sroberto i = (u_long) pps_i.clear_sequence; 1683182007Sroberto# ifdef HAVE_STRUCT_TIMESPEC 1684285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1685285612Sdelphij "serial/j (%lu, %lu) %ld.%09ld", i, 1686285612Sdelphij j, (long)tsp->tv_sec, 1687285612Sdelphij (long)tsp->tv_nsec); 1688182007Sroberto# else 1689285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 1690285612Sdelphij "serial/j (%lu, %lu) %ld.%06ld", i, 1691285612Sdelphij j, (long)tsp->tv_sec, 1692285612Sdelphij (long)tsp->tv_usec); 1693182007Sroberto# endif 1694182007Sroberto } 1695132451Sroberto#endif 1696132451Sroberto 1697132451Sroberto if (pps_i.clear_sequence == j) { 1698285612Sdelphij oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps"); 1699285612Sdelphij 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) { 1758285612Sdelphij oncore_log_f(instance, LOG_ERR, 1759285612Sdelphij "time_pps_getcap failed: %m"); 1760285612Sdelphij peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1761132451Sroberto return; 1762132451Sroberto } 1763132451Sroberto 1764132451Sroberto if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { 1765285612Sdelphij oncore_log_f(instance, LOG_ERR, 1766285612Sdelphij "time_pps_getparams failed: %m"); 1767285612Sdelphij 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)) 1782285612Sdelphij 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) { 1807285612Sdelphij snprintf(f1, sizeof(f1), "%d", 1808285612Sdelphij instance->BEHn[21]); 1809285612Sdelphij snprintf(f2, sizeof(f2), "%d", 1810285612Sdelphij instance->BEHn[22]); 1811285612Sdelphij snprintf(f3, sizeof(f3), "%2d", 1812285612Sdelphij instance->BEHn[23] * 256 + 1813285612Sdelphij instance->BEHn[24]); 1814285612Sdelphij snprintf(f4, sizeof(f4), "%3d", 1815285612Sdelphij (s_char)instance->BEHn[25]); 1816182007Sroberto } else { 1817285612Sdelphij strlcpy(f1, "x", sizeof(f1)); 1818285612Sdelphij strlcpy(f2, "x", sizeof(f2)); 1819285612Sdelphij strlcpy(f3, "xx", sizeof(f3)); 1820285612Sdelphij strlcpy(f4, "xxx", sizeof(f4)); 1821182007Sroberto } 1822285612Sdelphij 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) { 1840285612Sdelphij snprintf(f1, sizeof(f1), "%d", 1841285612Sdelphij instance->BEHn[6]); 1842285612Sdelphij snprintf(f2, sizeof(f2), "%d", 1843285612Sdelphij instance->BEHn[7]); 1844285612Sdelphij snprintf(f3, sizeof(f3), "%d", 1845285612Sdelphij instance->BEHn[12] * 256 + 1846285612Sdelphij instance->BEHn[13]); 1847285612Sdelphij snprintf(f4, sizeof(f4), "%3d", 1848285612Sdelphij (s_char)instance->BEHn[14]); 1849182007Sroberto } else { 1850285612Sdelphij strlcpy(f1, "x", sizeof(f1)); 1851285612Sdelphij strlcpy(f2, "x", sizeof(f2)); 1852285612Sdelphij strlcpy(f3, "xx", sizeof(f3)); 1853285612Sdelphij strlcpy(f4, "xxx", sizeof(f4)); 1854182007Sroberto } 1855285612Sdelphij 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); 1877285612Sdelphij peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1878132451Sroberto return; 1879132451Sroberto } 1880132451Sroberto 1881285612Sdelphij 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 } 1890285612Sdelphij 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{ 1909285612Sdelphij#ifdef ONCORE_VERBOSE_MSG_ANY 191054359Sroberto int i; 191154359Sroberto const char *fmt = oncore_messages[idx].fmt; 191254359Sroberto const char *p; 1913285612Sdelphij char *q; 1914285612Sdelphij char *qlim; 191582498Sroberto#ifdef HAVE_GETCLOCK 191682498Sroberto struct timespec ts; 191782498Sroberto#endif 191854359Sroberto struct timeval tv; 1919285612Sdelphij 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 1929285612Sdelphij oncore_log(instance, LOG_DEBUG, "%ld.%06ld", 1930285612Sdelphij (long)tv.tv_sec, (long)tv.tv_usec); 193154359Sroberto 193254359Sroberto if (!*fmt) { 1933285612Sdelphij snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2], 1934285612Sdelphij buf[3]); 1935285612Sdelphij for(i = 2; i < len && i < 2400 ; i++) { 1936285612Sdelphij snprintf(Msg2, sizeof(Msg2), "%02x", 1937285612Sdelphij buf[i]); 1938285612Sdelphij strlcat(Msg, Msg2, sizeof(Msg)); 1939285612Sdelphij } 1940285612Sdelphij oncore_log(instance, LOG_DEBUG, Msg); 194154359Sroberto return; 194254359Sroberto } else { 1943285612Sdelphij strlcpy(Msg, "##", sizeof(Msg)); 1944285612Sdelphij qlim = Msg + sizeof(Msg) - 3; 1945285612Sdelphij for (p = fmt, q = Msg + 2; q < qlim && *p; ) { 1946285612Sdelphij *q++ = *p++; 1947285612Sdelphij *q++ = '_'; 194854359Sroberto } 1949285612Sdelphij *q = '\0'; 1950285612Sdelphij oncore_log(instance, LOG_DEBUG, Msg); 1951285612Sdelphij snprintf(Msg, sizeof(Msg), "%c%c", buf[2], 1952285612Sdelphij buf[3]); 195354359Sroberto i = 4; 195454359Sroberto for (p = fmt; *p; p++) { 1955285612Sdelphij snprintf(Msg2, "%02x", buf[i++]); 1956285612Sdelphij strlcat(Msg, Msg2, sizeof(Msg)); 195754359Sroberto } 1958285612Sdelphij 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 ) 1987285612Sdelphij{ 1988285612Sdelphij const char *cp; 198982498Sroberto 1990285612Sdelphij cp = "set to"; 1991285612Sdelphij if (instance->o_state == ONCORE_RUN) 1992285612Sdelphij cp = "is"; 199354359Sroberto 1994285612Sdelphij instance->Ag = buf[4]; 1995285612Sdelphij oncore_log_f(instance, LOG_INFO, 1996285612Sdelphij "Satellite mask angle %s %d degrees", cp, 1997285612Sdelphij (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) { 2038285612Sdelphij oncore_log(instance, LOG_NOTICE, 2039132451Sroberto "Initiating hardware 3D site survey"); 204054359Sroberto 2041285612Sdelphij 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 2068285612Sdelphij oncore_log_f(instance, LOG_INFO, "PPS Offset is set to %ld ns", 2069285612Sdelphij 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 2092285612Sdelphij oncore_log_f(instance, LOG_INFO, "Cable delay is set to %ld ns", 2093285612Sdelphij 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 2138285612Sdelphij oncore_log_f(instance, LOG_INFO, "Input says chan = %d", 2139285612Sdelphij instance->chan_in); 2140285612Sdelphij oncore_log_f(instance, LOG_INFO, "Model # says chan = %d", 2141285612Sdelphij instance->chan_id); 2142285612Sdelphij oncore_log_f(instance, LOG_INFO, "Testing says chan = %d", 2143285612Sdelphij instance->chan_ck); 2144285612Sdelphij oncore_log_f(instance, LOG_INFO, "Using chan = %d", 2145285612Sdelphij instance->chan); 2146132451Sroberto 2147132451Sroberto instance->o_state = ONCORE_HAVE_CHAN; 2148285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN"); 2149132451Sroberto 2150132451Sroberto instance->timeout = 4; 2151285612Sdelphij 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 2168285612Sdelphij /* check if we saw a response to Gc (M12 or M12+T */ 2169285612Sdelphij 2170285612Sdelphij if (instance->pps_control_msg_seen != -2) { 2171285612Sdelphij if ((instance->pps_control_msg_seen == -1) && (instance->pps_control != -1)) { 2172285612Sdelphij oncore_log(instance, LOG_INFO, "PPSCONTROL set, but not implemented (not M12)"); 2173285612Sdelphij } 2174285612Sdelphij instance->pps_control_msg_seen = -2; 2175285612Sdelphij } 2176285612Sdelphij 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) { 2199285612Sdelphij oncore_log(instance, LOG_NOTICE, 2200285612Sdelphij "Not Good, no @@At command (no Position Hold), must be a GT/GT+"); 2201285612Sdelphij 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; 2215285612Sdelphij oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 221682498Sroberto break; 2217132451Sroberto 221882498Sroberto case 2: 2219132451Sroberto case 4: /* Site Survey */ 2220285612Sdelphij 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) 2224285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */ 2225132451Sroberto else 2226285612Sdelphij 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 2233285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); 223482498Sroberto 2235132451Sroberto /* Read back Cable Delay for Output */ 223682498Sroberto 2237285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); 2238132451Sroberto 2239132451Sroberto /* Read back Satellite Mask Angle for Output */ 2240132451Sroberto 2241285612Sdelphij 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) { 2258285612Sdelphij oncore_log(instance, LOG_NOTICE, 2259182007Sroberto "Initiating hardware 3D site survey"); 2260132451Sroberto 2261285612Sdelphij oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW"); 2262182007Sroberto instance->site_survey = ONCORE_SS_HW; 2263182007Sroberto } else { 2264285612Sdelphij 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 2291285612Sdelphij oncore_log_f(instance, LOG_INFO, 2292285612Sdelphij "Initiating software 3D site survey (%d samples)", 2293285612Sdelphij POS_HOLD_AVERAGE); 2294182007Sroberto 2295285612Sdelphij 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) 2300285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */ 2301182007Sroberto else { 2302285612Sdelphij oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ 2303285612Sdelphij 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"; 2375285612Sdelphij 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) { 2416285612Sdelphij 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{ 2450285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 2451285612Sdelphij "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x", 2452285612Sdelphij ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], 2453285612Sdelphij 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 2478285612Sdelphij instance->saw_Bj = 1; 2479285612Sdelphij 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 } 2495285612Sdelphij oncore_log(instance, LOG_NOTICE, cp); 2496132451Sroberto} 249782498Sroberto 2498132451Sroberto 2499132451Sroberto 2500132451Srobertostatic void 2501285612Sdelphijoncore_msg_Bl( 2502285612Sdelphij struct instance *instance, 2503285612Sdelphij u_char *buf, 2504285612Sdelphij size_t len 2505285612Sdelphij ) 2506285612Sdelphij{ 2507285612Sdelphij int subframe, valid, page, i, j, tow; 2508285612Sdelphij int day_now, day_lsf; 2509285612Sdelphij const char *cp; 2510285612Sdelphij enum { 2511285612Sdelphij WARN_NOT_YET, 2512285612Sdelphij WARN_0, 2513285612Sdelphij WARN_PLUS, 2514285612Sdelphij WARN_MINUS 2515285612Sdelphij } warn; 2516285612Sdelphij 2517285612Sdelphij 2518285612Sdelphij subframe = buf[6] & 017; 2519285612Sdelphij valid = (buf[6] >> 4) & 017; 2520285612Sdelphij page = buf[7]; 2521285612Sdelphij 2522285612Sdelphij if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) { 2523285612Sdelphij instance->Bl.dt_ls = buf[32]; 2524285612Sdelphij instance->Bl.WN_lsf = buf[33]; 2525285612Sdelphij instance->Bl.DN_lsf = buf[34]; 2526285612Sdelphij instance->Bl.dt_lsf = buf[35]; 2527285612Sdelphij instance->Bl.lsf_flg++; 2528285612Sdelphij } 2529285612Sdelphij if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) { 2530285612Sdelphij i = (buf[7+7]<<8) + buf[7+8]; 2531285612Sdelphij instance->Bl.WN = i >> 6; 2532285612Sdelphij tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6]; 2533285612Sdelphij tow >>= 7; 2534285612Sdelphij tow = tow & 0377777; 2535285612Sdelphij tow <<= 2; 2536285612Sdelphij instance->Bl.DN = tow/57600L + 1; 2537285612Sdelphij instance->Bl.wn_flg++; 2538285612Sdelphij } 2539285612Sdelphij if (instance->Bl.wn_flg && instance->Bl.lsf_flg) { 2540285612Sdelphij instance->Bl.wn_flg = instance->Bl.lsf_flg = 0; 2541285612Sdelphij oncore_cmd_Bl[2] = 0; 2542285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl); 2543285612Sdelphij oncore_cmd_Bl[2] = 1; 2544285612Sdelphij 2545285612Sdelphij i = instance->Bl.WN&01400; 2546285612Sdelphij instance->Bl.WN_lsf |= i; 2547285612Sdelphij 2548285612Sdelphij /* have everything I need, doit */ 2549285612Sdelphij 2550285612Sdelphij i = (instance->Bl.WN_lsf - instance->Bl.WN); 2551285612Sdelphij if (i < 0) 2552285612Sdelphij i += 1024; 2553285612Sdelphij day_now = instance->Bl.DN; 2554285612Sdelphij day_lsf = 7*i + instance->Bl.DN_lsf; 2555285612Sdelphij 2556285612Sdelphij /* ignore if in past or more than a month in future */ 2557285612Sdelphij 2558285612Sdelphij warn = WARN_NOT_YET; 2559285612Sdelphij if (day_lsf >= day_now && day_lsf - day_now < 32) { 2560285612Sdelphij /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */ 2561285612Sdelphij if (day_lsf - day_now < 28 || instance->BEHa[5] < 20) { 2562285612Sdelphij i = instance->Bl.dt_lsf - instance->Bl.dt_ls; 2563285612Sdelphij switch (i) { 2564285612Sdelphij case -1: 2565285612Sdelphij warn = WARN_MINUS; 2566285612Sdelphij break; 2567285612Sdelphij case 0: 2568285612Sdelphij warn = WARN_0; 2569285612Sdelphij break; 2570285612Sdelphij case 1: 2571285612Sdelphij warn = WARN_PLUS; 2572285612Sdelphij break; 2573285612Sdelphij } 2574285612Sdelphij } 2575285612Sdelphij } 2576285612Sdelphij 2577285612Sdelphij switch (warn) { 2578285612Sdelphij case WARN_0: 2579285612Sdelphij case WARN_NOT_YET: 2580285612Sdelphij instance->peer->leap = LEAP_NOWARNING; 2581285612Sdelphij cp = "Set peer.leap to LEAP_NOWARNING"; 2582285612Sdelphij break; 2583285612Sdelphij case WARN_MINUS: 2584285612Sdelphij instance->peer->leap = LEAP_DELSECOND; 2585285612Sdelphij cp = "Set peer.leap to LEAP_DELSECOND"; 2586285612Sdelphij break; 2587285612Sdelphij case WARN_PLUS: 2588285612Sdelphij instance->peer->leap = LEAP_ADDSECOND; 2589285612Sdelphij cp = "Set peer.leap to LEAP_ADDSECOND"; 2590285612Sdelphij break; 2591316722Sdelphij default: 2592316722Sdelphij cp = NULL; 2593316722Sdelphij break; 2594285612Sdelphij } 2595285612Sdelphij oncore_log(instance, LOG_NOTICE, cp); 2596285612Sdelphij 2597285612Sdelphij i = instance->Bl.dt_lsf-instance->Bl.dt_ls; 2598285612Sdelphij if (i) { 2599285612Sdelphij j = (i >= 0) ? i : -i; /* abs(i) */ 2600285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 2601285612Sdelphij "see Leap_Second (%c%d) in %d days", 2602285612Sdelphij ((i >= 0) ? '+' : '-'), j, 2603285612Sdelphij day_lsf-day_now); 2604285612Sdelphij } 2605285612Sdelphij } 2606285612Sdelphij 2607285612Sdelphij/* 2608285612Sdelphij * Reg only wants the following output for "deeper" driver debugging. 2609285612Sdelphij * See Bug 2142 and Bug 1866 2610285612Sdelphij */ 2611285612Sdelphij#if 0 2612285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 2613285612Sdelphij "dt_ls = %d dt_lsf = %d WN = %d DN = %d WN_lsf = %d DNlsf = %d wn_flg = %d lsf_flg = %d Bl_day = %d", 2614285612Sdelphij instance->Bl.dt_ls, instance->Bl.dt_lsf, 2615285612Sdelphij instance->Bl.WN, instance->Bl.DN, 2616285612Sdelphij instance->Bl.WN_lsf, instance->Bl.DN_lsf, 2617285612Sdelphij instance->Bl.wn_flg, instance->Bl.lsf_flg, 2618285612Sdelphij instance->Bl.Bl_day); 2619285612Sdelphij#endif 2620285612Sdelphij} 2621285612Sdelphij 2622285612Sdelphij 2623285612Sdelphijstatic void 2624132451Srobertooncore_msg_BnEnHn( 2625132451Sroberto struct instance *instance, 2626132451Sroberto u_char *buf, 2627132451Sroberto size_t len 2628132451Sroberto ) 2629132451Sroberto{ 2630132451Sroberto long dt1, dt2; 2631132451Sroberto 2632132451Sroberto if (instance->o_state != ONCORE_RUN) 2633132451Sroberto return; 2634132451Sroberto 2635132451Sroberto if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */ 2636132451Sroberto instance->traim_ck = 1; 2637132451Sroberto instance->traim_delay = 0; 2638285612Sdelphij oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON"); 2639132451Sroberto 2640132451Sroberto oncore_set_traim(instance); 264182498Sroberto } 2642132451Sroberto 2643132451Sroberto memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */ 2644132451Sroberto 2645182007Sroberto if (!instance->traim) /* BnEnHn will be turned off in any case */ 2646182007Sroberto return; 2647182007Sroberto 2648132451Sroberto /* If Time RAIM doesn't like it, don't trust it */ 2649132451Sroberto 2650132451Sroberto if (buf[2] == 'H') { 2651285612Sdelphij if (instance->BEHn[6]) { /* bad TRAIM */ 2652285612Sdelphij oncore_log(instance, LOG_WARNING, "BAD TRAIM"); 2653132451Sroberto return; 2654285612Sdelphij } 2655132451Sroberto 2656132451Sroberto dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2657182007Sroberto instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */ 2658132451Sroberto dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2659132451Sroberto } else { 2660132451Sroberto if (instance->BEHn[21]) /* bad TRAIM */ 2661132451Sroberto return; 2662132451Sroberto 2663132451Sroberto dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2664182007Sroberto instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */ 2665132451Sroberto dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 2666132451Sroberto } 2667132451Sroberto 2668132451Sroberto oncore_get_timestamp(instance, dt1, dt2); 266982498Sroberto} 267082498Sroberto 267182498Sroberto 267282498Sroberto 267382498Sroberto/* Here for @@Ca, @@Fa and @@Ia messages */ 267482498Sroberto 2675132451Sroberto/* These are Self test Commands for 6, 8, and 12 chan receivers. 2676132451Sroberto * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE. 2677132451Sroberto * It was found that under some circumstances the following 267882498Sroberto * command would fail if issued immediately after the return from the 267982498Sroberto * @@Fa, but a 2sec delay seemed to fix things. Since simply calling 2680132451Sroberto * sleep(2) is wasteful, and may cause trouble for some OS's, repeating 2681132451Sroberto * itimer, we set a flag, and test it at the next POLL. If it hasn't 268282498Sroberto * been cleared, we reissue the @@Cj that is issued below. 268382498Sroberto * Note that we do a @@Cj at the beginning, and again here. 268482498Sroberto * The first is to get the info, the 2nd is just used as a safe command 268582498Sroberto * after the @@Fa for all Oncores (and it was in this posn in the 268682498Sroberto * original code). 268782498Sroberto */ 268882498Sroberto 268982498Srobertostatic void 269082498Srobertooncore_msg_CaFaIa( 269182498Sroberto struct instance *instance, 269282498Sroberto u_char *buf, 269382498Sroberto size_t len 269482498Sroberto ) 269582498Sroberto{ 2696132451Sroberto int i; 269782498Sroberto 269882498Sroberto if (instance->o_state == ONCORE_TEST_SENT) { 2699132451Sroberto enum antenna_state antenna; 270082498Sroberto 270182498Sroberto instance->timeout = 0; 270282498Sroberto 2703285612Sdelphij#if ONCORE_VERBOSE_SELF_TEST 270482498Sroberto if (debug > 2) { 270582498Sroberto if (buf[2] == 'I') 2706285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 2707285612Sdelphij ">>@@%ca %x %x %x", buf[2], 2708285612Sdelphij buf[4], buf[5], buf[6]); 270982498Sroberto else 2710285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 2711285612Sdelphij ">>@@%ca %x %x", buf[2], 2712285612Sdelphij buf[4], buf[5]); 271382498Sroberto } 2714182007Sroberto#endif 271582498Sroberto 2716132451Sroberto antenna = (buf[4] & 0xc0) >> 6; 271782498Sroberto buf[4] &= ~0xc0; 271882498Sroberto 2719132451Sroberto i = buf[4] || buf[5]; 2720132451Sroberto if (buf[2] == 'I') i = i || buf[6]; 2721132451Sroberto if (i) { 2722285612Sdelphij if (buf[2] == 'I') 2723285612Sdelphij oncore_log_f(instance, LOG_ERR, 2724285612Sdelphij "self test failed: result %02x %02x %02x", 2725285612Sdelphij buf[4], buf[5], buf[6]); 2726285612Sdelphij else 2727285612Sdelphij oncore_log_f(instance, LOG_ERR, 2728285612Sdelphij "self test failed: result %02x %02x", 2729285612Sdelphij buf[4], buf[5]); 2730132451Sroberto 2731285612Sdelphij oncore_log(instance, LOG_ERR, 2732285612Sdelphij "ONCORE: self test failed, shutting down driver"); 2733285612Sdelphij 2734132451Sroberto refclock_report(instance->peer, CEVNT_FAULT); 273582498Sroberto oncore_shutdown(instance->unit, instance->peer); 273682498Sroberto return; 273782498Sroberto } 273882498Sroberto 2739132451Sroberto /* report the current antenna state */ 274082498Sroberto 2741132451Sroberto oncore_antenna_report(instance, antenna); 274282498Sroberto 274382498Sroberto instance->o_state = ONCORE_INIT; 2744285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT"); 2745132451Sroberto 2746132451Sroberto instance->timeout = 4; 2747285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 274882498Sroberto } 274982498Sroberto} 275082498Sroberto 275182498Sroberto 275282498Sroberto 2753132451Sroberto/* 2754132451Sroberto * Demultiplex the almanac into shmem 2755132451Sroberto */ 275682498Sroberto 275782498Srobertostatic void 2758132451Srobertooncore_msg_Cb( 275982498Sroberto struct instance *instance, 276082498Sroberto u_char *buf, 276182498Sroberto size_t len 276282498Sroberto ) 276382498Sroberto{ 2764132451Sroberto int i; 276554359Sroberto 2766132451Sroberto if (instance->shmem == NULL) 2767132451Sroberto return; 276882498Sroberto 2769132451Sroberto if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26) 2770132451Sroberto i = buf[5]; 2771132451Sroberto else if (buf[4] == 4 && buf[5] <= 5) 2772132451Sroberto i = buf[5] + 24; 2773132451Sroberto else if (buf[4] == 4 && buf[5] <= 10) 2774132451Sroberto i = buf[5] + 23; 2775132451Sroberto else if (buf[4] == 4 && buf[5] == 25) 2776132451Sroberto i = 34; 2777132451Sroberto else { 2778285612Sdelphij oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC"); 277954359Sroberto return; 2780132451Sroberto } 278154359Sroberto 2782132451Sroberto i *= 36; 2783132451Sroberto instance->shmem[instance->shmem_Cb + i + 2]++; 2784132451Sroberto memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); 278554359Sroberto 2786285612Sdelphij#ifdef ONCORE_VERBOSE_MSG_CB 2787285612Sdelphij oncore_log_f(instance, LOG_DEBUG, "See Cb [%d,%d]", buf[4], 2788285612Sdelphij buf[5]); 2789132451Sroberto#endif 2790132451Sroberto} 279182498Sroberto 279282498Sroberto 2793132451Sroberto 2794132451Sroberto/* 2795132451Sroberto * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup 2796132451Sroberto * not so for VP (eeprom) or any unit with a battery 2797132451Sroberto */ 2798132451Sroberto 2799132451Srobertostatic void 2800132451Srobertooncore_msg_Cf( 2801132451Sroberto struct instance *instance, 2802132451Sroberto u_char *buf, 2803132451Sroberto size_t len 2804132451Sroberto ) 2805132451Sroberto{ 2806132451Sroberto if (instance->o_state == ONCORE_RESET_SENT) { 2807285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 2808132451Sroberto /* Reset set VP to IDLE */ 2809132451Sroberto instance->o_state = ONCORE_TEST_SENT; 2810285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 2811132451Sroberto 2812285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 281382498Sroberto } 2814132451Sroberto} 281582498Sroberto 281682498Sroberto 281782498Sroberto 2818132451Sroberto/* 2819132451Sroberto * This is the Grand Central Station for the Preliminary Initialization. 2820132451Sroberto * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running. 2821132451Sroberto * 2822132451Sroberto * We do an @@Cj whenever we need a safe command for all Oncores. 2823132451Sroberto * The @@Cj gets us back here where we can switch to the next phase of setup. 2824132451Sroberto * 2825132451Sroberto * o Once at the very beginning (in start) to get the Model number. 2826132451Sroberto * This info is printed, but no longer used. 2827132451Sroberto * o Again after we have determined the number of Channels in the receiver. 2828132451Sroberto * o And once later after we have done a reset and test, (which may hang), 2829132451Sroberto * as we are about to initialize the Oncore and start it running. 2830132451Sroberto * o We have one routine below for each case. 2831132451Sroberto */ 283282498Sroberto 2833132451Srobertostatic void 2834132451Srobertooncore_msg_Cj( 2835132451Sroberto struct instance *instance, 2836132451Sroberto u_char *buf, 2837132451Sroberto size_t len 2838132451Sroberto ) 2839132451Sroberto{ 2840132451Sroberto int mode; 284182498Sroberto 2842132451Sroberto memcpy(instance->Cj, buf, len); 284382498Sroberto 2844132451Sroberto instance->timeout = 0; 2845132451Sroberto if (instance->o_state == ONCORE_CHECK_ID) { 2846132451Sroberto oncore_msg_Cj_id(instance, buf, len); 2847132451Sroberto oncore_chan_test(instance); 2848132451Sroberto } else if (instance->o_state == ONCORE_HAVE_CHAN) { 2849132451Sroberto mode = instance->init_type; 2850132451Sroberto if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */ 2851132451Sroberto instance->o_state = ONCORE_RESET_SENT; 2852285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT"); 2853285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); 2854132451Sroberto } else { 2855132451Sroberto instance->o_state = ONCORE_TEST_SENT; 2856285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 285782498Sroberto } 285882498Sroberto } 285982498Sroberto 2860132451Sroberto if (instance->o_state == ONCORE_TEST_SENT) { 2861132451Sroberto if (instance->chan == 6) 2862285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); 2863132451Sroberto else if (instance->chan == 8) 2864285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); 2865132451Sroberto else if (instance->chan == 12) 2866285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); 2867132451Sroberto } else if (instance->o_state == ONCORE_INIT) 2868132451Sroberto oncore_msg_Cj_init(instance, buf, len); 2869132451Sroberto} 287082498Sroberto 287182498Sroberto 287282498Sroberto 2873132451Sroberto/* The information on determining a Oncore 'Model', viz VP, UT, etc, from 2874132451Sroberto * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> 2875132451Sroberto * and from Motorola. Until recently Rick was the only source of 2876132451Sroberto * this information as Motorola didn't give the information out. 2877132451Sroberto * 2878132451Sroberto * Determine the Type from the Model #, this determines #chan and if TRAIM is 2879132451Sroberto * available. 2880132451Sroberto * 2881132451Sroberto * The Information from this routine is NO LONGER USED. 2882132451Sroberto * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED 2883132451Sroberto */ 288482498Sroberto 2885132451Srobertostatic void 2886132451Srobertooncore_msg_Cj_id( 2887132451Sroberto struct instance *instance, 2888132451Sroberto u_char *buf, 2889132451Sroberto size_t len 2890132451Sroberto ) 2891132451Sroberto{ 2892285612Sdelphij char *cp2, Model[21]; 2893285612Sdelphij const char *cp, *cp1; 2894132451Sroberto 2895132451Sroberto /* Write Receiver ID message to clockstats file */ 2896132451Sroberto 2897132451Sroberto instance->Cj[294] = '\0'; 2898285612Sdelphij for (cp= (char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { 2899285612Sdelphij char *cpw = strchr(cp, '\r'); 2900285612Sdelphij if (!cpw) 2901285612Sdelphij cpw = (char *)&instance->Cj[294]; 2902285612Sdelphij *cpw = '\0'; 2903285612Sdelphij oncore_log(instance, LOG_NOTICE, cp); 2904285612Sdelphij *cpw = '\r'; 2905285612Sdelphij cp = cpw+2; 290682498Sroberto } 290782498Sroberto 2908132451Sroberto /* next, the Firmware Version and Revision numbers */ 290982498Sroberto 2910182007Sroberto instance->version = atoi((char *) &instance->Cj[83]); 2911182007Sroberto instance->revision = atoi((char *) &instance->Cj[111]); 291282498Sroberto 2913132451Sroberto /* from model number decide which Oncore this is, 2914132451Sroberto and then the number of channels */ 291582498Sroberto 2916182007Sroberto for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ 2917132451Sroberto ; 2918132451Sroberto cp1 = cp; 2919132451Sroberto cp2 = Model; 2920285612Sdelphij for (; !isspace((unsigned char)*cp) && cp-cp1 < 20; cp++, cp2++) 2921132451Sroberto *cp2 = *cp; 2922132451Sroberto *cp2 = '\0'; 2923132451Sroberto 2924132451Sroberto cp = 0; 2925132451Sroberto if (!strncmp(Model, "PVT6", (size_t) 4)) { 2926132451Sroberto cp = "PVT6"; 2927132451Sroberto instance->model = ONCORE_PVT6; 2928132451Sroberto } else if (Model[0] == 'A') { 2929132451Sroberto cp = "Basic"; 2930132451Sroberto instance->model = ONCORE_BASIC; 2931132451Sroberto } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { 2932132451Sroberto cp = "VP"; 2933132451Sroberto instance->model = ONCORE_VP; 2934132451Sroberto } else if (Model[0] == 'P') { 2935132451Sroberto cp = "M12"; 2936132451Sroberto instance->model = ONCORE_M12; 2937132451Sroberto } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') { 2938132451Sroberto if (Model[5] == 'N') { 2939132451Sroberto cp = "GT"; 2940132451Sroberto instance->model = ONCORE_GT; 2941132451Sroberto } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { 2942132451Sroberto cp = "GT+"; 2943132451Sroberto instance->model = ONCORE_GTPLUS; 2944132451Sroberto } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { 2945132451Sroberto cp = "UT"; 2946132451Sroberto instance->model = ONCORE_UT; 2947132451Sroberto } else if (Model[1] == '5' && Model[5] == 'G') { 2948132451Sroberto cp = "UT+"; 2949132451Sroberto instance->model = ONCORE_UTPLUS; 2950132451Sroberto } else if (Model[1] == '6' && Model[5] == 'G') { 2951132451Sroberto cp = "SL"; 2952132451Sroberto instance->model = ONCORE_SL; 2953132451Sroberto } else { 2954132451Sroberto cp = "Unknown"; 2955132451Sroberto instance->model = ONCORE_UNKNOWN; 295654359Sroberto } 2957132451Sroberto } else { 2958132451Sroberto cp = "Unknown"; 2959132451Sroberto instance->model = ONCORE_UNKNOWN; 296054359Sroberto } 296154359Sroberto 2962132451Sroberto /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */ 296354359Sroberto 2964285612Sdelphij oncore_log_f(instance, LOG_INFO, 2965285612Sdelphij "This looks like an Oncore %s with version %d.%d firmware.", 2966285612Sdelphij cp, instance->version, instance->revision); 296782498Sroberto 2968132451Sroberto instance->chan_id = 8; /* default */ 2969132451Sroberto if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2970132451Sroberto instance->chan_id = 6; 2971132451Sroberto else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2972132451Sroberto instance->chan_id = 8; 2973132451Sroberto else if (instance->model == ONCORE_M12) 2974132451Sroberto instance->chan_id = 12; 297582498Sroberto 2976132451Sroberto instance->traim_id = 0; /* default */ 2977132451Sroberto if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 2978132451Sroberto instance->traim_id = 0; 2979132451Sroberto else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 2980132451Sroberto instance->traim_id = 1; 2981132451Sroberto else if (instance->model == ONCORE_M12) 2982132451Sroberto instance->traim_id = -1; 298382498Sroberto 2984285612Sdelphij oncore_log_f(instance, LOG_INFO, "Channels = %d, TRAIM = %s", 2985285612Sdelphij instance->chan_id, 2986285612Sdelphij ((instance->traim_id < 0) 2987285612Sdelphij ? "UNKNOWN" 2988285612Sdelphij : (instance->traim_id > 0) 2989285612Sdelphij ? "ON" 2990285612Sdelphij : "OFF")); 2991132451Sroberto} 2992132451Sroberto 2993132451Sroberto 2994132451Sroberto 2995132451Sroberto/* OK, know type of Oncore, have possibly reset it, and have tested it. 2996132451Sroberto * We know the number of channels. 2997132451Sroberto * We will determine whether we have TRAIM before we actually start. 2998132451Sroberto * Now initialize. 2999132451Sroberto */ 3000132451Sroberto 3001132451Srobertostatic void 3002132451Srobertooncore_msg_Cj_init( 3003132451Sroberto struct instance *instance, 3004132451Sroberto u_char *buf, 3005132451Sroberto size_t len 3006132451Sroberto ) 3007132451Sroberto{ 3008285612Sdelphij u_char Cmd[20]; 3009132451Sroberto int mode; 3010132451Sroberto 3011132451Sroberto 3012132451Sroberto /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to 3013132451Sroberto * start again if we go from 0D -> 3D, then loses them again when we 3014132451Sroberto * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. 3015132451Sroberto * For NOW we will turn this aspect of filling SHMEM off for the M12 301682498Sroberto */ 301782498Sroberto 3018132451Sroberto if (instance->chan == 12) { 3019132451Sroberto instance->shmem_bad_Ea = 1; 3020285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 3021285612Sdelphij "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", 3022285612Sdelphij instance->version, instance->revision); 302354359Sroberto } 302454359Sroberto 3025285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 3026285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */ 3027285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */ 3028285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */ 3029285612Sdelphij oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */ 3030285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */ 3031285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */ 303282498Sroberto 3033132451Sroberto mode = instance->init_type; 303482498Sroberto 3035132451Sroberto /* If there is Position input in the Config file 3036132451Sroberto * and mode = (1,3) set it as posn hold posn, goto 0D mode. 3037132451Sroberto * or mode = (2,4) set it as INITIAL position, and do Site Survey. 303882498Sroberto */ 303954359Sroberto 3040132451Sroberto if (instance->posn_set) { 3041285612Sdelphij oncore_log(instance, LOG_INFO, "Setting Posn from input data"); 3042132451Sroberto oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */ 3043132451Sroberto } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */ 3044132451Sroberto if (instance->chan != 12) 3045285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx)); 304682498Sroberto 3047132451Sroberto if (mode != 0) { 3048132451Sroberto /* cable delay in ns */ 3049132451Sroberto memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az)); 3050285612Sdelphij w32_buf(&Cmd[-2+4], (int)instance->delay); 3051285612Sdelphij oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */ 305282498Sroberto 3053132451Sroberto /* PPS offset in ns */ 3054285612Sdelphij memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */ 3055285612Sdelphij w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */ 3056285612Sdelphij oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ay)); 3057132451Sroberto 3058132451Sroberto /* Satellite mask angle */ 3059132451Sroberto 3060132451Sroberto if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */ 3061132451Sroberto memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag)); 3062132451Sroberto Cmd[-2+4] = instance->Ag; 3063285612Sdelphij oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ag)); 3064132451Sroberto } 306582498Sroberto } 306682498Sroberto 3067132451Sroberto /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s 3068132451Sroberto * now we're really running 3069132451Sroberto * these were ALL started in the chan test, 3070132451Sroberto * However, if we had mode=3,4 then commands got turned off, so we turn 3071132451Sroberto * them on again here just in case 307254359Sroberto */ 307354359Sroberto 3074132451Sroberto if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */ 3075285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 3076285612Sdelphij oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 3077285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 3078285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3079285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba )); 3080132451Sroberto } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */ 3081285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 3082285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 3083285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 3084285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 3085285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea )); 3086132451Sroberto } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */ 3087285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 3088285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 3089285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 3090285612Sdelphij oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 3091285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha )); 3092285612Sdelphij oncore_cmd_Gc[2] = (instance->pps_control < 0) ? 1 : instance->pps_control; 3093285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* PPS off/continuous/Tracking 1+sat/TRAIM */ 309454359Sroberto } 309554359Sroberto 3096132451Sroberto instance->count = 1; 3097132451Sroberto instance->o_state = ONCORE_ALMANAC; 3098285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC"); 3099132451Sroberto} 310082498Sroberto 310154359Sroberto 310254359Sroberto 3103132451Sroberto/* 12chan position */ 310454359Sroberto 3105132451Srobertostatic void 3106132451Srobertooncore_msg_Ga( 3107132451Sroberto struct instance *instance, 3108132451Sroberto u_char *buf, 3109132451Sroberto size_t len 3110132451Sroberto ) 3111132451Sroberto{ 3112132451Sroberto long lat, lon, ht; 3113132451Sroberto double Lat, Lon, Ht; 311454359Sroberto 311554359Sroberto 3116132451Sroberto lat = buf_w32(&buf[4]); 3117132451Sroberto lon = buf_w32(&buf[8]); 3118132451Sroberto ht = buf_w32(&buf[12]); /* GPS ellipsoid */ 311954359Sroberto 3120132451Sroberto Lat = lat; 3121132451Sroberto Lon = lon; 3122132451Sroberto Ht = ht; 312354359Sroberto 3124132451Sroberto Lat /= 3600000; 3125132451Sroberto Lon /= 3600000; 3126132451Sroberto Ht /= 100; 3127132451Sroberto 3128285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 3129285612Sdelphij "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, 3130285612Sdelphij Lon, Ht); 3131132451Sroberto 3132132451Sroberto instance->ss_lat = lat; 3133132451Sroberto instance->ss_long = lon; 3134132451Sroberto instance->ss_ht = ht; 313554359Sroberto 3136132451Sroberto oncore_print_posn(instance); 3137132451Sroberto} 313882498Sroberto 313982498Sroberto 314082498Sroberto 3141132451Sroberto/* 12 chan time/date */ 314282498Sroberto 3143132451Srobertostatic void 3144132451Srobertooncore_msg_Gb( 3145132451Sroberto struct instance *instance, 3146132451Sroberto u_char *buf, 3147132451Sroberto size_t len 3148132451Sroberto ) 3149132451Sroberto{ 3150285612Sdelphij const char * gmts; 3151132451Sroberto int mo, d, y, h, m, s, gmth, gmtm; 315282498Sroberto 3153132451Sroberto mo = buf[4]; 3154132451Sroberto d = buf[5]; 3155132451Sroberto y = 256*buf[6]+buf[7]; 3156132451Sroberto 3157132451Sroberto h = buf[8]; 3158132451Sroberto m = buf[9]; 3159132451Sroberto s = buf[10]; 3160132451Sroberto 3161132451Sroberto gmts = ((buf[11] == 0) ? "+" : "-"); 3162132451Sroberto gmth = buf[12]; 3163132451Sroberto gmtm = buf[13]; 3164132451Sroberto 3165285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 3166285612Sdelphij "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)", 3167285612Sdelphij d, months[mo-1], y, h, m, s, gmts, gmth, gmtm); 316854359Sroberto} 316954359Sroberto 317054359Sroberto 317154359Sroberto 3172285612Sdelphij/* Response to PPS Control message (M12 and M12+T only ) */ 3173285612Sdelphij 3174285612Sdelphijstatic void 3175285612Sdelphijoncore_msg_Gc( 3176285612Sdelphij struct instance *instance, 3177285612Sdelphij u_char *buf, 3178285612Sdelphij size_t len 3179285612Sdelphij ) 3180285612Sdelphij{ 3181285612Sdelphij const char *tbl[] = {"OFF", "ON", "SATELLITE", "TRAIM" }; 3182285612Sdelphij 3183285612Sdelphij instance->pps_control_msg_seen = 1; 3184285612Sdelphij oncore_log_f(instance, LOG_INFO, "PPS Control set to %s", 3185285612Sdelphij tbl[buf[4]]); 3186285612Sdelphij} 3187285612Sdelphij 3188285612Sdelphij 3189285612Sdelphij 3190132451Sroberto/* Leap Second for M12, gives all info from satellite message */ 3191132451Sroberto/* also in UT v3.0 */ 319282498Sroberto 319382498Srobertostatic void 3194132451Srobertooncore_msg_Gj( 319582498Sroberto struct instance *instance, 3196132451Sroberto u_char *buf, 3197132451Sroberto size_t len 319882498Sroberto ) 319982498Sroberto{ 3200285612Sdelphij static const char * insrem[2] = { 3201285612Sdelphij "removed", 3202285612Sdelphij "inserted" 3203285612Sdelphij }; 3204285612Sdelphij 3205132451Sroberto int dt; 3206285612Sdelphij const char *cp; 320754359Sroberto 3208132451Sroberto instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */ 320954359Sroberto 3210132451Sroberto /* print the message to verify whats there */ 321154359Sroberto 3212132451Sroberto dt = buf[5] - buf[4]; 321354359Sroberto 3214285612Sdelphij oncore_log_f(instance, LOG_INFO, 3215285612Sdelphij "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", 3216285612Sdelphij buf[4], buf[5], 256 * buf[6] + buf[7], buf[8], 3217285612Sdelphij buf[9], buf[10], 3218285612Sdelphij (buf[14] + 256 * 3219285612Sdelphij (buf[13] + 256 * (buf[12] + 256 * buf[11]))), 3220285612Sdelphij buf[15], buf[16], buf[17]); 322154359Sroberto 3222285612Sdelphij /* There seems to be eternal confusion about when a leap second 3223285612Sdelphij * takes place. It's the second *before* the new TAI offset 3224285612Sdelphij * becomes effective. But since the ONCORE receiver tells us 3225285612Sdelphij * just that, we would have to do some time/date calculations to 3226285612Sdelphij * get the actual leap second -- that is, the one that is 3227285612Sdelphij * deleted or inserted. 3228285612Sdelphij * 3229285612Sdelphij * Going through all this for a simple log is probably overkill, 3230285612Sdelphij * so for fixing bug#1050 the message output is changed to 3231285612Sdelphij * reflect the fact that it tells the second after the leap 3232285612Sdelphij * second. 3233285612Sdelphij */ 3234285612Sdelphij if (dt) 3235285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 3236285612Sdelphij "Leap second %s (%d) before %04u-%02u-%02u/%02u:%02u:%02u", 3237285612Sdelphij insrem[(dt > 0)], dt, 3238285612Sdelphij 256u * buf[6] + buf[7], buf[8], buf[9], 3239285612Sdelphij buf[15], buf[16], buf[17]); 3240285612Sdelphij 3241132451Sroberto /* Only raise warning within a month of the leap second */ 324254359Sroberto 3243182007Sroberto instance->pp->leap = LEAP_NOWARNING; 3244182007Sroberto cp = "Set pp.leap to LEAP_NOWARNING"; 324554359Sroberto 3246132451Sroberto if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */ 3247132451Sroberto buf[8] == instance->BEHa[4]) { /* month */ 3248132451Sroberto if (dt) { 3249132451Sroberto if (dt < 0) { 3250182007Sroberto instance->pp->leap = LEAP_DELSECOND; 3251182007Sroberto cp = "Set pp.leap to LEAP_DELSECOND"; 3252132451Sroberto } else { 3253182007Sroberto instance->pp->leap = LEAP_ADDSECOND; 3254182007Sroberto cp = "Set pp.leap to LEAP_ADDSECOND"; 3255132451Sroberto } 325654359Sroberto } 3257132451Sroberto } 3258285612Sdelphij oncore_log(instance, LOG_INFO, cp); 3259132451Sroberto} 326054359Sroberto 326154359Sroberto 326254359Sroberto 3263132451Sroberto/* Power on failure */ 326454359Sroberto 3265132451Srobertostatic void 3266132451Srobertooncore_msg_Sz( 3267132451Sroberto struct instance *instance, 3268132451Sroberto u_char *buf, 3269132451Sroberto size_t len 3270132451Sroberto ) 3271132451Sroberto{ 3272132451Sroberto if (instance && instance->peer) { 3273285612Sdelphij oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On"); 3274132451Sroberto oncore_shutdown(instance->unit, instance->peer); 327554359Sroberto } 3276132451Sroberto} 327754359Sroberto 3278132451Sroberto/************** Small Subroutines ***************/ 327954359Sroberto 328054359Sroberto 3281132451Srobertostatic void 3282132451Srobertooncore_antenna_report( 3283132451Sroberto struct instance *instance, 3284132451Sroberto enum antenna_state new_state) 3285132451Sroberto{ 3286285612Sdelphij const char *cp; 3287132451Sroberto 3288132451Sroberto if (instance->ant_state == new_state) 328954359Sroberto return; 329054359Sroberto 3291132451Sroberto switch (new_state) { 3292132451Sroberto case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break; 3293132451Sroberto case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break; 3294132451Sroberto case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break; 3295132451Sroberto case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break; 3296132451Sroberto default: cp = "GPS antenna: ?"; break; 329756746Sroberto } 329854359Sroberto 3299132451Sroberto instance->ant_state = new_state; 3300285612Sdelphij oncore_log(instance, LOG_NOTICE, cp); 3301132451Sroberto} 330254359Sroberto 330354359Sroberto 330454359Sroberto 3305132451Srobertostatic void 3306132451Srobertooncore_chan_test( 3307132451Sroberto struct instance *instance 3308132451Sroberto ) 3309132451Sroberto{ 3310132451Sroberto /* subroutine oncore_Cj_id has determined the number of channels from the 3311132451Sroberto * model number of the attached oncore. This is not always correct since 3312132451Sroberto * the oncore could have non-standard firmware. Here we check (independently) by 3313132451Sroberto * trying a 6, 8, and 12 chan command, and see which responds. 3314132451Sroberto * Caution: more than one CAN respond. 331582498Sroberto * 3316132451Sroberto * This #chan is used by the code rather than that calculated from the model number. 331782498Sroberto */ 331882498Sroberto 3319132451Sroberto instance->o_state = ONCORE_CHECK_CHAN; 3320285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN"); 332154359Sroberto 3322132451Sroberto instance->count3 = 1; 3323285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); 3324285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); 3325285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); 3326132451Sroberto} 332782498Sroberto 332882498Sroberto 332982498Sroberto 3330132451Sroberto/* check for a GOOD Almanac, have we got one yet? */ 333154359Sroberto 3332132451Srobertostatic void 3333132451Srobertooncore_check_almanac( 3334132451Sroberto struct instance *instance 3335132451Sroberto ) 3336132451Sroberto{ 3337132451Sroberto if (instance->chan == 6) { 3338132451Sroberto instance->rsm.bad_almanac = instance->BEHa[64]&0x1; 3339132451Sroberto instance->rsm.bad_fix = instance->BEHa[64]&0x52; 3340132451Sroberto } else if (instance->chan == 8) { 3341132451Sroberto instance->rsm.bad_almanac = instance->BEHa[72]&0x1; 3342132451Sroberto instance->rsm.bad_fix = instance->BEHa[72]&0x52; 3343132451Sroberto } else if (instance->chan == 12) { 3344182007Sroberto int bits1, bits2, bits3; 3345132451Sroberto 3346132451Sroberto bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 3347132451Sroberto bits2 = instance->BEHa[130]; 3348132451Sroberto instance->rsm.bad_almanac = (bits2 & 0x80); 3349132451Sroberto instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); 3350132451Sroberto /* too few sat Bad Geom */ 3351182007Sroberto 3352182007Sroberto bits3 = instance->BEHa[141]; /* UTC parameters */ 3353182007Sroberto if (!instance->count5_set && (bits3 & 0xC0)) { 3354285612Sdelphij instance->count5 = 4; /* was 2 [Bug 1766] */ 3355182007Sroberto instance->count5_set = 1; 3356182007Sroberto } 3357285612Sdelphij#ifdef ONCORE_VERBOSE_CHECK_ALMANAC 3358285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 3359285612Sdelphij "DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x", 3360285612Sdelphij instance->BEHa[129], instance->BEHa[130], 3361285612Sdelphij bits1, bits2, bits3, 3362285612Sdelphij instance->mode == MODE_0D, 3363285612Sdelphij instance->mode == MODE_2D, 3364285612Sdelphij instance->mode == MODE_3D, 3365285612Sdelphij instance->rsm.bad_almanac, 3366285612Sdelphij instance->rsm.bad_fix); 3367285612Sdelphij } 336854359Sroberto#endif 3369132451Sroberto } 3370132451Sroberto} 337154359Sroberto 337254359Sroberto 337354359Sroberto 3374132451Sroberto/* check the antenna for changes (did it get unplugged?) */ 337554359Sroberto 3376132451Srobertostatic void 3377132451Srobertooncore_check_antenna( 3378132451Sroberto struct instance *instance 3379132451Sroberto ) 3380132451Sroberto{ 3381132451Sroberto enum antenna_state antenna; /* antenna state */ 338282498Sroberto 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{ 3421285612Sdelphij oncore_cmd_Bl[2] = 1; /* just to be sure */ 3422285612Sdelphij 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)) 3427285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3428285612Sdelphij 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 3435285612Sdelphij 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; 3449285612Sdelphij if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) { 3450285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 3451285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl)); 3452285612Sdelphij } 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 3504285612Sdelphij if (MSL) /* not set ! */ 3505285612Sdelphij oncore_log_f(instance, LOG_INFO, 3506285612Sdelphij "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 3528285612Sdelphij#ifndef ONCORE_VERBOSE_LOAD_ALMANAC 3529285612Sdelphij for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 3530285612Sdelphij 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 } 3538285612Sdelphij#else /* ONCORE_VERBOSE_LOAD_ALMANAC follows */ 3539285612Sdelphij for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 3540285612Sdelphij cp += (n+3)) { 3541285612Sdelphij oncore_log_f(instance, LOG_DEBUG, "See %c%c%c%c %d", 3542285612Sdelphij *(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) { 3548285612Sdelphij oncore_log(instance, LOG_DEBUG, "GOOD SF"); 3549132451Sroberto write(instance->ttyfd, cp, n); 3550132451Sroberto } else 3551285612Sdelphij oncore_log(instance, LOG_DEBUG, "BAD SF"); 3552132451Sroberto } else 3553285612Sdelphij 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 */ 3561285612Sdelphij 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); 3572285612Sdelphij#ifdef ONCORE_VERBOSE_LOAD_ALMANAC 3573285612Sdelphij oncore_log_f(instance, LOG_DEBUG, 3574285612Sdelphij "SHMEM posn = %ld (%d, %d, %d)", 3575285612Sdelphij (long)(cp-instance->shmem), 3576285612Sdelphij 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 3590285612Sdelphij GETTIMEOFDAY(&tv, 0); 3591132451Sroberto tm = gmtime((const time_t *) &tv.tv_sec); 3592285612Sdelphij 3593285612Sdelphij#ifdef ONCORE_VERBOSE_LOAD_ALMANAC 3594285612Sdelphij oncore_log_f(instance, LOG_DEBUG, "DATE %d %d %d, %d %d %d", 3595285612Sdelphij 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, 3596285612Sdelphij 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; 3610285612Sdelphij oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Gb)); 3611132451Sroberto } else { 3612132451Sroberto /* First set GMT offset to zero */ 3613132451Sroberto 3614285612Sdelphij 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; 3621285612Sdelphij 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; 3627285612Sdelphij oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Aa)); 3628132451Sroberto } 3629132451Sroberto 3630285612Sdelphij 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{ 3643285612Sdelphij#ifdef ONCORE_VERBOSE_CB 3644132451Sroberto int ii; 3645285612Sdelphij char Msg[160], Msg2[10]; 364654359Sroberto 3647285612Sdelphij oncore_log_f(instance, LOG_DEBUG, "DEBUG: See: %c%c%c%c", *(cp), 3648285612Sdelphij *(cp+1), *(cp+2), *(cp+3)); 364954359Sroberto 3650285612Sdelphij snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4), 3651285612Sdelphij *(cp+5)); 3652285612Sdelphij for (ii = 0; ii < 33; ii++) { 3653285612Sdelphij snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii)); 3654285612Sdelphij strlcat(Msg, Msg2, sizeof(Msg)); 3655285612Sdelphij } 3656285612Sdelphij oncore_log(instance, LOG_DEBUG, Msg); 3657285612Sdelphij 3658285612Sdelphij oncore_log_f(instance, LOG_DEBUG, "Debug: Cb: [%d,%d]", *(cp+4), 3659285612Sdelphij *(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{ 3692285612Sdelphij 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 3697285612Sdelphij 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.; 3717285612Sdelphij oncore_log_f(instance, LOG_INFO, 3718285612Sdelphij "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", 3719285612Sdelphij 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.; 3727285612Sdelphij oncore_log_f(instance, LOG_INFO, 3728285612Sdelphij "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", 3729285612Sdelphij 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.; 3737285612Sdelphij oncore_log_f(instance, LOG_INFO, 3738285612Sdelphij "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", 3739285612Sdelphij 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( 3750285612Sdelphij struct instance *instance, 3751132451Sroberto u_char *ptr, 375282498Sroberto size_t len 375356746Sroberto ) 375456746Sroberto{ 3755285612Sdelphij int fd; 3756132451Sroberto u_char cs = 0; 375756746Sroberto 3758285612Sdelphij fd = instance->ttyfd; 3759285612Sdelphij#ifdef ONCORE_VERBOSE_SENDMSG 3760285612Sdelphij if (debug > 4) { 3761285612Sdelphij oncore_log_f(instance, LOG_DEBUG, "ONCORE: Send @@%c%c %d", 3762285612Sdelphij ptr[0], ptr[1], (int)len); 3763285612Sdelphij } 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) 3787285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */ 3788132451Sroberto else { 3789285612Sdelphij oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */ 3790285612Sdelphij 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; 3801285612Sdelphij 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; 3806285612Sdelphij 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; 3816285612Sdelphij 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); 3820285612Sdelphij 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); 3824285612Sdelphij 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; 3829285612Sdelphij 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) 3835285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); 3836132451Sroberto else 3837285612Sdelphij 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 3853285612Sdelphij oncore_log_f(instance, LOG_INFO, "Input says TRAIM = %d", 3854285612Sdelphij instance->traim_in); 3855285612Sdelphij oncore_log_f(instance, LOG_INFO, "Model # says TRAIM = %d", 3856285612Sdelphij instance->traim_id); 3857285612Sdelphij oncore_log_f(instance, LOG_INFO, "Testing says TRAIM = %d", 3858285612Sdelphij instance->traim_ck); 3859285612Sdelphij oncore_log_f(instance, LOG_INFO, "Using TRAIM = %d", 3860285612Sdelphij 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) 3866285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx)); 3867132451Sroberto else if (instance->chan == 8) 3868285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx)); 3869132451Sroberto else /* chan == 12 */ 3870285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0)); 3871285612Sdelphij 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) 3890285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ 3891132451Sroberto else 3892285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ 3893132451Sroberto } else { 3894132451Sroberto if (instance->saw_At) { /* out of 0D -> 3D mode */ 3895285612Sdelphij oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); 3896132451Sroberto if (instance->shmem_Posn == 2) /* 3D -> 2D mode */ 3897285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 3898132451Sroberto } else 3899285612Sdelphij 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) 3904285612Sdelphij 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 */ 3908285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 3909285612Sdelphij oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ 3910132451Sroberto } else 3911285612Sdelphij 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))) { 3940285612Sdelphij oncore_log(instance, LOG_INFO, "Now in 0D mode"); 3941132451Sroberto 3942132451Sroberto if (instance->chan == 12) 3943285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax)); 3944132451Sroberto else 3945285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); 3946132451Sroberto 3947285612Sdelphij 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 3973285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 3974285612Sdelphij "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)", 3975285612Sdelphij instance->ss_lat, instance->ss_long, 3976285612Sdelphij instance->ss_ht); 3977132451Sroberto lat = instance->ss_lat/3600000.; 3978132451Sroberto lon = instance->ss_long/3600000.; 3979132451Sroberto ht = instance->ss_ht/100; 3980285612Sdelphij oncore_log_f(instance, LOG_NOTICE, 3981285612Sdelphij "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)", 3982285612Sdelphij lat, lon, ht); 3983132451Sroberto 3984132451Sroberto oncore_set_posn(instance); 3985132451Sroberto 3986285612Sdelphij oncore_log(instance, LOG_INFO, "Now in 0D mode"); 3987132451Sroberto 3988285612Sdelphij 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) { 4001285612Sdelphij instance->counta++; 4002285612Sdelphij if (instance->counta%5 == 0) 4003285612Sdelphij 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) 4020285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); 4021132451Sroberto else if (instance->chan == 8) 4022285612Sdelphij oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En)); 4023132451Sroberto else if (instance->chan == 12) { 4024285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */ 4025285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */ 4026285612Sdelphij oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */ 4027132451Sroberto } 4028132451Sroberto instance->traim_delay = 1; 4029132451Sroberto 4030285612Sdelphij oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC"); 4031132451Sroberto 4032132451Sroberto instance->o_state = ONCORE_RUN; 4033285612Sdelphij oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN"); 4034132451Sroberto } 4035132451Sroberto return(0); 4036132451Sroberto} 4037132451Sroberto 4038132451Sroberto 4039132451Sroberto 4040285612Sdelphijstatic void 4041285612Sdelphijoncore_log ( 4042285612Sdelphij struct instance *instance, 4043285612Sdelphij int log_level, 4044285612Sdelphij const char *msg 4045285612Sdelphij ) 4046285612Sdelphij{ 4047285612Sdelphij msyslog(log_level, "ONCORE[%d]: %s", instance->unit, msg); 4048285612Sdelphij mprintf_clock_stats(&instance->peer->srcadr, "ONCORE[%d]: %s", 4049285612Sdelphij instance->unit, msg); 4050285612Sdelphij} 4051285612Sdelphij 4052285612Sdelphij 4053285612Sdelphijstatic int 4054285612Sdelphijoncore_log_f( 4055285612Sdelphij struct instance * instance, 4056285612Sdelphij int log_level, 4057285612Sdelphij const char * fmt, 4058285612Sdelphij ... 4059285612Sdelphij ) 4060285612Sdelphij{ 4061285612Sdelphij va_list ap; 4062285612Sdelphij int rc; 4063285612Sdelphij char msg[512]; 4064285612Sdelphij 4065285612Sdelphij va_start(ap, fmt); 4066285612Sdelphij rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 4067285612Sdelphij va_end(ap); 4068285612Sdelphij oncore_log(instance, log_level, msg); 4069285612Sdelphij 4070285612Sdelphij#ifdef ONCORE_VERBOSE_ONCORE_LOG 4071285612Sdelphij instance->max_len = max(strlen(msg), instance->max_len); 4072285612Sdelphij instance->max_count++; 4073285612Sdelphij if (instance->max_count % 100 == 0) 4074285612Sdelphij oncore_log_f(instance, LOG_INFO, 4075285612Sdelphij "Max Message Length so far is %d", 4076285612Sdelphij instance->max_len); 4077285612Sdelphij#endif 4078285612Sdelphij return rc; 4079285612Sdelphij} 4080285612Sdelphij 408154359Sroberto#else 408254359Srobertoint refclock_oncore_bs; 4083285612Sdelphij#endif /* REFCLOCK && CLOCK_ONCORE */ 4084