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 * ----------------------------------------------------------------------------
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
15 * The receivers without position hold (GT, GT+) will be less accurate.
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
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
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
54 * --------------------------------------------------------------------------
55 * Reg Clemens (Feb 2006)
56 * Fix some gcc4 compiler complaints
57 * Fix possible segfault in oncore_init_shmem
58 * change all (possible) fprintf(stderr, to record_clock_stats
59 * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
60 * immediately after new Almanac Read.
61 * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
62 * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
63 * the new one. Compiles depending on timepps.h seen.
64 * --------------------------------------------------------------------------
65 * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
66 * (the oncore driver was setting the wrong ntpd variable)
67 * --------------------------------------------------------------------------
68 * Reg.Clemens (Mar 2004)
69 * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
70 * SCO, you now need to use one of the timepps.h files in the root dir.
71 * this driver will 'grab' it for you if you dont have one in /usr/include
72 * --------------------------------------------------------------------------
73 * This code uses the two devices
74 * /dev/oncore.serial.n
76 * which may be linked to the same device.
77 * and can read initialization data from the file
78 * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
79 * n or N are the unit number, viz 127.127.30.N.
80 * --------------------------------------------------------------------------
81 * Reg.Clemens <reg@dwf.com> Sep98.
82 * Original code written for FreeBSD.
83 * With these mods it works on FreeBSD, SunOS, Solaris and Linux
84 * (SunOS 4.1.3 + ppsclock)
86 * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
88 * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
89 * state machine state) are printed to CLOCKSTATS if that file is enabled
92 * --------------------------------------------------------------------------
94 * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
95 * doing an average of 10000 valid 2D and 3D fixes is what the automatic
96 * site survey mode does. Looking at the output from the receiver
97 * it seems like it is only using 3D fixes.
98 * When we do it ourselves, take 10000 3D fixes.
101 #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */
104 * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
105 * "STATUS" line in the oncore config file, which contains the most recent
106 * copy of all types of messages we recognize. This file can be mmap(2)'ed
107 * by monitoring and statistics programs.
109 * See separate HTML documentation for this option.
116 #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
120 #include "ntp_unixtime.h"
121 #include "ntp_refclock.h"
122 #include "ntp_stdlib.h"
126 #include <sys/stat.h>
127 #ifdef ONCORE_SHMEM_STATUS
128 # ifdef HAVE_SYS_MMAN_H
129 # include <sys/mman.h>
131 # define MAP_FAILED ((u_char *) -1)
132 # endif /* MAP_FAILED */
133 # endif /* HAVE_SYS_MMAN_H */
134 #endif /* ONCORE_SHMEM_STATUS */
137 # include "ppsapi_timepps.h"
140 #ifdef HAVE_SYS_SIO_H
141 # include <sys/sio.h>
156 enum site_survey_state {
165 ONCORE_ANTENNA_UNKNOWN = -1,
166 ONCORE_ANTENNA_OK = 0,
167 ONCORE_ANTENNA_OC = 1,
168 ONCORE_ANTENNA_UC = 2,
169 ONCORE_ANTENNA_NV = 3
172 /* Model Name, derived from the @@Cj message.
173 * Used to initialize some variables.
189 /* the bits that describe these properties are in the same place
190 * on the VP/UT, but have moved on the M12. As such we extract
191 * them, and use them from this struct.
203 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
204 * see what mode it is in. The bits on the M12 are multiplexed with
205 * other messages, so we have to 'keep' the last known mode here.
216 int unit; /* 127.127.30.unit */
217 struct refclockproc *pp;
220 int ttyfd; /* TTY file descriptor */
221 int ppsfd; /* PPS file descriptor */
222 int shmemfd; /* Status shm descriptor */
225 enum receive_state o_state; /* Receive state */
226 enum posn_mode mode; /* 0D, 2D, 3D */
227 enum site_survey_state site_survey; /* Site Survey state */
228 enum antenna_state ant_state; /* antenna state */
232 u_long delay; /* ns */
233 long offset; /* ns */
244 u_char almanac_from_shmem;
253 enum oncore_model model;
257 u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
258 s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
259 /* the following 7 are all timing counters */
260 u_char traim_delay; /* seconds counter, waiting for reply */
261 u_char count; /* cycles thru Ea before starting */
262 u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */
263 u_char count2; /* cycles thru Ea after count, to check for @@Ea */
264 u_char count3; /* cycles thru Ea checking for # channels */
265 u_char count4; /* cycles thru leap after Gj to issue Bj */
266 u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */
267 u_char count5_set; /* only set count5 once */
269 u_char timeout; /* count to retry Cj after Fa self-test */
271 struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */
277 u_char BEHa[160]; /* Ba, Ea or Ha */
278 u_char BEHn[80]; /* Bn , En , or Hn */
280 u_char Ag; /* Satellite mask angle */
288 s_char chan_in; /* chan number from INPUT, will always use it */
289 u_char chan_id; /* chan number determined from part number */
290 u_char chan_ck; /* chan number determined by sending commands to hardware */
291 s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */
292 s_char traim_id; /* TRAIM determined from part number */
293 u_char traim_ck; /* TRAIM determined by sending commands to hardware */
294 u_char once; /* one pass code at top of BaEaHa */
299 #define rcvbuf instance->Rcvbuf
300 #define rcvptr instance->Rcvptr
302 static int oncore_start P((int, struct peer *));
303 static void oncore_poll P((int, struct peer *));
304 static void oncore_shutdown P((int, struct peer *));
305 static void oncore_consume P((struct instance *));
306 static void oncore_read_config P((struct instance *));
307 static void oncore_receive P((struct recvbuf *));
308 static int oncore_ppsapi P((struct instance *));
309 static void oncore_get_timestamp P((struct instance *, long, long));
310 static void oncore_init_shmem P((struct instance *));
312 static void oncore_antenna_report P((struct instance *, enum antenna_state));
313 static void oncore_chan_test P((struct instance *));
314 static void oncore_check_almanac P((struct instance *));
315 static void oncore_check_antenna P((struct instance *));
316 static void oncore_check_leap_sec P((struct instance *));
317 static int oncore_checksum_ok P((u_char *, int));
318 static void oncore_compute_dH P((struct instance *));
319 static void oncore_load_almanac P((struct instance *));
320 static void oncore_print_Cb P((struct instance *, u_char *));
321 /* static void oncore_print_array P((u_char *, int)); */
322 static void oncore_print_posn P((struct instance *));
323 static void oncore_sendmsg P((int, u_char *, size_t));
324 static void oncore_set_posn P((struct instance *));
325 static void oncore_set_traim P((struct instance *));
326 static void oncore_shmem_get_3D P((struct instance *));
327 static void oncore_ss P((struct instance *));
328 static int oncore_wait_almanac P((struct instance *));
330 static void oncore_msg_any P((struct instance *, u_char *, size_t, int));
331 static void oncore_msg_Adef P((struct instance *, u_char *, size_t));
332 static void oncore_msg_Ag P((struct instance *, u_char *, size_t));
333 static void oncore_msg_As P((struct instance *, u_char *, size_t));
334 static void oncore_msg_At P((struct instance *, u_char *, size_t));
335 static void oncore_msg_Ay P((struct instance *, u_char *, size_t));
336 static void oncore_msg_Az P((struct instance *, u_char *, size_t));
337 static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t));
338 static void oncore_msg_Bd P((struct instance *, u_char *, size_t));
339 static void oncore_msg_Bj P((struct instance *, u_char *, size_t));
340 static void oncore_msg_BnEnHn P((struct instance *, u_char *, size_t));
341 static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t));
342 static void oncore_msg_Cb P((struct instance *, u_char *, size_t));
343 static void oncore_msg_Cf P((struct instance *, u_char *, size_t));
344 static void oncore_msg_Cj P((struct instance *, u_char *, size_t));
345 static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t));
346 static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
347 static void oncore_msg_Ga P((struct instance *, u_char *, size_t));
348 static void oncore_msg_Gb P((struct instance *, u_char *, size_t));
349 static void oncore_msg_Gj P((struct instance *, u_char *, size_t));
350 static void oncore_msg_Sz P((struct instance *, u_char *, size_t));
352 struct refclock refclock_oncore = {
353 oncore_start, /* start up driver */
354 oncore_shutdown, /* shut down driver */
355 oncore_poll, /* transmit poll message */
356 noentry, /* not used */
357 noentry, /* not used */
358 noentry, /* not used */
359 NOFLAGS /* not used */
363 * Understanding the next bit here is not easy unless you have a manual
364 * for the the various Oncore Models.
367 static struct msg_desc {
370 void (*handler) P((struct instance *, u_char *, size_t));
373 } oncore_messages[] = {
374 /* Ea and En first since they're most common */
375 { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
376 { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
377 { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
378 { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
379 { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
380 { "Hn", 78, oncore_msg_BnEnHn, "" },
383 { "Ad", 11, oncore_msg_Adef, "" },
384 { "Ae", 11, oncore_msg_Adef, "" },
385 { "Af", 15, oncore_msg_Adef, "" },
386 { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */
387 { "As", 20, oncore_msg_As, "" },
388 { "At", 8, oncore_msg_At, "" },
392 { "Ay", 11, oncore_msg_Ay, "" },
393 { "Az", 11, oncore_msg_Az, "" },
396 { "Bd", 23, oncore_msg_Bd, "" },
397 { "Bj", 8, oncore_msg_Bj, "" },
398 { "Ca", 9, oncore_msg_CaFaIa, "" },
399 { "Cb", 33, oncore_msg_Cb, "" },
400 { "Cf", 7, oncore_msg_Cf, "" },
403 { "Cj", 294, oncore_msg_Cj, "" },
405 { "Fa", 9, oncore_msg_CaFaIa, "" },
406 { "Ga", 20, oncore_msg_Ga, "" },
407 { "Gb", 17, oncore_msg_Gb, "" },
411 { "Gj", 21, oncore_msg_Gj, "" },
412 { "Ia", 10, oncore_msg_CaFaIa, "" },
413 { "Sz", 8, oncore_msg_Sz, "" },
418 static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */
419 static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */
420 static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */
421 static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */
422 static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */
423 static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */
424 static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */
425 static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */
426 static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */
427 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 */
428 static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */
429 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */
430 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */
431 static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */
432 static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */
433 static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */
434 static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */
435 static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */
436 static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */
437 static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */
438 static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */
439 static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */
440 static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */
441 static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */
442 static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */
443 static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */
444 static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */
445 static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */
446 static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */
447 static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */
448 static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */
449 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 */
450 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 */
451 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 */
452 static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */
453 static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */
454 static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */
455 static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */
456 static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */
457 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */
458 static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */
459 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 */
460 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 */
461 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 */
462 static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */
463 static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */
464 static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */
465 0xff, 0xff, 0xff, 0xff, /* */
466 0xff, 0xff, 0xff, 0xff, 0xff }; /* */
467 static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */
468 static u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */
469 static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */
470 static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */
471 static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */
472 static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */
473 static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */
474 static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */
475 static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */
476 static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */
477 static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */
478 static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */
479 static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */
480 static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */
482 /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
483 * the GT had Au,Av, but not As,At
484 * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
486 * dont see Bd in UT/GT thru 1999
487 * Gj in UT as of 3.0, 1999 , Bj as of 1.3
490 static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
491 "Aug", "Sep", "Oct", "Nov", "Dec" };
493 #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */
494 #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */
496 #define SPEED B9600 /* Oncore Binary speed (9600 bps) */
499 * Assemble and disassemble 32bit signed quantities from a buffer.
503 /* to buffer, int w, u_char *buf */
504 #define w32_buf(buf,w) { u_int i_tmp; \
505 i_tmp = (w<0) ? (~(-w)+1) : (w); \
506 (buf)[0] = (i_tmp >> 24) & 0xff; \
507 (buf)[1] = (i_tmp >> 16) & 0xff; \
508 (buf)[2] = (i_tmp >> 8) & 0xff; \
509 (buf)[3] = (i_tmp ) & 0xff; \
512 #define w32(buf) (((buf)[0]&0xff) << 24 | \
513 ((buf)[1]&0xff) << 16 | \
514 ((buf)[2]&0xff) << 8 | \
517 /* from buffer, char *buf, result to an int */
518 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
522 * oncore_start - initialize data for processing
531 #define STRING_LEN 32
532 register struct instance *instance;
533 struct refclockproc *pp;
535 char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
537 struct stat stat1, stat2;
539 /* create instance structure for this unit */
541 if (!(instance = (struct instance *) malloc(sizeof *instance))) {
545 memset((char *) instance, 0, sizeof *instance);
547 /* initialize miscellaneous variables */
550 pp->unitptr = (caddr_t) instance;
552 instance->unit = unit;
553 instance->peer = peer;
554 instance->assert = 1;
557 instance->Bj_day = -1;
558 instance->traim = -1;
559 instance->traim_in = -1;
560 instance->chan_in = -1;
561 instance->model = ONCORE_UNKNOWN;
562 instance->mode = MODE_UNKNOWN;
563 instance->site_survey = ONCORE_SS_UNKNOWN;
564 instance->Ag = 0xff; /* Satellite mask angle, unset by user */
565 instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
567 peer->precision = -26;
570 pp->clockdesc = "Motorola Oncore GPS Receiver";
571 memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
573 cp = "ONCORE DRIVER -- CONFIGURING";
574 record_clock_stats(&(instance->peer->srcadr), cp);
576 instance->o_state = ONCORE_NO_IDEA;
577 cp = "state = ONCORE_NO_IDEA";
578 record_clock_stats(&(instance->peer->srcadr), cp);
581 * This is a bit complicated, a we dont want to open the same file twice
582 * (its a problem on some OS), and device2 may not exist for the new PPS
585 (void)sprintf(device1, DEVICE1, unit);
586 (void)sprintf(device2, DEVICE2, unit);
589 /* opening different devices for fd1 and fd2 presents no problems */
590 /* opening the SAME device twice, seems to be OS dependent.
591 (a) on Linux (no streams) no problem
592 (b) on SunOS (and possibly Solaris, untested), (streams)
593 never see the line discipline.
594 Since things ALWAYS work if we only open the device once, we check
595 to see if the two devices are in fact the same, then proceed to
599 if (stat(device1, &stat1)) {
600 sprintf(Msg, "Can't stat fd1 (%s)\n", device1);
601 record_clock_stats(&(instance->peer->srcadr), Msg);
605 if (stat(device2, &stat2)) {
606 sprintf(Msg, "Can't stat fd2 (%s)\n", device2);
607 record_clock_stats(&(instance->peer->srcadr), Msg);
611 if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
612 sprintf(Msg, "Can't open fd1 (%s)\n", device1);
613 record_clock_stats(&(instance->peer->srcadr), Msg);
617 if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */
619 else { /* different devices here */
620 if ((fd2=open(device2, O_RDWR)) < 0) {
621 sprintf(Msg, "Can't open fd2 (%s)\n", device2);
622 record_clock_stats(&(instance->peer->srcadr), Msg);
628 /* open ppsapi soure */
630 if (time_pps_create(num, &instance->pps_h) < 0) {
631 record_clock_stats(&(instance->peer->srcadr), "PPSAPI not found in kernel");
635 /* continue initialization */
637 instance->ttyfd = fd1;
638 instance->ppsfd = fd2;
640 /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
642 oncore_read_config(instance);
644 if (!oncore_ppsapi(instance))
647 pp->io.clock_recv = oncore_receive;
648 pp->io.srcclock = (caddr_t)peer;
651 if (!io_addclock(&pp->io)) {
652 record_clock_stats(&(instance->peer->srcadr), "ONCORE: io_addclock");
658 #ifdef ONCORE_SHMEM_STATUS
660 * Before starting ONCORE, lets setup SHMEM
661 * This will include merging an old SHMEM into the new one if
662 * an old one is found.
665 oncore_init_shmem(instance);
669 * This will return the Model of the Oncore receiver.
670 * and start the Initialization loop in oncore_msg_Cj.
673 instance->o_state = ONCORE_CHECK_ID;
674 cp = "state = ONCORE_CHECK_ID";
675 record_clock_stats(&(instance->peer->srcadr), cp);
677 instance->timeout = 4;
678 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
679 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
681 instance->pollcnt = 2;
687 * oncore_shutdown - shut down the clock
696 register struct instance *instance;
697 struct refclockproc *pp;
700 instance = (struct instance *) pp->unitptr;
702 io_closeclock(&pp->io);
704 time_pps_destroy (instance->pps_h);
706 close(instance->ttyfd);
708 if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
709 close(instance->ppsfd);
711 if (instance->shmemfd)
712 close(instance->shmemfd);
720 * oncore_poll - called by the transmit procedure
729 struct instance *instance;
731 instance = (struct instance *) peer->procptr->unitptr;
732 if (instance->timeout) {
736 if (instance->timeout == 0) {
737 cp = "Oncore: No response from @@Cj, shutting down driver";
738 record_clock_stats(&(instance->peer->srcadr), cp);
739 oncore_shutdown(unit, peer);
741 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
742 cp = "Oncore: Resend @@Cj";
743 record_clock_stats(&(instance->peer->srcadr), cp);
748 if (!instance->pollcnt)
749 refclock_report(peer, CEVNT_TIMEOUT);
752 peer->procptr->polls++;
753 instance->polled = 1;
764 struct instance *instance
767 int cap, mode, mode1;
770 if (time_pps_getcap(instance->pps_h, &cap) < 0) {
771 msyslog(LOG_ERR, "time_pps_getcap failed: %m");
775 if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
776 msyslog(LOG_ERR, "time_pps_getparams failed: %m");
780 /* nb. only turn things on, if someone else has turned something
781 * on before we get here, leave it alone!
784 if (instance->assert) {
786 mode = PPS_CAPTUREASSERT;
787 mode1 = PPS_OFFSETASSERT;
790 mode = PPS_CAPTURECLEAR;
791 mode1 = PPS_OFFSETCLEAR;
793 sprintf(Msg, "Initializing timeing to %s.", cp);
794 record_clock_stats(&(instance->peer->srcadr), Msg);
797 sprintf(Msg, "Can't set timeing to %s, exiting...", cp);
798 record_clock_stats(&(instance->peer->srcadr), Msg);
802 if (!(mode1 & cap)) {
803 sprintf(Msg, "Can't set PPS_%sCLEAR, this will increase jitter.", cp);
804 record_clock_stats(&(instance->peer->srcadr), Msg);
808 /* only set what is legal */
810 instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
812 if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
813 record_clock_stats(&(instance->peer->srcadr), "ONCORE: time_pps_setparams fails");
817 /* If HARDPPS is on, we tell kernel */
819 if (instance->hardpps) {
822 record_clock_stats(&(instance->peer->srcadr), "HARDPPS Set.");
824 if (instance->assert)
825 i = PPS_CAPTUREASSERT;
827 i = PPS_CAPTURECLEAR;
829 /* we know that 'i' is legal from above */
831 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
832 PPS_TSFMT_TSPEC) < 0) {
833 msyslog(LOG_ERR, "time_pps_kcbind failed: %m");
834 record_clock_stats(&(instance->peer->srcadr), "HARDPPS failed, abort...");
844 #ifdef ONCORE_SHMEM_STATUS
847 struct instance *instance
850 int i, l, n, fd, shmem_old_size, n1;
852 u_char *cp, *cp1, *buf, *shmem_old;
858 * The first thing we do is see if there is an instance->shmem_fname file (still)
859 * out there from a previous run. If so, we copy it in and use it to initialize
860 * shmem (so we won't lose our almanac if we need it).
865 if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
866 record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open SHMEM file");
869 shmem_old_size = sbuf.st_size;
870 if (shmem_old_size != 0) {
871 shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
872 if (shmem_old == NULL)
873 record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem_old");
875 read(fd, shmem_old, shmem_old_size);
880 /* OK, we now create the NEW SHMEM. */
882 if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
883 record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open shmem");
890 /* see how big it needs to be */
893 for (mp=oncore_messages; mp->flag[0]; mp++) {
895 /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
896 if (!strcmp(mp->flag, "Cb")) {
897 instance->shmem_Cb = n;
898 n += (mp->len + 3) * 34;
900 if (!strcmp(mp->flag, "Ba")) {
901 instance->shmem_Ba = n;
902 n += (mp->len + 3) * 3;
904 if (!strcmp(mp->flag, "Ea")) {
905 instance->shmem_Ea = n;
906 n += (mp->len + 3) * 3;
908 if (!strcmp(mp->flag, "Ha")) {
909 instance->shmem_Ha = n;
910 n += (mp->len + 3) * 3;
914 shmem_length = n + 2;
916 buf = malloc(shmem_length);
918 record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem");
919 close(instance->shmemfd);
926 memset(buf, 0, shmem_length);
928 /* next build the new SHMEM buffer in memory */
930 for (mp=oncore_messages; mp->flag[0]; mp++) {
932 buf[l + 0] = mp->len >> 8;
933 buf[l + 1] = mp->len & 0xff;
937 buf[l + 5] = mp->flag[0];
938 buf[l + 6] = mp->flag[1];
939 if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
940 if (!strcmp(mp->flag, "Cb"))
944 for (i=1; i<n; i++) {
945 buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
946 buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
947 buf[l + i * (mp->len+3) + 2] = 0;
948 buf[l + i * (mp->len+3) + 3] = '@';
949 buf[l + i * (mp->len+3) + 4] = '@';
950 buf[l + i * (mp->len+3) + 5] = mp->flag[0];
951 buf[l + i * (mp->len+3) + 6] = mp->flag[1];
956 /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
957 * copying the data in shmem_old to buf.
958 * When we are done we write it out and free both buffers.
959 * If the structure sizes dont agree, I will not copy.
960 * This could be due to an addition/deletion or a problem with the disk file.
964 if (shmem_old_size == shmem_length) {
965 for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) {
966 n1 = 256*(*(cp1-3)) + *(cp1-2);
967 if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
970 memcpy(cp, cp1, (size_t) n);
976 i = write(instance->shmemfd, buf, shmem_length);
979 if (i != shmem_length) {
980 record_clock_stats(&(instance->peer->srcadr), "ONCORE: error writing shmem");
981 close(instance->shmemfd);
985 instance->shmem = (u_char *) mmap(0, shmem_length,
986 PROT_READ | PROT_WRITE,
987 #ifdef MAP_HASSEMAPHORE
990 MAP_SHARED, instance->shmemfd, (off_t)0);
992 if (instance->shmem == (u_char *)MAP_FAILED) {
994 close(instance->shmemfd);
998 sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s",
999 (u_long) shmem_length, instance->shmem_fname);
1000 record_clock_stats(&(instance->peer->srcadr), Msg);
1002 #endif /* ONCORE_SHMEM_STATUS */
1007 * Read Input file if it exists.
1012 struct instance *instance
1016 * First we try to open the configuration file
1018 * where N is the unit number viz 127.127.30.N.
1019 * If we don't find it we try
1024 * If we don't find any then we don't have the cable delay or PPS offset
1025 * and we choose MODE (4) below.
1027 * Five Choices for MODE
1028 * (0) ONCORE is preinitialized, don't do anything to change it.
1029 * nb, DON'T set 0D mode, DON'T set Delay, position...
1030 * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1031 * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
1032 * lock this in, go to 0D mode.
1033 * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1034 * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
1035 * lock this in, go to 0D mode.
1036 * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
1037 * then this position is set as the INITIAL position of the ONCORE.
1038 * This can reduce the time to first fix.
1039 * -------------------------------------------------------------------------------
1040 * Note that an Oncore UT without a battery backup retains NO information if it is
1041 * power cycled, with a Battery Backup it remembers the almanac, etc.
1042 * For an Oncore VP, there is an eeprom that will contain this data, along with the
1043 * option of Battery Backup.
1044 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
1045 * power cycle, since there is nowhere to store the data.
1046 * -------------------------------------------------------------------------------
1048 * If we open one or the other of the files, we read it looking for
1049 * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
1050 * STATUS, POSN3D, POSN2D, CHAN, TRAIM
1051 * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must
1052 * be present or mode reverts to (2,4).
1056 * # is comment to end of line
1057 * = allowed between 1st and 2nd fields.
1059 * Expect to see one line with 'MODE' as first field, followed by an integer
1060 * in the range 0-4 (default = 4).
1062 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
1063 * All numbers are floating point.
1068 * Expect to see one line with 'HT' as first field,
1069 * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'
1070 * for feet or meters. HT is the height above the GPS ellipsoid.
1071 * If the receiver reports height in both GPS and MSL, then we will report
1072 * the difference GPS-MSL on the clockstats file.
1074 * There is an optional line, starting with DELAY, followed
1075 * by 1 or two fields. The first is a number (a time) the second is
1076 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1077 * DELAY is cable delay, typically a few tens of ns.
1079 * There is an optional line, starting with OFFSET, followed
1080 * by 1 or two fields. The first is a number (a time) the second is
1081 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1082 * OFFSET is the offset of the PPS pulse from 0. (only fully implemented
1083 * with the PPSAPI, we need to be able to tell the Kernel about this
1084 * offset if the Kernel PLL is in use, but can only do this presently
1085 * when using the PPSAPI interface. If not using the Kernel PLL,
1086 * then there is no problem.
1088 * There is an optional line, with either ASSERT or CLEAR on it, which
1089 * determine which transition of the PPS signal is used for timing by the
1090 * PPSAPI. If neither is present, then ASSERT is assumed.
1091 * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
1092 * For Flag2, ASSERT=0, and hence is default.
1094 * There is an optional line, with HARDPPS on it. Including this line causes
1095 * the PPS signal to control the kernel PLL.
1096 * HARDPPS can also be set with FLAG3 of the ntp.conf input.
1097 * For Flag3, 0 is disabled, and the default.
1099 * There are three options that have to do with using the shared memory option.
1100 * First, to enable the option there must be a SHMEM line with a file name.
1101 * The file name is the file associated with the shared memory.
1103 * In shared memory, there is one 'record' for each returned variable.
1104 * For the @@Ea data there are three 'records' containing position data.
1105 * There will always be data in the record corresponding to the '0D' @@Ea record,
1106 * and the user has a choice of filling the '3D' record by specifying POSN3D,
1107 * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D'
1108 * record is filled once every 15s.
1110 * Two additional variables that can be set are CHAN and TRAIM. These should be
1111 * set correctly by the code examining the @@Cj record, but we bring them out here
1112 * to allow the user to override either the # of channels, or the existence of TRAIM.
1113 * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
1114 * followed by YES or NO.
1116 * There is an optional line with MASK on it followed by one integer field in the
1117 * range 0 to 89. This sets the satellite mask angle and will determine the minimum
1118 * elevation angle for satellites to be tracked by the receiver. The default value
1119 * is 10 deg for the VP and 0 deg for all other receivers.
1121 * So acceptable input would be
1122 * # these are my coordinates (RWC)
1125 * HT 1589 # could equally well say HT 5215 FT
1130 char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp;
1131 char *dirs[] = { "/etc/ntp", "/etc", 0 };
1132 int i, sign, lat_flg, long_flg, ht_flg, mode, mask;
1135 fd = NULL; /* just to shutup gcc complaint */
1136 for (cpp=dirs; *cpp; cpp++) {
1138 sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */
1139 if ((fd=fopen(device, "r")))
1141 sprintf(device, "%s/ntp.oncore%d", cp, instance->unit); /* try "ntp.oncore0" */
1142 if ((fd=fopen(device, "r")))
1144 sprintf(device, "%s/ntp.oncore", cp); /* and finally "ntp.oncore" */
1145 if ((fd=fopen(device, "r")))
1149 if (!fd) { /* no inputfile, default to the works ... */
1150 instance->init_type = 4;
1155 lat_flg = long_flg = ht_flg = 0;
1156 while (fgets(line, 100, fd)) {
1158 /* Remove comments */
1159 if ((cp = strchr(line, '#')))
1162 /* Remove trailing space */
1163 for (i = strlen(line);
1164 i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
1168 /* Remove leading space */
1169 for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
1172 /* Stop if nothing left */
1176 /* Uppercase the command and find the arg */
1177 for (ca = cc; *ca; ca++) {
1178 if (isascii((int)*ca)) {
1179 if (islower((int)*ca)) {
1181 } else if (isspace((int)*ca) || (*ca == '='))
1186 /* Remove space (and possible =) leading the arg */
1187 for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
1190 if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
1192 instance->shmem_fname = (char *) malloc((unsigned) (i+1));
1193 strcpy(instance->shmem_fname, ca);
1197 /* Uppercase argument as well */
1198 for (cp = ca; *cp; cp++)
1199 if (isascii((int)*cp) && islower((int)*cp))
1202 if (!strncmp(cc, "LAT", (size_t) 3)) {
1204 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1210 instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1212 } else if (!strncmp(cc, "LON", (size_t) 3)) {
1214 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1220 instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1222 } else if (!strncmp(cc, "HT", (size_t) 2)) {
1225 sscanf(ca, "%lf %1s", &f1, units);
1226 if (units[0] == 'F')
1228 instance->ss_ht = 100 * f1; /* cm */
1230 } else if (!strncmp(cc, "DELAY", (size_t) 5)) {
1233 sscanf(ca, "%lf %1s", &f1, units);
1234 if (units[0] == 'N')
1236 else if (units[0] == 'U')
1238 else if (units[0] == 'M')
1241 f1 = 1000000000 * f1;
1242 if (f1 < 0 || f1 > 1.e9)
1244 if (f1 < 0 || f1 > 999999) {
1245 sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
1246 record_clock_stats(&(instance->peer->srcadr), Msg);
1248 instance->delay = f1; /* delay in ns */
1249 } else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
1252 sscanf(ca, "%lf %1s", &f1, units);
1253 if (units[0] == 'N')
1255 else if (units[0] == 'U')
1257 else if (units[0] == 'M')
1260 f1 = 1000000000 * f1;
1261 if (f1 < 0 || f1 > 1.e9)
1263 if (f1 < 0 || f1 > 999999999.) {
1264 sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
1265 record_clock_stats(&(instance->peer->srcadr), Msg);
1267 instance->offset = f1; /* offset in ns */
1268 } else if (!strncmp(cc, "MODE", (size_t) 4)) {
1269 sscanf(ca, "%d", &mode);
1270 if (mode < 0 || mode > 4)
1272 } else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
1273 instance->assert = 1;
1274 } else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
1275 instance->assert = 0;
1276 } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
1277 instance->hardpps = 1;
1278 } else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
1279 instance->shmem_Posn = 2;
1280 } else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
1281 instance->shmem_Posn = 3;
1282 } else if (!strncmp(cc, "CHAN", (size_t) 4)) {
1283 sscanf(ca, "%d", &i);
1284 if ((i == 6) || (i == 8) || (i == 12))
1285 instance->chan_in = i;
1286 } else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
1287 instance->traim_in = 1; /* so TRAIM alone is YES */
1288 if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */
1289 instance->traim_in = 0;
1290 } else if (!strncmp(cc, "MASK", (size_t) 4)) {
1291 sscanf(ca, "%d", &mask);
1292 if (mask > -1 && mask < 90)
1293 instance->Ag = mask; /* Satellite mask angle */
1299 * OK, have read all of data file, and extracted the good stuff.
1300 * If lat/long/ht specified they ALL must be specified for mode = (1,3).
1303 instance->posn_set = 1;
1304 if (!( lat_flg && long_flg && ht_flg )) {
1305 printf("ONCORE: incomplete data on %s\n", device);
1306 instance->posn_set = 0;
1307 if (mode == 1 || mode == 3) {
1308 sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
1309 record_clock_stats(&(instance->peer->srcadr), Msg);
1313 instance->init_type = mode;
1315 sprintf(Msg, "Input mode = %d", mode);
1316 record_clock_stats(&(instance->peer->srcadr), Msg);
1322 * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
1327 struct recvbuf *rbufp
1333 struct instance *instance;
1335 peer = (struct peer *)rbufp->recv_srcclock;
1336 instance = (struct instance *) peer->procptr->unitptr;
1337 p = (u_char *) &rbufp->recv_space;
1342 printf("ONCORE: >>>");
1343 for(i=0; i<rbufp->recv_length; i++)
1344 printf("%02x ", p[i]);
1346 printf("ONCORE: >>>");
1347 for(i=0; i<rbufp->recv_length; i++)
1348 printf("%03o ", p[i]);
1353 i = rbufp->recv_length;
1354 if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
1355 i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */
1356 memcpy(rcvbuf+rcvptr, p, i);
1358 oncore_consume(instance);
1364 * Deal with any complete messages
1369 struct instance *instance
1375 while (rcvptr >= 7) {
1376 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1377 /* We're not in sync, lets try to get there */
1378 for (i=1; i < rcvptr-1; i++)
1379 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1383 printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
1386 memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1391 /* Ok, we have a header now */
1392 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1394 if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1399 printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
1401 memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1406 l = oncore_messages[m].len;
1409 printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1411 /* Got the entire message ? */
1416 /* are we at the end of message? should be <Cksum><CR><LF> */
1418 if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1421 printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
1423 } else { /* check the CheckSum */
1424 if (oncore_checksum_ok(rcvbuf, l)) {
1425 if (instance->shmem != NULL) {
1426 instance->shmem[oncore_messages[m].shmem + 2]++;
1427 memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1428 rcvbuf, (size_t) l);
1430 oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1431 if (oncore_messages[m].handler)
1432 oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1436 printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit);
1437 printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
1439 printf("%03o ", rcvbuf[i]);
1446 memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1454 oncore_get_timestamp(
1455 struct instance *instance,
1456 long dt1, /* tick offset THIS time step */
1457 long dt2 /* tick offset NEXT time step */
1464 #ifdef HAVE_STRUCT_TIMESPEC
1465 struct timespec *tsp = 0;
1467 struct timeval *tsp = 0;
1471 pps_params_t current_params;
1472 struct timespec timeout;
1476 /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
1477 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
1478 * times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
1479 * This gives good time, which gets better when the SS is done.
1482 if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
1484 /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
1486 if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
1490 /* Don't do anything without an almanac to define the GPS->UTC delta */
1492 if (instance->rsm.bad_almanac)
1495 /* Once the Almanac is valid, the M12+T does not produce valid UTC
1497 * Wait for UTC offset decode valid, then wait one message more
1498 * so we are not off by 13 seconds after reset.
1501 if (instance->count5) {
1506 j = instance->ev_serial;
1508 timeout.tv_nsec = 0;
1509 if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1511 printf("ONCORE: time_pps_fetch failed\n");
1515 if (instance->assert) {
1516 tsp = &pps_i.assert_timestamp;
1520 i = (u_long) pps_i.assert_sequence;
1521 # ifdef HAVE_STRUCT_TIMESPEC
1522 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1523 instance->unit, i, j,
1524 (long)tsp->tv_sec, (long)tsp->tv_nsec);
1526 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1527 instance->unit, i, j,
1528 (long)tsp->tv_sec, (long)tsp->tv_usec);
1533 if (pps_i.assert_sequence == j) {
1534 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1537 instance->ev_serial = pps_i.assert_sequence;
1539 tsp = &pps_i.clear_timestamp;
1543 i = (u_long) pps_i.clear_sequence;
1544 # ifdef HAVE_STRUCT_TIMESPEC
1545 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1546 instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
1548 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1549 instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
1554 if (pps_i.clear_sequence == j) {
1555 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1558 instance->ev_serial = pps_i.clear_sequence;
1561 /* convert timespec -> ntp l_fp */
1565 ts.l_uf = dmy * 4294967296.0;
1566 ts.l_ui = tsp->tv_sec;
1569 alternate code for previous 4 lines is
1570 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1572 dmy = tsp->tv_sec; /* integer part */
1573 DTOLFP(dmy, &ts_tmp);
1574 L_ADD(&ts, &ts_tmp);
1576 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1578 ts.l_ui = tsp->tv_sec;
1581 /* now have timestamp in ts */
1582 /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
1583 /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
1584 /* we just try to add them in and dont test for that here */
1586 /* saw_tooth not really necessary if using TIMEVAL */
1587 /* since its only precise to us, but do it anyway. */
1589 /* offset in ns, and is positive (late), we subtract */
1590 /* to put the PPS time transition back where it belongs */
1592 /* must hand the offset for the NEXT sec off to the Kernel to do */
1593 /* the addition, so that the Kernel PLL sees the offset too */
1595 if (instance->assert)
1596 instance->pps_p.assert_offset.tv_nsec = -dt2;
1598 instance->pps_p.clear_offset.tv_nsec = -dt2;
1600 /* The following code is necessary, and not just a time_pps_setparams,
1601 * using the saved instance->pps_p, since some other process on the
1602 * machine may have diddled with the mode bits (say adding something
1603 * that it needs). We take what is there and ADD what we need.
1604 * [[ The results from the time_pps_getcap is unlikely to change so
1605 * we could probably just save it, but I choose to do the call ]]
1606 * Unfortunately, there is only ONE set of mode bits in the kernel per
1607 * interface, and not one set for each open handle.
1609 * There is still a race condition here where we might mess up someone
1610 * elses mode, but if he is being careful too, he should survive.
1613 if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) {
1614 msyslog(LOG_ERR, "time_pps_getcap failed: %m");
1618 if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) {
1619 msyslog(LOG_ERR, "time_pps_getparams failed: %m");
1623 /* or current and mine */
1624 current_params.mode |= instance->pps_p.mode;
1625 /* but only set whats legal */
1626 current_params.mode &= current_mode;
1628 current_params.assert_offset.tv_sec = 0;
1629 current_params.assert_offset.tv_nsec = -dt2;
1630 current_params.clear_offset.tv_sec = 0;
1631 current_params.clear_offset.tv_nsec = -dt2;
1633 if (time_pps_setparams(instance->pps_h, ¤t_params))
1634 record_clock_stats(&(instance->peer->srcadr), "ONCORE: Error doing time_pps_setparams");
1636 /* have time from UNIX origin, convert to NTP origin. */
1638 ts.l_ui += JAN_1970;
1639 instance->pp->lastrec = ts;
1641 /* print out information about this timestamp (long line) */
1644 ts_tmp.l_ui = 0; /* zero integer part */
1645 LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */
1646 j = 1.0e9*dmy; /* then to integer ns */
1649 if (instance->chan == 6)
1650 Rsm = instance->BEHa[64];
1651 else if (instance->chan == 8)
1652 Rsm = instance->BEHa[72];
1653 else if (instance->chan == 12)
1654 Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
1656 if (instance->chan == 6 || instance->chan == 8) {
1657 char f1[5], f2[5], f3[5], f4[5];
1658 if (instance->traim) {
1659 sprintf(f1, "%d", instance->BEHn[21]);
1660 sprintf(f2, "%d", instance->BEHn[22]);
1661 sprintf(f3, "%2d", instance->BEHn[23]*256+instance->BEHn[24]);
1662 sprintf(f4, "%3d", (s_char) instance->BEHn[25]);
1669 sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 121 */
1670 "%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",
1672 instance->pp->year, instance->pp->day,
1673 instance->pp->hour, instance->pp->minute, instance->pp->second,
1674 (long) tsp->tv_sec % 60,
1675 Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
1677 instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2,
1678 /* nsat visible, nsat tracked, traim,traim,traim */
1680 /* sigma neg-sawtooth */
1681 /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
1682 instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
1683 ); /* will be 0 for 6 chan */
1684 } else if (instance->chan == 12) {
1685 char f1[5], f2[5], f3[5], f4[5];
1686 if (instance->traim) {
1687 sprintf(f1, "%d", instance->BEHn[6]);
1688 sprintf(f2, "%d", instance->BEHn[7]);
1689 sprintf(f3, "%d", instance->BEHn[12]*256+instance->BEHn[13]);
1690 sprintf(f4, "%3d", (s_char) instance->BEHn[14]);
1697 sprintf(instance->pp->a_lastcode,
1698 "%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",
1700 instance->pp->year, instance->pp->day,
1701 instance->pp->hour, instance->pp->minute, instance->pp->second,
1702 (long) tsp->tv_sec % 60,
1703 Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
1705 instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2,
1706 /* nsat visible, nsat tracked traim,traim,traim */
1708 /* sigma neg-sawtooth */
1709 /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
1710 instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
1711 instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
1719 n = strlen(instance->pp->a_lastcode);
1720 printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
1724 /* and some things I dont understand (magic ntp things) */
1726 if (!refclock_process(instance->pp)) {
1727 refclock_report(instance->peer, CEVNT_BADTIME);
1731 record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
1732 instance->pollcnt = 2;
1734 if (instance->polled) {
1735 instance->polled = 0;
1736 /* instance->pp->dispersion = instance->pp->skew = 0; */
1737 instance->pp->lastref = instance->pp->lastrec;
1738 refclock_receive(instance->peer);
1743 /*************** oncore_msg_XX routines start here *******************/
1747 * print Oncore response message.
1752 struct instance *instance,
1759 const char *fmt = oncore_messages[idx].fmt;
1761 #ifdef HAVE_GETCLOCK
1768 # ifdef HAVE_GETCLOCK
1769 (void) getclock(TIMEOFDAY, &ts);
1770 tv.tv_sec = ts.tv_sec;
1771 tv.tv_usec = ts.tv_nsec / 1000;
1773 GETTIMEOFDAY(&tv, 0);
1775 printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
1778 printf(">>@@%c%c ", buf[2], buf[3]);
1779 for(i=2; i < len && i < 2400 ; i++)
1780 printf("%02x", buf[i]);
1785 for (p = fmt; *p; p++) {
1789 printf("\n%c%c", buf[2], buf[3]);
1791 for (p = fmt; *p; p++) {
1792 printf("%02x", buf[i++]);
1802 /* Latitude, Longitude, Height */
1806 struct instance *instance,
1819 struct instance *instance,
1823 { char Msg[160], *cp;
1826 if (instance->o_state == ONCORE_RUN)
1829 instance->Ag = buf[4];
1830 sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag);
1831 record_clock_stats(&(instance->peer->srcadr), Msg);
1837 * get Position hold position
1842 struct instance *instance,
1847 instance->ss_lat = buf_w32(&buf[4]);
1848 instance->ss_long = buf_w32(&buf[8]);
1849 instance->ss_ht = buf_w32(&buf[12]);
1851 /* Print out Position */
1852 oncore_print_posn(instance);
1858 * Try to use Oncore UT+ Auto Survey Feature
1859 * If its not there (VP), set flag to do it ourselves.
1864 struct instance *instance,
1871 instance->saw_At = 1;
1872 if (instance->site_survey == ONCORE_SS_TESTING) {
1874 record_clock_stats(&(instance->peer->srcadr),
1875 "Initiating hardware 3D site survey");
1877 cp = "SSstate = ONCORE_SS_HW";
1878 record_clock_stats(&(instance->peer->srcadr), cp);
1879 instance->site_survey = ONCORE_SS_HW;
1888 * Nb. @@Ay is not supported for early UT (no plus) model
1893 struct instance *instance,
1900 if (instance->saw_Ay)
1903 instance->saw_Ay = 1;
1905 instance->offset = buf_w32(&buf[4]);
1907 sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
1908 record_clock_stats(&(instance->peer->srcadr), Msg);
1919 struct instance *instance,
1926 if (instance->saw_Az)
1929 instance->saw_Az = 1;
1931 instance->delay = buf_w32(&buf[4]);
1933 sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
1934 record_clock_stats(&(instance->peer->srcadr), Msg);
1939 /* Ba, Ea and Ha come here, these contain Position */
1943 struct instance *instance,
1952 /* OK, we are close to the RUN state now.
1953 * But we have a few more items to initialize first.
1955 * At the beginning of this routine there are several 'timers'.
1956 * We enter this routine 1/sec, and since the upper levels of NTP have usurped
1957 * the use of timers, we use the 1/sec entry to do things that
1958 * we would normally do with timers...
1961 if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */
1962 if (buf[2] == 'B') { /* 6chan */
1963 if (instance->chan_ck < 6) instance->chan_ck = 6;
1964 } else if (buf[2] == 'E') { /* 8chan */
1965 if (instance->chan_ck < 8) instance->chan_ck = 8;
1966 } else if (buf[2] == 'H') { /* 12chan */
1967 if (instance->chan_ck < 12) instance->chan_ck = 12;
1970 if (instance->count3++ < 5)
1973 instance->count3 = 0;
1975 if (instance->chan_in != -1) /* set in Input */
1976 instance->chan = instance->chan_in;
1977 else /* set from test */
1978 instance->chan = instance->chan_ck;
1980 sprintf(Msg, "Input says chan = %d", instance->chan_in);
1981 record_clock_stats(&(instance->peer->srcadr), Msg);
1982 sprintf(Msg, "Model # says chan = %d", instance->chan_id);
1983 record_clock_stats(&(instance->peer->srcadr), Msg);
1984 sprintf(Msg, "Testing says chan = %d", instance->chan_ck);
1985 record_clock_stats(&(instance->peer->srcadr), Msg);
1986 sprintf(Msg, "Using chan = %d", instance->chan);
1987 record_clock_stats(&(instance->peer->srcadr), Msg);
1989 instance->o_state = ONCORE_HAVE_CHAN;
1990 cp = "state = ONCORE_HAVE_CHAN";
1991 record_clock_stats(&(instance->peer->srcadr), cp);
1993 instance->timeout = 4;
1994 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
1998 if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
2001 /* PAUSE 5sec - make sure results are stable, before using position */
2003 if (instance->count) {
2004 if (instance->count++ < 5)
2006 instance->count = 0;
2009 memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */
2011 /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
2013 oncore_check_almanac(instance);
2014 oncore_check_antenna(instance);
2016 /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
2017 /* When we have an almanac, we will start the Bn/En/@@Hn messages */
2019 if (instance->o_state == ONCORE_ALMANAC)
2020 if (oncore_wait_almanac(instance))
2023 /* do some things once when we get this far in BaEaHa */
2025 if (instance->once) {
2027 instance->count2 = 1;
2029 /* Have we seen an @@At (position hold) command response */
2030 /* if not, message out */
2032 if (instance->chan != 12 && !instance->saw_At) {
2033 cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+";
2034 record_clock_stats(&(instance->peer->srcadr), cp);
2035 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
2038 /* have an Almanac, can start the SiteSurvey
2039 * (actually only need to get past the almanac_load where we diddle with At
2040 * command,- we can't change it after we start the HW_SS below
2043 mode = instance->init_type;
2045 case 0: /* NO initialization, don't change anything */
2046 case 1: /* Use given Position */
2048 instance->site_survey = ONCORE_SS_DONE;
2049 cp = "SSstate = ONCORE_SS_DONE";
2050 record_clock_stats(&(instance->peer->srcadr), cp);
2054 case 4: /* Site Survey */
2055 cp = "SSstate = ONCORE_SS_TESTING";
2056 record_clock_stats(&(instance->peer->srcadr), cp);
2057 instance->site_survey = ONCORE_SS_TESTING;
2058 instance->count1 = 1;
2059 if (instance->chan == 12)
2060 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */
2062 oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */
2066 /* Read back PPS Offset for Output */
2067 /* Nb. This will fail silently for early UT (no plus) and M12 models */
2069 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
2071 /* Read back Cable Delay for Output */
2073 oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
2075 /* Read back Satellite Mask Angle for Output */
2077 oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx, sizeof(oncore_cmd_Agx));
2081 /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
2082 * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
2083 * We must do the Gd3, and then wait a cycle or two for things to settle,
2084 * then check Ha[130]&0x10 to see if a SS is in progress.
2085 * We will set SW if HW has not been set after an appropriate delay.
2088 if (instance->site_survey == ONCORE_SS_TESTING) {
2089 if (instance->chan == 12) {
2090 if (instance->count1) {
2091 if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
2092 instance->count1 = 0;
2093 if (instance->BEHa[130]&0x10) {
2094 record_clock_stats(&(instance->peer->srcadr),
2095 "Initiating hardware 3D site survey");
2097 record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_HW");
2098 instance->site_survey = ONCORE_SS_HW;
2100 record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
2101 instance->site_survey = ONCORE_SS_SW;
2106 if (instance->count1) {
2107 if (instance->count1++ > 5) {
2108 instance->count1 = 0;
2110 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
2111 * wait after the @@At2/@@Gd3 command we have not changed the state to
2112 * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then
2113 * the variable would have been changed by now.
2114 * There are three possibilities:
2116 * (a) We did not get a response to the @@At0 or @@At2 commands,
2117 * and it must be a GT/GT+/SL with no position hold mode.
2118 * We will have to do it ourselves.
2119 * (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
2120 * must be a VP or older UT which doesn't have Site Survey mode.
2121 * We will have to do it ourselves.
2123 * (c) We saw the @@Gd command, and saw H[13]*0x10
2124 * We will have to do it ourselves (done above)
2127 sprintf(Msg, "Initiating software 3D site survey (%d samples)",
2129 record_clock_stats(&(instance->peer->srcadr), Msg);
2131 record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
2132 instance->site_survey = ONCORE_SS_SW;
2134 instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
2135 if (instance->chan == 12)
2136 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
2138 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
2139 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
2146 /* check the mode we are in 0/2/3D */
2148 if (instance->chan == 6) {
2149 if (instance->BEHa[64]&0x8)
2150 instance->mode = MODE_0D;
2151 else if (instance->BEHa[64]&0x10)
2152 instance->mode = MODE_2D;
2153 else if (instance->BEHa[64]&0x20)
2154 instance->mode = MODE_3D;
2155 } else if (instance->chan == 8) {
2156 if (instance->BEHa[72]&0x8)
2157 instance->mode = MODE_0D;
2158 else if (instance->BEHa[72]&0x10)
2159 instance->mode = MODE_2D;
2160 else if (instance->BEHa[72]&0x20)
2161 instance->mode = MODE_3D;
2162 } else if (instance->chan == 12) {
2165 bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
2167 instance->mode = MODE_0D;
2168 else if (bits == 0x6)
2169 instance->mode = MODE_2D;
2170 else if (bits == 0x7)
2171 instance->mode = MODE_3D;
2174 /* copy the record to the (extra) location in SHMEM */
2176 if (instance->shmem) {
2178 u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */
2180 switch(instance->chan) {
2181 case 6: smp = &instance->shmem[instance->shmem_Ba]; break;
2182 case 8: smp = &instance->shmem[instance->shmem_Ea]; break;
2183 case 12: smp = &instance->shmem[instance->shmem_Ha]; break;
2184 default: smp = (u_char *) NULL; break;
2187 switch (instance->mode) {
2188 case MODE_0D: i = 1; break; /* 0D, Position Hold */
2189 case MODE_2D: i = 2; break; /* 2D, Altitude Hold */
2190 case MODE_3D: i = 3; break; /* 3D fix */
2191 default: i = 0; break;
2194 if (i && smp != NULL) {
2197 memcpy(&smp[i+3], buf, (size_t) (len+3));
2202 * check if traim timer active
2203 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
2206 if (instance->traim_delay) {
2207 if (instance->traim_delay++ > 5) {
2208 instance->traim = 0;
2209 instance->traim_delay = 0;
2210 cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2211 record_clock_stats(&(instance->peer->srcadr), cp);
2213 oncore_set_traim(instance);
2219 /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
2221 if (!instance->have_dH && !instance->traim_delay)
2222 oncore_compute_dH(instance);
2225 * must be ONCORE_RUN if we are here.
2226 * Have # chan and TRAIM by now.
2229 instance->pp->year = buf[6]*256+buf[7];
2230 instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
2231 instance->pp->hour = buf[8];
2232 instance->pp->minute = buf[9];
2233 instance->pp->second = buf[10];
2236 * Are we doing a Hardware or Software Site Survey?
2239 if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
2240 oncore_ss(instance);
2242 /* see if we ever saw a response from the @@Ayx above */
2244 if (instance->count2) {
2245 if (instance->count2++ > 5) { /* this delay to check on @@Ay command */
2246 instance->count2 = 0;
2248 /* Have we seen an Ay (1PPS time offset) command response */
2249 /* if not, and non-zero offset, zero the offset, and send message */
2251 if (!instance->saw_Ay && instance->offset) {
2252 cp = "No @@Ay command, PPS OFFSET ignored";
2253 record_clock_stats(&(instance->peer->srcadr), cp);
2254 instance->offset = 0;
2260 * Check the leap second status once per day.
2263 oncore_check_leap_sec(instance);
2266 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2269 if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
2270 oncore_shmem_get_3D(instance);
2272 if (!instance->traim) /* NO traim, no BnEnHn, go get tick */
2273 oncore_get_timestamp(instance, instance->offset, instance->offset);
2278 /* Almanac Status */
2282 struct instance *instance,
2289 sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
2290 ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) );
2291 record_clock_stats(&(instance->peer->srcadr), Msg);
2296 /* get leap-second warning message */
2299 * @@Bj does NOT behave as documented in current Oncore firmware.
2300 * It turns on the LEAP indicator when the data is set, and does not,
2301 * as documented, wait until the beginning of the month when the
2302 * leap second will occur.
2303 * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
2304 * @@Bj is only called in June/December.
2309 struct instance *instance,
2318 instance->pp->leap = LEAP_ADDSECOND;
2319 cp = "Set pp.leap to LEAP_ADDSECOND";
2322 instance->pp->leap = LEAP_DELSECOND;
2323 cp = "Set pp.leap to LEAP_DELSECOND";
2327 instance->pp->leap = LEAP_NOWARNING;
2328 cp = "Set pp.leap to LEAP_NOWARNING";
2331 record_clock_stats(&(instance->peer->srcadr), cp);
2338 struct instance *instance,
2346 if (instance->o_state != ONCORE_RUN)
2349 if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */
2350 instance->traim_ck = 1;
2351 instance->traim_delay = 0;
2352 cp = "ONCORE: Detected TRAIM, TRAIM = ON";
2353 record_clock_stats(&(instance->peer->srcadr), cp);
2355 oncore_set_traim(instance);
2358 memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */
2360 if (!instance->traim) /* BnEnHn will be turned off in any case */
2363 /* If Time RAIM doesn't like it, don't trust it */
2365 if (buf[2] == 'H') {
2366 if (instance->BEHn[6]) /* bad TRAIM */
2369 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
2370 instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
2371 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
2373 if (instance->BEHn[21]) /* bad TRAIM */
2376 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
2377 instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */
2378 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
2381 oncore_get_timestamp(instance, dt1, dt2);
2386 /* Here for @@Ca, @@Fa and @@Ia messages */
2388 /* These are Self test Commands for 6, 8, and 12 chan receivers.
2389 * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
2390 * It was found that under some circumstances the following
2391 * command would fail if issued immediately after the return from the
2392 * @@Fa, but a 2sec delay seemed to fix things. Since simply calling
2393 * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
2394 * itimer, we set a flag, and test it at the next POLL. If it hasn't
2395 * been cleared, we reissue the @@Cj that is issued below.
2396 * Note that we do a @@Cj at the beginning, and again here.
2397 * The first is to get the info, the 2nd is just used as a safe command
2398 * after the @@Fa for all Oncores (and it was in this posn in the
2404 struct instance *instance,
2412 if (instance->o_state == ONCORE_TEST_SENT) {
2413 enum antenna_state antenna;
2415 instance->timeout = 0;
2420 printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
2422 printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
2426 antenna = (buf[4] & 0xc0) >> 6;
2429 i = buf[4] || buf[5];
2430 if (buf[2] == 'I') i = i || buf[6];
2432 if (buf[2] == 'I') {
2433 msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x",
2434 instance->unit, buf[4], buf[5], buf[6]);
2436 msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x",
2437 instance->unit, buf[4], buf[5]);
2439 cp = "ONCORE: self test failed, shutting down driver";
2440 record_clock_stats(&instance->peer->srcadr, cp);
2442 refclock_report(instance->peer, CEVNT_FAULT);
2443 oncore_shutdown(instance->unit, instance->peer);
2447 /* report the current antenna state */
2449 oncore_antenna_report(instance, antenna);
2451 instance->o_state = ONCORE_INIT;
2452 cp = "state = ONCORE_INIT";
2453 record_clock_stats(&(instance->peer->srcadr), cp);
2455 instance->timeout = 4;
2456 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2463 * Demultiplex the almanac into shmem
2468 struct instance *instance,
2475 if (instance->shmem == NULL)
2478 if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
2480 else if (buf[4] == 4 && buf[5] <= 5)
2482 else if (buf[4] == 4 && buf[5] <= 10)
2484 else if (buf[4] == 4 && buf[5] == 25)
2489 cp = "Cb: Response is NO ALMANAC";
2490 record_clock_stats(&(instance->peer->srcadr), cp);
2495 instance->shmem[instance->shmem_Cb + i + 2]++;
2496 memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
2501 sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]);
2502 record_clock_stats(&(instance->peer->srcadr), Msg);
2510 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
2511 * not so for VP (eeprom) or any unit with a battery
2516 struct instance *instance,
2523 if (instance->o_state == ONCORE_RESET_SENT) {
2524 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
2525 /* Reset set VP to IDLE */
2526 instance->o_state = ONCORE_TEST_SENT;
2527 cp = "state = ONCORE_TEST_SENT";
2528 record_clock_stats(&(instance->peer->srcadr), cp);
2530 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2537 * This is the Grand Central Station for the Preliminary Initialization.
2538 * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
2540 * We do an @@Cj whenever we need a safe command for all Oncores.
2541 * The @@Cj gets us back here where we can switch to the next phase of setup.
2543 * o Once at the very beginning (in start) to get the Model number.
2544 * This info is printed, but no longer used.
2545 * o Again after we have determined the number of Channels in the receiver.
2546 * o And once later after we have done a reset and test, (which may hang),
2547 * as we are about to initialize the Oncore and start it running.
2548 * o We have one routine below for each case.
2553 struct instance *instance,
2561 memcpy(instance->Cj, buf, len);
2563 instance->timeout = 0;
2564 if (instance->o_state == ONCORE_CHECK_ID) {
2565 oncore_msg_Cj_id(instance, buf, len);
2566 oncore_chan_test(instance);
2567 } else if (instance->o_state == ONCORE_HAVE_CHAN) {
2568 mode = instance->init_type;
2569 if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */
2570 instance->o_state = ONCORE_RESET_SENT;
2571 cp = "state = ONCORE_RESET_SENT";
2572 record_clock_stats(&(instance->peer->srcadr), cp);
2573 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
2575 instance->o_state = ONCORE_TEST_SENT;
2576 cp = "state = ONCORE_TEST_SENT";
2577 record_clock_stats(&(instance->peer->srcadr), cp);
2581 if (instance->o_state == ONCORE_TEST_SENT) {
2582 if (instance->chan == 6)
2583 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
2584 else if (instance->chan == 8)
2585 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
2586 else if (instance->chan == 12)
2587 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
2588 } else if (instance->o_state == ONCORE_INIT)
2589 oncore_msg_Cj_init(instance, buf, len);
2594 /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
2595 * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
2596 * and from Motorola. Until recently Rick was the only source of
2597 * this information as Motorola didn't give the information out.
2599 * Determine the Type from the Model #, this determines #chan and if TRAIM is
2602 * The Information from this routine is NO LONGER USED.
2603 * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
2608 struct instance *instance,
2613 char *cp, *cp1, *cp2, Model[21], Msg[160];
2615 /* Write Receiver ID message to clockstats file */
2617 instance->Cj[294] = '\0';
2618 for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
2619 cp1 = strchr(cp, '\r');
2621 cp1 = (char *)&instance->Cj[294];
2623 record_clock_stats(&(instance->peer->srcadr), cp);
2628 /* next, the Firmware Version and Revision numbers */
2630 instance->version = atoi((char *) &instance->Cj[83]);
2631 instance->revision = atoi((char *) &instance->Cj[111]);
2633 /* from model number decide which Oncore this is,
2634 and then the number of channels */
2636 for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */
2640 for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
2645 if (!strncmp(Model, "PVT6", (size_t) 4)) {
2647 instance->model = ONCORE_PVT6;
2648 } else if (Model[0] == 'A') {
2650 instance->model = ONCORE_BASIC;
2651 } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
2653 instance->model = ONCORE_VP;
2654 } else if (Model[0] == 'P') {
2656 instance->model = ONCORE_M12;
2657 } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
2658 if (Model[5] == 'N') {
2660 instance->model = ONCORE_GT;
2661 } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
2663 instance->model = ONCORE_GTPLUS;
2664 } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
2666 instance->model = ONCORE_UT;
2667 } else if (Model[1] == '5' && Model[5] == 'G') {
2669 instance->model = ONCORE_UTPLUS;
2670 } else if (Model[1] == '6' && Model[5] == 'G') {
2672 instance->model = ONCORE_SL;
2675 instance->model = ONCORE_UNKNOWN;
2679 instance->model = ONCORE_UNKNOWN;
2682 /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
2684 sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
2685 record_clock_stats(&(instance->peer->srcadr), Msg);
2687 instance->chan_id = 8; /* default */
2688 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2689 instance->chan_id = 6;
2690 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2691 instance->chan_id = 8;
2692 else if (instance->model == ONCORE_M12)
2693 instance->chan_id = 12;
2695 instance->traim_id = 0; /* default */
2696 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2697 instance->traim_id = 0;
2698 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2699 instance->traim_id = 1;
2700 else if (instance->model == ONCORE_M12)
2701 instance->traim_id = -1;
2703 sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id,
2704 ((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF")));
2705 record_clock_stats(&(instance->peer->srcadr), Msg);
2710 /* OK, know type of Oncore, have possibly reset it, and have tested it.
2711 * We know the number of channels.
2712 * We will determine whether we have TRAIM before we actually start.
2718 struct instance *instance,
2728 /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
2729 * start again if we go from 0D -> 3D, then loses them again when we
2730 * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM.
2731 * For NOW we will turn this aspect of filling SHMEM off for the M12
2734 if (instance->chan == 12) {
2735 instance->shmem_bad_Ea = 1;
2736 sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision);
2737 record_clock_stats(&(instance->peer->srcadr), Msg);
2740 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
2741 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
2742 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
2743 oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
2744 oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
2745 oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
2746 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
2748 mode = instance->init_type;
2750 /* If there is Position input in the Config file
2751 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
2752 * or mode = (2,4) set it as INITIAL position, and do Site Survey.
2755 if (instance->posn_set) {
2756 record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data");
2757 oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */
2758 } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
2759 if (instance->chan != 12)
2760 oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
2763 /* cable delay in ns */
2764 memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
2765 w32_buf(&Cmd[-2+4], instance->delay);
2766 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */
2768 /* PPS offset in ns */
2769 if (instance->offset) {
2770 memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */
2771 w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */
2772 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay));
2775 /* Satellite mask angle */
2777 if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */
2778 memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
2779 Cmd[-2+4] = instance->Ag;
2780 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ag));
2784 /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
2785 * now we're really running
2786 * these were ALL started in the chan test,
2787 * However, if we had mode=3,4 then commands got turned off, so we turn
2788 * them on again here just in case
2791 if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
2792 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2793 oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2794 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2795 oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2796 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
2797 } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */
2798 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2799 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2800 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2801 oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2802 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
2803 } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */
2804 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2805 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2806 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2807 oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2808 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
2811 instance->count = 1;
2812 instance->o_state = ONCORE_ALMANAC;
2813 cp = "state = ONCORE_ALMANAC";
2814 record_clock_stats(&(instance->peer->srcadr), cp);
2819 /* 12chan position */
2823 struct instance *instance,
2830 double Lat, Lon, Ht;
2833 lat = buf_w32(&buf[4]);
2834 lon = buf_w32(&buf[8]);
2835 ht = buf_w32(&buf[12]); /* GPS ellipsoid */
2846 sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, Lon, Ht);
2847 record_clock_stats(&(instance->peer->srcadr), Msg);
2849 instance->ss_lat = lat;
2850 instance->ss_long = lon;
2851 instance->ss_ht = ht;
2853 oncore_print_posn(instance);
2858 /* 12 chan time/date */
2862 struct instance *instance,
2867 char Msg[160], *gmts;
2868 int mo, d, y, h, m, s, gmth, gmtm;
2872 y = 256*buf[6]+buf[7];
2878 gmts = ((buf[11] == 0) ? "+" : "-");
2882 sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
2883 d, Month[mo-1], y, h, m, s, gmts, gmth, gmtm);
2884 record_clock_stats(&(instance->peer->srcadr), Msg);
2889 /* Leap Second for M12, gives all info from satellite message */
2890 /* also in UT v3.0 */
2894 struct instance *instance,
2902 instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
2904 /* print the message to verify whats there */
2906 dt = buf[5] - buf[4];
2909 sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
2911 buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
2912 (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
2913 buf[15], buf[16], buf[17]);
2914 record_clock_stats(&(instance->peer->srcadr), Msg);
2917 sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
2919 dt, buf[9], Month[buf[8]-1], 256*buf[6]+buf[7],
2920 buf[15], buf[16], buf[17]);
2921 record_clock_stats(&(instance->peer->srcadr), Msg);
2924 /* Only raise warning within a month of the leap second */
2926 instance->pp->leap = LEAP_NOWARNING;
2927 cp = "Set pp.leap to LEAP_NOWARNING";
2929 if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
2930 buf[8] == instance->BEHa[4]) { /* month */
2933 instance->pp->leap = LEAP_DELSECOND;
2934 cp = "Set pp.leap to LEAP_DELSECOND";
2936 instance->pp->leap = LEAP_ADDSECOND;
2937 cp = "Set pp.leap to LEAP_ADDSECOND";
2941 record_clock_stats(&(instance->peer->srcadr), cp);
2946 /* Power on failure */
2950 struct instance *instance,
2957 cp = "Oncore: System Failure at Power On";
2958 if (instance && instance->peer) {
2959 record_clock_stats(&(instance->peer->srcadr), cp);
2960 oncore_shutdown(instance->unit, instance->peer);
2964 /************** Small Subroutines ***************/
2968 oncore_antenna_report(
2969 struct instance *instance,
2970 enum antenna_state new_state)
2974 if (instance->ant_state == new_state)
2977 switch (new_state) {
2978 case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break;
2979 case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break;
2980 case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
2981 case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break;
2982 default: cp = "GPS antenna: ?"; break;
2985 instance->ant_state = new_state;
2986 record_clock_stats(&instance->peer->srcadr, cp);
2993 struct instance *instance
2998 /* subroutine oncore_Cj_id has determined the number of channels from the
2999 * model number of the attached oncore. This is not always correct since
3000 * the oncore could have non-standard firmware. Here we check (independently) by
3001 * trying a 6, 8, and 12 chan command, and see which responds.
3002 * Caution: more than one CAN respond.
3004 * This #chan is used by the code rather than that calculated from the model number.
3007 instance->o_state = ONCORE_CHECK_CHAN;
3008 cp = "state = ONCORE_CHECK_CHAN";
3009 record_clock_stats(&(instance->peer->srcadr), cp);
3011 instance->count3 = 1;
3012 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
3013 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
3014 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
3019 /* check for a GOOD Almanac, have we got one yet? */
3022 oncore_check_almanac(
3023 struct instance *instance
3026 if (instance->chan == 6) {
3027 instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
3028 instance->rsm.bad_fix = instance->BEHa[64]&0x52;
3029 } else if (instance->chan == 8) {
3030 instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
3031 instance->rsm.bad_fix = instance->BEHa[72]&0x52;
3032 } else if (instance->chan == 12) {
3033 int bits1, bits2, bits3;
3035 bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
3036 bits2 = instance->BEHa[130];
3037 instance->rsm.bad_almanac = (bits2 & 0x80);
3038 instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2);
3039 /* too few sat Bad Geom */
3041 bits3 = instance->BEHa[141]; /* UTC parameters */
3042 if (!instance->count5_set && (bits3 & 0xC0)) {
3043 instance->count5 = 2;
3044 instance->count5_set = 1;
3050 sprintf(Msg, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x\n",
3052 instance->BEHa[129], instance->BEHa[130], bits1, bits2, bits3, instance->mode == MODE_0D,
3053 instance->mode == MODE_2D, instance->mode == MODE_3D,
3054 instance->rsm.bad_almanac, instance->rsm.bad_fix);
3055 record_clock_stats(&(instance->peer->srcadr), Msg);
3063 /* check the antenna for changes (did it get unplugged?) */
3066 oncore_check_antenna(
3067 struct instance *instance
3070 enum antenna_state antenna; /* antenna state */
3072 antenna = instance->ant_state;
3073 if (instance->chan == 12)
3074 antenna = (instance->BEHa[130] & 0x6 ) >> 1;
3076 antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */
3078 oncore_antenna_report (instance, antenna);
3084 * Check the leap second status once per day.
3086 * Note that the ONCORE firmware for the Bj command is wrong at
3088 * It starts advertising a LEAP SECOND as soon as the GPS satellite
3089 * data message (page 18, subframe 4) is updated to a date in the
3090 * future, and does not wait for the month that it will occur.
3091 * The event will usually be advertised several months in advance.
3092 * Since there is a one bit flag, there is no way to tell if it is
3093 * this month, or when...
3095 * As such, we have the workaround below, of only checking for leap
3096 * seconds with the Bj command in June/December.
3098 * The Gj command gives more information, and we can tell in which
3099 * month to apply the correction.
3101 * Note that with the VP we COULD read the raw data message, and
3102 * interpret it ourselves, but since this is specific to this receiver
3103 * only, and the above workaround is adequate, we don't bother.
3107 oncore_check_leap_sec(
3108 struct instance *instance
3111 if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */
3112 instance->Bj_day = instance->BEHa[5];
3114 if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */
3115 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3116 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3120 if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */
3121 instance->count4 = 1;
3123 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
3127 /* Gj works for some 6/8 chan UT and the M12 */
3128 /* if no response from Gj in 5 sec, we try Bj */
3129 /* which isnt implemented in all the GT/UT either */
3131 if (instance->count4) { /* delay, waiting for Gj response */
3132 if (instance->saw_Gj == 1)
3133 instance->count4 = 0;
3134 else if (instance->count4++ > 5) { /* delay, waiting for Gj response */
3135 instance->saw_Gj = -1; /* didnt see it, will use Bj */
3136 instance->count4 = 0;
3137 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3138 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3145 /* check the message checksum,
3146 * buf points to START of message ( @@ )
3147 * len is length WITH CR/LF.
3159 for (i = 2; i < len-3; i++)
3162 return(j == buf[len-3]);
3169 struct instance *instance
3175 /* Here calculate dH = GPS - MSL for output message */
3176 /* also set Altitude Hold mode if GT */
3178 instance->have_dH = 1;
3179 if (instance->chan == 12) {
3180 GPS = buf_w32(&instance->BEHa[39]);
3181 MSL = buf_w32(&instance->BEHa[43]);
3183 GPS = buf_w32(&instance->BEHa[23]);
3184 MSL = buf_w32(&instance->BEHa[27]);
3186 instance->dH = GPS - MSL;
3187 instance->dH /= 100.;
3189 /* if MSL is not set, the calculation is meaningless */
3191 if (MSL) { /* not set ! */
3192 sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
3193 record_clock_stats(&(instance->peer->srcadr), Msg);
3200 * try loading Almanac from shmem (where it was copied from shmem_old
3204 oncore_load_almanac(
3205 struct instance *instance
3208 u_char *cp, Cmd[20];
3213 if (!instance->shmem)
3217 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3218 if (!strncmp((char *) cp, "@@Cb", 4) &&
3219 oncore_checksum_ok(cp, 33) &&
3220 (*(cp+4) == 4 || *(cp+4) == 5)) {
3221 write(instance->ttyfd, cp, n);
3223 oncore_print_Cb(instance, cp);
3228 /************DEBUG************/
3229 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3232 sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
3233 record_clock_stats(&(instance->peer->srcadr), Msg);
3235 if (!strncmp(cp, "@@Cb", 4)) {
3236 oncore_print_Cb(instance, cp);
3237 if (oncore_checksum_ok(cp, 33)) {
3238 if (*(cp+4) == 4 || *(cp+4) == 5) {
3239 record_clock_stats(&(instance->peer->srcadr), "GOOD SF");
3240 write(instance->ttyfd, cp, n);
3242 record_clock_stats(&(instance->peer->srcadr), "BAD SF");
3244 record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM");
3247 /************DEBUG************/
3250 /* Must load position and time or the Almanac doesn't do us any good */
3252 if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */
3253 record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM");
3254 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3255 if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) ||
3256 (instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) ||
3257 (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
3260 instance->posn_set = 1;
3261 ii = buf_w32(cp + 15);
3262 jj = buf_w32(cp + 19);
3263 kk = buf_w32(cp + 23);
3267 sprintf(Msg, "SHMEM posn = %ld (%d, %d, %d)", (long) (cp-instance->shmem), ii, jj, kk);
3268 record_clock_stats(&(instance->peer->srcadr), Msg);
3271 if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
3272 instance->ss_lat = ii;
3273 instance->ss_long = jj;
3274 instance->ss_ht = kk;
3279 oncore_set_posn(instance);
3281 /* and set time to time from Computer clock */
3283 gettimeofday(&tv, 0);
3284 tm = gmtime((const time_t *) &tv.tv_sec);
3288 sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday,
3289 tm->tm_hour, tm->tm_min, tm->tm_sec);
3290 record_clock_stats(&(instance->peer->srcadr), Msg);
3293 if (instance->chan == 12) {
3294 memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
3295 Cmd[-2+4] = tm->tm_mon + 1;
3296 Cmd[-2+5] = tm->tm_mday;
3297 Cmd[-2+6] = (1900+tm->tm_year)/256;
3298 Cmd[-2+7] = (1900+tm->tm_year)%256;
3299 Cmd[-2+8] = tm->tm_hour;
3300 Cmd[-2+9] = tm->tm_min;
3301 Cmd[-2+10] = tm->tm_sec;
3305 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Gb));
3307 /* First set GMT offset to zero */
3309 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
3311 memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
3312 Cmd[-2+4] = tm->tm_mon + 1;
3313 Cmd[-2+5] = tm->tm_mday;
3314 Cmd[-2+6] = (1900+tm->tm_year)/256;
3315 Cmd[-2+7] = (1900+tm->tm_year)%256;
3316 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ac));
3318 memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
3319 Cmd[-2+4] = tm->tm_hour;
3320 Cmd[-2+5] = tm->tm_min;
3321 Cmd[-2+6] = tm->tm_sec;
3322 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Aa));
3325 record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac");
3330 /* Almanac data input */
3334 struct instance *instance,
3342 printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3));
3343 printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5));
3344 for(ii=0; ii<33; ii++)
3345 printf(" %d", *(cp+ii));
3348 sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5));
3349 record_clock_stats(&(instance->peer->srcadr), Msg);
3366 for (j=0; j<jj; j++) {
3367 printf("%4d: ", nn);
3369 for (i=0; i<16; i++)
3370 printf(" %o", *cp++);
3379 struct instance *instance
3382 char Msg[120], ew, ns;
3383 double xd, xm, xs, yd, ym, ys, hm, hft;
3384 int idx, idy, is, imx, imy;
3387 record_clock_stats(&(instance->peer->srcadr), "Posn:");
3389 lon = instance->ss_long;
3396 lat = instance->ss_lat;
3402 hm = instance->ss_ht/100.;
3405 xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */
3407 sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
3408 record_clock_stats(&(instance->peer->srcadr), Msg);
3417 "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
3418 record_clock_stats(&(instance->peer->srcadr), Msg);
3427 "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
3428 record_clock_stats(&(instance->peer->srcadr), Msg);
3434 * write message to Oncore.
3448 printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
3450 write(fd, "@@", (size_t) 2);
3451 write(fd, ptr, len);
3454 write(fd, &cs, (size_t) 1);
3455 write(fd, "\r\n", (size_t) 2);
3462 struct instance *instance
3468 /* Turn OFF position hold, it needs to be off to set position (for some units),
3469 will get set ON in @@Ea later */
3471 if (instance->chan == 12)
3472 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
3474 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
3475 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
3478 mode = instance->init_type;
3480 if (mode != 0) { /* first set posn hold position */
3481 memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */
3482 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3483 w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3484 w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
3486 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */
3488 memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
3489 w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3491 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */
3493 /* next set current position */
3495 if (instance->chan == 12) {
3496 memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
3497 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3498 w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3499 w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
3501 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */
3503 memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
3504 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3505 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */
3507 memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
3508 w32_buf(&Cmd[-2+4], (int) instance->ss_long);
3509 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */
3511 memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
3512 w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3514 oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */
3517 /* Finally, turn on position hold */
3519 if (instance->chan == 12)
3520 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
3522 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
3530 struct instance *instance
3535 if (instance->traim_in != -1) /* set in Input */
3536 instance->traim = instance->traim_in;
3538 instance->traim = instance->traim_ck;
3540 sprintf(Msg, "Input says TRAIM = %d", instance->traim_in);
3541 record_clock_stats(&(instance->peer->srcadr), Msg);
3542 sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id);
3543 record_clock_stats(&(instance->peer->srcadr), Msg);
3544 sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck);
3545 record_clock_stats(&(instance->peer->srcadr), Msg);
3546 sprintf(Msg, "Using TRAIM = %d", instance->traim);
3547 record_clock_stats(&(instance->peer->srcadr), Msg);
3549 if (instance->traim_ck == 1 && instance->traim == 0) {
3550 /* if it should be off, and I turned it on during testing,
3551 then turn it off again */
3552 if (instance->chan == 6)
3553 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
3554 else if (instance->chan == 8)
3555 oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
3556 else /* chan == 12 */
3557 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
3558 oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
3565 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
3569 oncore_shmem_get_3D(
3570 struct instance *instance
3573 if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */
3574 instance->shmem_reset = 1;
3575 if (instance->chan == 12) {
3576 if (instance->shmem_Posn == 2)
3577 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */
3579 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */
3581 if (instance->saw_At) { /* out of 0D -> 3D mode */
3582 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
3583 if (instance->shmem_Posn == 2) /* 3D -> 2D mode */
3584 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3586 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3588 } else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
3589 instance->shmem_reset = 0;
3590 if (instance->chan == 12)
3591 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */
3593 if (instance->saw_At) {
3594 if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */
3595 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3596 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */
3598 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3606 * Here we do the Software SiteSurvey.
3607 * We have to average our own position for the Position Hold Mode
3608 * We use Heights from the GPS ellipsoid.
3609 * We check for the END of either HW or SW SiteSurvey.
3614 struct instance *instance
3618 double lat, lon, ht;
3621 if (instance->site_survey == ONCORE_SS_HW) {
3623 * Check to see if Hardware SiteSurvey has Finished.
3626 if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) ||
3627 (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
3628 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3630 if (instance->chan == 12)
3631 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
3633 oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
3635 cp = "SSstate = ONCORE_SS_DONE";
3636 record_clock_stats(&(instance->peer->srcadr), cp);
3637 instance->site_survey = ONCORE_SS_DONE;
3641 * Must be a Software Site Survey.
3644 if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */
3647 if (instance->mode != MODE_3D) /* Use only 3D Fixes */
3650 instance->ss_lat += buf_w32(&instance->BEHa[15]);
3651 instance->ss_long += buf_w32(&instance->BEHa[19]);
3652 instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */
3653 instance->ss_count++;
3655 if (instance->ss_count != POS_HOLD_AVERAGE)
3658 instance->ss_lat /= POS_HOLD_AVERAGE;
3659 instance->ss_long /= POS_HOLD_AVERAGE;
3660 instance->ss_ht /= POS_HOLD_AVERAGE;
3662 sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
3663 instance->ss_lat, instance->ss_long, instance->ss_ht);
3664 record_clock_stats(&(instance->peer->srcadr), Msg);
3665 lat = instance->ss_lat/3600000.;
3666 lon = instance->ss_long/3600000.;
3667 ht = instance->ss_ht/100;
3668 sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
3670 record_clock_stats(&(instance->peer->srcadr), Msg);
3672 oncore_set_posn(instance);
3674 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3676 cp = "SSstate = ONCORE_SS_DONE";
3677 record_clock_stats(&(instance->peer->srcadr), cp);
3678 instance->site_survey = ONCORE_SS_DONE;
3685 oncore_wait_almanac(
3686 struct instance *instance
3689 if (instance->rsm.bad_almanac) {
3692 printf("ONCORE[%d]: waiting for almanac\n", instance->unit);
3696 * If we get here (first time) then we don't have an almanac in memory.
3697 * Check if we have a SHMEM, and if so try to load whatever is there.
3700 if (!instance->almanac_from_shmem) {
3701 instance->almanac_from_shmem = 1;
3702 oncore_load_almanac(instance);
3705 } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
3706 commands, and can finally check for TRAIM. Again, we set a delay
3707 (5sec) and wait for things to settle down */
3709 if (instance->chan == 6)
3710 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
3711 else if (instance->chan == 8)
3712 oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
3713 else if (instance->chan == 12) {
3714 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
3715 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
3716 oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
3718 instance->traim_delay = 1;
3720 record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC");
3722 instance->o_state = ONCORE_RUN;
3723 record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN");
3731 int refclock_oncore_bs;
3732 #endif /* REFCLOCK */