1 /* $NetBSD: refclock_oncore.c,v 1.10 2007/01/06 19:45:23 kardel Exp $ */
4 * ----------------------------------------------------------------------------
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
9 * ----------------------------------------------------------------------------
13 * Driver for some of the various the Motorola Oncore GPS receivers.
14 * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
15 * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
17 * The receivers without position hold (GT, GT+) will be less accurate.
22 * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC.
23 * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P
24 * SOFTWARE VER # 2 SOFTWARE VER # 8
25 * SOFTWARE REV # 2 SOFTWARE REV # 8
26 * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996
27 * MODEL # R1121N1114 MODEL # B4121P1155
28 * HWDR P/N # 1 HDWR P/N # _
29 * SERIAL # R0010A SERIAL # SSG0226478
30 * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02
34 * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC.
35 * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A
36 * SOFTWARE VER # 5 SOFTWARE VER # 1
37 * SOFTWARE REV # 0 SOFTWARE REV # 3
38 * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000
39 * MODEL # A11121P116 MODEL # P143T12NR1
40 * HDWR P/N # _ HWDR P/N # 1
41 * SERIAL # SSG0049809 SERIAL # P003UD
42 * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27
45 * (M12+T) (M12+T later version)
46 * COPYRIGHT 1991-2002 MOTOROLA INC. COPYRIGHT 1991-2003 MOTOROLA INC.
47 * SFTW P/N # 61-G10268A SFTW P/N # 61-G10268A
48 * SOFTWARE VER # 2 SOFTWARE VER # 2
49 * SOFTWARE REV # 0 SOFTWARE REV # 1
50 * SOFTWARE DATE AUG 14 2002 SOFTWARE DATE APR 16 2003
51 * MODEL # P283T12T11 MODEL # P273T12T12
52 * HWDR P/N # 2 HWDR P/N # 2
53 * SERIAL # P04DC2 SERIAL # P05Z7Z
54 * MANUFACTUR DATE 2J17 MANUFACTUR DATE 3G15
56 * --------------------------------------------------------------------------
57 * Reg Clemens (Feb 2006)
58 * Fix some gcc4 compiler complaints
59 * Fix possible segfault in oncore_init_shmem
60 * change all (possible) fprintf(stderr, to record_clock_stats
61 * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
62 * immediately after new Almanac Read.
63 * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
64 * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
65 * the new one. Compiles depending on timepps.h seen.
66 * --------------------------------------------------------------------------
67 * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
68 * (the oncore driver was setting the wrong ntpd variable)
69 * --------------------------------------------------------------------------
70 * Reg.Clemens (Mar 2004)
71 * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
72 * SCO, you now need to use one of the timepps.h files in the root dir.
73 * this driver will 'grab' it for you if you dont have one in /usr/include
74 * --------------------------------------------------------------------------
75 * This code uses the two devices
76 * /dev/oncore.serial.n
78 * which may be linked to the same device.
79 * and can read initialization data from the file
80 * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
81 * n or N are the unit number, viz 127.127.30.N.
82 * --------------------------------------------------------------------------
83 * Reg.Clemens <reg@dwf.com> Sep98.
84 * Original code written for FreeBSD.
85 * With these mods it works on FreeBSD, SunOS, Solaris and Linux
86 * (SunOS 4.1.3 + ppsclock)
88 * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
90 * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
91 * state machine state) are printed to CLOCKSTATS if that file is enabled
94 * --------------------------------------------------------------------------
96 * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
97 * doing an average of 10000 valid 2D and 3D fixes is what the automatic
98 * site survey mode does. Looking at the output from the receiver
99 * it seems like it is only using 3D fixes.
100 * When we do it ourselves, take 10000 3D fixes.
103 #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */
106 * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
107 * "STATUS" line in the oncore config file, which contains the most recent
108 * copy of all types of messages we recognize. This file can be mmap(2)'ed
109 * by monitoring and statistics programs.
111 * See separate HTML documentation for this option.
118 #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
122 #include "ntp_unixtime.h"
123 #include "ntp_refclock.h"
124 #include "ntp_stdlib.h"
128 #include <sys/stat.h>
129 #ifdef ONCORE_SHMEM_STATUS
130 # ifdef HAVE_SYS_MMAN_H
131 # include <sys/mman.h>
133 # define MAP_FAILED ((u_char *) -1)
134 # endif /* MAP_FAILED */
135 # endif /* HAVE_SYS_MMAN_H */
136 #endif /* ONCORE_SHMEM_STATUS */
139 # include "ppsapi_timepps.h"
142 #ifdef HAVE_SYS_SIO_H
143 # include <sys/sio.h>
158 enum site_survey_state
{
167 ONCORE_ANTENNA_UNKNOWN
= -1,
168 ONCORE_ANTENNA_OK
= 0,
169 ONCORE_ANTENNA_OC
= 1,
170 ONCORE_ANTENNA_UC
= 2,
171 ONCORE_ANTENNA_NV
= 3
174 /* Model Name, derived from the @@Cj message.
175 * Used to initialize some variables.
191 /* the bits that describe these properties are in the same place
192 * on the VP/UT, but have moved on the M12. As such we extract
193 * them, and use them from this struct.
205 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
206 * see what mode it is in. The bits on the M12 are multiplexed with
207 * other messages, so we have to 'keep' the last known mode here.
218 int unit
; /* 127.127.30.unit */
219 struct refclockproc
*pp
;
222 int ttyfd
; /* TTY file descriptor */
223 int ppsfd
; /* PPS file descriptor */
224 int shmemfd
; /* Status shm descriptor */
227 enum receive_state o_state
; /* Receive state */
228 enum posn_mode mode
; /* 0D, 2D, 3D */
229 enum site_survey_state site_survey
; /* Site Survey state */
230 enum antenna_state ant_state
; /* antenna state */
234 u_long delay
; /* ns */
235 long offset
; /* ns */
246 u_char almanac_from_shmem
;
255 enum oncore_model model
;
259 u_char chan
; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
260 s_char traim
; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
261 /* the following 7 are all timing counters */
262 u_char traim_delay
; /* seconds counter, waiting for reply */
263 u_char count
; /* cycles thru Ea before starting */
264 u_char count1
; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */
265 u_char count2
; /* cycles thru Ea after count, to check for @@Ea */
266 u_char count3
; /* cycles thru Ea checking for # channels */
267 u_char count4
; /* cycles thru leap after Gj to issue Bj */
268 u_char count5
; /* cycles thru get_timestamp waiting for valid UTC correction */
269 u_char count5_set
; /* only set count5 once */
271 u_char timeout
; /* count to retry Cj after Fa self-test */
273 struct RSM rsm
; /* bits extracted from Receiver Status Msg in @@Ea */
279 u_char BEHa
[160]; /* Ba, Ea or Ha */
280 u_char BEHn
[80]; /* Bn , En , or Hn */
282 u_char Ag
; /* Satellite mask angle */
290 s_char chan_in
; /* chan number from INPUT, will always use it */
291 u_char chan_id
; /* chan number determined from part number */
292 u_char chan_ck
; /* chan number determined by sending commands to hardware */
293 s_char traim_in
; /* TRAIM from INPUT, will always use ON/OFF specified */
294 s_char traim_id
; /* TRAIM determined from part number */
295 u_char traim_ck
; /* TRAIM determined by sending commands to hardware */
296 u_char once
; /* one pass code at top of BaEaHa */
301 #define rcvbuf instance->Rcvbuf
302 #define rcvptr instance->Rcvptr
304 static int oncore_start
P((int, struct peer
*));
305 static void oncore_poll
P((int, struct peer
*));
306 static void oncore_shutdown
P((int, struct peer
*));
307 static void oncore_consume
P((struct instance
*));
308 static void oncore_read_config
P((struct instance
*));
309 static void oncore_receive
P((struct recvbuf
*));
310 static int oncore_ppsapi
P((struct instance
*));
311 static void oncore_get_timestamp
P((struct instance
*, long, long));
312 static void oncore_init_shmem
P((struct instance
*));
314 static void oncore_antenna_report
P((struct instance
*, enum antenna_state
));
315 static void oncore_chan_test
P((struct instance
*));
316 static void oncore_check_almanac
P((struct instance
*));
317 static void oncore_check_antenna
P((struct instance
*));
318 static void oncore_check_leap_sec
P((struct instance
*));
319 static int oncore_checksum_ok
P((u_char
*, int));
320 static void oncore_compute_dH
P((struct instance
*));
321 static void oncore_load_almanac
P((struct instance
*));
322 static void oncore_print_Cb
P((struct instance
*, u_char
*));
323 /* static void oncore_print_array P((u_char *, int)); */
324 static void oncore_print_posn
P((struct instance
*));
325 static void oncore_sendmsg
P((int, u_char
*, size_t));
326 static void oncore_set_posn
P((struct instance
*));
327 static void oncore_set_traim
P((struct instance
*));
328 static void oncore_shmem_get_3D
P((struct instance
*));
329 static void oncore_ss
P((struct instance
*));
330 static int oncore_wait_almanac
P((struct instance
*));
332 static void oncore_msg_any
P((struct instance
*, u_char
*, size_t, int));
333 static void oncore_msg_Adef
P((struct instance
*, u_char
*, size_t));
334 static void oncore_msg_Ag
P((struct instance
*, u_char
*, size_t));
335 static void oncore_msg_As
P((struct instance
*, u_char
*, size_t));
336 static void oncore_msg_At
P((struct instance
*, u_char
*, size_t));
337 static void oncore_msg_Ay
P((struct instance
*, u_char
*, size_t));
338 static void oncore_msg_Az
P((struct instance
*, u_char
*, size_t));
339 static void oncore_msg_BaEaHa
P((struct instance
*, u_char
*, size_t));
340 static void oncore_msg_Bd
P((struct instance
*, u_char
*, size_t));
341 static void oncore_msg_Bj
P((struct instance
*, u_char
*, size_t));
342 static void oncore_msg_BnEnHn
P((struct instance
*, u_char
*, size_t));
343 static void oncore_msg_CaFaIa
P((struct instance
*, u_char
*, size_t));
344 static void oncore_msg_Cb
P((struct instance
*, u_char
*, size_t));
345 static void oncore_msg_Cf
P((struct instance
*, u_char
*, size_t));
346 static void oncore_msg_Cj
P((struct instance
*, u_char
*, size_t));
347 static void oncore_msg_Cj_id
P((struct instance
*, u_char
*, size_t));
348 static void oncore_msg_Cj_init
P((struct instance
*, u_char
*, size_t));
349 static void oncore_msg_Ga
P((struct instance
*, u_char
*, size_t));
350 static void oncore_msg_Gb
P((struct instance
*, u_char
*, size_t));
351 static void oncore_msg_Gj
P((struct instance
*, u_char
*, size_t));
352 static void oncore_msg_Sz
P((struct instance
*, u_char
*, size_t));
354 struct refclock refclock_oncore
= {
355 oncore_start
, /* start up driver */
356 oncore_shutdown
, /* shut down driver */
357 oncore_poll
, /* transmit poll message */
358 noentry
, /* not used */
359 noentry
, /* not used */
360 noentry
, /* not used */
361 NOFLAGS
/* not used */
365 * Understanding the next bit here is not easy unless you have a manual
366 * for the the various Oncore Models.
369 static struct msg_desc
{
372 void (*handler
) P((struct instance
*, u_char
*, size_t));
375 } oncore_messages
[] = {
376 /* Ea and En first since they're most common */
377 { "Ea", 76, oncore_msg_BaEaHa
, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
378 { "Ba", 68, oncore_msg_BaEaHa
, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
379 { "Ha", 154, oncore_msg_BaEaHa
, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
380 { "Bn", 59, oncore_msg_BnEnHn
, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
381 { "En", 69, oncore_msg_BnEnHn
, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
382 { "Hn", 78, oncore_msg_BnEnHn
, "" },
385 { "Ad", 11, oncore_msg_Adef
, "" },
386 { "Ae", 11, oncore_msg_Adef
, "" },
387 { "Af", 15, oncore_msg_Adef
, "" },
388 { "Ag", 8, oncore_msg_Ag
, "" }, /* Satellite mask angle */
389 { "As", 20, oncore_msg_As
, "" },
390 { "At", 8, oncore_msg_At
, "" },
394 { "Ay", 11, oncore_msg_Ay
, "" },
395 { "Az", 11, oncore_msg_Az
, "" },
398 { "Bd", 23, oncore_msg_Bd
, "" },
399 { "Bj", 8, oncore_msg_Bj
, "" },
400 { "Ca", 9, oncore_msg_CaFaIa
, "" },
401 { "Cb", 33, oncore_msg_Cb
, "" },
402 { "Cf", 7, oncore_msg_Cf
, "" },
405 { "Cj", 294, oncore_msg_Cj
, "" },
407 { "Fa", 9, oncore_msg_CaFaIa
, "" },
408 { "Ga", 20, oncore_msg_Ga
, "" },
409 { "Gb", 17, oncore_msg_Gb
, "" },
413 { "Gj", 21, oncore_msg_Gj
, "" },
414 { "Ia", 10, oncore_msg_CaFaIa
, "" },
415 { "Sz", 8, oncore_msg_Sz
, "" },
420 static u_char oncore_cmd_Aa
[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */
421 static u_char oncore_cmd_Ab
[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */
422 static u_char oncore_cmd_AB
[] = { 'A', 'B', 4 }; /* VP Application Type: Static */
423 static u_char oncore_cmd_Ac
[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */
424 static u_char oncore_cmd_Ad
[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */
425 static u_char oncore_cmd_Ae
[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */
426 static u_char oncore_cmd_Af
[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */
427 static u_char oncore_cmd_Ag
[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */
428 static u_char oncore_cmd_Agx
[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */
429 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 */
430 static u_char oncore_cmd_Asx
[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */
431 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */
432 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */
433 static u_char oncore_cmd_At0
[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */
434 static u_char oncore_cmd_At1
[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */
435 static u_char oncore_cmd_At2
[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */
436 static u_char oncore_cmd_Atx
[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */
437 static u_char oncore_cmd_Au
[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */
438 static u_char oncore_cmd_Av0
[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */
439 static u_char oncore_cmd_Av1
[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */
440 static u_char oncore_cmd_Aw
[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */
441 static u_char oncore_cmd_Ay
[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */
442 static u_char oncore_cmd_Ayx
[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */
443 static u_char oncore_cmd_Az
[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */
444 static u_char oncore_cmd_Azx
[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */
445 static u_char oncore_cmd_Ba0
[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */
446 static u_char oncore_cmd_Ba
[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */
447 static u_char oncore_cmd_Bb
[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */
448 static u_char oncore_cmd_Bd
[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */
449 static u_char oncore_cmd_Be
[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */
450 static u_char oncore_cmd_Bj
[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */
451 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 */
452 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 */
453 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 */
454 static u_char oncore_cmd_Ca
[] = { 'C', 'a' }; /* 6 Self Test */
455 static u_char oncore_cmd_Cf
[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */
456 static u_char oncore_cmd_Cg
[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */
457 static u_char oncore_cmd_Cj
[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */
458 static u_char oncore_cmd_Ea0
[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */
459 static u_char oncore_cmd_Ea
[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */
460 static u_char oncore_cmd_Ek
[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */
461 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 */
462 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 */
463 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 */
464 static u_char oncore_cmd_Fa
[] = { 'F', 'a' }; /* 8 Self Test */
465 static u_char oncore_cmd_Ga
[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */
466 static u_char oncore_cmd_Gax
[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */
467 0xff, 0xff, 0xff, 0xff, /* */
468 0xff, 0xff, 0xff, 0xff, 0xff }; /* */
469 static u_char oncore_cmd_Gb
[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */
470 static u_char oncore_cmd_Gc
[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */
471 static u_char oncore_cmd_Gd0
[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */
472 static u_char oncore_cmd_Gd1
[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */
473 static u_char oncore_cmd_Gd2
[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */
474 static u_char oncore_cmd_Gd3
[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */
475 static u_char oncore_cmd_Ge0
[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */
476 static u_char oncore_cmd_Ge
[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */
477 static u_char oncore_cmd_Gj
[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */
478 static u_char oncore_cmd_Ha0
[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */
479 static u_char oncore_cmd_Ha
[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */
480 static u_char oncore_cmd_Hn0
[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */
481 static u_char oncore_cmd_Hn
[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */
482 static u_char oncore_cmd_Ia
[] = { 'I', 'a' }; /* 12 Self Test */
484 /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
485 * the GT had Au,Av, but not As,At
486 * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
488 * dont see Bd in UT/GT thru 1999
489 * Gj in UT as of 3.0, 1999 , Bj as of 1.3
492 static char *Month
[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
493 "Aug", "Sep", "Oct", "Nov", "Dec" };
495 #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */
496 #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */
498 #define SPEED B9600 /* Oncore Binary speed (9600 bps) */
501 * Assemble and disassemble 32bit signed quantities from a buffer.
505 /* to buffer, int w, u_char *buf */
506 #define w32_buf(buf,w) { u_int i_tmp; \
507 i_tmp = (w<0) ? (~(-w)+1) : (w); \
508 (buf)[0] = (i_tmp >> 24) & 0xff; \
509 (buf)[1] = (i_tmp >> 16) & 0xff; \
510 (buf)[2] = (i_tmp >> 8) & 0xff; \
511 (buf)[3] = (i_tmp ) & 0xff; \
514 #define w32(buf) (((buf)[0]&0xff) << 24 | \
515 ((buf)[1]&0xff) << 16 | \
516 ((buf)[2]&0xff) << 8 | \
519 /* from buffer, char *buf, result to an int */
520 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
524 * oncore_start - initialize data for processing
533 #define STRING_LEN 32
534 register struct instance
*instance
;
535 struct refclockproc
*pp
;
537 char device1
[STRING_LEN
], device2
[STRING_LEN
], Msg
[160];
539 struct stat stat1
, stat2
;
541 /* create instance structure for this unit */
543 if (!(instance
= (struct instance
*) malloc(sizeof *instance
))) {
547 memset((char *) instance
, 0, sizeof *instance
);
549 /* initialize miscellaneous variables */
552 pp
->unitptr
= (caddr_t
) instance
;
554 instance
->unit
= unit
;
555 instance
->peer
= peer
;
556 instance
->assert = 1;
559 instance
->Bj_day
= -1;
560 instance
->traim
= -1;
561 instance
->traim_in
= -1;
562 instance
->chan_in
= -1;
563 instance
->model
= ONCORE_UNKNOWN
;
564 instance
->mode
= MODE_UNKNOWN
;
565 instance
->site_survey
= ONCORE_SS_UNKNOWN
;
566 instance
->Ag
= 0xff; /* Satellite mask angle, unset by user */
567 instance
->ant_state
= ONCORE_ANTENNA_UNKNOWN
;
569 peer
->precision
= -26;
572 pp
->clockdesc
= "Motorola Oncore GPS Receiver";
573 memcpy((char *)&pp
->refid
, "GPS\0", (size_t) 4);
575 cp
= "ONCORE DRIVER -- CONFIGURING";
576 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
578 instance
->o_state
= ONCORE_NO_IDEA
;
579 cp
= "state = ONCORE_NO_IDEA";
580 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
583 * This is a bit complicated, a we dont want to open the same file twice
584 * (its a problem on some OS), and device2 may not exist for the new PPS
587 (void)sprintf(device1
, DEVICE1
, unit
);
588 (void)sprintf(device2
, DEVICE2
, unit
);
591 /* opening different devices for fd1 and fd2 presents no problems */
592 /* opening the SAME device twice, seems to be OS dependent.
593 (a) on Linux (no streams) no problem
594 (b) on SunOS (and possibly Solaris, untested), (streams)
595 never see the line discipline.
596 Since things ALWAYS work if we only open the device once, we check
597 to see if the two devices are in fact the same, then proceed to
601 if (stat(device1
, &stat1
)) {
602 sprintf(Msg
, "Can't stat fd1 (%s)\n", device1
);
603 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
607 if (stat(device2
, &stat2
)) {
608 sprintf(Msg
, "Can't stat fd2 (%s)\n", device2
);
609 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
613 if (!(fd1
= refclock_open(device1
, SPEED
, LDISC_RAW
))) {
614 sprintf(Msg
, "Can't open fd1 (%s)\n", device1
);
615 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
619 if ((stat1
.st_dev
== stat2
.st_dev
) && (stat1
.st_ino
== stat2
.st_ino
)) /* same device here */
621 else { /* different devices here */
622 if ((fd2
=open(device2
, O_RDWR
)) < 0) {
623 sprintf(Msg
, "Can't open fd2 (%s)\n", device2
);
624 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
630 /* open ppsapi soure */
632 if (time_pps_create(num
, &instance
->pps_h
) < 0) {
633 record_clock_stats(&(instance
->peer
->srcadr
), "PPSAPI not found in kernel");
637 /* continue initialization */
639 instance
->ttyfd
= fd1
;
640 instance
->ppsfd
= fd2
;
642 /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
644 oncore_read_config(instance
);
646 if (!oncore_ppsapi(instance
))
649 pp
->io
.clock_recv
= oncore_receive
;
650 pp
->io
.srcclock
= (caddr_t
)peer
;
653 if (!io_addclock(&pp
->io
)) {
654 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: io_addclock");
660 #ifdef ONCORE_SHMEM_STATUS
662 * Before starting ONCORE, lets setup SHMEM
663 * This will include merging an old SHMEM into the new one if
664 * an old one is found.
667 oncore_init_shmem(instance
);
671 * This will return the Model of the Oncore receiver.
672 * and start the Initialization loop in oncore_msg_Cj.
675 instance
->o_state
= ONCORE_CHECK_ID
;
676 cp
= "state = ONCORE_CHECK_ID";
677 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
679 instance
->timeout
= 4;
680 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cg
, sizeof(oncore_cmd_Cg
)); /* Set Posn Fix mode (not Idle (VP)) */
681 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cj
, sizeof(oncore_cmd_Cj
));
683 instance
->pollcnt
= 2;
689 * oncore_shutdown - shut down the clock
698 register struct instance
*instance
;
699 struct refclockproc
*pp
;
702 instance
= (struct instance
*) pp
->unitptr
;
704 io_closeclock(&pp
->io
);
706 time_pps_destroy (instance
->pps_h
);
708 close(instance
->ttyfd
);
710 if ((instance
->ppsfd
!= -1) && (instance
->ppsfd
!= instance
->ttyfd
))
711 close(instance
->ppsfd
);
713 if (instance
->shmemfd
)
714 close(instance
->shmemfd
);
722 * oncore_poll - called by the transmit procedure
731 struct instance
*instance
;
733 instance
= (struct instance
*) peer
->procptr
->unitptr
;
734 if (instance
->timeout
) {
738 if (instance
->timeout
== 0) {
739 cp
= "Oncore: No response from @@Cj, shutting down driver";
740 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
741 oncore_shutdown(unit
, peer
);
743 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cj
, sizeof(oncore_cmd_Cj
));
744 cp
= "Oncore: Resend @@Cj";
745 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
750 if (!instance
->pollcnt
)
751 refclock_report(peer
, CEVNT_TIMEOUT
);
754 peer
->procptr
->polls
++;
755 instance
->polled
= 1;
766 struct instance
*instance
769 int cap
, mode
, mode1
;
772 if (time_pps_getcap(instance
->pps_h
, &cap
) < 0) {
773 msyslog(LOG_ERR
, "time_pps_getcap failed: %m");
777 if (time_pps_getparams(instance
->pps_h
, &instance
->pps_p
) < 0) {
778 msyslog(LOG_ERR
, "time_pps_getparams failed: %m");
782 /* nb. only turn things on, if someone else has turned something
783 * on before we get here, leave it alone!
786 if (instance
->assert) {
788 mode
= PPS_CAPTUREASSERT
;
789 mode1
= PPS_OFFSETASSERT
;
792 mode
= PPS_CAPTURECLEAR
;
793 mode1
= PPS_OFFSETCLEAR
;
795 sprintf(Msg
, "Initializing timeing to %s.", cp
);
796 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
799 sprintf(Msg
, "Can't set timeing to %s, exiting...", cp
);
800 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
804 if (!(mode1
& cap
)) {
805 sprintf(Msg
, "Can't set PPS_%sCLEAR, this will increase jitter.", cp
);
806 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
810 /* only set what is legal */
812 instance
->pps_p
.mode
= (mode
| mode1
| PPS_TSFMT_TSPEC
) & cap
;
814 if (time_pps_setparams(instance
->pps_h
, &instance
->pps_p
) < 0) {
815 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: time_pps_setparams fails");
819 /* If HARDPPS is on, we tell kernel */
821 if (instance
->hardpps
) {
824 record_clock_stats(&(instance
->peer
->srcadr
), "HARDPPS Set.");
826 if (instance
->assert)
827 i
= PPS_CAPTUREASSERT
;
829 i
= PPS_CAPTURECLEAR
;
831 /* we know that 'i' is legal from above */
833 if (time_pps_kcbind(instance
->pps_h
, PPS_KC_HARDPPS
, i
,
834 PPS_TSFMT_TSPEC
) < 0) {
835 msyslog(LOG_ERR
, "time_pps_kcbind failed: %m");
836 record_clock_stats(&(instance
->peer
->srcadr
), "HARDPPS failed, abort...");
846 #ifdef ONCORE_SHMEM_STATUS
849 struct instance
*instance
852 int i
, l
, n
, fd
, shmem_old_size
, n1
;
854 u_char
*cp
, *cp1
, *buf
, *shmem_old
;
860 * The first thing we do is see if there is an instance->shmem_fname file (still)
861 * out there from a previous run. If so, we copy it in and use it to initialize
862 * shmem (so we won't lose our almanac if we need it).
867 if ((fd
= open(instance
->shmem_fname
, O_RDONLY
)) < 0)
868 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: Can't open SHMEM file");
871 shmem_old_size
= sbuf
.st_size
;
872 if (shmem_old_size
!= 0) {
873 shmem_old
= (u_char
*) malloc((unsigned) sbuf
.st_size
);
874 if (shmem_old
== NULL
)
875 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: Can't malloc buffer for shmem_old");
877 read(fd
, shmem_old
, shmem_old_size
);
882 /* OK, we now create the NEW SHMEM. */
884 if ((instance
->shmemfd
= open(instance
->shmem_fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644)) < 0) {
885 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: Can't open shmem");
892 /* see how big it needs to be */
895 for (mp
=oncore_messages
; mp
->flag
[0]; mp
++) {
897 /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
898 if (!strcmp(mp
->flag
, "Cb")) {
899 instance
->shmem_Cb
= n
;
900 n
+= (mp
->len
+ 3) * 34;
902 if (!strcmp(mp
->flag
, "Ba")) {
903 instance
->shmem_Ba
= n
;
904 n
+= (mp
->len
+ 3) * 3;
906 if (!strcmp(mp
->flag
, "Ea")) {
907 instance
->shmem_Ea
= n
;
908 n
+= (mp
->len
+ 3) * 3;
910 if (!strcmp(mp
->flag
, "Ha")) {
911 instance
->shmem_Ha
= n
;
912 n
+= (mp
->len
+ 3) * 3;
916 shmem_length
= n
+ 2;
918 buf
= malloc(shmem_length
);
920 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: Can't malloc buffer for shmem");
921 close(instance
->shmemfd
);
928 memset(buf
, 0, shmem_length
);
930 /* next build the new SHMEM buffer in memory */
932 for (mp
=oncore_messages
; mp
->flag
[0]; mp
++) {
934 buf
[l
+ 0] = mp
->len
>> 8;
935 buf
[l
+ 1] = mp
->len
& 0xff;
939 buf
[l
+ 5] = mp
->flag
[0];
940 buf
[l
+ 6] = mp
->flag
[1];
941 if (!strcmp(mp
->flag
, "Cb") || !strcmp(mp
->flag
, "Ba") || !strcmp(mp
->flag
, "Ea") || !strcmp(mp
->flag
, "Ha")) {
942 if (!strcmp(mp
->flag
, "Cb"))
946 for (i
=1; i
<n
; i
++) {
947 buf
[l
+ i
* (mp
->len
+3) + 0] = mp
->len
>> 8;
948 buf
[l
+ i
* (mp
->len
+3) + 1] = mp
->len
& 0xff;
949 buf
[l
+ i
* (mp
->len
+3) + 2] = 0;
950 buf
[l
+ i
* (mp
->len
+3) + 3] = '@';
951 buf
[l
+ i
* (mp
->len
+3) + 4] = '@';
952 buf
[l
+ i
* (mp
->len
+3) + 5] = mp
->flag
[0];
953 buf
[l
+ i
* (mp
->len
+3) + 6] = mp
->flag
[1];
958 /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
959 * copying the data in shmem_old to buf.
960 * When we are done we write it out and free both buffers.
961 * If the structure sizes dont agree, I will not copy.
962 * This could be due to an addition/deletion or a problem with the disk file.
966 if (shmem_old_size
== shmem_length
) {
967 for (cp
=buf
+4, cp1
=shmem_old
+4; (n
= 256*(*(cp
-3)) + *(cp
-2)); cp
+=(n
+3), cp1
+=(n
+3)) {
968 n1
= 256*(*(cp1
-3)) + *(cp1
-2);
969 if (n
== 0 || n1
!= n
|| strncmp((char *) cp
, (char *) cp1
, 4))
972 memcpy(cp
, cp1
, (size_t) n
);
978 i
= write(instance
->shmemfd
, buf
, shmem_length
);
981 if (i
!= shmem_length
) {
982 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: error writing shmem");
983 close(instance
->shmemfd
);
987 instance
->shmem
= (u_char
*) mmap(0, shmem_length
,
988 PROT_READ
| PROT_WRITE
,
989 #ifdef MAP_HASSEMAPHORE
992 MAP_SHARED
, instance
->shmemfd
, (off_t
)0);
994 if (instance
->shmem
== (u_char
*)MAP_FAILED
) {
996 close(instance
->shmemfd
);
1000 sprintf(Msg
, "SHMEM (size = %ld) is CONFIGURED and available as %s",
1001 (u_long
) shmem_length
, instance
->shmem_fname
);
1002 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1004 #endif /* ONCORE_SHMEM_STATUS */
1009 * Read Input file if it exists.
1014 struct instance
*instance
1018 * First we try to open the configuration file
1020 * where N is the unit number viz 127.127.30.N.
1021 * If we don't find it we try
1026 * If we don't find any then we don't have the cable delay or PPS offset
1027 * and we choose MODE (4) below.
1029 * Five Choices for MODE
1030 * (0) ONCORE is preinitialized, don't do anything to change it.
1031 * nb, DON'T set 0D mode, DON'T set Delay, position...
1032 * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1033 * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
1034 * lock this in, go to 0D mode.
1035 * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1036 * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
1037 * lock this in, go to 0D mode.
1038 * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
1039 * then this position is set as the INITIAL position of the ONCORE.
1040 * This can reduce the time to first fix.
1041 * -------------------------------------------------------------------------------
1042 * Note that an Oncore UT without a battery backup retains NO information if it is
1043 * power cycled, with a Battery Backup it remembers the almanac, etc.
1044 * For an Oncore VP, there is an eeprom that will contain this data, along with the
1045 * option of Battery Backup.
1046 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
1047 * power cycle, since there is nowhere to store the data.
1048 * -------------------------------------------------------------------------------
1050 * If we open one or the other of the files, we read it looking for
1051 * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
1052 * STATUS, POSN3D, POSN2D, CHAN, TRAIM
1053 * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must
1054 * be present or mode reverts to (2,4).
1058 * # is comment to end of line
1059 * = allowed between 1st and 2nd fields.
1061 * Expect to see one line with 'MODE' as first field, followed by an integer
1062 * in the range 0-4 (default = 4).
1064 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
1065 * All numbers are floating point.
1070 * Expect to see one line with 'HT' as first field,
1071 * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'
1072 * for feet or meters. HT is the height above the GPS ellipsoid.
1073 * If the receiver reports height in both GPS and MSL, then we will report
1074 * the difference GPS-MSL on the clockstats file.
1076 * There is an optional line, starting with DELAY, followed
1077 * by 1 or two fields. The first is a number (a time) the second is
1078 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1079 * DELAY is cable delay, typically a few tens of ns.
1081 * There is an optional line, starting with OFFSET, followed
1082 * by 1 or two fields. The first is a number (a time) the second is
1083 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1084 * OFFSET is the offset of the PPS pulse from 0. (only fully implemented
1085 * with the PPSAPI, we need to be able to tell the Kernel about this
1086 * offset if the Kernel PLL is in use, but can only do this presently
1087 * when using the PPSAPI interface. If not using the Kernel PLL,
1088 * then there is no problem.
1090 * There is an optional line, with either ASSERT or CLEAR on it, which
1091 * determine which transition of the PPS signal is used for timing by the
1092 * PPSAPI. If neither is present, then ASSERT is assumed.
1093 * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
1094 * For Flag2, ASSERT=0, and hence is default.
1096 * There is an optional line, with HARDPPS on it. Including this line causes
1097 * the PPS signal to control the kernel PLL.
1098 * HARDPPS can also be set with FLAG3 of the ntp.conf input.
1099 * For Flag3, 0 is disabled, and the default.
1101 * There are three options that have to do with using the shared memory option.
1102 * First, to enable the option there must be a SHMEM line with a file name.
1103 * The file name is the file associated with the shared memory.
1105 * In shared memory, there is one 'record' for each returned variable.
1106 * For the @@Ea data there are three 'records' containing position data.
1107 * There will always be data in the record corresponding to the '0D' @@Ea record,
1108 * and the user has a choice of filling the '3D' record by specifying POSN3D,
1109 * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D'
1110 * record is filled once every 15s.
1112 * Two additional variables that can be set are CHAN and TRAIM. These should be
1113 * set correctly by the code examining the @@Cj record, but we bring them out here
1114 * to allow the user to override either the # of channels, or the existence of TRAIM.
1115 * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
1116 * followed by YES or NO.
1118 * There is an optional line with MASK on it followed by one integer field in the
1119 * range 0 to 89. This sets the satellite mask angle and will determine the minimum
1120 * elevation angle for satellites to be tracked by the receiver. The default value
1121 * is 10 deg for the VP and 0 deg for all other receivers.
1123 * So acceptable input would be
1124 * # these are my coordinates (RWC)
1127 * HT 1589 # could equally well say HT 5215 FT
1132 char *cp
, *cc
, *ca
, line
[100], units
[2], device
[20], Msg
[160], **cpp
;
1133 char *dirs
[] = { "/etc/ntp", "/etc", 0 };
1134 int i
, sign
, lat_flg
, long_flg
, ht_flg
, mode
, mask
;
1137 fd
= NULL
; /* just to shutup gcc complaint */
1138 for (cpp
=dirs
; *cpp
; cpp
++) {
1140 sprintf(device
, "%s/ntp.oncore.%d", cp
, instance
->unit
); /* try "ntp.oncore.0 */
1141 if ((fd
=fopen(device
, "r")))
1143 sprintf(device
, "%s/ntp.oncore%d", cp
, instance
->unit
); /* try "ntp.oncore0" */
1144 if ((fd
=fopen(device
, "r")))
1146 sprintf(device
, "%s/ntp.oncore", cp
); /* and finally "ntp.oncore" */
1147 if ((fd
=fopen(device
, "r")))
1151 if (!fd
) { /* no inputfile, default to the works ... */
1152 instance
->init_type
= 4;
1157 lat_flg
= long_flg
= ht_flg
= 0;
1158 while (fgets(line
, 100, fd
)) {
1160 /* Remove comments */
1161 if ((cp
= strchr(line
, '#')))
1164 /* Remove trailing space */
1165 for (i
= strlen(line
);
1166 i
> 0 && isascii((int)line
[i
- 1]) && isspace((int)line
[i
- 1]);
1170 /* Remove leading space */
1171 for (cc
= line
; *cc
&& isascii((int)*cc
) && isspace((int)*cc
); cc
++)
1174 /* Stop if nothing left */
1178 /* Uppercase the command and find the arg */
1179 for (ca
= cc
; *ca
; ca
++) {
1180 if (isascii((int)*ca
)) {
1181 if (islower((int)*ca
)) {
1182 *ca
= toupper((int)*ca
);
1183 } else if (isspace((int)*ca
) || (*ca
== '='))
1188 /* Remove space (and possible =) leading the arg */
1189 for (; *ca
&& isascii((int)*ca
) && (isspace((int)*ca
) || (*ca
== '=')); ca
++)
1192 if (!strncmp(cc
, "STATUS", (size_t) 6) || !strncmp(cc
, "SHMEM", (size_t) 5)) {
1194 instance
->shmem_fname
= (char *) malloc((unsigned) (i
+1));
1195 strcpy(instance
->shmem_fname
, ca
);
1199 /* Uppercase argument as well */
1200 for (cp
= ca
; *cp
; cp
++)
1201 if (isascii((int)*cp
) && islower((int)*cp
))
1202 *cp
= toupper((int)*cp
);
1204 if (!strncmp(cc
, "LAT", (size_t) 3)) {
1206 sscanf(ca
, "%lf %lf %lf", &f1
, &f2
, &f3
);
1212 instance
->ss_lat
= sign
*1000*(fabs(f3
) + 60*(fabs(f2
) + 60*f1
)); /*miliseconds*/
1214 } else if (!strncmp(cc
, "LON", (size_t) 3)) {
1216 sscanf(ca
, "%lf %lf %lf", &f1
, &f2
, &f3
);
1222 instance
->ss_long
= sign
*1000*(fabs(f3
) + 60*(fabs(f2
) + 60*f1
)); /*miliseconds*/
1224 } else if (!strncmp(cc
, "HT", (size_t) 2)) {
1227 sscanf(ca
, "%lf %1s", &f1
, units
);
1228 if (units
[0] == 'F')
1230 instance
->ss_ht
= 100 * f1
; /* cm */
1232 } else if (!strncmp(cc
, "DELAY", (size_t) 5)) {
1235 sscanf(ca
, "%lf %1s", &f1
, units
);
1236 if (units
[0] == 'N')
1238 else if (units
[0] == 'U')
1240 else if (units
[0] == 'M')
1243 f1
= 1000000000 * f1
;
1244 if (f1
< 0 || f1
> 1.e9
)
1246 if (f1
< 0 || f1
> 999999) {
1247 sprintf(Msg
, "PPS Cable delay of %fns out of Range, ignored", f1
);
1248 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1250 instance
->delay
= f1
; /* delay in ns */
1251 } else if (!strncmp(cc
, "OFFSET", (size_t) 6)) {
1254 sscanf(ca
, "%lf %1s", &f1
, units
);
1255 if (units
[0] == 'N')
1257 else if (units
[0] == 'U')
1259 else if (units
[0] == 'M')
1262 f1
= 1000000000 * f1
;
1263 if (f1
< 0 || f1
> 1.e9
)
1265 if (f1
< 0 || f1
> 999999999.) {
1266 sprintf(Msg
, "PPS Offset of %fns out of Range, ignored", f1
);
1267 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1269 instance
->offset
= f1
; /* offset in ns */
1270 } else if (!strncmp(cc
, "MODE", (size_t) 4)) {
1271 sscanf(ca
, "%d", &mode
);
1272 if (mode
< 0 || mode
> 4)
1274 } else if (!strncmp(cc
, "ASSERT", (size_t) 6)) {
1275 instance
->assert = 1;
1276 } else if (!strncmp(cc
, "CLEAR", (size_t) 5)) {
1277 instance
->assert = 0;
1278 } else if (!strncmp(cc
, "HARDPPS", (size_t) 7)) {
1279 instance
->hardpps
= 1;
1280 } else if (!strncmp(cc
, "POSN2D", (size_t) 6)) {
1281 instance
->shmem_Posn
= 2;
1282 } else if (!strncmp(cc
, "POSN3D", (size_t) 6)) {
1283 instance
->shmem_Posn
= 3;
1284 } else if (!strncmp(cc
, "CHAN", (size_t) 4)) {
1285 sscanf(ca
, "%d", &i
);
1286 if ((i
== 6) || (i
== 8) || (i
== 12))
1287 instance
->chan_in
= i
;
1288 } else if (!strncmp(cc
, "TRAIM", (size_t) 5)) {
1289 instance
->traim_in
= 1; /* so TRAIM alone is YES */
1290 if (!strcmp(ca
, "NO") || !strcmp(ca
, "OFF")) /* Yes/No, On/Off */
1291 instance
->traim_in
= 0;
1292 } else if (!strncmp(cc
, "MASK", (size_t) 4)) {
1293 sscanf(ca
, "%d", &mask
);
1294 if (mask
> -1 && mask
< 90)
1295 instance
->Ag
= mask
; /* Satellite mask angle */
1301 * OK, have read all of data file, and extracted the good stuff.
1302 * If lat/long/ht specified they ALL must be specified for mode = (1,3).
1305 instance
->posn_set
= 1;
1306 if (!( lat_flg
&& long_flg
&& ht_flg
)) {
1307 printf("ONCORE: incomplete data on %s\n", device
);
1308 instance
->posn_set
= 0;
1309 if (mode
== 1 || mode
== 3) {
1310 sprintf(Msg
, "Input Mode = %d, but no/incomplete position, mode set to %d", mode
, mode
+1);
1311 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1315 instance
->init_type
= mode
;
1317 sprintf(Msg
, "Input mode = %d", mode
);
1318 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1324 * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
1329 struct recvbuf
*rbufp
1335 struct instance
*instance
;
1337 peer
= (struct peer
*)rbufp
->recv_srcclock
;
1338 instance
= (struct instance
*) peer
->procptr
->unitptr
;
1339 p
= (u_char
*) &rbufp
->recv_space
;
1344 printf("ONCORE: >>>");
1345 for(i
=0; i
<rbufp
->recv_length
; i
++)
1346 printf("%02x ", p
[i
]);
1348 printf("ONCORE: >>>");
1349 for(i
=0; i
<rbufp
->recv_length
; i
++)
1350 printf("%03o ", p
[i
]);
1355 i
= rbufp
->recv_length
;
1356 if (rcvbuf
+rcvptr
+i
> &rcvbuf
[sizeof rcvbuf
])
1357 i
= sizeof(rcvbuf
) - rcvptr
; /* and some char will be lost */
1358 memcpy(rcvbuf
+rcvptr
, p
, i
);
1360 oncore_consume(instance
);
1366 * Deal with any complete messages
1371 struct instance
*instance
1377 while (rcvptr
>= 7) {
1378 if (rcvbuf
[0] != '@' || rcvbuf
[1] != '@') {
1379 /* We're not in sync, lets try to get there */
1380 for (i
=1; i
< rcvptr
-1; i
++)
1381 if (rcvbuf
[i
] == '@' && rcvbuf
[i
+1] == '@')
1385 printf("ONCORE[%d]: >>> skipping %d chars\n", instance
->unit
, i
);
1388 memcpy(rcvbuf
, rcvbuf
+i
, (size_t)(rcvptr
-i
));
1393 /* Ok, we have a header now */
1394 l
= sizeof(oncore_messages
)/sizeof(oncore_messages
[0]) -1;
1396 if (!strncmp(oncore_messages
[m
].flag
, (char *)(rcvbuf
+2), (size_t) 2))
1401 printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance
->unit
, rcvbuf
[2], rcvbuf
[3]);
1403 memcpy(rcvbuf
, rcvbuf
+4, (size_t) 4);
1408 l
= oncore_messages
[m
].len
;
1411 printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance
->unit
, rcvbuf
[2], rcvbuf
[3], rcvptr
, l
, m
);
1413 /* Got the entire message ? */
1418 /* are we at the end of message? should be <Cksum><CR><LF> */
1420 if (rcvbuf
[l
-2] != '\r' || rcvbuf
[l
-1] != '\n') {
1423 printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance
->unit
);
1425 } else { /* check the CheckSum */
1426 if (oncore_checksum_ok(rcvbuf
, l
)) {
1427 if (instance
->shmem
!= NULL
) {
1428 instance
->shmem
[oncore_messages
[m
].shmem
+ 2]++;
1429 memcpy(instance
->shmem
+ oncore_messages
[m
].shmem
+ 3,
1430 rcvbuf
, (size_t) l
);
1432 oncore_msg_any(instance
, rcvbuf
, (size_t) (l
-3), m
);
1433 if (oncore_messages
[m
].handler
)
1434 oncore_messages
[m
].handler(instance
, rcvbuf
, (size_t) (l
-3));
1438 printf("ONCORE[%d]: Checksum mismatch!\n", instance
->unit
);
1439 printf("ONCORE[%d]: @@%c%c ", instance
->unit
, rcvbuf
[2], rcvbuf
[3]);
1441 printf("%03o ", rcvbuf
[i
]);
1448 memcpy(rcvbuf
, rcvbuf
+l
, (size_t) (rcvptr
-l
));
1456 oncore_get_timestamp(
1457 struct instance
*instance
,
1458 long dt1
, /* tick offset THIS time step */
1459 long dt2
/* tick offset NEXT time step */
1466 #ifdef HAVE_STRUCT_TIMESPEC
1467 struct timespec
*tsp
= 0;
1469 struct timeval
*tsp
= 0;
1473 pps_params_t current_params
;
1474 struct timespec timeout
;
1478 /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
1479 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
1480 * times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
1481 * This gives good time, which gets better when the SS is done.
1484 if ((instance
->site_survey
== ONCORE_SS_DONE
) && (instance
->mode
!= MODE_0D
))
1486 /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
1488 if ((instance
->site_survey
!= ONCORE_SS_DONE
) || (instance
->mode
!= MODE_0D
))
1492 /* Don't do anything without an almanac to define the GPS->UTC delta */
1494 if (instance
->rsm
.bad_almanac
)
1497 /* Once the Almanac is valid, the M12+T does not produce valid UTC
1499 * Wait for UTC offset decode valid, then wait one message more
1500 * so we are not off by 13 seconds after reset.
1503 if (instance
->count5
) {
1508 j
= instance
->ev_serial
;
1510 timeout
.tv_nsec
= 0;
1511 if (time_pps_fetch(instance
->pps_h
, PPS_TSFMT_TSPEC
, &pps_i
,
1513 printf("ONCORE: time_pps_fetch failed\n");
1517 if (instance
->assert) {
1518 tsp
= &pps_i
.assert_timestamp
;
1522 i
= (u_long
) pps_i
.assert_sequence
;
1523 # ifdef HAVE_STRUCT_TIMESPEC
1524 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1525 instance
->unit
, i
, j
,
1526 (long)tsp
->tv_sec
, (long)tsp
->tv_nsec
);
1528 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1529 instance
->unit
, i
, j
,
1530 (long)tsp
->tv_sec
, (long)tsp
->tv_usec
);
1535 if (pps_i
.assert_sequence
== j
) {
1536 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1539 instance
->ev_serial
= pps_i
.assert_sequence
;
1541 tsp
= &pps_i
.clear_timestamp
;
1545 i
= (u_long
) pps_i
.clear_sequence
;
1546 # ifdef HAVE_STRUCT_TIMESPEC
1547 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1548 instance
->unit
, i
, j
, (long)tsp
->tv_sec
, (long)tsp
->tv_nsec
);
1550 printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1551 instance
->unit
, i
, j
, (long)tsp
->tv_sec
, (long)tsp
->tv_usec
);
1556 if (pps_i
.clear_sequence
== j
) {
1557 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1560 instance
->ev_serial
= pps_i
.clear_sequence
;
1563 /* convert timespec -> ntp l_fp */
1567 ts
.l_uf
= dmy
* 4294967296.0;
1568 ts
.l_ui
= tsp
->tv_sec
;
1571 alternate code
for previous
4 lines is
1572 dmy
= 1.0e-9*tsp
->tv_nsec
; /* fractional part */
1574 dmy
= tsp
->tv_sec
; /* integer part */
1575 DTOLFP(dmy
, &ts_tmp
);
1576 L_ADD(&ts
, &ts_tmp
);
1578 dmy
= 1.0e-9*tsp
->tv_nsec
; /* fractional part */
1580 ts
.l_ui
= tsp
->tv_sec
;
1583 /* now have timestamp in ts */
1584 /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
1585 /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
1586 /* we just try to add them in and dont test for that here */
1588 /* saw_tooth not really necessary if using TIMEVAL */
1589 /* since its only precise to us, but do it anyway. */
1591 /* offset in ns, and is positive (late), we subtract */
1592 /* to put the PPS time transition back where it belongs */
1594 /* must hand the offset for the NEXT sec off to the Kernel to do */
1595 /* the addition, so that the Kernel PLL sees the offset too */
1597 if (instance
->assert)
1598 instance
->pps_p
.assert_offset
.tv_nsec
= -dt2
;
1600 instance
->pps_p
.clear_offset
.tv_nsec
= -dt2
;
1602 /* The following code is necessary, and not just a time_pps_setparams,
1603 * using the saved instance->pps_p, since some other process on the
1604 * machine may have diddled with the mode bits (say adding something
1605 * that it needs). We take what is there and ADD what we need.
1606 * [[ The results from the time_pps_getcap is unlikely to change so
1607 * we could probably just save it, but I choose to do the call ]]
1608 * Unfortunately, there is only ONE set of mode bits in the kernel per
1609 * interface, and not one set for each open handle.
1611 * There is still a race condition here where we might mess up someone
1612 * elses mode, but if he is being careful too, he should survive.
1615 if (time_pps_getcap(instance
->pps_h
, ¤t_mode
) < 0) {
1616 msyslog(LOG_ERR
, "time_pps_getcap failed: %m");
1620 if (time_pps_getparams(instance
->pps_h
, ¤t_params
) < 0) {
1621 msyslog(LOG_ERR
, "time_pps_getparams failed: %m");
1625 /* or current and mine */
1626 current_params
.mode
|= instance
->pps_p
.mode
;
1627 /* but only set whats legal */
1628 current_params
.mode
&= current_mode
;
1630 current_params
.assert_offset
.tv_sec
= 0;
1631 current_params
.assert_offset
.tv_nsec
= -dt2
;
1632 current_params
.clear_offset
.tv_sec
= 0;
1633 current_params
.clear_offset
.tv_nsec
= -dt2
;
1635 if (time_pps_setparams(instance
->pps_h
, ¤t_params
))
1636 record_clock_stats(&(instance
->peer
->srcadr
), "ONCORE: Error doing time_pps_setparams");
1638 /* have time from UNIX origin, convert to NTP origin. */
1640 ts
.l_ui
+= JAN_1970
;
1641 instance
->pp
->lastrec
= ts
;
1643 /* print out information about this timestamp (long line) */
1646 ts_tmp
.l_ui
= 0; /* zero integer part */
1647 LFPTOD(&ts_tmp
, dmy
); /* convert fractional part to a double */
1648 j
= 1.0e9
*dmy
; /* then to integer ns */
1651 if (instance
->chan
== 6)
1652 Rsm
= instance
->BEHa
[64];
1653 else if (instance
->chan
== 8)
1654 Rsm
= instance
->BEHa
[72];
1655 else if (instance
->chan
== 12)
1656 Rsm
= ((instance
->BEHa
[129]<<8) | instance
->BEHa
[130]);
1658 if (instance
->chan
== 6 || instance
->chan
== 8) {
1659 char f1
[5], f2
[5], f3
[5], f4
[5];
1660 if (instance
->traim
) {
1661 sprintf(f1
, "%d", instance
->BEHn
[21]);
1662 sprintf(f2
, "%d", instance
->BEHn
[22]);
1663 sprintf(f3
, "%2d", instance
->BEHn
[23]*256+instance
->BEHn
[24]);
1664 sprintf(f4
, "%3d", (s_char
) instance
->BEHn
[25]);
1671 sprintf(instance
->pp
->a_lastcode
, /* MAX length 128, currently at 121 */
1672 "%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",
1674 instance
->pp
->year
, instance
->pp
->day
,
1675 instance
->pp
->hour
, instance
->pp
->minute
, instance
->pp
->second
,
1676 (long) tsp
->tv_sec
% 60,
1677 Rsm
, 0.1*(256*instance
->BEHa
[35]+instance
->BEHa
[36]),
1679 instance
->BEHa
[38], instance
->BEHa
[39], instance
->traim
, f1
, f2
,
1680 /* nsat visible, nsat tracked, traim,traim,traim */
1682 /* sigma neg-sawtooth */
1683 /*sat*/ instance
->BEHa
[41], instance
->BEHa
[45], instance
->BEHa
[49], instance
->BEHa
[53],
1684 instance
->BEHa
[57], instance
->BEHa
[61], instance
->BEHa
[65], instance
->BEHa
[69]
1685 ); /* will be 0 for 6 chan */
1686 } else if (instance
->chan
== 12) {
1687 char f1
[5], f2
[5], f3
[5], f4
[5];
1688 if (instance
->traim
) {
1689 sprintf(f1
, "%d", instance
->BEHn
[6]);
1690 sprintf(f2
, "%d", instance
->BEHn
[7]);
1691 sprintf(f3
, "%d", instance
->BEHn
[12]*256+instance
->BEHn
[13]);
1692 sprintf(f4
, "%3d", (s_char
) instance
->BEHn
[14]);
1699 sprintf(instance
->pp
->a_lastcode
,
1700 "%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",
1702 instance
->pp
->year
, instance
->pp
->day
,
1703 instance
->pp
->hour
, instance
->pp
->minute
, instance
->pp
->second
,
1704 (long) tsp
->tv_sec
% 60,
1705 Rsm
, 0.1*(256*instance
->BEHa
[53]+instance
->BEHa
[54]),
1707 instance
->BEHa
[55], instance
->BEHa
[56], instance
->traim
, f1
, f2
,
1708 /* nsat visible, nsat tracked traim,traim,traim */
1710 /* sigma neg-sawtooth */
1711 /*sat*/ instance
->BEHa
[58], instance
->BEHa
[64], instance
->BEHa
[70], instance
->BEHa
[76],
1712 instance
->BEHa
[82], instance
->BEHa
[88], instance
->BEHa
[94], instance
->BEHa
[100],
1713 instance
->BEHa
[106], instance
->BEHa
[112], instance
->BEHa
[118], instance
->BEHa
[124]
1721 n
= strlen(instance
->pp
->a_lastcode
);
1722 printf("ONCORE[%d]: len = %d %s\n", instance
->unit
, n
, instance
->pp
->a_lastcode
);
1726 /* and some things I dont understand (magic ntp things) */
1728 if (!refclock_process(instance
->pp
)) {
1729 refclock_report(instance
->peer
, CEVNT_BADTIME
);
1733 record_clock_stats(&(instance
->peer
->srcadr
), instance
->pp
->a_lastcode
);
1734 instance
->pollcnt
= 2;
1736 if (instance
->polled
) {
1737 instance
->polled
= 0;
1738 /* instance->pp->dispersion = instance->pp->skew = 0; */
1739 instance
->pp
->lastref
= instance
->pp
->lastrec
;
1740 refclock_receive(instance
->peer
);
1745 /*************** oncore_msg_XX routines start here *******************/
1749 * print Oncore response message.
1754 struct instance
*instance
,
1761 const char *fmt
= oncore_messages
[idx
].fmt
;
1763 #ifdef HAVE_GETCLOCK
1770 # ifdef HAVE_GETCLOCK
1771 (void) getclock(TIMEOFDAY
, &ts
);
1772 tv
.tv_sec
= ts
.tv_sec
;
1773 tv
.tv_usec
= ts
.tv_nsec
/ 1000;
1775 GETTIMEOFDAY(&tv
, 0);
1777 printf("ONCORE[%d]: %ld.%06ld\n", instance
->unit
, (long) tv
.tv_sec
, (long) tv
.tv_usec
);
1780 printf(">>@@%c%c ", buf
[2], buf
[3]);
1781 for(i
=2; i
< len
&& i
< 2400 ; i
++)
1782 printf("%02x", buf
[i
]);
1787 for (p
= fmt
; *p
; p
++) {
1791 printf("\n%c%c", buf
[2], buf
[3]);
1793 for (p
= fmt
; *p
; p
++) {
1794 printf("%02x", buf
[i
++]);
1804 /* Latitude, Longitude, Height */
1808 struct instance
*instance
,
1821 struct instance
*instance
,
1825 { char Msg
[160], *cp
;
1828 if (instance
->o_state
== ONCORE_RUN
)
1831 instance
->Ag
= buf
[4];
1832 sprintf(Msg
, "Satellite mask angle %s %d degrees", cp
, (int) instance
->Ag
);
1833 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1839 * get Position hold position
1844 struct instance
*instance
,
1849 instance
->ss_lat
= buf_w32(&buf
[4]);
1850 instance
->ss_long
= buf_w32(&buf
[8]);
1851 instance
->ss_ht
= buf_w32(&buf
[12]);
1853 /* Print out Position */
1854 oncore_print_posn(instance
);
1860 * Try to use Oncore UT+ Auto Survey Feature
1861 * If its not there (VP), set flag to do it ourselves.
1866 struct instance
*instance
,
1873 instance
->saw_At
= 1;
1874 if (instance
->site_survey
== ONCORE_SS_TESTING
) {
1876 record_clock_stats(&(instance
->peer
->srcadr
),
1877 "Initiating hardware 3D site survey");
1879 cp
= "SSstate = ONCORE_SS_HW";
1880 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
1881 instance
->site_survey
= ONCORE_SS_HW
;
1890 * Nb. @@Ay is not supported for early UT (no plus) model
1895 struct instance
*instance
,
1902 if (instance
->saw_Ay
)
1905 instance
->saw_Ay
= 1;
1907 instance
->offset
= buf_w32(&buf
[4]);
1909 sprintf(Msg
, "PPS Offset is set to %ld ns", instance
->offset
);
1910 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1921 struct instance
*instance
,
1928 if (instance
->saw_Az
)
1931 instance
->saw_Az
= 1;
1933 instance
->delay
= buf_w32(&buf
[4]);
1935 sprintf(Msg
, "Cable delay is set to %ld ns", instance
->delay
);
1936 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1941 /* Ba, Ea and Ha come here, these contain Position */
1945 struct instance
*instance
,
1954 /* OK, we are close to the RUN state now.
1955 * But we have a few more items to initialize first.
1957 * At the beginning of this routine there are several 'timers'.
1958 * We enter this routine 1/sec, and since the upper levels of NTP have usurped
1959 * the use of timers, we use the 1/sec entry to do things that
1960 * we would normally do with timers...
1963 if (instance
->o_state
== ONCORE_CHECK_CHAN
) { /* here while checking for the # chan */
1964 if (buf
[2] == 'B') { /* 6chan */
1965 if (instance
->chan_ck
< 6) instance
->chan_ck
= 6;
1966 } else if (buf
[2] == 'E') { /* 8chan */
1967 if (instance
->chan_ck
< 8) instance
->chan_ck
= 8;
1968 } else if (buf
[2] == 'H') { /* 12chan */
1969 if (instance
->chan_ck
< 12) instance
->chan_ck
= 12;
1972 if (instance
->count3
++ < 5)
1975 instance
->count3
= 0;
1977 if (instance
->chan_in
!= -1) /* set in Input */
1978 instance
->chan
= instance
->chan_in
;
1979 else /* set from test */
1980 instance
->chan
= instance
->chan_ck
;
1982 sprintf(Msg
, "Input says chan = %d", instance
->chan_in
);
1983 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1984 sprintf(Msg
, "Model # says chan = %d", instance
->chan_id
);
1985 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1986 sprintf(Msg
, "Testing says chan = %d", instance
->chan_ck
);
1987 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1988 sprintf(Msg
, "Using chan = %d", instance
->chan
);
1989 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
1991 instance
->o_state
= ONCORE_HAVE_CHAN
;
1992 cp
= "state = ONCORE_HAVE_CHAN";
1993 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
1995 instance
->timeout
= 4;
1996 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cj
, sizeof(oncore_cmd_Cj
));
2000 if (instance
->o_state
!= ONCORE_ALMANAC
&& instance
->o_state
!= ONCORE_RUN
)
2003 /* PAUSE 5sec - make sure results are stable, before using position */
2005 if (instance
->count
) {
2006 if (instance
->count
++ < 5)
2008 instance
->count
= 0;
2011 memcpy(instance
->BEHa
, buf
, (size_t) (len
+3)); /* Ba, Ea or Ha */
2013 /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
2015 oncore_check_almanac(instance
);
2016 oncore_check_antenna(instance
);
2018 /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
2019 /* When we have an almanac, we will start the Bn/En/@@Hn messages */
2021 if (instance
->o_state
== ONCORE_ALMANAC
)
2022 if (oncore_wait_almanac(instance
))
2025 /* do some things once when we get this far in BaEaHa */
2027 if (instance
->once
) {
2029 instance
->count2
= 1;
2031 /* Have we seen an @@At (position hold) command response */
2032 /* if not, message out */
2034 if (instance
->chan
!= 12 && !instance
->saw_At
) {
2035 cp
= "Not Good, no @@At command (no Position Hold), must be a GT/GT+";
2036 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2037 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Av1
, sizeof(oncore_cmd_Av1
));
2040 /* have an Almanac, can start the SiteSurvey
2041 * (actually only need to get past the almanac_load where we diddle with At
2042 * command,- we can't change it after we start the HW_SS below
2045 mode
= instance
->init_type
;
2047 case 0: /* NO initialization, don't change anything */
2048 case 1: /* Use given Position */
2050 instance
->site_survey
= ONCORE_SS_DONE
;
2051 cp
= "SSstate = ONCORE_SS_DONE";
2052 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2056 case 4: /* Site Survey */
2057 cp
= "SSstate = ONCORE_SS_TESTING";
2058 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2059 instance
->site_survey
= ONCORE_SS_TESTING
;
2060 instance
->count1
= 1;
2061 if (instance
->chan
== 12)
2062 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gd3
, sizeof(oncore_cmd_Gd3
)); /* M12+T */
2064 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_At2
, sizeof(oncore_cmd_At2
)); /* not GT, arg not VP */
2068 /* Read back PPS Offset for Output */
2069 /* Nb. This will fail silently for early UT (no plus) and M12 models */
2071 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ayx
, sizeof(oncore_cmd_Ayx
));
2073 /* Read back Cable Delay for Output */
2075 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Azx
, sizeof(oncore_cmd_Azx
));
2077 /* Read back Satellite Mask Angle for Output */
2079 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Agx
, sizeof(oncore_cmd_Agx
));
2083 /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
2084 * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
2085 * We must do the Gd3, and then wait a cycle or two for things to settle,
2086 * then check Ha[130]&0x10 to see if a SS is in progress.
2087 * We will set SW if HW has not been set after an appropriate delay.
2090 if (instance
->site_survey
== ONCORE_SS_TESTING
) {
2091 if (instance
->chan
== 12) {
2092 if (instance
->count1
) {
2093 if (instance
->count1
++ > 5 || instance
->BEHa
[130]&0x10) {
2094 instance
->count1
= 0;
2095 if (instance
->BEHa
[130]&0x10) {
2096 record_clock_stats(&(instance
->peer
->srcadr
),
2097 "Initiating hardware 3D site survey");
2099 record_clock_stats(&(instance
->peer
->srcadr
), "SSstate = ONCORE_SS_HW");
2100 instance
->site_survey
= ONCORE_SS_HW
;
2102 record_clock_stats(&(instance
->peer
->srcadr
), "SSstate = ONCORE_SS_SW");
2103 instance
->site_survey
= ONCORE_SS_SW
;
2108 if (instance
->count1
) {
2109 if (instance
->count1
++ > 5) {
2110 instance
->count1
= 0;
2112 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
2113 * wait after the @@At2/@@Gd3 command we have not changed the state to
2114 * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then
2115 * the variable would have been changed by now.
2116 * There are three possibilities:
2118 * (a) We did not get a response to the @@At0 or @@At2 commands,
2119 * and it must be a GT/GT+/SL with no position hold mode.
2120 * We will have to do it ourselves.
2121 * (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
2122 * must be a VP or older UT which doesn't have Site Survey mode.
2123 * We will have to do it ourselves.
2125 * (c) We saw the @@Gd command, and saw H[13]*0x10
2126 * We will have to do it ourselves (done above)
2129 sprintf(Msg
, "Initiating software 3D site survey (%d samples)",
2131 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2133 record_clock_stats(&(instance
->peer
->srcadr
), "SSstate = ONCORE_SS_SW");
2134 instance
->site_survey
= ONCORE_SS_SW
;
2136 instance
->ss_lat
= instance
->ss_long
= instance
->ss_ht
= 0;
2137 if (instance
->chan
== 12)
2138 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gd0
, sizeof(oncore_cmd_Gd0
)); /* disable */
2140 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_At0
, sizeof(oncore_cmd_At0
)); /* disable */
2141 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Av0
, sizeof(oncore_cmd_Av0
)); /* disable */
2148 /* check the mode we are in 0/2/3D */
2150 if (instance
->chan
== 6) {
2151 if (instance
->BEHa
[64]&0x8)
2152 instance
->mode
= MODE_0D
;
2153 else if (instance
->BEHa
[64]&0x10)
2154 instance
->mode
= MODE_2D
;
2155 else if (instance
->BEHa
[64]&0x20)
2156 instance
->mode
= MODE_3D
;
2157 } else if (instance
->chan
== 8) {
2158 if (instance
->BEHa
[72]&0x8)
2159 instance
->mode
= MODE_0D
;
2160 else if (instance
->BEHa
[72]&0x10)
2161 instance
->mode
= MODE_2D
;
2162 else if (instance
->BEHa
[72]&0x20)
2163 instance
->mode
= MODE_3D
;
2164 } else if (instance
->chan
== 12) {
2167 bits
= (instance
->BEHa
[129]>>5) & 0x7; /* actually Ha */
2169 instance
->mode
= MODE_0D
;
2170 else if (bits
== 0x6)
2171 instance
->mode
= MODE_2D
;
2172 else if (bits
== 0x7)
2173 instance
->mode
= MODE_3D
;
2176 /* copy the record to the (extra) location in SHMEM */
2178 if (instance
->shmem
) {
2180 u_char
*smp
; /* pointer to start of shared mem for Ba/Ea/Ha */
2182 switch(instance
->chan
) {
2183 case 6: smp
= &instance
->shmem
[instance
->shmem_Ba
]; break;
2184 case 8: smp
= &instance
->shmem
[instance
->shmem_Ea
]; break;
2185 case 12: smp
= &instance
->shmem
[instance
->shmem_Ha
]; break;
2186 default: smp
= (u_char
*) NULL
; break;
2189 switch (instance
->mode
) {
2190 case MODE_0D
: i
= 1; break; /* 0D, Position Hold */
2191 case MODE_2D
: i
= 2; break; /* 2D, Altitude Hold */
2192 case MODE_3D
: i
= 3; break; /* 3D fix */
2193 default: i
= 0; break;
2196 if (i
&& smp
!= NULL
) {
2199 memcpy(&smp
[i
+3], buf
, (size_t) (len
+3));
2204 * check if traim timer active
2205 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
2208 if (instance
->traim_delay
) {
2209 if (instance
->traim_delay
++ > 5) {
2210 instance
->traim
= 0;
2211 instance
->traim_delay
= 0;
2212 cp
= "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2213 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2215 oncore_set_traim(instance
);
2221 /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
2223 if (!instance
->have_dH
&& !instance
->traim_delay
)
2224 oncore_compute_dH(instance
);
2227 * must be ONCORE_RUN if we are here.
2228 * Have # chan and TRAIM by now.
2231 instance
->pp
->year
= buf
[6]*256+buf
[7];
2232 instance
->pp
->day
= ymd2yd(buf
[6]*256+buf
[7], buf
[4], buf
[5]);
2233 instance
->pp
->hour
= buf
[8];
2234 instance
->pp
->minute
= buf
[9];
2235 instance
->pp
->second
= buf
[10];
2238 * Are we doing a Hardware or Software Site Survey?
2241 if (instance
->site_survey
== ONCORE_SS_HW
|| instance
->site_survey
== ONCORE_SS_SW
)
2242 oncore_ss(instance
);
2244 /* see if we ever saw a response from the @@Ayx above */
2246 if (instance
->count2
) {
2247 if (instance
->count2
++ > 5) { /* this delay to check on @@Ay command */
2248 instance
->count2
= 0;
2250 /* Have we seen an Ay (1PPS time offset) command response */
2251 /* if not, and non-zero offset, zero the offset, and send message */
2253 if (!instance
->saw_Ay
&& instance
->offset
) {
2254 cp
= "No @@Ay command, PPS OFFSET ignored";
2255 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2256 instance
->offset
= 0;
2262 * Check the leap second status once per day.
2265 oncore_check_leap_sec(instance
);
2268 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2271 if (instance
->shmem
&& !instance
->shmem_bad_Ea
&& instance
->shmem_Posn
&& (instance
->site_survey
== ONCORE_SS_DONE
))
2272 oncore_shmem_get_3D(instance
);
2274 if (!instance
->traim
) /* NO traim, no BnEnHn, go get tick */
2275 oncore_get_timestamp(instance
, instance
->offset
, instance
->offset
);
2280 /* Almanac Status */
2284 struct instance
*instance
,
2291 sprintf(Msg
, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
2292 ((buf
[4]) ? "LOADED" : "(NONE)"), buf
[5], buf
[6], buf
[7], w32(&buf
[8]) );
2293 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2298 /* get leap-second warning message */
2301 * @@Bj does NOT behave as documented in current Oncore firmware.
2302 * It turns on the LEAP indicator when the data is set, and does not,
2303 * as documented, wait until the beginning of the month when the
2304 * leap second will occur.
2305 * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
2306 * @@Bj is only called in June/December.
2311 struct instance
*instance
,
2320 instance
->pp
->leap
= LEAP_ADDSECOND
;
2321 cp
= "Set pp.leap to LEAP_ADDSECOND";
2324 instance
->pp
->leap
= LEAP_DELSECOND
;
2325 cp
= "Set pp.leap to LEAP_DELSECOND";
2329 instance
->pp
->leap
= LEAP_NOWARNING
;
2330 cp
= "Set pp.leap to LEAP_NOWARNING";
2333 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2340 struct instance
*instance
,
2348 if (instance
->o_state
!= ONCORE_RUN
)
2351 if (instance
->traim_delay
) { /* flag that @@Bn/@@En/Hn returned */
2352 instance
->traim_ck
= 1;
2353 instance
->traim_delay
= 0;
2354 cp
= "ONCORE: Detected TRAIM, TRAIM = ON";
2355 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2357 oncore_set_traim(instance
);
2360 memcpy(instance
->BEHn
, buf
, (size_t) len
); /* Bn or En or Hn */
2362 if (!instance
->traim
) /* BnEnHn will be turned off in any case */
2365 /* If Time RAIM doesn't like it, don't trust it */
2367 if (buf
[2] == 'H') {
2368 if (instance
->BEHn
[6]) /* bad TRAIM */
2371 dt1
= instance
->saw_tooth
+ instance
->offset
; /* dt this time step */
2372 instance
->saw_tooth
= (s_char
) instance
->BEHn
[14]; /* update for next time Hn[14] */
2373 dt2
= instance
->saw_tooth
+ instance
->offset
; /* dt next time step */
2375 if (instance
->BEHn
[21]) /* bad TRAIM */
2378 dt1
= instance
->saw_tooth
+ instance
->offset
; /* dt this time step */
2379 instance
->saw_tooth
= (s_char
) instance
->BEHn
[25]; /* update for next time Bn[25], En[25] */
2380 dt2
= instance
->saw_tooth
+ instance
->offset
; /* dt next time step */
2383 oncore_get_timestamp(instance
, dt1
, dt2
);
2388 /* Here for @@Ca, @@Fa and @@Ia messages */
2390 /* These are Self test Commands for 6, 8, and 12 chan receivers.
2391 * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
2392 * It was found that under some circumstances the following
2393 * command would fail if issued immediately after the return from the
2394 * @@Fa, but a 2sec delay seemed to fix things. Since simply calling
2395 * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
2396 * itimer, we set a flag, and test it at the next POLL. If it hasn't
2397 * been cleared, we reissue the @@Cj that is issued below.
2398 * Note that we do a @@Cj at the beginning, and again here.
2399 * The first is to get the info, the 2nd is just used as a safe command
2400 * after the @@Fa for all Oncores (and it was in this posn in the
2406 struct instance
*instance
,
2414 if (instance
->o_state
== ONCORE_TEST_SENT
) {
2415 enum antenna_state antenna
;
2417 instance
->timeout
= 0;
2422 printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance
->unit
, buf
[2], buf
[4], buf
[5], buf
[6]);
2424 printf("ONCORE[%d]: >>@@%ca %x %x\n", instance
->unit
, buf
[2], buf
[4], buf
[5]);
2428 antenna
= (buf
[4] & 0xc0) >> 6;
2431 i
= buf
[4] || buf
[5];
2432 if (buf
[2] == 'I') i
= i
|| buf
[6];
2434 if (buf
[2] == 'I') {
2435 msyslog(LOG_ERR
, "ONCORE[%d]: self test failed: result %02x %02x %02x",
2436 instance
->unit
, buf
[4], buf
[5], buf
[6]);
2438 msyslog(LOG_ERR
, "ONCORE[%d]: self test failed: result %02x %02x",
2439 instance
->unit
, buf
[4], buf
[5]);
2441 cp
= "ONCORE: self test failed, shutting down driver";
2442 record_clock_stats(&instance
->peer
->srcadr
, cp
);
2444 refclock_report(instance
->peer
, CEVNT_FAULT
);
2445 oncore_shutdown(instance
->unit
, instance
->peer
);
2449 /* report the current antenna state */
2451 oncore_antenna_report(instance
, antenna
);
2453 instance
->o_state
= ONCORE_INIT
;
2454 cp
= "state = ONCORE_INIT";
2455 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2457 instance
->timeout
= 4;
2458 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cj
, sizeof(oncore_cmd_Cj
));
2465 * Demultiplex the almanac into shmem
2470 struct instance
*instance
,
2477 if (instance
->shmem
== NULL
)
2480 if (buf
[4] == 5 && buf
[5] > 0 && buf
[5] < 26)
2482 else if (buf
[4] == 4 && buf
[5] <= 5)
2484 else if (buf
[4] == 4 && buf
[5] <= 10)
2486 else if (buf
[4] == 4 && buf
[5] == 25)
2491 cp
= "Cb: Response is NO ALMANAC";
2492 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2497 instance
->shmem
[instance
->shmem_Cb
+ i
+ 2]++;
2498 memcpy(instance
->shmem
+ instance
->shmem_Cb
+ i
+ 3, buf
, (size_t) (len
+ 3));
2503 sprintf(Msg
, "See Cb [%d,%d]", buf
[4], buf
[5]);
2504 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2512 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
2513 * not so for VP (eeprom) or any unit with a battery
2518 struct instance
*instance
,
2525 if (instance
->o_state
== ONCORE_RESET_SENT
) {
2526 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cg
, sizeof(oncore_cmd_Cg
)); /* Return to Posn Fix mode */
2527 /* Reset set VP to IDLE */
2528 instance
->o_state
= ONCORE_TEST_SENT
;
2529 cp
= "state = ONCORE_TEST_SENT";
2530 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2532 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cj
, sizeof(oncore_cmd_Cj
));
2539 * This is the Grand Central Station for the Preliminary Initialization.
2540 * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
2542 * We do an @@Cj whenever we need a safe command for all Oncores.
2543 * The @@Cj gets us back here where we can switch to the next phase of setup.
2545 * o Once at the very beginning (in start) to get the Model number.
2546 * This info is printed, but no longer used.
2547 * o Again after we have determined the number of Channels in the receiver.
2548 * o And once later after we have done a reset and test, (which may hang),
2549 * as we are about to initialize the Oncore and start it running.
2550 * o We have one routine below for each case.
2555 struct instance
*instance
,
2563 memcpy(instance
->Cj
, buf
, len
);
2565 instance
->timeout
= 0;
2566 if (instance
->o_state
== ONCORE_CHECK_ID
) {
2567 oncore_msg_Cj_id(instance
, buf
, len
);
2568 oncore_chan_test(instance
);
2569 } else if (instance
->o_state
== ONCORE_HAVE_CHAN
) {
2570 mode
= instance
->init_type
;
2571 if (mode
== 3 || mode
== 4) { /* Cf will return here to check for TEST */
2572 instance
->o_state
= ONCORE_RESET_SENT
;
2573 cp
= "state = ONCORE_RESET_SENT";
2574 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2575 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cf
, sizeof(oncore_cmd_Cf
));
2577 instance
->o_state
= ONCORE_TEST_SENT
;
2578 cp
= "state = ONCORE_TEST_SENT";
2579 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2583 if (instance
->o_state
== ONCORE_TEST_SENT
) {
2584 if (instance
->chan
== 6)
2585 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ca
, sizeof(oncore_cmd_Ca
));
2586 else if (instance
->chan
== 8)
2587 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Fa
, sizeof(oncore_cmd_Fa
));
2588 else if (instance
->chan
== 12)
2589 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ia
, sizeof(oncore_cmd_Ia
));
2590 } else if (instance
->o_state
== ONCORE_INIT
)
2591 oncore_msg_Cj_init(instance
, buf
, len
);
2596 /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
2597 * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
2598 * and from Motorola. Until recently Rick was the only source of
2599 * this information as Motorola didn't give the information out.
2601 * Determine the Type from the Model #, this determines #chan and if TRAIM is
2604 * The Information from this routine is NO LONGER USED.
2605 * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
2610 struct instance
*instance
,
2615 char *cp
, *cp1
, *cp2
, Model
[21], Msg
[160];
2617 /* Write Receiver ID message to clockstats file */
2619 instance
->Cj
[294] = '\0';
2620 for (cp
=(char *)instance
->Cj
; cp
< (char *) &instance
->Cj
[294]; ) {
2621 cp1
= strchr(cp
, '\r');
2623 cp1
= (char *)&instance
->Cj
[294];
2625 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2630 /* next, the Firmware Version and Revision numbers */
2632 instance
->version
= atoi((char *) &instance
->Cj
[83]);
2633 instance
->revision
= atoi((char *) &instance
->Cj
[111]);
2635 /* from model number decide which Oncore this is,
2636 and then the number of channels */
2638 for (cp
= (char *) &instance
->Cj
[160]; *cp
== ' '; cp
++) /* start right after 'Model #' */
2642 for (; !isspace((int)*cp
) && cp
-cp1
< 20; cp
++, cp2
++)
2647 if (!strncmp(Model
, "PVT6", (size_t) 4)) {
2649 instance
->model
= ONCORE_PVT6
;
2650 } else if (Model
[0] == 'A') {
2652 instance
->model
= ONCORE_BASIC
;
2653 } else if (Model
[0] == 'B' || !strncmp(Model
, "T8", (size_t) 2)) {
2655 instance
->model
= ONCORE_VP
;
2656 } else if (Model
[0] == 'P') {
2658 instance
->model
= ONCORE_M12
;
2659 } else if (Model
[0] == 'R' || Model
[0] == 'D' || Model
[0] == 'S') {
2660 if (Model
[5] == 'N') {
2662 instance
->model
= ONCORE_GT
;
2663 } else if ((Model
[1] == '3' || Model
[1] == '4') && Model
[5] == 'G') {
2665 instance
->model
= ONCORE_GTPLUS
;
2666 } else if ((Model
[1] == '5' && Model
[5] == 'U') || (Model
[1] == '1' && Model
[5] == 'A')) {
2668 instance
->model
= ONCORE_UT
;
2669 } else if (Model
[1] == '5' && Model
[5] == 'G') {
2671 instance
->model
= ONCORE_UTPLUS
;
2672 } else if (Model
[1] == '6' && Model
[5] == 'G') {
2674 instance
->model
= ONCORE_SL
;
2677 instance
->model
= ONCORE_UNKNOWN
;
2681 instance
->model
= ONCORE_UNKNOWN
;
2684 /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
2686 sprintf(Msg
, "This looks like an Oncore %s with version %d.%d firmware.", cp
, instance
->version
, instance
->revision
);
2687 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2689 instance
->chan_id
= 8; /* default */
2690 if (instance
->model
== ONCORE_BASIC
|| instance
->model
== ONCORE_PVT6
)
2691 instance
->chan_id
= 6;
2692 else if (instance
->model
== ONCORE_VP
|| instance
->model
== ONCORE_UT
|| instance
->model
== ONCORE_UTPLUS
)
2693 instance
->chan_id
= 8;
2694 else if (instance
->model
== ONCORE_M12
)
2695 instance
->chan_id
= 12;
2697 instance
->traim_id
= 0; /* default */
2698 if (instance
->model
== ONCORE_BASIC
|| instance
->model
== ONCORE_PVT6
)
2699 instance
->traim_id
= 0;
2700 else if (instance
->model
== ONCORE_VP
|| instance
->model
== ONCORE_UT
|| instance
->model
== ONCORE_UTPLUS
)
2701 instance
->traim_id
= 1;
2702 else if (instance
->model
== ONCORE_M12
)
2703 instance
->traim_id
= -1;
2705 sprintf(Msg
, "Channels = %d, TRAIM = %s", instance
->chan_id
,
2706 ((instance
->traim_id
< 0) ? "UNKNOWN" : ((instance
->traim_id
> 0) ? "ON" : "OFF")));
2707 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2712 /* OK, know type of Oncore, have possibly reset it, and have tested it.
2713 * We know the number of channels.
2714 * We will determine whether we have TRAIM before we actually start.
2720 struct instance
*instance
,
2730 /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
2731 * start again if we go from 0D -> 3D, then loses them again when we
2732 * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM.
2733 * For NOW we will turn this aspect of filling SHMEM off for the M12
2736 if (instance
->chan
== 12) {
2737 instance
->shmem_bad_Ea
= 1;
2738 sprintf(Msg
, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance
->version
, instance
->revision
);
2739 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2742 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Cg
, sizeof(oncore_cmd_Cg
)); /* Return to Posn Fix mode */
2743 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bb
, sizeof(oncore_cmd_Bb
)); /* turn on for shmem (6/8/12) */
2744 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ek
, sizeof(oncore_cmd_Ek
)); /* turn off (VP) */
2745 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Aw
, sizeof(oncore_cmd_Aw
)); /* UTC time (6/8/12) */
2746 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_AB
, sizeof(oncore_cmd_AB
)); /* Appl type static (VP) */
2747 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Be
, sizeof(oncore_cmd_Be
)); /* Tell us the Almanac for shmem (6/8/12) */
2748 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bd
, sizeof(oncore_cmd_Bd
)); /* Tell us when Almanac changes */
2750 mode
= instance
->init_type
;
2752 /* If there is Position input in the Config file
2753 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
2754 * or mode = (2,4) set it as INITIAL position, and do Site Survey.
2757 if (instance
->posn_set
) {
2758 record_clock_stats(&(instance
->peer
->srcadr
), "Setting Posn from input data");
2759 oncore_set_posn(instance
); /* this should print posn indirectly thru the As cmd */
2760 } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
2761 if (instance
->chan
!= 12)
2762 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Atx
, sizeof(oncore_cmd_Atx
));
2765 /* cable delay in ns */
2766 memcpy(Cmd
, oncore_cmd_Az
, (size_t) sizeof(oncore_cmd_Az
));
2767 w32_buf(&Cmd
[-2+4], instance
->delay
);
2768 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Az
)); /* 6,8,12 */
2770 /* PPS offset in ns */
2771 if (instance
->offset
) {
2772 memcpy(Cmd
, oncore_cmd_Ay
, (size_t) sizeof(oncore_cmd_Ay
)); /* some have it, some don't */
2773 w32_buf(&Cmd
[-2+4], instance
->offset
); /* will check for hw response */
2774 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Ay
));
2777 /* Satellite mask angle */
2779 if (instance
->Ag
!= 0xff) { /* will have 0xff in it if not set by user */
2780 memcpy(Cmd
, oncore_cmd_Ag
, (size_t) sizeof(oncore_cmd_Ag
));
2781 Cmd
[-2+4] = instance
->Ag
;
2782 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Ag
));
2786 /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
2787 * now we're really running
2788 * these were ALL started in the chan test,
2789 * However, if we had mode=3,4 then commands got turned off, so we turn
2790 * them on again here just in case
2793 if (instance
->chan
== 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
2794 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ea0
, sizeof(oncore_cmd_Ea0
));
2795 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_En0
, sizeof(oncore_cmd_En0
));
2796 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ha0
, sizeof(oncore_cmd_Ha0
));
2797 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Hn0
, sizeof(oncore_cmd_Hn0
));
2798 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ba
, sizeof(oncore_cmd_Ba
));
2799 } else if (instance
->chan
== 8) { /* start 8chan, kill 6,12chan commands */
2800 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ba0
, sizeof(oncore_cmd_Ba0
));
2801 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bn0
, sizeof(oncore_cmd_Bn0
));
2802 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ha0
, sizeof(oncore_cmd_Ha0
));
2803 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Hn0
, sizeof(oncore_cmd_Hn0
));
2804 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ea
, sizeof(oncore_cmd_Ea
));
2805 } else if (instance
->chan
== 12){ /* start 12chan, kill 6,12chan commands */
2806 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ba0
, sizeof(oncore_cmd_Ba0
));
2807 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bn0
, sizeof(oncore_cmd_Bn0
));
2808 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ea0
, sizeof(oncore_cmd_Ea0
));
2809 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_En0
, sizeof(oncore_cmd_En0
));
2810 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ha
, sizeof(oncore_cmd_Ha
));
2813 instance
->count
= 1;
2814 instance
->o_state
= ONCORE_ALMANAC
;
2815 cp
= "state = ONCORE_ALMANAC";
2816 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2821 /* 12chan position */
2825 struct instance
*instance
,
2832 double Lat
, Lon
, Ht
;
2835 lat
= buf_w32(&buf
[4]);
2836 lon
= buf_w32(&buf
[8]);
2837 ht
= buf_w32(&buf
[12]); /* GPS ellipsoid */
2848 sprintf(Msg
, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat
, Lon
, Ht
);
2849 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2851 instance
->ss_lat
= lat
;
2852 instance
->ss_long
= lon
;
2853 instance
->ss_ht
= ht
;
2855 oncore_print_posn(instance
);
2860 /* 12 chan time/date */
2864 struct instance
*instance
,
2869 char Msg
[160], *gmts
;
2870 int mo
, d
, y
, h
, m
, s
, gmth
, gmtm
;
2874 y
= 256*buf
[6]+buf
[7];
2880 gmts
= ((buf
[11] == 0) ? "+" : "-");
2884 sprintf(Msg
, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
2885 d
, Month
[mo
-1], y
, h
, m
, s
, gmts
, gmth
, gmtm
);
2886 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2891 /* Leap Second for M12, gives all info from satellite message */
2892 /* also in UT v3.0 */
2896 struct instance
*instance
,
2904 instance
->saw_Gj
= 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
2906 /* print the message to verify whats there */
2908 dt
= buf
[5] - buf
[4];
2911 sprintf(Msg
, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
2913 buf
[4], buf
[5], 256*buf
[6]+buf
[7], buf
[8], buf
[9], buf
[10],
2914 (buf
[14]+256*(buf
[13]+256*(buf
[12]+256*buf
[11]))),
2915 buf
[15], buf
[16], buf
[17]);
2916 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2919 sprintf(Msg
, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
2921 dt
, buf
[9], Month
[buf
[8]-1], 256*buf
[6]+buf
[7],
2922 buf
[15], buf
[16], buf
[17]);
2923 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
2926 /* Only raise warning within a month of the leap second */
2928 instance
->pp
->leap
= LEAP_NOWARNING
;
2929 cp
= "Set pp.leap to LEAP_NOWARNING";
2931 if (buf
[6] == instance
->BEHa
[6] && buf
[7] == instance
->BEHa
[7] && /* year */
2932 buf
[8] == instance
->BEHa
[4]) { /* month */
2935 instance
->pp
->leap
= LEAP_DELSECOND
;
2936 cp
= "Set pp.leap to LEAP_DELSECOND";
2938 instance
->pp
->leap
= LEAP_ADDSECOND
;
2939 cp
= "Set pp.leap to LEAP_ADDSECOND";
2943 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2948 /* Power on failure */
2952 struct instance
*instance
,
2959 cp
= "Oncore: System Failure at Power On";
2960 if (instance
&& instance
->peer
) {
2961 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
2962 oncore_shutdown(instance
->unit
, instance
->peer
);
2966 /************** Small Subroutines ***************/
2970 oncore_antenna_report(
2971 struct instance
*instance
,
2972 enum antenna_state new_state
)
2976 if (instance
->ant_state
== new_state
)
2979 switch (new_state
) {
2980 case ONCORE_ANTENNA_OK
: cp
= "GPS antenna: OK"; break;
2981 case ONCORE_ANTENNA_OC
: cp
= "GPS antenna: short (overcurrent)"; break;
2982 case ONCORE_ANTENNA_UC
: cp
= "GPS antenna: open (not connected)"; break;
2983 case ONCORE_ANTENNA_NV
: cp
= "GPS antenna: short (no voltage)"; break;
2984 default: cp
= "GPS antenna: ?"; break;
2987 instance
->ant_state
= new_state
;
2988 record_clock_stats(&instance
->peer
->srcadr
, cp
);
2995 struct instance
*instance
3000 /* subroutine oncore_Cj_id has determined the number of channels from the
3001 * model number of the attached oncore. This is not always correct since
3002 * the oncore could have non-standard firmware. Here we check (independently) by
3003 * trying a 6, 8, and 12 chan command, and see which responds.
3004 * Caution: more than one CAN respond.
3006 * This #chan is used by the code rather than that calculated from the model number.
3009 instance
->o_state
= ONCORE_CHECK_CHAN
;
3010 cp
= "state = ONCORE_CHECK_CHAN";
3011 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
3013 instance
->count3
= 1;
3014 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ba
, sizeof(oncore_cmd_Ba
));
3015 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ea
, sizeof(oncore_cmd_Ea
));
3016 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ha
, sizeof(oncore_cmd_Ha
));
3021 /* check for a GOOD Almanac, have we got one yet? */
3024 oncore_check_almanac(
3025 struct instance
*instance
3028 if (instance
->chan
== 6) {
3029 instance
->rsm
.bad_almanac
= instance
->BEHa
[64]&0x1;
3030 instance
->rsm
.bad_fix
= instance
->BEHa
[64]&0x52;
3031 } else if (instance
->chan
== 8) {
3032 instance
->rsm
.bad_almanac
= instance
->BEHa
[72]&0x1;
3033 instance
->rsm
.bad_fix
= instance
->BEHa
[72]&0x52;
3034 } else if (instance
->chan
== 12) {
3035 int bits1
, bits2
, bits3
;
3037 bits1
= (instance
->BEHa
[129]>>5) & 0x7; /* actually Ha */
3038 bits2
= instance
->BEHa
[130];
3039 instance
->rsm
.bad_almanac
= (bits2
& 0x80);
3040 instance
->rsm
.bad_fix
= (bits2
& 0x8) || (bits1
== 0x2);
3041 /* too few sat Bad Geom */
3043 bits3
= instance
->BEHa
[141]; /* UTC parameters */
3044 if (!instance
->count5_set
&& (bits3
& 0xC0)) {
3045 instance
->count5
= 2;
3046 instance
->count5_set
= 1;
3052 sprintf(Msg
, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x\n",
3054 instance
->BEHa
[129], instance
->BEHa
[130], bits1
, bits2
, bits3
, instance
->mode
== MODE_0D
,
3055 instance
->mode
== MODE_2D
, instance
->mode
== MODE_3D
,
3056 instance
->rsm
.bad_almanac
, instance
->rsm
.bad_fix
);
3057 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3065 /* check the antenna for changes (did it get unplugged?) */
3068 oncore_check_antenna(
3069 struct instance
*instance
3072 enum antenna_state antenna
; /* antenna state */
3074 antenna
= instance
->ant_state
;
3075 if (instance
->chan
== 12)
3076 antenna
= (instance
->BEHa
[130] & 0x6 ) >> 1;
3078 antenna
= (instance
->BEHa
[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */
3080 oncore_antenna_report (instance
, antenna
);
3086 * Check the leap second status once per day.
3088 * Note that the ONCORE firmware for the Bj command is wrong at
3090 * It starts advertising a LEAP SECOND as soon as the GPS satellite
3091 * data message (page 18, subframe 4) is updated to a date in the
3092 * future, and does not wait for the month that it will occur.
3093 * The event will usually be advertised several months in advance.
3094 * Since there is a one bit flag, there is no way to tell if it is
3095 * this month, or when...
3097 * As such, we have the workaround below, of only checking for leap
3098 * seconds with the Bj command in June/December.
3100 * The Gj command gives more information, and we can tell in which
3101 * month to apply the correction.
3103 * Note that with the VP we COULD read the raw data message, and
3104 * interpret it ourselves, but since this is specific to this receiver
3105 * only, and the above workaround is adequate, we don't bother.
3109 oncore_check_leap_sec(
3110 struct instance
*instance
3113 if (instance
->Bj_day
!= instance
->BEHa
[5]) { /* do this 1/day */
3114 instance
->Bj_day
= instance
->BEHa
[5];
3116 if (instance
->saw_Gj
< 0) { /* -1 DONT have Gj use Bj */
3117 if ((instance
->BEHa
[4] == 6) || (instance
->BEHa
[4] == 12))
3118 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bj
, sizeof(oncore_cmd_Bj
));
3122 if (instance
->saw_Gj
== 0) /* 0 is dont know if we have Gj */
3123 instance
->count4
= 1;
3125 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gj
, sizeof(oncore_cmd_Gj
));
3129 /* Gj works for some 6/8 chan UT and the M12 */
3130 /* if no response from Gj in 5 sec, we try Bj */
3131 /* which isnt implemented in all the GT/UT either */
3133 if (instance
->count4
) { /* delay, waiting for Gj response */
3134 if (instance
->saw_Gj
== 1)
3135 instance
->count4
= 0;
3136 else if (instance
->count4
++ > 5) { /* delay, waiting for Gj response */
3137 instance
->saw_Gj
= -1; /* didnt see it, will use Bj */
3138 instance
->count4
= 0;
3139 if ((instance
->BEHa
[4] == 6) || (instance
->BEHa
[4] == 12))
3140 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bj
, sizeof(oncore_cmd_Bj
));
3147 /* check the message checksum,
3148 * buf points to START of message ( @@ )
3149 * len is length WITH CR/LF.
3161 for (i
= 2; i
< len
-3; i
++)
3164 return(j
== buf
[len
-3]);
3171 struct instance
*instance
3177 /* Here calculate dH = GPS - MSL for output message */
3178 /* also set Altitude Hold mode if GT */
3180 instance
->have_dH
= 1;
3181 if (instance
->chan
== 12) {
3182 GPS
= buf_w32(&instance
->BEHa
[39]);
3183 MSL
= buf_w32(&instance
->BEHa
[43]);
3185 GPS
= buf_w32(&instance
->BEHa
[23]);
3186 MSL
= buf_w32(&instance
->BEHa
[27]);
3188 instance
->dH
= GPS
- MSL
;
3189 instance
->dH
/= 100.;
3191 /* if MSL is not set, the calculation is meaningless */
3193 if (MSL
) { /* not set ! */
3194 sprintf(Msg
, "dH = (GPS - MSL) = %.2fm", instance
->dH
);
3195 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3202 * try loading Almanac from shmem (where it was copied from shmem_old
3206 oncore_load_almanac(
3207 struct instance
*instance
3210 u_char
*cp
, Cmd
[20];
3215 if (!instance
->shmem
)
3219 for (cp
=instance
->shmem
+4; (n
= 256*(*(cp
-3)) + *(cp
-2)); cp
+=(n
+3)) {
3220 if (!strncmp((char *) cp
, "@@Cb", 4) &&
3221 oncore_checksum_ok(cp
, 33) &&
3222 (*(cp
+4) == 4 || *(cp
+4) == 5)) {
3223 write(instance
->ttyfd
, cp
, n
);
3225 oncore_print_Cb(instance
, cp
);
3230 /************DEBUG************/
3231 for (cp
=instance
->shmem
+4; (n
= 256*(*(cp
-3)) + *(cp
-2)); cp
+=(n
+3)) {
3234 sprintf(Msg
, "See %c%c%c%c %d", *(cp
), *(cp
+1), *(cp
+2), *(cp
+3), *(cp
+4));
3235 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3237 if (!strncmp(cp
, "@@Cb", 4)) {
3238 oncore_print_Cb(instance
, cp
);
3239 if (oncore_checksum_ok(cp
, 33)) {
3240 if (*(cp
+4) == 4 || *(cp
+4) == 5) {
3241 record_clock_stats(&(instance
->peer
->srcadr
), "GOOD SF");
3242 write(instance
->ttyfd
, cp
, n
);
3244 record_clock_stats(&(instance
->peer
->srcadr
), "BAD SF");
3246 record_clock_stats(&(instance
->peer
->srcadr
), "BAD CHECKSUM");
3249 /************DEBUG************/
3252 /* Must load position and time or the Almanac doesn't do us any good */
3254 if (!instance
->posn_set
) { /* if we input a posn use it, else from SHMEM */
3255 record_clock_stats(&(instance
->peer
->srcadr
), "Loading Posn from SHMEM");
3256 for (cp
=instance
->shmem
+4; (n
= 256*(*(cp
-3)) + *(cp
-2)); cp
+=(n
+3)) {
3257 if ((instance
->chan
== 6 && (!strncmp((char *) cp
, "@@Ba", 4) && oncore_checksum_ok(cp
, 68))) ||
3258 (instance
->chan
== 8 && (!strncmp((char *) cp
, "@@Ea", 4) && oncore_checksum_ok(cp
, 76))) ||
3259 (instance
->chan
== 12 && (!strncmp((char *) cp
, "@@Ha", 4) && oncore_checksum_ok(cp
, 154)))) {
3262 instance
->posn_set
= 1;
3263 ii
= buf_w32(cp
+ 15);
3264 jj
= buf_w32(cp
+ 19);
3265 kk
= buf_w32(cp
+ 23);
3269 sprintf(Msg
, "SHMEM posn = %ld (%d, %d, %d)", (long) (cp
-instance
->shmem
), ii
, jj
, kk
);
3270 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3273 if (ii
!= 0 || jj
!= 0 || kk
!= 0) { /* phk asked for this test */
3274 instance
->ss_lat
= ii
;
3275 instance
->ss_long
= jj
;
3276 instance
->ss_ht
= kk
;
3281 oncore_set_posn(instance
);
3283 /* and set time to time from Computer clock */
3287 * XXX NetBSD (@20060729 all variants) defines tv_sec as a long
3288 * -> not SUS standard and doesn't even work within the system
3289 * without kludges like the one below
3293 gettimeofday(&tv
, 0);
3294 help
= tv
.tv_sec
; /* cope with type mismatches */
3300 sprintf(Msg
, "DATE %d %d %d, %d %d %d", 1900+tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
,
3301 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
3302 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3305 if (instance
->chan
== 12) {
3306 memcpy(Cmd
, oncore_cmd_Gb
, (size_t) sizeof(oncore_cmd_Gb
));
3307 Cmd
[-2+4] = tm
->tm_mon
+ 1;
3308 Cmd
[-2+5] = tm
->tm_mday
;
3309 Cmd
[-2+6] = (1900+tm
->tm_year
)/256;
3310 Cmd
[-2+7] = (1900+tm
->tm_year
)%256;
3311 Cmd
[-2+8] = tm
->tm_hour
;
3312 Cmd
[-2+9] = tm
->tm_min
;
3313 Cmd
[-2+10] = tm
->tm_sec
;
3317 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Gb
));
3319 /* First set GMT offset to zero */
3321 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ab
, sizeof(oncore_cmd_Ab
));
3323 memcpy(Cmd
, oncore_cmd_Ac
, (size_t) sizeof(oncore_cmd_Ac
));
3324 Cmd
[-2+4] = tm
->tm_mon
+ 1;
3325 Cmd
[-2+5] = tm
->tm_mday
;
3326 Cmd
[-2+6] = (1900+tm
->tm_year
)/256;
3327 Cmd
[-2+7] = (1900+tm
->tm_year
)%256;
3328 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Ac
));
3330 memcpy(Cmd
, oncore_cmd_Aa
, (size_t) sizeof(oncore_cmd_Aa
));
3331 Cmd
[-2+4] = tm
->tm_hour
;
3332 Cmd
[-2+5] = tm
->tm_min
;
3333 Cmd
[-2+6] = tm
->tm_sec
;
3334 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Aa
));
3337 record_clock_stats(&(instance
->peer
->srcadr
), "Setting Posn and Time after Loading Almanac");
3342 /* Almanac data input */
3346 struct instance
*instance
,
3354 printf("DEBUG: See: %c%c%c%c\n", *(cp
), *(cp
+1), *(cp
+2), *(cp
+3));
3355 printf("DEBUG: Cb: [%d,%d]", *(cp
+4), *(cp
+5));
3356 for(ii
=0; ii
<33; ii
++)
3357 printf(" %d", *(cp
+ii
));
3360 sprintf(Msg
, "Debug: Cb: [%d,%d]", *(cp
+4), *(cp
+5));
3361 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3378 for (j
=0; j
<jj
; j
++) {
3379 printf("%4d: ", nn
);
3381 for (i
=0; i
<16; i
++)
3382 printf(" %o", *cp
++);
3391 struct instance
*instance
3394 char Msg
[120], ew
, ns
;
3395 double xd
, xm
, xs
, yd
, ym
, ys
, hm
, hft
;
3396 int idx
, idy
, is
, imx
, imy
;
3399 record_clock_stats(&(instance
->peer
->srcadr
), "Posn:");
3401 lon
= instance
->ss_long
;
3408 lat
= instance
->ss_lat
;
3414 hm
= instance
->ss_ht
/100.;
3417 xd
= lat
/3600000.; /* lat, lon in int msec arc, ht in cm. */
3419 sprintf(Msg
, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns
, xd
, ew
, yd
, hm
, hft
);
3420 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3429 "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns
, idx
, xm
, ew
, idy
, ym
, hm
, hft
);
3430 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3439 "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
);
3440 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3446 * write message to Oncore.
3460 printf("ONCORE: Send @@%c%c %d\n", ptr
[0], ptr
[1], (int) len
);
3462 write(fd
, "@@", (size_t) 2);
3463 write(fd
, ptr
, len
);
3466 write(fd
, &cs
, (size_t) 1);
3467 write(fd
, "\r\n", (size_t) 2);
3474 struct instance
*instance
3480 /* Turn OFF position hold, it needs to be off to set position (for some units),
3481 will get set ON in @@Ea later */
3483 if (instance
->chan
== 12)
3484 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gd0
, sizeof(oncore_cmd_Gd0
)); /* (12) */
3486 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_At0
, sizeof(oncore_cmd_At0
)); /* (6/8) */
3487 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Av0
, sizeof(oncore_cmd_Av0
)); /* (6/8) */
3490 mode
= instance
->init_type
;
3492 if (mode
!= 0) { /* first set posn hold position */
3493 memcpy(Cmd
, oncore_cmd_As
, (size_t) sizeof(oncore_cmd_As
)); /* don't modify static variables */
3494 w32_buf(&Cmd
[-2+4], (int) instance
->ss_lat
);
3495 w32_buf(&Cmd
[-2+8], (int) instance
->ss_long
);
3496 w32_buf(&Cmd
[-2+12], (int) instance
->ss_ht
);
3498 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_As
)); /* posn hold 3D posn (6/8/12) */
3500 memcpy(Cmd
, oncore_cmd_Au
, (size_t) sizeof(oncore_cmd_Au
));
3501 w32_buf(&Cmd
[-2+4], (int) instance
->ss_ht
);
3503 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Au
)); /* altitude hold (6/8/12 not UT, M12T) */
3505 /* next set current position */
3507 if (instance
->chan
== 12) {
3508 memcpy(Cmd
, oncore_cmd_Ga
, (size_t) sizeof(oncore_cmd_Ga
));
3509 w32_buf(&Cmd
[-2+4], (int) instance
->ss_lat
);
3510 w32_buf(&Cmd
[-2+8], (int) instance
->ss_long
);
3511 w32_buf(&Cmd
[-2+12],(int) instance
->ss_ht
);
3513 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Ga
)); /* 3d posn (12) */
3515 memcpy(Cmd
, oncore_cmd_Ad
, (size_t) sizeof(oncore_cmd_Ad
));
3516 w32_buf(&Cmd
[-2+4], (int) instance
->ss_lat
);
3517 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Ad
)); /* lat (6/8) */
3519 memcpy(Cmd
, oncore_cmd_Ae
, (size_t) sizeof(oncore_cmd_Ae
));
3520 w32_buf(&Cmd
[-2+4], (int) instance
->ss_long
);
3521 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Ae
)); /* long (6/8) */
3523 memcpy(Cmd
, oncore_cmd_Af
, (size_t) sizeof(oncore_cmd_Af
));
3524 w32_buf(&Cmd
[-2+4], (int) instance
->ss_ht
);
3526 oncore_sendmsg(instance
->ttyfd
, Cmd
, sizeof(oncore_cmd_Af
)); /* ht (6/8) */
3529 /* Finally, turn on position hold */
3531 if (instance
->chan
== 12)
3532 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gd1
, sizeof(oncore_cmd_Gd1
));
3534 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_At1
, sizeof(oncore_cmd_At1
));
3542 struct instance
*instance
3547 if (instance
->traim_in
!= -1) /* set in Input */
3548 instance
->traim
= instance
->traim_in
;
3550 instance
->traim
= instance
->traim_ck
;
3552 sprintf(Msg
, "Input says TRAIM = %d", instance
->traim_in
);
3553 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3554 sprintf(Msg
, "Model # says TRAIM = %d", instance
->traim_id
);
3555 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3556 sprintf(Msg
, "Testing says TRAIM = %d", instance
->traim_ck
);
3557 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3558 sprintf(Msg
, "Using TRAIM = %d", instance
->traim
);
3559 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3561 if (instance
->traim_ck
== 1 && instance
->traim
== 0) {
3562 /* if it should be off, and I turned it on during testing,
3563 then turn it off again */
3564 if (instance
->chan
== 6)
3565 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bnx
, sizeof(oncore_cmd_Bnx
));
3566 else if (instance
->chan
== 8)
3567 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Enx
, sizeof(oncore_cmd_Enx
));
3568 else /* chan == 12 */
3569 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ge0
, sizeof(oncore_cmd_Ge0
));
3570 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Hn0
, sizeof(oncore_cmd_Hn0
));
3577 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
3581 oncore_shmem_get_3D(
3582 struct instance
*instance
3585 if (instance
->pp
->second
%15 == 3) { /* start the sequence */ /* by changing mode */
3586 instance
->shmem_reset
= 1;
3587 if (instance
->chan
== 12) {
3588 if (instance
->shmem_Posn
== 2)
3589 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gd2
, sizeof(oncore_cmd_Gd2
)); /* 2D */
3591 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gd0
, sizeof(oncore_cmd_Gd0
)); /* 3D */
3593 if (instance
->saw_At
) { /* out of 0D -> 3D mode */
3594 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_At0
, sizeof(oncore_cmd_At0
));
3595 if (instance
->shmem_Posn
== 2) /* 3D -> 2D mode */
3596 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Av1
, sizeof(oncore_cmd_Av1
));
3598 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Av0
, sizeof(oncore_cmd_Av0
));
3600 } else if (instance
->shmem_reset
|| (instance
->mode
!= MODE_0D
)) {
3601 instance
->shmem_reset
= 0;
3602 if (instance
->chan
== 12)
3603 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gd1
, sizeof(oncore_cmd_Gd1
)); /* 0D */
3605 if (instance
->saw_At
) {
3606 if (instance
->mode
== MODE_2D
) /* 2D -> 3D or 0D mode */
3607 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Av0
, sizeof(oncore_cmd_Av0
));
3608 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_At1
, sizeof(oncore_cmd_At1
)); /* to 0D mode */
3610 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Av1
, sizeof(oncore_cmd_Av1
));
3618 * Here we do the Software SiteSurvey.
3619 * We have to average our own position for the Position Hold Mode
3620 * We use Heights from the GPS ellipsoid.
3621 * We check for the END of either HW or SW SiteSurvey.
3626 struct instance
*instance
3630 double lat
, lon
, ht
;
3633 if (instance
->site_survey
== ONCORE_SS_HW
) {
3635 * Check to see if Hardware SiteSurvey has Finished.
3638 if ((instance
->chan
== 8 && !(instance
->BEHa
[37] & 0x20)) ||
3639 (instance
->chan
== 12 && !(instance
->BEHa
[130] & 0x10))) {
3640 record_clock_stats(&(instance
->peer
->srcadr
), "Now in 0D mode");
3642 if (instance
->chan
== 12)
3643 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gax
, sizeof(oncore_cmd_Gax
));
3645 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Asx
, sizeof(oncore_cmd_Asx
));
3647 cp
= "SSstate = ONCORE_SS_DONE";
3648 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
3649 instance
->site_survey
= ONCORE_SS_DONE
;
3653 * Must be a Software Site Survey.
3656 if (instance
->rsm
.bad_fix
) /* Not if poor geometry or less than 3 sats */
3659 if (instance
->mode
!= MODE_3D
) /* Use only 3D Fixes */
3662 instance
->ss_lat
+= buf_w32(&instance
->BEHa
[15]);
3663 instance
->ss_long
+= buf_w32(&instance
->BEHa
[19]);
3664 instance
->ss_ht
+= buf_w32(&instance
->BEHa
[23]); /* GPS ellipsoid */
3665 instance
->ss_count
++;
3667 if (instance
->ss_count
!= POS_HOLD_AVERAGE
)
3670 instance
->ss_lat
/= POS_HOLD_AVERAGE
;
3671 instance
->ss_long
/= POS_HOLD_AVERAGE
;
3672 instance
->ss_ht
/= POS_HOLD_AVERAGE
;
3674 sprintf(Msg
, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
3675 instance
->ss_lat
, instance
->ss_long
, instance
->ss_ht
);
3676 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3677 lat
= instance
->ss_lat
/3600000.;
3678 lon
= instance
->ss_long
/3600000.;
3679 ht
= instance
->ss_ht
/100;
3680 sprintf(Msg
, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
3682 record_clock_stats(&(instance
->peer
->srcadr
), Msg
);
3684 oncore_set_posn(instance
);
3686 record_clock_stats(&(instance
->peer
->srcadr
), "Now in 0D mode");
3688 cp
= "SSstate = ONCORE_SS_DONE";
3689 record_clock_stats(&(instance
->peer
->srcadr
), cp
);
3690 instance
->site_survey
= ONCORE_SS_DONE
;
3697 oncore_wait_almanac(
3698 struct instance
*instance
3701 if (instance
->rsm
.bad_almanac
) {
3704 printf("ONCORE[%d]: waiting for almanac\n", instance
->unit
);
3708 * If we get here (first time) then we don't have an almanac in memory.
3709 * Check if we have a SHMEM, and if so try to load whatever is there.
3712 if (!instance
->almanac_from_shmem
) {
3713 instance
->almanac_from_shmem
= 1;
3714 oncore_load_almanac(instance
);
3717 } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
3718 commands, and can finally check for TRAIM. Again, we set a delay
3719 (5sec) and wait for things to settle down */
3721 if (instance
->chan
== 6)
3722 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Bn
, sizeof(oncore_cmd_Bn
));
3723 else if (instance
->chan
== 8)
3724 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_En
, sizeof(oncore_cmd_En
));
3725 else if (instance
->chan
== 12) {
3726 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Gc
, sizeof(oncore_cmd_Gc
)); /* 1PPS on, continuous */
3727 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Ge
, sizeof(oncore_cmd_Ge
)); /* TRAIM on */
3728 oncore_sendmsg(instance
->ttyfd
, oncore_cmd_Hn
, sizeof(oncore_cmd_Hn
)); /* TRAIM status 1/s */
3730 instance
->traim_delay
= 1;
3732 record_clock_stats(&(instance
->peer
->srcadr
), "Have now loaded an ALMANAC");
3734 instance
->o_state
= ONCORE_RUN
;
3735 record_clock_stats(&(instance
->peer
->srcadr
), "state = ONCORE_RUN");
3743 int refclock_oncore_bs
;
3744 #endif /* REFCLOCK */