1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * ---------------------------------------------------------------------------- 3c0b746e5SOllivier Robert * "THE BEER-WARE LICENSE" (Revision 42): 4c0b746e5SOllivier Robert * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5c0b746e5SOllivier Robert * can do whatever you want with this stuff. If we meet some day, and you think 6c0b746e5SOllivier Robert * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7c0b746e5SOllivier Robert * ---------------------------------------------------------------------------- 8c0b746e5SOllivier Robert * 9c0b746e5SOllivier Robert * refclock_oncore.c 10c0b746e5SOllivier Robert * 11c0b746e5SOllivier Robert * Driver for some of the various the Motorola Oncore GPS receivers. 129c2daa00SOllivier Robert * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T 139c2daa00SOllivier Robert * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate 149c2daa00SOllivier Robert * than the others. 15224ba2bdSOllivier Robert * The receivers without position hold (GT, GT+) will be less accurate. 16c0b746e5SOllivier Robert * 17c0b746e5SOllivier Robert * Tested with: 18c0b746e5SOllivier Robert * 19c0b746e5SOllivier Robert * (UT) (VP) 20c0b746e5SOllivier Robert * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. 21c0b746e5SOllivier Robert * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P 22c0b746e5SOllivier Robert * SOFTWARE VER # 2 SOFTWARE VER # 8 23c0b746e5SOllivier Robert * SOFTWARE REV # 2 SOFTWARE REV # 8 24c0b746e5SOllivier Robert * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 25c0b746e5SOllivier Robert * MODEL # R1121N1114 MODEL # B4121P1155 26c0b746e5SOllivier Robert * HWDR P/N # 1 HDWR P/N # _ 27c0b746e5SOllivier Robert * SERIAL # R0010A SERIAL # SSG0226478 28c0b746e5SOllivier Robert * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 29c0b746e5SOllivier Robert * OPTIONS LIST IB 30c0b746e5SOllivier Robert * 31224ba2bdSOllivier Robert * (Basic) (M12) 329c2daa00SOllivier Robert * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. 339c2daa00SOllivier Robert * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A 349c2daa00SOllivier Robert * SOFTWARE VER # 5 SOFTWARE VER # 1 359c2daa00SOllivier Robert * SOFTWARE REV # 0 SOFTWARE REV # 3 369c2daa00SOllivier Robert * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000 379c2daa00SOllivier Robert * MODEL # A11121P116 MODEL # P143T12NR1 38224ba2bdSOllivier Robert * HDWR P/N # _ HWDR P/N # 1 399c2daa00SOllivier Robert * SERIAL # SSG0049809 SERIAL # P003UD 409c2daa00SOllivier Robert * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27 419c2daa00SOllivier Robert * OPTIONS LIST AB 42224ba2bdSOllivier Robert * 43ea906c41SOllivier Robert * (M12+T) (M12+T later version) 44ea906c41SOllivier Robert * COPYRIGHT 1991-2002 MOTOROLA INC. COPYRIGHT 1991-2003 MOTOROLA INC. 45ea906c41SOllivier Robert * SFTW P/N # 61-G10268A SFTW P/N # 61-G10268A 46ea906c41SOllivier Robert * SOFTWARE VER # 2 SOFTWARE VER # 2 47ea906c41SOllivier Robert * SOFTWARE REV # 0 SOFTWARE REV # 1 48ea906c41SOllivier Robert * SOFTWARE DATE AUG 14 2002 SOFTWARE DATE APR 16 2003 49ea906c41SOllivier Robert * MODEL # P283T12T11 MODEL # P273T12T12 50ea906c41SOllivier Robert * HWDR P/N # 2 HWDR P/N # 2 51ea906c41SOllivier Robert * SERIAL # P04DC2 SERIAL # P05Z7Z 52ea906c41SOllivier Robert * MANUFACTUR DATE 2J17 MANUFACTUR DATE 3G15 53ea906c41SOllivier Robert * 54ea906c41SOllivier Robert * -------------------------------------------------------------------------- 552b15cb3dSCy Schubert * Reg Clemens (June 2009) 562b15cb3dSCy Schubert * BUG[1220] OK, big patch, but mostly done mechanically. Change direct calls to write 572b15cb3dSCy Schubert * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog. 582b15cb3dSCy Schubert * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New 592b15cb3dSCy Schubert * routine oncore_log. 602b15cb3dSCy Schubert * -------------------------------------------------------------------------- 612b15cb3dSCy Schubert * Reg Clemens (June 2009) 622b15cb3dSCy Schubert * BUG[1218] The comment on where the oncore driver gets its input file does not 632b15cb3dSCy Schubert * agree with the code. Change the comment. 642b15cb3dSCy Schubert * -------------------------------------------------------------------------- 652b15cb3dSCy Schubert * Reg Clemens (June 2009) 662b15cb3dSCy Schubert * change exit statements to return(0) in main program. I had assumed that if the 672b15cb3dSCy Schubert * PPS driver did not start for some reason, we shuould stop NTPD itelf. Others 682b15cb3dSCy Schubert * disagree. We now give an ERR log message and stop this driver. 692b15cb3dSCy Schubert * -------------------------------------------------------------------------- 702b15cb3dSCy Schubert * Reg Clemens (June 2009) 712b15cb3dSCy Schubert * A bytes available message for the input subsystem (Debug message). 722b15cb3dSCy Schubert * -------------------------------------------------------------------------- 732b15cb3dSCy Schubert * Reg Clemens (Nov 2008) 742b15cb3dSCy Schubert * This code adds a message for TRAIM messages. Users often worry about the 752b15cb3dSCy Schubert * driver not starting up, and it is often because of signal strength being low. 762b15cb3dSCy Schubert * Low signal strength will give TRAIM messages. 772b15cb3dSCy Schubert * -------------------------------------------------------------------------- 782b15cb3dSCy Schubert * Reg Clemens (Nov 2008) 792b15cb3dSCy Schubert * Add waiting on Almanac Message. 802b15cb3dSCy Schubert * -------------------------------------------------------------------------- 812b15cb3dSCy Schubert * Reg Clemens (Nov 2008) 822b15cb3dSCy Schubert * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs 832b15cb3dSCy Schubert * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command 842b15cb3dSCy Schubert * that says 'Leap Pending'. As documented it only becomes true in the month 852b15cb3dSCy Schubert * before the leap second is to be applied, but in practice at least some of 862b15cb3dSCy Schubert * the receivers turn this indicator on as soon as the message is posted, which 872b15cb3dSCy Schubert * can be 6months early. As such, we use the Bj command to turn on the 882b15cb3dSCy Schubert * instance->pp->leap indicator but only run this test in December and June for 892b15cb3dSCy Schubert * updates on 1Jan and 1July. 902b15cb3dSCy Schubert * 912b15cb3dSCy Schubert * The @@Gj command exists in later ONCOREs, and it gives the exact date 922b15cb3dSCy Schubert * and size of the Leap Update. It can be emulated in the VP using the @@Bl 932b15cb3dSCy Schubert * command which reads the raw Satellite Broadcast Messages. 942b15cb3dSCy Schubert * We use these two commands to print informative messages in the clockstats 952b15cb3dSCy Schubert * file once per day as soon as the message appears on the satellites. 962b15cb3dSCy Schubert * -------------------------------------------------------------------------- 97ea906c41SOllivier Robert * Reg Clemens (Feb 2006) 98ea906c41SOllivier Robert * Fix some gcc4 compiler complaints 99ea906c41SOllivier Robert * Fix possible segfault in oncore_init_shmem 100ea906c41SOllivier Robert * change all (possible) fprintf(stderr, to record_clock_stats 101ea906c41SOllivier Robert * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct 102ea906c41SOllivier Robert * immediately after new Almanac Read. 103ea906c41SOllivier Robert * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it> 104ea906c41SOllivier Robert * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or 105ea906c41SOllivier Robert * the new one. Compiles depending on timepps.h seen. 106ea906c41SOllivier Robert * -------------------------------------------------------------------------- 107ea906c41SOllivier Robert * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds 108ea906c41SOllivier Robert * (the oncore driver was setting the wrong ntpd variable) 109ea906c41SOllivier Robert * -------------------------------------------------------------------------- 110ea906c41SOllivier Robert * Reg.Clemens (Mar 2004) 111ea906c41SOllivier Robert * Support for interfaces other than PPSAPI removed, for Solaris, SunOS, 112ea906c41SOllivier Robert * SCO, you now need to use one of the timepps.h files in the root dir. 113ea906c41SOllivier Robert * this driver will 'grab' it for you if you dont have one in /usr/include 114c0b746e5SOllivier Robert * -------------------------------------------------------------------------- 115c0b746e5SOllivier Robert * This code uses the two devices 116c0b746e5SOllivier Robert * /dev/oncore.serial.n 117c0b746e5SOllivier Robert * /dev/oncore.pps.n 118c0b746e5SOllivier Robert * which may be linked to the same device. 119c0b746e5SOllivier Robert * and can read initialization data from the file 120224ba2bdSOllivier Robert * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where 121224ba2bdSOllivier Robert * n or N are the unit number, viz 127.127.30.N. 122c0b746e5SOllivier Robert * -------------------------------------------------------------------------- 123c0b746e5SOllivier Robert * Reg.Clemens <reg@dwf.com> Sep98. 124c0b746e5SOllivier Robert * Original code written for FreeBSD. 125224ba2bdSOllivier Robert * With these mods it works on FreeBSD, SunOS, Solaris and Linux 126224ba2bdSOllivier Robert * (SunOS 4.1.3 + ppsclock) 127224ba2bdSOllivier Robert * (Solaris7 + MU4) 128224ba2bdSOllivier Robert * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). 129c0b746e5SOllivier Robert * 130c0b746e5SOllivier Robert * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the 131c0b746e5SOllivier Robert * state machine state) are printed to CLOCKSTATS if that file is enabled 132c0b746e5SOllivier Robert * in /etc/ntp.conf. 133c0b746e5SOllivier Robert * 134c0b746e5SOllivier Robert * -------------------------------------------------------------------------- 135224ba2bdSOllivier Robert * 136c0b746e5SOllivier Robert * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) 137c0b746e5SOllivier Robert * doing an average of 10000 valid 2D and 3D fixes is what the automatic 138c0b746e5SOllivier Robert * site survey mode does. Looking at the output from the receiver 139c0b746e5SOllivier Robert * it seems like it is only using 3D fixes. 140c0b746e5SOllivier Robert * When we do it ourselves, take 10000 3D fixes. 141c0b746e5SOllivier Robert */ 142c0b746e5SOllivier Robert 143c0b746e5SOllivier Robert #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ 144c0b746e5SOllivier Robert 145a151a66cSOllivier Robert /* 146a151a66cSOllivier Robert * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a 147a151a66cSOllivier Robert * "STATUS" line in the oncore config file, which contains the most recent 148a151a66cSOllivier Robert * copy of all types of messages we recognize. This file can be mmap(2)'ed 149a151a66cSOllivier Robert * by monitoring and statistics programs. 150224ba2bdSOllivier Robert * 151224ba2bdSOllivier Robert * See separate HTML documentation for this option. 152a151a66cSOllivier Robert */ 153a151a66cSOllivier Robert 154c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 155c0b746e5SOllivier Robert #include <config.h> 156c0b746e5SOllivier Robert #endif 157c0b746e5SOllivier Robert 158ea906c41SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_ONCORE) 159224ba2bdSOllivier Robert 160224ba2bdSOllivier Robert #include "ntpd.h" 161224ba2bdSOllivier Robert #include "ntp_io.h" 162224ba2bdSOllivier Robert #include "ntp_unixtime.h" 163224ba2bdSOllivier Robert #include "ntp_refclock.h" 1642b15cb3dSCy Schubert #include "ntp_calendar.h" 1652d4e511cSCy Schubert #include "ntp_calgps.h" 166224ba2bdSOllivier Robert #include "ntp_stdlib.h" 167c0b746e5SOllivier Robert 168c0b746e5SOllivier Robert #include <stdio.h> 1692b15cb3dSCy Schubert #include <stdarg.h> 170c0b746e5SOllivier Robert #include <ctype.h> 171c0b746e5SOllivier Robert #include <sys/stat.h> 172a151a66cSOllivier Robert #ifdef ONCORE_SHMEM_STATUS 173a151a66cSOllivier Robert # ifdef HAVE_SYS_MMAN_H 174a151a66cSOllivier Robert # include <sys/mman.h> 175a151a66cSOllivier Robert # ifndef MAP_FAILED 176a151a66cSOllivier Robert # define MAP_FAILED ((u_char *) -1) 177ea906c41SOllivier Robert # endif /* MAP_FAILED */ 178a151a66cSOllivier Robert # endif /* HAVE_SYS_MMAN_H */ 179a151a66cSOllivier Robert #endif /* ONCORE_SHMEM_STATUS */ 180c0b746e5SOllivier Robert 181c0b746e5SOllivier Robert #ifdef HAVE_PPSAPI 182ea906c41SOllivier Robert # include "ppsapi_timepps.h" 183c0b746e5SOllivier Robert #endif 184c0b746e5SOllivier Robert 1852b15cb3dSCy Schubert struct Bl { 1862b15cb3dSCy Schubert int dt_ls; 1872b15cb3dSCy Schubert int dt_lsf; 1882b15cb3dSCy Schubert int WN; 1892b15cb3dSCy Schubert int DN; 1902b15cb3dSCy Schubert int WN_lsf; 1912b15cb3dSCy Schubert int DN_lsf; 1922b15cb3dSCy Schubert int wn_flg; 1932b15cb3dSCy Schubert int lsf_flg; 1942b15cb3dSCy Schubert int Bl_day; 1952b15cb3dSCy Schubert } Bl; 196a151a66cSOllivier Robert 197c0b746e5SOllivier Robert enum receive_state { 198c0b746e5SOllivier Robert ONCORE_NO_IDEA, 1999c2daa00SOllivier Robert ONCORE_CHECK_ID, 2009c2daa00SOllivier Robert ONCORE_CHECK_CHAN, 2019c2daa00SOllivier Robert ONCORE_HAVE_CHAN, 202c0b746e5SOllivier Robert ONCORE_RESET_SENT, 203c0b746e5SOllivier Robert ONCORE_TEST_SENT, 204224ba2bdSOllivier Robert ONCORE_INIT, 205c0b746e5SOllivier Robert ONCORE_ALMANAC, 206c0b746e5SOllivier Robert ONCORE_RUN 207c0b746e5SOllivier Robert }; 208c0b746e5SOllivier Robert 209c0b746e5SOllivier Robert enum site_survey_state { 210c0b746e5SOllivier Robert ONCORE_SS_UNKNOWN, 211224ba2bdSOllivier Robert ONCORE_SS_TESTING, 212c0b746e5SOllivier Robert ONCORE_SS_HW, 213c0b746e5SOllivier Robert ONCORE_SS_SW, 214c0b746e5SOllivier Robert ONCORE_SS_DONE 215c0b746e5SOllivier Robert }; 216c0b746e5SOllivier Robert 2179c2daa00SOllivier Robert enum antenna_state { 2189c2daa00SOllivier Robert ONCORE_ANTENNA_UNKNOWN = -1, 2199c2daa00SOllivier Robert ONCORE_ANTENNA_OK = 0, 2209c2daa00SOllivier Robert ONCORE_ANTENNA_OC = 1, 2219c2daa00SOllivier Robert ONCORE_ANTENNA_UC = 2, 2229c2daa00SOllivier Robert ONCORE_ANTENNA_NV = 3 2239c2daa00SOllivier Robert }; 2249c2daa00SOllivier Robert 225224ba2bdSOllivier Robert /* Model Name, derived from the @@Cj message. 226224ba2bdSOllivier Robert * Used to initialize some variables. 227224ba2bdSOllivier Robert */ 228224ba2bdSOllivier Robert 229224ba2bdSOllivier Robert enum oncore_model { 230224ba2bdSOllivier Robert ONCORE_BASIC, 231224ba2bdSOllivier Robert ONCORE_PVT6, 232224ba2bdSOllivier Robert ONCORE_VP, 233224ba2bdSOllivier Robert ONCORE_UT, 234224ba2bdSOllivier Robert ONCORE_UTPLUS, 235224ba2bdSOllivier Robert ONCORE_GT, 236224ba2bdSOllivier Robert ONCORE_GTPLUS, 237224ba2bdSOllivier Robert ONCORE_SL, 238224ba2bdSOllivier Robert ONCORE_M12, 239224ba2bdSOllivier Robert ONCORE_UNKNOWN 240224ba2bdSOllivier Robert }; 241224ba2bdSOllivier Robert 242224ba2bdSOllivier Robert /* the bits that describe these properties are in the same place 243224ba2bdSOllivier Robert * on the VP/UT, but have moved on the M12. As such we extract 244224ba2bdSOllivier Robert * them, and use them from this struct. 245224ba2bdSOllivier Robert * 246224ba2bdSOllivier Robert */ 247224ba2bdSOllivier Robert 248224ba2bdSOllivier Robert struct RSM { 249224ba2bdSOllivier Robert u_char posn0D; 250224ba2bdSOllivier Robert u_char posn2D; 251224ba2bdSOllivier Robert u_char posn3D; 252224ba2bdSOllivier Robert u_char bad_almanac; 253224ba2bdSOllivier Robert u_char bad_fix; 254224ba2bdSOllivier Robert }; 255224ba2bdSOllivier Robert 256224ba2bdSOllivier Robert /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to 257224ba2bdSOllivier Robert * see what mode it is in. The bits on the M12 are multiplexed with 258224ba2bdSOllivier Robert * other messages, so we have to 'keep' the last known mode here. 259224ba2bdSOllivier Robert */ 260224ba2bdSOllivier Robert 261224ba2bdSOllivier Robert enum posn_mode { 262224ba2bdSOllivier Robert MODE_UNKNOWN, 263224ba2bdSOllivier Robert MODE_0D, 264224ba2bdSOllivier Robert MODE_2D, 265224ba2bdSOllivier Robert MODE_3D 266224ba2bdSOllivier Robert }; 267224ba2bdSOllivier Robert 268c0b746e5SOllivier Robert struct instance { 269c0b746e5SOllivier Robert int unit; /* 127.127.30.unit */ 270224ba2bdSOllivier Robert struct refclockproc *pp; 271224ba2bdSOllivier Robert struct peer *peer; 272224ba2bdSOllivier Robert 273c0b746e5SOllivier Robert int ttyfd; /* TTY file descriptor */ 274c0b746e5SOllivier Robert int ppsfd; /* PPS file descriptor */ 2759c2daa00SOllivier Robert int shmemfd; /* Status shm descriptor */ 276c0b746e5SOllivier Robert pps_handle_t pps_h; 277c0b746e5SOllivier Robert pps_params_t pps_p; 278c0b746e5SOllivier Robert enum receive_state o_state; /* Receive state */ 279224ba2bdSOllivier Robert enum posn_mode mode; /* 0D, 2D, 3D */ 280c0b746e5SOllivier Robert enum site_survey_state site_survey; /* Site Survey state */ 2819c2daa00SOllivier Robert enum antenna_state ant_state; /* antenna state */ 282c0b746e5SOllivier Robert 283c0b746e5SOllivier Robert int Bj_day; 284c0b746e5SOllivier Robert 285224ba2bdSOllivier Robert u_long delay; /* ns */ 286c0b746e5SOllivier Robert long offset; /* ns */ 287c0b746e5SOllivier Robert 288224ba2bdSOllivier Robert u_char *shmem; 289224ba2bdSOllivier Robert char *shmem_fname; 290224ba2bdSOllivier Robert u_int shmem_Cb; 291224ba2bdSOllivier Robert u_int shmem_Ba; 292224ba2bdSOllivier Robert u_int shmem_Ea; 293224ba2bdSOllivier Robert u_int shmem_Ha; 294224ba2bdSOllivier Robert u_char shmem_reset; 295224ba2bdSOllivier Robert u_char shmem_Posn; 2969c2daa00SOllivier Robert u_char shmem_bad_Ea; 2979c2daa00SOllivier Robert u_char almanac_from_shmem; 298224ba2bdSOllivier Robert 299c0b746e5SOllivier Robert double ss_lat; 300c0b746e5SOllivier Robert double ss_long; 301c0b746e5SOllivier Robert double ss_ht; 302224ba2bdSOllivier Robert double dH; 303c0b746e5SOllivier Robert int ss_count; 304a151a66cSOllivier Robert u_char posn_set; 305c0b746e5SOllivier Robert 306224ba2bdSOllivier Robert enum oncore_model model; 307224ba2bdSOllivier Robert u_int version; 308224ba2bdSOllivier Robert u_int revision; 309224ba2bdSOllivier Robert 310224ba2bdSOllivier Robert u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ 311ea906c41SOllivier Robert s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */ 3129c2daa00SOllivier Robert /* the following 7 are all timing counters */ 313224ba2bdSOllivier Robert u_char traim_delay; /* seconds counter, waiting for reply */ 3149c2daa00SOllivier Robert u_char count; /* cycles thru Ea before starting */ 3159c2daa00SOllivier Robert u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */ 3169c2daa00SOllivier Robert u_char count2; /* cycles thru Ea after count, to check for @@Ea */ 3179c2daa00SOllivier Robert u_char count3; /* cycles thru Ea checking for # channels */ 3189c2daa00SOllivier Robert u_char count4; /* cycles thru leap after Gj to issue Bj */ 319ea906c41SOllivier Robert u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */ 320ea906c41SOllivier Robert u_char count5_set; /* only set count5 once */ 3212b15cb3dSCy Schubert u_char counta; /* count for waiting on almanac message */ 3229c2daa00SOllivier Robert u_char pollcnt; 3239c2daa00SOllivier Robert u_char timeout; /* count to retry Cj after Fa self-test */ 3242b15cb3dSCy Schubert u_char max_len; /* max length message seen by oncore_log, for debugging */ 3252b15cb3dSCy Schubert u_char max_count; /* count for message statistics */ 326224ba2bdSOllivier Robert 327224ba2bdSOllivier Robert struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ 3282b15cb3dSCy Schubert struct Bl Bl; /* Satellite Broadcast Data Message */ 329a151a66cSOllivier Robert u_char printed; 330a151a66cSOllivier Robert u_char polled; 3319c2daa00SOllivier Robert u_long ev_serial; 3322b15cb3dSCy Schubert unsigned Rcvptr; 333c0b746e5SOllivier Robert u_char Rcvbuf[500]; 3349c2daa00SOllivier Robert u_char BEHa[160]; /* Ba, Ea or Ha */ 3359c2daa00SOllivier Robert u_char BEHn[80]; /* Bn , En , or Hn */ 336c0b746e5SOllivier Robert u_char Cj[300]; 3379c2daa00SOllivier Robert u_char Ag; /* Satellite mask angle */ 3389c2daa00SOllivier Robert u_char saw_At; 3399c2daa00SOllivier Robert u_char saw_Ay; 3409c2daa00SOllivier Robert u_char saw_Az; 3412b15cb3dSCy Schubert s_char saw_Bj; 3429c2daa00SOllivier Robert s_char saw_Gj; 343224ba2bdSOllivier Robert u_char have_dH; 344c0b746e5SOllivier Robert u_char init_type; 345c0b746e5SOllivier Robert s_char saw_tooth; 3469c2daa00SOllivier Robert s_char chan_in; /* chan number from INPUT, will always use it */ 3479c2daa00SOllivier Robert u_char chan_id; /* chan number determined from part number */ 3489c2daa00SOllivier Robert u_char chan_ck; /* chan number determined by sending commands to hardware */ 349ea906c41SOllivier Robert s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */ 3509c2daa00SOllivier Robert s_char traim_id; /* TRAIM determined from part number */ 3519c2daa00SOllivier Robert u_char traim_ck; /* TRAIM determined by sending commands to hardware */ 3529c2daa00SOllivier Robert u_char once; /* one pass code at top of BaEaHa */ 353a151a66cSOllivier Robert s_char assert; 3549c2daa00SOllivier Robert u_char hardpps; 3552b15cb3dSCy Schubert s_char pps_control; /* PPS control, M12 only */ 3562b15cb3dSCy Schubert s_char pps_control_msg_seen; 357c0b746e5SOllivier Robert }; 358c0b746e5SOllivier Robert 359c0b746e5SOllivier Robert #define rcvbuf instance->Rcvbuf 360c0b746e5SOllivier Robert #define rcvptr instance->Rcvptr 361c0b746e5SOllivier Robert 3622b15cb3dSCy Schubert static int oncore_start (int, struct peer *); 3632b15cb3dSCy Schubert static void oncore_poll (int, struct peer *); 3642b15cb3dSCy Schubert static void oncore_shutdown (int, struct peer *); 3652b15cb3dSCy Schubert static void oncore_consume (struct instance *); 3662b15cb3dSCy Schubert static void oncore_read_config (struct instance *); 3672b15cb3dSCy Schubert static void oncore_receive (struct recvbuf *); 3682b15cb3dSCy Schubert static int oncore_ppsapi (struct instance *); 3692b15cb3dSCy Schubert static void oncore_get_timestamp (struct instance *, long, long); 3702b15cb3dSCy Schubert static void oncore_init_shmem (struct instance *); 3719c2daa00SOllivier Robert 3722b15cb3dSCy Schubert static void oncore_antenna_report (struct instance *, enum antenna_state); 3732b15cb3dSCy Schubert static void oncore_chan_test (struct instance *); 3742b15cb3dSCy Schubert static void oncore_check_almanac (struct instance *); 3752b15cb3dSCy Schubert static void oncore_check_antenna (struct instance *); 3762b15cb3dSCy Schubert static void oncore_check_leap_sec (struct instance *); 3772b15cb3dSCy Schubert static int oncore_checksum_ok (u_char *, int); 3782b15cb3dSCy Schubert static void oncore_compute_dH (struct instance *); 3792b15cb3dSCy Schubert static void oncore_load_almanac (struct instance *); 3802b15cb3dSCy Schubert static void oncore_log (struct instance *, int, const char *); 3812b15cb3dSCy Schubert static int oncore_log_f (struct instance *, int, const char *, ...) 3822b15cb3dSCy Schubert NTP_PRINTF(3, 4); 3832b15cb3dSCy Schubert static void oncore_print_Cb (struct instance *, u_char *); 3842b15cb3dSCy Schubert /* static void oncore_print_array (u_char *, int); */ 3852b15cb3dSCy Schubert static void oncore_print_posn (struct instance *); 3862b15cb3dSCy Schubert static void oncore_sendmsg (struct instance *, u_char *, size_t); 3872b15cb3dSCy Schubert static void oncore_set_posn (struct instance *); 3882b15cb3dSCy Schubert static void oncore_set_traim (struct instance *); 3892b15cb3dSCy Schubert static void oncore_shmem_get_3D (struct instance *); 3902b15cb3dSCy Schubert static void oncore_ss (struct instance *); 3912b15cb3dSCy Schubert static int oncore_wait_almanac (struct instance *); 3922d4e511cSCy Schubert static void oncore_feed_clockproc (struct instance *); 393c0b746e5SOllivier Robert 3942b15cb3dSCy Schubert static void oncore_msg_any (struct instance *, u_char *, size_t, int); 3952b15cb3dSCy Schubert static void oncore_msg_Adef (struct instance *, u_char *, size_t); 3962b15cb3dSCy Schubert static void oncore_msg_Ag (struct instance *, u_char *, size_t); 3972b15cb3dSCy Schubert static void oncore_msg_As (struct instance *, u_char *, size_t); 3982b15cb3dSCy Schubert static void oncore_msg_At (struct instance *, u_char *, size_t); 3992b15cb3dSCy Schubert static void oncore_msg_Ay (struct instance *, u_char *, size_t); 4002b15cb3dSCy Schubert static void oncore_msg_Az (struct instance *, u_char *, size_t); 4012b15cb3dSCy Schubert static void oncore_msg_BaEaHa (struct instance *, u_char *, size_t); 4022b15cb3dSCy Schubert static void oncore_msg_Bd (struct instance *, u_char *, size_t); 4032b15cb3dSCy Schubert static void oncore_msg_Bj (struct instance *, u_char *, size_t); 4042b15cb3dSCy Schubert static void oncore_msg_Bl (struct instance *, u_char *, size_t); 4052b15cb3dSCy Schubert static void oncore_msg_BnEnHn (struct instance *, u_char *, size_t); 4062b15cb3dSCy Schubert static void oncore_msg_CaFaIa (struct instance *, u_char *, size_t); 4072b15cb3dSCy Schubert static void oncore_msg_Cb (struct instance *, u_char *, size_t); 4082b15cb3dSCy Schubert static void oncore_msg_Cf (struct instance *, u_char *, size_t); 4092b15cb3dSCy Schubert static void oncore_msg_Cj (struct instance *, u_char *, size_t); 4102b15cb3dSCy Schubert static void oncore_msg_Cj_id (struct instance *, u_char *, size_t); 4112b15cb3dSCy Schubert static void oncore_msg_Cj_init (struct instance *, u_char *, size_t); 4122b15cb3dSCy Schubert static void oncore_msg_Ga (struct instance *, u_char *, size_t); 4132b15cb3dSCy Schubert static void oncore_msg_Gb (struct instance *, u_char *, size_t); 4142b15cb3dSCy Schubert static void oncore_msg_Gc (struct instance *, u_char *, size_t); 4152b15cb3dSCy Schubert static void oncore_msg_Gj (struct instance *, u_char *, size_t); 4162b15cb3dSCy Schubert static void oncore_msg_Sz (struct instance *, u_char *, size_t); 417c0b746e5SOllivier Robert 418c0b746e5SOllivier Robert struct refclock refclock_oncore = { 419c0b746e5SOllivier Robert oncore_start, /* start up driver */ 420c0b746e5SOllivier Robert oncore_shutdown, /* shut down driver */ 421c0b746e5SOllivier Robert oncore_poll, /* transmit poll message */ 422ea906c41SOllivier Robert noentry, /* not used */ 423c0b746e5SOllivier Robert noentry, /* not used */ 424c0b746e5SOllivier Robert noentry, /* not used */ 425c0b746e5SOllivier Robert NOFLAGS /* not used */ 426c0b746e5SOllivier Robert }; 427c0b746e5SOllivier Robert 428c0b746e5SOllivier Robert /* 429c0b746e5SOllivier Robert * Understanding the next bit here is not easy unless you have a manual 430224ba2bdSOllivier Robert * for the the various Oncore Models. 431c0b746e5SOllivier Robert */ 432c0b746e5SOllivier Robert 433a151a66cSOllivier Robert static struct msg_desc { 434c0b746e5SOllivier Robert const char flag[3]; 435c0b746e5SOllivier Robert const int len; 4362b15cb3dSCy Schubert void (*handler) (struct instance *, u_char *, size_t); 437c0b746e5SOllivier Robert const char *fmt; 438a151a66cSOllivier Robert int shmem; 439c0b746e5SOllivier Robert } oncore_messages[] = { 440c0b746e5SOllivier Robert /* Ea and En first since they're most common */ 4412b15cb3dSCy Schubert { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC", 0 }, 4422b15cb3dSCy Schubert { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC", 0 }, 4432b15cb3dSCy Schubert { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC", 0 }, 4442b15cb3dSCy Schubert { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC", 0 }, 4452b15cb3dSCy Schubert { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC", 0 }, 4462b15cb3dSCy Schubert { "Hn", 78, oncore_msg_BnEnHn, "", 0 }, 4472b15cb3dSCy Schubert { "Ab", 10, 0, "", 0 }, 4482b15cb3dSCy Schubert { "Ac", 11, 0, "", 0 }, 4492b15cb3dSCy Schubert { "Ad", 11, oncore_msg_Adef, "", 0 }, 4502b15cb3dSCy Schubert { "Ae", 11, oncore_msg_Adef, "", 0 }, 4512b15cb3dSCy Schubert { "Af", 15, oncore_msg_Adef, "", 0 }, 4522b15cb3dSCy Schubert { "Ag", 8, oncore_msg_Ag, "", 0 }, /* Satellite mask angle */ 4532b15cb3dSCy Schubert { "As", 20, oncore_msg_As, "", 0 }, 4542b15cb3dSCy Schubert { "At", 8, oncore_msg_At, "", 0 }, 4552b15cb3dSCy Schubert { "Au", 12, 0, "", 0 }, 4562b15cb3dSCy Schubert { "Av", 8, 0, "", 0 }, 4572b15cb3dSCy Schubert { "Aw", 8, 0, "", 0 }, 4582b15cb3dSCy Schubert { "Ay", 11, oncore_msg_Ay, "", 0 }, 4592b15cb3dSCy Schubert { "Az", 11, oncore_msg_Az, "", 0 }, 4602b15cb3dSCy Schubert { "AB", 8, 0, "", 0 }, 4612b15cb3dSCy Schubert { "Bb", 92, 0, "", 0 }, 4622b15cb3dSCy Schubert { "Bd", 23, oncore_msg_Bd, "", 0 }, 4632b15cb3dSCy Schubert { "Bj", 8, oncore_msg_Bj, "", 0 }, 4642b15cb3dSCy Schubert { "Bl", 41, oncore_msg_Bl, "", 0 }, 4652b15cb3dSCy Schubert { "Ca", 9, oncore_msg_CaFaIa, "", 0 }, 4662b15cb3dSCy Schubert { "Cb", 33, oncore_msg_Cb, "", 0 }, 4672b15cb3dSCy Schubert { "Cf", 7, oncore_msg_Cf, "", 0 }, 4682b15cb3dSCy Schubert { "Cg", 8, 0, "", 0 }, 4692b15cb3dSCy Schubert { "Ch", 9, 0, "", 0 }, 4702b15cb3dSCy Schubert { "Cj", 294, oncore_msg_Cj, "", 0 }, 4712b15cb3dSCy Schubert { "Ek", 71, 0, "", 0 }, 4722b15cb3dSCy Schubert { "Fa", 9, oncore_msg_CaFaIa, "", 0 }, 4732b15cb3dSCy Schubert { "Ga", 20, oncore_msg_Ga, "", 0 }, 4742b15cb3dSCy Schubert { "Gb", 17, oncore_msg_Gb, "", 0 }, 4752b15cb3dSCy Schubert { "Gc", 8, oncore_msg_Gc, "", 0 }, 4762b15cb3dSCy Schubert { "Gd", 8, 0, "", 0 }, 4772b15cb3dSCy Schubert { "Ge", 8, 0, "", 0 }, 4782b15cb3dSCy Schubert { "Gj", 21, oncore_msg_Gj, "", 0 }, 4792b15cb3dSCy Schubert { "Ia", 10, oncore_msg_CaFaIa, "", 0 }, 4802b15cb3dSCy Schubert { "Sz", 8, oncore_msg_Sz, "", 0 }, 4812b15cb3dSCy Schubert { {0}, 7, 0, "", 0 } 482c0b746e5SOllivier Robert }; 483c0b746e5SOllivier Robert 4849c2daa00SOllivier Robert 4859c2daa00SOllivier Robert static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */ 4869c2daa00SOllivier Robert static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */ 4879c2daa00SOllivier Robert static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */ 4889c2daa00SOllivier Robert static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */ 4899c2daa00SOllivier Robert static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */ 4909c2daa00SOllivier Robert static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */ 4919c2daa00SOllivier Robert static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */ 4929c2daa00SOllivier Robert static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */ 4939c2daa00SOllivier Robert static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */ 4949c2daa00SOllivier Robert static u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 6/8/12 Posn Hold Parameters */ 4959c2daa00SOllivier Robert static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */ 4969c2daa00SOllivier Robert 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */ 4979c2daa00SOllivier Robert 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */ 4989c2daa00SOllivier Robert static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */ 4999c2daa00SOllivier Robert static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */ 5009c2daa00SOllivier Robert static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */ 5019c2daa00SOllivier Robert static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */ 5029c2daa00SOllivier Robert static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */ 5039c2daa00SOllivier Robert static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */ 5049c2daa00SOllivier Robert static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */ 5059c2daa00SOllivier Robert static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */ 5069c2daa00SOllivier Robert static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */ 5079c2daa00SOllivier Robert static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */ 5089c2daa00SOllivier Robert static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */ 5099c2daa00SOllivier Robert static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */ 5109c2daa00SOllivier Robert static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */ 5119c2daa00SOllivier Robert static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */ 5129c2daa00SOllivier Robert static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */ 5139c2daa00SOllivier Robert static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */ 5149c2daa00SOllivier Robert static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */ 5159c2daa00SOllivier Robert static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */ 5162b15cb3dSCy Schubert static u_char oncore_cmd_Bl[] = { 'B', 'l', 1 }; /* VP Satellite Broadcast Data Msg */ 5179c2daa00SOllivier Robert static 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 */ 518ea906c41SOllivier Robert static 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 */ 519ea906c41SOllivier Robert static 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 */ 5209c2daa00SOllivier Robert static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */ 5219c2daa00SOllivier Robert static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */ 5229c2daa00SOllivier Robert static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */ 5239c2daa00SOllivier Robert static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */ 5249c2daa00SOllivier Robert static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */ 5259c2daa00SOllivier Robert static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */ 5269c2daa00SOllivier Robert static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */ 5279c2daa00SOllivier Robert static 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 */ 528ea906c41SOllivier Robert static 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 */ 529ea906c41SOllivier Robert static 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 */ 5309c2daa00SOllivier Robert static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */ 5319c2daa00SOllivier Robert static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */ 5329c2daa00SOllivier Robert static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */ 5339c2daa00SOllivier Robert 0xff, 0xff, 0xff, 0xff, /* */ 5349c2daa00SOllivier Robert 0xff, 0xff, 0xff, 0xff, 0xff }; /* */ 5359c2daa00SOllivier Robert static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */ 5362b15cb3dSCy Schubert static u_char oncore_cmd_Gc[] = { 'G', 'c', 0 }; /* 12 PPS Control: Off, On, 1+satellite,TRAIM */ 5379c2daa00SOllivier Robert static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */ 5389c2daa00SOllivier Robert static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */ 5399c2daa00SOllivier Robert static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */ 5409c2daa00SOllivier Robert static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */ 5419c2daa00SOllivier Robert static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */ 5429c2daa00SOllivier Robert static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */ 5439c2daa00SOllivier Robert static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */ 5449c2daa00SOllivier Robert static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */ 5459c2daa00SOllivier Robert static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */ 5469c2daa00SOllivier Robert static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */ 5479c2daa00SOllivier Robert static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */ 5489c2daa00SOllivier Robert static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */ 5499c2daa00SOllivier Robert 5509c2daa00SOllivier Robert /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av 5519c2daa00SOllivier Robert * the GT had Au,Av, but not As,At 5529c2daa00SOllivier Robert * This was as of v2.0 of both firmware sets. possibly 1.3 for UT. 5539c2daa00SOllivier Robert * Bj in UT at v1.3 5549c2daa00SOllivier Robert * dont see Bd in UT/GT thru 1999 5559c2daa00SOllivier Robert * Gj in UT as of 3.0, 1999 , Bj as of 1.3 556c0b746e5SOllivier Robert */ 557c0b746e5SOllivier Robert 558c0b746e5SOllivier Robert #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ 559c0b746e5SOllivier Robert #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ 560c0b746e5SOllivier Robert 561c0b746e5SOllivier Robert #define SPEED B9600 /* Oncore Binary speed (9600 bps) */ 562c0b746e5SOllivier Robert 563c0b746e5SOllivier Robert /* 564c0b746e5SOllivier Robert * Assemble and disassemble 32bit signed quantities from a buffer. 565c0b746e5SOllivier Robert * 566c0b746e5SOllivier Robert */ 567c0b746e5SOllivier Robert 568c0b746e5SOllivier Robert /* to buffer, int w, u_char *buf */ 569224ba2bdSOllivier Robert #define w32_buf(buf,w) { u_int i_tmp; \ 570c0b746e5SOllivier Robert i_tmp = (w<0) ? (~(-w)+1) : (w); \ 571c0b746e5SOllivier Robert (buf)[0] = (i_tmp >> 24) & 0xff; \ 572c0b746e5SOllivier Robert (buf)[1] = (i_tmp >> 16) & 0xff; \ 573c0b746e5SOllivier Robert (buf)[2] = (i_tmp >> 8) & 0xff; \ 574c0b746e5SOllivier Robert (buf)[3] = (i_tmp ) & 0xff; \ 575c0b746e5SOllivier Robert } 576c0b746e5SOllivier Robert 577c0b746e5SOllivier Robert #define w32(buf) (((buf)[0]&0xff) << 24 | \ 578c0b746e5SOllivier Robert ((buf)[1]&0xff) << 16 | \ 579c0b746e5SOllivier Robert ((buf)[2]&0xff) << 8 | \ 580c0b746e5SOllivier Robert ((buf)[3]&0xff) ) 581c0b746e5SOllivier Robert 582c0b746e5SOllivier Robert /* from buffer, char *buf, result to an int */ 583c0b746e5SOllivier Robert #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) 584c0b746e5SOllivier Robert 585224ba2bdSOllivier Robert 586c0b746e5SOllivier Robert /* 587c0b746e5SOllivier Robert * oncore_start - initialize data for processing 588c0b746e5SOllivier Robert */ 589224ba2bdSOllivier Robert 590c0b746e5SOllivier Robert static int 591c0b746e5SOllivier Robert oncore_start( 592c0b746e5SOllivier Robert int unit, 593c0b746e5SOllivier Robert struct peer *peer 594c0b746e5SOllivier Robert ) 595c0b746e5SOllivier Robert { 596ea906c41SOllivier Robert #define STRING_LEN 32 597c0b746e5SOllivier Robert register struct instance *instance; 598c0b746e5SOllivier Robert struct refclockproc *pp; 5992b15cb3dSCy Schubert int fd1, fd2; 6002b15cb3dSCy Schubert char device1[STRING_LEN], device2[STRING_LEN]; 6012b15cb3dSCy Schubert #ifndef SYS_WINNT 602c0b746e5SOllivier Robert struct stat stat1, stat2; 6032b15cb3dSCy Schubert #endif 604c0b746e5SOllivier Robert 6059c2daa00SOllivier Robert /* create instance structure for this unit */ 6069c2daa00SOllivier Robert 6072b15cb3dSCy Schubert instance = emalloc(sizeof(*instance)); 6082b15cb3dSCy Schubert memset(instance, 0, sizeof(*instance)); 6099c2daa00SOllivier Robert 6109c2daa00SOllivier Robert /* initialize miscellaneous variables */ 611224ba2bdSOllivier Robert 612c0b746e5SOllivier Robert pp = peer->procptr; 613224ba2bdSOllivier Robert instance->pp = pp; 614c0b746e5SOllivier Robert instance->unit = unit; 615224ba2bdSOllivier Robert instance->peer = peer; 6169c2daa00SOllivier Robert instance->assert = 1; 6179c2daa00SOllivier Robert instance->once = 1; 618224ba2bdSOllivier Robert 619c0b746e5SOllivier Robert instance->Bj_day = -1; 620224ba2bdSOllivier Robert instance->traim = -1; 6219c2daa00SOllivier Robert instance->traim_in = -1; 6229c2daa00SOllivier Robert instance->chan_in = -1; 6232b15cb3dSCy Schubert instance->pps_control = -1; /* PPS control, M12 only */ 6242b15cb3dSCy Schubert instance->pps_control_msg_seen = -1; /* Have seen response to Gc msg */ 625224ba2bdSOllivier Robert instance->model = ONCORE_UNKNOWN; 626224ba2bdSOllivier Robert instance->mode = MODE_UNKNOWN; 627224ba2bdSOllivier Robert instance->site_survey = ONCORE_SS_UNKNOWN; 6289c2daa00SOllivier Robert instance->Ag = 0xff; /* Satellite mask angle, unset by user */ 6299c2daa00SOllivier Robert instance->ant_state = ONCORE_ANTENNA_UNKNOWN; 630224ba2bdSOllivier Robert 6312b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* PPS not active yet */ 632224ba2bdSOllivier Robert peer->precision = -26; 633224ba2bdSOllivier Robert peer->minpoll = 4; 634224ba2bdSOllivier Robert peer->maxpoll = 4; 635224ba2bdSOllivier Robert pp->clockdesc = "Motorola Oncore GPS Receiver"; 636224ba2bdSOllivier Robert memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); 637c0b746e5SOllivier Robert 6382b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING"); 639ea906c41SOllivier Robert instance->o_state = ONCORE_NO_IDEA; 6402b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_NO_IDEA"); 641ea906c41SOllivier Robert 642ea906c41SOllivier Robert /* Now open files. 643ea906c41SOllivier Robert * This is a bit complicated, a we dont want to open the same file twice 644ea906c41SOllivier Robert * (its a problem on some OS), and device2 may not exist for the new PPS 645ea906c41SOllivier Robert */ 646ea906c41SOllivier Robert 6472b15cb3dSCy Schubert (void)snprintf(device1, sizeof(device1), DEVICE1, unit); 6482b15cb3dSCy Schubert (void)snprintf(device2, sizeof(device2), DEVICE2, unit); 649ea906c41SOllivier Robert 650ea906c41SOllivier Robert /* OPEN DEVICES */ 651ea906c41SOllivier Robert /* opening different devices for fd1 and fd2 presents no problems */ 652ea906c41SOllivier Robert /* opening the SAME device twice, seems to be OS dependent. 653ea906c41SOllivier Robert (a) on Linux (no streams) no problem 654ea906c41SOllivier Robert (b) on SunOS (and possibly Solaris, untested), (streams) 655ea906c41SOllivier Robert never see the line discipline. 656ea906c41SOllivier Robert Since things ALWAYS work if we only open the device once, we check 657ea906c41SOllivier Robert to see if the two devices are in fact the same, then proceed to 658ea906c41SOllivier Robert do one open or two. 659ea906c41SOllivier Robert 6602b15cb3dSCy Schubert For use with linuxPPS we assume that the N_TTY file has been opened 6612b15cb3dSCy Schubert and that the line discipline has been changed to N_PPS by another 6622b15cb3dSCy Schubert program (say ppsldisc) so that the two files expected by the oncore 6632b15cb3dSCy Schubert driver can be opened. 6642b15cb3dSCy Schubert 6652b15cb3dSCy Schubert Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do 6662b15cb3dSCy Schubert the stat below without error even though the file has already had its 6672b15cb3dSCy Schubert line discipline changed by another process. 6682b15cb3dSCy Schubert 6692b15cb3dSCy Schubert The Windows port of ntpd arranges to return duplicate handles for 6702b15cb3dSCy Schubert multiple opens of the same serial device, and doesn't have inodes 6712b15cb3dSCy Schubert for serial handles, so we just open both on Windows. 6722b15cb3dSCy Schubert */ 6732b15cb3dSCy Schubert #ifndef SYS_WINNT 674ea906c41SOllivier Robert if (stat(device1, &stat1)) { 6752b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, "Can't stat fd1 (%s)", 6762b15cb3dSCy Schubert device1); 6772b15cb3dSCy Schubert return(0); /* exit, no file, can't start driver */ 678ea906c41SOllivier Robert } 679ea906c41SOllivier Robert 680ea906c41SOllivier Robert if (stat(device2, &stat2)) { 6812b15cb3dSCy Schubert stat2.st_dev = stat2.st_ino = -2; 6822b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, "Can't stat fd2 (%s) %d %m", 6832b15cb3dSCy Schubert device2, errno); 6842b15cb3dSCy Schubert } 6852b15cb3dSCy Schubert #endif /* !SYS_WINNT */ 6862b15cb3dSCy Schubert 687a466cc55SCy Schubert fd1 = refclock_open(&peer->srcadr, device1, SPEED, LDISC_RAW); 6882b15cb3dSCy Schubert if (fd1 <= 0) { 6892b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, "Can't open fd1 (%s)", 6902b15cb3dSCy Schubert device1); 6912b15cb3dSCy Schubert return(0); /* exit, can't open file, can't start driver */ 692ea906c41SOllivier Robert } 693ea906c41SOllivier Robert 6942b15cb3dSCy Schubert /* for LINUX the PPS device is the result of a line discipline. 6952b15cb3dSCy Schubert It seems simplest to let an external program create the appropriate 6962b15cb3dSCy Schubert /dev/pps<n> file, and only check (carefully) for its existance here 6972b15cb3dSCy Schubert */ 698ea906c41SOllivier Robert 6992b15cb3dSCy Schubert #ifndef SYS_WINNT 700ea906c41SOllivier Robert if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */ 701ea906c41SOllivier Robert fd2 = fd1; 7022b15cb3dSCy Schubert else 7032b15cb3dSCy Schubert #endif /* !SYS_WINNT */ 7042b15cb3dSCy Schubert { /* different devices here */ 7052b15cb3dSCy Schubert if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) { 7062b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, 7072b15cb3dSCy Schubert "Can't open fd2 (%s)", device2); 7082b15cb3dSCy Schubert return(0); /* exit, can't open PPS file, can't start driver */ 709ea906c41SOllivier Robert } 710ea906c41SOllivier Robert } 711ea906c41SOllivier Robert 7122b15cb3dSCy Schubert /* open ppsapi source */ 713ea906c41SOllivier Robert 7142b15cb3dSCy Schubert if (time_pps_create(fd2, &instance->pps_h) < 0) { 7152b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel"); 7162b15cb3dSCy Schubert return(0); /* exit, don't find PPSAPI in kernel */ 717ea906c41SOllivier Robert } 718ea906c41SOllivier Robert 719ea906c41SOllivier Robert /* continue initialization */ 720ea906c41SOllivier Robert 721ea906c41SOllivier Robert instance->ttyfd = fd1; 722ea906c41SOllivier Robert instance->ppsfd = fd2; 723ea906c41SOllivier Robert 7249c2daa00SOllivier Robert /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */ 725c0b746e5SOllivier Robert 726c0b746e5SOllivier Robert oncore_read_config(instance); 727c0b746e5SOllivier Robert 7289c2daa00SOllivier Robert if (!oncore_ppsapi(instance)) 7299c2daa00SOllivier Robert return(0); 7309c2daa00SOllivier Robert 7319c2daa00SOllivier Robert pp->io.clock_recv = oncore_receive; 7322b15cb3dSCy Schubert pp->io.srcclock = peer; 7339c2daa00SOllivier Robert pp->io.datalen = 0; 7349c2daa00SOllivier Robert pp->io.fd = fd1; 7359c2daa00SOllivier Robert if (!io_addclock(&pp->io)) { 7362b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "can't do io_addclock"); 7372b15cb3dSCy Schubert close(fd1); 7382b15cb3dSCy Schubert pp->io.fd = -1; 7399c2daa00SOllivier Robert free(instance); 7409c2daa00SOllivier Robert return (0); 7419c2daa00SOllivier Robert } 7422b15cb3dSCy Schubert pp->unitptr = instance; 7439c2daa00SOllivier Robert 7449c2daa00SOllivier Robert #ifdef ONCORE_SHMEM_STATUS 7459c2daa00SOllivier Robert /* 7469c2daa00SOllivier Robert * Before starting ONCORE, lets setup SHMEM 7479c2daa00SOllivier Robert * This will include merging an old SHMEM into the new one if 7489c2daa00SOllivier Robert * an old one is found. 7499c2daa00SOllivier Robert */ 7509c2daa00SOllivier Robert 7519c2daa00SOllivier Robert oncore_init_shmem(instance); 7529c2daa00SOllivier Robert #endif 7539c2daa00SOllivier Robert 7549c2daa00SOllivier Robert /* 7559c2daa00SOllivier Robert * This will return the Model of the Oncore receiver. 7569c2daa00SOllivier Robert * and start the Initialization loop in oncore_msg_Cj. 7579c2daa00SOllivier Robert */ 7589c2daa00SOllivier Robert 7599c2daa00SOllivier Robert instance->o_state = ONCORE_CHECK_ID; 7602b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID"); 7619c2daa00SOllivier Robert 7629c2daa00SOllivier Robert instance->timeout = 4; 7632b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ 7642b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 7659c2daa00SOllivier Robert 7669c2daa00SOllivier Robert instance->pollcnt = 2; 7679c2daa00SOllivier Robert return (1); 7689c2daa00SOllivier Robert } 7699c2daa00SOllivier Robert 7709c2daa00SOllivier Robert 7719c2daa00SOllivier Robert /* 7729c2daa00SOllivier Robert * oncore_shutdown - shut down the clock 7739c2daa00SOllivier Robert */ 7749c2daa00SOllivier Robert 7759c2daa00SOllivier Robert static void 7769c2daa00SOllivier Robert oncore_shutdown( 7779c2daa00SOllivier Robert int unit, 7789c2daa00SOllivier Robert struct peer *peer 7799c2daa00SOllivier Robert ) 7809c2daa00SOllivier Robert { 7819c2daa00SOllivier Robert register struct instance *instance; 7829c2daa00SOllivier Robert struct refclockproc *pp; 7839c2daa00SOllivier Robert 7849c2daa00SOllivier Robert pp = peer->procptr; 7852b15cb3dSCy Schubert instance = pp->unitptr; 7869c2daa00SOllivier Robert 7872b15cb3dSCy Schubert if (pp->io.fd != -1) 7889c2daa00SOllivier Robert io_closeclock(&pp->io); 7899c2daa00SOllivier Robert 7902b15cb3dSCy Schubert if (instance != NULL) { 791ea906c41SOllivier Robert time_pps_destroy (instance->pps_h); 792ea906c41SOllivier Robert 7939c2daa00SOllivier Robert close(instance->ttyfd); 794ea906c41SOllivier Robert 795ea906c41SOllivier Robert if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd)) 7969c2daa00SOllivier Robert close(instance->ppsfd); 797ea906c41SOllivier Robert 7989c2daa00SOllivier Robert if (instance->shmemfd) 7999c2daa00SOllivier Robert close(instance->shmemfd); 800ea906c41SOllivier Robert 8019c2daa00SOllivier Robert free(instance); 8029c2daa00SOllivier Robert } 8032b15cb3dSCy Schubert } 8049c2daa00SOllivier Robert 8059c2daa00SOllivier Robert 8069c2daa00SOllivier Robert 8079c2daa00SOllivier Robert /* 8089c2daa00SOllivier Robert * oncore_poll - called by the transmit procedure 8099c2daa00SOllivier Robert */ 8109c2daa00SOllivier Robert 8119c2daa00SOllivier Robert static void 8129c2daa00SOllivier Robert oncore_poll( 8139c2daa00SOllivier Robert int unit, 8149c2daa00SOllivier Robert struct peer *peer 8159c2daa00SOllivier Robert ) 8169c2daa00SOllivier Robert { 8179c2daa00SOllivier Robert struct instance *instance; 8189c2daa00SOllivier Robert 8192b15cb3dSCy Schubert instance = peer->procptr->unitptr; 8209c2daa00SOllivier Robert if (instance->timeout) { 8219c2daa00SOllivier Robert instance->timeout--; 8229c2daa00SOllivier Robert if (instance->timeout == 0) { 8232b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, 8242b15cb3dSCy Schubert "Oncore: No response from @@Cj, shutting down driver"); 8259c2daa00SOllivier Robert oncore_shutdown(unit, peer); 8269c2daa00SOllivier Robert } else { 8272b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 8282b15cb3dSCy Schubert oncore_log(instance, LOG_WARNING, "Oncore: Resend @@Cj"); 8299c2daa00SOllivier Robert } 8309c2daa00SOllivier Robert return; 8319c2daa00SOllivier Robert } 8329c2daa00SOllivier Robert 8339c2daa00SOllivier Robert if (!instance->pollcnt) 8349c2daa00SOllivier Robert refclock_report(peer, CEVNT_TIMEOUT); 8359c2daa00SOllivier Robert else 8369c2daa00SOllivier Robert instance->pollcnt--; 8379c2daa00SOllivier Robert peer->procptr->polls++; 8389c2daa00SOllivier Robert instance->polled = 1; 8399c2daa00SOllivier Robert } 8409c2daa00SOllivier Robert 8419c2daa00SOllivier Robert 8429c2daa00SOllivier Robert 8439c2daa00SOllivier Robert /* 8449c2daa00SOllivier Robert * Initialize PPSAPI 8459c2daa00SOllivier Robert */ 8469c2daa00SOllivier Robert 8479c2daa00SOllivier Robert static int 8489c2daa00SOllivier Robert oncore_ppsapi( 8499c2daa00SOllivier Robert struct instance *instance 8509c2daa00SOllivier Robert ) 8519c2daa00SOllivier Robert { 852ea906c41SOllivier Robert int cap, mode, mode1; 8532b15cb3dSCy Schubert const char *cp; 8549c2daa00SOllivier Robert 855ea906c41SOllivier Robert if (time_pps_getcap(instance->pps_h, &cap) < 0) { 8562b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, "time_pps_getcap failed: %m"); 857a151a66cSOllivier Robert return (0); 858a151a66cSOllivier Robert } 859a151a66cSOllivier Robert 860a151a66cSOllivier Robert if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) { 8612b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, "time_pps_getparams failed: %m"); 862a151a66cSOllivier Robert return (0); 863a151a66cSOllivier Robert } 864a151a66cSOllivier Robert 865a151a66cSOllivier Robert /* nb. only turn things on, if someone else has turned something 866a151a66cSOllivier Robert * on before we get here, leave it alone! 867a151a66cSOllivier Robert */ 868a151a66cSOllivier Robert 869ea906c41SOllivier Robert if (instance->assert) { 8702b15cb3dSCy Schubert cp = "Assert"; 871ea906c41SOllivier Robert mode = PPS_CAPTUREASSERT; 872ea906c41SOllivier Robert mode1 = PPS_OFFSETASSERT; 873c0b746e5SOllivier Robert } else { 8742b15cb3dSCy Schubert cp = "Clear"; 875ea906c41SOllivier Robert mode = PPS_CAPTURECLEAR; 876ea906c41SOllivier Robert mode1 = PPS_OFFSETCLEAR; 877c0b746e5SOllivier Robert } 8782b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Initializing timing to %s.", 8792b15cb3dSCy Schubert cp); 880ea906c41SOllivier Robert 881ea906c41SOllivier Robert if (!(mode & cap)) { 8822b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, 8832b15cb3dSCy Schubert "Can't set timing to %s, exiting...", cp); 884ea906c41SOllivier Robert return(0); 885ea906c41SOllivier Robert } 886ea906c41SOllivier Robert 887ea906c41SOllivier Robert if (!(mode1 & cap)) { 8882b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 8892b15cb3dSCy Schubert "Can't set %s, this will increase jitter.", 8902b15cb3dSCy Schubert cp); 891ea906c41SOllivier Robert mode1 = 0; 892ea906c41SOllivier Robert } 893ea906c41SOllivier Robert 894ea906c41SOllivier Robert /* only set what is legal */ 895ea906c41SOllivier Robert 896ea906c41SOllivier Robert instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap; 897a151a66cSOllivier Robert 898c0b746e5SOllivier Robert if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { 8992b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, "ONCORE: time_pps_setparams fails %m"); 9002b15cb3dSCy Schubert return(0); /* exit, can't do time_pps_setparans on PPS file */ 901c0b746e5SOllivier Robert } 902a151a66cSOllivier Robert 9039c2daa00SOllivier Robert /* If HARDPPS is on, we tell kernel */ 904a151a66cSOllivier Robert 9059c2daa00SOllivier Robert if (instance->hardpps) { 906a151a66cSOllivier Robert int i; 907a151a66cSOllivier Robert 9082b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "HARDPPS Set."); 909ea906c41SOllivier Robert 910a151a66cSOllivier Robert if (instance->assert) 911a151a66cSOllivier Robert i = PPS_CAPTUREASSERT; 912a151a66cSOllivier Robert else 913a151a66cSOllivier Robert i = PPS_CAPTURECLEAR; 914a151a66cSOllivier Robert 915ea906c41SOllivier Robert /* we know that 'i' is legal from above */ 916ea906c41SOllivier Robert 917a151a66cSOllivier Robert if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, 918c0b746e5SOllivier Robert PPS_TSFMT_TSPEC) < 0) { 9192b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, "time_pps_kcbind failed: %m"); 9202b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "HARDPPS failed, abort..."); 921a151a66cSOllivier Robert return (0); 922a151a66cSOllivier Robert } 9232b15cb3dSCy Schubert 9242b15cb3dSCy Schubert hardpps_enable = 1; 925a151a66cSOllivier Robert } 9269c2daa00SOllivier Robert return(1); 927c0b746e5SOllivier Robert } 928a151a66cSOllivier Robert 9299c2daa00SOllivier Robert 9309c2daa00SOllivier Robert 9319c2daa00SOllivier Robert #ifdef ONCORE_SHMEM_STATUS 9329c2daa00SOllivier Robert static void 9339c2daa00SOllivier Robert oncore_init_shmem( 9349c2daa00SOllivier Robert struct instance *instance 9359c2daa00SOllivier Robert ) 9369c2daa00SOllivier Robert { 9372b15cb3dSCy Schubert int l, fd; 938ea906c41SOllivier Robert u_char *cp, *cp1, *buf, *shmem_old; 9399c2daa00SOllivier Robert struct msg_desc *mp; 9409c2daa00SOllivier Robert struct stat sbuf; 9412b15cb3dSCy Schubert size_t i, n, n1, shmem_length, shmem_old_size; 942c0b746e5SOllivier Robert 943c0b746e5SOllivier Robert /* 9449c2daa00SOllivier Robert * The first thing we do is see if there is an instance->shmem_fname file (still) 9459c2daa00SOllivier Robert * out there from a previous run. If so, we copy it in and use it to initialize 9469c2daa00SOllivier Robert * shmem (so we won't lose our almanac if we need it). 947c0b746e5SOllivier Robert */ 948c0b746e5SOllivier Robert 9499c2daa00SOllivier Robert shmem_old = 0; 950ea906c41SOllivier Robert shmem_old_size = 0; 9519c2daa00SOllivier Robert if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0) 9522b15cb3dSCy Schubert oncore_log(instance, LOG_WARNING, "ONCORE: Can't open SHMEM file"); 9539c2daa00SOllivier Robert else { 9549c2daa00SOllivier Robert fstat(fd, &sbuf); 9559c2daa00SOllivier Robert shmem_old_size = sbuf.st_size; 956ea906c41SOllivier Robert if (shmem_old_size != 0) { 9572b15cb3dSCy Schubert shmem_old = emalloc((unsigned) sbuf.st_size); 958a466cc55SCy Schubert if (read(fd, shmem_old, shmem_old_size) != shmem_old_size) 959a466cc55SCy Schubert oncore_log(instance, LOG_WARNING, 960a466cc55SCy Schubert "ONCORE: truncated/failed read of SHMEM file"); 961ea906c41SOllivier Robert } 9629c2daa00SOllivier Robert close(fd); 9639c2daa00SOllivier Robert } 9649c2daa00SOllivier Robert 9659c2daa00SOllivier Robert /* OK, we now create the NEW SHMEM. */ 9669c2daa00SOllivier Robert 9679c2daa00SOllivier Robert if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { 9682b15cb3dSCy Schubert oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem"); 969ea906c41SOllivier Robert if (shmem_old) 970ea906c41SOllivier Robert free(shmem_old); 971ea906c41SOllivier Robert 9729c2daa00SOllivier Robert return; 9739c2daa00SOllivier Robert } 9749c2daa00SOllivier Robert 9759c2daa00SOllivier Robert /* see how big it needs to be */ 9769c2daa00SOllivier Robert 9779c2daa00SOllivier Robert n = 1; 9789c2daa00SOllivier Robert for (mp=oncore_messages; mp->flag[0]; mp++) { 9799c2daa00SOllivier Robert mp->shmem = n; 9809c2daa00SOllivier Robert /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ 9819c2daa00SOllivier Robert if (!strcmp(mp->flag, "Cb")) { 9829c2daa00SOllivier Robert instance->shmem_Cb = n; 9839c2daa00SOllivier Robert n += (mp->len + 3) * 34; 9849c2daa00SOllivier Robert } 9859c2daa00SOllivier Robert if (!strcmp(mp->flag, "Ba")) { 9869c2daa00SOllivier Robert instance->shmem_Ba = n; 9879c2daa00SOllivier Robert n += (mp->len + 3) * 3; 9889c2daa00SOllivier Robert } 9899c2daa00SOllivier Robert if (!strcmp(mp->flag, "Ea")) { 9909c2daa00SOllivier Robert instance->shmem_Ea = n; 9919c2daa00SOllivier Robert n += (mp->len + 3) * 3; 9929c2daa00SOllivier Robert } 9939c2daa00SOllivier Robert if (!strcmp(mp->flag, "Ha")) { 9949c2daa00SOllivier Robert instance->shmem_Ha = n; 9959c2daa00SOllivier Robert n += (mp->len + 3) * 3; 9969c2daa00SOllivier Robert } 9979c2daa00SOllivier Robert n += (mp->len + 3); 9989c2daa00SOllivier Robert } 9999c2daa00SOllivier Robert shmem_length = n + 2; 10009c2daa00SOllivier Robert 10012b15cb3dSCy Schubert buf = emalloc(shmem_length); 10029c2daa00SOllivier Robert memset(buf, 0, shmem_length); 10039c2daa00SOllivier Robert 10049c2daa00SOllivier Robert /* next build the new SHMEM buffer in memory */ 10059c2daa00SOllivier Robert 10069c2daa00SOllivier Robert for (mp=oncore_messages; mp->flag[0]; mp++) { 10079c2daa00SOllivier Robert l = mp->shmem; 10089c2daa00SOllivier Robert buf[l + 0] = mp->len >> 8; 10099c2daa00SOllivier Robert buf[l + 1] = mp->len & 0xff; 10109c2daa00SOllivier Robert buf[l + 2] = 0; 10119c2daa00SOllivier Robert buf[l + 3] = '@'; 10129c2daa00SOllivier Robert buf[l + 4] = '@'; 10139c2daa00SOllivier Robert buf[l + 5] = mp->flag[0]; 10149c2daa00SOllivier Robert buf[l + 6] = mp->flag[1]; 10159c2daa00SOllivier Robert if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { 10169c2daa00SOllivier Robert if (!strcmp(mp->flag, "Cb")) 10179c2daa00SOllivier Robert n = 35; 10189c2daa00SOllivier Robert else 10199c2daa00SOllivier Robert n = 4; 10209c2daa00SOllivier Robert for (i=1; i<n; i++) { 10219c2daa00SOllivier Robert buf[l + i * (mp->len+3) + 0] = mp->len >> 8; 10229c2daa00SOllivier Robert buf[l + i * (mp->len+3) + 1] = mp->len & 0xff; 10239c2daa00SOllivier Robert buf[l + i * (mp->len+3) + 2] = 0; 10249c2daa00SOllivier Robert buf[l + i * (mp->len+3) + 3] = '@'; 10259c2daa00SOllivier Robert buf[l + i * (mp->len+3) + 4] = '@'; 10269c2daa00SOllivier Robert buf[l + i * (mp->len+3) + 5] = mp->flag[0]; 10279c2daa00SOllivier Robert buf[l + i * (mp->len+3) + 6] = mp->flag[1]; 10289c2daa00SOllivier Robert } 10299c2daa00SOllivier Robert } 10309c2daa00SOllivier Robert } 10319c2daa00SOllivier Robert 10329c2daa00SOllivier Robert /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem) 1033ea906c41SOllivier Robert * copying the data in shmem_old to buf. 1034ea906c41SOllivier Robert * When we are done we write it out and free both buffers. 1035ea906c41SOllivier Robert * If the structure sizes dont agree, I will not copy. 1036ea906c41SOllivier Robert * This could be due to an addition/deletion or a problem with the disk file. 10379c2daa00SOllivier Robert */ 10389c2daa00SOllivier Robert 10399c2daa00SOllivier Robert if (shmem_old) { 1040ea906c41SOllivier Robert if (shmem_old_size == shmem_length) { 10419c2daa00SOllivier Robert for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) { 10429c2daa00SOllivier Robert n1 = 256*(*(cp1-3)) + *(cp1-2); 1043ea906c41SOllivier Robert if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4)) 10449c2daa00SOllivier Robert break; 10459c2daa00SOllivier Robert 10469c2daa00SOllivier Robert memcpy(cp, cp1, (size_t) n); 10479c2daa00SOllivier Robert } 1048ea906c41SOllivier Robert } 10499c2daa00SOllivier Robert free(shmem_old); 10509c2daa00SOllivier Robert } 10519c2daa00SOllivier Robert 10529c2daa00SOllivier Robert i = write(instance->shmemfd, buf, shmem_length); 10539c2daa00SOllivier Robert free(buf); 10549c2daa00SOllivier Robert 10559c2daa00SOllivier Robert if (i != shmem_length) { 10562b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem"); 10579c2daa00SOllivier Robert close(instance->shmemfd); 10589c2daa00SOllivier Robert return; 10599c2daa00SOllivier Robert } 10609c2daa00SOllivier Robert 10619c2daa00SOllivier Robert instance->shmem = (u_char *) mmap(0, shmem_length, 10629c2daa00SOllivier Robert PROT_READ | PROT_WRITE, 10639c2daa00SOllivier Robert #ifdef MAP_HASSEMAPHORE 10649c2daa00SOllivier Robert MAP_HASSEMAPHORE | 10659c2daa00SOllivier Robert #endif 10669c2daa00SOllivier Robert MAP_SHARED, instance->shmemfd, (off_t)0); 10679c2daa00SOllivier Robert 10689c2daa00SOllivier Robert if (instance->shmem == (u_char *)MAP_FAILED) { 10699c2daa00SOllivier Robert instance->shmem = 0; 10709c2daa00SOllivier Robert close(instance->shmemfd); 10719c2daa00SOllivier Robert return; 10729c2daa00SOllivier Robert } 10739c2daa00SOllivier Robert 10742b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 10752b15cb3dSCy Schubert "SHMEM (size = %ld) is CONFIGURED and available as %s", 1076ea906c41SOllivier Robert (u_long) shmem_length, instance->shmem_fname); 10779c2daa00SOllivier Robert } 10789c2daa00SOllivier Robert #endif /* ONCORE_SHMEM_STATUS */ 10799c2daa00SOllivier Robert 1080a151a66cSOllivier Robert 1081a151a66cSOllivier Robert 1082c0b746e5SOllivier Robert /* 1083c0b746e5SOllivier Robert * Read Input file if it exists. 1084c0b746e5SOllivier Robert */ 1085224ba2bdSOllivier Robert 1086c0b746e5SOllivier Robert static void 1087c0b746e5SOllivier Robert oncore_read_config( 1088c0b746e5SOllivier Robert struct instance *instance 1089c0b746e5SOllivier Robert ) 1090c0b746e5SOllivier Robert { 1091c0b746e5SOllivier Robert /* 1092224ba2bdSOllivier Robert * First we try to open the configuration file 10932b15cb3dSCy Schubert * /etc/ntp.oncore.N 1094224ba2bdSOllivier Robert * where N is the unit number viz 127.127.30.N. 1095224ba2bdSOllivier Robert * If we don't find it we try 10962b15cb3dSCy Schubert * /etc/ntp.oncoreN 1097224ba2bdSOllivier Robert * and then 1098224ba2bdSOllivier Robert * /etc/ntp.oncore 1099c0b746e5SOllivier Robert * 1100224ba2bdSOllivier Robert * If we don't find any then we don't have the cable delay or PPS offset 1101c0b746e5SOllivier Robert * and we choose MODE (4) below. 1102c0b746e5SOllivier Robert * 1103c0b746e5SOllivier Robert * Five Choices for MODE 1104c0b746e5SOllivier Robert * (0) ONCORE is preinitialized, don't do anything to change it. 1105c0b746e5SOllivier Robert * nb, DON'T set 0D mode, DON'T set Delay, position... 1106c0b746e5SOllivier Robert * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. 1107c0b746e5SOllivier Robert * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, 1108c0b746e5SOllivier Robert * lock this in, go to 0D mode. 1109c0b746e5SOllivier Robert * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. 1110c0b746e5SOllivier Robert * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, 1111c0b746e5SOllivier Robert * lock this in, go to 0D mode. 1112c0b746e5SOllivier Robert * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] 1113c0b746e5SOllivier Robert * then this position is set as the INITIAL position of the ONCORE. 1114c0b746e5SOllivier Robert * This can reduce the time to first fix. 1115c0b746e5SOllivier Robert * ------------------------------------------------------------------------------- 1116c0b746e5SOllivier Robert * Note that an Oncore UT without a battery backup retains NO information if it is 1117c0b746e5SOllivier Robert * power cycled, with a Battery Backup it remembers the almanac, etc. 1118c0b746e5SOllivier Robert * For an Oncore VP, there is an eeprom that will contain this data, along with the 1119c0b746e5SOllivier Robert * option of Battery Backup. 1120c0b746e5SOllivier Robert * So a UT without Battery Backup is equivalent to doing a HARD RESET on each 1121c0b746e5SOllivier Robert * power cycle, since there is nowhere to store the data. 1122c0b746e5SOllivier Robert * ------------------------------------------------------------------------------- 1123c0b746e5SOllivier Robert * 1124c0b746e5SOllivier Robert * If we open one or the other of the files, we read it looking for 11259c2daa00SOllivier Robert * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS, 11269c2daa00SOllivier Robert * STATUS, POSN3D, POSN2D, CHAN, TRAIM 1127c0b746e5SOllivier Robert * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must 1128c0b746e5SOllivier Robert * be present or mode reverts to (2,4). 1129c0b746e5SOllivier Robert * 1130c0b746e5SOllivier Robert * Read input file. 1131c0b746e5SOllivier Robert * 1132c0b746e5SOllivier Robert * # is comment to end of line 1133c0b746e5SOllivier Robert * = allowed between 1st and 2nd fields. 1134c0b746e5SOllivier Robert * 1135c0b746e5SOllivier Robert * Expect to see one line with 'MODE' as first field, followed by an integer 1136c0b746e5SOllivier Robert * in the range 0-4 (default = 4). 1137c0b746e5SOllivier Robert * 1138c0b746e5SOllivier Robert * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. 1139c0b746e5SOllivier Robert * All numbers are floating point. 1140c0b746e5SOllivier Robert * DDD.ddd 1141c0b746e5SOllivier Robert * DDD MMM.mmm 1142c0b746e5SOllivier Robert * DDD MMM SSS.sss 1143c0b746e5SOllivier Robert * 1144224ba2bdSOllivier Robert * Expect to see one line with 'HT' as first field, 1145224ba2bdSOllivier Robert * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' 1146224ba2bdSOllivier Robert * for feet or meters. HT is the height above the GPS ellipsoid. 11479c2daa00SOllivier Robert * If the receiver reports height in both GPS and MSL, then we will report 1148224ba2bdSOllivier Robert * the difference GPS-MSL on the clockstats file. 1149c0b746e5SOllivier Robert * 1150224ba2bdSOllivier Robert * There is an optional line, starting with DELAY, followed 1151c0b746e5SOllivier Robert * by 1 or two fields. The first is a number (a time) the second is 1152c0b746e5SOllivier Robert * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 1153c0b746e5SOllivier Robert * DELAY is cable delay, typically a few tens of ns. 1154224ba2bdSOllivier Robert * 1155224ba2bdSOllivier Robert * There is an optional line, starting with OFFSET, followed 1156224ba2bdSOllivier Robert * by 1 or two fields. The first is a number (a time) the second is 1157224ba2bdSOllivier Robert * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. 1158c0b746e5SOllivier Robert * OFFSET is the offset of the PPS pulse from 0. (only fully implemented 1159c0b746e5SOllivier Robert * with the PPSAPI, we need to be able to tell the Kernel about this 1160c0b746e5SOllivier Robert * offset if the Kernel PLL is in use, but can only do this presently 1161c0b746e5SOllivier Robert * when using the PPSAPI interface. If not using the Kernel PLL, 1162c0b746e5SOllivier Robert * then there is no problem. 1163c0b746e5SOllivier Robert * 1164224ba2bdSOllivier Robert * There is an optional line, with either ASSERT or CLEAR on it, which 1165c0b746e5SOllivier Robert * determine which transition of the PPS signal is used for timing by the 1166c0b746e5SOllivier Robert * PPSAPI. If neither is present, then ASSERT is assumed. 11679c2daa00SOllivier Robert * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input. 11689c2daa00SOllivier Robert * For Flag2, ASSERT=0, and hence is default. 1169c0b746e5SOllivier Robert * 11709c2daa00SOllivier Robert * There is an optional line, with HARDPPS on it. Including this line causes 11719c2daa00SOllivier Robert * the PPS signal to control the kernel PLL. 11729c2daa00SOllivier Robert * HARDPPS can also be set with FLAG3 of the ntp.conf input. 11739c2daa00SOllivier Robert * For Flag3, 0 is disabled, and the default. 11749c2daa00SOllivier Robert * 11759c2daa00SOllivier Robert * There are three options that have to do with using the shared memory option. 11769c2daa00SOllivier Robert * First, to enable the option there must be a SHMEM line with a file name. 1177224ba2bdSOllivier Robert * The file name is the file associated with the shared memory. 1178224ba2bdSOllivier Robert * 11799c2daa00SOllivier Robert * In shared memory, there is one 'record' for each returned variable. 11809c2daa00SOllivier Robert * For the @@Ea data there are three 'records' containing position data. 11819c2daa00SOllivier Robert * There will always be data in the record corresponding to the '0D' @@Ea record, 11829c2daa00SOllivier Robert * and the user has a choice of filling the '3D' record by specifying POSN3D, 11839c2daa00SOllivier Robert * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D' 11849c2daa00SOllivier Robert * record is filled once every 15s. 1185224ba2bdSOllivier Robert * 1186224ba2bdSOllivier Robert * Two additional variables that can be set are CHAN and TRAIM. These should be 1187224ba2bdSOllivier Robert * set correctly by the code examining the @@Cj record, but we bring them out here 11889c2daa00SOllivier Robert * to allow the user to override either the # of channels, or the existence of TRAIM. 1189224ba2bdSOllivier Robert * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be 1190224ba2bdSOllivier Robert * followed by YES or NO. 1191224ba2bdSOllivier Robert * 11929c2daa00SOllivier Robert * There is an optional line with MASK on it followed by one integer field in the 11939c2daa00SOllivier Robert * range 0 to 89. This sets the satellite mask angle and will determine the minimum 11949c2daa00SOllivier Robert * elevation angle for satellites to be tracked by the receiver. The default value 11959c2daa00SOllivier Robert * is 10 deg for the VP and 0 deg for all other receivers. 11969c2daa00SOllivier Robert * 11972b15cb3dSCy Schubert * There is an optional line with PPSCONTROL on it (only valid for M12 or M12+T 11982b15cb3dSCy Schubert * receivers, the option is read, but ignored for all others) 11992b15cb3dSCy Schubert * and it is followed by: 12002b15cb3dSCy Schubert * ON Turn PPS on. This is the default and the default for other 12012b15cb3dSCy Schubert * oncore receivers. The PPS is on even if not tracking 12022b15cb3dSCy Schubert * any satellites. 12032b15cb3dSCy Schubert * SATELLITE Turns PPS on if tracking at least 1 satellite, else off. 12042b15cb3dSCy Schubert * TRAIM Turns PPS on or off controlled by TRAIM. 12052b15cb3dSCy Schubert * The OFF option is NOT implemented, since the Oncore driver will not work 12062b15cb3dSCy Schubert * without the PPS signal. 12072b15cb3dSCy Schubert * 1208c0b746e5SOllivier Robert * So acceptable input would be 1209c0b746e5SOllivier Robert * # these are my coordinates (RWC) 1210c0b746e5SOllivier Robert * LON -106 34.610 1211c0b746e5SOllivier Robert * LAT 35 08.999 1212c0b746e5SOllivier Robert * HT 1589 # could equally well say HT 5215 FT 1213c0b746e5SOllivier Robert * DELAY 60 ns 1214c0b746e5SOllivier Robert */ 1215c0b746e5SOllivier Robert 1216c0b746e5SOllivier Robert FILE *fd; 12172b15cb3dSCy Schubert char *cc, *ca, line[100], units[2], device[64]; 12182b15cb3dSCy Schubert const char *dirs[] = { "/etc/ntp", "/etc", 0 }; 12192b15cb3dSCy Schubert const char *cp, **cpp; 12209c2daa00SOllivier Robert int i, sign, lat_flg, long_flg, ht_flg, mode, mask; 1221c0b746e5SOllivier Robert double f1, f2, f3; 1222c0b746e5SOllivier Robert 1223ea906c41SOllivier Robert fd = NULL; /* just to shutup gcc complaint */ 1224ea906c41SOllivier Robert for (cpp=dirs; *cpp; cpp++) { 1225ea906c41SOllivier Robert cp = *cpp; 12262b15cb3dSCy Schubert snprintf(device, sizeof(device), "%s/ntp.oncore.%d", 12272b15cb3dSCy Schubert cp, instance->unit); /* try "ntp.oncore.0 */ 1228ea906c41SOllivier Robert if ((fd=fopen(device, "r"))) 1229ea906c41SOllivier Robert break; 12302b15cb3dSCy Schubert snprintf(device, sizeof(device), "%s/ntp.oncore%d", 12312b15cb3dSCy Schubert cp, instance->unit); /* try "ntp.oncore0" */ 1232ea906c41SOllivier Robert if ((fd=fopen(device, "r"))) 1233ea906c41SOllivier Robert break; 12342b15cb3dSCy Schubert snprintf(device, sizeof(device), "%s/ntp.oncore", cp); 12352b15cb3dSCy Schubert if ((fd=fopen(device, "r"))) /* last try "ntp.oncore" */ 1236ea906c41SOllivier Robert break; 1237ea906c41SOllivier Robert } 1238ea906c41SOllivier Robert 1239ea906c41SOllivier Robert if (!fd) { /* no inputfile, default to the works ... */ 1240c0b746e5SOllivier Robert instance->init_type = 4; 1241c0b746e5SOllivier Robert return; 1242c0b746e5SOllivier Robert } 1243c0b746e5SOllivier Robert 12449c2daa00SOllivier Robert mode = mask = 0; 1245c0b746e5SOllivier Robert lat_flg = long_flg = ht_flg = 0; 1246c0b746e5SOllivier Robert while (fgets(line, 100, fd)) { 12472b15cb3dSCy Schubert char *cpw; 1248a151a66cSOllivier Robert 1249a151a66cSOllivier Robert /* Remove comments */ 12502b15cb3dSCy Schubert if ((cpw = strchr(line, '#'))) 12512b15cb3dSCy Schubert *cpw = '\0'; 1252a151a66cSOllivier Robert 1253a151a66cSOllivier Robert /* Remove trailing space */ 1254a151a66cSOllivier Robert for (i = strlen(line); 12552b15cb3dSCy Schubert i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]); 1256a151a66cSOllivier Robert ) 1257a151a66cSOllivier Robert line[--i] = '\0'; 1258a151a66cSOllivier Robert 1259a151a66cSOllivier Robert /* Remove leading space */ 12602b15cb3dSCy Schubert for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++) 1261a151a66cSOllivier Robert continue; 1262a151a66cSOllivier Robert 1263a151a66cSOllivier Robert /* Stop if nothing left */ 1264a151a66cSOllivier Robert if (!*cc) 1265a151a66cSOllivier Robert continue; 1266a151a66cSOllivier Robert 1267224ba2bdSOllivier Robert /* Uppercase the command and find the arg */ 1268a151a66cSOllivier Robert for (ca = cc; *ca; ca++) { 12692b15cb3dSCy Schubert if (isascii((unsigned char)*ca)) { 12702b15cb3dSCy Schubert if (islower((unsigned char)*ca)) { 12712b15cb3dSCy Schubert *ca = toupper((unsigned char)*ca); 12722b15cb3dSCy Schubert } else if (isspace((unsigned char)*ca) || (*ca == '=')) 1273a151a66cSOllivier Robert break; 1274a151a66cSOllivier Robert } 1275a151a66cSOllivier Robert } 1276a151a66cSOllivier Robert 1277224ba2bdSOllivier Robert /* Remove space (and possible =) leading the arg */ 12782b15cb3dSCy Schubert for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++) 1279a151a66cSOllivier Robert continue; 1280a151a66cSOllivier Robert 1281224ba2bdSOllivier Robert if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { 12822b15cb3dSCy Schubert instance->shmem_fname = estrdup(ca); 1283a151a66cSOllivier Robert continue; 1284a151a66cSOllivier Robert } 1285a151a66cSOllivier Robert 1286a151a66cSOllivier Robert /* Uppercase argument as well */ 12872b15cb3dSCy Schubert for (cpw = ca; *cpw; cpw++) 12882b15cb3dSCy Schubert if (isascii((unsigned char)*cpw) && islower((unsigned char)*cpw)) 12892b15cb3dSCy Schubert *cpw = toupper((unsigned char)*cpw); 1290a151a66cSOllivier Robert 1291224ba2bdSOllivier Robert if (!strncmp(cc, "LAT", (size_t) 3)) { 1292c0b746e5SOllivier Robert f1 = f2 = f3 = 0; 1293a151a66cSOllivier Robert sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 1294c0b746e5SOllivier Robert sign = 1; 1295c0b746e5SOllivier Robert if (f1 < 0) { 1296c0b746e5SOllivier Robert f1 = -f1; 1297c0b746e5SOllivier Robert sign = -1; 1298c0b746e5SOllivier Robert } 1299c0b746e5SOllivier Robert instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 1300c0b746e5SOllivier Robert lat_flg++; 1301224ba2bdSOllivier Robert } else if (!strncmp(cc, "LON", (size_t) 3)) { 1302c0b746e5SOllivier Robert f1 = f2 = f3 = 0; 1303a151a66cSOllivier Robert sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); 1304c0b746e5SOllivier Robert sign = 1; 1305c0b746e5SOllivier Robert if (f1 < 0) { 1306c0b746e5SOllivier Robert f1 = -f1; 1307c0b746e5SOllivier Robert sign = -1; 1308c0b746e5SOllivier Robert } 1309c0b746e5SOllivier Robert instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ 1310c0b746e5SOllivier Robert long_flg++; 1311224ba2bdSOllivier Robert } else if (!strncmp(cc, "HT", (size_t) 2)) { 1312c0b746e5SOllivier Robert f1 = 0; 1313c0b746e5SOllivier Robert units[0] = '\0'; 1314a151a66cSOllivier Robert sscanf(ca, "%lf %1s", &f1, units); 1315c0b746e5SOllivier Robert if (units[0] == 'F') 1316c0b746e5SOllivier Robert f1 = 0.3048 * f1; 1317c0b746e5SOllivier Robert instance->ss_ht = 100 * f1; /* cm */ 1318c0b746e5SOllivier Robert ht_flg++; 1319224ba2bdSOllivier Robert } else if (!strncmp(cc, "DELAY", (size_t) 5)) { 1320c0b746e5SOllivier Robert f1 = 0; 1321c0b746e5SOllivier Robert units[0] = '\0'; 1322a151a66cSOllivier Robert sscanf(ca, "%lf %1s", &f1, units); 1323c0b746e5SOllivier Robert if (units[0] == 'N') 1324c0b746e5SOllivier Robert ; 1325c0b746e5SOllivier Robert else if (units[0] == 'U') 1326c0b746e5SOllivier Robert f1 = 1000 * f1; 1327c0b746e5SOllivier Robert else if (units[0] == 'M') 1328c0b746e5SOllivier Robert f1 = 1000000 * f1; 1329c0b746e5SOllivier Robert else 1330c0b746e5SOllivier Robert f1 = 1000000000 * f1; 1331c0b746e5SOllivier Robert if (f1 < 0 || f1 > 1.e9) 1332c0b746e5SOllivier Robert f1 = 0; 13332b15cb3dSCy Schubert if (f1 < 0 || f1 > 999999) 13342b15cb3dSCy Schubert oncore_log_f(instance, LOG_WARNING, 13352b15cb3dSCy Schubert "PPS Cable delay of %fns out of Range, ignored", 13362b15cb3dSCy Schubert f1); 13372b15cb3dSCy Schubert else 1338c0b746e5SOllivier Robert instance->delay = f1; /* delay in ns */ 1339224ba2bdSOllivier Robert } else if (!strncmp(cc, "OFFSET", (size_t) 6)) { 1340c0b746e5SOllivier Robert f1 = 0; 1341c0b746e5SOllivier Robert units[0] = '\0'; 1342a151a66cSOllivier Robert sscanf(ca, "%lf %1s", &f1, units); 1343c0b746e5SOllivier Robert if (units[0] == 'N') 1344c0b746e5SOllivier Robert ; 1345c0b746e5SOllivier Robert else if (units[0] == 'U') 1346c0b746e5SOllivier Robert f1 = 1000 * f1; 1347c0b746e5SOllivier Robert else if (units[0] == 'M') 1348c0b746e5SOllivier Robert f1 = 1000000 * f1; 1349c0b746e5SOllivier Robert else 1350c0b746e5SOllivier Robert f1 = 1000000000 * f1; 1351c0b746e5SOllivier Robert if (f1 < 0 || f1 > 1.e9) 1352c0b746e5SOllivier Robert f1 = 0; 13532b15cb3dSCy Schubert if (f1 < 0 || f1 > 999999999.) 13542b15cb3dSCy Schubert oncore_log_f(instance, LOG_WARNING, 13552b15cb3dSCy Schubert "PPS Offset of %fns out of Range, ignored", 13562b15cb3dSCy Schubert f1); 13572b15cb3dSCy Schubert else 1358c0b746e5SOllivier Robert instance->offset = f1; /* offset in ns */ 1359224ba2bdSOllivier Robert } else if (!strncmp(cc, "MODE", (size_t) 4)) { 1360a151a66cSOllivier Robert sscanf(ca, "%d", &mode); 1361c0b746e5SOllivier Robert if (mode < 0 || mode > 4) 1362c0b746e5SOllivier Robert mode = 4; 1363224ba2bdSOllivier Robert } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { 1364c0b746e5SOllivier Robert instance->assert = 1; 1365224ba2bdSOllivier Robert } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { 1366c0b746e5SOllivier Robert instance->assert = 0; 13679c2daa00SOllivier Robert } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) { 13689c2daa00SOllivier Robert instance->hardpps = 1; 1369224ba2bdSOllivier Robert } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { 1370224ba2bdSOllivier Robert instance->shmem_Posn = 2; 1371224ba2bdSOllivier Robert } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { 1372224ba2bdSOllivier Robert instance->shmem_Posn = 3; 1373224ba2bdSOllivier Robert } else if (!strncmp(cc, "CHAN", (size_t) 4)) { 1374224ba2bdSOllivier Robert sscanf(ca, "%d", &i); 1375224ba2bdSOllivier Robert if ((i == 6) || (i == 8) || (i == 12)) 13769c2daa00SOllivier Robert instance->chan_in = i; 1377224ba2bdSOllivier Robert } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { 13789c2daa00SOllivier Robert instance->traim_in = 1; /* so TRAIM alone is YES */ 1379224ba2bdSOllivier Robert if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ 13809c2daa00SOllivier Robert instance->traim_in = 0; 13819c2daa00SOllivier Robert } else if (!strncmp(cc, "MASK", (size_t) 4)) { 13829c2daa00SOllivier Robert sscanf(ca, "%d", &mask); 13839c2daa00SOllivier Robert if (mask > -1 && mask < 90) 13849c2daa00SOllivier Robert instance->Ag = mask; /* Satellite mask angle */ 13852b15cb3dSCy Schubert } else if (!strncmp(cc,"PPSCONTROL",10)) { /* pps control M12 only */ 13862b15cb3dSCy Schubert if (!strcmp(ca,"ON") || !strcmp(ca, "CONTINUOUS")) { 13872b15cb3dSCy Schubert instance->pps_control = 1; /* PPS always on */ 13882b15cb3dSCy Schubert } else if (!strcmp(ca,"SATELLITE")) { 13892b15cb3dSCy Schubert instance->pps_control = 2; /* PPS on when satellite is available */ 13902b15cb3dSCy Schubert } else if (!strcmp(ca,"TRAIM")) { 13912b15cb3dSCy Schubert instance->pps_control = 3; /* PPS on when TRAIM status is OK */ 13922b15cb3dSCy Schubert } else { 13932b15cb3dSCy Schubert oncore_log_f(instance, LOG_WARNING, 13942b15cb3dSCy Schubert "Unknown value \"%s\" for PPSCONTROL, ignored", 13952b15cb3dSCy Schubert cc); 13962b15cb3dSCy Schubert } 1397c0b746e5SOllivier Robert } 1398c0b746e5SOllivier Robert } 1399c0b746e5SOllivier Robert fclose(fd); 1400c0b746e5SOllivier Robert 1401c0b746e5SOllivier Robert /* 1402c0b746e5SOllivier Robert * OK, have read all of data file, and extracted the good stuff. 1403c0b746e5SOllivier Robert * If lat/long/ht specified they ALL must be specified for mode = (1,3). 1404c0b746e5SOllivier Robert */ 1405c0b746e5SOllivier Robert 1406c0b746e5SOllivier Robert instance->posn_set = 1; 14079c2daa00SOllivier Robert if (!( lat_flg && long_flg && ht_flg )) { 14082b15cb3dSCy Schubert oncore_log_f(instance, LOG_WARNING, 14092b15cb3dSCy Schubert "ONCORE: incomplete data on %s", device); 1410c0b746e5SOllivier Robert instance->posn_set = 0; 1411224ba2bdSOllivier Robert if (mode == 1 || mode == 3) { 14122b15cb3dSCy Schubert oncore_log_f(instance, LOG_WARNING, 14132b15cb3dSCy Schubert "Input Mode = %d, but no/incomplete position, mode set to %d", 14142b15cb3dSCy Schubert mode, mode+1); 1415224ba2bdSOllivier Robert mode++; 1416c0b746e5SOllivier Robert } 1417c0b746e5SOllivier Robert } 1418224ba2bdSOllivier Robert instance->init_type = mode; 1419224ba2bdSOllivier Robert 14202b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Input mode = %d", mode); 1421224ba2bdSOllivier Robert } 1422224ba2bdSOllivier Robert 1423224ba2bdSOllivier Robert 1424224ba2bdSOllivier Robert 1425c0b746e5SOllivier Robert /* 14269c2daa00SOllivier Robert * move data from NTP to buffer (toss the extra in the unlikely case it won't fit) 1427c0b746e5SOllivier Robert */ 1428224ba2bdSOllivier Robert 1429c0b746e5SOllivier Robert static void 1430c0b746e5SOllivier Robert oncore_receive( 1431c0b746e5SOllivier Robert struct recvbuf *rbufp 1432c0b746e5SOllivier Robert ) 1433c0b746e5SOllivier Robert { 1434224ba2bdSOllivier Robert size_t i; 1435c0b746e5SOllivier Robert u_char *p; 1436c0b746e5SOllivier Robert struct peer *peer; 1437c0b746e5SOllivier Robert struct instance *instance; 1438c0b746e5SOllivier Robert 14392b15cb3dSCy Schubert peer = rbufp->recv_peer; 14402b15cb3dSCy Schubert instance = peer->procptr->unitptr; 1441c0b746e5SOllivier Robert p = (u_char *) &rbufp->recv_space; 1442c0b746e5SOllivier Robert 14432b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_RECEIVE 1444c0b746e5SOllivier Robert if (debug > 4) { 1445c0b746e5SOllivier Robert int i; 14462b15cb3dSCy Schubert char Msg[120], Msg2[10]; 14472b15cb3dSCy Schubert 14482b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 14492b15cb3dSCy Schubert ">>> %d bytes available", 14502b15cb3dSCy Schubert rbufp->recv_length); 14512b15cb3dSCy Schubert strlcpy(Msg, ">>>", sizeof(Msg)); 14522b15cb3dSCy Schubert for (i = 0; i < rbufp->recv_length; i++) { 14532b15cb3dSCy Schubert snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]); 14542b15cb3dSCy Schubert strlcat(Msg, Msg2, sizeof(Msg)); 14552b15cb3dSCy Schubert } 14562b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, Msg); 14572b15cb3dSCy Schubert 14582b15cb3dSCy Schubert strlcpy(Msg, ">>>", sizeof(Msg)); 14592b15cb3dSCy Schubert for (i = 0; i < rbufp->recv_length; i++) { 14602b15cb3dSCy Schubert snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]); 14612b15cb3dSCy Schubert strlcat(Msg, Msg2, sizeof(Msg)); 14622b15cb3dSCy Schubert } 14632b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, Msg); 1464c0b746e5SOllivier Robert } 1465c0b746e5SOllivier Robert #endif 1466c0b746e5SOllivier Robert 1467c0b746e5SOllivier Robert i = rbufp->recv_length; 1468f0574f5cSXin LI if ((size_t)rcvptr + i >= sizeof(rcvbuf)) 1469c0b746e5SOllivier Robert i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ 1470c0b746e5SOllivier Robert memcpy(rcvbuf+rcvptr, p, i); 1471c0b746e5SOllivier Robert rcvptr += i; 1472c0b746e5SOllivier Robert oncore_consume(instance); 1473c0b746e5SOllivier Robert } 1474c0b746e5SOllivier Robert 1475c0b746e5SOllivier Robert 1476c0b746e5SOllivier Robert 1477c0b746e5SOllivier Robert /* 1478c0b746e5SOllivier Robert * Deal with any complete messages 1479c0b746e5SOllivier Robert */ 1480224ba2bdSOllivier Robert 1481c0b746e5SOllivier Robert static void 1482c0b746e5SOllivier Robert oncore_consume( 1483c0b746e5SOllivier Robert struct instance *instance 1484c0b746e5SOllivier Robert ) 1485c0b746e5SOllivier Robert { 14862b15cb3dSCy Schubert unsigned i, m, l; 1487c0b746e5SOllivier Robert 1488c0b746e5SOllivier Robert while (rcvptr >= 7) { 1489c0b746e5SOllivier Robert if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { 1490c0b746e5SOllivier Robert /* We're not in sync, lets try to get there */ 1491c0b746e5SOllivier Robert for (i=1; i < rcvptr-1; i++) 1492c0b746e5SOllivier Robert if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') 1493c0b746e5SOllivier Robert break; 14942b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME 1495c0b746e5SOllivier Robert if (debug > 4) 14962b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 14972b15cb3dSCy Schubert ">>> skipping %d chars", 14982b15cb3dSCy Schubert i); 1499ea906c41SOllivier Robert #endif 1500c0b746e5SOllivier Robert if (i != rcvptr) 1501224ba2bdSOllivier Robert memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i)); 1502c0b746e5SOllivier Robert rcvptr -= i; 1503224ba2bdSOllivier Robert continue; 1504c0b746e5SOllivier Robert } 1505c0b746e5SOllivier Robert 1506c0b746e5SOllivier Robert /* Ok, we have a header now */ 1507c0b746e5SOllivier Robert l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; 1508c0b746e5SOllivier Robert for(m=0; m<l; m++) 1509224ba2bdSOllivier Robert if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2)) 1510c0b746e5SOllivier Robert break; 1511224ba2bdSOllivier Robert if (m == l) { 15122b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME 1513224ba2bdSOllivier Robert if (debug > 4) 15142b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 15152b15cb3dSCy Schubert ">>> Unknown MSG, skipping 4 (%c%c)", 15162b15cb3dSCy Schubert rcvbuf[2], rcvbuf[3]); 1517ea906c41SOllivier Robert #endif 1518224ba2bdSOllivier Robert memcpy(rcvbuf, rcvbuf+4, (size_t) 4); 1519224ba2bdSOllivier Robert rcvptr -= 4; 1520224ba2bdSOllivier Robert continue; 1521224ba2bdSOllivier Robert } 1522224ba2bdSOllivier Robert 1523c0b746e5SOllivier Robert l = oncore_messages[m].len; 15242b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME 1525c0b746e5SOllivier Robert if (debug > 3) 15262b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 15272b15cb3dSCy Schubert "GOT: %c%c %d of %d entry %d", 15282b15cb3dSCy Schubert instance->unit, rcvbuf[2], 15292b15cb3dSCy Schubert rcvbuf[3], rcvptr, l, m); 1530c0b746e5SOllivier Robert #endif 1531c0b746e5SOllivier Robert /* Got the entire message ? */ 1532c0b746e5SOllivier Robert 1533c0b746e5SOllivier Robert if (rcvptr < l) 1534c0b746e5SOllivier Robert return; 1535c0b746e5SOllivier Robert 1536224ba2bdSOllivier Robert /* are we at the end of message? should be <Cksum><CR><LF> */ 1537c0b746e5SOllivier Robert 1538224ba2bdSOllivier Robert if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') { 15392b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME 1540224ba2bdSOllivier Robert if (debug) 15412b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message"); 1542ea906c41SOllivier Robert #endif 1543224ba2bdSOllivier Robert } else { /* check the CheckSum */ 15449c2daa00SOllivier Robert if (oncore_checksum_ok(rcvbuf, l)) { 1545224ba2bdSOllivier Robert if (instance->shmem != NULL) { 1546224ba2bdSOllivier Robert instance->shmem[oncore_messages[m].shmem + 2]++; 1547224ba2bdSOllivier Robert memcpy(instance->shmem + oncore_messages[m].shmem + 3, 1548224ba2bdSOllivier Robert rcvbuf, (size_t) l); 1549224ba2bdSOllivier Robert } 1550224ba2bdSOllivier Robert oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m); 1551c0b746e5SOllivier Robert if (oncore_messages[m].handler) 1552224ba2bdSOllivier Robert oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3)); 1553ea906c41SOllivier Robert } 15542b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CONSUME 1555ea906c41SOllivier Robert else if (debug) { 15562b15cb3dSCy Schubert char Msg[120], Msg2[10]; 15572b15cb3dSCy Schubert 15582b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "Checksum mismatch!"); 15592b15cb3dSCy Schubert snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]); 15602b15cb3dSCy Schubert for (i = 4; i < l; i++) { 15612b15cb3dSCy Schubert snprintf(Msg2, sizeof(Msg2), 15622b15cb3dSCy Schubert "%03o ", rcvbuf[i]); 15632b15cb3dSCy Schubert strlcat(Msg, Msg2, sizeof(Msg)); 15642b15cb3dSCy Schubert } 15652b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, Msg); 1566c0b746e5SOllivier Robert } 1567ea906c41SOllivier Robert #endif 1568224ba2bdSOllivier Robert } 1569c0b746e5SOllivier Robert 1570c0b746e5SOllivier Robert if (l != rcvptr) 1571224ba2bdSOllivier Robert memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); 1572c0b746e5SOllivier Robert rcvptr -= l; 1573c0b746e5SOllivier Robert } 1574c0b746e5SOllivier Robert } 1575c0b746e5SOllivier Robert 1576c0b746e5SOllivier Robert 1577c0b746e5SOllivier Robert 1578224ba2bdSOllivier Robert static void 1579224ba2bdSOllivier Robert oncore_get_timestamp( 1580224ba2bdSOllivier Robert struct instance *instance, 1581224ba2bdSOllivier Robert long dt1, /* tick offset THIS time step */ 1582224ba2bdSOllivier Robert long dt2 /* tick offset NEXT time step */ 1583224ba2bdSOllivier Robert ) 1584224ba2bdSOllivier Robert { 1585224ba2bdSOllivier Robert int Rsm; 1586ea906c41SOllivier Robert u_long j; 1587c0b746e5SOllivier Robert l_fp ts, ts_tmp; 1588c0b746e5SOllivier Robert double dmy; 1589224ba2bdSOllivier Robert #ifdef HAVE_STRUCT_TIMESPEC 1590c0b746e5SOllivier Robert struct timespec *tsp = 0; 1591c0b746e5SOllivier Robert #else 1592c0b746e5SOllivier Robert struct timeval *tsp = 0; 1593c0b746e5SOllivier Robert #endif 1594224ba2bdSOllivier Robert int current_mode; 1595224ba2bdSOllivier Robert pps_params_t current_params; 1596c0b746e5SOllivier Robert struct timespec timeout; 15972b15cb3dSCy Schubert struct peer *peer; 1598c0b746e5SOllivier Robert pps_info_t pps_i; 15992b15cb3dSCy Schubert char Msg[160]; 16002b15cb3dSCy Schubert 16012b15cb3dSCy Schubert peer = instance->peer; 1602c0b746e5SOllivier Robert 16039c2daa00SOllivier Robert #if 1 16049c2daa00SOllivier Robert /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru. 16059c2daa00SOllivier Robert * If we have Finished the SiteSurvey, then we fall thru for the 14/15 16069c2daa00SOllivier Robert * times we get here in 0D mode (the 1/15 is in 3D for SHMEM). 16079c2daa00SOllivier Robert * This gives good time, which gets better when the SS is done. 16089c2daa00SOllivier Robert */ 16099c2daa00SOllivier Robert 16102b15cb3dSCy Schubert if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) { 16119c2daa00SOllivier Robert #else 16129c2daa00SOllivier Robert /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */ 16139c2daa00SOllivier Robert 16142b15cb3dSCy Schubert if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) { 16159c2daa00SOllivier Robert #endif 16162b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1617c0b746e5SOllivier Robert return; 16182b15cb3dSCy Schubert } 1619c0b746e5SOllivier Robert 1620c0b746e5SOllivier Robert /* Don't do anything without an almanac to define the GPS->UTC delta */ 1621c0b746e5SOllivier Robert 16222b15cb3dSCy Schubert if (instance->rsm.bad_almanac) { 16232b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1624c0b746e5SOllivier Robert return; 16252b15cb3dSCy Schubert } 1626c0b746e5SOllivier Robert 1627ea906c41SOllivier Robert /* Once the Almanac is valid, the M12+T does not produce valid UTC 1628ea906c41SOllivier Robert * immediately. 1629ea906c41SOllivier Robert * Wait for UTC offset decode valid, then wait one message more 1630ea906c41SOllivier Robert * so we are not off by 13 seconds after reset. 1631ea906c41SOllivier Robert */ 1632ea906c41SOllivier Robert 1633ea906c41SOllivier Robert if (instance->count5) { 1634ea906c41SOllivier Robert instance->count5--; 16352b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1636ea906c41SOllivier Robert return; 1637ea906c41SOllivier Robert } 1638ea906c41SOllivier Robert 1639c0b746e5SOllivier Robert j = instance->ev_serial; 1640c0b746e5SOllivier Robert timeout.tv_sec = 0; 1641c0b746e5SOllivier Robert timeout.tv_nsec = 0; 1642c0b746e5SOllivier Robert if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, 1643c0b746e5SOllivier Robert &timeout) < 0) { 16442b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, 16452b15cb3dSCy Schubert "time_pps_fetch failed %m"); 16462b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1647c0b746e5SOllivier Robert return; 1648c0b746e5SOllivier Robert } 1649c0b746e5SOllivier Robert 1650c0b746e5SOllivier Robert if (instance->assert) { 1651c0b746e5SOllivier Robert tsp = &pps_i.assert_timestamp; 1652c0b746e5SOllivier Robert 16532b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_GET_TIMESTAMP 1654224ba2bdSOllivier Robert if (debug > 2) { 16552b15cb3dSCy Schubert u_long i; 16562b15cb3dSCy Schubert 1657224ba2bdSOllivier Robert i = (u_long) pps_i.assert_sequence; 1658224ba2bdSOllivier Robert # ifdef HAVE_STRUCT_TIMESPEC 16592b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 16602b15cb3dSCy Schubert "serial/j (%lu, %lu) %ld.%09ld", i, 16612b15cb3dSCy Schubert j, (long)tsp->tv_sec, 16622b15cb3dSCy Schubert (long)tsp->tv_nsec); 1663224ba2bdSOllivier Robert # else 16642b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 16652b15cb3dSCy Schubert "serial/j (%lu, %lu) %ld.%06ld", i, 16662b15cb3dSCy Schubert j, (long)tsp->tv_sec, 16672b15cb3dSCy Schubert (long)tsp->tv_usec); 1668224ba2bdSOllivier Robert # endif 1669224ba2bdSOllivier Robert } 1670ea906c41SOllivier Robert #endif 1671c0b746e5SOllivier Robert 1672c0b746e5SOllivier Robert if (pps_i.assert_sequence == j) { 16732b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps"); 16742b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1675c0b746e5SOllivier Robert return; 1676c0b746e5SOllivier Robert } 16772b15cb3dSCy Schubert 1678c0b746e5SOllivier Robert instance->ev_serial = pps_i.assert_sequence; 1679c0b746e5SOllivier Robert } else { 1680c0b746e5SOllivier Robert tsp = &pps_i.clear_timestamp; 1681c0b746e5SOllivier Robert 16822b15cb3dSCy Schubert #if 0 1683224ba2bdSOllivier Robert if (debug > 2) { 16842b15cb3dSCy Schubert u_long i; 16852b15cb3dSCy Schubert 1686224ba2bdSOllivier Robert i = (u_long) pps_i.clear_sequence; 1687224ba2bdSOllivier Robert # ifdef HAVE_STRUCT_TIMESPEC 16882b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 16892b15cb3dSCy Schubert "serial/j (%lu, %lu) %ld.%09ld", i, 16902b15cb3dSCy Schubert j, (long)tsp->tv_sec, 16912b15cb3dSCy Schubert (long)tsp->tv_nsec); 1692224ba2bdSOllivier Robert # else 16932b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 16942b15cb3dSCy Schubert "serial/j (%lu, %lu) %ld.%06ld", i, 16952b15cb3dSCy Schubert j, (long)tsp->tv_sec, 16962b15cb3dSCy Schubert (long)tsp->tv_usec); 1697224ba2bdSOllivier Robert # endif 1698224ba2bdSOllivier Robert } 1699ea906c41SOllivier Robert #endif 1700c0b746e5SOllivier Robert 1701c0b746e5SOllivier Robert if (pps_i.clear_sequence == j) { 17022b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps"); 17032b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1704c0b746e5SOllivier Robert return; 1705c0b746e5SOllivier Robert } 1706c0b746e5SOllivier Robert instance->ev_serial = pps_i.clear_sequence; 1707c0b746e5SOllivier Robert } 1708c0b746e5SOllivier Robert 1709c0b746e5SOllivier Robert /* convert timespec -> ntp l_fp */ 1710c0b746e5SOllivier Robert 1711c0b746e5SOllivier Robert dmy = tsp->tv_nsec; 1712c0b746e5SOllivier Robert dmy /= 1e9; 1713c0b746e5SOllivier Robert ts.l_uf = dmy * 4294967296.0; 1714c0b746e5SOllivier Robert ts.l_ui = tsp->tv_sec; 1715ea906c41SOllivier Robert 1716c0b746e5SOllivier Robert #if 0 1717c0b746e5SOllivier Robert alternate code for previous 4 lines is 1718c0b746e5SOllivier Robert dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1719c0b746e5SOllivier Robert DTOLFP(dmy, &ts); 1720c0b746e5SOllivier Robert dmy = tsp->tv_sec; /* integer part */ 1721c0b746e5SOllivier Robert DTOLFP(dmy, &ts_tmp); 1722c0b746e5SOllivier Robert L_ADD(&ts, &ts_tmp); 1723c0b746e5SOllivier Robert or more simply 1724c0b746e5SOllivier Robert dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ 1725c0b746e5SOllivier Robert DTOLFP(dmy, &ts); 1726c0b746e5SOllivier Robert ts.l_ui = tsp->tv_sec; 1727c0b746e5SOllivier Robert #endif /* 0 */ 1728c0b746e5SOllivier Robert 1729c0b746e5SOllivier Robert /* now have timestamp in ts */ 1730224ba2bdSOllivier Robert /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ 1731ea906c41SOllivier Robert /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */ 1732ea906c41SOllivier Robert /* we just try to add them in and dont test for that here */ 1733c0b746e5SOllivier Robert 1734c0b746e5SOllivier Robert /* saw_tooth not really necessary if using TIMEVAL */ 1735c0b746e5SOllivier Robert /* since its only precise to us, but do it anyway. */ 1736c0b746e5SOllivier Robert 1737c0b746e5SOllivier Robert /* offset in ns, and is positive (late), we subtract */ 1738c0b746e5SOllivier Robert /* to put the PPS time transition back where it belongs */ 1739c0b746e5SOllivier Robert 1740224ba2bdSOllivier Robert /* must hand the offset for the NEXT sec off to the Kernel to do */ 1741224ba2bdSOllivier Robert /* the addition, so that the Kernel PLL sees the offset too */ 1742c0b746e5SOllivier Robert 1743224ba2bdSOllivier Robert if (instance->assert) 1744224ba2bdSOllivier Robert instance->pps_p.assert_offset.tv_nsec = -dt2; 1745224ba2bdSOllivier Robert else 1746224ba2bdSOllivier Robert instance->pps_p.clear_offset.tv_nsec = -dt2; 1747224ba2bdSOllivier Robert 1748224ba2bdSOllivier Robert /* The following code is necessary, and not just a time_pps_setparams, 1749224ba2bdSOllivier Robert * using the saved instance->pps_p, since some other process on the 1750224ba2bdSOllivier Robert * machine may have diddled with the mode bits (say adding something 1751224ba2bdSOllivier Robert * that it needs). We take what is there and ADD what we need. 1752224ba2bdSOllivier Robert * [[ The results from the time_pps_getcap is unlikely to change so 1753224ba2bdSOllivier Robert * we could probably just save it, but I choose to do the call ]] 1754224ba2bdSOllivier Robert * Unfortunately, there is only ONE set of mode bits in the kernel per 1755224ba2bdSOllivier Robert * interface, and not one set for each open handle. 1756224ba2bdSOllivier Robert * 1757224ba2bdSOllivier Robert * There is still a race condition here where we might mess up someone 1758224ba2bdSOllivier Robert * elses mode, but if he is being careful too, he should survive. 1759224ba2bdSOllivier Robert */ 1760224ba2bdSOllivier Robert 1761224ba2bdSOllivier Robert if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { 17622b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, 17632b15cb3dSCy Schubert "time_pps_getcap failed: %m"); 17642b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1765224ba2bdSOllivier Robert return; 1766c0b746e5SOllivier Robert } 1767c0b746e5SOllivier Robert 1768224ba2bdSOllivier Robert if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { 17692b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, 17702b15cb3dSCy Schubert "time_pps_getparams failed: %m"); 17712b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1772224ba2bdSOllivier Robert return; 1773224ba2bdSOllivier Robert } 1774224ba2bdSOllivier Robert 1775224ba2bdSOllivier Robert /* or current and mine */ 1776224ba2bdSOllivier Robert current_params.mode |= instance->pps_p.mode; 1777224ba2bdSOllivier Robert /* but only set whats legal */ 1778224ba2bdSOllivier Robert current_params.mode &= current_mode; 1779224ba2bdSOllivier Robert 1780224ba2bdSOllivier Robert current_params.assert_offset.tv_sec = 0; 1781224ba2bdSOllivier Robert current_params.assert_offset.tv_nsec = -dt2; 1782224ba2bdSOllivier Robert current_params.clear_offset.tv_sec = 0; 1783224ba2bdSOllivier Robert current_params.clear_offset.tv_nsec = -dt2; 1784224ba2bdSOllivier Robert 1785224ba2bdSOllivier Robert if (time_pps_setparams(instance->pps_h, ¤t_params)) 17862b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams"); 1787c0b746e5SOllivier Robert 1788c0b746e5SOllivier Robert /* have time from UNIX origin, convert to NTP origin. */ 1789c0b746e5SOllivier Robert 1790c0b746e5SOllivier Robert ts.l_ui += JAN_1970; 1791c0b746e5SOllivier Robert instance->pp->lastrec = ts; 17929c2daa00SOllivier Robert 17939c2daa00SOllivier Robert /* print out information about this timestamp (long line) */ 1794c0b746e5SOllivier Robert 1795c0b746e5SOllivier Robert ts_tmp = ts; 1796c0b746e5SOllivier Robert ts_tmp.l_ui = 0; /* zero integer part */ 1797c0b746e5SOllivier Robert LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ 1798c0b746e5SOllivier Robert j = 1.0e9*dmy; /* then to integer ns */ 1799224ba2bdSOllivier Robert 1800224ba2bdSOllivier Robert Rsm = 0; 1801224ba2bdSOllivier Robert if (instance->chan == 6) 18029c2daa00SOllivier Robert Rsm = instance->BEHa[64]; 1803224ba2bdSOllivier Robert else if (instance->chan == 8) 18049c2daa00SOllivier Robert Rsm = instance->BEHa[72]; 1805224ba2bdSOllivier Robert else if (instance->chan == 12) 18069c2daa00SOllivier Robert Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]); 1807224ba2bdSOllivier Robert 1808224ba2bdSOllivier Robert if (instance->chan == 6 || instance->chan == 8) { 1809ea906c41SOllivier Robert char f1[5], f2[5], f3[5], f4[5]; 1810ea906c41SOllivier Robert if (instance->traim) { 18112b15cb3dSCy Schubert snprintf(f1, sizeof(f1), "%d", 18122b15cb3dSCy Schubert instance->BEHn[21]); 18132b15cb3dSCy Schubert snprintf(f2, sizeof(f2), "%d", 18142b15cb3dSCy Schubert instance->BEHn[22]); 18152b15cb3dSCy Schubert snprintf(f3, sizeof(f3), "%2d", 18162b15cb3dSCy Schubert instance->BEHn[23] * 256 + 18172b15cb3dSCy Schubert instance->BEHn[24]); 18182b15cb3dSCy Schubert snprintf(f4, sizeof(f4), "%3d", 18192b15cb3dSCy Schubert (s_char)instance->BEHn[25]); 1820ea906c41SOllivier Robert } else { 18212b15cb3dSCy Schubert strlcpy(f1, "x", sizeof(f1)); 18222b15cb3dSCy Schubert strlcpy(f2, "x", sizeof(f2)); 18232b15cb3dSCy Schubert strlcpy(f3, "xx", sizeof(f3)); 18242b15cb3dSCy Schubert strlcpy(f4, "xxx", sizeof(f4)); 1825ea906c41SOllivier Robert } 18262b15cb3dSCy Schubert snprintf(Msg, sizeof(Msg), /* MAX length 128, currently at 127 */ 1827ea906c41SOllivier Robert "%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", 1828c0b746e5SOllivier Robert ts.l_ui, j, 1829c0b746e5SOllivier Robert instance->pp->year, instance->pp->day, 1830c0b746e5SOllivier Robert instance->pp->hour, instance->pp->minute, instance->pp->second, 1831c0b746e5SOllivier Robert (long) tsp->tv_sec % 60, 18329c2daa00SOllivier Robert Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]), 1833224ba2bdSOllivier Robert /*rsat dop */ 1834ea906c41SOllivier Robert instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2, 1835ea906c41SOllivier Robert /* nsat visible, nsat tracked, traim,traim,traim */ 1836ea906c41SOllivier Robert f3, f4, 1837c0b746e5SOllivier Robert /* sigma neg-sawtooth */ 18389c2daa00SOllivier Robert /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53], 18399c2daa00SOllivier Robert instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69] 1840224ba2bdSOllivier Robert ); /* will be 0 for 6 chan */ 1841224ba2bdSOllivier Robert } else if (instance->chan == 12) { 1842ea906c41SOllivier Robert char f1[5], f2[5], f3[5], f4[5]; 1843ea906c41SOllivier Robert if (instance->traim) { 18442b15cb3dSCy Schubert snprintf(f1, sizeof(f1), "%d", 18452b15cb3dSCy Schubert instance->BEHn[6]); 18462b15cb3dSCy Schubert snprintf(f2, sizeof(f2), "%d", 18472b15cb3dSCy Schubert instance->BEHn[7]); 18482b15cb3dSCy Schubert snprintf(f3, sizeof(f3), "%d", 18492b15cb3dSCy Schubert instance->BEHn[12] * 256 + 18502b15cb3dSCy Schubert instance->BEHn[13]); 18512b15cb3dSCy Schubert snprintf(f4, sizeof(f4), "%3d", 18522b15cb3dSCy Schubert (s_char)instance->BEHn[14]); 1853ea906c41SOllivier Robert } else { 18542b15cb3dSCy Schubert strlcpy(f1, "x", sizeof(f1)); 18552b15cb3dSCy Schubert strlcpy(f2, "x", sizeof(f2)); 18562b15cb3dSCy Schubert strlcpy(f3, "xx", sizeof(f3)); 18572b15cb3dSCy Schubert strlcpy(f4, "xxx", sizeof(f4)); 1858ea906c41SOllivier Robert } 18592b15cb3dSCy Schubert snprintf(Msg, sizeof(Msg), 1860ea906c41SOllivier Robert "%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", 1861224ba2bdSOllivier Robert ts.l_ui, j, 1862224ba2bdSOllivier Robert instance->pp->year, instance->pp->day, 1863224ba2bdSOllivier Robert instance->pp->hour, instance->pp->minute, instance->pp->second, 1864224ba2bdSOllivier Robert (long) tsp->tv_sec % 60, 18659c2daa00SOllivier Robert Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]), 1866224ba2bdSOllivier Robert /*rsat dop */ 1867ea906c41SOllivier Robert instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2, 1868ea906c41SOllivier Robert /* nsat visible, nsat tracked traim,traim,traim */ 1869ea906c41SOllivier Robert f3, f4, 18709c2daa00SOllivier Robert /* sigma neg-sawtooth */ 18719c2daa00SOllivier Robert /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76], 18729c2daa00SOllivier Robert instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100], 18739c2daa00SOllivier Robert instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124] 1874c0b746e5SOllivier Robert ); 1875224ba2bdSOllivier Robert } 1876c0b746e5SOllivier Robert 1877ea906c41SOllivier Robert /* and some things I dont understand (magic ntp things) */ 18789c2daa00SOllivier Robert 18792d4e511cSCy Schubert #if 1 18802d4e511cSCy Schubert oncore_feed_clockproc(instance); 18812d4e511cSCy Schubert #else 1882c0b746e5SOllivier Robert if (!refclock_process(instance->pp)) { 18832d4e511cSCy Schubert refclock_report(peer, CEVNT_BADTIME); 18842b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 1885c0b746e5SOllivier Robert return; 1886c0b746e5SOllivier Robert } 18872d4e511cSCy Schubert #endif 1888c0b746e5SOllivier Robert 18892b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, Msg); /* this is long message above */ 1890c0b746e5SOllivier Robert instance->pollcnt = 2; 1891c0b746e5SOllivier Robert 1892c0b746e5SOllivier Robert if (instance->polled) { 1893c0b746e5SOllivier Robert instance->polled = 0; 1894ea906c41SOllivier Robert /* instance->pp->dispersion = instance->pp->skew = 0; */ 18959c2daa00SOllivier Robert instance->pp->lastref = instance->pp->lastrec; 1896c0b746e5SOllivier Robert refclock_receive(instance->peer); 1897c0b746e5SOllivier Robert } 18982b15cb3dSCy Schubert peer->flags |= FLAG_PPS; 1899c0b746e5SOllivier Robert } 1900c0b746e5SOllivier Robert 1901c0b746e5SOllivier Robert 19029c2daa00SOllivier Robert /*************** oncore_msg_XX routines start here *******************/ 19039c2daa00SOllivier Robert 19049c2daa00SOllivier Robert 19059c2daa00SOllivier Robert /* 19069c2daa00SOllivier Robert * print Oncore response message. 19079c2daa00SOllivier Robert */ 19089c2daa00SOllivier Robert 19099c2daa00SOllivier Robert static void 19109c2daa00SOllivier Robert oncore_msg_any( 19119c2daa00SOllivier Robert struct instance *instance, 19129c2daa00SOllivier Robert u_char *buf, 19139c2daa00SOllivier Robert size_t len, 19149c2daa00SOllivier Robert int idx 19159c2daa00SOllivier Robert ) 19169c2daa00SOllivier Robert { 19172b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_MSG_ANY 19189c2daa00SOllivier Robert int i; 19199c2daa00SOllivier Robert const char *fmt = oncore_messages[idx].fmt; 19209c2daa00SOllivier Robert const char *p; 19212b15cb3dSCy Schubert char *q; 19222b15cb3dSCy Schubert char *qlim; 19239c2daa00SOllivier Robert #ifdef HAVE_GETCLOCK 19249c2daa00SOllivier Robert struct timespec ts; 19259c2daa00SOllivier Robert #endif 19269c2daa00SOllivier Robert struct timeval tv; 19272b15cb3dSCy Schubert char Msg[120], Msg2[10]; 19289c2daa00SOllivier Robert 19299c2daa00SOllivier Robert if (debug > 3) { 19309c2daa00SOllivier Robert # ifdef HAVE_GETCLOCK 19319c2daa00SOllivier Robert (void) getclock(TIMEOFDAY, &ts); 19329c2daa00SOllivier Robert tv.tv_sec = ts.tv_sec; 19339c2daa00SOllivier Robert tv.tv_usec = ts.tv_nsec / 1000; 19349c2daa00SOllivier Robert # else 19359c2daa00SOllivier Robert GETTIMEOFDAY(&tv, 0); 19369c2daa00SOllivier Robert # endif 19372b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, "%ld.%06ld", 19382b15cb3dSCy Schubert (long)tv.tv_sec, (long)tv.tv_usec); 19399c2daa00SOllivier Robert 19409c2daa00SOllivier Robert if (!*fmt) { 19412b15cb3dSCy Schubert snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2], 19422b15cb3dSCy Schubert buf[3]); 19432b15cb3dSCy Schubert for(i = 2; i < len && i < 2400 ; i++) { 19442b15cb3dSCy Schubert snprintf(Msg2, sizeof(Msg2), "%02x", 19452b15cb3dSCy Schubert buf[i]); 19462b15cb3dSCy Schubert strlcat(Msg, Msg2, sizeof(Msg)); 19472b15cb3dSCy Schubert } 19482b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, Msg); 19499c2daa00SOllivier Robert return; 19509c2daa00SOllivier Robert } else { 19512b15cb3dSCy Schubert strlcpy(Msg, "##", sizeof(Msg)); 19522b15cb3dSCy Schubert qlim = Msg + sizeof(Msg) - 3; 19532b15cb3dSCy Schubert for (p = fmt, q = Msg + 2; q < qlim && *p; ) { 19542b15cb3dSCy Schubert *q++ = *p++; 19552b15cb3dSCy Schubert *q++ = '_'; 19569c2daa00SOllivier Robert } 19572b15cb3dSCy Schubert *q = '\0'; 19582b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, Msg); 19592b15cb3dSCy Schubert snprintf(Msg, sizeof(Msg), "%c%c", buf[2], 19602b15cb3dSCy Schubert buf[3]); 19619c2daa00SOllivier Robert i = 4; 19629c2daa00SOllivier Robert for (p = fmt; *p; p++) { 19632b15cb3dSCy Schubert snprintf(Msg2, "%02x", buf[i++]); 19642b15cb3dSCy Schubert strlcat(Msg, Msg2, sizeof(Msg)); 19659c2daa00SOllivier Robert } 19662b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, Msg); 19679c2daa00SOllivier Robert } 19689c2daa00SOllivier Robert } 1969ea906c41SOllivier Robert #endif 19709c2daa00SOllivier Robert } 19719c2daa00SOllivier Robert 19729c2daa00SOllivier Robert 19739c2daa00SOllivier Robert 19749c2daa00SOllivier Robert /* Latitude, Longitude, Height */ 19759c2daa00SOllivier Robert 19769c2daa00SOllivier Robert static void 19779c2daa00SOllivier Robert oncore_msg_Adef( 19789c2daa00SOllivier Robert struct instance *instance, 19799c2daa00SOllivier Robert u_char *buf, 19809c2daa00SOllivier Robert size_t len 19819c2daa00SOllivier Robert ) 19829c2daa00SOllivier Robert { 19839c2daa00SOllivier Robert } 19849c2daa00SOllivier Robert 19859c2daa00SOllivier Robert 19869c2daa00SOllivier Robert 19879c2daa00SOllivier Robert /* Mask Angle */ 19889c2daa00SOllivier Robert 19899c2daa00SOllivier Robert static void 19909c2daa00SOllivier Robert oncore_msg_Ag( 19919c2daa00SOllivier Robert struct instance *instance, 19929c2daa00SOllivier Robert u_char *buf, 19939c2daa00SOllivier Robert size_t len 19949c2daa00SOllivier Robert ) 19952b15cb3dSCy Schubert { 19962b15cb3dSCy Schubert const char *cp; 19979c2daa00SOllivier Robert 19989c2daa00SOllivier Robert cp = "set to"; 19999c2daa00SOllivier Robert if (instance->o_state == ONCORE_RUN) 20009c2daa00SOllivier Robert cp = "is"; 20019c2daa00SOllivier Robert 20029c2daa00SOllivier Robert instance->Ag = buf[4]; 20032b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 20042b15cb3dSCy Schubert "Satellite mask angle %s %d degrees", cp, 20052b15cb3dSCy Schubert (int)instance->Ag); 20069c2daa00SOllivier Robert } 20079c2daa00SOllivier Robert 20089c2daa00SOllivier Robert 20099c2daa00SOllivier Robert 20109c2daa00SOllivier Robert /* 20119c2daa00SOllivier Robert * get Position hold position 20129c2daa00SOllivier Robert */ 20139c2daa00SOllivier Robert 20149c2daa00SOllivier Robert static void 20159c2daa00SOllivier Robert oncore_msg_As( 20169c2daa00SOllivier Robert struct instance *instance, 20179c2daa00SOllivier Robert u_char *buf, 20189c2daa00SOllivier Robert size_t len 20199c2daa00SOllivier Robert ) 20209c2daa00SOllivier Robert { 20219c2daa00SOllivier Robert instance->ss_lat = buf_w32(&buf[4]); 20229c2daa00SOllivier Robert instance->ss_long = buf_w32(&buf[8]); 20239c2daa00SOllivier Robert instance->ss_ht = buf_w32(&buf[12]); 20249c2daa00SOllivier Robert 20259c2daa00SOllivier Robert /* Print out Position */ 20269c2daa00SOllivier Robert oncore_print_posn(instance); 20279c2daa00SOllivier Robert } 20289c2daa00SOllivier Robert 20299c2daa00SOllivier Robert 2030c0b746e5SOllivier Robert 2031c0b746e5SOllivier Robert /* 2032c0b746e5SOllivier Robert * Try to use Oncore UT+ Auto Survey Feature 2033c0b746e5SOllivier Robert * If its not there (VP), set flag to do it ourselves. 2034c0b746e5SOllivier Robert */ 2035224ba2bdSOllivier Robert 2036c0b746e5SOllivier Robert static void 2037c0b746e5SOllivier Robert oncore_msg_At( 2038c0b746e5SOllivier Robert struct instance *instance, 2039c0b746e5SOllivier Robert u_char *buf, 2040224ba2bdSOllivier Robert size_t len 2041c0b746e5SOllivier Robert ) 2042c0b746e5SOllivier Robert { 2043224ba2bdSOllivier Robert instance->saw_At = 1; 2044224ba2bdSOllivier Robert if (instance->site_survey == ONCORE_SS_TESTING) { 2045a151a66cSOllivier Robert if (buf[4] == 2) { 20462b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, 2047a151a66cSOllivier Robert "Initiating hardware 3D site survey"); 20489c2daa00SOllivier Robert 20492b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW"); 2050c0b746e5SOllivier Robert instance->site_survey = ONCORE_SS_HW; 2051224ba2bdSOllivier Robert } 2052c0b746e5SOllivier Robert } 2053c0b746e5SOllivier Robert } 2054c0b746e5SOllivier Robert 2055c0b746e5SOllivier Robert 2056c0b746e5SOllivier Robert 20579c2daa00SOllivier Robert /* 20589c2daa00SOllivier Robert * get PPS Offset 20599c2daa00SOllivier Robert * Nb. @@Ay is not supported for early UT (no plus) model 20609c2daa00SOllivier Robert */ 20619c2daa00SOllivier Robert 20629c2daa00SOllivier Robert static void 20639c2daa00SOllivier Robert oncore_msg_Ay( 20649c2daa00SOllivier Robert struct instance *instance, 20659c2daa00SOllivier Robert u_char *buf, 20669c2daa00SOllivier Robert size_t len 20679c2daa00SOllivier Robert ) 20689c2daa00SOllivier Robert { 20699c2daa00SOllivier Robert if (instance->saw_Ay) 20709c2daa00SOllivier Robert return; 20719c2daa00SOllivier Robert 20729c2daa00SOllivier Robert instance->saw_Ay = 1; 20739c2daa00SOllivier Robert 20749c2daa00SOllivier Robert instance->offset = buf_w32(&buf[4]); 20759c2daa00SOllivier Robert 20762b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "PPS Offset is set to %ld ns", 20772b15cb3dSCy Schubert instance->offset); 20789c2daa00SOllivier Robert } 20799c2daa00SOllivier Robert 20809c2daa00SOllivier Robert 20819c2daa00SOllivier Robert 20829c2daa00SOllivier Robert /* 20839c2daa00SOllivier Robert * get Cable Delay 20849c2daa00SOllivier Robert */ 20859c2daa00SOllivier Robert 20869c2daa00SOllivier Robert static void 20879c2daa00SOllivier Robert oncore_msg_Az( 20889c2daa00SOllivier Robert struct instance *instance, 20899c2daa00SOllivier Robert u_char *buf, 20909c2daa00SOllivier Robert size_t len 20919c2daa00SOllivier Robert ) 20929c2daa00SOllivier Robert { 20939c2daa00SOllivier Robert if (instance->saw_Az) 20949c2daa00SOllivier Robert return; 20959c2daa00SOllivier Robert 20969c2daa00SOllivier Robert instance->saw_Az = 1; 20979c2daa00SOllivier Robert 20989c2daa00SOllivier Robert instance->delay = buf_w32(&buf[4]); 20999c2daa00SOllivier Robert 21002b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Cable delay is set to %ld ns", 21012b15cb3dSCy Schubert instance->delay); 21029c2daa00SOllivier Robert } 21039c2daa00SOllivier Robert 21049c2daa00SOllivier Robert 21059c2daa00SOllivier Robert 21069c2daa00SOllivier Robert /* Ba, Ea and Ha come here, these contain Position */ 21079c2daa00SOllivier Robert 21089c2daa00SOllivier Robert static void 21099c2daa00SOllivier Robert oncore_msg_BaEaHa( 21109c2daa00SOllivier Robert struct instance *instance, 21119c2daa00SOllivier Robert u_char *buf, 21129c2daa00SOllivier Robert size_t len 21139c2daa00SOllivier Robert ) 21149c2daa00SOllivier Robert { 21159c2daa00SOllivier Robert const char *cp; 21169c2daa00SOllivier Robert int mode; 21179c2daa00SOllivier Robert 21189c2daa00SOllivier Robert /* OK, we are close to the RUN state now. 21199c2daa00SOllivier Robert * But we have a few more items to initialize first. 21209c2daa00SOllivier Robert * 21219c2daa00SOllivier Robert * At the beginning of this routine there are several 'timers'. 21229c2daa00SOllivier Robert * We enter this routine 1/sec, and since the upper levels of NTP have usurped 21239c2daa00SOllivier Robert * the use of timers, we use the 1/sec entry to do things that 21249c2daa00SOllivier Robert * we would normally do with timers... 21259c2daa00SOllivier Robert */ 21269c2daa00SOllivier Robert 21279c2daa00SOllivier Robert if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */ 21289c2daa00SOllivier Robert if (buf[2] == 'B') { /* 6chan */ 21299c2daa00SOllivier Robert if (instance->chan_ck < 6) instance->chan_ck = 6; 21309c2daa00SOllivier Robert } else if (buf[2] == 'E') { /* 8chan */ 21319c2daa00SOllivier Robert if (instance->chan_ck < 8) instance->chan_ck = 8; 21329c2daa00SOllivier Robert } else if (buf[2] == 'H') { /* 12chan */ 21339c2daa00SOllivier Robert if (instance->chan_ck < 12) instance->chan_ck = 12; 21349c2daa00SOllivier Robert } 21359c2daa00SOllivier Robert 21369c2daa00SOllivier Robert if (instance->count3++ < 5) 21379c2daa00SOllivier Robert return; 21389c2daa00SOllivier Robert 21399c2daa00SOllivier Robert instance->count3 = 0; 21409c2daa00SOllivier Robert 21419c2daa00SOllivier Robert if (instance->chan_in != -1) /* set in Input */ 21429c2daa00SOllivier Robert instance->chan = instance->chan_in; 21439c2daa00SOllivier Robert else /* set from test */ 21449c2daa00SOllivier Robert instance->chan = instance->chan_ck; 21459c2daa00SOllivier Robert 21462b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Input says chan = %d", 21472b15cb3dSCy Schubert instance->chan_in); 21482b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Model # says chan = %d", 21492b15cb3dSCy Schubert instance->chan_id); 21502b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Testing says chan = %d", 21512b15cb3dSCy Schubert instance->chan_ck); 21522b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Using chan = %d", 21532b15cb3dSCy Schubert instance->chan); 21549c2daa00SOllivier Robert 21559c2daa00SOllivier Robert instance->o_state = ONCORE_HAVE_CHAN; 21562b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN"); 21579c2daa00SOllivier Robert 21589c2daa00SOllivier Robert instance->timeout = 4; 21592b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 21609c2daa00SOllivier Robert return; 21619c2daa00SOllivier Robert } 21629c2daa00SOllivier Robert 21639c2daa00SOllivier Robert if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) 21649c2daa00SOllivier Robert return; 21659c2daa00SOllivier Robert 2166ea906c41SOllivier Robert /* PAUSE 5sec - make sure results are stable, before using position */ 21679c2daa00SOllivier Robert 21689c2daa00SOllivier Robert if (instance->count) { 2169ea906c41SOllivier Robert if (instance->count++ < 5) 21709c2daa00SOllivier Robert return; 21719c2daa00SOllivier Robert instance->count = 0; 21729c2daa00SOllivier Robert } 21739c2daa00SOllivier Robert 21749c2daa00SOllivier Robert memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */ 21759c2daa00SOllivier Robert 21762b15cb3dSCy Schubert /* check if we saw a response to Gc (M12 or M12+T */ 21772b15cb3dSCy Schubert 21782b15cb3dSCy Schubert if (instance->pps_control_msg_seen != -2) { 21792b15cb3dSCy Schubert if ((instance->pps_control_msg_seen == -1) && (instance->pps_control != -1)) { 21802b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "PPSCONTROL set, but not implemented (not M12)"); 21812b15cb3dSCy Schubert } 21822b15cb3dSCy Schubert instance->pps_control_msg_seen = -2; 21832b15cb3dSCy Schubert } 21842b15cb3dSCy Schubert 2185ea906c41SOllivier Robert /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */ 21869c2daa00SOllivier Robert 21879c2daa00SOllivier Robert oncore_check_almanac(instance); 21889c2daa00SOllivier Robert oncore_check_antenna(instance); 21899c2daa00SOllivier Robert 2190ea906c41SOllivier Robert /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */ 21919c2daa00SOllivier Robert /* When we have an almanac, we will start the Bn/En/@@Hn messages */ 21929c2daa00SOllivier Robert 21939c2daa00SOllivier Robert if (instance->o_state == ONCORE_ALMANAC) 21949c2daa00SOllivier Robert if (oncore_wait_almanac(instance)) 21959c2daa00SOllivier Robert return; 21969c2daa00SOllivier Robert 21979c2daa00SOllivier Robert /* do some things once when we get this far in BaEaHa */ 21989c2daa00SOllivier Robert 21999c2daa00SOllivier Robert if (instance->once) { 22009c2daa00SOllivier Robert instance->once = 0; 22019c2daa00SOllivier Robert instance->count2 = 1; 22029c2daa00SOllivier Robert 22039c2daa00SOllivier Robert /* Have we seen an @@At (position hold) command response */ 22049c2daa00SOllivier Robert /* if not, message out */ 22059c2daa00SOllivier Robert 22069c2daa00SOllivier Robert if (instance->chan != 12 && !instance->saw_At) { 22072b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, 22082b15cb3dSCy Schubert "Not Good, no @@At command (no Position Hold), must be a GT/GT+"); 22092b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 22109c2daa00SOllivier Robert } 22119c2daa00SOllivier Robert 22129c2daa00SOllivier Robert /* have an Almanac, can start the SiteSurvey 22139c2daa00SOllivier Robert * (actually only need to get past the almanac_load where we diddle with At 22149c2daa00SOllivier Robert * command,- we can't change it after we start the HW_SS below 22159c2daa00SOllivier Robert */ 22169c2daa00SOllivier Robert 22179c2daa00SOllivier Robert mode = instance->init_type; 22189c2daa00SOllivier Robert switch (mode) { 22199c2daa00SOllivier Robert case 0: /* NO initialization, don't change anything */ 22209c2daa00SOllivier Robert case 1: /* Use given Position */ 22219c2daa00SOllivier Robert case 3: 22229c2daa00SOllivier Robert instance->site_survey = ONCORE_SS_DONE; 22232b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 22249c2daa00SOllivier Robert break; 22259c2daa00SOllivier Robert 22269c2daa00SOllivier Robert case 2: 22279c2daa00SOllivier Robert case 4: /* Site Survey */ 22282b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING"); 22299c2daa00SOllivier Robert instance->site_survey = ONCORE_SS_TESTING; 22309c2daa00SOllivier Robert instance->count1 = 1; 22319c2daa00SOllivier Robert if (instance->chan == 12) 22322b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */ 22339c2daa00SOllivier Robert else 22342b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */ 22359c2daa00SOllivier Robert break; 22369c2daa00SOllivier Robert } 22379c2daa00SOllivier Robert 22389c2daa00SOllivier Robert /* Read back PPS Offset for Output */ 22399c2daa00SOllivier Robert /* Nb. This will fail silently for early UT (no plus) and M12 models */ 22409c2daa00SOllivier Robert 22412b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); 22429c2daa00SOllivier Robert 22439c2daa00SOllivier Robert /* Read back Cable Delay for Output */ 22449c2daa00SOllivier Robert 22452b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); 22469c2daa00SOllivier Robert 22479c2daa00SOllivier Robert /* Read back Satellite Mask Angle for Output */ 22489c2daa00SOllivier Robert 22492b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Agx, sizeof(oncore_cmd_Agx)); 22509c2daa00SOllivier Robert } 22519c2daa00SOllivier Robert 2252ea906c41SOllivier Robert 2253ea906c41SOllivier Robert /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is 2254ea906c41SOllivier Robert * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey) 2255ea906c41SOllivier Robert * We must do the Gd3, and then wait a cycle or two for things to settle, 2256ea906c41SOllivier Robert * then check Ha[130]&0x10 to see if a SS is in progress. 2257ea906c41SOllivier Robert * We will set SW if HW has not been set after an appropriate delay. 2258ea906c41SOllivier Robert */ 2259ea906c41SOllivier Robert 22609c2daa00SOllivier Robert if (instance->site_survey == ONCORE_SS_TESTING) { 2261ea906c41SOllivier Robert if (instance->chan == 12) { 2262ea906c41SOllivier Robert if (instance->count1) { 2263ea906c41SOllivier Robert if (instance->count1++ > 5 || instance->BEHa[130]&0x10) { 2264ea906c41SOllivier Robert instance->count1 = 0; 2265ea906c41SOllivier Robert if (instance->BEHa[130]&0x10) { 22662b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, 2267ea906c41SOllivier Robert "Initiating hardware 3D site survey"); 2268ea906c41SOllivier Robert 22692b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW"); 2270ea906c41SOllivier Robert instance->site_survey = ONCORE_SS_HW; 2271ea906c41SOllivier Robert } else { 22722b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW"); 2273ea906c41SOllivier Robert instance->site_survey = ONCORE_SS_SW; 2274ea906c41SOllivier Robert } 2275ea906c41SOllivier Robert } 2276ea906c41SOllivier Robert } 2277ea906c41SOllivier Robert } else { 2278ea906c41SOllivier Robert if (instance->count1) { 2279ea906c41SOllivier Robert if (instance->count1++ > 5) { 2280ea906c41SOllivier Robert instance->count1 = 0; 22819c2daa00SOllivier Robert /* 22829c2daa00SOllivier Robert * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec 22839c2daa00SOllivier Robert * wait after the @@At2/@@Gd3 command we have not changed the state to 22849c2daa00SOllivier Robert * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then 22859c2daa00SOllivier Robert * the variable would have been changed by now. 22869c2daa00SOllivier Robert * There are three possibilities: 22879c2daa00SOllivier Robert * 6/8chan 22889c2daa00SOllivier Robert * (a) We did not get a response to the @@At0 or @@At2 commands, 22899c2daa00SOllivier Robert * and it must be a GT/GT+/SL with no position hold mode. 22909c2daa00SOllivier Robert * We will have to do it ourselves. 22919c2daa00SOllivier Robert * (b) We saw the @@At0, @@At2 commands, but @@At2 failed, 22929c2daa00SOllivier Robert * must be a VP or older UT which doesn't have Site Survey mode. 22939c2daa00SOllivier Robert * We will have to do it ourselves. 22949c2daa00SOllivier Robert * 12chan 2295ea906c41SOllivier Robert * (c) We saw the @@Gd command, and saw H[13]*0x10 2296ea906c41SOllivier Robert * We will have to do it ourselves (done above) 22979c2daa00SOllivier Robert */ 22989c2daa00SOllivier Robert 22992b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 23002b15cb3dSCy Schubert "Initiating software 3D site survey (%d samples)", 23019c2daa00SOllivier Robert POS_HOLD_AVERAGE); 23029c2daa00SOllivier Robert 23032b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW"); 23049c2daa00SOllivier Robert instance->site_survey = ONCORE_SS_SW; 23059c2daa00SOllivier Robert 23069c2daa00SOllivier Robert instance->ss_lat = instance->ss_long = instance->ss_ht = 0; 23079c2daa00SOllivier Robert if (instance->chan == 12) 23082b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */ 23099c2daa00SOllivier Robert else { 23102b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ 23112b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */ 23129c2daa00SOllivier Robert } 23139c2daa00SOllivier Robert } 23149c2daa00SOllivier Robert } 23159c2daa00SOllivier Robert } 2316ea906c41SOllivier Robert } 23179c2daa00SOllivier Robert 23189c2daa00SOllivier Robert /* check the mode we are in 0/2/3D */ 23199c2daa00SOllivier Robert 23209c2daa00SOllivier Robert if (instance->chan == 6) { 23219c2daa00SOllivier Robert if (instance->BEHa[64]&0x8) 23229c2daa00SOllivier Robert instance->mode = MODE_0D; 23239c2daa00SOllivier Robert else if (instance->BEHa[64]&0x10) 23249c2daa00SOllivier Robert instance->mode = MODE_2D; 23259c2daa00SOllivier Robert else if (instance->BEHa[64]&0x20) 23269c2daa00SOllivier Robert instance->mode = MODE_3D; 23279c2daa00SOllivier Robert } else if (instance->chan == 8) { 23289c2daa00SOllivier Robert if (instance->BEHa[72]&0x8) 23299c2daa00SOllivier Robert instance->mode = MODE_0D; 23309c2daa00SOllivier Robert else if (instance->BEHa[72]&0x10) 23319c2daa00SOllivier Robert instance->mode = MODE_2D; 23329c2daa00SOllivier Robert else if (instance->BEHa[72]&0x20) 23339c2daa00SOllivier Robert instance->mode = MODE_3D; 23349c2daa00SOllivier Robert } else if (instance->chan == 12) { 23359c2daa00SOllivier Robert int bits; 23369c2daa00SOllivier Robert 23379c2daa00SOllivier Robert bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 23389c2daa00SOllivier Robert if (bits == 0x4) 23399c2daa00SOllivier Robert instance->mode = MODE_0D; 23409c2daa00SOllivier Robert else if (bits == 0x6) 23419c2daa00SOllivier Robert instance->mode = MODE_2D; 23429c2daa00SOllivier Robert else if (bits == 0x7) 23439c2daa00SOllivier Robert instance->mode = MODE_3D; 23449c2daa00SOllivier Robert } 23459c2daa00SOllivier Robert 23469c2daa00SOllivier Robert /* copy the record to the (extra) location in SHMEM */ 23479c2daa00SOllivier Robert 23489c2daa00SOllivier Robert if (instance->shmem) { 23499c2daa00SOllivier Robert int i; 23509c2daa00SOllivier Robert u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */ 23519c2daa00SOllivier Robert 23529c2daa00SOllivier Robert switch(instance->chan) { 23539c2daa00SOllivier Robert case 6: smp = &instance->shmem[instance->shmem_Ba]; break; 23549c2daa00SOllivier Robert case 8: smp = &instance->shmem[instance->shmem_Ea]; break; 23559c2daa00SOllivier Robert case 12: smp = &instance->shmem[instance->shmem_Ha]; break; 2356ea906c41SOllivier Robert default: smp = (u_char *) NULL; break; 23579c2daa00SOllivier Robert } 23589c2daa00SOllivier Robert 23599c2daa00SOllivier Robert switch (instance->mode) { 23609c2daa00SOllivier Robert case MODE_0D: i = 1; break; /* 0D, Position Hold */ 23619c2daa00SOllivier Robert case MODE_2D: i = 2; break; /* 2D, Altitude Hold */ 23629c2daa00SOllivier Robert case MODE_3D: i = 3; break; /* 3D fix */ 23639c2daa00SOllivier Robert default: i = 0; break; 23649c2daa00SOllivier Robert } 23659c2daa00SOllivier Robert 2366ea906c41SOllivier Robert if (i && smp != NULL) { 23679c2daa00SOllivier Robert i *= (len+6); 23689c2daa00SOllivier Robert smp[i + 2]++; 23699c2daa00SOllivier Robert memcpy(&smp[i+3], buf, (size_t) (len+3)); 23709c2daa00SOllivier Robert } 23719c2daa00SOllivier Robert } 23729c2daa00SOllivier Robert 23739c2daa00SOllivier Robert /* 2374ea906c41SOllivier Robert * check if traim timer active 23759c2daa00SOllivier Robert * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond 23769c2daa00SOllivier Robert */ 23779c2daa00SOllivier Robert 23789c2daa00SOllivier Robert if (instance->traim_delay) { 23799c2daa00SOllivier Robert if (instance->traim_delay++ > 5) { 23809c2daa00SOllivier Robert instance->traim = 0; 23819c2daa00SOllivier Robert instance->traim_delay = 0; 23829c2daa00SOllivier Robert cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; 23832b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, cp); 23849c2daa00SOllivier Robert 23859c2daa00SOllivier Robert oncore_set_traim(instance); 23869c2daa00SOllivier Robert } else 23879c2daa00SOllivier Robert return; 23889c2daa00SOllivier Robert 23899c2daa00SOllivier Robert } 23909c2daa00SOllivier Robert 23919c2daa00SOllivier Robert /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */ 23929c2daa00SOllivier Robert 23939c2daa00SOllivier Robert if (!instance->have_dH && !instance->traim_delay) 23949c2daa00SOllivier Robert oncore_compute_dH(instance); 23959c2daa00SOllivier Robert 23969c2daa00SOllivier Robert /* 23979c2daa00SOllivier Robert * must be ONCORE_RUN if we are here. 23989c2daa00SOllivier Robert * Have # chan and TRAIM by now. 23999c2daa00SOllivier Robert */ 24009c2daa00SOllivier Robert 24019c2daa00SOllivier Robert instance->pp->year = buf[6]*256+buf[7]; 24029c2daa00SOllivier Robert instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); 24039c2daa00SOllivier Robert instance->pp->hour = buf[8]; 24049c2daa00SOllivier Robert instance->pp->minute = buf[9]; 24059c2daa00SOllivier Robert instance->pp->second = buf[10]; 24069c2daa00SOllivier Robert 24079c2daa00SOllivier Robert /* 24089c2daa00SOllivier Robert * Are we doing a Hardware or Software Site Survey? 24099c2daa00SOllivier Robert */ 24109c2daa00SOllivier Robert 24119c2daa00SOllivier Robert if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW) 24129c2daa00SOllivier Robert oncore_ss(instance); 24139c2daa00SOllivier Robert 24149c2daa00SOllivier Robert /* see if we ever saw a response from the @@Ayx above */ 24159c2daa00SOllivier Robert 24169c2daa00SOllivier Robert if (instance->count2) { 24179c2daa00SOllivier Robert if (instance->count2++ > 5) { /* this delay to check on @@Ay command */ 24189c2daa00SOllivier Robert instance->count2 = 0; 24199c2daa00SOllivier Robert 24209c2daa00SOllivier Robert /* Have we seen an Ay (1PPS time offset) command response */ 24219c2daa00SOllivier Robert /* if not, and non-zero offset, zero the offset, and send message */ 24229c2daa00SOllivier Robert 24239c2daa00SOllivier Robert if (!instance->saw_Ay && instance->offset) { 24242b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored"); 24259c2daa00SOllivier Robert instance->offset = 0; 24269c2daa00SOllivier Robert } 24279c2daa00SOllivier Robert } 24289c2daa00SOllivier Robert } 24299c2daa00SOllivier Robert 24309c2daa00SOllivier Robert /* 24319c2daa00SOllivier Robert * Check the leap second status once per day. 24329c2daa00SOllivier Robert */ 24339c2daa00SOllivier Robert 24349c2daa00SOllivier Robert oncore_check_leap_sec(instance); 24359c2daa00SOllivier Robert 24369c2daa00SOllivier Robert /* 24379c2daa00SOllivier Robert * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 24389c2daa00SOllivier Robert */ 24399c2daa00SOllivier Robert 24409c2daa00SOllivier Robert if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) 24419c2daa00SOllivier Robert oncore_shmem_get_3D(instance); 24429c2daa00SOllivier Robert 24439c2daa00SOllivier Robert if (!instance->traim) /* NO traim, no BnEnHn, go get tick */ 24449c2daa00SOllivier Robert oncore_get_timestamp(instance, instance->offset, instance->offset); 24459c2daa00SOllivier Robert } 24469c2daa00SOllivier Robert 24479c2daa00SOllivier Robert 24489c2daa00SOllivier Robert 24499c2daa00SOllivier Robert /* Almanac Status */ 24509c2daa00SOllivier Robert 24519c2daa00SOllivier Robert static void 24529c2daa00SOllivier Robert oncore_msg_Bd( 24539c2daa00SOllivier Robert struct instance *instance, 24549c2daa00SOllivier Robert u_char *buf, 24559c2daa00SOllivier Robert size_t len 24569c2daa00SOllivier Robert ) 24579c2daa00SOllivier Robert { 24582b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 24592b15cb3dSCy Schubert "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x", 24602b15cb3dSCy Schubert ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], 24612b15cb3dSCy Schubert buf[7], w32(&buf[8])); 24629c2daa00SOllivier Robert } 24639c2daa00SOllivier Robert 24649c2daa00SOllivier Robert 24659c2daa00SOllivier Robert 2466c0b746e5SOllivier Robert /* get leap-second warning message */ 2467c0b746e5SOllivier Robert 2468c0b746e5SOllivier Robert /* 2469c0b746e5SOllivier Robert * @@Bj does NOT behave as documented in current Oncore firmware. 2470c0b746e5SOllivier Robert * It turns on the LEAP indicator when the data is set, and does not, 2471c0b746e5SOllivier Robert * as documented, wait until the beginning of the month when the 2472c0b746e5SOllivier Robert * leap second will occur. 24739c2daa00SOllivier Robert * Since this firmware bug will never be fixed in all the outstanding Oncore receivers 24749c2daa00SOllivier Robert * @@Bj is only called in June/December. 2475c0b746e5SOllivier Robert */ 2476c0b746e5SOllivier Robert 2477c0b746e5SOllivier Robert static void 2478c0b746e5SOllivier Robert oncore_msg_Bj( 2479c0b746e5SOllivier Robert struct instance *instance, 2480c0b746e5SOllivier Robert u_char *buf, 2481224ba2bdSOllivier Robert size_t len 2482c0b746e5SOllivier Robert ) 2483c0b746e5SOllivier Robert { 2484c0b746e5SOllivier Robert const char *cp; 2485c0b746e5SOllivier Robert 24862b15cb3dSCy Schubert instance->saw_Bj = 1; 24872b15cb3dSCy Schubert 2488c0b746e5SOllivier Robert switch(buf[4]) { 2489c0b746e5SOllivier Robert case 1: 2490ea906c41SOllivier Robert instance->pp->leap = LEAP_ADDSECOND; 2491ea906c41SOllivier Robert cp = "Set pp.leap to LEAP_ADDSECOND"; 2492c0b746e5SOllivier Robert break; 2493c0b746e5SOllivier Robert case 2: 2494ea906c41SOllivier Robert instance->pp->leap = LEAP_DELSECOND; 2495ea906c41SOllivier Robert cp = "Set pp.leap to LEAP_DELSECOND"; 2496c0b746e5SOllivier Robert break; 2497c0b746e5SOllivier Robert case 0: 2498c0b746e5SOllivier Robert default: 2499ea906c41SOllivier Robert instance->pp->leap = LEAP_NOWARNING; 2500ea906c41SOllivier Robert cp = "Set pp.leap to LEAP_NOWARNING"; 2501c0b746e5SOllivier Robert break; 2502c0b746e5SOllivier Robert } 25032b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, cp); 2504c0b746e5SOllivier Robert } 2505c0b746e5SOllivier Robert 25069c2daa00SOllivier Robert 25079c2daa00SOllivier Robert 25089c2daa00SOllivier Robert static void 25092b15cb3dSCy Schubert oncore_msg_Bl( 25102b15cb3dSCy Schubert struct instance *instance, 25112b15cb3dSCy Schubert u_char *buf, 25122b15cb3dSCy Schubert size_t len 25132b15cb3dSCy Schubert ) 25142b15cb3dSCy Schubert { 25152b15cb3dSCy Schubert int subframe, valid, page, i, j, tow; 25162b15cb3dSCy Schubert int day_now, day_lsf; 25172b15cb3dSCy Schubert const char *cp; 25182b15cb3dSCy Schubert enum { 25192b15cb3dSCy Schubert WARN_NOT_YET, 25202b15cb3dSCy Schubert WARN_0, 25212b15cb3dSCy Schubert WARN_PLUS, 25222b15cb3dSCy Schubert WARN_MINUS 25232b15cb3dSCy Schubert } warn; 25242b15cb3dSCy Schubert 25252b15cb3dSCy Schubert 25262b15cb3dSCy Schubert subframe = buf[6] & 017; 25272b15cb3dSCy Schubert valid = (buf[6] >> 4) & 017; 25282b15cb3dSCy Schubert page = buf[7]; 25292b15cb3dSCy Schubert 25302b15cb3dSCy Schubert if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) { 25312b15cb3dSCy Schubert instance->Bl.dt_ls = buf[32]; 25322b15cb3dSCy Schubert instance->Bl.WN_lsf = buf[33]; 25332b15cb3dSCy Schubert instance->Bl.DN_lsf = buf[34]; 25342b15cb3dSCy Schubert instance->Bl.dt_lsf = buf[35]; 25352b15cb3dSCy Schubert instance->Bl.lsf_flg++; 25362b15cb3dSCy Schubert } 25372b15cb3dSCy Schubert if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) { 25382b15cb3dSCy Schubert i = (buf[7+7]<<8) + buf[7+8]; 25392b15cb3dSCy Schubert instance->Bl.WN = i >> 6; 25402b15cb3dSCy Schubert tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6]; 25412b15cb3dSCy Schubert tow >>= 7; 25422b15cb3dSCy Schubert tow = tow & 0377777; 25432b15cb3dSCy Schubert tow <<= 2; 25442b15cb3dSCy Schubert instance->Bl.DN = tow/57600L + 1; 25452b15cb3dSCy Schubert instance->Bl.wn_flg++; 25462b15cb3dSCy Schubert } 25472b15cb3dSCy Schubert if (instance->Bl.wn_flg && instance->Bl.lsf_flg) { 25482b15cb3dSCy Schubert instance->Bl.wn_flg = instance->Bl.lsf_flg = 0; 25492b15cb3dSCy Schubert oncore_cmd_Bl[2] = 0; 25502b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl); 25512b15cb3dSCy Schubert oncore_cmd_Bl[2] = 1; 25522b15cb3dSCy Schubert 25532b15cb3dSCy Schubert i = instance->Bl.WN&01400; 25542b15cb3dSCy Schubert instance->Bl.WN_lsf |= i; 25552b15cb3dSCy Schubert 25562b15cb3dSCy Schubert /* have everything I need, doit */ 25572b15cb3dSCy Schubert 25582b15cb3dSCy Schubert i = (instance->Bl.WN_lsf - instance->Bl.WN); 25592b15cb3dSCy Schubert if (i < 0) 25602b15cb3dSCy Schubert i += 1024; 25612b15cb3dSCy Schubert day_now = instance->Bl.DN; 25622b15cb3dSCy Schubert day_lsf = 7*i + instance->Bl.DN_lsf; 25632b15cb3dSCy Schubert 25642b15cb3dSCy Schubert /* ignore if in past or more than a month in future */ 25652b15cb3dSCy Schubert 25662b15cb3dSCy Schubert warn = WARN_NOT_YET; 25672b15cb3dSCy Schubert if (day_lsf >= day_now && day_lsf - day_now < 32) { 25682b15cb3dSCy Schubert /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */ 25692b15cb3dSCy Schubert if (day_lsf - day_now < 28 || instance->BEHa[5] < 20) { 25702b15cb3dSCy Schubert i = instance->Bl.dt_lsf - instance->Bl.dt_ls; 25712b15cb3dSCy Schubert switch (i) { 25722b15cb3dSCy Schubert case -1: 25732b15cb3dSCy Schubert warn = WARN_MINUS; 25742b15cb3dSCy Schubert break; 25752b15cb3dSCy Schubert case 0: 25762b15cb3dSCy Schubert warn = WARN_0; 25772b15cb3dSCy Schubert break; 25782b15cb3dSCy Schubert case 1: 25792b15cb3dSCy Schubert warn = WARN_PLUS; 25802b15cb3dSCy Schubert break; 25812b15cb3dSCy Schubert } 25822b15cb3dSCy Schubert } 25832b15cb3dSCy Schubert } 25842b15cb3dSCy Schubert 25852b15cb3dSCy Schubert switch (warn) { 25862b15cb3dSCy Schubert case WARN_0: 25872b15cb3dSCy Schubert case WARN_NOT_YET: 25882b15cb3dSCy Schubert instance->peer->leap = LEAP_NOWARNING; 25892b15cb3dSCy Schubert cp = "Set peer.leap to LEAP_NOWARNING"; 25902b15cb3dSCy Schubert break; 25912b15cb3dSCy Schubert case WARN_MINUS: 25922b15cb3dSCy Schubert instance->peer->leap = LEAP_DELSECOND; 25932b15cb3dSCy Schubert cp = "Set peer.leap to LEAP_DELSECOND"; 25942b15cb3dSCy Schubert break; 25952b15cb3dSCy Schubert case WARN_PLUS: 25962b15cb3dSCy Schubert instance->peer->leap = LEAP_ADDSECOND; 25972b15cb3dSCy Schubert cp = "Set peer.leap to LEAP_ADDSECOND"; 25982b15cb3dSCy Schubert break; 2599f0574f5cSXin LI default: 2600f0574f5cSXin LI cp = NULL; 2601f0574f5cSXin LI break; 26022b15cb3dSCy Schubert } 26032b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, cp); 26042b15cb3dSCy Schubert 26052b15cb3dSCy Schubert i = instance->Bl.dt_lsf-instance->Bl.dt_ls; 26062b15cb3dSCy Schubert if (i) { 26072b15cb3dSCy Schubert j = (i >= 0) ? i : -i; /* abs(i) */ 26082b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 26092b15cb3dSCy Schubert "see Leap_Second (%c%d) in %d days", 26102b15cb3dSCy Schubert ((i >= 0) ? '+' : '-'), j, 26112b15cb3dSCy Schubert day_lsf-day_now); 26122b15cb3dSCy Schubert } 26132b15cb3dSCy Schubert } 26142b15cb3dSCy Schubert 26152b15cb3dSCy Schubert /* 26162b15cb3dSCy Schubert * Reg only wants the following output for "deeper" driver debugging. 26172b15cb3dSCy Schubert * See Bug 2142 and Bug 1866 26182b15cb3dSCy Schubert */ 26192b15cb3dSCy Schubert #if 0 26202b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 26212b15cb3dSCy Schubert "dt_ls = %d dt_lsf = %d WN = %d DN = %d WN_lsf = %d DNlsf = %d wn_flg = %d lsf_flg = %d Bl_day = %d", 26222b15cb3dSCy Schubert instance->Bl.dt_ls, instance->Bl.dt_lsf, 26232b15cb3dSCy Schubert instance->Bl.WN, instance->Bl.DN, 26242b15cb3dSCy Schubert instance->Bl.WN_lsf, instance->Bl.DN_lsf, 26252b15cb3dSCy Schubert instance->Bl.wn_flg, instance->Bl.lsf_flg, 26262b15cb3dSCy Schubert instance->Bl.Bl_day); 26272b15cb3dSCy Schubert #endif 26282b15cb3dSCy Schubert } 26292b15cb3dSCy Schubert 26302b15cb3dSCy Schubert 26312b15cb3dSCy Schubert static void 26329c2daa00SOllivier Robert oncore_msg_BnEnHn( 26339c2daa00SOllivier Robert struct instance *instance, 26349c2daa00SOllivier Robert u_char *buf, 26359c2daa00SOllivier Robert size_t len 26369c2daa00SOllivier Robert ) 26379c2daa00SOllivier Robert { 26389c2daa00SOllivier Robert long dt1, dt2; 26399c2daa00SOllivier Robert 26409c2daa00SOllivier Robert if (instance->o_state != ONCORE_RUN) 26419c2daa00SOllivier Robert return; 26429c2daa00SOllivier Robert 26439c2daa00SOllivier Robert if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */ 26449c2daa00SOllivier Robert instance->traim_ck = 1; 26459c2daa00SOllivier Robert instance->traim_delay = 0; 26462b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON"); 26479c2daa00SOllivier Robert 26489c2daa00SOllivier Robert oncore_set_traim(instance); 26499c2daa00SOllivier Robert } 26509c2daa00SOllivier Robert 26519c2daa00SOllivier Robert memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */ 26529c2daa00SOllivier Robert 2653ea906c41SOllivier Robert if (!instance->traim) /* BnEnHn will be turned off in any case */ 2654ea906c41SOllivier Robert return; 2655ea906c41SOllivier Robert 26569c2daa00SOllivier Robert /* If Time RAIM doesn't like it, don't trust it */ 26579c2daa00SOllivier Robert 26589c2daa00SOllivier Robert if (buf[2] == 'H') { 26592b15cb3dSCy Schubert if (instance->BEHn[6]) { /* bad TRAIM */ 26602b15cb3dSCy Schubert oncore_log(instance, LOG_WARNING, "BAD TRAIM"); 26619c2daa00SOllivier Robert return; 26622b15cb3dSCy Schubert } 26639c2daa00SOllivier Robert 26649c2daa00SOllivier Robert dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2665ea906c41SOllivier Robert instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */ 26669c2daa00SOllivier Robert dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 26679c2daa00SOllivier Robert } else { 26689c2daa00SOllivier Robert if (instance->BEHn[21]) /* bad TRAIM */ 26699c2daa00SOllivier Robert return; 26709c2daa00SOllivier Robert 26719c2daa00SOllivier Robert dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ 2672ea906c41SOllivier Robert instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */ 26739c2daa00SOllivier Robert dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ 26749c2daa00SOllivier Robert } 26759c2daa00SOllivier Robert 26769c2daa00SOllivier Robert oncore_get_timestamp(instance, dt1, dt2); 26779c2daa00SOllivier Robert } 26789c2daa00SOllivier Robert 26799c2daa00SOllivier Robert 26809c2daa00SOllivier Robert 26819c2daa00SOllivier Robert /* Here for @@Ca, @@Fa and @@Ia messages */ 26829c2daa00SOllivier Robert 26839c2daa00SOllivier Robert /* These are Self test Commands for 6, 8, and 12 chan receivers. 26849c2daa00SOllivier Robert * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE. 26859c2daa00SOllivier Robert * It was found that under some circumstances the following 26869c2daa00SOllivier Robert * command would fail if issued immediately after the return from the 26879c2daa00SOllivier Robert * @@Fa, but a 2sec delay seemed to fix things. Since simply calling 26889c2daa00SOllivier Robert * sleep(2) is wasteful, and may cause trouble for some OS's, repeating 26899c2daa00SOllivier Robert * itimer, we set a flag, and test it at the next POLL. If it hasn't 26909c2daa00SOllivier Robert * been cleared, we reissue the @@Cj that is issued below. 26919c2daa00SOllivier Robert * Note that we do a @@Cj at the beginning, and again here. 26929c2daa00SOllivier Robert * The first is to get the info, the 2nd is just used as a safe command 26939c2daa00SOllivier Robert * after the @@Fa for all Oncores (and it was in this posn in the 26949c2daa00SOllivier Robert * original code). 26959c2daa00SOllivier Robert */ 26969c2daa00SOllivier Robert 26979c2daa00SOllivier Robert static void 26989c2daa00SOllivier Robert oncore_msg_CaFaIa( 26999c2daa00SOllivier Robert struct instance *instance, 27009c2daa00SOllivier Robert u_char *buf, 27019c2daa00SOllivier Robert size_t len 27029c2daa00SOllivier Robert ) 27039c2daa00SOllivier Robert { 27049c2daa00SOllivier Robert int i; 27059c2daa00SOllivier Robert 27069c2daa00SOllivier Robert if (instance->o_state == ONCORE_TEST_SENT) { 27079c2daa00SOllivier Robert enum antenna_state antenna; 27089c2daa00SOllivier Robert 27099c2daa00SOllivier Robert instance->timeout = 0; 27109c2daa00SOllivier Robert 27112b15cb3dSCy Schubert #if ONCORE_VERBOSE_SELF_TEST 27129c2daa00SOllivier Robert if (debug > 2) { 27139c2daa00SOllivier Robert if (buf[2] == 'I') 27142b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 27152b15cb3dSCy Schubert ">>@@%ca %x %x %x", buf[2], 27162b15cb3dSCy Schubert buf[4], buf[5], buf[6]); 27179c2daa00SOllivier Robert else 27182b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 27192b15cb3dSCy Schubert ">>@@%ca %x %x", buf[2], 27202b15cb3dSCy Schubert buf[4], buf[5]); 27219c2daa00SOllivier Robert } 2722ea906c41SOllivier Robert #endif 27239c2daa00SOllivier Robert 27249c2daa00SOllivier Robert antenna = (buf[4] & 0xc0) >> 6; 27259c2daa00SOllivier Robert buf[4] &= ~0xc0; 27269c2daa00SOllivier Robert 27279c2daa00SOllivier Robert i = buf[4] || buf[5]; 27289c2daa00SOllivier Robert if (buf[2] == 'I') i = i || buf[6]; 27299c2daa00SOllivier Robert if (i) { 27302b15cb3dSCy Schubert if (buf[2] == 'I') 27312b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, 27322b15cb3dSCy Schubert "self test failed: result %02x %02x %02x", 27332b15cb3dSCy Schubert buf[4], buf[5], buf[6]); 27342b15cb3dSCy Schubert else 27352b15cb3dSCy Schubert oncore_log_f(instance, LOG_ERR, 27362b15cb3dSCy Schubert "self test failed: result %02x %02x", 27372b15cb3dSCy Schubert buf[4], buf[5]); 27382b15cb3dSCy Schubert 27392b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, 27402b15cb3dSCy Schubert "ONCORE: self test failed, shutting down driver"); 27419c2daa00SOllivier Robert 27429c2daa00SOllivier Robert refclock_report(instance->peer, CEVNT_FAULT); 27439c2daa00SOllivier Robert oncore_shutdown(instance->unit, instance->peer); 27449c2daa00SOllivier Robert return; 27459c2daa00SOllivier Robert } 27469c2daa00SOllivier Robert 27479c2daa00SOllivier Robert /* report the current antenna state */ 27489c2daa00SOllivier Robert 27499c2daa00SOllivier Robert oncore_antenna_report(instance, antenna); 27509c2daa00SOllivier Robert 27519c2daa00SOllivier Robert instance->o_state = ONCORE_INIT; 27522b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT"); 27539c2daa00SOllivier Robert 27549c2daa00SOllivier Robert instance->timeout = 4; 27552b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 27569c2daa00SOllivier Robert } 27579c2daa00SOllivier Robert } 27589c2daa00SOllivier Robert 27599c2daa00SOllivier Robert 27609c2daa00SOllivier Robert 27619c2daa00SOllivier Robert /* 27629c2daa00SOllivier Robert * Demultiplex the almanac into shmem 27639c2daa00SOllivier Robert */ 27649c2daa00SOllivier Robert 27659c2daa00SOllivier Robert static void 27669c2daa00SOllivier Robert oncore_msg_Cb( 27679c2daa00SOllivier Robert struct instance *instance, 27689c2daa00SOllivier Robert u_char *buf, 27699c2daa00SOllivier Robert size_t len 27709c2daa00SOllivier Robert ) 27719c2daa00SOllivier Robert { 27729c2daa00SOllivier Robert int i; 27739c2daa00SOllivier Robert 27749c2daa00SOllivier Robert if (instance->shmem == NULL) 27759c2daa00SOllivier Robert return; 27769c2daa00SOllivier Robert 27779c2daa00SOllivier Robert if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26) 27789c2daa00SOllivier Robert i = buf[5]; 27799c2daa00SOllivier Robert else if (buf[4] == 4 && buf[5] <= 5) 27809c2daa00SOllivier Robert i = buf[5] + 24; 27819c2daa00SOllivier Robert else if (buf[4] == 4 && buf[5] <= 10) 27829c2daa00SOllivier Robert i = buf[5] + 23; 27839c2daa00SOllivier Robert else if (buf[4] == 4 && buf[5] == 25) 27849c2daa00SOllivier Robert i = 34; 27859c2daa00SOllivier Robert else { 27862b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC"); 27879c2daa00SOllivier Robert return; 27889c2daa00SOllivier Robert } 27899c2daa00SOllivier Robert 27909c2daa00SOllivier Robert i *= 36; 27919c2daa00SOllivier Robert instance->shmem[instance->shmem_Cb + i + 2]++; 27929c2daa00SOllivier Robert memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); 27939c2daa00SOllivier Robert 27942b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_MSG_CB 27952b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, "See Cb [%d,%d]", buf[4], 27962b15cb3dSCy Schubert buf[5]); 27979c2daa00SOllivier Robert #endif 27989c2daa00SOllivier Robert } 27999c2daa00SOllivier Robert 28009c2daa00SOllivier Robert 28019c2daa00SOllivier Robert 28029c2daa00SOllivier Robert /* 28039c2daa00SOllivier Robert * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup 28049c2daa00SOllivier Robert * not so for VP (eeprom) or any unit with a battery 28059c2daa00SOllivier Robert */ 28069c2daa00SOllivier Robert 28079c2daa00SOllivier Robert static void 28089c2daa00SOllivier Robert oncore_msg_Cf( 28099c2daa00SOllivier Robert struct instance *instance, 28109c2daa00SOllivier Robert u_char *buf, 28119c2daa00SOllivier Robert size_t len 28129c2daa00SOllivier Robert ) 28139c2daa00SOllivier Robert { 28149c2daa00SOllivier Robert if (instance->o_state == ONCORE_RESET_SENT) { 28152b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 28169c2daa00SOllivier Robert /* Reset set VP to IDLE */ 28179c2daa00SOllivier Robert instance->o_state = ONCORE_TEST_SENT; 28182b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 28199c2daa00SOllivier Robert 28202b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); 28219c2daa00SOllivier Robert } 28229c2daa00SOllivier Robert } 28239c2daa00SOllivier Robert 28249c2daa00SOllivier Robert 28259c2daa00SOllivier Robert 28269c2daa00SOllivier Robert /* 28279c2daa00SOllivier Robert * This is the Grand Central Station for the Preliminary Initialization. 28289c2daa00SOllivier Robert * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running. 28299c2daa00SOllivier Robert * 28309c2daa00SOllivier Robert * We do an @@Cj whenever we need a safe command for all Oncores. 28319c2daa00SOllivier Robert * The @@Cj gets us back here where we can switch to the next phase of setup. 28329c2daa00SOllivier Robert * 28339c2daa00SOllivier Robert * o Once at the very beginning (in start) to get the Model number. 28349c2daa00SOllivier Robert * This info is printed, but no longer used. 28359c2daa00SOllivier Robert * o Again after we have determined the number of Channels in the receiver. 28369c2daa00SOllivier Robert * o And once later after we have done a reset and test, (which may hang), 28379c2daa00SOllivier Robert * as we are about to initialize the Oncore and start it running. 28389c2daa00SOllivier Robert * o We have one routine below for each case. 28399c2daa00SOllivier Robert */ 28409c2daa00SOllivier Robert 28419c2daa00SOllivier Robert static void 28429c2daa00SOllivier Robert oncore_msg_Cj( 28439c2daa00SOllivier Robert struct instance *instance, 28449c2daa00SOllivier Robert u_char *buf, 28459c2daa00SOllivier Robert size_t len 28469c2daa00SOllivier Robert ) 28479c2daa00SOllivier Robert { 28489c2daa00SOllivier Robert int mode; 28499c2daa00SOllivier Robert 28509c2daa00SOllivier Robert memcpy(instance->Cj, buf, len); 28519c2daa00SOllivier Robert 28529c2daa00SOllivier Robert instance->timeout = 0; 28539c2daa00SOllivier Robert if (instance->o_state == ONCORE_CHECK_ID) { 28549c2daa00SOllivier Robert oncore_msg_Cj_id(instance, buf, len); 28559c2daa00SOllivier Robert oncore_chan_test(instance); 28569c2daa00SOllivier Robert } else if (instance->o_state == ONCORE_HAVE_CHAN) { 28579c2daa00SOllivier Robert mode = instance->init_type; 28589c2daa00SOllivier Robert if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */ 28599c2daa00SOllivier Robert instance->o_state = ONCORE_RESET_SENT; 28602b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT"); 28612b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); 28629c2daa00SOllivier Robert } else { 28639c2daa00SOllivier Robert instance->o_state = ONCORE_TEST_SENT; 28642b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT"); 28659c2daa00SOllivier Robert } 28669c2daa00SOllivier Robert } 28679c2daa00SOllivier Robert 28689c2daa00SOllivier Robert if (instance->o_state == ONCORE_TEST_SENT) { 28699c2daa00SOllivier Robert if (instance->chan == 6) 28702b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); 28719c2daa00SOllivier Robert else if (instance->chan == 8) 28722b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); 28739c2daa00SOllivier Robert else if (instance->chan == 12) 28742b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); 28759c2daa00SOllivier Robert } else if (instance->o_state == ONCORE_INIT) 28769c2daa00SOllivier Robert oncore_msg_Cj_init(instance, buf, len); 28779c2daa00SOllivier Robert } 28789c2daa00SOllivier Robert 28799c2daa00SOllivier Robert 28809c2daa00SOllivier Robert 28819c2daa00SOllivier Robert /* The information on determining a Oncore 'Model', viz VP, UT, etc, from 28829c2daa00SOllivier Robert * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> 28839c2daa00SOllivier Robert * and from Motorola. Until recently Rick was the only source of 28849c2daa00SOllivier Robert * this information as Motorola didn't give the information out. 28859c2daa00SOllivier Robert * 28869c2daa00SOllivier Robert * Determine the Type from the Model #, this determines #chan and if TRAIM is 28879c2daa00SOllivier Robert * available. 28889c2daa00SOllivier Robert * 28899c2daa00SOllivier Robert * The Information from this routine is NO LONGER USED. 28909c2daa00SOllivier Robert * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED 28919c2daa00SOllivier Robert */ 28929c2daa00SOllivier Robert 28939c2daa00SOllivier Robert static void 28949c2daa00SOllivier Robert oncore_msg_Cj_id( 28959c2daa00SOllivier Robert struct instance *instance, 28969c2daa00SOllivier Robert u_char *buf, 28979c2daa00SOllivier Robert size_t len 28989c2daa00SOllivier Robert ) 28999c2daa00SOllivier Robert { 29002b15cb3dSCy Schubert char *cp2, Model[21]; 29012b15cb3dSCy Schubert const char *cp, *cp1; 29029c2daa00SOllivier Robert 29039c2daa00SOllivier Robert /* Write Receiver ID message to clockstats file */ 29049c2daa00SOllivier Robert 29059c2daa00SOllivier Robert instance->Cj[294] = '\0'; 29069c2daa00SOllivier Robert for (cp= (char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { 29072b15cb3dSCy Schubert char *cpw = strchr(cp, '\r'); 29082b15cb3dSCy Schubert if (!cpw) 29092b15cb3dSCy Schubert cpw = (char *)&instance->Cj[294]; 29102b15cb3dSCy Schubert *cpw = '\0'; 29112b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, cp); 29122b15cb3dSCy Schubert *cpw = '\r'; 29132b15cb3dSCy Schubert cp = cpw+2; 29149c2daa00SOllivier Robert } 29159c2daa00SOllivier Robert 29169c2daa00SOllivier Robert /* next, the Firmware Version and Revision numbers */ 29179c2daa00SOllivier Robert 2918ea906c41SOllivier Robert instance->version = atoi((char *) &instance->Cj[83]); 2919ea906c41SOllivier Robert instance->revision = atoi((char *) &instance->Cj[111]); 29209c2daa00SOllivier Robert 29219c2daa00SOllivier Robert /* from model number decide which Oncore this is, 29229c2daa00SOllivier Robert and then the number of channels */ 29239c2daa00SOllivier Robert 2924ea906c41SOllivier Robert for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ 29259c2daa00SOllivier Robert ; 29269c2daa00SOllivier Robert cp1 = cp; 29279c2daa00SOllivier Robert cp2 = Model; 29282b15cb3dSCy Schubert for (; !isspace((unsigned char)*cp) && cp-cp1 < 20; cp++, cp2++) 29299c2daa00SOllivier Robert *cp2 = *cp; 29309c2daa00SOllivier Robert *cp2 = '\0'; 29319c2daa00SOllivier Robert 29329c2daa00SOllivier Robert cp = 0; 29339c2daa00SOllivier Robert if (!strncmp(Model, "PVT6", (size_t) 4)) { 29349c2daa00SOllivier Robert cp = "PVT6"; 29359c2daa00SOllivier Robert instance->model = ONCORE_PVT6; 29369c2daa00SOllivier Robert } else if (Model[0] == 'A') { 29379c2daa00SOllivier Robert cp = "Basic"; 29389c2daa00SOllivier Robert instance->model = ONCORE_BASIC; 29399c2daa00SOllivier Robert } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { 29409c2daa00SOllivier Robert cp = "VP"; 29419c2daa00SOllivier Robert instance->model = ONCORE_VP; 29429c2daa00SOllivier Robert } else if (Model[0] == 'P') { 29439c2daa00SOllivier Robert cp = "M12"; 29449c2daa00SOllivier Robert instance->model = ONCORE_M12; 29459c2daa00SOllivier Robert } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') { 29469c2daa00SOllivier Robert if (Model[5] == 'N') { 29479c2daa00SOllivier Robert cp = "GT"; 29489c2daa00SOllivier Robert instance->model = ONCORE_GT; 29499c2daa00SOllivier Robert } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { 29509c2daa00SOllivier Robert cp = "GT+"; 29519c2daa00SOllivier Robert instance->model = ONCORE_GTPLUS; 29529c2daa00SOllivier Robert } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { 29539c2daa00SOllivier Robert cp = "UT"; 29549c2daa00SOllivier Robert instance->model = ONCORE_UT; 29559c2daa00SOllivier Robert } else if (Model[1] == '5' && Model[5] == 'G') { 29569c2daa00SOllivier Robert cp = "UT+"; 29579c2daa00SOllivier Robert instance->model = ONCORE_UTPLUS; 29589c2daa00SOllivier Robert } else if (Model[1] == '6' && Model[5] == 'G') { 29599c2daa00SOllivier Robert cp = "SL"; 29609c2daa00SOllivier Robert instance->model = ONCORE_SL; 29619c2daa00SOllivier Robert } else { 29629c2daa00SOllivier Robert cp = "Unknown"; 29639c2daa00SOllivier Robert instance->model = ONCORE_UNKNOWN; 29649c2daa00SOllivier Robert } 29659c2daa00SOllivier Robert } else { 29669c2daa00SOllivier Robert cp = "Unknown"; 29679c2daa00SOllivier Robert instance->model = ONCORE_UNKNOWN; 29689c2daa00SOllivier Robert } 29699c2daa00SOllivier Robert 29709c2daa00SOllivier Robert /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */ 29719c2daa00SOllivier Robert 29722b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 29732b15cb3dSCy Schubert "This looks like an Oncore %s with version %d.%d firmware.", 29742b15cb3dSCy Schubert cp, instance->version, instance->revision); 29759c2daa00SOllivier Robert 29769c2daa00SOllivier Robert instance->chan_id = 8; /* default */ 29779c2daa00SOllivier Robert if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 29789c2daa00SOllivier Robert instance->chan_id = 6; 29799c2daa00SOllivier Robert else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 29809c2daa00SOllivier Robert instance->chan_id = 8; 29819c2daa00SOllivier Robert else if (instance->model == ONCORE_M12) 29829c2daa00SOllivier Robert instance->chan_id = 12; 29839c2daa00SOllivier Robert 29849c2daa00SOllivier Robert instance->traim_id = 0; /* default */ 29859c2daa00SOllivier Robert if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) 29869c2daa00SOllivier Robert instance->traim_id = 0; 29879c2daa00SOllivier Robert else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) 29889c2daa00SOllivier Robert instance->traim_id = 1; 29899c2daa00SOllivier Robert else if (instance->model == ONCORE_M12) 29909c2daa00SOllivier Robert instance->traim_id = -1; 29919c2daa00SOllivier Robert 29922b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Channels = %d, TRAIM = %s", 29932b15cb3dSCy Schubert instance->chan_id, 29942b15cb3dSCy Schubert ((instance->traim_id < 0) 29952b15cb3dSCy Schubert ? "UNKNOWN" 29962b15cb3dSCy Schubert : (instance->traim_id > 0) 29972b15cb3dSCy Schubert ? "ON" 29982b15cb3dSCy Schubert : "OFF")); 29999c2daa00SOllivier Robert } 30009c2daa00SOllivier Robert 30019c2daa00SOllivier Robert 30029c2daa00SOllivier Robert 30039c2daa00SOllivier Robert /* OK, know type of Oncore, have possibly reset it, and have tested it. 30049c2daa00SOllivier Robert * We know the number of channels. 30059c2daa00SOllivier Robert * We will determine whether we have TRAIM before we actually start. 30069c2daa00SOllivier Robert * Now initialize. 30079c2daa00SOllivier Robert */ 30089c2daa00SOllivier Robert 30099c2daa00SOllivier Robert static void 30109c2daa00SOllivier Robert oncore_msg_Cj_init( 30119c2daa00SOllivier Robert struct instance *instance, 30129c2daa00SOllivier Robert u_char *buf, 30139c2daa00SOllivier Robert size_t len 30149c2daa00SOllivier Robert ) 30159c2daa00SOllivier Robert { 3016ea906c41SOllivier Robert u_char Cmd[20]; 30179c2daa00SOllivier Robert int mode; 30189c2daa00SOllivier Robert 30199c2daa00SOllivier Robert 30209c2daa00SOllivier Robert /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to 30219c2daa00SOllivier Robert * start again if we go from 0D -> 3D, then loses them again when we 30229c2daa00SOllivier Robert * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. 30239c2daa00SOllivier Robert * For NOW we will turn this aspect of filling SHMEM off for the M12 30249c2daa00SOllivier Robert */ 30259c2daa00SOllivier Robert 30269c2daa00SOllivier Robert if (instance->chan == 12) { 30279c2daa00SOllivier Robert instance->shmem_bad_Ea = 1; 30282b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 30292b15cb3dSCy Schubert "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", 30302b15cb3dSCy Schubert instance->version, instance->revision); 30319c2daa00SOllivier Robert } 30329c2daa00SOllivier Robert 30332b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */ 30342b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */ 30352b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */ 30362b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */ 30372b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */ 30382b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */ 30392b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */ 30409c2daa00SOllivier Robert 30419c2daa00SOllivier Robert mode = instance->init_type; 30429c2daa00SOllivier Robert 30439c2daa00SOllivier Robert /* If there is Position input in the Config file 30449c2daa00SOllivier Robert * and mode = (1,3) set it as posn hold posn, goto 0D mode. 30459c2daa00SOllivier Robert * or mode = (2,4) set it as INITIAL position, and do Site Survey. 30469c2daa00SOllivier Robert */ 30479c2daa00SOllivier Robert 30489c2daa00SOllivier Robert if (instance->posn_set) { 30492b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "Setting Posn from input data"); 30509c2daa00SOllivier Robert oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */ 30519c2daa00SOllivier Robert } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */ 30529c2daa00SOllivier Robert if (instance->chan != 12) 30532b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx)); 30549c2daa00SOllivier Robert 30559c2daa00SOllivier Robert if (mode != 0) { 30569c2daa00SOllivier Robert /* cable delay in ns */ 30579c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az)); 30582b15cb3dSCy Schubert w32_buf(&Cmd[-2+4], (int)instance->delay); 30592b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */ 30609c2daa00SOllivier Robert 30619c2daa00SOllivier Robert /* PPS offset in ns */ 30629c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */ 30639c2daa00SOllivier Robert w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */ 30642b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ay)); 30659c2daa00SOllivier Robert 30669c2daa00SOllivier Robert /* Satellite mask angle */ 30679c2daa00SOllivier Robert 30689c2daa00SOllivier Robert if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */ 30699c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag)); 30709c2daa00SOllivier Robert Cmd[-2+4] = instance->Ag; 30712b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ag)); 30729c2daa00SOllivier Robert } 30739c2daa00SOllivier Robert } 30749c2daa00SOllivier Robert 30759c2daa00SOllivier Robert /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s 30769c2daa00SOllivier Robert * now we're really running 30779c2daa00SOllivier Robert * these were ALL started in the chan test, 30789c2daa00SOllivier Robert * However, if we had mode=3,4 then commands got turned off, so we turn 30799c2daa00SOllivier Robert * them on again here just in case 30809c2daa00SOllivier Robert */ 30819c2daa00SOllivier Robert 30829c2daa00SOllivier Robert if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */ 30832b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 30842b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 30852b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 30862b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 30872b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba )); 30889c2daa00SOllivier Robert } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */ 30892b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 30902b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 30912b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0)); 30922b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 30932b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea )); 30949c2daa00SOllivier Robert } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */ 30952b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); 30962b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); 30972b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); 30982b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0)); 30992b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha )); 31002b15cb3dSCy Schubert oncore_cmd_Gc[2] = (instance->pps_control < 0) ? 1 : instance->pps_control; 31012b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* PPS off/continuous/Tracking 1+sat/TRAIM */ 31029c2daa00SOllivier Robert } 31039c2daa00SOllivier Robert 31049c2daa00SOllivier Robert instance->count = 1; 31059c2daa00SOllivier Robert instance->o_state = ONCORE_ALMANAC; 31062b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC"); 31079c2daa00SOllivier Robert } 31089c2daa00SOllivier Robert 31099c2daa00SOllivier Robert 31109c2daa00SOllivier Robert 31119c2daa00SOllivier Robert /* 12chan position */ 31129c2daa00SOllivier Robert 31139c2daa00SOllivier Robert static void 31149c2daa00SOllivier Robert oncore_msg_Ga( 31159c2daa00SOllivier Robert struct instance *instance, 31169c2daa00SOllivier Robert u_char *buf, 31179c2daa00SOllivier Robert size_t len 31189c2daa00SOllivier Robert ) 31199c2daa00SOllivier Robert { 31209c2daa00SOllivier Robert long lat, lon, ht; 31219c2daa00SOllivier Robert double Lat, Lon, Ht; 31229c2daa00SOllivier Robert 31239c2daa00SOllivier Robert 31249c2daa00SOllivier Robert lat = buf_w32(&buf[4]); 31259c2daa00SOllivier Robert lon = buf_w32(&buf[8]); 31269c2daa00SOllivier Robert ht = buf_w32(&buf[12]); /* GPS ellipsoid */ 31279c2daa00SOllivier Robert 31289c2daa00SOllivier Robert Lat = lat; 31299c2daa00SOllivier Robert Lon = lon; 31309c2daa00SOllivier Robert Ht = ht; 31319c2daa00SOllivier Robert 31329c2daa00SOllivier Robert Lat /= 3600000; 31339c2daa00SOllivier Robert Lon /= 3600000; 31349c2daa00SOllivier Robert Ht /= 100; 31359c2daa00SOllivier Robert 31362b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 31372b15cb3dSCy Schubert "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, 31382b15cb3dSCy Schubert Lon, Ht); 31399c2daa00SOllivier Robert 31409c2daa00SOllivier Robert instance->ss_lat = lat; 31419c2daa00SOllivier Robert instance->ss_long = lon; 31429c2daa00SOllivier Robert instance->ss_ht = ht; 31439c2daa00SOllivier Robert 31449c2daa00SOllivier Robert oncore_print_posn(instance); 31459c2daa00SOllivier Robert } 31469c2daa00SOllivier Robert 31479c2daa00SOllivier Robert 31489c2daa00SOllivier Robert 31499c2daa00SOllivier Robert /* 12 chan time/date */ 31509c2daa00SOllivier Robert 31519c2daa00SOllivier Robert static void 31529c2daa00SOllivier Robert oncore_msg_Gb( 31539c2daa00SOllivier Robert struct instance *instance, 31549c2daa00SOllivier Robert u_char *buf, 31559c2daa00SOllivier Robert size_t len 31569c2daa00SOllivier Robert ) 31579c2daa00SOllivier Robert { 31582b15cb3dSCy Schubert const char * gmts; 31599c2daa00SOllivier Robert int mo, d, y, h, m, s, gmth, gmtm; 31609c2daa00SOllivier Robert 31619c2daa00SOllivier Robert mo = buf[4]; 31629c2daa00SOllivier Robert d = buf[5]; 31639c2daa00SOllivier Robert y = 256*buf[6]+buf[7]; 31649c2daa00SOllivier Robert 31659c2daa00SOllivier Robert h = buf[8]; 31669c2daa00SOllivier Robert m = buf[9]; 31679c2daa00SOllivier Robert s = buf[10]; 31689c2daa00SOllivier Robert 31699c2daa00SOllivier Robert gmts = ((buf[11] == 0) ? "+" : "-"); 31709c2daa00SOllivier Robert gmth = buf[12]; 31719c2daa00SOllivier Robert gmtm = buf[13]; 31729c2daa00SOllivier Robert 31732b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 31742b15cb3dSCy Schubert "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)", 31752b15cb3dSCy Schubert d, months[mo-1], y, h, m, s, gmts, gmth, gmtm); 31762b15cb3dSCy Schubert } 31772b15cb3dSCy Schubert 31782b15cb3dSCy Schubert 31792b15cb3dSCy Schubert 31802b15cb3dSCy Schubert /* Response to PPS Control message (M12 and M12+T only ) */ 31812b15cb3dSCy Schubert 31822b15cb3dSCy Schubert static void 31832b15cb3dSCy Schubert oncore_msg_Gc( 31842b15cb3dSCy Schubert struct instance *instance, 31852b15cb3dSCy Schubert u_char *buf, 31862b15cb3dSCy Schubert size_t len 31872b15cb3dSCy Schubert ) 31882b15cb3dSCy Schubert { 31892b15cb3dSCy Schubert const char *tbl[] = {"OFF", "ON", "SATELLITE", "TRAIM" }; 31902b15cb3dSCy Schubert 31912b15cb3dSCy Schubert instance->pps_control_msg_seen = 1; 31922b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "PPS Control set to %s", 31932b15cb3dSCy Schubert tbl[buf[4]]); 31949c2daa00SOllivier Robert } 31959c2daa00SOllivier Robert 31969c2daa00SOllivier Robert 31979c2daa00SOllivier Robert 3198224ba2bdSOllivier Robert /* Leap Second for M12, gives all info from satellite message */ 31999c2daa00SOllivier Robert /* also in UT v3.0 */ 3200224ba2bdSOllivier Robert 3201224ba2bdSOllivier Robert static void 3202224ba2bdSOllivier Robert oncore_msg_Gj( 3203224ba2bdSOllivier Robert struct instance *instance, 3204224ba2bdSOllivier Robert u_char *buf, 3205224ba2bdSOllivier Robert size_t len 3206224ba2bdSOllivier Robert ) 3207224ba2bdSOllivier Robert { 32082b15cb3dSCy Schubert static const char * insrem[2] = { 32092b15cb3dSCy Schubert "removed", 32102b15cb3dSCy Schubert "inserted" 32112b15cb3dSCy Schubert }; 32122b15cb3dSCy Schubert 3213224ba2bdSOllivier Robert int dt; 32142b15cb3dSCy Schubert const char *cp; 32159c2daa00SOllivier Robert 32169c2daa00SOllivier Robert instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */ 3217224ba2bdSOllivier Robert 3218224ba2bdSOllivier Robert /* print the message to verify whats there */ 3219224ba2bdSOllivier Robert 3220224ba2bdSOllivier Robert dt = buf[5] - buf[4]; 3221224ba2bdSOllivier Robert 32222b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 32232b15cb3dSCy Schubert "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", 32242b15cb3dSCy Schubert buf[4], buf[5], 256 * buf[6] + buf[7], buf[8], 32252b15cb3dSCy Schubert buf[9], buf[10], 32262b15cb3dSCy Schubert (buf[14] + 256 * 32272b15cb3dSCy Schubert (buf[13] + 256 * (buf[12] + 256 * buf[11]))), 3228224ba2bdSOllivier Robert buf[15], buf[16], buf[17]); 32292b15cb3dSCy Schubert 32302b15cb3dSCy Schubert /* There seems to be eternal confusion about when a leap second 32312b15cb3dSCy Schubert * takes place. It's the second *before* the new TAI offset 32322b15cb3dSCy Schubert * becomes effective. But since the ONCORE receiver tells us 32332b15cb3dSCy Schubert * just that, we would have to do some time/date calculations to 32342b15cb3dSCy Schubert * get the actual leap second -- that is, the one that is 32352b15cb3dSCy Schubert * deleted or inserted. 32362b15cb3dSCy Schubert * 32372b15cb3dSCy Schubert * Going through all this for a simple log is probably overkill, 32382b15cb3dSCy Schubert * so for fixing bug#1050 the message output is changed to 32392b15cb3dSCy Schubert * reflect the fact that it tells the second after the leap 32402b15cb3dSCy Schubert * second. 32412b15cb3dSCy Schubert */ 32422b15cb3dSCy Schubert if (dt) 32432b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 32442b15cb3dSCy Schubert "Leap second %s (%d) before %04u-%02u-%02u/%02u:%02u:%02u", 32452b15cb3dSCy Schubert insrem[(dt > 0)], dt, 32462b15cb3dSCy Schubert 256u * buf[6] + buf[7], buf[8], buf[9], 3247224ba2bdSOllivier Robert buf[15], buf[16], buf[17]); 3248224ba2bdSOllivier Robert 3249224ba2bdSOllivier Robert /* Only raise warning within a month of the leap second */ 3250224ba2bdSOllivier Robert 3251ea906c41SOllivier Robert instance->pp->leap = LEAP_NOWARNING; 3252ea906c41SOllivier Robert cp = "Set pp.leap to LEAP_NOWARNING"; 3253224ba2bdSOllivier Robert 32549c2daa00SOllivier Robert if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */ 32559c2daa00SOllivier Robert buf[8] == instance->BEHa[4]) { /* month */ 3256224ba2bdSOllivier Robert if (dt) { 3257224ba2bdSOllivier Robert if (dt < 0) { 3258ea906c41SOllivier Robert instance->pp->leap = LEAP_DELSECOND; 3259ea906c41SOllivier Robert cp = "Set pp.leap to LEAP_DELSECOND"; 3260224ba2bdSOllivier Robert } else { 3261ea906c41SOllivier Robert instance->pp->leap = LEAP_ADDSECOND; 3262ea906c41SOllivier Robert cp = "Set pp.leap to LEAP_ADDSECOND"; 3263224ba2bdSOllivier Robert } 3264224ba2bdSOllivier Robert } 3265224ba2bdSOllivier Robert } 32662b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, cp); 3267224ba2bdSOllivier Robert } 3268224ba2bdSOllivier Robert 3269c0b746e5SOllivier Robert 3270c0b746e5SOllivier Robert 32719c2daa00SOllivier Robert /* Power on failure */ 3272224ba2bdSOllivier Robert 3273c0b746e5SOllivier Robert static void 32749c2daa00SOllivier Robert oncore_msg_Sz( 3275c0b746e5SOllivier Robert struct instance *instance, 3276c0b746e5SOllivier Robert u_char *buf, 3277224ba2bdSOllivier Robert size_t len 3278c0b746e5SOllivier Robert ) 3279c0b746e5SOllivier Robert { 32809c2daa00SOllivier Robert if (instance && instance->peer) { 32812b15cb3dSCy Schubert oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On"); 32829c2daa00SOllivier Robert oncore_shutdown(instance->unit, instance->peer); 32839c2daa00SOllivier Robert } 32849c2daa00SOllivier Robert } 32859c2daa00SOllivier Robert 32869c2daa00SOllivier Robert /************** Small Subroutines ***************/ 32879c2daa00SOllivier Robert 32889c2daa00SOllivier Robert 32899c2daa00SOllivier Robert static void 32909c2daa00SOllivier Robert oncore_antenna_report( 32919c2daa00SOllivier Robert struct instance *instance, 32929c2daa00SOllivier Robert enum antenna_state new_state) 32939c2daa00SOllivier Robert { 32942b15cb3dSCy Schubert const char *cp; 32959c2daa00SOllivier Robert 32969c2daa00SOllivier Robert if (instance->ant_state == new_state) 3297c0b746e5SOllivier Robert return; 3298c0b746e5SOllivier Robert 32999c2daa00SOllivier Robert switch (new_state) { 33009c2daa00SOllivier Robert case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break; 33019c2daa00SOllivier Robert case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break; 33029c2daa00SOllivier Robert case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break; 33039c2daa00SOllivier Robert case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break; 33049c2daa00SOllivier Robert default: cp = "GPS antenna: ?"; break; 33059c2daa00SOllivier Robert } 3306c0b746e5SOllivier Robert 33079c2daa00SOllivier Robert instance->ant_state = new_state; 33082b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, cp); 3309224ba2bdSOllivier Robert } 3310224ba2bdSOllivier Robert 3311224ba2bdSOllivier Robert 3312224ba2bdSOllivier Robert 3313224ba2bdSOllivier Robert static void 33149c2daa00SOllivier Robert oncore_chan_test( 33159c2daa00SOllivier Robert struct instance *instance 33169c2daa00SOllivier Robert ) 33179c2daa00SOllivier Robert { 33189c2daa00SOllivier Robert /* subroutine oncore_Cj_id has determined the number of channels from the 33199c2daa00SOllivier Robert * model number of the attached oncore. This is not always correct since 33209c2daa00SOllivier Robert * the oncore could have non-standard firmware. Here we check (independently) by 33219c2daa00SOllivier Robert * trying a 6, 8, and 12 chan command, and see which responds. 33229c2daa00SOllivier Robert * Caution: more than one CAN respond. 33239c2daa00SOllivier Robert * 33249c2daa00SOllivier Robert * This #chan is used by the code rather than that calculated from the model number. 33259c2daa00SOllivier Robert */ 33269c2daa00SOllivier Robert 33279c2daa00SOllivier Robert instance->o_state = ONCORE_CHECK_CHAN; 33282b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN"); 33299c2daa00SOllivier Robert 33309c2daa00SOllivier Robert instance->count3 = 1; 33312b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); 33322b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); 33332b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); 33349c2daa00SOllivier Robert } 33359c2daa00SOllivier Robert 33369c2daa00SOllivier Robert 33379c2daa00SOllivier Robert 33389c2daa00SOllivier Robert /* check for a GOOD Almanac, have we got one yet? */ 33399c2daa00SOllivier Robert 33409c2daa00SOllivier Robert static void 33419c2daa00SOllivier Robert oncore_check_almanac( 33429c2daa00SOllivier Robert struct instance *instance 33439c2daa00SOllivier Robert ) 33449c2daa00SOllivier Robert { 33459c2daa00SOllivier Robert if (instance->chan == 6) { 33469c2daa00SOllivier Robert instance->rsm.bad_almanac = instance->BEHa[64]&0x1; 33479c2daa00SOllivier Robert instance->rsm.bad_fix = instance->BEHa[64]&0x52; 33489c2daa00SOllivier Robert } else if (instance->chan == 8) { 33499c2daa00SOllivier Robert instance->rsm.bad_almanac = instance->BEHa[72]&0x1; 33509c2daa00SOllivier Robert instance->rsm.bad_fix = instance->BEHa[72]&0x52; 33519c2daa00SOllivier Robert } else if (instance->chan == 12) { 3352ea906c41SOllivier Robert int bits1, bits2, bits3; 33539c2daa00SOllivier Robert 33549c2daa00SOllivier Robert bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */ 33559c2daa00SOllivier Robert bits2 = instance->BEHa[130]; 33569c2daa00SOllivier Robert instance->rsm.bad_almanac = (bits2 & 0x80); 33579c2daa00SOllivier Robert instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); 33589c2daa00SOllivier Robert /* too few sat Bad Geom */ 3359ea906c41SOllivier Robert 3360ea906c41SOllivier Robert bits3 = instance->BEHa[141]; /* UTC parameters */ 3361ea906c41SOllivier Robert if (!instance->count5_set && (bits3 & 0xC0)) { 33622b15cb3dSCy Schubert instance->count5 = 4; /* was 2 [Bug 1766] */ 3363ea906c41SOllivier Robert instance->count5_set = 1; 3364ea906c41SOllivier Robert } 33652b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CHECK_ALMANAC 33662b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 33672b15cb3dSCy Schubert "DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x", 33682b15cb3dSCy Schubert instance->BEHa[129], instance->BEHa[130], 33692b15cb3dSCy Schubert bits1, bits2, bits3, 33702b15cb3dSCy Schubert instance->mode == MODE_0D, 33712b15cb3dSCy Schubert instance->mode == MODE_2D, 33722b15cb3dSCy Schubert instance->mode == MODE_3D, 33732b15cb3dSCy Schubert instance->rsm.bad_almanac, 33742b15cb3dSCy Schubert instance->rsm.bad_fix); 3375ea906c41SOllivier Robert } 33769c2daa00SOllivier Robert #endif 33779c2daa00SOllivier Robert } 33789c2daa00SOllivier Robert } 33799c2daa00SOllivier Robert 33809c2daa00SOllivier Robert 33819c2daa00SOllivier Robert 33829c2daa00SOllivier Robert /* check the antenna for changes (did it get unplugged?) */ 33839c2daa00SOllivier Robert 33849c2daa00SOllivier Robert static void 33859c2daa00SOllivier Robert oncore_check_antenna( 33869c2daa00SOllivier Robert struct instance *instance 33879c2daa00SOllivier Robert ) 33889c2daa00SOllivier Robert { 33899c2daa00SOllivier Robert enum antenna_state antenna; /* antenna state */ 33909c2daa00SOllivier Robert 33919c2daa00SOllivier Robert if (instance->chan == 12) 33929c2daa00SOllivier Robert antenna = (instance->BEHa[130] & 0x6 ) >> 1; 33939c2daa00SOllivier Robert else 33949c2daa00SOllivier Robert antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */ 33959c2daa00SOllivier Robert 33969c2daa00SOllivier Robert oncore_antenna_report (instance, antenna); 33979c2daa00SOllivier Robert } 33989c2daa00SOllivier Robert 33999c2daa00SOllivier Robert 34009c2daa00SOllivier Robert 34019c2daa00SOllivier Robert /* 34029c2daa00SOllivier Robert * Check the leap second status once per day. 34039c2daa00SOllivier Robert * 34049c2daa00SOllivier Robert * Note that the ONCORE firmware for the Bj command is wrong at 34059c2daa00SOllivier Robert * least in the VP. 34069c2daa00SOllivier Robert * It starts advertising a LEAP SECOND as soon as the GPS satellite 34079c2daa00SOllivier Robert * data message (page 18, subframe 4) is updated to a date in the 34089c2daa00SOllivier Robert * future, and does not wait for the month that it will occur. 34099c2daa00SOllivier Robert * The event will usually be advertised several months in advance. 34109c2daa00SOllivier Robert * Since there is a one bit flag, there is no way to tell if it is 34119c2daa00SOllivier Robert * this month, or when... 34129c2daa00SOllivier Robert * 34139c2daa00SOllivier Robert * As such, we have the workaround below, of only checking for leap 34149c2daa00SOllivier Robert * seconds with the Bj command in June/December. 34159c2daa00SOllivier Robert * 34169c2daa00SOllivier Robert * The Gj command gives more information, and we can tell in which 34179c2daa00SOllivier Robert * month to apply the correction. 34189c2daa00SOllivier Robert * 34199c2daa00SOllivier Robert * Note that with the VP we COULD read the raw data message, and 34209c2daa00SOllivier Robert * interpret it ourselves, but since this is specific to this receiver 34219c2daa00SOllivier Robert * only, and the above workaround is adequate, we don't bother. 34229c2daa00SOllivier Robert */ 34239c2daa00SOllivier Robert 34249c2daa00SOllivier Robert static void 34259c2daa00SOllivier Robert oncore_check_leap_sec( 34269c2daa00SOllivier Robert struct instance *instance 34279c2daa00SOllivier Robert ) 34289c2daa00SOllivier Robert { 34292b15cb3dSCy Schubert oncore_cmd_Bl[2] = 1; /* just to be sure */ 34309c2daa00SOllivier Robert if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */ 34319c2daa00SOllivier Robert instance->Bj_day = instance->BEHa[5]; 34329c2daa00SOllivier Robert 34339c2daa00SOllivier Robert if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */ 34349c2daa00SOllivier Robert if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) 34352b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 34362b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl)); 34379c2daa00SOllivier Robert return; 34389c2daa00SOllivier Robert } 34399c2daa00SOllivier Robert 34409c2daa00SOllivier Robert if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */ 34419c2daa00SOllivier Robert instance->count4 = 1; 34429c2daa00SOllivier Robert 34432b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); 34449c2daa00SOllivier Robert return; 34459c2daa00SOllivier Robert } 34469c2daa00SOllivier Robert 34479c2daa00SOllivier Robert /* Gj works for some 6/8 chan UT and the M12 */ 34489c2daa00SOllivier Robert /* if no response from Gj in 5 sec, we try Bj */ 34499c2daa00SOllivier Robert /* which isnt implemented in all the GT/UT either */ 34509c2daa00SOllivier Robert 34519c2daa00SOllivier Robert if (instance->count4) { /* delay, waiting for Gj response */ 34529c2daa00SOllivier Robert if (instance->saw_Gj == 1) 34539c2daa00SOllivier Robert instance->count4 = 0; 34549c2daa00SOllivier Robert else if (instance->count4++ > 5) { /* delay, waiting for Gj response */ 34559c2daa00SOllivier Robert instance->saw_Gj = -1; /* didnt see it, will use Bj */ 34569c2daa00SOllivier Robert instance->count4 = 0; 34572b15cb3dSCy Schubert if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) { 34582b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); 34592b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl)); 34602b15cb3dSCy Schubert } 34619c2daa00SOllivier Robert } 34629c2daa00SOllivier Robert } 34639c2daa00SOllivier Robert } 34649c2daa00SOllivier Robert 34659c2daa00SOllivier Robert 34669c2daa00SOllivier Robert 34679c2daa00SOllivier Robert /* check the message checksum, 34689c2daa00SOllivier Robert * buf points to START of message ( @@ ) 34699c2daa00SOllivier Robert * len is length WITH CR/LF. 34709c2daa00SOllivier Robert */ 34719c2daa00SOllivier Robert 34729c2daa00SOllivier Robert static int 34739c2daa00SOllivier Robert oncore_checksum_ok( 34749c2daa00SOllivier Robert u_char *buf, 34759c2daa00SOllivier Robert int len 34769c2daa00SOllivier Robert ) 34779c2daa00SOllivier Robert { 34789c2daa00SOllivier Robert int i, j; 34799c2daa00SOllivier Robert 34809c2daa00SOllivier Robert j = 0; 34819c2daa00SOllivier Robert for (i = 2; i < len-3; i++) 34829c2daa00SOllivier Robert j ^= buf[i]; 34839c2daa00SOllivier Robert 34849c2daa00SOllivier Robert return(j == buf[len-3]); 34859c2daa00SOllivier Robert } 34869c2daa00SOllivier Robert 34879c2daa00SOllivier Robert 34889c2daa00SOllivier Robert 34899c2daa00SOllivier Robert static void 34909c2daa00SOllivier Robert oncore_compute_dH( 34919c2daa00SOllivier Robert struct instance *instance 34929c2daa00SOllivier Robert ) 34939c2daa00SOllivier Robert { 34949c2daa00SOllivier Robert int GPS, MSL; 34959c2daa00SOllivier Robert 34969c2daa00SOllivier Robert /* Here calculate dH = GPS - MSL for output message */ 34979c2daa00SOllivier Robert /* also set Altitude Hold mode if GT */ 34989c2daa00SOllivier Robert 34999c2daa00SOllivier Robert instance->have_dH = 1; 35009c2daa00SOllivier Robert if (instance->chan == 12) { 35019c2daa00SOllivier Robert GPS = buf_w32(&instance->BEHa[39]); 35029c2daa00SOllivier Robert MSL = buf_w32(&instance->BEHa[43]); 35039c2daa00SOllivier Robert } else { 35049c2daa00SOllivier Robert GPS = buf_w32(&instance->BEHa[23]); 35059c2daa00SOllivier Robert MSL = buf_w32(&instance->BEHa[27]); 35069c2daa00SOllivier Robert } 35079c2daa00SOllivier Robert instance->dH = GPS - MSL; 35089c2daa00SOllivier Robert instance->dH /= 100.; 35099c2daa00SOllivier Robert 35109c2daa00SOllivier Robert /* if MSL is not set, the calculation is meaningless */ 35119c2daa00SOllivier Robert 35122b15cb3dSCy Schubert if (MSL) /* not set ! */ 35132b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 35142b15cb3dSCy Schubert "dH = (GPS - MSL) = %.2fm", instance->dH); 35159c2daa00SOllivier Robert } 35169c2daa00SOllivier Robert 35179c2daa00SOllivier Robert 35189c2daa00SOllivier Robert 35199c2daa00SOllivier Robert /* 35209c2daa00SOllivier Robert * try loading Almanac from shmem (where it was copied from shmem_old 35219c2daa00SOllivier Robert */ 35229c2daa00SOllivier Robert 35239c2daa00SOllivier Robert static void 35249c2daa00SOllivier Robert oncore_load_almanac( 35259c2daa00SOllivier Robert struct instance *instance 35269c2daa00SOllivier Robert ) 35279c2daa00SOllivier Robert { 35289c2daa00SOllivier Robert u_char *cp, Cmd[20]; 35299c2daa00SOllivier Robert int n; 35309c2daa00SOllivier Robert struct timeval tv; 35319c2daa00SOllivier Robert struct tm *tm; 35329c2daa00SOllivier Robert 35339c2daa00SOllivier Robert if (!instance->shmem) 35349c2daa00SOllivier Robert return; 35359c2daa00SOllivier Robert 35362b15cb3dSCy Schubert #ifndef ONCORE_VERBOSE_LOAD_ALMANAC 35372b15cb3dSCy Schubert for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 35382b15cb3dSCy Schubert cp += (n + 3)) { 3539ea906c41SOllivier Robert if (!strncmp((char *) cp, "@@Cb", 4) && 35409c2daa00SOllivier Robert oncore_checksum_ok(cp, 33) && 35419c2daa00SOllivier Robert (*(cp+4) == 4 || *(cp+4) == 5)) { 3542a466cc55SCy Schubert refclock_fdwrite(instance->peer, instance->ttyfd, 3543a466cc55SCy Schubert cp, n, "data"); 35449c2daa00SOllivier Robert oncore_print_Cb(instance, cp); 35459c2daa00SOllivier Robert } 35469c2daa00SOllivier Robert } 35472b15cb3dSCy Schubert #else /* ONCORE_VERBOSE_LOAD_ALMANAC follows */ 35482b15cb3dSCy Schubert for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2)); 35492b15cb3dSCy Schubert cp += (n+3)) { 35502b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, "See %c%c%c%c %d", 35512b15cb3dSCy Schubert *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4)); 35529c2daa00SOllivier Robert 35539c2daa00SOllivier Robert if (!strncmp(cp, "@@Cb", 4)) { 35549c2daa00SOllivier Robert oncore_print_Cb(instance, cp); 35559c2daa00SOllivier Robert if (oncore_checksum_ok(cp, 33)) { 35569c2daa00SOllivier Robert if (*(cp+4) == 4 || *(cp+4) == 5) { 35572b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, "GOOD SF"); 35589c2daa00SOllivier Robert write(instance->ttyfd, cp, n); 35599c2daa00SOllivier Robert } else 35602b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, "BAD SF"); 35619c2daa00SOllivier Robert } else 35622b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM"); 35639c2daa00SOllivier Robert } 35649c2daa00SOllivier Robert } 35659c2daa00SOllivier Robert #endif 35669c2daa00SOllivier Robert 35679c2daa00SOllivier Robert /* Must load position and time or the Almanac doesn't do us any good */ 35689c2daa00SOllivier Robert 35699c2daa00SOllivier Robert if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */ 35702b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM"); 35719c2daa00SOllivier Robert for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) { 3572ea906c41SOllivier Robert if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) || 3573ea906c41SOllivier Robert (instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) || 3574ea906c41SOllivier Robert (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) { 35759c2daa00SOllivier Robert int ii, jj, kk; 35769c2daa00SOllivier Robert 35779c2daa00SOllivier Robert instance->posn_set = 1; 35789c2daa00SOllivier Robert ii = buf_w32(cp + 15); 35799c2daa00SOllivier Robert jj = buf_w32(cp + 19); 35809c2daa00SOllivier Robert kk = buf_w32(cp + 23); 35812b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_LOAD_ALMANAC 35822b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, 35832b15cb3dSCy Schubert "SHMEM posn = %ld (%d, %d, %d)", 35842b15cb3dSCy Schubert (long)(cp-instance->shmem), 35852b15cb3dSCy Schubert ii, jj, kk); 3586ea906c41SOllivier Robert #endif 35879c2daa00SOllivier Robert if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */ 35889c2daa00SOllivier Robert instance->ss_lat = ii; 35899c2daa00SOllivier Robert instance->ss_long = jj; 35909c2daa00SOllivier Robert instance->ss_ht = kk; 35919c2daa00SOllivier Robert } 35929c2daa00SOllivier Robert } 35939c2daa00SOllivier Robert } 35949c2daa00SOllivier Robert } 35959c2daa00SOllivier Robert oncore_set_posn(instance); 35969c2daa00SOllivier Robert 35979c2daa00SOllivier Robert /* and set time to time from Computer clock */ 35989c2daa00SOllivier Robert 35992b15cb3dSCy Schubert GETTIMEOFDAY(&tv, 0); 36009c2daa00SOllivier Robert tm = gmtime((const time_t *) &tv.tv_sec); 36012b15cb3dSCy Schubert 36022b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_LOAD_ALMANAC 36032b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, "DATE %d %d %d, %d %d %d", 36042b15cb3dSCy Schubert 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, 36059c2daa00SOllivier Robert tm->tm_hour, tm->tm_min, tm->tm_sec); 36069c2daa00SOllivier Robert #endif 36079c2daa00SOllivier Robert if (instance->chan == 12) { 36089c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb)); 3609ea906c41SOllivier Robert Cmd[-2+4] = tm->tm_mon + 1; 36109c2daa00SOllivier Robert Cmd[-2+5] = tm->tm_mday; 36119c2daa00SOllivier Robert Cmd[-2+6] = (1900+tm->tm_year)/256; 36129c2daa00SOllivier Robert Cmd[-2+7] = (1900+tm->tm_year)%256; 36139c2daa00SOllivier Robert Cmd[-2+8] = tm->tm_hour; 36149c2daa00SOllivier Robert Cmd[-2+9] = tm->tm_min; 36159c2daa00SOllivier Robert Cmd[-2+10] = tm->tm_sec; 36169c2daa00SOllivier Robert Cmd[-2+11] = 0; 36179c2daa00SOllivier Robert Cmd[-2+12] = 0; 36189c2daa00SOllivier Robert Cmd[-2+13] = 0; 36192b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Gb)); 36209c2daa00SOllivier Robert } else { 36219c2daa00SOllivier Robert /* First set GMT offset to zero */ 36229c2daa00SOllivier Robert 36232b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab)); 36249c2daa00SOllivier Robert 36259c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac)); 3626ea906c41SOllivier Robert Cmd[-2+4] = tm->tm_mon + 1; 36279c2daa00SOllivier Robert Cmd[-2+5] = tm->tm_mday; 36289c2daa00SOllivier Robert Cmd[-2+6] = (1900+tm->tm_year)/256; 36299c2daa00SOllivier Robert Cmd[-2+7] = (1900+tm->tm_year)%256; 36302b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ac)); 36319c2daa00SOllivier Robert 36329c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa)); 36339c2daa00SOllivier Robert Cmd[-2+4] = tm->tm_hour; 36349c2daa00SOllivier Robert Cmd[-2+5] = tm->tm_min; 36359c2daa00SOllivier Robert Cmd[-2+6] = tm->tm_sec; 36362b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Aa)); 36379c2daa00SOllivier Robert } 36389c2daa00SOllivier Robert 36392b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac"); 36409c2daa00SOllivier Robert } 36419c2daa00SOllivier Robert 36429c2daa00SOllivier Robert 36439c2daa00SOllivier Robert 36449c2daa00SOllivier Robert /* Almanac data input */ 36459c2daa00SOllivier Robert 36469c2daa00SOllivier Robert static void 36479c2daa00SOllivier Robert oncore_print_Cb( 36489c2daa00SOllivier Robert struct instance *instance, 36499c2daa00SOllivier Robert u_char *cp 36509c2daa00SOllivier Robert ) 36519c2daa00SOllivier Robert { 36522b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_CB 36539c2daa00SOllivier Robert int ii; 36542b15cb3dSCy Schubert char Msg[160], Msg2[10]; 36559c2daa00SOllivier Robert 36562b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, "DEBUG: See: %c%c%c%c", *(cp), 36572b15cb3dSCy Schubert *(cp+1), *(cp+2), *(cp+3)); 36589c2daa00SOllivier Robert 36592b15cb3dSCy Schubert snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4), 36602b15cb3dSCy Schubert *(cp+5)); 36612b15cb3dSCy Schubert for (ii = 0; ii < 33; ii++) { 36622b15cb3dSCy Schubert snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii)); 36632b15cb3dSCy Schubert strlcat(Msg, Msg2, sizeof(Msg)); 36642b15cb3dSCy Schubert } 36652b15cb3dSCy Schubert oncore_log(instance, LOG_DEBUG, Msg); 36662b15cb3dSCy Schubert 36672b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, "Debug: Cb: [%d,%d]", *(cp+4), 36682b15cb3dSCy Schubert *(cp+5)); 36699c2daa00SOllivier Robert #endif 36709c2daa00SOllivier Robert } 36719c2daa00SOllivier Robert 36729c2daa00SOllivier Robert 36739c2daa00SOllivier Robert #if 0 36749c2daa00SOllivier Robert static void 36759c2daa00SOllivier Robert oncore_print_array( 36769c2daa00SOllivier Robert u_char *cp, 36779c2daa00SOllivier Robert int n 36789c2daa00SOllivier Robert ) 36799c2daa00SOllivier Robert { 36809c2daa00SOllivier Robert int jj, i, j, nn; 36819c2daa00SOllivier Robert 36829c2daa00SOllivier Robert nn = 0; 36839c2daa00SOllivier Robert printf("\nTOP\n"); 36849c2daa00SOllivier Robert jj = n/16; 36859c2daa00SOllivier Robert for (j=0; j<jj; j++) { 36869c2daa00SOllivier Robert printf("%4d: ", nn); 36879c2daa00SOllivier Robert nn += 16; 36889c2daa00SOllivier Robert for (i=0; i<16; i++) 36899c2daa00SOllivier Robert printf(" %o", *cp++); 36909c2daa00SOllivier Robert printf("\n"); 36919c2daa00SOllivier Robert } 36929c2daa00SOllivier Robert } 36939c2daa00SOllivier Robert #endif 36949c2daa00SOllivier Robert 36959c2daa00SOllivier Robert 36969c2daa00SOllivier Robert static void 36979c2daa00SOllivier Robert oncore_print_posn( 3698224ba2bdSOllivier Robert struct instance *instance 3699224ba2bdSOllivier Robert ) 3700224ba2bdSOllivier Robert { 37012b15cb3dSCy Schubert char ew, ns; 3702224ba2bdSOllivier Robert double xd, xm, xs, yd, ym, ys, hm, hft; 3703224ba2bdSOllivier Robert int idx, idy, is, imx, imy; 3704224ba2bdSOllivier Robert long lat, lon; 3705c0b746e5SOllivier Robert 37062b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "Posn:"); 3707c0b746e5SOllivier Robert ew = 'E'; 3708c0b746e5SOllivier Robert lon = instance->ss_long; 3709c0b746e5SOllivier Robert if (lon < 0) { 3710c0b746e5SOllivier Robert ew = 'W'; 3711c0b746e5SOllivier Robert lon = -lon; 3712c0b746e5SOllivier Robert } 3713c0b746e5SOllivier Robert 3714c0b746e5SOllivier Robert ns = 'N'; 3715c0b746e5SOllivier Robert lat = instance->ss_lat; 3716c0b746e5SOllivier Robert if (lat < 0) { 3717c0b746e5SOllivier Robert ns = 'S'; 3718c0b746e5SOllivier Robert lat = -lat; 3719c0b746e5SOllivier Robert } 3720c0b746e5SOllivier Robert 3721c0b746e5SOllivier Robert hm = instance->ss_ht/100.; 3722c0b746e5SOllivier Robert hft= hm/0.3048; 3723c0b746e5SOllivier Robert 3724c0b746e5SOllivier Robert xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ 3725c0b746e5SOllivier Robert yd = lon/3600000.; 37262b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 37272b15cb3dSCy Schubert "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", 37282b15cb3dSCy Schubert ns, xd, ew, yd, hm, hft); 3729c0b746e5SOllivier Robert 3730c0b746e5SOllivier Robert idx = xd; 3731c0b746e5SOllivier Robert idy = yd; 3732c0b746e5SOllivier Robert imx = lat%3600000; 3733c0b746e5SOllivier Robert imy = lon%3600000; 3734c0b746e5SOllivier Robert xm = imx/60000.; 3735c0b746e5SOllivier Robert ym = imy/60000.; 37362b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 37372b15cb3dSCy Schubert "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", 37382b15cb3dSCy Schubert ns, idx, xm, ew, idy, ym, hm, hft); 3739c0b746e5SOllivier Robert 3740c0b746e5SOllivier Robert imx = xm; 3741c0b746e5SOllivier Robert imy = ym; 3742c0b746e5SOllivier Robert is = lat%60000; 3743c0b746e5SOllivier Robert xs = is/1000.; 3744c0b746e5SOllivier Robert is = lon%60000; 3745c0b746e5SOllivier Robert ys = is/1000.; 37462b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 37472b15cb3dSCy Schubert "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", 37482b15cb3dSCy Schubert ns, idx, imx, xs, ew, idy, imy, ys, hm, hft); 3749a151a66cSOllivier Robert } 3750c0b746e5SOllivier Robert 3751c0b746e5SOllivier Robert 3752a151a66cSOllivier Robert 3753a151a66cSOllivier Robert /* 37549c2daa00SOllivier Robert * write message to Oncore. 3755a151a66cSOllivier Robert */ 3756224ba2bdSOllivier Robert 3757a151a66cSOllivier Robert static void 37589c2daa00SOllivier Robert oncore_sendmsg( 37592b15cb3dSCy Schubert struct instance *instance, 37609c2daa00SOllivier Robert u_char *ptr, 3761224ba2bdSOllivier Robert size_t len 3762a151a66cSOllivier Robert ) 3763a151a66cSOllivier Robert { 37642b15cb3dSCy Schubert int fd; 37659c2daa00SOllivier Robert u_char cs = 0; 3766a466cc55SCy Schubert const struct peer * peer; 3767a151a66cSOllivier Robert 37682b15cb3dSCy Schubert fd = instance->ttyfd; 3769a466cc55SCy Schubert peer = instance->peer; 37702b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_SENDMSG 37712b15cb3dSCy Schubert if (debug > 4) { 37722b15cb3dSCy Schubert oncore_log_f(instance, LOG_DEBUG, "ONCORE: Send @@%c%c %d", 37732b15cb3dSCy Schubert ptr[0], ptr[1], (int)len); 37742b15cb3dSCy Schubert } 3775ea906c41SOllivier Robert #endif 3776a466cc55SCy Schubert refclock_fdwrite(peer, fd, "@@", (size_t)2, "data"); 3777a466cc55SCy Schubert refclock_fdwrite(peer, fd, ptr, len, "data"); 37789c2daa00SOllivier Robert while (len--) 37799c2daa00SOllivier Robert cs ^= *ptr++; 3780a466cc55SCy Schubert refclock_fdwrite(peer, fd, &cs, (size_t)1, "data"); 3781a466cc55SCy Schubert refclock_fdwrite(peer, fd, "\r\n", (size_t)2, "data"); 37829c2daa00SOllivier Robert } 3783a151a66cSOllivier Robert 3784a151a66cSOllivier Robert 3785c0b746e5SOllivier Robert 37869c2daa00SOllivier Robert static void 37879c2daa00SOllivier Robert oncore_set_posn( 37889c2daa00SOllivier Robert struct instance *instance 37899c2daa00SOllivier Robert ) 37909c2daa00SOllivier Robert { 37919c2daa00SOllivier Robert int mode; 3792ea906c41SOllivier Robert u_char Cmd[20]; 37939c2daa00SOllivier Robert 37949c2daa00SOllivier Robert /* Turn OFF position hold, it needs to be off to set position (for some units), 37959c2daa00SOllivier Robert will get set ON in @@Ea later */ 37969c2daa00SOllivier Robert 37979c2daa00SOllivier Robert if (instance->chan == 12) 37982b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */ 37999c2daa00SOllivier Robert else { 38002b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */ 38012b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */ 38029c2daa00SOllivier Robert } 38039c2daa00SOllivier Robert 38049c2daa00SOllivier Robert mode = instance->init_type; 38059c2daa00SOllivier Robert 38069c2daa00SOllivier Robert if (mode != 0) { /* first set posn hold position */ 38079c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */ 38089c2daa00SOllivier Robert w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 38099c2daa00SOllivier Robert w32_buf(&Cmd[-2+8], (int) instance->ss_long); 38109c2daa00SOllivier Robert w32_buf(&Cmd[-2+12], (int) instance->ss_ht); 38119c2daa00SOllivier Robert Cmd[-2+16] = 0; 38122b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */ 38139c2daa00SOllivier Robert 38149c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au)); 38159c2daa00SOllivier Robert w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 38169c2daa00SOllivier Robert Cmd[-2+8] = 0; 38172b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */ 38189c2daa00SOllivier Robert 38199c2daa00SOllivier Robert /* next set current position */ 38209c2daa00SOllivier Robert 38219c2daa00SOllivier Robert if (instance->chan == 12) { 38229c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga)); 38239c2daa00SOllivier Robert w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 38249c2daa00SOllivier Robert w32_buf(&Cmd[-2+8], (int) instance->ss_long); 38259c2daa00SOllivier Robert w32_buf(&Cmd[-2+12],(int) instance->ss_ht); 38269c2daa00SOllivier Robert Cmd[-2+16] = 0; 38272b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */ 38289c2daa00SOllivier Robert } else { 38299c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad)); 38309c2daa00SOllivier Robert w32_buf(&Cmd[-2+4], (int) instance->ss_lat); 38312b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */ 38329c2daa00SOllivier Robert 38339c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae)); 38349c2daa00SOllivier Robert w32_buf(&Cmd[-2+4], (int) instance->ss_long); 38352b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */ 38369c2daa00SOllivier Robert 38379c2daa00SOllivier Robert memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af)); 38389c2daa00SOllivier Robert w32_buf(&Cmd[-2+4], (int) instance->ss_ht); 38399c2daa00SOllivier Robert Cmd[-2+8] = 0; 38402b15cb3dSCy Schubert oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */ 38419c2daa00SOllivier Robert } 38429c2daa00SOllivier Robert 38439c2daa00SOllivier Robert /* Finally, turn on position hold */ 38449c2daa00SOllivier Robert 38459c2daa00SOllivier Robert if (instance->chan == 12) 38462b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); 38479c2daa00SOllivier Robert else 38482b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); 38499c2daa00SOllivier Robert } 38509c2daa00SOllivier Robert } 38519c2daa00SOllivier Robert 38529c2daa00SOllivier Robert 38539c2daa00SOllivier Robert 38549c2daa00SOllivier Robert static void 38559c2daa00SOllivier Robert oncore_set_traim( 38569c2daa00SOllivier Robert struct instance *instance 38579c2daa00SOllivier Robert ) 38589c2daa00SOllivier Robert { 38599c2daa00SOllivier Robert if (instance->traim_in != -1) /* set in Input */ 38609c2daa00SOllivier Robert instance->traim = instance->traim_in; 38619c2daa00SOllivier Robert else 38629c2daa00SOllivier Robert instance->traim = instance->traim_ck; 38639c2daa00SOllivier Robert 38642b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Input says TRAIM = %d", 38652b15cb3dSCy Schubert instance->traim_in); 38662b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Model # says TRAIM = %d", 38672b15cb3dSCy Schubert instance->traim_id); 38682b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Testing says TRAIM = %d", 38692b15cb3dSCy Schubert instance->traim_ck); 38702b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, "Using TRAIM = %d", 38712b15cb3dSCy Schubert instance->traim); 38729c2daa00SOllivier Robert 38739c2daa00SOllivier Robert if (instance->traim_ck == 1 && instance->traim == 0) { 38749c2daa00SOllivier Robert /* if it should be off, and I turned it on during testing, 38759c2daa00SOllivier Robert then turn it off again */ 38769c2daa00SOllivier Robert if (instance->chan == 6) 38772b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx)); 38789c2daa00SOllivier Robert else if (instance->chan == 8) 38792b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx)); 38809c2daa00SOllivier Robert else /* chan == 12 */ 38812b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0)); 38822b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0)); 38839c2daa00SOllivier Robert } 3884c0b746e5SOllivier Robert } 3885c0b746e5SOllivier Robert 3886a151a66cSOllivier Robert 3887a151a66cSOllivier Robert 3888a151a66cSOllivier Robert /* 38899c2daa00SOllivier Robert * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. 3890a151a66cSOllivier Robert */ 3891224ba2bdSOllivier Robert 3892a151a66cSOllivier Robert static void 38939c2daa00SOllivier Robert oncore_shmem_get_3D( 38949c2daa00SOllivier Robert struct instance *instance 3895a151a66cSOllivier Robert ) 3896a151a66cSOllivier Robert { 38979c2daa00SOllivier Robert if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */ 38989c2daa00SOllivier Robert instance->shmem_reset = 1; 38999c2daa00SOllivier Robert if (instance->chan == 12) { 39009c2daa00SOllivier Robert if (instance->shmem_Posn == 2) 39012b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ 39029c2daa00SOllivier Robert else 39032b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ 39049c2daa00SOllivier Robert } else { 39059c2daa00SOllivier Robert if (instance->saw_At) { /* out of 0D -> 3D mode */ 39062b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); 39079c2daa00SOllivier Robert if (instance->shmem_Posn == 2) /* 3D -> 2D mode */ 39082b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 39099c2daa00SOllivier Robert } else 39102b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 39119c2daa00SOllivier Robert } 39129c2daa00SOllivier Robert } else if (instance->shmem_reset || (instance->mode != MODE_0D)) { 39139c2daa00SOllivier Robert instance->shmem_reset = 0; 39149c2daa00SOllivier Robert if (instance->chan == 12) 39152b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */ 39169c2daa00SOllivier Robert else { 39179c2daa00SOllivier Robert if (instance->saw_At) { 39189c2daa00SOllivier Robert if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */ 39192b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); 39202b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ 39219c2daa00SOllivier Robert } else 39222b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); 39239c2daa00SOllivier Robert } 39249c2daa00SOllivier Robert } 3925a151a66cSOllivier Robert } 3926224ba2bdSOllivier Robert 39279c2daa00SOllivier Robert 39289c2daa00SOllivier Robert 39299c2daa00SOllivier Robert /* 39309c2daa00SOllivier Robert * Here we do the Software SiteSurvey. 39319c2daa00SOllivier Robert * We have to average our own position for the Position Hold Mode 39329c2daa00SOllivier Robert * We use Heights from the GPS ellipsoid. 39339c2daa00SOllivier Robert * We check for the END of either HW or SW SiteSurvey. 39349c2daa00SOllivier Robert */ 39359c2daa00SOllivier Robert 3936224ba2bdSOllivier Robert static void 39379c2daa00SOllivier Robert oncore_ss( 39389c2daa00SOllivier Robert struct instance *instance 3939224ba2bdSOllivier Robert ) 3940224ba2bdSOllivier Robert { 39419c2daa00SOllivier Robert double lat, lon, ht; 3942224ba2bdSOllivier Robert 39439c2daa00SOllivier Robert 39449c2daa00SOllivier Robert if (instance->site_survey == ONCORE_SS_HW) { 39459c2daa00SOllivier Robert /* 39469c2daa00SOllivier Robert * Check to see if Hardware SiteSurvey has Finished. 39479c2daa00SOllivier Robert */ 39489c2daa00SOllivier Robert 39499c2daa00SOllivier Robert if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) || 39509c2daa00SOllivier Robert (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) { 39512b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "Now in 0D mode"); 39529c2daa00SOllivier Robert 39539c2daa00SOllivier Robert if (instance->chan == 12) 39542b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax)); 39559c2daa00SOllivier Robert else 39562b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); 39579c2daa00SOllivier Robert 39582b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 39599c2daa00SOllivier Robert instance->site_survey = ONCORE_SS_DONE; 39609c2daa00SOllivier Robert } 39619c2daa00SOllivier Robert } else { 39629c2daa00SOllivier Robert /* 39639c2daa00SOllivier Robert * Must be a Software Site Survey. 39649c2daa00SOllivier Robert */ 39659c2daa00SOllivier Robert 39669c2daa00SOllivier Robert if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ 39679c2daa00SOllivier Robert return; 39689c2daa00SOllivier Robert 39699c2daa00SOllivier Robert if (instance->mode != MODE_3D) /* Use only 3D Fixes */ 39709c2daa00SOllivier Robert return; 39719c2daa00SOllivier Robert 39729c2daa00SOllivier Robert instance->ss_lat += buf_w32(&instance->BEHa[15]); 39739c2daa00SOllivier Robert instance->ss_long += buf_w32(&instance->BEHa[19]); 39749c2daa00SOllivier Robert instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */ 39759c2daa00SOllivier Robert instance->ss_count++; 39769c2daa00SOllivier Robert 39779c2daa00SOllivier Robert if (instance->ss_count != POS_HOLD_AVERAGE) 39789c2daa00SOllivier Robert return; 39799c2daa00SOllivier Robert 39809c2daa00SOllivier Robert instance->ss_lat /= POS_HOLD_AVERAGE; 39819c2daa00SOllivier Robert instance->ss_long /= POS_HOLD_AVERAGE; 39829c2daa00SOllivier Robert instance->ss_ht /= POS_HOLD_AVERAGE; 39839c2daa00SOllivier Robert 39842b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 39852b15cb3dSCy Schubert "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)", 39862b15cb3dSCy Schubert instance->ss_lat, instance->ss_long, 39872b15cb3dSCy Schubert instance->ss_ht); 39889c2daa00SOllivier Robert lat = instance->ss_lat/3600000.; 39899c2daa00SOllivier Robert lon = instance->ss_long/3600000.; 39909c2daa00SOllivier Robert ht = instance->ss_ht/100; 39912b15cb3dSCy Schubert oncore_log_f(instance, LOG_NOTICE, 39922b15cb3dSCy Schubert "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)", 39939c2daa00SOllivier Robert lat, lon, ht); 39949c2daa00SOllivier Robert 39959c2daa00SOllivier Robert oncore_set_posn(instance); 39969c2daa00SOllivier Robert 39972b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "Now in 0D mode"); 39989c2daa00SOllivier Robert 39992b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE"); 40009c2daa00SOllivier Robert instance->site_survey = ONCORE_SS_DONE; 4001224ba2bdSOllivier Robert } 4002224ba2bdSOllivier Robert } 4003224ba2bdSOllivier Robert 40049c2daa00SOllivier Robert 40059c2daa00SOllivier Robert 40069c2daa00SOllivier Robert static int 40079c2daa00SOllivier Robert oncore_wait_almanac( 40089c2daa00SOllivier Robert struct instance *instance 40099c2daa00SOllivier Robert ) 40109c2daa00SOllivier Robert { 40119c2daa00SOllivier Robert if (instance->rsm.bad_almanac) { 40122b15cb3dSCy Schubert instance->counta++; 40132b15cb3dSCy Schubert if (instance->counta%5 == 0) 40142b15cb3dSCy Schubert oncore_log(instance, LOG_INFO, "Waiting for Almanac"); 40159c2daa00SOllivier Robert 40169c2daa00SOllivier Robert /* 40179c2daa00SOllivier Robert * If we get here (first time) then we don't have an almanac in memory. 40189c2daa00SOllivier Robert * Check if we have a SHMEM, and if so try to load whatever is there. 40199c2daa00SOllivier Robert */ 40209c2daa00SOllivier Robert 40219c2daa00SOllivier Robert if (!instance->almanac_from_shmem) { 40229c2daa00SOllivier Robert instance->almanac_from_shmem = 1; 40239c2daa00SOllivier Robert oncore_load_almanac(instance); 40249c2daa00SOllivier Robert } 40259c2daa00SOllivier Robert return(1); 40269c2daa00SOllivier Robert } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn 40279c2daa00SOllivier Robert commands, and can finally check for TRAIM. Again, we set a delay 40289c2daa00SOllivier Robert (5sec) and wait for things to settle down */ 40299c2daa00SOllivier Robert 40309c2daa00SOllivier Robert if (instance->chan == 6) 40312b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); 40329c2daa00SOllivier Robert else if (instance->chan == 8) 40332b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En)); 40349c2daa00SOllivier Robert else if (instance->chan == 12) { 40352b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */ 40362b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */ 40372b15cb3dSCy Schubert oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */ 40389c2daa00SOllivier Robert } 40399c2daa00SOllivier Robert instance->traim_delay = 1; 40409c2daa00SOllivier Robert 40412b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC"); 40429c2daa00SOllivier Robert 40439c2daa00SOllivier Robert instance->o_state = ONCORE_RUN; 40442b15cb3dSCy Schubert oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN"); 40459c2daa00SOllivier Robert } 40469c2daa00SOllivier Robert return(0); 40479c2daa00SOllivier Robert } 40489c2daa00SOllivier Robert 40499c2daa00SOllivier Robert 40502d4e511cSCy Schubert static void 40512d4e511cSCy Schubert oncore_feed_clockproc( 40522d4e511cSCy Schubert struct instance * instance 40532d4e511cSCy Schubert ) 40542d4e511cSCy Schubert { 40552d4e511cSCy Schubert struct peer * const peer = instance->peer; 40562d4e511cSCy Schubert struct refclockproc * const pp = instance->pp; 40572d4e511cSCy Schubert 40582d4e511cSCy Schubert TCivilDate cd; /* calendar date + time */ 40592d4e511cSCy Schubert TGpsDatum gd; /* GPS datum, remapped into NTP epoch */ 40602d4e511cSCy Schubert l_fp fp; /* the reference time in NTP format */ 40612d4e511cSCy Schubert 40622d4e511cSCy Schubert if (pp->year >= 1980) { 40632d4e511cSCy Schubert /* There are oncore receivers that run in a fixed 40642d4e511cSCy Schubert * (possibly shifted) GPS era and fold back into that 40652d4e511cSCy Schubert * era on every GPS week rollover. 40662d4e511cSCy Schubert * 40672d4e511cSCy Schubert * We do not trust the date we get and remap to a GPS 40682d4e511cSCy Schubert * era defined by the GPS base date (derived from the 40692d4e511cSCy Schubert * build time stamp or a 'tos basedate' config option. 40702d4e511cSCy Schubert */ 40712d4e511cSCy Schubert ZERO(fp); /* has a zero to begin with */ 40722d4e511cSCy Schubert ZERO(cd); /* month == monthday == 0 -> use year+yearday */ 40732d4e511cSCy Schubert cd.year = pp->year; 40742d4e511cSCy Schubert cd.yearday = pp->day; 40752d4e511cSCy Schubert cd.hour = pp->hour; 40762d4e511cSCy Schubert cd.minute = pp->minute; 40772d4e511cSCy Schubert cd.second = pp->second; 40782d4e511cSCy Schubert 40792d4e511cSCy Schubert /* the magic happens in the next line: */ 40802d4e511cSCy Schubert gd = gpscal_from_calendar(&cd, fp); /* fp should be zero here */ 40812d4e511cSCy Schubert 40822d4e511cSCy Schubert /* To avoid the trouble the day-of-year calculations in 40832d4e511cSCy Schubert * 'refclock_process()' can cause we feed the time 40842d4e511cSCy Schubert * stamps we have now directly. This also saves us two 40852d4e511cSCy Schubert * full calendar calendar conversion cycles. 40862d4e511cSCy Schubert */ 40872d4e511cSCy Schubert fp = ntpfp_from_gpsdatum(&gd); 40882d4e511cSCy Schubert refclock_process_offset(pp, fp, pp->lastrec, pp->fudgetime1); 40892d4e511cSCy Schubert } else { 40902d4e511cSCy Schubert /* This is obviously a bad date/time... */ 40912d4e511cSCy Schubert refclock_report(peer, CEVNT_BADDATE); 40922d4e511cSCy Schubert peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */ 40932d4e511cSCy Schubert return; 40942d4e511cSCy Schubert } 40952d4e511cSCy Schubert } 40969c2daa00SOllivier Robert 40972b15cb3dSCy Schubert static void 40982b15cb3dSCy Schubert oncore_log ( 40992b15cb3dSCy Schubert struct instance *instance, 41002b15cb3dSCy Schubert int log_level, 41012b15cb3dSCy Schubert const char *msg 41022b15cb3dSCy Schubert ) 41032b15cb3dSCy Schubert { 41042b15cb3dSCy Schubert msyslog(log_level, "ONCORE[%d]: %s", instance->unit, msg); 41052b15cb3dSCy Schubert mprintf_clock_stats(&instance->peer->srcadr, "ONCORE[%d]: %s", 41062b15cb3dSCy Schubert instance->unit, msg); 41072b15cb3dSCy Schubert } 41082b15cb3dSCy Schubert 41092b15cb3dSCy Schubert 41102b15cb3dSCy Schubert static int 41112b15cb3dSCy Schubert oncore_log_f( 41122b15cb3dSCy Schubert struct instance * instance, 41132b15cb3dSCy Schubert int log_level, 41142b15cb3dSCy Schubert const char * fmt, 41152b15cb3dSCy Schubert ... 41162b15cb3dSCy Schubert ) 41172b15cb3dSCy Schubert { 41182b15cb3dSCy Schubert va_list ap; 41192b15cb3dSCy Schubert int rc; 41202b15cb3dSCy Schubert char msg[512]; 41212b15cb3dSCy Schubert 41222b15cb3dSCy Schubert va_start(ap, fmt); 41232b15cb3dSCy Schubert rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 41242b15cb3dSCy Schubert va_end(ap); 41252b15cb3dSCy Schubert oncore_log(instance, log_level, msg); 41262b15cb3dSCy Schubert 41272b15cb3dSCy Schubert #ifdef ONCORE_VERBOSE_ONCORE_LOG 41282b15cb3dSCy Schubert instance->max_len = max(strlen(msg), instance->max_len); 41292b15cb3dSCy Schubert instance->max_count++; 41302b15cb3dSCy Schubert if (instance->max_count % 100 == 0) 41312b15cb3dSCy Schubert oncore_log_f(instance, LOG_INFO, 41322b15cb3dSCy Schubert "Max Message Length so far is %d", 41332b15cb3dSCy Schubert instance->max_len); 41342b15cb3dSCy Schubert #endif 41352b15cb3dSCy Schubert return rc; 41362b15cb3dSCy Schubert } 41372b15cb3dSCy Schubert 4138c0b746e5SOllivier Robert #else 4139*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT 41402b15cb3dSCy Schubert #endif /* REFCLOCK && CLOCK_ONCORE */ 4141