Annotation of embedaddon/ntp/ntpd/refclock_oncore.c, revision 1.1
1.1 ! misho 1: /*
! 2: * ----------------------------------------------------------------------------
! 3: * "THE BEER-WARE LICENSE" (Revision 42):
! 4: * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
! 5: * can do whatever you want with this stuff. If we meet some day, and you think
! 6: * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
! 7: * ----------------------------------------------------------------------------
! 8: *
! 9: * refclock_oncore.c
! 10: *
! 11: * Driver for some of the various the Motorola Oncore GPS receivers.
! 12: * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
! 13: * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
! 14: * than the others.
! 15: * The receivers without position hold (GT, GT+) will be less accurate.
! 16: *
! 17: * Tested with:
! 18: *
! 19: * (UT) (VP)
! 20: * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC.
! 21: * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P
! 22: * SOFTWARE VER # 2 SOFTWARE VER # 8
! 23: * SOFTWARE REV # 2 SOFTWARE REV # 8
! 24: * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996
! 25: * MODEL # R1121N1114 MODEL # B4121P1155
! 26: * HWDR P/N # 1 HDWR P/N # _
! 27: * SERIAL # R0010A SERIAL # SSG0226478
! 28: * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02
! 29: * OPTIONS LIST IB
! 30: *
! 31: * (Basic) (M12)
! 32: * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC.
! 33: * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A
! 34: * SOFTWARE VER # 5 SOFTWARE VER # 1
! 35: * SOFTWARE REV # 0 SOFTWARE REV # 3
! 36: * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000
! 37: * MODEL # A11121P116 MODEL # P143T12NR1
! 38: * HDWR P/N # _ HWDR P/N # 1
! 39: * SERIAL # SSG0049809 SERIAL # P003UD
! 40: * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27
! 41: * OPTIONS LIST AB
! 42: *
! 43: * (M12+T) (M12+T later version)
! 44: * COPYRIGHT 1991-2002 MOTOROLA INC. COPYRIGHT 1991-2003 MOTOROLA INC.
! 45: * SFTW P/N # 61-G10268A SFTW P/N # 61-G10268A
! 46: * SOFTWARE VER # 2 SOFTWARE VER # 2
! 47: * SOFTWARE REV # 0 SOFTWARE REV # 1
! 48: * SOFTWARE DATE AUG 14 2002 SOFTWARE DATE APR 16 2003
! 49: * MODEL # P283T12T11 MODEL # P273T12T12
! 50: * HWDR P/N # 2 HWDR P/N # 2
! 51: * SERIAL # P04DC2 SERIAL # P05Z7Z
! 52: * MANUFACTUR DATE 2J17 MANUFACTUR DATE 3G15
! 53: *
! 54: * --------------------------------------------------------------------------
! 55: * Reg Clemens (June 2009)
! 56: * BUG[1220] OK, big patch, but mostly done mechanically. Change direct calls to write
! 57: * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog.
! 58: * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New
! 59: * routine oncore_log.
! 60: * --------------------------------------------------------------------------
! 61: * Reg Clemens (June 2009)
! 62: * BUG[1218] The comment on where the oncore driver gets its input file does not
! 63: * agree with the code. Change the comment.
! 64: * --------------------------------------------------------------------------
! 65: * Reg Clemens (June 2009)
! 66: * change exit statements to return(0) in main program. I had assumed that if the
! 67: * PPS driver did not start for some reason, we shuould stop NTPD itelf. Others
! 68: * disagree. We now give an ERR log message and stop this driver.
! 69: * --------------------------------------------------------------------------
! 70: * Reg Clemens (June 2009)
! 71: * A bytes available message for the input subsystem (Debug message).
! 72: * --------------------------------------------------------------------------
! 73: * Reg Clemens (Nov 2008)
! 74: * This code adds a message for TRAIM messages. Users often worry about the
! 75: * driver not starting up, and it is often because of signal strength being low.
! 76: * Low signal strength will give TRAIM messages.
! 77: * --------------------------------------------------------------------------
! 78: * Reg Clemens (Nov 2008)
! 79: * Add waiting on Almanac Message.
! 80: * --------------------------------------------------------------------------
! 81: * Reg Clemens (Nov 2008)
! 82: * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs
! 83: * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command
! 84: * that says 'Leap Pending'. As documented it only becomes true in the month
! 85: * before the leap second is to be applied, but in practice at least some of
! 86: * the receivers turn this indicator on as soon as the message is posted, which
! 87: * can be 6months early. As such, we use the Bj command to turn on the
! 88: * instance->pp->leap indicator but only run this test in December and June for
! 89: * updates on 1Jan and 1July.
! 90: *
! 91: * The @@Gj command exists in later ONCOREs, and it gives the exact date
! 92: * and size of the Leap Update. It can be emulated in the VP using the @@Bl
! 93: * command which reads the raw Satellite Broadcast Messages.
! 94: * We use these two commands to print informative messages in the clockstats
! 95: * file once per day as soon as the message appears on the satellites.
! 96: * --------------------------------------------------------------------------
! 97: * Reg Clemens (Feb 2006)
! 98: * Fix some gcc4 compiler complaints
! 99: * Fix possible segfault in oncore_init_shmem
! 100: * change all (possible) fprintf(stderr, to record_clock_stats
! 101: * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
! 102: * immediately after new Almanac Read.
! 103: * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
! 104: * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
! 105: * the new one. Compiles depending on timepps.h seen.
! 106: * --------------------------------------------------------------------------
! 107: * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
! 108: * (the oncore driver was setting the wrong ntpd variable)
! 109: * --------------------------------------------------------------------------
! 110: * Reg.Clemens (Mar 2004)
! 111: * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
! 112: * SCO, you now need to use one of the timepps.h files in the root dir.
! 113: * this driver will 'grab' it for you if you dont have one in /usr/include
! 114: * --------------------------------------------------------------------------
! 115: * This code uses the two devices
! 116: * /dev/oncore.serial.n
! 117: * /dev/oncore.pps.n
! 118: * which may be linked to the same device.
! 119: * and can read initialization data from the file
! 120: * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
! 121: * n or N are the unit number, viz 127.127.30.N.
! 122: * --------------------------------------------------------------------------
! 123: * Reg.Clemens <reg@dwf.com> Sep98.
! 124: * Original code written for FreeBSD.
! 125: * With these mods it works on FreeBSD, SunOS, Solaris and Linux
! 126: * (SunOS 4.1.3 + ppsclock)
! 127: * (Solaris7 + MU4)
! 128: * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
! 129: *
! 130: * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
! 131: * state machine state) are printed to CLOCKSTATS if that file is enabled
! 132: * in /etc/ntp.conf.
! 133: *
! 134: * --------------------------------------------------------------------------
! 135: *
! 136: * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
! 137: * doing an average of 10000 valid 2D and 3D fixes is what the automatic
! 138: * site survey mode does. Looking at the output from the receiver
! 139: * it seems like it is only using 3D fixes.
! 140: * When we do it ourselves, take 10000 3D fixes.
! 141: */
! 142:
! 143: #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */
! 144:
! 145: /*
! 146: * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
! 147: * "STATUS" line in the oncore config file, which contains the most recent
! 148: * copy of all types of messages we recognize. This file can be mmap(2)'ed
! 149: * by monitoring and statistics programs.
! 150: *
! 151: * See separate HTML documentation for this option.
! 152: */
! 153:
! 154: #ifdef HAVE_CONFIG_H
! 155: #include <config.h>
! 156: #endif
! 157:
! 158: #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
! 159:
! 160: #include "ntpd.h"
! 161: #include "ntp_io.h"
! 162: #include "ntp_unixtime.h"
! 163: #include "ntp_refclock.h"
! 164: #include "ntp_stdlib.h"
! 165:
! 166: #include <stdio.h>
! 167: #include <ctype.h>
! 168: #include <sys/stat.h>
! 169: #ifdef ONCORE_SHMEM_STATUS
! 170: # ifdef HAVE_SYS_MMAN_H
! 171: # include <sys/mman.h>
! 172: # ifndef MAP_FAILED
! 173: # define MAP_FAILED ((u_char *) -1)
! 174: # endif /* MAP_FAILED */
! 175: # endif /* HAVE_SYS_MMAN_H */
! 176: #endif /* ONCORE_SHMEM_STATUS */
! 177:
! 178: #ifdef HAVE_PPSAPI
! 179: # include "ppsapi_timepps.h"
! 180: #endif
! 181:
! 182: #ifdef HAVE_SYS_SIO_H
! 183: # include <sys/sio.h>
! 184: #endif
! 185:
! 186: struct Bl {
! 187: int dt_ls;
! 188: int dt_lsf;
! 189: int WN;
! 190: int DN;
! 191: int WN_lsf;
! 192: int DN_lsf;
! 193: int wn_flg;
! 194: int lsf_flg;
! 195: int Bl_day;
! 196: } Bl;
! 197:
! 198: enum receive_state {
! 199: ONCORE_NO_IDEA,
! 200: ONCORE_CHECK_ID,
! 201: ONCORE_CHECK_CHAN,
! 202: ONCORE_HAVE_CHAN,
! 203: ONCORE_RESET_SENT,
! 204: ONCORE_TEST_SENT,
! 205: ONCORE_INIT,
! 206: ONCORE_ALMANAC,
! 207: ONCORE_RUN
! 208: };
! 209:
! 210: enum site_survey_state {
! 211: ONCORE_SS_UNKNOWN,
! 212: ONCORE_SS_TESTING,
! 213: ONCORE_SS_HW,
! 214: ONCORE_SS_SW,
! 215: ONCORE_SS_DONE
! 216: };
! 217:
! 218: enum antenna_state {
! 219: ONCORE_ANTENNA_UNKNOWN = -1,
! 220: ONCORE_ANTENNA_OK = 0,
! 221: ONCORE_ANTENNA_OC = 1,
! 222: ONCORE_ANTENNA_UC = 2,
! 223: ONCORE_ANTENNA_NV = 3
! 224: };
! 225:
! 226: /* Model Name, derived from the @@Cj message.
! 227: * Used to initialize some variables.
! 228: */
! 229:
! 230: enum oncore_model {
! 231: ONCORE_BASIC,
! 232: ONCORE_PVT6,
! 233: ONCORE_VP,
! 234: ONCORE_UT,
! 235: ONCORE_UTPLUS,
! 236: ONCORE_GT,
! 237: ONCORE_GTPLUS,
! 238: ONCORE_SL,
! 239: ONCORE_M12,
! 240: ONCORE_UNKNOWN
! 241: };
! 242:
! 243: /* the bits that describe these properties are in the same place
! 244: * on the VP/UT, but have moved on the M12. As such we extract
! 245: * them, and use them from this struct.
! 246: *
! 247: */
! 248:
! 249: struct RSM {
! 250: u_char posn0D;
! 251: u_char posn2D;
! 252: u_char posn3D;
! 253: u_char bad_almanac;
! 254: u_char bad_fix;
! 255: };
! 256:
! 257: /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
! 258: * see what mode it is in. The bits on the M12 are multiplexed with
! 259: * other messages, so we have to 'keep' the last known mode here.
! 260: */
! 261:
! 262: enum posn_mode {
! 263: MODE_UNKNOWN,
! 264: MODE_0D,
! 265: MODE_2D,
! 266: MODE_3D
! 267: };
! 268:
! 269: struct instance {
! 270: int unit; /* 127.127.30.unit */
! 271: struct refclockproc *pp;
! 272: struct peer *peer;
! 273:
! 274: int ttyfd; /* TTY file descriptor */
! 275: int ppsfd; /* PPS file descriptor */
! 276: int shmemfd; /* Status shm descriptor */
! 277: pps_handle_t pps_h;
! 278: pps_params_t pps_p;
! 279: enum receive_state o_state; /* Receive state */
! 280: enum posn_mode mode; /* 0D, 2D, 3D */
! 281: enum site_survey_state site_survey; /* Site Survey state */
! 282: enum antenna_state ant_state; /* antenna state */
! 283:
! 284: int Bj_day;
! 285:
! 286: u_long delay; /* ns */
! 287: long offset; /* ns */
! 288:
! 289: u_char *shmem;
! 290: char *shmem_fname;
! 291: u_int shmem_Cb;
! 292: u_int shmem_Ba;
! 293: u_int shmem_Ea;
! 294: u_int shmem_Ha;
! 295: u_char shmem_reset;
! 296: u_char shmem_Posn;
! 297: u_char shmem_bad_Ea;
! 298: u_char almanac_from_shmem;
! 299:
! 300: double ss_lat;
! 301: double ss_long;
! 302: double ss_ht;
! 303: double dH;
! 304: int ss_count;
! 305: u_char posn_set;
! 306:
! 307: enum oncore_model model;
! 308: u_int version;
! 309: u_int revision;
! 310:
! 311: u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
! 312: s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
! 313: /* the following 7 are all timing counters */
! 314: u_char traim_delay; /* seconds counter, waiting for reply */
! 315: u_char count; /* cycles thru Ea before starting */
! 316: u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */
! 317: u_char count2; /* cycles thru Ea after count, to check for @@Ea */
! 318: u_char count3; /* cycles thru Ea checking for # channels */
! 319: u_char count4; /* cycles thru leap after Gj to issue Bj */
! 320: u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */
! 321: u_char count5_set; /* only set count5 once */
! 322: u_char counta; /* count for waiting on almanac message */
! 323: u_char pollcnt;
! 324: u_char timeout; /* count to retry Cj after Fa self-test */
! 325: u_char max_len; /* max length message seen by oncore_log, for debugging */
! 326: u_char max_count; /* count for message statistics */
! 327:
! 328: struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */
! 329: struct Bl Bl; /* Satellite Broadcast Data Message */
! 330: u_char printed;
! 331: u_char polled;
! 332: u_long ev_serial;
! 333: int Rcvptr;
! 334: u_char Rcvbuf[500];
! 335: u_char BEHa[160]; /* Ba, Ea or Ha */
! 336: u_char BEHn[80]; /* Bn , En , or Hn */
! 337: u_char Cj[300];
! 338: u_char Ag; /* Satellite mask angle */
! 339: u_char saw_At;
! 340: u_char saw_Ay;
! 341: u_char saw_Az;
! 342: s_char saw_Bj;
! 343: s_char saw_Gj;
! 344: u_char have_dH;
! 345: u_char init_type;
! 346: s_char saw_tooth;
! 347: s_char chan_in; /* chan number from INPUT, will always use it */
! 348: u_char chan_id; /* chan number determined from part number */
! 349: u_char chan_ck; /* chan number determined by sending commands to hardware */
! 350: s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */
! 351: s_char traim_id; /* TRAIM determined from part number */
! 352: u_char traim_ck; /* TRAIM determined by sending commands to hardware */
! 353: u_char once; /* one pass code at top of BaEaHa */
! 354: s_char assert;
! 355: u_char hardpps;
! 356: };
! 357:
! 358: #define rcvbuf instance->Rcvbuf
! 359: #define rcvptr instance->Rcvptr
! 360:
! 361: static int oncore_start (int, struct peer *);
! 362: static void oncore_poll (int, struct peer *);
! 363: static void oncore_shutdown (int, struct peer *);
! 364: static void oncore_consume (struct instance *);
! 365: static void oncore_read_config (struct instance *);
! 366: static void oncore_receive (struct recvbuf *);
! 367: static int oncore_ppsapi (struct instance *);
! 368: static void oncore_get_timestamp (struct instance *, long, long);
! 369: static void oncore_init_shmem (struct instance *);
! 370:
! 371: static void oncore_antenna_report (struct instance *, enum antenna_state);
! 372: static void oncore_chan_test (struct instance *);
! 373: static void oncore_check_almanac (struct instance *);
! 374: static void oncore_check_antenna (struct instance *);
! 375: static void oncore_check_leap_sec (struct instance *);
! 376: static int oncore_checksum_ok (u_char *, int);
! 377: static void oncore_compute_dH (struct instance *);
! 378: static void oncore_load_almanac (struct instance *);
! 379: static void oncore_log (struct instance *, int, const char *);
! 380: static void oncore_print_Cb (struct instance *, u_char *);
! 381: /* static void oncore_print_array (u_char *, int); */
! 382: static void oncore_print_posn (struct instance *);
! 383: static void oncore_sendmsg (struct instance *, u_char *, size_t);
! 384: static void oncore_set_posn (struct instance *);
! 385: static void oncore_set_traim (struct instance *);
! 386: static void oncore_shmem_get_3D (struct instance *);
! 387: static void oncore_ss (struct instance *);
! 388: static int oncore_wait_almanac (struct instance *);
! 389:
! 390: static void oncore_msg_any (struct instance *, u_char *, size_t, int);
! 391: static void oncore_msg_Adef (struct instance *, u_char *, size_t);
! 392: static void oncore_msg_Ag (struct instance *, u_char *, size_t);
! 393: static void oncore_msg_As (struct instance *, u_char *, size_t);
! 394: static void oncore_msg_At (struct instance *, u_char *, size_t);
! 395: static void oncore_msg_Ay (struct instance *, u_char *, size_t);
! 396: static void oncore_msg_Az (struct instance *, u_char *, size_t);
! 397: static void oncore_msg_BaEaHa (struct instance *, u_char *, size_t);
! 398: static void oncore_msg_Bd (struct instance *, u_char *, size_t);
! 399: static void oncore_msg_Bj (struct instance *, u_char *, size_t);
! 400: static void oncore_msg_Bl (struct instance *, u_char *, size_t);
! 401: static void oncore_msg_BnEnHn (struct instance *, u_char *, size_t);
! 402: static void oncore_msg_CaFaIa (struct instance *, u_char *, size_t);
! 403: static void oncore_msg_Cb (struct instance *, u_char *, size_t);
! 404: static void oncore_msg_Cf (struct instance *, u_char *, size_t);
! 405: static void oncore_msg_Cj (struct instance *, u_char *, size_t);
! 406: static void oncore_msg_Cj_id (struct instance *, u_char *, size_t);
! 407: static void oncore_msg_Cj_init (struct instance *, u_char *, size_t);
! 408: static void oncore_msg_Ga (struct instance *, u_char *, size_t);
! 409: static void oncore_msg_Gb (struct instance *, u_char *, size_t);
! 410: static void oncore_msg_Gj (struct instance *, u_char *, size_t);
! 411: static void oncore_msg_Sz (struct instance *, u_char *, size_t);
! 412:
! 413: struct refclock refclock_oncore = {
! 414: oncore_start, /* start up driver */
! 415: oncore_shutdown, /* shut down driver */
! 416: oncore_poll, /* transmit poll message */
! 417: noentry, /* not used */
! 418: noentry, /* not used */
! 419: noentry, /* not used */
! 420: NOFLAGS /* not used */
! 421: };
! 422:
! 423: /*
! 424: * Understanding the next bit here is not easy unless you have a manual
! 425: * for the the various Oncore Models.
! 426: */
! 427:
! 428: static struct msg_desc {
! 429: const char flag[3];
! 430: const int len;
! 431: void (*handler) (struct instance *, u_char *, size_t);
! 432: const char *fmt;
! 433: int shmem;
! 434: } oncore_messages[] = {
! 435: /* Ea and En first since they're most common */
! 436: { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
! 437: { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
! 438: { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
! 439: { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
! 440: { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
! 441: { "Hn", 78, oncore_msg_BnEnHn, "" },
! 442: { "Ab", 10, 0, "" },
! 443: { "Ac", 11, 0, "" },
! 444: { "Ad", 11, oncore_msg_Adef, "" },
! 445: { "Ae", 11, oncore_msg_Adef, "" },
! 446: { "Af", 15, oncore_msg_Adef, "" },
! 447: { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */
! 448: { "As", 20, oncore_msg_As, "" },
! 449: { "At", 8, oncore_msg_At, "" },
! 450: { "Au", 12, 0, "" },
! 451: { "Av", 8, 0, "" },
! 452: { "Aw", 8, 0, "" },
! 453: { "Ay", 11, oncore_msg_Ay, "" },
! 454: { "Az", 11, oncore_msg_Az, "" },
! 455: { "AB", 8, 0, "" },
! 456: { "Bb", 92, 0, "" },
! 457: { "Bd", 23, oncore_msg_Bd, "" },
! 458: { "Bj", 8, oncore_msg_Bj, "" },
! 459: { "Bl", 41, oncore_msg_Bl, "" },
! 460: { "Ca", 9, oncore_msg_CaFaIa, "" },
! 461: { "Cb", 33, oncore_msg_Cb, "" },
! 462: { "Cf", 7, oncore_msg_Cf, "" },
! 463: { "Cg", 8, 0, "" },
! 464: { "Ch", 9, 0, "" },
! 465: { "Cj", 294, oncore_msg_Cj, "" },
! 466: { "Ek", 71, 0, "" },
! 467: { "Fa", 9, oncore_msg_CaFaIa, "" },
! 468: { "Ga", 20, oncore_msg_Ga, "" },
! 469: { "Gb", 17, oncore_msg_Gb, "" },
! 470: { "Gc", 8, 0, "" },
! 471: { "Gd", 8, 0, "" },
! 472: { "Ge", 8, 0, "" },
! 473: { "Gj", 21, oncore_msg_Gj, "" },
! 474: { "Ia", 10, oncore_msg_CaFaIa, "" },
! 475: { "Sz", 8, oncore_msg_Sz, "" },
! 476: { {0}, 7, 0, "" }
! 477: };
! 478:
! 479:
! 480: static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */
! 481: static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */
! 482: static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */
! 483: static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */
! 484: static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */
! 485: static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */
! 486: static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */
! 487: static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */
! 488: static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */
! 489: 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 */
! 490: static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */
! 491: 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */
! 492: 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */
! 493: static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */
! 494: static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */
! 495: static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */
! 496: static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */
! 497: static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */
! 498: static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */
! 499: static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */
! 500: static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */
! 501: static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */
! 502: static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */
! 503: static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */
! 504: static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */
! 505: static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */
! 506: static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */
! 507: static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */
! 508: static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */
! 509: static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */
! 510: static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */
! 511: static u_char oncore_cmd_Bl[] = { 'B', 'l', 1 }; /* VP Satellite Broadcast Data Msg */
! 512: 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 */
! 513: 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 */
! 514: 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 */
! 515: static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */
! 516: static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */
! 517: static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */
! 518: static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */
! 519: static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */
! 520: static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */
! 521: static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */
! 522: 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 */
! 523: 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 */
! 524: 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 */
! 525: static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */
! 526: static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */
! 527: static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */
! 528: 0xff, 0xff, 0xff, 0xff, /* */
! 529: 0xff, 0xff, 0xff, 0xff, 0xff }; /* */
! 530: static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */
! 531: static u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */
! 532: static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */
! 533: static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */
! 534: static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */
! 535: static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */
! 536: static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */
! 537: static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */
! 538: static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */
! 539: static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */
! 540: static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */
! 541: static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */
! 542: static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */
! 543: static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */
! 544:
! 545: /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
! 546: * the GT had Au,Av, but not As,At
! 547: * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
! 548: * Bj in UT at v1.3
! 549: * dont see Bd in UT/GT thru 1999
! 550: * Gj in UT as of 3.0, 1999 , Bj as of 1.3
! 551: */
! 552:
! 553: static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
! 554: "Aug", "Sep", "Oct", "Nov", "Dec" };
! 555:
! 556: #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */
! 557: #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */
! 558:
! 559: #define SPEED B9600 /* Oncore Binary speed (9600 bps) */
! 560:
! 561: /*
! 562: * Assemble and disassemble 32bit signed quantities from a buffer.
! 563: *
! 564: */
! 565:
! 566: /* to buffer, int w, u_char *buf */
! 567: #define w32_buf(buf,w) { u_int i_tmp; \
! 568: i_tmp = (w<0) ? (~(-w)+1) : (w); \
! 569: (buf)[0] = (i_tmp >> 24) & 0xff; \
! 570: (buf)[1] = (i_tmp >> 16) & 0xff; \
! 571: (buf)[2] = (i_tmp >> 8) & 0xff; \
! 572: (buf)[3] = (i_tmp ) & 0xff; \
! 573: }
! 574:
! 575: #define w32(buf) (((buf)[0]&0xff) << 24 | \
! 576: ((buf)[1]&0xff) << 16 | \
! 577: ((buf)[2]&0xff) << 8 | \
! 578: ((buf)[3]&0xff) )
! 579:
! 580: /* from buffer, char *buf, result to an int */
! 581: #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
! 582:
! 583:
! 584: /*
! 585: * oncore_start - initialize data for processing
! 586: */
! 587:
! 588: static int
! 589: oncore_start(
! 590: int unit,
! 591: struct peer *peer
! 592: )
! 593: {
! 594: #define STRING_LEN 32
! 595: register struct instance *instance;
! 596: struct refclockproc *pp;
! 597: int fd1, fd2;
! 598: char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
! 599: struct stat stat1, stat2;
! 600:
! 601: /* create instance structure for this unit */
! 602:
! 603: instance = emalloc(sizeof(*instance));
! 604: memset(instance, 0, sizeof(*instance));
! 605:
! 606: /* initialize miscellaneous variables */
! 607:
! 608: pp = peer->procptr;
! 609: pp->unitptr = (caddr_t) instance;
! 610: instance->pp = pp;
! 611: instance->unit = unit;
! 612: instance->peer = peer;
! 613: instance->assert = 1;
! 614: instance->once = 1;
! 615:
! 616: instance->Bj_day = -1;
! 617: instance->traim = -1;
! 618: instance->traim_in = -1;
! 619: instance->chan_in = -1;
! 620: instance->model = ONCORE_UNKNOWN;
! 621: instance->mode = MODE_UNKNOWN;
! 622: instance->site_survey = ONCORE_SS_UNKNOWN;
! 623: instance->Ag = 0xff; /* Satellite mask angle, unset by user */
! 624: instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
! 625:
! 626: peer->precision = -26;
! 627: peer->minpoll = 4;
! 628: peer->maxpoll = 4;
! 629: pp->clockdesc = "Motorola Oncore GPS Receiver";
! 630: memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
! 631:
! 632: oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING");
! 633: instance->o_state = ONCORE_NO_IDEA;
! 634: oncore_log(instance, LOG_NOTICE, "state = ONCORE_NO_IDEA");
! 635:
! 636: /* Now open files.
! 637: * This is a bit complicated, a we dont want to open the same file twice
! 638: * (its a problem on some OS), and device2 may not exist for the new PPS
! 639: */
! 640:
! 641: (void)snprintf(device1, sizeof(device1), DEVICE1, unit);
! 642: (void)snprintf(device2, sizeof(device2), DEVICE2, unit);
! 643:
! 644: /* OPEN DEVICES */
! 645: /* opening different devices for fd1 and fd2 presents no problems */
! 646: /* opening the SAME device twice, seems to be OS dependent.
! 647: (a) on Linux (no streams) no problem
! 648: (b) on SunOS (and possibly Solaris, untested), (streams)
! 649: never see the line discipline.
! 650: Since things ALWAYS work if we only open the device once, we check
! 651: to see if the two devices are in fact the same, then proceed to
! 652: do one open or two.
! 653:
! 654: For use with linuxPPS we assume that the N_TTY file has been opened
! 655: and that the line discipline has been changed to N_PPS by another
! 656: program (say ppsldisc) so that the two files expected by the oncore
! 657: driver can be opened.
! 658:
! 659: Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do
! 660: the stat below without error even though the file has already had its
! 661: line discipline changed by another process.
! 662:
! 663: The Windows port of ntpd arranges to return duplicate handles for
! 664: multiple opens of the same serial device, and doesn't have inodes
! 665: for serial handles, so we just open both on Windows.
! 666: */
! 667: #ifndef SYS_WINNT
! 668: if (stat(device1, &stat1)) {
! 669: snprintf(Msg, sizeof(Msg), "Can't stat fd1 (%s)",
! 670: device1);
! 671: oncore_log(instance, LOG_ERR, Msg);
! 672: return(0); /* exit, no file, can't start driver */
! 673: }
! 674:
! 675: if (stat(device2, &stat2)) {
! 676: stat2.st_dev = stat2.st_ino = -2;
! 677: snprintf(Msg, sizeof(Msg),
! 678: "Can't stat fd2 (%s) errno = %d",
! 679: device2, errno);
! 680: oncore_log(instance, LOG_ERR, Msg);
! 681: }
! 682: #endif /* !SYS_WINNT */
! 683:
! 684: if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
! 685: snprintf(Msg, sizeof(Msg), "Can't open fd1 (%s)",
! 686: device1);
! 687: oncore_log(instance, LOG_ERR, Msg);
! 688: return(0); /* exit, can't open file, can't start driver */
! 689: }
! 690:
! 691: /* for LINUX the PPS device is the result of a line discipline.
! 692: It seems simplest to let an external program create the appropriate
! 693: /dev/pps<n> file, and only check (carefully) for its existance here
! 694: */
! 695:
! 696: #ifndef SYS_WINNT
! 697: if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */
! 698: fd2 = fd1;
! 699: else
! 700: #endif /* !SYS_WINNT */
! 701: { /* different devices here */
! 702: if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) {
! 703: snprintf(Msg, sizeof(Msg),
! 704: "Can't open fd2 (%s)", device2);
! 705: oncore_log(instance, LOG_ERR, Msg);
! 706: return(0); /* exit, can't open PPS file, can't start driver */
! 707: }
! 708: }
! 709:
! 710: /* open ppsapi source */
! 711:
! 712: if (time_pps_create(fd2, &instance->pps_h) < 0) {
! 713: oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel");
! 714: return(0); /* exit, don't find PPSAPI in kernel */
! 715: }
! 716:
! 717: /* continue initialization */
! 718:
! 719: instance->ttyfd = fd1;
! 720: instance->ppsfd = fd2;
! 721:
! 722: /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
! 723:
! 724: oncore_read_config(instance);
! 725:
! 726: if (!oncore_ppsapi(instance))
! 727: return(0);
! 728:
! 729: pp->io.clock_recv = oncore_receive;
! 730: pp->io.srcclock = (caddr_t)peer;
! 731: pp->io.datalen = 0;
! 732: pp->io.fd = fd1;
! 733: if (!io_addclock(&pp->io)) {
! 734: oncore_log(instance, LOG_ERR, "can't do io_addclock");
! 735: (void) close(fd1);
! 736: free(instance);
! 737: return (0);
! 738: }
! 739:
! 740: #ifdef ONCORE_SHMEM_STATUS
! 741: /*
! 742: * Before starting ONCORE, lets setup SHMEM
! 743: * This will include merging an old SHMEM into the new one if
! 744: * an old one is found.
! 745: */
! 746:
! 747: oncore_init_shmem(instance);
! 748: #endif
! 749:
! 750: /*
! 751: * This will return the Model of the Oncore receiver.
! 752: * and start the Initialization loop in oncore_msg_Cj.
! 753: */
! 754:
! 755: instance->o_state = ONCORE_CHECK_ID;
! 756: oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID");
! 757:
! 758: instance->timeout = 4;
! 759: oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
! 760: oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
! 761:
! 762: instance->pollcnt = 2;
! 763: return (1);
! 764: }
! 765:
! 766:
! 767: /*
! 768: * oncore_shutdown - shut down the clock
! 769: */
! 770:
! 771: static void
! 772: oncore_shutdown(
! 773: int unit,
! 774: struct peer *peer
! 775: )
! 776: {
! 777: register struct instance *instance;
! 778: struct refclockproc *pp;
! 779:
! 780: pp = peer->procptr;
! 781: instance = (struct instance *) pp->unitptr;
! 782:
! 783: io_closeclock(&pp->io);
! 784:
! 785: time_pps_destroy (instance->pps_h);
! 786:
! 787: close(instance->ttyfd);
! 788:
! 789: if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
! 790: close(instance->ppsfd);
! 791:
! 792: if (instance->shmemfd)
! 793: close(instance->shmemfd);
! 794:
! 795: free(instance);
! 796: }
! 797:
! 798:
! 799:
! 800: /*
! 801: * oncore_poll - called by the transmit procedure
! 802: */
! 803:
! 804: static void
! 805: oncore_poll(
! 806: int unit,
! 807: struct peer *peer
! 808: )
! 809: {
! 810: struct instance *instance;
! 811:
! 812: instance = (struct instance *) peer->procptr->unitptr;
! 813: if (instance->timeout) {
! 814: instance->timeout--;
! 815: if (instance->timeout == 0) {
! 816: oncore_log(instance, LOG_ERR,
! 817: "Oncore: No response from @@Cj, shutting down driver");
! 818: oncore_shutdown(unit, peer);
! 819: } else {
! 820: oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
! 821: oncore_log(instance, LOG_WARNING, "Oncore: Resend @@Cj");
! 822: }
! 823: return;
! 824: }
! 825:
! 826: if (!instance->pollcnt)
! 827: refclock_report(peer, CEVNT_TIMEOUT);
! 828: else
! 829: instance->pollcnt--;
! 830: peer->procptr->polls++;
! 831: instance->polled = 1;
! 832: }
! 833:
! 834:
! 835:
! 836: /*
! 837: * Initialize PPSAPI
! 838: */
! 839:
! 840: static int
! 841: oncore_ppsapi(
! 842: struct instance *instance
! 843: )
! 844: {
! 845: int cap, mode, mode1;
! 846: char *cp, Msg[160];
! 847:
! 848: if (time_pps_getcap(instance->pps_h, &cap) < 0) {
! 849: msnprintf(Msg, sizeof(Msg), "time_pps_getcap failed: %m");
! 850: oncore_log(instance, LOG_ERR, Msg);
! 851: return (0);
! 852: }
! 853:
! 854: if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
! 855: msnprintf(Msg, sizeof(Msg), "time_pps_getparams failed: %m");
! 856: oncore_log(instance, LOG_ERR, Msg);
! 857: return (0);
! 858: }
! 859:
! 860: /* nb. only turn things on, if someone else has turned something
! 861: * on before we get here, leave it alone!
! 862: */
! 863:
! 864: if (instance->assert) {
! 865: cp = "Assert";
! 866: mode = PPS_CAPTUREASSERT;
! 867: mode1 = PPS_OFFSETASSERT;
! 868: } else {
! 869: cp = "Clear";
! 870: mode = PPS_CAPTURECLEAR;
! 871: mode1 = PPS_OFFSETCLEAR;
! 872: }
! 873: snprintf(Msg, sizeof(Msg), "Initializing timing to %s.", cp);
! 874: oncore_log(instance, LOG_INFO, Msg);
! 875:
! 876: if (!(mode & cap)) {
! 877: snprintf(Msg, sizeof(Msg),
! 878: "Can't set timing to %s, exiting...", cp);
! 879: oncore_log(instance, LOG_ERR, Msg);
! 880: return(0);
! 881: }
! 882:
! 883: if (!(mode1 & cap)) {
! 884: snprintf(Msg, sizeof(Msg),
! 885: "Can't set %s, this will increase jitter.", cp);
! 886: oncore_log(instance, LOG_NOTICE, Msg);
! 887: mode1 = 0;
! 888: }
! 889:
! 890: /* only set what is legal */
! 891:
! 892: instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
! 893:
! 894: if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
! 895: oncore_log(instance, LOG_ERR, "ONCORE: time_pps_setparams fails");
! 896: return(0); /* exit, can't do time_pps_setparans on PPS file */
! 897: }
! 898:
! 899: /* If HARDPPS is on, we tell kernel */
! 900:
! 901: if (instance->hardpps) {
! 902: int i;
! 903:
! 904: oncore_log(instance, LOG_INFO, "HARDPPS Set.");
! 905:
! 906: if (instance->assert)
! 907: i = PPS_CAPTUREASSERT;
! 908: else
! 909: i = PPS_CAPTURECLEAR;
! 910:
! 911: /* we know that 'i' is legal from above */
! 912:
! 913: if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
! 914: PPS_TSFMT_TSPEC) < 0) {
! 915: msnprintf(Msg, sizeof(Msg), "time_pps_kcbind failed: %m");
! 916: oncore_log(instance, LOG_ERR, Msg);
! 917: oncore_log(instance, LOG_ERR, "HARDPPS failed, abort...");
! 918: return (0);
! 919: }
! 920:
! 921: pps_enable = 1;
! 922: }
! 923: return(1);
! 924: }
! 925:
! 926:
! 927:
! 928: #ifdef ONCORE_SHMEM_STATUS
! 929: static void
! 930: oncore_init_shmem(
! 931: struct instance *instance
! 932: )
! 933: {
! 934: int i, l, n, fd, shmem_old_size, n1;
! 935: char Msg[160];
! 936: u_char *cp, *cp1, *buf, *shmem_old;
! 937: struct msg_desc *mp;
! 938: struct stat sbuf;
! 939: size_t shmem_length;
! 940:
! 941: /*
! 942: * The first thing we do is see if there is an instance->shmem_fname file (still)
! 943: * out there from a previous run. If so, we copy it in and use it to initialize
! 944: * shmem (so we won't lose our almanac if we need it).
! 945: */
! 946:
! 947: shmem_old = 0;
! 948: shmem_old_size = 0;
! 949: if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
! 950: oncore_log(instance, LOG_WARNING, "ONCORE: Can't open SHMEM file");
! 951: else {
! 952: fstat(fd, &sbuf);
! 953: shmem_old_size = sbuf.st_size;
! 954: if (shmem_old_size != 0) {
! 955: shmem_old = emalloc((unsigned) sbuf.st_size);
! 956: read(fd, shmem_old, shmem_old_size);
! 957: }
! 958: close(fd);
! 959: }
! 960:
! 961: /* OK, we now create the NEW SHMEM. */
! 962:
! 963: if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
! 964: oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem");
! 965: if (shmem_old)
! 966: free(shmem_old);
! 967:
! 968: return;
! 969: }
! 970:
! 971: /* see how big it needs to be */
! 972:
! 973: n = 1;
! 974: for (mp=oncore_messages; mp->flag[0]; mp++) {
! 975: mp->shmem = n;
! 976: /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
! 977: if (!strcmp(mp->flag, "Cb")) {
! 978: instance->shmem_Cb = n;
! 979: n += (mp->len + 3) * 34;
! 980: }
! 981: if (!strcmp(mp->flag, "Ba")) {
! 982: instance->shmem_Ba = n;
! 983: n += (mp->len + 3) * 3;
! 984: }
! 985: if (!strcmp(mp->flag, "Ea")) {
! 986: instance->shmem_Ea = n;
! 987: n += (mp->len + 3) * 3;
! 988: }
! 989: if (!strcmp(mp->flag, "Ha")) {
! 990: instance->shmem_Ha = n;
! 991: n += (mp->len + 3) * 3;
! 992: }
! 993: n += (mp->len + 3);
! 994: }
! 995: shmem_length = n + 2;
! 996:
! 997: buf = emalloc(shmem_length);
! 998: memset(buf, 0, shmem_length);
! 999:
! 1000: /* next build the new SHMEM buffer in memory */
! 1001:
! 1002: for (mp=oncore_messages; mp->flag[0]; mp++) {
! 1003: l = mp->shmem;
! 1004: buf[l + 0] = mp->len >> 8;
! 1005: buf[l + 1] = mp->len & 0xff;
! 1006: buf[l + 2] = 0;
! 1007: buf[l + 3] = '@';
! 1008: buf[l + 4] = '@';
! 1009: buf[l + 5] = mp->flag[0];
! 1010: buf[l + 6] = mp->flag[1];
! 1011: if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
! 1012: if (!strcmp(mp->flag, "Cb"))
! 1013: n = 35;
! 1014: else
! 1015: n = 4;
! 1016: for (i=1; i<n; i++) {
! 1017: buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
! 1018: buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
! 1019: buf[l + i * (mp->len+3) + 2] = 0;
! 1020: buf[l + i * (mp->len+3) + 3] = '@';
! 1021: buf[l + i * (mp->len+3) + 4] = '@';
! 1022: buf[l + i * (mp->len+3) + 5] = mp->flag[0];
! 1023: buf[l + i * (mp->len+3) + 6] = mp->flag[1];
! 1024: }
! 1025: }
! 1026: }
! 1027:
! 1028: /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
! 1029: * copying the data in shmem_old to buf.
! 1030: * When we are done we write it out and free both buffers.
! 1031: * If the structure sizes dont agree, I will not copy.
! 1032: * This could be due to an addition/deletion or a problem with the disk file.
! 1033: */
! 1034:
! 1035: if (shmem_old) {
! 1036: if (shmem_old_size == shmem_length) {
! 1037: for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) {
! 1038: n1 = 256*(*(cp1-3)) + *(cp1-2);
! 1039: if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
! 1040: break;
! 1041:
! 1042: memcpy(cp, cp1, (size_t) n);
! 1043: }
! 1044: }
! 1045: free(shmem_old);
! 1046: }
! 1047:
! 1048: i = write(instance->shmemfd, buf, shmem_length);
! 1049: free(buf);
! 1050:
! 1051: if (i != shmem_length) {
! 1052: oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem");
! 1053: close(instance->shmemfd);
! 1054: return;
! 1055: }
! 1056:
! 1057: instance->shmem = (u_char *) mmap(0, shmem_length,
! 1058: PROT_READ | PROT_WRITE,
! 1059: #ifdef MAP_HASSEMAPHORE
! 1060: MAP_HASSEMAPHORE |
! 1061: #endif
! 1062: MAP_SHARED, instance->shmemfd, (off_t)0);
! 1063:
! 1064: if (instance->shmem == (u_char *)MAP_FAILED) {
! 1065: instance->shmem = 0;
! 1066: close(instance->shmemfd);
! 1067: return;
! 1068: }
! 1069:
! 1070: snprintf(Msg, sizeof(Msg),
! 1071: "SHMEM (size = %ld) is CONFIGURED and available as %s",
! 1072: (u_long) shmem_length, instance->shmem_fname);
! 1073: oncore_log(instance, LOG_NOTICE, Msg);
! 1074: }
! 1075: #endif /* ONCORE_SHMEM_STATUS */
! 1076:
! 1077:
! 1078:
! 1079: /*
! 1080: * Read Input file if it exists.
! 1081: */
! 1082:
! 1083: static void
! 1084: oncore_read_config(
! 1085: struct instance *instance
! 1086: )
! 1087: {
! 1088: /*
! 1089: * First we try to open the configuration file
! 1090: * /etc/ntp.oncore.N
! 1091: * where N is the unit number viz 127.127.30.N.
! 1092: * If we don't find it we try
! 1093: * /etc/ntp.oncoreN
! 1094: * and then
! 1095: * /etc/ntp.oncore
! 1096: *
! 1097: * If we don't find any then we don't have the cable delay or PPS offset
! 1098: * and we choose MODE (4) below.
! 1099: *
! 1100: * Five Choices for MODE
! 1101: * (0) ONCORE is preinitialized, don't do anything to change it.
! 1102: * nb, DON'T set 0D mode, DON'T set Delay, position...
! 1103: * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
! 1104: * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
! 1105: * lock this in, go to 0D mode.
! 1106: * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
! 1107: * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
! 1108: * lock this in, go to 0D mode.
! 1109: * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
! 1110: * then this position is set as the INITIAL position of the ONCORE.
! 1111: * This can reduce the time to first fix.
! 1112: * -------------------------------------------------------------------------------
! 1113: * Note that an Oncore UT without a battery backup retains NO information if it is
! 1114: * power cycled, with a Battery Backup it remembers the almanac, etc.
! 1115: * For an Oncore VP, there is an eeprom that will contain this data, along with the
! 1116: * option of Battery Backup.
! 1117: * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
! 1118: * power cycle, since there is nowhere to store the data.
! 1119: * -------------------------------------------------------------------------------
! 1120: *
! 1121: * If we open one or the other of the files, we read it looking for
! 1122: * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
! 1123: * STATUS, POSN3D, POSN2D, CHAN, TRAIM
! 1124: * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must
! 1125: * be present or mode reverts to (2,4).
! 1126: *
! 1127: * Read input file.
! 1128: *
! 1129: * # is comment to end of line
! 1130: * = allowed between 1st and 2nd fields.
! 1131: *
! 1132: * Expect to see one line with 'MODE' as first field, followed by an integer
! 1133: * in the range 0-4 (default = 4).
! 1134: *
! 1135: * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
! 1136: * All numbers are floating point.
! 1137: * DDD.ddd
! 1138: * DDD MMM.mmm
! 1139: * DDD MMM SSS.sss
! 1140: *
! 1141: * Expect to see one line with 'HT' as first field,
! 1142: * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'
! 1143: * for feet or meters. HT is the height above the GPS ellipsoid.
! 1144: * If the receiver reports height in both GPS and MSL, then we will report
! 1145: * the difference GPS-MSL on the clockstats file.
! 1146: *
! 1147: * There is an optional line, starting with DELAY, followed
! 1148: * by 1 or two fields. The first is a number (a time) the second is
! 1149: * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
! 1150: * DELAY is cable delay, typically a few tens of ns.
! 1151: *
! 1152: * There is an optional line, starting with OFFSET, followed
! 1153: * by 1 or two fields. The first is a number (a time) the second is
! 1154: * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
! 1155: * OFFSET is the offset of the PPS pulse from 0. (only fully implemented
! 1156: * with the PPSAPI, we need to be able to tell the Kernel about this
! 1157: * offset if the Kernel PLL is in use, but can only do this presently
! 1158: * when using the PPSAPI interface. If not using the Kernel PLL,
! 1159: * then there is no problem.
! 1160: *
! 1161: * There is an optional line, with either ASSERT or CLEAR on it, which
! 1162: * determine which transition of the PPS signal is used for timing by the
! 1163: * PPSAPI. If neither is present, then ASSERT is assumed.
! 1164: * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
! 1165: * For Flag2, ASSERT=0, and hence is default.
! 1166: *
! 1167: * There is an optional line, with HARDPPS on it. Including this line causes
! 1168: * the PPS signal to control the kernel PLL.
! 1169: * HARDPPS can also be set with FLAG3 of the ntp.conf input.
! 1170: * For Flag3, 0 is disabled, and the default.
! 1171: *
! 1172: * There are three options that have to do with using the shared memory option.
! 1173: * First, to enable the option there must be a SHMEM line with a file name.
! 1174: * The file name is the file associated with the shared memory.
! 1175: *
! 1176: * In shared memory, there is one 'record' for each returned variable.
! 1177: * For the @@Ea data there are three 'records' containing position data.
! 1178: * There will always be data in the record corresponding to the '0D' @@Ea record,
! 1179: * and the user has a choice of filling the '3D' record by specifying POSN3D,
! 1180: * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D'
! 1181: * record is filled once every 15s.
! 1182: *
! 1183: * Two additional variables that can be set are CHAN and TRAIM. These should be
! 1184: * set correctly by the code examining the @@Cj record, but we bring them out here
! 1185: * to allow the user to override either the # of channels, or the existence of TRAIM.
! 1186: * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
! 1187: * followed by YES or NO.
! 1188: *
! 1189: * There is an optional line with MASK on it followed by one integer field in the
! 1190: * range 0 to 89. This sets the satellite mask angle and will determine the minimum
! 1191: * elevation angle for satellites to be tracked by the receiver. The default value
! 1192: * is 10 deg for the VP and 0 deg for all other receivers.
! 1193: *
! 1194: * So acceptable input would be
! 1195: * # these are my coordinates (RWC)
! 1196: * LON -106 34.610
! 1197: * LAT 35 08.999
! 1198: * HT 1589 # could equally well say HT 5215 FT
! 1199: * DELAY 60 ns
! 1200: */
! 1201:
! 1202: FILE *fd;
! 1203: char *cp, *cc, *ca, line[100], units[2], device[64], Msg[160], **cpp;
! 1204: char *dirs[] = { "/etc/ntp", "/etc", 0 };
! 1205: int i, sign, lat_flg, long_flg, ht_flg, mode, mask;
! 1206: double f1, f2, f3;
! 1207:
! 1208: fd = NULL; /* just to shutup gcc complaint */
! 1209: for (cpp=dirs; *cpp; cpp++) {
! 1210: cp = *cpp;
! 1211: snprintf(device, sizeof(device), "%s/ntp.oncore.%d",
! 1212: cp, instance->unit); /* try "ntp.oncore.0 */
! 1213: if ((fd=fopen(device, "r")))
! 1214: break;
! 1215: snprintf(device, sizeof(device), "%s/ntp.oncore%d",
! 1216: cp, instance->unit); /* try "ntp.oncore0" */
! 1217: if ((fd=fopen(device, "r")))
! 1218: break;
! 1219: snprintf(device, sizeof(device), "%s/ntp.oncore", cp);
! 1220: if ((fd=fopen(device, "r"))) /* last try "ntp.oncore" */
! 1221: break;
! 1222: }
! 1223:
! 1224: if (!fd) { /* no inputfile, default to the works ... */
! 1225: instance->init_type = 4;
! 1226: return;
! 1227: }
! 1228:
! 1229: mode = mask = 0;
! 1230: lat_flg = long_flg = ht_flg = 0;
! 1231: while (fgets(line, 100, fd)) {
! 1232:
! 1233: /* Remove comments */
! 1234: if ((cp = strchr(line, '#')))
! 1235: *cp = '\0';
! 1236:
! 1237: /* Remove trailing space */
! 1238: for (i = strlen(line);
! 1239: i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
! 1240: )
! 1241: line[--i] = '\0';
! 1242:
! 1243: /* Remove leading space */
! 1244: for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
! 1245: continue;
! 1246:
! 1247: /* Stop if nothing left */
! 1248: if (!*cc)
! 1249: continue;
! 1250:
! 1251: /* Uppercase the command and find the arg */
! 1252: for (ca = cc; *ca; ca++) {
! 1253: if (isascii((int)*ca)) {
! 1254: if (islower((int)*ca)) {
! 1255: *ca = toupper(*ca);
! 1256: } else if (isspace((int)*ca) || (*ca == '='))
! 1257: break;
! 1258: }
! 1259: }
! 1260:
! 1261: /* Remove space (and possible =) leading the arg */
! 1262: for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
! 1263: continue;
! 1264:
! 1265: if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
! 1266: instance->shmem_fname = estrdup(ca);
! 1267: continue;
! 1268: }
! 1269:
! 1270: /* Uppercase argument as well */
! 1271: for (cp = ca; *cp; cp++)
! 1272: if (isascii((int)*cp) && islower((int)*cp))
! 1273: *cp = toupper(*cp);
! 1274:
! 1275: if (!strncmp(cc, "LAT", (size_t) 3)) {
! 1276: f1 = f2 = f3 = 0;
! 1277: sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
! 1278: sign = 1;
! 1279: if (f1 < 0) {
! 1280: f1 = -f1;
! 1281: sign = -1;
! 1282: }
! 1283: instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
! 1284: lat_flg++;
! 1285: } else if (!strncmp(cc, "LON", (size_t) 3)) {
! 1286: f1 = f2 = f3 = 0;
! 1287: sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
! 1288: sign = 1;
! 1289: if (f1 < 0) {
! 1290: f1 = -f1;
! 1291: sign = -1;
! 1292: }
! 1293: instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
! 1294: long_flg++;
! 1295: } else if (!strncmp(cc, "HT", (size_t) 2)) {
! 1296: f1 = 0;
! 1297: units[0] = '\0';
! 1298: sscanf(ca, "%lf %1s", &f1, units);
! 1299: if (units[0] == 'F')
! 1300: f1 = 0.3048 * f1;
! 1301: instance->ss_ht = 100 * f1; /* cm */
! 1302: ht_flg++;
! 1303: } else if (!strncmp(cc, "DELAY", (size_t) 5)) {
! 1304: f1 = 0;
! 1305: units[0] = '\0';
! 1306: sscanf(ca, "%lf %1s", &f1, units);
! 1307: if (units[0] == 'N')
! 1308: ;
! 1309: else if (units[0] == 'U')
! 1310: f1 = 1000 * f1;
! 1311: else if (units[0] == 'M')
! 1312: f1 = 1000000 * f1;
! 1313: else
! 1314: f1 = 1000000000 * f1;
! 1315: if (f1 < 0 || f1 > 1.e9)
! 1316: f1 = 0;
! 1317: if (f1 < 0 || f1 > 999999) {
! 1318: snprintf(Msg, sizeof(Msg),
! 1319: "PPS Cable delay of %fns out of Range, ignored",
! 1320: f1);
! 1321: oncore_log(instance, LOG_WARNING, Msg);
! 1322: } else
! 1323: instance->delay = f1; /* delay in ns */
! 1324: } else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
! 1325: f1 = 0;
! 1326: units[0] = '\0';
! 1327: sscanf(ca, "%lf %1s", &f1, units);
! 1328: if (units[0] == 'N')
! 1329: ;
! 1330: else if (units[0] == 'U')
! 1331: f1 = 1000 * f1;
! 1332: else if (units[0] == 'M')
! 1333: f1 = 1000000 * f1;
! 1334: else
! 1335: f1 = 1000000000 * f1;
! 1336: if (f1 < 0 || f1 > 1.e9)
! 1337: f1 = 0;
! 1338: if (f1 < 0 || f1 > 999999999.) {
! 1339: snprintf(Msg, sizeof(Msg),
! 1340: "PPS Offset of %fns out of Range, ignored",
! 1341: f1);
! 1342: oncore_log(instance, LOG_WARNING, Msg);
! 1343: } else
! 1344: instance->offset = f1; /* offset in ns */
! 1345: } else if (!strncmp(cc, "MODE", (size_t) 4)) {
! 1346: sscanf(ca, "%d", &mode);
! 1347: if (mode < 0 || mode > 4)
! 1348: mode = 4;
! 1349: } else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
! 1350: instance->assert = 1;
! 1351: } else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
! 1352: instance->assert = 0;
! 1353: } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
! 1354: instance->hardpps = 1;
! 1355: } else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
! 1356: instance->shmem_Posn = 2;
! 1357: } else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
! 1358: instance->shmem_Posn = 3;
! 1359: } else if (!strncmp(cc, "CHAN", (size_t) 4)) {
! 1360: sscanf(ca, "%d", &i);
! 1361: if ((i == 6) || (i == 8) || (i == 12))
! 1362: instance->chan_in = i;
! 1363: } else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
! 1364: instance->traim_in = 1; /* so TRAIM alone is YES */
! 1365: if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */
! 1366: instance->traim_in = 0;
! 1367: } else if (!strncmp(cc, "MASK", (size_t) 4)) {
! 1368: sscanf(ca, "%d", &mask);
! 1369: if (mask > -1 && mask < 90)
! 1370: instance->Ag = mask; /* Satellite mask angle */
! 1371: }
! 1372: }
! 1373: fclose(fd);
! 1374:
! 1375: /*
! 1376: * OK, have read all of data file, and extracted the good stuff.
! 1377: * If lat/long/ht specified they ALL must be specified for mode = (1,3).
! 1378: */
! 1379:
! 1380: instance->posn_set = 1;
! 1381: if (!( lat_flg && long_flg && ht_flg )) {
! 1382: snprintf(Msg, sizeof(Msg),
! 1383: "ONCORE: incomplete data on %s", device);
! 1384: oncore_log (instance, LOG_WARNING, Msg);
! 1385: instance->posn_set = 0;
! 1386: if (mode == 1 || mode == 3) {
! 1387: snprintf(Msg, sizeof(Msg),
! 1388: "Input Mode = %d, but no/incomplete position, mode set to %d",
! 1389: mode, mode+1);
! 1390: oncore_log(instance, LOG_WARNING, Msg);
! 1391: mode++;
! 1392: }
! 1393: }
! 1394: instance->init_type = mode;
! 1395:
! 1396: snprintf(Msg, sizeof(Msg), "Input mode = %d", mode);
! 1397: oncore_log(instance, LOG_INFO, Msg);
! 1398: }
! 1399:
! 1400:
! 1401:
! 1402: /*
! 1403: * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
! 1404: */
! 1405:
! 1406: static void
! 1407: oncore_receive(
! 1408: struct recvbuf *rbufp
! 1409: )
! 1410: {
! 1411: size_t i;
! 1412: u_char *p;
! 1413: struct peer *peer;
! 1414: struct instance *instance;
! 1415:
! 1416: peer = (struct peer *)rbufp->recv_srcclock;
! 1417: instance = (struct instance *) peer->procptr->unitptr;
! 1418: p = (u_char *) &rbufp->recv_space;
! 1419:
! 1420: #ifdef ONCORE_VERBOSE_RECEIVE
! 1421: if (debug > 4) {
! 1422: int i;
! 1423: char Msg[120], Msg2[10];
! 1424:
! 1425: snprintf(Msg, sizeof(Msg), ">>> %d bytes available",
! 1426: rbufp->recv_length);
! 1427: oncore_log(instance, LOG_DEBUG, Msg);
! 1428: strncpy(Msg, ">>>", sizeof(Msg));
! 1429: for (i = 0; i < rbufp->recv_length; i++) {
! 1430: snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]);
! 1431: strncat(Msg, Msg2, sizeof(Msg));
! 1432: }
! 1433: oncore_log(instance, LOG_DEBUG, Msg);
! 1434:
! 1435: strncpy(Msg, ">>>", sizeof(Msg));
! 1436: for (i = 0; i < rbufp->recv_length; i++) {
! 1437: snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]);
! 1438: strncat(Msg, Msg2, sizeof(Msg));
! 1439: }
! 1440: oncore_log(instance, LOG_DEBUG, Msg);
! 1441: }
! 1442: #endif
! 1443:
! 1444: i = rbufp->recv_length;
! 1445: if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
! 1446: i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */
! 1447: memcpy(rcvbuf+rcvptr, p, i);
! 1448: rcvptr += i;
! 1449: oncore_consume(instance);
! 1450: }
! 1451:
! 1452:
! 1453:
! 1454: /*
! 1455: * Deal with any complete messages
! 1456: */
! 1457:
! 1458: static void
! 1459: oncore_consume(
! 1460: struct instance *instance
! 1461: )
! 1462: {
! 1463: int i, m;
! 1464: unsigned l;
! 1465:
! 1466: while (rcvptr >= 7) {
! 1467: if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
! 1468: /* We're not in sync, lets try to get there */
! 1469: for (i=1; i < rcvptr-1; i++)
! 1470: if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
! 1471: break;
! 1472: #ifdef ONCORE_VERBOSE_CONSUME
! 1473: if (debug > 4) {
! 1474: char Msg[120];
! 1475:
! 1476: snprintf(Msg, sizeof(Msg),
! 1477: ">>> skipping %d chars", i);
! 1478: oncore_log(instance, LOG_DEBUG, Msg);
! 1479: }
! 1480: #endif
! 1481: if (i != rcvptr)
! 1482: memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
! 1483: rcvptr -= i;
! 1484: continue;
! 1485: }
! 1486:
! 1487: /* Ok, we have a header now */
! 1488: l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
! 1489: for(m=0; m<l; m++)
! 1490: if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
! 1491: break;
! 1492: if (m == l) {
! 1493: #ifdef ONCORE_VERBOSE_CONSUME
! 1494: if (debug > 4) {
! 1495: char Msg[120];
! 1496:
! 1497: snprintf(Msg, sizeof(Msg),
! 1498: ">>> Unknown MSG, skipping 4 (%c%c)",
! 1499: rcvbuf[2], rcvbuf[3]);
! 1500: oncore_log(instance, LOG_DEBUG, Msg);
! 1501: }
! 1502: #endif
! 1503: memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
! 1504: rcvptr -= 4;
! 1505: continue;
! 1506: }
! 1507:
! 1508: l = oncore_messages[m].len;
! 1509: #ifdef ONCORE_VERBOSE_CONSUME
! 1510: if (debug > 3) {
! 1511: char Msg[120];
! 1512:
! 1513: snprintf(Msg, sizeof(Msg),
! 1514: "GOT: %c%c %d of %d entry %d",
! 1515: instance->unit, rcvbuf[2], rcvbuf[3],
! 1516: rcvptr, l, m);
! 1517: oncore_log(instance, LOG_DEBUG, Msg);
! 1518: }
! 1519: #endif
! 1520: /* Got the entire message ? */
! 1521:
! 1522: if (rcvptr < l)
! 1523: return;
! 1524:
! 1525: /* are we at the end of message? should be <Cksum><CR><LF> */
! 1526:
! 1527: if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
! 1528: #ifdef ONCORE_VERBOSE_CONSUME
! 1529: if (debug)
! 1530: oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message");
! 1531: #endif
! 1532: } else { /* check the CheckSum */
! 1533: if (oncore_checksum_ok(rcvbuf, l)) {
! 1534: if (instance->shmem != NULL) {
! 1535: instance->shmem[oncore_messages[m].shmem + 2]++;
! 1536: memcpy(instance->shmem + oncore_messages[m].shmem + 3,
! 1537: rcvbuf, (size_t) l);
! 1538: }
! 1539: oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
! 1540: if (oncore_messages[m].handler)
! 1541: oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
! 1542: }
! 1543: #ifdef ONCORE_VERBOSE_CONSUME
! 1544: else if (debug) {
! 1545: char Msg[120], Msg2[10];
! 1546:
! 1547: oncore_log(instance, LOG_ERR, "Checksum mismatch!");
! 1548: snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]);
! 1549: for (i = 4; i < l; i++) {
! 1550: snprintf(Msg2, sizeof(Msg2),
! 1551: "%03o ", rcvbuf[i]);
! 1552: strncat(Msg, Msg2, sizeof(Msg));
! 1553: }
! 1554: oncore_log(instance, LOG_DEBUG, Msg);
! 1555: }
! 1556: #endif
! 1557: }
! 1558:
! 1559: if (l != rcvptr)
! 1560: memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
! 1561: rcvptr -= l;
! 1562: }
! 1563: }
! 1564:
! 1565:
! 1566:
! 1567: static void
! 1568: oncore_get_timestamp(
! 1569: struct instance *instance,
! 1570: long dt1, /* tick offset THIS time step */
! 1571: long dt2 /* tick offset NEXT time step */
! 1572: )
! 1573: {
! 1574: int Rsm;
! 1575: u_long j;
! 1576: l_fp ts, ts_tmp;
! 1577: double dmy;
! 1578: #ifdef HAVE_STRUCT_TIMESPEC
! 1579: struct timespec *tsp = 0;
! 1580: #else
! 1581: struct timeval *tsp = 0;
! 1582: #endif
! 1583: int current_mode;
! 1584: pps_params_t current_params;
! 1585: struct timespec timeout;
! 1586: struct peer *peer;
! 1587: pps_info_t pps_i;
! 1588: char Msg[140];
! 1589:
! 1590: peer = instance->peer;
! 1591:
! 1592: #if 1
! 1593: /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
! 1594: * If we have Finished the SiteSurvey, then we fall thru for the 14/15
! 1595: * times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
! 1596: * This gives good time, which gets better when the SS is done.
! 1597: */
! 1598:
! 1599: if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) {
! 1600: #else
! 1601: /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
! 1602:
! 1603: if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) {
! 1604: #endif
! 1605: peer->flags &= ~FLAG_PPS;
! 1606: return;
! 1607: }
! 1608:
! 1609: /* Don't do anything without an almanac to define the GPS->UTC delta */
! 1610:
! 1611: if (instance->rsm.bad_almanac) {
! 1612: peer->flags &= ~FLAG_PPS;
! 1613: return;
! 1614: }
! 1615:
! 1616: /* Once the Almanac is valid, the M12+T does not produce valid UTC
! 1617: * immediately.
! 1618: * Wait for UTC offset decode valid, then wait one message more
! 1619: * so we are not off by 13 seconds after reset.
! 1620: */
! 1621:
! 1622: if (instance->count5) {
! 1623: instance->count5--;
! 1624: peer->flags &= ~FLAG_PPS;
! 1625: return;
! 1626: }
! 1627:
! 1628: j = instance->ev_serial;
! 1629: timeout.tv_sec = 0;
! 1630: timeout.tv_nsec = 0;
! 1631: if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
! 1632: &timeout) < 0) {
! 1633: oncore_log(instance, LOG_ERR, "time_pps_fetch failed");
! 1634: peer->flags &= ~FLAG_PPS;
! 1635: return;
! 1636: }
! 1637:
! 1638: if (instance->assert) {
! 1639: tsp = &pps_i.assert_timestamp;
! 1640:
! 1641: #ifdef ONCORE_VERBOSE_GET_TIMESTAMP
! 1642: if (debug > 2) {
! 1643: u_long i;
! 1644:
! 1645: i = (u_long) pps_i.assert_sequence;
! 1646: # ifdef HAVE_STRUCT_TIMESPEC
! 1647: snprintf(Msg, sizeof(Msg),
! 1648: "serial/j (%lu, %lu) %ld.%09ld", i, j,
! 1649: (long)tsp->tv_sec, (long)tsp->tv_nsec);
! 1650: # else
! 1651: snprintf(Msg, sizeof(Msg),
! 1652: "serial/j (%lu, %lu) %ld.%06ld", i, j,
! 1653: (long)tsp->tv_sec, (long)tsp->tv_usec);
! 1654: # endif
! 1655: oncore_log(instance, LOG_DEBUG, Msg);
! 1656: }
! 1657: #endif
! 1658:
! 1659: if (pps_i.assert_sequence == j) {
! 1660: oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps");
! 1661: peer->flags &= ~FLAG_PPS;
! 1662: return;
! 1663: }
! 1664:
! 1665: instance->ev_serial = pps_i.assert_sequence;
! 1666: } else {
! 1667: tsp = &pps_i.clear_timestamp;
! 1668:
! 1669: #if 0
! 1670: if (debug > 2) {
! 1671: u_long i;
! 1672:
! 1673: i = (u_long) pps_i.clear_sequence;
! 1674: # ifdef HAVE_STRUCT_TIMESPEC
! 1675: snprintf(Msg, sizeof(Msg),
! 1676: "serial/j (%lu, %lu) %ld.%09ld", i, j,
! 1677: (long)tsp->tv_sec, (long)tsp->tv_nsec);
! 1678: # else
! 1679: snprintf(Msg. sizeof(Msg),
! 1680: "serial/j (%lu, %lu) %ld.%06ld", i, j,
! 1681: (long)tsp->tv_sec, (long)tsp->tv_usec);
! 1682: # endif
! 1683: oncore_log(instance, LOG_DEBUG, Msg);
! 1684: }
! 1685: #endif
! 1686:
! 1687: if (pps_i.clear_sequence == j) {
! 1688: oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps");
! 1689: peer->flags &= ~FLAG_PPS;
! 1690: return;
! 1691: }
! 1692: instance->ev_serial = pps_i.clear_sequence;
! 1693: }
! 1694:
! 1695: /* convert timespec -> ntp l_fp */
! 1696:
! 1697: dmy = tsp->tv_nsec;
! 1698: dmy /= 1e9;
! 1699: ts.l_uf = dmy * 4294967296.0;
! 1700: ts.l_ui = tsp->tv_sec;
! 1701:
! 1702: #if 0
! 1703: alternate code for previous 4 lines is
! 1704: dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
! 1705: DTOLFP(dmy, &ts);
! 1706: dmy = tsp->tv_sec; /* integer part */
! 1707: DTOLFP(dmy, &ts_tmp);
! 1708: L_ADD(&ts, &ts_tmp);
! 1709: or more simply
! 1710: dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
! 1711: DTOLFP(dmy, &ts);
! 1712: ts.l_ui = tsp->tv_sec;
! 1713: #endif /* 0 */
! 1714:
! 1715: /* now have timestamp in ts */
! 1716: /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
! 1717: /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
! 1718: /* we just try to add them in and dont test for that here */
! 1719:
! 1720: /* saw_tooth not really necessary if using TIMEVAL */
! 1721: /* since its only precise to us, but do it anyway. */
! 1722:
! 1723: /* offset in ns, and is positive (late), we subtract */
! 1724: /* to put the PPS time transition back where it belongs */
! 1725:
! 1726: /* must hand the offset for the NEXT sec off to the Kernel to do */
! 1727: /* the addition, so that the Kernel PLL sees the offset too */
! 1728:
! 1729: if (instance->assert)
! 1730: instance->pps_p.assert_offset.tv_nsec = -dt2;
! 1731: else
! 1732: instance->pps_p.clear_offset.tv_nsec = -dt2;
! 1733:
! 1734: /* The following code is necessary, and not just a time_pps_setparams,
! 1735: * using the saved instance->pps_p, since some other process on the
! 1736: * machine may have diddled with the mode bits (say adding something
! 1737: * that it needs). We take what is there and ADD what we need.
! 1738: * [[ The results from the time_pps_getcap is unlikely to change so
! 1739: * we could probably just save it, but I choose to do the call ]]
! 1740: * Unfortunately, there is only ONE set of mode bits in the kernel per
! 1741: * interface, and not one set for each open handle.
! 1742: *
! 1743: * There is still a race condition here where we might mess up someone
! 1744: * elses mode, but if he is being careful too, he should survive.
! 1745: */
! 1746:
! 1747: if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) {
! 1748: msnprintf(Msg, sizeof(Msg), "time_pps_getcap failed: %m");
! 1749: oncore_log(instance, LOG_ERR, Msg);
! 1750: peer->flags &= ~FLAG_PPS;
! 1751: return;
! 1752: }
! 1753:
! 1754: if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) {
! 1755: msnprintf(Msg, sizeof(Msg), "time_pps_getparams failed: %m");
! 1756: oncore_log(instance, LOG_ERR, Msg);
! 1757: peer->flags &= ~FLAG_PPS;
! 1758: return;
! 1759: }
! 1760:
! 1761: /* or current and mine */
! 1762: current_params.mode |= instance->pps_p.mode;
! 1763: /* but only set whats legal */
! 1764: current_params.mode &= current_mode;
! 1765:
! 1766: current_params.assert_offset.tv_sec = 0;
! 1767: current_params.assert_offset.tv_nsec = -dt2;
! 1768: current_params.clear_offset.tv_sec = 0;
! 1769: current_params.clear_offset.tv_nsec = -dt2;
! 1770:
! 1771: if (time_pps_setparams(instance->pps_h, ¤t_params))
! 1772: oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams");
! 1773:
! 1774: /* have time from UNIX origin, convert to NTP origin. */
! 1775:
! 1776: ts.l_ui += JAN_1970;
! 1777: instance->pp->lastrec = ts;
! 1778:
! 1779: /* print out information about this timestamp (long line) */
! 1780:
! 1781: ts_tmp = ts;
! 1782: ts_tmp.l_ui = 0; /* zero integer part */
! 1783: LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */
! 1784: j = 1.0e9*dmy; /* then to integer ns */
! 1785:
! 1786: Rsm = 0;
! 1787: if (instance->chan == 6)
! 1788: Rsm = instance->BEHa[64];
! 1789: else if (instance->chan == 8)
! 1790: Rsm = instance->BEHa[72];
! 1791: else if (instance->chan == 12)
! 1792: Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
! 1793:
! 1794: if (instance->chan == 6 || instance->chan == 8) {
! 1795: char f1[5], f2[5], f3[5], f4[5];
! 1796: if (instance->traim) {
! 1797: snprintf(f1, sizeof(f1), "%d",
! 1798: instance->BEHn[21]);
! 1799: snprintf(f2, sizeof(f2), "%d",
! 1800: instance->BEHn[22]);
! 1801: snprintf(f3, sizeof(f3), "%2d",
! 1802: instance->BEHn[23] * 256 +
! 1803: instance->BEHn[24]);
! 1804: snprintf(f4, sizeof(f4), "%3d",
! 1805: (s_char)instance->BEHn[25]);
! 1806: } else {
! 1807: strncpy(f1, "x", sizeof(f1));
! 1808: strncpy(f2, "x", sizeof(f2));
! 1809: strncpy(f3, "xx", sizeof(f3));
! 1810: strncpy(f4, "xxx", sizeof(f4));
! 1811: }
! 1812: snprintf(Msg, sizeof(Msg), /* MAX length 128, currently at 127 */
! 1813: "%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",
! 1814: ts.l_ui, j,
! 1815: instance->pp->year, instance->pp->day,
! 1816: instance->pp->hour, instance->pp->minute, instance->pp->second,
! 1817: (long) tsp->tv_sec % 60,
! 1818: Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
! 1819: /*rsat dop */
! 1820: instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2,
! 1821: /* nsat visible, nsat tracked, traim,traim,traim */
! 1822: f3, f4,
! 1823: /* sigma neg-sawtooth */
! 1824: /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
! 1825: instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
! 1826: ); /* will be 0 for 6 chan */
! 1827: } else if (instance->chan == 12) {
! 1828: char f1[5], f2[5], f3[5], f4[5];
! 1829: if (instance->traim) {
! 1830: snprintf(f1, sizeof(f1), "%d",
! 1831: instance->BEHn[6]);
! 1832: snprintf(f2, sizeof(f2), "%d",
! 1833: instance->BEHn[7]);
! 1834: snprintf(f3, sizeof(f3), "%d",
! 1835: instance->BEHn[12] * 256 +
! 1836: instance->BEHn[13]);
! 1837: snprintf(f4, sizeof(f4), "%3d",
! 1838: (s_char)instance->BEHn[14]);
! 1839: } else {
! 1840: strncpy(f1, "x", sizeof(f1));
! 1841: strncpy(f2, "x", sizeof(f2));
! 1842: strncpy(f3, "xx", sizeof(f3));
! 1843: strncpy(f4, "xxx", sizeof(f4));
! 1844: }
! 1845: snprintf(Msg, sizeof(Msg),
! 1846: "%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",
! 1847: ts.l_ui, j,
! 1848: instance->pp->year, instance->pp->day,
! 1849: instance->pp->hour, instance->pp->minute, instance->pp->second,
! 1850: (long) tsp->tv_sec % 60,
! 1851: Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
! 1852: /*rsat dop */
! 1853: instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2,
! 1854: /* nsat visible, nsat tracked traim,traim,traim */
! 1855: f3, f4,
! 1856: /* sigma neg-sawtooth */
! 1857: /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
! 1858: instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
! 1859: instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
! 1860: );
! 1861: }
! 1862:
! 1863: /* and some things I dont understand (magic ntp things) */
! 1864:
! 1865: if (!refclock_process(instance->pp)) {
! 1866: refclock_report(instance->peer, CEVNT_BADTIME);
! 1867: peer->flags &= ~FLAG_PPS;
! 1868: return;
! 1869: }
! 1870:
! 1871: oncore_log(instance, LOG_INFO, Msg); /* this is long message above */
! 1872: instance->pollcnt = 2;
! 1873:
! 1874: if (instance->polled) {
! 1875: instance->polled = 0;
! 1876: /* instance->pp->dispersion = instance->pp->skew = 0; */
! 1877: instance->pp->lastref = instance->pp->lastrec;
! 1878: refclock_receive(instance->peer);
! 1879: }
! 1880: peer->flags |= FLAG_PPS;
! 1881: }
! 1882:
! 1883:
! 1884: /*************** oncore_msg_XX routines start here *******************/
! 1885:
! 1886:
! 1887: /*
! 1888: * print Oncore response message.
! 1889: */
! 1890:
! 1891: static void
! 1892: oncore_msg_any(
! 1893: struct instance *instance,
! 1894: u_char *buf,
! 1895: size_t len,
! 1896: int idx
! 1897: )
! 1898: {
! 1899: #ifdef ONCORE_VERBOSE_MSG_ANY
! 1900: int i;
! 1901: const char *fmt = oncore_messages[idx].fmt;
! 1902: const char *p;
! 1903: char *q;
! 1904: char *qlim;
! 1905: #ifdef HAVE_GETCLOCK
! 1906: struct timespec ts;
! 1907: #endif
! 1908: struct timeval tv;
! 1909: char Msg[120], Msg2[10];
! 1910:
! 1911: if (debug > 3) {
! 1912: # ifdef HAVE_GETCLOCK
! 1913: (void) getclock(TIMEOFDAY, &ts);
! 1914: tv.tv_sec = ts.tv_sec;
! 1915: tv.tv_usec = ts.tv_nsec / 1000;
! 1916: # else
! 1917: GETTIMEOFDAY(&tv, 0);
! 1918: # endif
! 1919: snprintf(Msg, sizeof(Msg), "%ld.%06ld",
! 1920: (long)tv.tv_sec, (long)tv.tv_usec);
! 1921: oncore_log(instance, LOG_DEBUG, Msg);
! 1922:
! 1923: if (!*fmt) {
! 1924: snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2],
! 1925: buf[3]);
! 1926: for(i = 2; i < len && i < 2400 ; i++) {
! 1927: snprintf(Msg2, sizeof(Msg2), "%02x",
! 1928: buf[i]);
! 1929: strncpy(Msg, Msg2, sizeof(Msg));
! 1930:
! 1931: }
! 1932: oncore_log(instance, LOG_DEBUG, Msg);
! 1933: return;
! 1934: } else {
! 1935: strncat(Msg, "##", sizeof(Msg));
! 1936: qlim = Msg + sizeof(Msg) - 3;
! 1937: for (p = fmt, q = Msg + 2; q < qlim && *p; ) {
! 1938: *q++ = *p++;
! 1939: *q++ = '_';
! 1940: }
! 1941: *q = '\0';
! 1942: oncore_log(instance, LOG_DEBUG, Msg);
! 1943: snprintf(Msg, sizeof(Msg), "%c%c", buf[2],
! 1944: buf[3]);
! 1945: i = 4;
! 1946: for (p = fmt; *p; p++) {
! 1947: snprintf(Msg2, "%02x", buf[i++]);
! 1948: strncat(Msg, Msg2, sizeof(Msg));
! 1949: }
! 1950: oncore_log(instance, LOG_DEBUG, Msg);
! 1951: }
! 1952: }
! 1953: #endif
! 1954: }
! 1955:
! 1956:
! 1957:
! 1958: /* Latitude, Longitude, Height */
! 1959:
! 1960: static void
! 1961: oncore_msg_Adef(
! 1962: struct instance *instance,
! 1963: u_char *buf,
! 1964: size_t len
! 1965: )
! 1966: {
! 1967: }
! 1968:
! 1969:
! 1970:
! 1971: /* Mask Angle */
! 1972:
! 1973: static void
! 1974: oncore_msg_Ag(
! 1975: struct instance *instance,
! 1976: u_char *buf,
! 1977: size_t len
! 1978: )
! 1979: { char Msg[160], *cp;
! 1980:
! 1981: cp = "set to";
! 1982: if (instance->o_state == ONCORE_RUN)
! 1983: cp = "is";
! 1984:
! 1985: instance->Ag = buf[4];
! 1986: snprintf(Msg, sizeof(Msg),
! 1987: "Satellite mask angle %s %d degrees", cp,
! 1988: (int)instance->Ag);
! 1989: oncore_log(instance, LOG_INFO, Msg);
! 1990: }
! 1991:
! 1992:
! 1993:
! 1994: /*
! 1995: * get Position hold position
! 1996: */
! 1997:
! 1998: static void
! 1999: oncore_msg_As(
! 2000: struct instance *instance,
! 2001: u_char *buf,
! 2002: size_t len
! 2003: )
! 2004: {
! 2005: instance->ss_lat = buf_w32(&buf[4]);
! 2006: instance->ss_long = buf_w32(&buf[8]);
! 2007: instance->ss_ht = buf_w32(&buf[12]);
! 2008:
! 2009: /* Print out Position */
! 2010: oncore_print_posn(instance);
! 2011: }
! 2012:
! 2013:
! 2014:
! 2015: /*
! 2016: * Try to use Oncore UT+ Auto Survey Feature
! 2017: * If its not there (VP), set flag to do it ourselves.
! 2018: */
! 2019:
! 2020: static void
! 2021: oncore_msg_At(
! 2022: struct instance *instance,
! 2023: u_char *buf,
! 2024: size_t len
! 2025: )
! 2026: {
! 2027: instance->saw_At = 1;
! 2028: if (instance->site_survey == ONCORE_SS_TESTING) {
! 2029: if (buf[4] == 2) {
! 2030: oncore_log(instance, LOG_NOTICE,
! 2031: "Initiating hardware 3D site survey");
! 2032:
! 2033: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
! 2034: instance->site_survey = ONCORE_SS_HW;
! 2035: }
! 2036: }
! 2037: }
! 2038:
! 2039:
! 2040:
! 2041: /*
! 2042: * get PPS Offset
! 2043: * Nb. @@Ay is not supported for early UT (no plus) model
! 2044: */
! 2045:
! 2046: static void
! 2047: oncore_msg_Ay(
! 2048: struct instance *instance,
! 2049: u_char *buf,
! 2050: size_t len
! 2051: )
! 2052: {
! 2053: char Msg[120];
! 2054:
! 2055: if (instance->saw_Ay)
! 2056: return;
! 2057:
! 2058: instance->saw_Ay = 1;
! 2059:
! 2060: instance->offset = buf_w32(&buf[4]);
! 2061:
! 2062: snprintf(Msg, sizeof(Msg), "PPS Offset is set to %ld ns",
! 2063: instance->offset);
! 2064: oncore_log(instance, LOG_INFO, Msg);
! 2065: }
! 2066:
! 2067:
! 2068:
! 2069: /*
! 2070: * get Cable Delay
! 2071: */
! 2072:
! 2073: static void
! 2074: oncore_msg_Az(
! 2075: struct instance *instance,
! 2076: u_char *buf,
! 2077: size_t len
! 2078: )
! 2079: {
! 2080: char Msg[120];
! 2081:
! 2082: if (instance->saw_Az)
! 2083: return;
! 2084:
! 2085: instance->saw_Az = 1;
! 2086:
! 2087: instance->delay = buf_w32(&buf[4]);
! 2088:
! 2089: snprintf(Msg, sizeof(Msg), "Cable delay is set to %ld ns",
! 2090: instance->delay);
! 2091: oncore_log(instance, LOG_INFO, Msg);
! 2092: }
! 2093:
! 2094:
! 2095:
! 2096: /* Ba, Ea and Ha come here, these contain Position */
! 2097:
! 2098: static void
! 2099: oncore_msg_BaEaHa(
! 2100: struct instance *instance,
! 2101: u_char *buf,
! 2102: size_t len
! 2103: )
! 2104: {
! 2105: const char *cp;
! 2106: char Msg[160];
! 2107: int mode;
! 2108:
! 2109: /* OK, we are close to the RUN state now.
! 2110: * But we have a few more items to initialize first.
! 2111: *
! 2112: * At the beginning of this routine there are several 'timers'.
! 2113: * We enter this routine 1/sec, and since the upper levels of NTP have usurped
! 2114: * the use of timers, we use the 1/sec entry to do things that
! 2115: * we would normally do with timers...
! 2116: */
! 2117:
! 2118: if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */
! 2119: if (buf[2] == 'B') { /* 6chan */
! 2120: if (instance->chan_ck < 6) instance->chan_ck = 6;
! 2121: } else if (buf[2] == 'E') { /* 8chan */
! 2122: if (instance->chan_ck < 8) instance->chan_ck = 8;
! 2123: } else if (buf[2] == 'H') { /* 12chan */
! 2124: if (instance->chan_ck < 12) instance->chan_ck = 12;
! 2125: }
! 2126:
! 2127: if (instance->count3++ < 5)
! 2128: return;
! 2129:
! 2130: instance->count3 = 0;
! 2131:
! 2132: if (instance->chan_in != -1) /* set in Input */
! 2133: instance->chan = instance->chan_in;
! 2134: else /* set from test */
! 2135: instance->chan = instance->chan_ck;
! 2136:
! 2137: snprintf(Msg, sizeof(Msg), "Input says chan = %d",
! 2138: instance->chan_in);
! 2139: oncore_log(instance, LOG_INFO, Msg);
! 2140: snprintf(Msg, sizeof(Msg), "Model # says chan = %d",
! 2141: instance->chan_id);
! 2142: oncore_log(instance, LOG_INFO, Msg);
! 2143: snprintf(Msg, sizeof(Msg), "Testing says chan = %d",
! 2144: instance->chan_ck);
! 2145: oncore_log(instance, LOG_INFO, Msg);
! 2146: snprintf(Msg, sizeof(Msg), "Using chan = %d",
! 2147: instance->chan);
! 2148: oncore_log(instance, LOG_INFO, Msg);
! 2149:
! 2150: instance->o_state = ONCORE_HAVE_CHAN;
! 2151: oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN");
! 2152:
! 2153: instance->timeout = 4;
! 2154: oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
! 2155: return;
! 2156: }
! 2157:
! 2158: if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
! 2159: return;
! 2160:
! 2161: /* PAUSE 5sec - make sure results are stable, before using position */
! 2162:
! 2163: if (instance->count) {
! 2164: if (instance->count++ < 5)
! 2165: return;
! 2166: instance->count = 0;
! 2167: }
! 2168:
! 2169: memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */
! 2170:
! 2171: /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
! 2172:
! 2173: oncore_check_almanac(instance);
! 2174: oncore_check_antenna(instance);
! 2175:
! 2176: /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
! 2177: /* When we have an almanac, we will start the Bn/En/@@Hn messages */
! 2178:
! 2179: if (instance->o_state == ONCORE_ALMANAC)
! 2180: if (oncore_wait_almanac(instance))
! 2181: return;
! 2182:
! 2183: /* do some things once when we get this far in BaEaHa */
! 2184:
! 2185: if (instance->once) {
! 2186: instance->once = 0;
! 2187: instance->count2 = 1;
! 2188:
! 2189: /* Have we seen an @@At (position hold) command response */
! 2190: /* if not, message out */
! 2191:
! 2192: if (instance->chan != 12 && !instance->saw_At) {
! 2193: oncore_log(instance, LOG_NOTICE,
! 2194: "Not Good, no @@At command (no Position Hold), must be a GT/GT+");
! 2195: oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
! 2196: }
! 2197:
! 2198: /* have an Almanac, can start the SiteSurvey
! 2199: * (actually only need to get past the almanac_load where we diddle with At
! 2200: * command,- we can't change it after we start the HW_SS below
! 2201: */
! 2202:
! 2203: mode = instance->init_type;
! 2204: switch (mode) {
! 2205: case 0: /* NO initialization, don't change anything */
! 2206: case 1: /* Use given Position */
! 2207: case 3:
! 2208: instance->site_survey = ONCORE_SS_DONE;
! 2209: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
! 2210: break;
! 2211:
! 2212: case 2:
! 2213: case 4: /* Site Survey */
! 2214: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING");
! 2215: instance->site_survey = ONCORE_SS_TESTING;
! 2216: instance->count1 = 1;
! 2217: if (instance->chan == 12)
! 2218: oncore_sendmsg(instance, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */
! 2219: else
! 2220: oncore_sendmsg(instance, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */
! 2221: break;
! 2222: }
! 2223:
! 2224: /* Read back PPS Offset for Output */
! 2225: /* Nb. This will fail silently for early UT (no plus) and M12 models */
! 2226:
! 2227: oncore_sendmsg(instance, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
! 2228:
! 2229: /* Read back Cable Delay for Output */
! 2230:
! 2231: oncore_sendmsg(instance, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
! 2232:
! 2233: /* Read back Satellite Mask Angle for Output */
! 2234:
! 2235: oncore_sendmsg(instance, oncore_cmd_Agx, sizeof(oncore_cmd_Agx));
! 2236: }
! 2237:
! 2238:
! 2239: /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
! 2240: * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
! 2241: * We must do the Gd3, and then wait a cycle or two for things to settle,
! 2242: * then check Ha[130]&0x10 to see if a SS is in progress.
! 2243: * We will set SW if HW has not been set after an appropriate delay.
! 2244: */
! 2245:
! 2246: if (instance->site_survey == ONCORE_SS_TESTING) {
! 2247: if (instance->chan == 12) {
! 2248: if (instance->count1) {
! 2249: if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
! 2250: instance->count1 = 0;
! 2251: if (instance->BEHa[130]&0x10) {
! 2252: oncore_log(instance, LOG_NOTICE,
! 2253: "Initiating hardware 3D site survey");
! 2254:
! 2255: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
! 2256: instance->site_survey = ONCORE_SS_HW;
! 2257: } else {
! 2258: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
! 2259: instance->site_survey = ONCORE_SS_SW;
! 2260: }
! 2261: }
! 2262: }
! 2263: } else {
! 2264: if (instance->count1) {
! 2265: if (instance->count1++ > 5) {
! 2266: instance->count1 = 0;
! 2267: /*
! 2268: * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
! 2269: * wait after the @@At2/@@Gd3 command we have not changed the state to
! 2270: * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then
! 2271: * the variable would have been changed by now.
! 2272: * There are three possibilities:
! 2273: * 6/8chan
! 2274: * (a) We did not get a response to the @@At0 or @@At2 commands,
! 2275: * and it must be a GT/GT+/SL with no position hold mode.
! 2276: * We will have to do it ourselves.
! 2277: * (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
! 2278: * must be a VP or older UT which doesn't have Site Survey mode.
! 2279: * We will have to do it ourselves.
! 2280: * 12chan
! 2281: * (c) We saw the @@Gd command, and saw H[13]*0x10
! 2282: * We will have to do it ourselves (done above)
! 2283: */
! 2284:
! 2285: snprintf(Msg, sizeof(Msg),
! 2286: "Initiating software 3D site survey (%d samples)",
! 2287: POS_HOLD_AVERAGE);
! 2288: oncore_log(instance, LOG_INFO, Msg);
! 2289:
! 2290: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
! 2291: instance->site_survey = ONCORE_SS_SW;
! 2292:
! 2293: instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
! 2294: if (instance->chan == 12)
! 2295: oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
! 2296: else {
! 2297: oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
! 2298: oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
! 2299: }
! 2300: }
! 2301: }
! 2302: }
! 2303: }
! 2304:
! 2305: /* check the mode we are in 0/2/3D */
! 2306:
! 2307: if (instance->chan == 6) {
! 2308: if (instance->BEHa[64]&0x8)
! 2309: instance->mode = MODE_0D;
! 2310: else if (instance->BEHa[64]&0x10)
! 2311: instance->mode = MODE_2D;
! 2312: else if (instance->BEHa[64]&0x20)
! 2313: instance->mode = MODE_3D;
! 2314: } else if (instance->chan == 8) {
! 2315: if (instance->BEHa[72]&0x8)
! 2316: instance->mode = MODE_0D;
! 2317: else if (instance->BEHa[72]&0x10)
! 2318: instance->mode = MODE_2D;
! 2319: else if (instance->BEHa[72]&0x20)
! 2320: instance->mode = MODE_3D;
! 2321: } else if (instance->chan == 12) {
! 2322: int bits;
! 2323:
! 2324: bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
! 2325: if (bits == 0x4)
! 2326: instance->mode = MODE_0D;
! 2327: else if (bits == 0x6)
! 2328: instance->mode = MODE_2D;
! 2329: else if (bits == 0x7)
! 2330: instance->mode = MODE_3D;
! 2331: }
! 2332:
! 2333: /* copy the record to the (extra) location in SHMEM */
! 2334:
! 2335: if (instance->shmem) {
! 2336: int i;
! 2337: u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */
! 2338:
! 2339: switch(instance->chan) {
! 2340: case 6: smp = &instance->shmem[instance->shmem_Ba]; break;
! 2341: case 8: smp = &instance->shmem[instance->shmem_Ea]; break;
! 2342: case 12: smp = &instance->shmem[instance->shmem_Ha]; break;
! 2343: default: smp = (u_char *) NULL; break;
! 2344: }
! 2345:
! 2346: switch (instance->mode) {
! 2347: case MODE_0D: i = 1; break; /* 0D, Position Hold */
! 2348: case MODE_2D: i = 2; break; /* 2D, Altitude Hold */
! 2349: case MODE_3D: i = 3; break; /* 3D fix */
! 2350: default: i = 0; break;
! 2351: }
! 2352:
! 2353: if (i && smp != NULL) {
! 2354: i *= (len+6);
! 2355: smp[i + 2]++;
! 2356: memcpy(&smp[i+3], buf, (size_t) (len+3));
! 2357: }
! 2358: }
! 2359:
! 2360: /*
! 2361: * check if traim timer active
! 2362: * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
! 2363: */
! 2364:
! 2365: if (instance->traim_delay) {
! 2366: if (instance->traim_delay++ > 5) {
! 2367: instance->traim = 0;
! 2368: instance->traim_delay = 0;
! 2369: cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
! 2370: oncore_log(instance, LOG_INFO, cp);
! 2371:
! 2372: oncore_set_traim(instance);
! 2373: } else
! 2374: return;
! 2375:
! 2376: }
! 2377:
! 2378: /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
! 2379:
! 2380: if (!instance->have_dH && !instance->traim_delay)
! 2381: oncore_compute_dH(instance);
! 2382:
! 2383: /*
! 2384: * must be ONCORE_RUN if we are here.
! 2385: * Have # chan and TRAIM by now.
! 2386: */
! 2387:
! 2388: instance->pp->year = buf[6]*256+buf[7];
! 2389: instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
! 2390: instance->pp->hour = buf[8];
! 2391: instance->pp->minute = buf[9];
! 2392: instance->pp->second = buf[10];
! 2393:
! 2394: /*
! 2395: * Are we doing a Hardware or Software Site Survey?
! 2396: */
! 2397:
! 2398: if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
! 2399: oncore_ss(instance);
! 2400:
! 2401: /* see if we ever saw a response from the @@Ayx above */
! 2402:
! 2403: if (instance->count2) {
! 2404: if (instance->count2++ > 5) { /* this delay to check on @@Ay command */
! 2405: instance->count2 = 0;
! 2406:
! 2407: /* Have we seen an Ay (1PPS time offset) command response */
! 2408: /* if not, and non-zero offset, zero the offset, and send message */
! 2409:
! 2410: if (!instance->saw_Ay && instance->offset) {
! 2411: oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored");
! 2412: instance->offset = 0;
! 2413: }
! 2414: }
! 2415: }
! 2416:
! 2417: /*
! 2418: * Check the leap second status once per day.
! 2419: */
! 2420:
! 2421: oncore_check_leap_sec(instance);
! 2422:
! 2423: /*
! 2424: * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
! 2425: */
! 2426:
! 2427: if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
! 2428: oncore_shmem_get_3D(instance);
! 2429:
! 2430: if (!instance->traim) /* NO traim, no BnEnHn, go get tick */
! 2431: oncore_get_timestamp(instance, instance->offset, instance->offset);
! 2432: }
! 2433:
! 2434:
! 2435:
! 2436: /* Almanac Status */
! 2437:
! 2438: static void
! 2439: oncore_msg_Bd(
! 2440: struct instance *instance,
! 2441: u_char *buf,
! 2442: size_t len
! 2443: )
! 2444: {
! 2445: char Msg[160];
! 2446:
! 2447: snprintf(Msg, sizeof(Msg),
! 2448: "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
! 2449: ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6],
! 2450: buf[7], w32(&buf[8]));
! 2451: oncore_log(instance, LOG_NOTICE, Msg);
! 2452: }
! 2453:
! 2454:
! 2455:
! 2456: /* get leap-second warning message */
! 2457:
! 2458: /*
! 2459: * @@Bj does NOT behave as documented in current Oncore firmware.
! 2460: * It turns on the LEAP indicator when the data is set, and does not,
! 2461: * as documented, wait until the beginning of the month when the
! 2462: * leap second will occur.
! 2463: * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
! 2464: * @@Bj is only called in June/December.
! 2465: */
! 2466:
! 2467: static void
! 2468: oncore_msg_Bj(
! 2469: struct instance *instance,
! 2470: u_char *buf,
! 2471: size_t len
! 2472: )
! 2473: {
! 2474: const char *cp;
! 2475:
! 2476: instance->saw_Bj = 1;
! 2477:
! 2478: switch(buf[4]) {
! 2479: case 1:
! 2480: instance->pp->leap = LEAP_ADDSECOND;
! 2481: cp = "Set pp.leap to LEAP_ADDSECOND";
! 2482: break;
! 2483: case 2:
! 2484: instance->pp->leap = LEAP_DELSECOND;
! 2485: cp = "Set pp.leap to LEAP_DELSECOND";
! 2486: break;
! 2487: case 0:
! 2488: default:
! 2489: instance->pp->leap = LEAP_NOWARNING;
! 2490: cp = "Set pp.leap to LEAP_NOWARNING";
! 2491: break;
! 2492: }
! 2493: oncore_log(instance, LOG_NOTICE, cp);
! 2494: }
! 2495:
! 2496:
! 2497:
! 2498: static void
! 2499: oncore_msg_Bl(
! 2500: struct instance *instance,
! 2501: u_char *buf,
! 2502: size_t len
! 2503: )
! 2504: {
! 2505: int chan, id, subframe, valid, page, i, j, tow;
! 2506: int day_now, day_lsf;
! 2507: char *cp, Msg[120];
! 2508: enum {
! 2509: WARN_NOT_YET,
! 2510: WARN_0,
! 2511: WARN_PLUS,
! 2512: WARN_MINUS
! 2513: } warn;
! 2514:
! 2515: day_now = day_lsf = 0;
! 2516: cp = NULL; /* keep gcc happy */
! 2517:
! 2518: chan = buf[4] & 0377;
! 2519: id = buf[5] & 0377;
! 2520: subframe = buf[6] & 017;
! 2521: valid = (buf[6] >> 4) & 017;
! 2522: page = buf[7];
! 2523:
! 2524: if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) {
! 2525: instance->Bl.dt_ls = buf[32];
! 2526: instance->Bl.WN_lsf = buf[33];
! 2527: instance->Bl.DN_lsf = buf[34];
! 2528: instance->Bl.dt_lsf = buf[35];
! 2529: instance->Bl.lsf_flg++;
! 2530: }
! 2531: if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) {
! 2532: i = (buf[7+7]<<8) + buf[7+8];
! 2533: instance->Bl.WN = i >> 6;
! 2534: tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6];
! 2535: tow >>= 7;
! 2536: tow = tow & 0377777;
! 2537: tow <<= 2;
! 2538: instance->Bl.DN = tow/57600L + 1;
! 2539: instance->Bl.wn_flg++;
! 2540: }
! 2541: if (instance->Bl.wn_flg && instance->Bl.lsf_flg) {
! 2542: instance->Bl.wn_flg = instance->Bl.lsf_flg = 0;
! 2543: oncore_cmd_Bl[2] = 0;
! 2544: oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl);
! 2545: oncore_cmd_Bl[2] = 1;
! 2546:
! 2547: i = instance->Bl.WN&01400;
! 2548: instance->Bl.WN_lsf |= i;
! 2549:
! 2550: /* have everything I need, doit */
! 2551:
! 2552: i = (instance->Bl.WN_lsf - instance->Bl.WN);
! 2553: if (i < 0)
! 2554: i += 1024;
! 2555: day_now = instance->Bl.DN;
! 2556: day_lsf = 7*i + instance->Bl.DN_lsf;
! 2557:
! 2558: /* ignore if in past or more than a month in future */
! 2559:
! 2560: warn = WARN_NOT_YET;
! 2561: if (day_lsf >= day_now && day_lsf - day_now < 32) {
! 2562: /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */
! 2563: if (day_lsf - day_now < 28 || instance->BEHa[5] < 20) {
! 2564: i = instance->Bl.dt_lsf - instance->Bl.dt_ls;
! 2565: switch (i) {
! 2566: case -1:
! 2567: warn = WARN_MINUS;
! 2568: break;
! 2569: case 0:
! 2570: warn = WARN_0;
! 2571: break;
! 2572: case 1:
! 2573: warn = WARN_PLUS;
! 2574: break;
! 2575: }
! 2576: }
! 2577: }
! 2578:
! 2579: switch (warn) {
! 2580: case WARN_0:
! 2581: case WARN_NOT_YET:
! 2582: instance->peer->leap = LEAP_NOWARNING;
! 2583: cp = "Set peer.leap to LEAP_NOWARNING";
! 2584: break;
! 2585: case WARN_MINUS:
! 2586: instance->peer->leap = LEAP_DELSECOND;
! 2587: cp = "Set peer.leap to LEAP_DELSECOND";
! 2588: break;
! 2589: case WARN_PLUS:
! 2590: instance->peer->leap = LEAP_ADDSECOND;
! 2591: cp = "Set peer.leap to LEAP_ADDSECOND";
! 2592: break;
! 2593: }
! 2594: oncore_log(instance, LOG_NOTICE, cp);
! 2595:
! 2596: i = instance->Bl.dt_lsf-instance->Bl.dt_ls;
! 2597: if (i) {
! 2598: j = (i >= 0) ? i : -i; /* abs(i) */
! 2599: snprintf(Msg, sizeof(Msg),
! 2600: "see Leap_Second (%c%d) in %d days",
! 2601: ((i >= 0) ? '+' : '-'), j,
! 2602: day_lsf-day_now);
! 2603: oncore_log(instance, LOG_NOTICE, Msg);
! 2604: }
! 2605: }
! 2606: snprintf(Msg, sizeof(Msg),
! 2607: "dt_ls = %d dt_lsf = %d WN = %d DN = %d WN_lsf = %d DNlsf = %d wn_flg = %d lsf_flg = %d Bl_day = %d",
! 2608: instance->Bl.dt_ls, instance->Bl.dt_lsf,
! 2609: instance->Bl.WN, instance->Bl.DN,
! 2610: instance->Bl.WN_lsf, instance->Bl.DN_lsf,
! 2611: instance->Bl.wn_flg, instance->Bl.lsf_flg,
! 2612: instance->Bl.Bl_day);
! 2613: oncore_log(instance, LOG_INFO, Msg);
! 2614: }
! 2615:
! 2616:
! 2617: static void
! 2618: oncore_msg_BnEnHn(
! 2619: struct instance *instance,
! 2620: u_char *buf,
! 2621: size_t len
! 2622: )
! 2623: {
! 2624: long dt1, dt2;
! 2625:
! 2626: if (instance->o_state != ONCORE_RUN)
! 2627: return;
! 2628:
! 2629: if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */
! 2630: instance->traim_ck = 1;
! 2631: instance->traim_delay = 0;
! 2632: oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON");
! 2633:
! 2634: oncore_set_traim(instance);
! 2635: }
! 2636:
! 2637: memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */
! 2638:
! 2639: if (!instance->traim) /* BnEnHn will be turned off in any case */
! 2640: return;
! 2641:
! 2642: /* If Time RAIM doesn't like it, don't trust it */
! 2643:
! 2644: if (buf[2] == 'H') {
! 2645: if (instance->BEHn[6]) { /* bad TRAIM */
! 2646: oncore_log(instance, LOG_WARNING, "BAD TRAIM");
! 2647: return;
! 2648: }
! 2649:
! 2650: dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
! 2651: instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
! 2652: dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
! 2653: } else {
! 2654: if (instance->BEHn[21]) /* bad TRAIM */
! 2655: return;
! 2656:
! 2657: dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
! 2658: instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */
! 2659: dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
! 2660: }
! 2661:
! 2662: oncore_get_timestamp(instance, dt1, dt2);
! 2663: }
! 2664:
! 2665:
! 2666:
! 2667: /* Here for @@Ca, @@Fa and @@Ia messages */
! 2668:
! 2669: /* These are Self test Commands for 6, 8, and 12 chan receivers.
! 2670: * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
! 2671: * It was found that under some circumstances the following
! 2672: * command would fail if issued immediately after the return from the
! 2673: * @@Fa, but a 2sec delay seemed to fix things. Since simply calling
! 2674: * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
! 2675: * itimer, we set a flag, and test it at the next POLL. If it hasn't
! 2676: * been cleared, we reissue the @@Cj that is issued below.
! 2677: * Note that we do a @@Cj at the beginning, and again here.
! 2678: * The first is to get the info, the 2nd is just used as a safe command
! 2679: * after the @@Fa for all Oncores (and it was in this posn in the
! 2680: * original code).
! 2681: */
! 2682:
! 2683: static void
! 2684: oncore_msg_CaFaIa(
! 2685: struct instance *instance,
! 2686: u_char *buf,
! 2687: size_t len
! 2688: )
! 2689: {
! 2690: char Msg[120];
! 2691: int i;
! 2692:
! 2693: if (instance->o_state == ONCORE_TEST_SENT) {
! 2694: enum antenna_state antenna;
! 2695:
! 2696: instance->timeout = 0;
! 2697:
! 2698: #if ONCORE_VERBOSE_SELF_TEST
! 2699: if (debug > 2) {
! 2700: if (buf[2] == 'I')
! 2701: snprintf(Msg, sizeof(Msg),
! 2702: ">>@@%ca %x %x %x", buf[2],
! 2703: buf[4], buf[5], buf[6]);
! 2704: else
! 2705: snprintf(Msg, sizeof(Msg),
! 2706: ">>@@%ca %x %x", buf[2],
! 2707: buf[4], buf[5]);
! 2708: oncore_log(instance, LOG_DEBUG, Msg);
! 2709: }
! 2710: #endif
! 2711:
! 2712: antenna = (buf[4] & 0xc0) >> 6;
! 2713: buf[4] &= ~0xc0;
! 2714:
! 2715: i = buf[4] || buf[5];
! 2716: if (buf[2] == 'I') i = i || buf[6];
! 2717: if (i) {
! 2718: if (buf[2] == 'I')
! 2719: snprintf(Msg, sizeof(Msg),
! 2720: "self test failed: result %02x %02x %02x",
! 2721: buf[4], buf[5], buf[6]);
! 2722: else
! 2723: snprintf(Msg, sizeof(Msg),
! 2724: "self test failed: result %02x %02x",
! 2725: buf[4], buf[5]);
! 2726: oncore_log(instance, LOG_ERR, Msg);
! 2727:
! 2728: oncore_log(instance, LOG_ERR,
! 2729: "ONCORE: self test failed, shutting down driver");
! 2730:
! 2731: refclock_report(instance->peer, CEVNT_FAULT);
! 2732: oncore_shutdown(instance->unit, instance->peer);
! 2733: return;
! 2734: }
! 2735:
! 2736: /* report the current antenna state */
! 2737:
! 2738: oncore_antenna_report(instance, antenna);
! 2739:
! 2740: instance->o_state = ONCORE_INIT;
! 2741: oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT");
! 2742:
! 2743: instance->timeout = 4;
! 2744: oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
! 2745: }
! 2746: }
! 2747:
! 2748:
! 2749:
! 2750: /*
! 2751: * Demultiplex the almanac into shmem
! 2752: */
! 2753:
! 2754: static void
! 2755: oncore_msg_Cb(
! 2756: struct instance *instance,
! 2757: u_char *buf,
! 2758: size_t len
! 2759: )
! 2760: {
! 2761: int i;
! 2762:
! 2763: if (instance->shmem == NULL)
! 2764: return;
! 2765:
! 2766: if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
! 2767: i = buf[5];
! 2768: else if (buf[4] == 4 && buf[5] <= 5)
! 2769: i = buf[5] + 24;
! 2770: else if (buf[4] == 4 && buf[5] <= 10)
! 2771: i = buf[5] + 23;
! 2772: else if (buf[4] == 4 && buf[5] == 25)
! 2773: i = 34;
! 2774: else {
! 2775: oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC");
! 2776: return;
! 2777: }
! 2778:
! 2779: i *= 36;
! 2780: instance->shmem[instance->shmem_Cb + i + 2]++;
! 2781: memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
! 2782:
! 2783: #ifdef ONCORE_VERBOSE_MSG_CB
! 2784: {
! 2785: char Msg[160];
! 2786:
! 2787: snprintf(Msg, sizeof(Msg), "See Cb [%d,%d]", buf[4],
! 2788: buf[5]);
! 2789: oncore_log(instance, LOG_DEBUG, Msg);
! 2790: }
! 2791: #endif
! 2792: }
! 2793:
! 2794:
! 2795:
! 2796: /*
! 2797: * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
! 2798: * not so for VP (eeprom) or any unit with a battery
! 2799: */
! 2800:
! 2801: static void
! 2802: oncore_msg_Cf(
! 2803: struct instance *instance,
! 2804: u_char *buf,
! 2805: size_t len
! 2806: )
! 2807: {
! 2808: if (instance->o_state == ONCORE_RESET_SENT) {
! 2809: oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
! 2810: /* Reset set VP to IDLE */
! 2811: instance->o_state = ONCORE_TEST_SENT;
! 2812: oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
! 2813:
! 2814: oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
! 2815: }
! 2816: }
! 2817:
! 2818:
! 2819:
! 2820: /*
! 2821: * This is the Grand Central Station for the Preliminary Initialization.
! 2822: * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
! 2823: *
! 2824: * We do an @@Cj whenever we need a safe command for all Oncores.
! 2825: * The @@Cj gets us back here where we can switch to the next phase of setup.
! 2826: *
! 2827: * o Once at the very beginning (in start) to get the Model number.
! 2828: * This info is printed, but no longer used.
! 2829: * o Again after we have determined the number of Channels in the receiver.
! 2830: * o And once later after we have done a reset and test, (which may hang),
! 2831: * as we are about to initialize the Oncore and start it running.
! 2832: * o We have one routine below for each case.
! 2833: */
! 2834:
! 2835: static void
! 2836: oncore_msg_Cj(
! 2837: struct instance *instance,
! 2838: u_char *buf,
! 2839: size_t len
! 2840: )
! 2841: {
! 2842: int mode;
! 2843:
! 2844: memcpy(instance->Cj, buf, len);
! 2845:
! 2846: instance->timeout = 0;
! 2847: if (instance->o_state == ONCORE_CHECK_ID) {
! 2848: oncore_msg_Cj_id(instance, buf, len);
! 2849: oncore_chan_test(instance);
! 2850: } else if (instance->o_state == ONCORE_HAVE_CHAN) {
! 2851: mode = instance->init_type;
! 2852: if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */
! 2853: instance->o_state = ONCORE_RESET_SENT;
! 2854: oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT");
! 2855: oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
! 2856: } else {
! 2857: instance->o_state = ONCORE_TEST_SENT;
! 2858: oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
! 2859: }
! 2860: }
! 2861:
! 2862: if (instance->o_state == ONCORE_TEST_SENT) {
! 2863: if (instance->chan == 6)
! 2864: oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
! 2865: else if (instance->chan == 8)
! 2866: oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
! 2867: else if (instance->chan == 12)
! 2868: oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
! 2869: } else if (instance->o_state == ONCORE_INIT)
! 2870: oncore_msg_Cj_init(instance, buf, len);
! 2871: }
! 2872:
! 2873:
! 2874:
! 2875: /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
! 2876: * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
! 2877: * and from Motorola. Until recently Rick was the only source of
! 2878: * this information as Motorola didn't give the information out.
! 2879: *
! 2880: * Determine the Type from the Model #, this determines #chan and if TRAIM is
! 2881: * available.
! 2882: *
! 2883: * The Information from this routine is NO LONGER USED.
! 2884: * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
! 2885: */
! 2886:
! 2887: static void
! 2888: oncore_msg_Cj_id(
! 2889: struct instance *instance,
! 2890: u_char *buf,
! 2891: size_t len
! 2892: )
! 2893: {
! 2894: char *cp, *cp1, *cp2, Model[21], Msg[160];
! 2895:
! 2896: /* Write Receiver ID message to clockstats file */
! 2897:
! 2898: instance->Cj[294] = '\0';
! 2899: for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
! 2900: cp1 = strchr(cp, '\r');
! 2901: if (!cp1)
! 2902: cp1 = (char *)&instance->Cj[294];
! 2903: *cp1 = '\0';
! 2904: oncore_log(instance, LOG_NOTICE, cp);
! 2905: *cp1 = '\r';
! 2906: cp = cp1+2;
! 2907: }
! 2908:
! 2909: /* next, the Firmware Version and Revision numbers */
! 2910:
! 2911: instance->version = atoi((char *) &instance->Cj[83]);
! 2912: instance->revision = atoi((char *) &instance->Cj[111]);
! 2913:
! 2914: /* from model number decide which Oncore this is,
! 2915: and then the number of channels */
! 2916:
! 2917: for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */
! 2918: ;
! 2919: cp1 = cp;
! 2920: cp2 = Model;
! 2921: for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
! 2922: *cp2 = *cp;
! 2923: *cp2 = '\0';
! 2924:
! 2925: cp = 0;
! 2926: if (!strncmp(Model, "PVT6", (size_t) 4)) {
! 2927: cp = "PVT6";
! 2928: instance->model = ONCORE_PVT6;
! 2929: } else if (Model[0] == 'A') {
! 2930: cp = "Basic";
! 2931: instance->model = ONCORE_BASIC;
! 2932: } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
! 2933: cp = "VP";
! 2934: instance->model = ONCORE_VP;
! 2935: } else if (Model[0] == 'P') {
! 2936: cp = "M12";
! 2937: instance->model = ONCORE_M12;
! 2938: } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
! 2939: if (Model[5] == 'N') {
! 2940: cp = "GT";
! 2941: instance->model = ONCORE_GT;
! 2942: } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
! 2943: cp = "GT+";
! 2944: instance->model = ONCORE_GTPLUS;
! 2945: } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
! 2946: cp = "UT";
! 2947: instance->model = ONCORE_UT;
! 2948: } else if (Model[1] == '5' && Model[5] == 'G') {
! 2949: cp = "UT+";
! 2950: instance->model = ONCORE_UTPLUS;
! 2951: } else if (Model[1] == '6' && Model[5] == 'G') {
! 2952: cp = "SL";
! 2953: instance->model = ONCORE_SL;
! 2954: } else {
! 2955: cp = "Unknown";
! 2956: instance->model = ONCORE_UNKNOWN;
! 2957: }
! 2958: } else {
! 2959: cp = "Unknown";
! 2960: instance->model = ONCORE_UNKNOWN;
! 2961: }
! 2962:
! 2963: /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
! 2964:
! 2965: snprintf(Msg, sizeof(Msg),
! 2966: "This looks like an Oncore %s with version %d.%d firmware.",
! 2967: cp, instance->version, instance->revision);
! 2968: oncore_log(instance, LOG_INFO, Msg);
! 2969:
! 2970: instance->chan_id = 8; /* default */
! 2971: if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
! 2972: instance->chan_id = 6;
! 2973: else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
! 2974: instance->chan_id = 8;
! 2975: else if (instance->model == ONCORE_M12)
! 2976: instance->chan_id = 12;
! 2977:
! 2978: instance->traim_id = 0; /* default */
! 2979: if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
! 2980: instance->traim_id = 0;
! 2981: else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
! 2982: instance->traim_id = 1;
! 2983: else if (instance->model == ONCORE_M12)
! 2984: instance->traim_id = -1;
! 2985:
! 2986: snprintf(Msg, sizeof(Msg), "Channels = %d, TRAIM = %s",
! 2987: instance->chan_id,
! 2988: ((instance->traim_id < 0)
! 2989: ? "UNKNOWN"
! 2990: : (instance->traim_id > 0)
! 2991: ? "ON"
! 2992: : "OFF"));
! 2993: oncore_log(instance, LOG_INFO, Msg);
! 2994: }
! 2995:
! 2996:
! 2997:
! 2998: /* OK, know type of Oncore, have possibly reset it, and have tested it.
! 2999: * We know the number of channels.
! 3000: * We will determine whether we have TRAIM before we actually start.
! 3001: * Now initialize.
! 3002: */
! 3003:
! 3004: static void
! 3005: oncore_msg_Cj_init(
! 3006: struct instance *instance,
! 3007: u_char *buf,
! 3008: size_t len
! 3009: )
! 3010: {
! 3011: char Msg[160];
! 3012: u_char Cmd[20];
! 3013: int mode;
! 3014:
! 3015:
! 3016: /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
! 3017: * start again if we go from 0D -> 3D, then loses them again when we
! 3018: * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM.
! 3019: * For NOW we will turn this aspect of filling SHMEM off for the M12
! 3020: */
! 3021:
! 3022: if (instance->chan == 12) {
! 3023: instance->shmem_bad_Ea = 1;
! 3024: snprintf(Msg, sizeof(Msg),
! 3025: "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***",
! 3026: instance->version, instance->revision);
! 3027: oncore_log(instance, LOG_NOTICE, Msg);
! 3028: }
! 3029:
! 3030: oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
! 3031: oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
! 3032: oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
! 3033: oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
! 3034: oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
! 3035: oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
! 3036: oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
! 3037:
! 3038: mode = instance->init_type;
! 3039:
! 3040: /* If there is Position input in the Config file
! 3041: * and mode = (1,3) set it as posn hold posn, goto 0D mode.
! 3042: * or mode = (2,4) set it as INITIAL position, and do Site Survey.
! 3043: */
! 3044:
! 3045: if (instance->posn_set) {
! 3046: oncore_log(instance, LOG_INFO, "Setting Posn from input data");
! 3047: oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */
! 3048: } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
! 3049: if (instance->chan != 12)
! 3050: oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
! 3051:
! 3052: if (mode != 0) {
! 3053: /* cable delay in ns */
! 3054: memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
! 3055: w32_buf(&Cmd[-2+4], instance->delay);
! 3056: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */
! 3057:
! 3058: /* PPS offset in ns */
! 3059: if (instance->offset) {
! 3060: memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */
! 3061: w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */
! 3062: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ay));
! 3063: }
! 3064:
! 3065: /* Satellite mask angle */
! 3066:
! 3067: if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */
! 3068: memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
! 3069: Cmd[-2+4] = instance->Ag;
! 3070: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ag));
! 3071: }
! 3072: }
! 3073:
! 3074: /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
! 3075: * now we're really running
! 3076: * these were ALL started in the chan test,
! 3077: * However, if we had mode=3,4 then commands got turned off, so we turn
! 3078: * them on again here just in case
! 3079: */
! 3080:
! 3081: if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
! 3082: oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
! 3083: oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
! 3084: oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
! 3085: oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
! 3086: oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
! 3087: } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */
! 3088: oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
! 3089: oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
! 3090: oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
! 3091: oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
! 3092: oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
! 3093: } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */
! 3094: oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
! 3095: oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
! 3096: oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
! 3097: oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
! 3098: oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
! 3099: }
! 3100:
! 3101: instance->count = 1;
! 3102: instance->o_state = ONCORE_ALMANAC;
! 3103: oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC");
! 3104: }
! 3105:
! 3106:
! 3107:
! 3108: /* 12chan position */
! 3109:
! 3110: static void
! 3111: oncore_msg_Ga(
! 3112: struct instance *instance,
! 3113: u_char *buf,
! 3114: size_t len
! 3115: )
! 3116: {
! 3117: char Msg[160];
! 3118: long lat, lon, ht;
! 3119: double Lat, Lon, Ht;
! 3120:
! 3121:
! 3122: lat = buf_w32(&buf[4]);
! 3123: lon = buf_w32(&buf[8]);
! 3124: ht = buf_w32(&buf[12]); /* GPS ellipsoid */
! 3125:
! 3126: Lat = lat;
! 3127: Lon = lon;
! 3128: Ht = ht;
! 3129:
! 3130: Lat /= 3600000;
! 3131: Lon /= 3600000;
! 3132: Ht /= 100;
! 3133:
! 3134:
! 3135: snprintf(Msg, sizeof(Msg),
! 3136: "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat,
! 3137: Lon, Ht);
! 3138: oncore_log(instance, LOG_NOTICE, Msg);
! 3139:
! 3140: instance->ss_lat = lat;
! 3141: instance->ss_long = lon;
! 3142: instance->ss_ht = ht;
! 3143:
! 3144: oncore_print_posn(instance);
! 3145: }
! 3146:
! 3147:
! 3148:
! 3149: /* 12 chan time/date */
! 3150:
! 3151: static void
! 3152: oncore_msg_Gb(
! 3153: struct instance *instance,
! 3154: u_char *buf,
! 3155: size_t len
! 3156: )
! 3157: {
! 3158: char Msg[160], *gmts;
! 3159: int mo, d, y, h, m, s, gmth, gmtm;
! 3160:
! 3161: mo = buf[4];
! 3162: d = buf[5];
! 3163: y = 256*buf[6]+buf[7];
! 3164:
! 3165: h = buf[8];
! 3166: m = buf[9];
! 3167: s = buf[10];
! 3168:
! 3169: gmts = ((buf[11] == 0) ? "+" : "-");
! 3170: gmth = buf[12];
! 3171: gmtm = buf[13];
! 3172:
! 3173: snprintf(Msg, sizeof(Msg),
! 3174: "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
! 3175: d, Month[mo-1], y, h, m, s, gmts, gmth, gmtm);
! 3176: oncore_log(instance, LOG_NOTICE, Msg);
! 3177: }
! 3178:
! 3179:
! 3180:
! 3181: /* Leap Second for M12, gives all info from satellite message */
! 3182: /* also in UT v3.0 */
! 3183:
! 3184: static void
! 3185: oncore_msg_Gj(
! 3186: struct instance *instance,
! 3187: u_char *buf,
! 3188: size_t len
! 3189: )
! 3190: {
! 3191: int dt;
! 3192: char Msg[160], *cp;
! 3193:
! 3194: instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
! 3195:
! 3196: /* print the message to verify whats there */
! 3197:
! 3198: dt = buf[5] - buf[4];
! 3199:
! 3200: snprintf(Msg, sizeof(Msg),
! 3201: "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", buf[4],
! 3202: buf[5], 256 * buf[6] + buf[7], buf[8], buf[9], buf[10],
! 3203: (buf[14] + 256 *
! 3204: (buf[13] + 256 * (buf[12] + 256 * buf[11]))),
! 3205: buf[15], buf[16], buf[17]);
! 3206: oncore_log(instance, LOG_INFO, Msg);
! 3207:
! 3208: if (dt) {
! 3209: snprintf(Msg, sizeof(Msg),
! 3210: "Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
! 3211: dt, buf[9], Month[buf[8] - 1],
! 3212: 256 * buf[6] + buf[7], buf[15], buf[16],
! 3213: buf[17]);
! 3214: oncore_log(instance, LOG_NOTICE, Msg);
! 3215: }
! 3216:
! 3217: /* Only raise warning within a month of the leap second */
! 3218:
! 3219: instance->pp->leap = LEAP_NOWARNING;
! 3220: cp = "Set pp.leap to LEAP_NOWARNING";
! 3221:
! 3222: if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
! 3223: buf[8] == instance->BEHa[4]) { /* month */
! 3224: if (dt) {
! 3225: if (dt < 0) {
! 3226: instance->pp->leap = LEAP_DELSECOND;
! 3227: cp = "Set pp.leap to LEAP_DELSECOND";
! 3228: } else {
! 3229: instance->pp->leap = LEAP_ADDSECOND;
! 3230: cp = "Set pp.leap to LEAP_ADDSECOND";
! 3231: }
! 3232: }
! 3233: }
! 3234: oncore_log(instance, LOG_INFO, cp);
! 3235: }
! 3236:
! 3237:
! 3238:
! 3239: /* Power on failure */
! 3240:
! 3241: static void
! 3242: oncore_msg_Sz(
! 3243: struct instance *instance,
! 3244: u_char *buf,
! 3245: size_t len
! 3246: )
! 3247: {
! 3248: if (instance && instance->peer) {
! 3249: oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On");
! 3250: oncore_shutdown(instance->unit, instance->peer);
! 3251: }
! 3252: }
! 3253:
! 3254: /************** Small Subroutines ***************/
! 3255:
! 3256:
! 3257: static void
! 3258: oncore_antenna_report(
! 3259: struct instance *instance,
! 3260: enum antenna_state new_state)
! 3261: {
! 3262: char *cp;
! 3263:
! 3264: if (instance->ant_state == new_state)
! 3265: return;
! 3266:
! 3267: switch (new_state) {
! 3268: case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break;
! 3269: case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break;
! 3270: case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
! 3271: case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break;
! 3272: default: cp = "GPS antenna: ?"; break;
! 3273: }
! 3274:
! 3275: instance->ant_state = new_state;
! 3276: oncore_log(instance, LOG_NOTICE, cp);
! 3277: }
! 3278:
! 3279:
! 3280:
! 3281: static void
! 3282: oncore_chan_test(
! 3283: struct instance *instance
! 3284: )
! 3285: {
! 3286: /* subroutine oncore_Cj_id has determined the number of channels from the
! 3287: * model number of the attached oncore. This is not always correct since
! 3288: * the oncore could have non-standard firmware. Here we check (independently) by
! 3289: * trying a 6, 8, and 12 chan command, and see which responds.
! 3290: * Caution: more than one CAN respond.
! 3291: *
! 3292: * This #chan is used by the code rather than that calculated from the model number.
! 3293: */
! 3294:
! 3295: instance->o_state = ONCORE_CHECK_CHAN;
! 3296: oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN");
! 3297:
! 3298: instance->count3 = 1;
! 3299: oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
! 3300: oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
! 3301: oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
! 3302: }
! 3303:
! 3304:
! 3305:
! 3306: /* check for a GOOD Almanac, have we got one yet? */
! 3307:
! 3308: static void
! 3309: oncore_check_almanac(
! 3310: struct instance *instance
! 3311: )
! 3312: {
! 3313: if (instance->chan == 6) {
! 3314: instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
! 3315: instance->rsm.bad_fix = instance->BEHa[64]&0x52;
! 3316: } else if (instance->chan == 8) {
! 3317: instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
! 3318: instance->rsm.bad_fix = instance->BEHa[72]&0x52;
! 3319: } else if (instance->chan == 12) {
! 3320: int bits1, bits2, bits3;
! 3321:
! 3322: bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
! 3323: bits2 = instance->BEHa[130];
! 3324: instance->rsm.bad_almanac = (bits2 & 0x80);
! 3325: instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2);
! 3326: /* too few sat Bad Geom */
! 3327:
! 3328: bits3 = instance->BEHa[141]; /* UTC parameters */
! 3329: if (!instance->count5_set && (bits3 & 0xC0)) {
! 3330: instance->count5 = 2;
! 3331: instance->count5_set = 1;
! 3332: }
! 3333: #ifdef ONCORE_VERBOSE_CHECK_ALMANAC
! 3334: {
! 3335: char Msg[160];
! 3336:
! 3337: snprintf(Msg, sizeof(Msg),
! 3338: "DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x",
! 3339: instance->BEHa[129],
! 3340: instance->BEHa[130], bits1, bits2,
! 3341: bits3, instance->mode == MODE_0D,
! 3342: instance->mode == MODE_2D,
! 3343: instance->mode == MODE_3D,
! 3344: instance->rsm.bad_almanac,
! 3345: instance->rsm.bad_fix);
! 3346: oncore_log(instance, LOG_DEBUG, Msg);
! 3347: }
! 3348: #endif
! 3349: }
! 3350: }
! 3351:
! 3352:
! 3353:
! 3354: /* check the antenna for changes (did it get unplugged?) */
! 3355:
! 3356: static void
! 3357: oncore_check_antenna(
! 3358: struct instance *instance
! 3359: )
! 3360: {
! 3361: enum antenna_state antenna; /* antenna state */
! 3362:
! 3363: antenna = instance->ant_state;
! 3364: if (instance->chan == 12)
! 3365: antenna = (instance->BEHa[130] & 0x6 ) >> 1;
! 3366: else
! 3367: antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */
! 3368:
! 3369: oncore_antenna_report (instance, antenna);
! 3370: }
! 3371:
! 3372:
! 3373:
! 3374: /*
! 3375: * Check the leap second status once per day.
! 3376: *
! 3377: * Note that the ONCORE firmware for the Bj command is wrong at
! 3378: * least in the VP.
! 3379: * It starts advertising a LEAP SECOND as soon as the GPS satellite
! 3380: * data message (page 18, subframe 4) is updated to a date in the
! 3381: * future, and does not wait for the month that it will occur.
! 3382: * The event will usually be advertised several months in advance.
! 3383: * Since there is a one bit flag, there is no way to tell if it is
! 3384: * this month, or when...
! 3385: *
! 3386: * As such, we have the workaround below, of only checking for leap
! 3387: * seconds with the Bj command in June/December.
! 3388: *
! 3389: * The Gj command gives more information, and we can tell in which
! 3390: * month to apply the correction.
! 3391: *
! 3392: * Note that with the VP we COULD read the raw data message, and
! 3393: * interpret it ourselves, but since this is specific to this receiver
! 3394: * only, and the above workaround is adequate, we don't bother.
! 3395: */
! 3396:
! 3397: static void
! 3398: oncore_check_leap_sec(
! 3399: struct instance *instance
! 3400: )
! 3401: {
! 3402: oncore_cmd_Bl[2] = 1; /* just to be sure */
! 3403: if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */
! 3404: instance->Bj_day = instance->BEHa[5];
! 3405:
! 3406: if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */
! 3407: if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
! 3408: oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
! 3409: oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
! 3410: return;
! 3411: }
! 3412:
! 3413: if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */
! 3414: instance->count4 = 1;
! 3415:
! 3416: oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
! 3417: return;
! 3418: }
! 3419:
! 3420: /* Gj works for some 6/8 chan UT and the M12 */
! 3421: /* if no response from Gj in 5 sec, we try Bj */
! 3422: /* which isnt implemented in all the GT/UT either */
! 3423:
! 3424: if (instance->count4) { /* delay, waiting for Gj response */
! 3425: if (instance->saw_Gj == 1)
! 3426: instance->count4 = 0;
! 3427: else if (instance->count4++ > 5) { /* delay, waiting for Gj response */
! 3428: instance->saw_Gj = -1; /* didnt see it, will use Bj */
! 3429: instance->count4 = 0;
! 3430: if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
! 3431: oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
! 3432: oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
! 3433: }
! 3434: }
! 3435: }
! 3436:
! 3437:
! 3438:
! 3439: /* check the message checksum,
! 3440: * buf points to START of message ( @@ )
! 3441: * len is length WITH CR/LF.
! 3442: */
! 3443:
! 3444: static int
! 3445: oncore_checksum_ok(
! 3446: u_char *buf,
! 3447: int len
! 3448: )
! 3449: {
! 3450: int i, j;
! 3451:
! 3452: j = 0;
! 3453: for (i = 2; i < len-3; i++)
! 3454: j ^= buf[i];
! 3455:
! 3456: return(j == buf[len-3]);
! 3457: }
! 3458:
! 3459:
! 3460:
! 3461: static void
! 3462: oncore_compute_dH(
! 3463: struct instance *instance
! 3464: )
! 3465: {
! 3466: int GPS, MSL;
! 3467: char Msg[160];
! 3468:
! 3469: /* Here calculate dH = GPS - MSL for output message */
! 3470: /* also set Altitude Hold mode if GT */
! 3471:
! 3472: instance->have_dH = 1;
! 3473: if (instance->chan == 12) {
! 3474: GPS = buf_w32(&instance->BEHa[39]);
! 3475: MSL = buf_w32(&instance->BEHa[43]);
! 3476: } else {
! 3477: GPS = buf_w32(&instance->BEHa[23]);
! 3478: MSL = buf_w32(&instance->BEHa[27]);
! 3479: }
! 3480: instance->dH = GPS - MSL;
! 3481: instance->dH /= 100.;
! 3482:
! 3483: /* if MSL is not set, the calculation is meaningless */
! 3484:
! 3485: if (MSL) { /* not set ! */
! 3486: snprintf(Msg, sizeof(Msg), "dH = (GPS - MSL) = %.2fm",
! 3487: instance->dH);
! 3488: oncore_log(instance, LOG_INFO, Msg);
! 3489: }
! 3490: }
! 3491:
! 3492:
! 3493:
! 3494: /*
! 3495: * try loading Almanac from shmem (where it was copied from shmem_old
! 3496: */
! 3497:
! 3498: static void
! 3499: oncore_load_almanac(
! 3500: struct instance *instance
! 3501: )
! 3502: {
! 3503: u_char *cp, Cmd[20];
! 3504: int n;
! 3505: struct timeval tv;
! 3506: struct tm *tm;
! 3507:
! 3508: if (!instance->shmem)
! 3509: return;
! 3510:
! 3511: #ifndef ONCORE_VERBOSE_LOAD_ALMANAC
! 3512: for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
! 3513: cp += (n + 3)) {
! 3514: if (!strncmp((char *) cp, "@@Cb", 4) &&
! 3515: oncore_checksum_ok(cp, 33) &&
! 3516: (*(cp+4) == 4 || *(cp+4) == 5)) {
! 3517: write(instance->ttyfd, cp, n);
! 3518: oncore_print_Cb(instance, cp);
! 3519: }
! 3520: }
! 3521: #else /* ONCORE_VERBOSE_LOAD_ALMANAC follows */
! 3522: for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
! 3523: cp += (n+3)) {
! 3524: char Msg[160];
! 3525:
! 3526: snprintf(Msg, sizeof(Msg), "See %c%c%c%c %d", *(cp),
! 3527: *(cp+1), *(cp+2), *(cp+3), *(cp+4));
! 3528: oncore_log(instance, LOG_DEBUG, Msg);
! 3529:
! 3530: if (!strncmp(cp, "@@Cb", 4)) {
! 3531: oncore_print_Cb(instance, cp);
! 3532: if (oncore_checksum_ok(cp, 33)) {
! 3533: if (*(cp+4) == 4 || *(cp+4) == 5) {
! 3534: oncore_log(instance, LOG_DEBUG, "GOOD SF");
! 3535: write(instance->ttyfd, cp, n);
! 3536: } else
! 3537: oncore_log(instance, LOG_DEBUG, "BAD SF");
! 3538: } else
! 3539: oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM");
! 3540: }
! 3541: }
! 3542: #endif
! 3543:
! 3544: /* Must load position and time or the Almanac doesn't do us any good */
! 3545:
! 3546: if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */
! 3547: oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM");
! 3548: for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
! 3549: if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) ||
! 3550: (instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) ||
! 3551: (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
! 3552: int ii, jj, kk;
! 3553:
! 3554: instance->posn_set = 1;
! 3555: ii = buf_w32(cp + 15);
! 3556: jj = buf_w32(cp + 19);
! 3557: kk = buf_w32(cp + 23);
! 3558: #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
! 3559: {
! 3560: char Msg[160];
! 3561: snprintf(Msg, sizeof(Msg),
! 3562: "SHMEM posn = %ld (%d, %d, %d)",
! 3563: (long)(cp-instance->shmem),
! 3564: ii, jj, kk);
! 3565: oncore_log(instance, LOG_DEBUG, Msg);
! 3566: }
! 3567: #endif
! 3568: if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
! 3569: instance->ss_lat = ii;
! 3570: instance->ss_long = jj;
! 3571: instance->ss_ht = kk;
! 3572: }
! 3573: }
! 3574: }
! 3575: }
! 3576: oncore_set_posn(instance);
! 3577:
! 3578: /* and set time to time from Computer clock */
! 3579:
! 3580: GETTIMEOFDAY(&tv, 0);
! 3581: tm = gmtime((const time_t *) &tv.tv_sec);
! 3582:
! 3583: #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
! 3584: {
! 3585: char Msg[160];
! 3586: snprintf(Msg, sizeof(Msg), "DATE %d %d %d, %d %d %d",
! 3587: 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
! 3588: tm->tm_hour, tm->tm_min, tm->tm_sec);
! 3589: oncore_log(instance, LOG_DEBUG, Msg);
! 3590: }
! 3591: #endif
! 3592: if (instance->chan == 12) {
! 3593: memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
! 3594: Cmd[-2+4] = tm->tm_mon + 1;
! 3595: Cmd[-2+5] = tm->tm_mday;
! 3596: Cmd[-2+6] = (1900+tm->tm_year)/256;
! 3597: Cmd[-2+7] = (1900+tm->tm_year)%256;
! 3598: Cmd[-2+8] = tm->tm_hour;
! 3599: Cmd[-2+9] = tm->tm_min;
! 3600: Cmd[-2+10] = tm->tm_sec;
! 3601: Cmd[-2+11] = 0;
! 3602: Cmd[-2+12] = 0;
! 3603: Cmd[-2+13] = 0;
! 3604: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Gb));
! 3605: } else {
! 3606: /* First set GMT offset to zero */
! 3607:
! 3608: oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
! 3609:
! 3610: memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
! 3611: Cmd[-2+4] = tm->tm_mon + 1;
! 3612: Cmd[-2+5] = tm->tm_mday;
! 3613: Cmd[-2+6] = (1900+tm->tm_year)/256;
! 3614: Cmd[-2+7] = (1900+tm->tm_year)%256;
! 3615: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ac));
! 3616:
! 3617: memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
! 3618: Cmd[-2+4] = tm->tm_hour;
! 3619: Cmd[-2+5] = tm->tm_min;
! 3620: Cmd[-2+6] = tm->tm_sec;
! 3621: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Aa));
! 3622: }
! 3623:
! 3624: oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac");
! 3625: }
! 3626:
! 3627:
! 3628:
! 3629: /* Almanac data input */
! 3630:
! 3631: static void
! 3632: oncore_print_Cb(
! 3633: struct instance *instance,
! 3634: u_char *cp
! 3635: )
! 3636: {
! 3637: #ifdef ONCORE_VERBOSE_CB
! 3638: int ii;
! 3639: char Msg[160], Msg2[10];
! 3640:
! 3641: snprintf(Msg, sizeof(Msg), "DEBUG: See: %c%c%c%c", *(cp),
! 3642: *(cp+1), *(cp+2), *(cp+3));
! 3643: oncore_log(instance, LOG_DEBUG, Msg);
! 3644: snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4),
! 3645: *(cp+5));
! 3646: for(ii = 0; ii < 33; ii++) {
! 3647: snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii));
! 3648: strncat(Msg, Msg2, sizeof(Msg));
! 3649: }
! 3650: oncore_log(instance, LOG_DEBUG, Msg);
! 3651:
! 3652: snprintf(Msg, sizeof(Msg), "Debug: Cb: [%d,%d]", *(cp+4),
! 3653: *(cp+5));
! 3654: oncore_log(instance, LOG_DEBUG, Msg);
! 3655: #endif
! 3656: }
! 3657:
! 3658:
! 3659: #if 0
! 3660: static void
! 3661: oncore_print_array(
! 3662: u_char *cp,
! 3663: int n
! 3664: )
! 3665: {
! 3666: int jj, i, j, nn;
! 3667:
! 3668: nn = 0;
! 3669: printf("\nTOP\n");
! 3670: jj = n/16;
! 3671: for (j=0; j<jj; j++) {
! 3672: printf("%4d: ", nn);
! 3673: nn += 16;
! 3674: for (i=0; i<16; i++)
! 3675: printf(" %o", *cp++);
! 3676: printf("\n");
! 3677: }
! 3678: }
! 3679: #endif
! 3680:
! 3681:
! 3682: static void
! 3683: oncore_print_posn(
! 3684: struct instance *instance
! 3685: )
! 3686: {
! 3687: char Msg[120], ew, ns;
! 3688: double xd, xm, xs, yd, ym, ys, hm, hft;
! 3689: int idx, idy, is, imx, imy;
! 3690: long lat, lon;
! 3691:
! 3692: oncore_log(instance, LOG_INFO, "Posn:");
! 3693: ew = 'E';
! 3694: lon = instance->ss_long;
! 3695: if (lon < 0) {
! 3696: ew = 'W';
! 3697: lon = -lon;
! 3698: }
! 3699:
! 3700: ns = 'N';
! 3701: lat = instance->ss_lat;
! 3702: if (lat < 0) {
! 3703: ns = 'S';
! 3704: lat = -lat;
! 3705: }
! 3706:
! 3707: hm = instance->ss_ht/100.;
! 3708: hft= hm/0.3048;
! 3709:
! 3710: xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */
! 3711: yd = lon/3600000.;
! 3712: snprintf(Msg, sizeof(Msg),
! 3713: "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS",
! 3714: ns, xd, ew, yd, hm, hft);
! 3715: oncore_log(instance, LOG_INFO, Msg);
! 3716:
! 3717: idx = xd;
! 3718: idy = yd;
! 3719: imx = lat%3600000;
! 3720: imy = lon%3600000;
! 3721: xm = imx/60000.;
! 3722: ym = imy/60000.;
! 3723: snprintf(Msg, sizeof(Msg),
! 3724: "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
! 3725: oncore_log(instance, LOG_INFO, Msg);
! 3726:
! 3727: imx = xm;
! 3728: imy = ym;
! 3729: is = lat%60000;
! 3730: xs = is/1000.;
! 3731: is = lon%60000;
! 3732: ys = is/1000.;
! 3733: snprintf(Msg, sizeof(Msg),
! 3734: "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS",
! 3735: ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
! 3736: oncore_log(instance, LOG_INFO, Msg);
! 3737: }
! 3738:
! 3739:
! 3740:
! 3741: /*
! 3742: * write message to Oncore.
! 3743: */
! 3744:
! 3745: static void
! 3746: oncore_sendmsg(
! 3747: struct instance *instance,
! 3748: u_char *ptr,
! 3749: size_t len
! 3750: )
! 3751: {
! 3752: int fd;
! 3753: u_char cs = 0;
! 3754:
! 3755: fd = instance->ttyfd;
! 3756: #ifdef ONCORE_VERBOSE_SENDMSG
! 3757: if (debug > 4) {
! 3758: char Msg[120];
! 3759:
! 3760: snprintf(Msg, sizeof(Msg), "ONCORE: Send @@%c%c %d",
! 3761: ptr[0], ptr[1], (int)len);
! 3762: oncore_log(instance, LOG_DEBUG, Msg);
! 3763: }
! 3764: #endif
! 3765: write(fd, "@@", (size_t) 2);
! 3766: write(fd, ptr, len);
! 3767: while (len--)
! 3768: cs ^= *ptr++;
! 3769: write(fd, &cs, (size_t) 1);
! 3770: write(fd, "\r\n", (size_t) 2);
! 3771: }
! 3772:
! 3773:
! 3774:
! 3775: static void
! 3776: oncore_set_posn(
! 3777: struct instance *instance
! 3778: )
! 3779: {
! 3780: int mode;
! 3781: u_char Cmd[20];
! 3782:
! 3783: /* Turn OFF position hold, it needs to be off to set position (for some units),
! 3784: will get set ON in @@Ea later */
! 3785:
! 3786: if (instance->chan == 12)
! 3787: oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
! 3788: else {
! 3789: oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
! 3790: oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
! 3791: }
! 3792:
! 3793: mode = instance->init_type;
! 3794:
! 3795: if (mode != 0) { /* first set posn hold position */
! 3796: memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */
! 3797: w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
! 3798: w32_buf(&Cmd[-2+8], (int) instance->ss_long);
! 3799: w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
! 3800: Cmd[-2+16] = 0;
! 3801: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */
! 3802:
! 3803: memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
! 3804: w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
! 3805: Cmd[-2+8] = 0;
! 3806: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */
! 3807:
! 3808: /* next set current position */
! 3809:
! 3810: if (instance->chan == 12) {
! 3811: memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
! 3812: w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
! 3813: w32_buf(&Cmd[-2+8], (int) instance->ss_long);
! 3814: w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
! 3815: Cmd[-2+16] = 0;
! 3816: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */
! 3817: } else {
! 3818: memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
! 3819: w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
! 3820: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */
! 3821:
! 3822: memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
! 3823: w32_buf(&Cmd[-2+4], (int) instance->ss_long);
! 3824: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */
! 3825:
! 3826: memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
! 3827: w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
! 3828: Cmd[-2+8] = 0;
! 3829: oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */
! 3830: }
! 3831:
! 3832: /* Finally, turn on position hold */
! 3833:
! 3834: if (instance->chan == 12)
! 3835: oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
! 3836: else
! 3837: oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1));
! 3838: }
! 3839: }
! 3840:
! 3841:
! 3842:
! 3843: static void
! 3844: oncore_set_traim(
! 3845: struct instance *instance
! 3846: )
! 3847: {
! 3848: char Msg[160];
! 3849:
! 3850: if (instance->traim_in != -1) /* set in Input */
! 3851: instance->traim = instance->traim_in;
! 3852: else
! 3853: instance->traim = instance->traim_ck;
! 3854:
! 3855: snprintf(Msg, sizeof(Msg), "Input says TRAIM = %d",
! 3856: instance->traim_in);
! 3857: oncore_log(instance, LOG_INFO, Msg);
! 3858: snprintf(Msg, sizeof(Msg), "Model # says TRAIM = %d",
! 3859: instance->traim_id);
! 3860: oncore_log(instance, LOG_INFO, Msg);
! 3861: snprintf(Msg, sizeof(Msg), "Testing says TRAIM = %d",
! 3862: instance->traim_ck);
! 3863: oncore_log(instance, LOG_INFO, Msg);
! 3864: snprintf(Msg, sizeof(Msg), "Using TRAIM = %d",
! 3865: instance->traim);
! 3866: oncore_log(instance, LOG_INFO, Msg);
! 3867:
! 3868: if (instance->traim_ck == 1 && instance->traim == 0) {
! 3869: /* if it should be off, and I turned it on during testing,
! 3870: then turn it off again */
! 3871: if (instance->chan == 6)
! 3872: oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
! 3873: else if (instance->chan == 8)
! 3874: oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
! 3875: else /* chan == 12 */
! 3876: oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
! 3877: oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
! 3878: }
! 3879: }
! 3880:
! 3881:
! 3882:
! 3883: /*
! 3884: * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
! 3885: */
! 3886:
! 3887: static void
! 3888: oncore_shmem_get_3D(
! 3889: struct instance *instance
! 3890: )
! 3891: {
! 3892: if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */
! 3893: instance->shmem_reset = 1;
! 3894: if (instance->chan == 12) {
! 3895: if (instance->shmem_Posn == 2)
! 3896: oncore_sendmsg(instance, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */
! 3897: else
! 3898: oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */
! 3899: } else {
! 3900: if (instance->saw_At) { /* out of 0D -> 3D mode */
! 3901: oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0));
! 3902: if (instance->shmem_Posn == 2) /* 3D -> 2D mode */
! 3903: oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
! 3904: } else
! 3905: oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
! 3906: }
! 3907: } else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
! 3908: instance->shmem_reset = 0;
! 3909: if (instance->chan == 12)
! 3910: oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */
! 3911: else {
! 3912: if (instance->saw_At) {
! 3913: if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */
! 3914: oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
! 3915: oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */
! 3916: } else
! 3917: oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
! 3918: }
! 3919: }
! 3920: }
! 3921:
! 3922:
! 3923:
! 3924: /*
! 3925: * Here we do the Software SiteSurvey.
! 3926: * We have to average our own position for the Position Hold Mode
! 3927: * We use Heights from the GPS ellipsoid.
! 3928: * We check for the END of either HW or SW SiteSurvey.
! 3929: */
! 3930:
! 3931: static void
! 3932: oncore_ss(
! 3933: struct instance *instance
! 3934: )
! 3935: {
! 3936: char Msg[160];
! 3937: double lat, lon, ht;
! 3938:
! 3939:
! 3940: if (instance->site_survey == ONCORE_SS_HW) {
! 3941: /*
! 3942: * Check to see if Hardware SiteSurvey has Finished.
! 3943: */
! 3944:
! 3945: if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) ||
! 3946: (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
! 3947: oncore_log(instance, LOG_INFO, "Now in 0D mode");
! 3948:
! 3949: if (instance->chan == 12)
! 3950: oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
! 3951: else
! 3952: oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
! 3953:
! 3954: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
! 3955: instance->site_survey = ONCORE_SS_DONE;
! 3956: }
! 3957: } else {
! 3958: /*
! 3959: * Must be a Software Site Survey.
! 3960: */
! 3961:
! 3962: if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */
! 3963: return;
! 3964:
! 3965: if (instance->mode != MODE_3D) /* Use only 3D Fixes */
! 3966: return;
! 3967:
! 3968: instance->ss_lat += buf_w32(&instance->BEHa[15]);
! 3969: instance->ss_long += buf_w32(&instance->BEHa[19]);
! 3970: instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */
! 3971: instance->ss_count++;
! 3972:
! 3973: if (instance->ss_count != POS_HOLD_AVERAGE)
! 3974: return;
! 3975:
! 3976: instance->ss_lat /= POS_HOLD_AVERAGE;
! 3977: instance->ss_long /= POS_HOLD_AVERAGE;
! 3978: instance->ss_ht /= POS_HOLD_AVERAGE;
! 3979:
! 3980: snprintf(Msg, sizeof(Msg),
! 3981: "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
! 3982: instance->ss_lat, instance->ss_long,
! 3983: instance->ss_ht);
! 3984: oncore_log(instance, LOG_NOTICE, Msg);
! 3985: lat = instance->ss_lat/3600000.;
! 3986: lon = instance->ss_long/3600000.;
! 3987: ht = instance->ss_ht/100;
! 3988: snprintf(Msg, sizeof(Msg),
! 3989: "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
! 3990: lat, lon, ht);
! 3991: oncore_log(instance, LOG_NOTICE, Msg);
! 3992:
! 3993: oncore_set_posn(instance);
! 3994:
! 3995: oncore_log(instance, LOG_INFO, "Now in 0D mode");
! 3996:
! 3997: oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
! 3998: instance->site_survey = ONCORE_SS_DONE;
! 3999: }
! 4000: }
! 4001:
! 4002:
! 4003:
! 4004: static int
! 4005: oncore_wait_almanac(
! 4006: struct instance *instance
! 4007: )
! 4008: {
! 4009: if (instance->rsm.bad_almanac) {
! 4010: instance->counta++;
! 4011: if (instance->counta%5 == 0)
! 4012: oncore_log(instance, LOG_INFO, "Waiting for Almanac");
! 4013:
! 4014: /*
! 4015: * If we get here (first time) then we don't have an almanac in memory.
! 4016: * Check if we have a SHMEM, and if so try to load whatever is there.
! 4017: */
! 4018:
! 4019: if (!instance->almanac_from_shmem) {
! 4020: instance->almanac_from_shmem = 1;
! 4021: oncore_load_almanac(instance);
! 4022: }
! 4023: return(1);
! 4024: } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
! 4025: commands, and can finally check for TRAIM. Again, we set a delay
! 4026: (5sec) and wait for things to settle down */
! 4027:
! 4028: if (instance->chan == 6)
! 4029: oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
! 4030: else if (instance->chan == 8)
! 4031: oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En));
! 4032: else if (instance->chan == 12) {
! 4033: oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
! 4034: oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
! 4035: oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
! 4036: }
! 4037: instance->traim_delay = 1;
! 4038:
! 4039: oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC");
! 4040:
! 4041: instance->o_state = ONCORE_RUN;
! 4042: oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN");
! 4043: }
! 4044: return(0);
! 4045: }
! 4046:
! 4047:
! 4048:
! 4049: static void
! 4050: oncore_log (
! 4051: struct instance *instance,
! 4052: int log_level,
! 4053: const char *msg
! 4054: )
! 4055: {
! 4056: int i;
! 4057: char Msg[200];
! 4058:
! 4059: snprintf(Msg, sizeof(Msg), "ONCORE[%d]: %s", instance->unit,
! 4060: msg);
! 4061: syslog(log_level, Msg);
! 4062:
! 4063: i = strlen(msg);
! 4064:
! 4065: if (i > 127) {
! 4066: snprintf(Msg, sizeof(Msg),
! 4067: "Internal Error: max error msg length exceeded in clockstats file (%d)",
! 4068: i);
! 4069: record_clock_stats(&(instance->peer->srcadr), Msg);
! 4070: record_clock_stats(&(instance->peer->srcadr), "Start of message was");
! 4071: strncpy(Msg, msg, 120);
! 4072: record_clock_stats(&(instance->peer->srcadr), Msg);
! 4073: } else { /* now put ONCORE[n]: ahead of message if it will fit */
! 4074: if (i < 110) {
! 4075: snprintf(Msg, sizeof(Msg), "ONCORE[%d]: %s",
! 4076: instance->unit, msg);
! 4077: record_clock_stats(&(instance->peer->srcadr), Msg);
! 4078: } else
! 4079: record_clock_stats(&(instance->peer->srcadr), msg);
! 4080: }
! 4081:
! 4082: #ifdef ONCORE_VERBOSE_ONCORE_LOG
! 4083: instance->max_len = max(i, instance->max_len);
! 4084: instance->max_count++;
! 4085: if (instance->max_count % 100 == 0) {
! 4086: snprintf(Msg, sizeof(Msg),
! 4087: "Max Message Length so far is %d",
! 4088: instance->max_len);
! 4089: oncore_log(instance, LOG_INFO, Msg);
! 4090: }
! 4091: #endif
! 4092: }
! 4093:
! 4094: #else
! 4095: int refclock_oncore_bs;
! 4096: #endif /* REFCLOCK && CLOCK_ONCORE */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>