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