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(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 read(fd, shmem_old, shmem_old_size);
959 }
960 close(fd);
961 }
962
963 /* OK, we now create the NEW SHMEM. */
964
965 if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
966 oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem");
967 if (shmem_old)
968 free(shmem_old);
969
970 return;
971 }
972
973 /* see how big it needs to be */
974
975 n = 1;
976 for (mp=oncore_messages; mp->flag[0]; mp++) {
977 mp->shmem = n;
978 /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
979 if (!strcmp(mp->flag, "Cb")) {
980 instance->shmem_Cb = n;
981 n += (mp->len + 3) * 34;
982 }
983 if (!strcmp(mp->flag, "Ba")) {
984 instance->shmem_Ba = n;
985 n += (mp->len + 3) * 3;
986 }
987 if (!strcmp(mp->flag, "Ea")) {
988 instance->shmem_Ea = n;
989 n += (mp->len + 3) * 3;
990 }
991 if (!strcmp(mp->flag, "Ha")) {
992 instance->shmem_Ha = n;
993 n += (mp->len + 3) * 3;
994 }
995 n += (mp->len + 3);
996 }
997 shmem_length = n + 2;
998
999 buf = emalloc(shmem_length);
1000 memset(buf, 0, shmem_length);
1001
1002 /* next build the new SHMEM buffer in memory */
1003
1004 for (mp=oncore_messages; mp->flag[0]; mp++) {
1005 l = mp->shmem;
1006 buf[l + 0] = mp->len >> 8;
1007 buf[l + 1] = mp->len & 0xff;
1008 buf[l + 2] = 0;
1009 buf[l + 3] = '@';
1010 buf[l + 4] = '@';
1011 buf[l + 5] = mp->flag[0];
1012 buf[l + 6] = mp->flag[1];
1013 if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
1014 if (!strcmp(mp->flag, "Cb"))
1015 n = 35;
1016 else
1017 n = 4;
1018 for (i=1; i<n; i++) {
1019 buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
1020 buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
1021 buf[l + i * (mp->len+3) + 2] = 0;
1022 buf[l + i * (mp->len+3) + 3] = '@';
1023 buf[l + i * (mp->len+3) + 4] = '@';
1024 buf[l + i * (mp->len+3) + 5] = mp->flag[0];
1025 buf[l + i * (mp->len+3) + 6] = mp->flag[1];
1026 }
1027 }
1028 }
1029
1030 /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
1031 * copying the data in shmem_old to buf.
1032 * When we are done we write it out and free both buffers.
1033 * If the structure sizes dont agree, I will not copy.
1034 * This could be due to an addition/deletion or a problem with the disk file.
1035 */
1036
1037 if (shmem_old) {
1038 if (shmem_old_size == shmem_length) {
1039 for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) {
1040 n1 = 256*(*(cp1-3)) + *(cp1-2);
1041 if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
1042 break;
1043
1044 memcpy(cp, cp1, (size_t) n);
1045 }
1046 }
1047 free(shmem_old);
1048 }
1049
1050 i = write(instance->shmemfd, buf, shmem_length);
1051 free(buf);
1052
1053 if (i != shmem_length) {
1054 oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem");
1055 close(instance->shmemfd);
1056 return;
1057 }
1058
1059 instance->shmem = (u_char *) mmap(0, shmem_length,
1060 PROT_READ | PROT_WRITE,
1061 #ifdef MAP_HASSEMAPHORE
1062 MAP_HASSEMAPHORE |
1063 #endif
1064 MAP_SHARED, instance->shmemfd, (off_t)0);
1065
1066 if (instance->shmem == (u_char *)MAP_FAILED) {
1067 instance->shmem = 0;
1068 close(instance->shmemfd);
1069 return;
1070 }
1071
1072 oncore_log_f(instance, LOG_NOTICE,
1073 "SHMEM (size = %ld) is CONFIGURED and available as %s",
1074 (u_long) shmem_length, instance->shmem_fname);
1075 }
1076 #endif /* ONCORE_SHMEM_STATUS */
1077
1078
1079
1080 /*
1081 * Read Input file if it exists.
1082 */
1083
1084 static void
oncore_read_config(struct instance * instance)1085 oncore_read_config(
1086 struct instance *instance
1087 )
1088 {
1089 /*
1090 * First we try to open the configuration file
1091 * /etc/ntp.oncore.N
1092 * where N is the unit number viz 127.127.30.N.
1093 * If we don't find it we try
1094 * /etc/ntp.oncoreN
1095 * and then
1096 * /etc/ntp.oncore
1097 *
1098 * If we don't find any then we don't have the cable delay or PPS offset
1099 * and we choose MODE (4) below.
1100 *
1101 * Five Choices for MODE
1102 * (0) ONCORE is preinitialized, don't do anything to change it.
1103 * nb, DON'T set 0D mode, DON'T set Delay, position...
1104 * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1105 * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
1106 * lock this in, go to 0D mode.
1107 * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1108 * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
1109 * lock this in, go to 0D mode.
1110 * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
1111 * then this position is set as the INITIAL position of the ONCORE.
1112 * This can reduce the time to first fix.
1113 * -------------------------------------------------------------------------------
1114 * Note that an Oncore UT without a battery backup retains NO information if it is
1115 * power cycled, with a Battery Backup it remembers the almanac, etc.
1116 * For an Oncore VP, there is an eeprom that will contain this data, along with the
1117 * option of Battery Backup.
1118 * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
1119 * power cycle, since there is nowhere to store the data.
1120 * -------------------------------------------------------------------------------
1121 *
1122 * If we open one or the other of the files, we read it looking for
1123 * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
1124 * STATUS, POSN3D, POSN2D, CHAN, TRAIM
1125 * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must
1126 * be present or mode reverts to (2,4).
1127 *
1128 * Read input file.
1129 *
1130 * # is comment to end of line
1131 * = allowed between 1st and 2nd fields.
1132 *
1133 * Expect to see one line with 'MODE' as first field, followed by an integer
1134 * in the range 0-4 (default = 4).
1135 *
1136 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
1137 * All numbers are floating point.
1138 * DDD.ddd
1139 * DDD MMM.mmm
1140 * DDD MMM SSS.sss
1141 *
1142 * Expect to see one line with 'HT' as first field,
1143 * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'
1144 * for feet or meters. HT is the height above the GPS ellipsoid.
1145 * If the receiver reports height in both GPS and MSL, then we will report
1146 * the difference GPS-MSL on the clockstats file.
1147 *
1148 * There is an optional line, starting with DELAY, followed
1149 * by 1 or two fields. The first is a number (a time) the second is
1150 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1151 * DELAY is cable delay, typically a few tens of ns.
1152 *
1153 * There is an optional line, starting with OFFSET, followed
1154 * by 1 or two fields. The first is a number (a time) the second is
1155 * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1156 * OFFSET is the offset of the PPS pulse from 0. (only fully implemented
1157 * with the PPSAPI, we need to be able to tell the Kernel about this
1158 * offset if the Kernel PLL is in use, but can only do this presently
1159 * when using the PPSAPI interface. If not using the Kernel PLL,
1160 * then there is no problem.
1161 *
1162 * There is an optional line, with either ASSERT or CLEAR on it, which
1163 * determine which transition of the PPS signal is used for timing by the
1164 * PPSAPI. If neither is present, then ASSERT is assumed.
1165 * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
1166 * For Flag2, ASSERT=0, and hence is default.
1167 *
1168 * There is an optional line, with HARDPPS on it. Including this line causes
1169 * the PPS signal to control the kernel PLL.
1170 * HARDPPS can also be set with FLAG3 of the ntp.conf input.
1171 * For Flag3, 0 is disabled, and the default.
1172 *
1173 * There are three options that have to do with using the shared memory option.
1174 * First, to enable the option there must be a SHMEM line with a file name.
1175 * The file name is the file associated with the shared memory.
1176 *
1177 * In shared memory, there is one 'record' for each returned variable.
1178 * For the @@Ea data there are three 'records' containing position data.
1179 * There will always be data in the record corresponding to the '0D' @@Ea record,
1180 * and the user has a choice of filling the '3D' record by specifying POSN3D,
1181 * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D'
1182 * record is filled once every 15s.
1183 *
1184 * Two additional variables that can be set are CHAN and TRAIM. These should be
1185 * set correctly by the code examining the @@Cj record, but we bring them out here
1186 * to allow the user to override either the # of channels, or the existence of TRAIM.
1187 * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
1188 * followed by YES or NO.
1189 *
1190 * There is an optional line with MASK on it followed by one integer field in the
1191 * range 0 to 89. This sets the satellite mask angle and will determine the minimum
1192 * elevation angle for satellites to be tracked by the receiver. The default value
1193 * is 10 deg for the VP and 0 deg for all other receivers.
1194 *
1195 * There is an optional line with PPSCONTROL on it (only valid for M12 or M12+T
1196 * receivers, the option is read, but ignored for all others)
1197 * and it is followed by:
1198 * ON Turn PPS on. This is the default and the default for other
1199 * oncore receivers. The PPS is on even if not tracking
1200 * any satellites.
1201 * SATELLITE Turns PPS on if tracking at least 1 satellite, else off.
1202 * TRAIM Turns PPS on or off controlled by TRAIM.
1203 * The OFF option is NOT implemented, since the Oncore driver will not work
1204 * without the PPS signal.
1205 *
1206 * So acceptable input would be
1207 * # these are my coordinates (RWC)
1208 * LON -106 34.610
1209 * LAT 35 08.999
1210 * HT 1589 # could equally well say HT 5215 FT
1211 * DELAY 60 ns
1212 */
1213
1214 FILE *fd;
1215 char *cc, *ca, line[100], units[2], device[64];
1216 const char *dirs[] = { "/etc/ntp", "/etc", 0 };
1217 const char *cp, **cpp;
1218 int i, sign, lat_flg, long_flg, ht_flg, mode, mask;
1219 double f1, f2, f3;
1220
1221 fd = NULL; /* just to shutup gcc complaint */
1222 for (cpp=dirs; *cpp; cpp++) {
1223 cp = *cpp;
1224 snprintf(device, sizeof(device), "%s/ntp.oncore.%d",
1225 cp, instance->unit); /* try "ntp.oncore.0 */
1226 if ((fd=fopen(device, "r")))
1227 break;
1228 snprintf(device, sizeof(device), "%s/ntp.oncore%d",
1229 cp, instance->unit); /* try "ntp.oncore0" */
1230 if ((fd=fopen(device, "r")))
1231 break;
1232 snprintf(device, sizeof(device), "%s/ntp.oncore", cp);
1233 if ((fd=fopen(device, "r"))) /* last try "ntp.oncore" */
1234 break;
1235 }
1236
1237 if (!fd) { /* no inputfile, default to the works ... */
1238 instance->init_type = 4;
1239 return;
1240 }
1241
1242 mode = mask = 0;
1243 lat_flg = long_flg = ht_flg = 0;
1244 while (fgets(line, 100, fd)) {
1245 char *cpw;
1246
1247 /* Remove comments */
1248 if ((cpw = strchr(line, '#')))
1249 *cpw = '\0';
1250
1251 /* Remove trailing space */
1252 for (i = strlen(line);
1253 i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]);
1254 )
1255 line[--i] = '\0';
1256
1257 /* Remove leading space */
1258 for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++)
1259 continue;
1260
1261 /* Stop if nothing left */
1262 if (!*cc)
1263 continue;
1264
1265 /* Uppercase the command and find the arg */
1266 for (ca = cc; *ca; ca++) {
1267 if (isascii((unsigned char)*ca)) {
1268 if (islower((unsigned char)*ca)) {
1269 *ca = toupper((unsigned char)*ca);
1270 } else if (isspace((unsigned char)*ca) || (*ca == '='))
1271 break;
1272 }
1273 }
1274
1275 /* Remove space (and possible =) leading the arg */
1276 for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++)
1277 continue;
1278
1279 if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
1280 instance->shmem_fname = estrdup(ca);
1281 continue;
1282 }
1283
1284 /* Uppercase argument as well */
1285 for (cpw = ca; *cpw; cpw++)
1286 if (isascii((unsigned char)*cpw) && islower((unsigned char)*cpw))
1287 *cpw = toupper((unsigned char)*cpw);
1288
1289 if (!strncmp(cc, "LAT", (size_t) 3)) {
1290 f1 = f2 = f3 = 0;
1291 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1292 sign = 1;
1293 if (f1 < 0) {
1294 f1 = -f1;
1295 sign = -1;
1296 }
1297 instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1298 lat_flg++;
1299 } else if (!strncmp(cc, "LON", (size_t) 3)) {
1300 f1 = f2 = f3 = 0;
1301 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1302 sign = 1;
1303 if (f1 < 0) {
1304 f1 = -f1;
1305 sign = -1;
1306 }
1307 instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1308 long_flg++;
1309 } else if (!strncmp(cc, "HT", (size_t) 2)) {
1310 f1 = 0;
1311 units[0] = '\0';
1312 sscanf(ca, "%lf %1s", &f1, units);
1313 if (units[0] == 'F')
1314 f1 = 0.3048 * f1;
1315 instance->ss_ht = 100 * f1; /* cm */
1316 ht_flg++;
1317 } else if (!strncmp(cc, "DELAY", (size_t) 5)) {
1318 f1 = 0;
1319 units[0] = '\0';
1320 sscanf(ca, "%lf %1s", &f1, units);
1321 if (units[0] == 'N')
1322 ;
1323 else if (units[0] == 'U')
1324 f1 = 1000 * f1;
1325 else if (units[0] == 'M')
1326 f1 = 1000000 * f1;
1327 else
1328 f1 = 1000000000 * f1;
1329 if (f1 < 0 || f1 > 1.e9)
1330 f1 = 0;
1331 if (f1 < 0 || f1 > 999999)
1332 oncore_log_f(instance, LOG_WARNING,
1333 "PPS Cable delay of %fns out of Range, ignored",
1334 f1);
1335 else
1336 instance->delay = f1; /* delay in ns */
1337 } else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
1338 f1 = 0;
1339 units[0] = '\0';
1340 sscanf(ca, "%lf %1s", &f1, units);
1341 if (units[0] == 'N')
1342 ;
1343 else if (units[0] == 'U')
1344 f1 = 1000 * f1;
1345 else if (units[0] == 'M')
1346 f1 = 1000000 * f1;
1347 else
1348 f1 = 1000000000 * f1;
1349 if (f1 < 0 || f1 > 1.e9)
1350 f1 = 0;
1351 if (f1 < 0 || f1 > 999999999.)
1352 oncore_log_f(instance, LOG_WARNING,
1353 "PPS Offset of %fns out of Range, ignored",
1354 f1);
1355 else
1356 instance->offset = f1; /* offset in ns */
1357 } else if (!strncmp(cc, "MODE", (size_t) 4)) {
1358 sscanf(ca, "%d", &mode);
1359 if (mode < 0 || mode > 4)
1360 mode = 4;
1361 } else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
1362 instance->assert = 1;
1363 } else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
1364 instance->assert = 0;
1365 } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
1366 instance->hardpps = 1;
1367 } else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
1368 instance->shmem_Posn = 2;
1369 } else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
1370 instance->shmem_Posn = 3;
1371 } else if (!strncmp(cc, "CHAN", (size_t) 4)) {
1372 sscanf(ca, "%d", &i);
1373 if ((i == 6) || (i == 8) || (i == 12))
1374 instance->chan_in = i;
1375 } else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
1376 instance->traim_in = 1; /* so TRAIM alone is YES */
1377 if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */
1378 instance->traim_in = 0;
1379 } else if (!strncmp(cc, "MASK", (size_t) 4)) {
1380 sscanf(ca, "%d", &mask);
1381 if (mask > -1 && mask < 90)
1382 instance->Ag = mask; /* Satellite mask angle */
1383 } else if (!strncmp(cc,"PPSCONTROL",10)) { /* pps control M12 only */
1384 if (!strcmp(ca,"ON") || !strcmp(ca, "CONTINUOUS")) {
1385 instance->pps_control = 1; /* PPS always on */
1386 } else if (!strcmp(ca,"SATELLITE")) {
1387 instance->pps_control = 2; /* PPS on when satellite is available */
1388 } else if (!strcmp(ca,"TRAIM")) {
1389 instance->pps_control = 3; /* PPS on when TRAIM status is OK */
1390 } else {
1391 oncore_log_f(instance, LOG_WARNING,
1392 "Unknown value \"%s\" for PPSCONTROL, ignored",
1393 cc);
1394 }
1395 }
1396 }
1397 fclose(fd);
1398
1399 /*
1400 * OK, have read all of data file, and extracted the good stuff.
1401 * If lat/long/ht specified they ALL must be specified for mode = (1,3).
1402 */
1403
1404 instance->posn_set = 1;
1405 if (!( lat_flg && long_flg && ht_flg )) {
1406 oncore_log_f(instance, LOG_WARNING,
1407 "ONCORE: incomplete data on %s", device);
1408 instance->posn_set = 0;
1409 if (mode == 1 || mode == 3) {
1410 oncore_log_f(instance, LOG_WARNING,
1411 "Input Mode = %d, but no/incomplete position, mode set to %d",
1412 mode, mode+1);
1413 mode++;
1414 }
1415 }
1416 instance->init_type = mode;
1417
1418 oncore_log_f(instance, LOG_INFO, "Input mode = %d", mode);
1419 }
1420
1421
1422
1423 /*
1424 * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
1425 */
1426
1427 static void
oncore_receive(struct recvbuf * rbufp)1428 oncore_receive(
1429 struct recvbuf *rbufp
1430 )
1431 {
1432 size_t i;
1433 u_char *p;
1434 struct peer *peer;
1435 struct instance *instance;
1436
1437 peer = rbufp->recv_peer;
1438 instance = peer->procptr->unitptr;
1439 p = (u_char *) &rbufp->recv_space;
1440
1441 #ifdef ONCORE_VERBOSE_RECEIVE
1442 if (debug > 4) {
1443 int i;
1444 char Msg[120], Msg2[10];
1445
1446 oncore_log_f(instance, LOG_DEBUG,
1447 ">>> %d bytes available",
1448 rbufp->recv_length);
1449 strlcpy(Msg, ">>>", sizeof(Msg));
1450 for (i = 0; i < rbufp->recv_length; i++) {
1451 snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]);
1452 strlcat(Msg, Msg2, sizeof(Msg));
1453 }
1454 oncore_log(instance, LOG_DEBUG, Msg);
1455
1456 strlcpy(Msg, ">>>", sizeof(Msg));
1457 for (i = 0; i < rbufp->recv_length; i++) {
1458 snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]);
1459 strlcat(Msg, Msg2, sizeof(Msg));
1460 }
1461 oncore_log(instance, LOG_DEBUG, Msg);
1462 }
1463 #endif
1464
1465 i = rbufp->recv_length;
1466 if ((size_t)rcvptr + i >= sizeof(rcvbuf))
1467 i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */
1468 memcpy(rcvbuf+rcvptr, p, i);
1469 rcvptr += i;
1470 oncore_consume(instance);
1471 }
1472
1473
1474
1475 /*
1476 * Deal with any complete messages
1477 */
1478
1479 static void
oncore_consume(struct instance * instance)1480 oncore_consume(
1481 struct instance *instance
1482 )
1483 {
1484 unsigned i, m, l;
1485
1486 while (rcvptr >= 7) {
1487 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1488 /* We're not in sync, lets try to get there */
1489 for (i=1; i < rcvptr-1; i++)
1490 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1491 break;
1492 #ifdef ONCORE_VERBOSE_CONSUME
1493 if (debug > 4)
1494 oncore_log_f(instance, LOG_DEBUG,
1495 ">>> skipping %d chars",
1496 i);
1497 #endif
1498 if (i != rcvptr)
1499 memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1500 rcvptr -= i;
1501 continue;
1502 }
1503
1504 /* Ok, we have a header now */
1505 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1506 for(m=0; m<l; m++)
1507 if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1508 break;
1509 if (m == l) {
1510 #ifdef ONCORE_VERBOSE_CONSUME
1511 if (debug > 4)
1512 oncore_log_f(instance, LOG_DEBUG,
1513 ">>> Unknown MSG, skipping 4 (%c%c)",
1514 rcvbuf[2], rcvbuf[3]);
1515 #endif
1516 memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1517 rcvptr -= 4;
1518 continue;
1519 }
1520
1521 l = oncore_messages[m].len;
1522 #ifdef ONCORE_VERBOSE_CONSUME
1523 if (debug > 3)
1524 oncore_log_f(instance, LOG_DEBUG,
1525 "GOT: %c%c %d of %d entry %d",
1526 instance->unit, rcvbuf[2],
1527 rcvbuf[3], rcvptr, l, m);
1528 #endif
1529 /* Got the entire message ? */
1530
1531 if (rcvptr < l)
1532 return;
1533
1534 /* are we at the end of message? should be <Cksum><CR><LF> */
1535
1536 if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1537 #ifdef ONCORE_VERBOSE_CONSUME
1538 if (debug)
1539 oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message");
1540 #endif
1541 } else { /* check the CheckSum */
1542 if (oncore_checksum_ok(rcvbuf, l)) {
1543 if (instance->shmem != NULL) {
1544 instance->shmem[oncore_messages[m].shmem + 2]++;
1545 memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1546 rcvbuf, (size_t) l);
1547 }
1548 oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1549 if (oncore_messages[m].handler)
1550 oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1551 }
1552 #ifdef ONCORE_VERBOSE_CONSUME
1553 else if (debug) {
1554 char Msg[120], Msg2[10];
1555
1556 oncore_log(instance, LOG_ERR, "Checksum mismatch!");
1557 snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]);
1558 for (i = 4; i < l; i++) {
1559 snprintf(Msg2, sizeof(Msg2),
1560 "%03o ", rcvbuf[i]);
1561 strlcat(Msg, Msg2, sizeof(Msg));
1562 }
1563 oncore_log(instance, LOG_DEBUG, Msg);
1564 }
1565 #endif
1566 }
1567
1568 if (l != rcvptr)
1569 memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1570 rcvptr -= l;
1571 }
1572 }
1573
1574
1575
1576 static void
oncore_get_timestamp(struct instance * instance,long dt1,long dt2)1577 oncore_get_timestamp(
1578 struct instance *instance,
1579 long dt1, /* tick offset THIS time step */
1580 long dt2 /* tick offset NEXT time step */
1581 )
1582 {
1583 int Rsm;
1584 u_long j;
1585 l_fp ts, ts_tmp;
1586 double dmy;
1587 #ifdef HAVE_STRUCT_TIMESPEC
1588 struct timespec *tsp = 0;
1589 #else
1590 struct timeval *tsp = 0;
1591 #endif
1592 int current_mode;
1593 pps_params_t current_params;
1594 struct timespec timeout;
1595 struct peer *peer;
1596 pps_info_t pps_i;
1597 char Msg[160];
1598
1599 peer = instance->peer;
1600
1601 #if 1
1602 /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
1603 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
1604 * times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
1605 * This gives good time, which gets better when the SS is done.
1606 */
1607
1608 if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) {
1609 #else
1610 /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
1611
1612 if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) {
1613 #endif
1614 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1615 return;
1616 }
1617
1618 /* Don't do anything without an almanac to define the GPS->UTC delta */
1619
1620 if (instance->rsm.bad_almanac) {
1621 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1622 return;
1623 }
1624
1625 /* Once the Almanac is valid, the M12+T does not produce valid UTC
1626 * immediately.
1627 * Wait for UTC offset decode valid, then wait one message more
1628 * so we are not off by 13 seconds after reset.
1629 */
1630
1631 if (instance->count5) {
1632 instance->count5--;
1633 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1634 return;
1635 }
1636
1637 j = instance->ev_serial;
1638 timeout.tv_sec = 0;
1639 timeout.tv_nsec = 0;
1640 if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1641 &timeout) < 0) {
1642 oncore_log_f(instance, LOG_ERR,
1643 "time_pps_fetch failed %m");
1644 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1645 return;
1646 }
1647
1648 if (instance->assert) {
1649 tsp = &pps_i.assert_timestamp;
1650
1651 #ifdef ONCORE_VERBOSE_GET_TIMESTAMP
1652 if (debug > 2) {
1653 u_long i;
1654
1655 i = (u_long) pps_i.assert_sequence;
1656 # ifdef HAVE_STRUCT_TIMESPEC
1657 oncore_log_f(instance, LOG_DEBUG,
1658 "serial/j (%lu, %lu) %ld.%09ld", i,
1659 j, (long)tsp->tv_sec,
1660 (long)tsp->tv_nsec);
1661 # else
1662 oncore_log_f(instance, LOG_DEBUG,
1663 "serial/j (%lu, %lu) %ld.%06ld", i,
1664 j, (long)tsp->tv_sec,
1665 (long)tsp->tv_usec);
1666 # endif
1667 }
1668 #endif
1669
1670 if (pps_i.assert_sequence == j) {
1671 oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps");
1672 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1673 return;
1674 }
1675
1676 instance->ev_serial = pps_i.assert_sequence;
1677 } else {
1678 tsp = &pps_i.clear_timestamp;
1679
1680 #if 0
1681 if (debug > 2) {
1682 u_long i;
1683
1684 i = (u_long) pps_i.clear_sequence;
1685 # ifdef HAVE_STRUCT_TIMESPEC
1686 oncore_log_f(instance, LOG_DEBUG,
1687 "serial/j (%lu, %lu) %ld.%09ld", i,
1688 j, (long)tsp->tv_sec,
1689 (long)tsp->tv_nsec);
1690 # else
1691 oncore_log_f(instance, LOG_DEBUG,
1692 "serial/j (%lu, %lu) %ld.%06ld", i,
1693 j, (long)tsp->tv_sec,
1694 (long)tsp->tv_usec);
1695 # endif
1696 }
1697 #endif
1698
1699 if (pps_i.clear_sequence == j) {
1700 oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps");
1701 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1702 return;
1703 }
1704 instance->ev_serial = pps_i.clear_sequence;
1705 }
1706
1707 /* convert timespec -> ntp l_fp */
1708
1709 dmy = tsp->tv_nsec;
1710 dmy /= 1e9;
1711 ts.l_uf = dmy * 4294967296.0;
1712 ts.l_ui = tsp->tv_sec;
1713
1714 #if 0
1715 alternate code for previous 4 lines is
1716 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1717 DTOLFP(dmy, &ts);
1718 dmy = tsp->tv_sec; /* integer part */
1719 DTOLFP(dmy, &ts_tmp);
1720 L_ADD(&ts, &ts_tmp);
1721 or more simply
1722 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1723 DTOLFP(dmy, &ts);
1724 ts.l_ui = tsp->tv_sec;
1725 #endif /* 0 */
1726
1727 /* now have timestamp in ts */
1728 /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
1729 /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
1730 /* we just try to add them in and dont test for that here */
1731
1732 /* saw_tooth not really necessary if using TIMEVAL */
1733 /* since its only precise to us, but do it anyway. */
1734
1735 /* offset in ns, and is positive (late), we subtract */
1736 /* to put the PPS time transition back where it belongs */
1737
1738 /* must hand the offset for the NEXT sec off to the Kernel to do */
1739 /* the addition, so that the Kernel PLL sees the offset too */
1740
1741 if (instance->assert)
1742 instance->pps_p.assert_offset.tv_nsec = -dt2;
1743 else
1744 instance->pps_p.clear_offset.tv_nsec = -dt2;
1745
1746 /* The following code is necessary, and not just a time_pps_setparams,
1747 * using the saved instance->pps_p, since some other process on the
1748 * machine may have diddled with the mode bits (say adding something
1749 * that it needs). We take what is there and ADD what we need.
1750 * [[ The results from the time_pps_getcap is unlikely to change so
1751 * we could probably just save it, but I choose to do the call ]]
1752 * Unfortunately, there is only ONE set of mode bits in the kernel per
1753 * interface, and not one set for each open handle.
1754 *
1755 * There is still a race condition here where we might mess up someone
1756 * elses mode, but if he is being careful too, he should survive.
1757 */
1758
1759 if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) {
1760 oncore_log_f(instance, LOG_ERR,
1761 "time_pps_getcap failed: %m");
1762 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1763 return;
1764 }
1765
1766 if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) {
1767 oncore_log_f(instance, LOG_ERR,
1768 "time_pps_getparams failed: %m");
1769 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1770 return;
1771 }
1772
1773 /* or current and mine */
1774 current_params.mode |= instance->pps_p.mode;
1775 /* but only set whats legal */
1776 current_params.mode &= current_mode;
1777
1778 current_params.assert_offset.tv_sec = 0;
1779 current_params.assert_offset.tv_nsec = -dt2;
1780 current_params.clear_offset.tv_sec = 0;
1781 current_params.clear_offset.tv_nsec = -dt2;
1782
1783 if (time_pps_setparams(instance->pps_h, ¤t_params))
1784 oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams");
1785
1786 /* have time from UNIX origin, convert to NTP origin. */
1787
1788 ts.l_ui += JAN_1970;
1789 instance->pp->lastrec = ts;
1790
1791 /* print out information about this timestamp (long line) */
1792
1793 ts_tmp = ts;
1794 ts_tmp.l_ui = 0; /* zero integer part */
1795 LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */
1796 j = 1.0e9*dmy; /* then to integer ns */
1797
1798 Rsm = 0;
1799 if (instance->chan == 6)
1800 Rsm = instance->BEHa[64];
1801 else if (instance->chan == 8)
1802 Rsm = instance->BEHa[72];
1803 else if (instance->chan == 12)
1804 Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
1805
1806 if (instance->chan == 6 || instance->chan == 8) {
1807 char f1[5], f2[5], f3[5], f4[5];
1808 if (instance->traim) {
1809 snprintf(f1, sizeof(f1), "%d",
1810 instance->BEHn[21]);
1811 snprintf(f2, sizeof(f2), "%d",
1812 instance->BEHn[22]);
1813 snprintf(f3, sizeof(f3), "%2d",
1814 instance->BEHn[23] * 256 +
1815 instance->BEHn[24]);
1816 snprintf(f4, sizeof(f4), "%3d",
1817 (s_char)instance->BEHn[25]);
1818 } else {
1819 strlcpy(f1, "x", sizeof(f1));
1820 strlcpy(f2, "x", sizeof(f2));
1821 strlcpy(f3, "xx", sizeof(f3));
1822 strlcpy(f4, "xxx", sizeof(f4));
1823 }
1824 snprintf(Msg, sizeof(Msg), /* MAX length 128, currently at 127 */
1825 "%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",
1826 ts.l_ui, j,
1827 instance->pp->year, instance->pp->day,
1828 instance->pp->hour, instance->pp->minute, instance->pp->second,
1829 (long) tsp->tv_sec % 60,
1830 Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
1831 /*rsat dop */
1832 instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2,
1833 /* nsat visible, nsat tracked, traim,traim,traim */
1834 f3, f4,
1835 /* sigma neg-sawtooth */
1836 /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
1837 instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
1838 ); /* will be 0 for 6 chan */
1839 } else if (instance->chan == 12) {
1840 char f1[5], f2[5], f3[5], f4[5];
1841 if (instance->traim) {
1842 snprintf(f1, sizeof(f1), "%d",
1843 instance->BEHn[6]);
1844 snprintf(f2, sizeof(f2), "%d",
1845 instance->BEHn[7]);
1846 snprintf(f3, sizeof(f3), "%d",
1847 instance->BEHn[12] * 256 +
1848 instance->BEHn[13]);
1849 snprintf(f4, sizeof(f4), "%3d",
1850 (s_char)instance->BEHn[14]);
1851 } else {
1852 strlcpy(f1, "x", sizeof(f1));
1853 strlcpy(f2, "x", sizeof(f2));
1854 strlcpy(f3, "xx", sizeof(f3));
1855 strlcpy(f4, "xxx", sizeof(f4));
1856 }
1857 snprintf(Msg, sizeof(Msg),
1858 "%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",
1859 ts.l_ui, j,
1860 instance->pp->year, instance->pp->day,
1861 instance->pp->hour, instance->pp->minute, instance->pp->second,
1862 (long) tsp->tv_sec % 60,
1863 Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
1864 /*rsat dop */
1865 instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2,
1866 /* nsat visible, nsat tracked traim,traim,traim */
1867 f3, f4,
1868 /* sigma neg-sawtooth */
1869 /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
1870 instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
1871 instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
1872 );
1873 }
1874
1875 /* and some things I dont understand (magic ntp things) */
1876
1877 #if 1
1878 oncore_feed_clockproc(instance);
1879 #else
1880 if (!refclock_process(instance->pp)) {
1881 refclock_report(peer, CEVNT_BADTIME);
1882 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
1883 return;
1884 }
1885 #endif
1886
1887 oncore_log(instance, LOG_INFO, Msg); /* this is long message above */
1888 instance->pollcnt = 2;
1889
1890 if (instance->polled) {
1891 instance->polled = 0;
1892 /* instance->pp->dispersion = instance->pp->skew = 0; */
1893 instance->pp->lastref = instance->pp->lastrec;
1894 refclock_receive(instance->peer);
1895 }
1896 peer->flags |= FLAG_PPS;
1897 }
1898
1899
1900 /*************** oncore_msg_XX routines start here *******************/
1901
1902
1903 /*
1904 * print Oncore response message.
1905 */
1906
1907 static void
1908 oncore_msg_any(
1909 struct instance *instance,
1910 u_char *buf,
1911 size_t len,
1912 int idx
1913 )
1914 {
1915 #ifdef ONCORE_VERBOSE_MSG_ANY
1916 int i;
1917 const char *fmt = oncore_messages[idx].fmt;
1918 const char *p;
1919 char *q;
1920 char *qlim;
1921 #ifdef HAVE_GETCLOCK
1922 struct timespec ts;
1923 #endif
1924 struct timeval tv;
1925 char Msg[120], Msg2[10];
1926
1927 if (debug > 3) {
1928 # ifdef HAVE_GETCLOCK
1929 (void) getclock(TIMEOFDAY, &ts);
1930 tv.tv_sec = ts.tv_sec;
1931 tv.tv_usec = ts.tv_nsec / 1000;
1932 # else
1933 GETTIMEOFDAY(&tv, 0);
1934 # endif
1935 oncore_log(instance, LOG_DEBUG, "%ld.%06ld",
1936 (long)tv.tv_sec, (long)tv.tv_usec);
1937
1938 if (!*fmt) {
1939 snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2],
1940 buf[3]);
1941 for(i = 2; i < len && i < 2400 ; i++) {
1942 snprintf(Msg2, sizeof(Msg2), "%02x",
1943 buf[i]);
1944 strlcat(Msg, Msg2, sizeof(Msg));
1945 }
1946 oncore_log(instance, LOG_DEBUG, Msg);
1947 return;
1948 } else {
1949 strlcpy(Msg, "##", sizeof(Msg));
1950 qlim = Msg + sizeof(Msg) - 3;
1951 for (p = fmt, q = Msg + 2; q < qlim && *p; ) {
1952 *q++ = *p++;
1953 *q++ = '_';
1954 }
1955 *q = '\0';
1956 oncore_log(instance, LOG_DEBUG, Msg);
1957 snprintf(Msg, sizeof(Msg), "%c%c", buf[2],
1958 buf[3]);
1959 i = 4;
1960 for (p = fmt; *p; p++) {
1961 snprintf(Msg2, "%02x", buf[i++]);
1962 strlcat(Msg, Msg2, sizeof(Msg));
1963 }
1964 oncore_log(instance, LOG_DEBUG, Msg);
1965 }
1966 }
1967 #endif
1968 }
1969
1970
1971
1972 /* Latitude, Longitude, Height */
1973
1974 static void
1975 oncore_msg_Adef(
1976 struct instance *instance,
1977 u_char *buf,
1978 size_t len
1979 )
1980 {
1981 }
1982
1983
1984
1985 /* Mask Angle */
1986
1987 static void
1988 oncore_msg_Ag(
1989 struct instance *instance,
1990 u_char *buf,
1991 size_t len
1992 )
1993 {
1994 const char *cp;
1995
1996 cp = "set to";
1997 if (instance->o_state == ONCORE_RUN)
1998 cp = "is";
1999
2000 instance->Ag = buf[4];
2001 oncore_log_f(instance, LOG_INFO,
2002 "Satellite mask angle %s %d degrees", cp,
2003 (int)instance->Ag);
2004 }
2005
2006
2007
2008 /*
2009 * get Position hold position
2010 */
2011
2012 static void
2013 oncore_msg_As(
2014 struct instance *instance,
2015 u_char *buf,
2016 size_t len
2017 )
2018 {
2019 instance->ss_lat = buf_w32(&buf[4]);
2020 instance->ss_long = buf_w32(&buf[8]);
2021 instance->ss_ht = buf_w32(&buf[12]);
2022
2023 /* Print out Position */
2024 oncore_print_posn(instance);
2025 }
2026
2027
2028
2029 /*
2030 * Try to use Oncore UT+ Auto Survey Feature
2031 * If its not there (VP), set flag to do it ourselves.
2032 */
2033
2034 static void
2035 oncore_msg_At(
2036 struct instance *instance,
2037 u_char *buf,
2038 size_t len
2039 )
2040 {
2041 instance->saw_At = 1;
2042 if (instance->site_survey == ONCORE_SS_TESTING) {
2043 if (buf[4] == 2) {
2044 oncore_log(instance, LOG_NOTICE,
2045 "Initiating hardware 3D site survey");
2046
2047 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
2048 instance->site_survey = ONCORE_SS_HW;
2049 }
2050 }
2051 }
2052
2053
2054
2055 /*
2056 * get PPS Offset
2057 * Nb. @@Ay is not supported for early UT (no plus) model
2058 */
2059
2060 static void
2061 oncore_msg_Ay(
2062 struct instance *instance,
2063 u_char *buf,
2064 size_t len
2065 )
2066 {
2067 if (instance->saw_Ay)
2068 return;
2069
2070 instance->saw_Ay = 1;
2071
2072 instance->offset = buf_w32(&buf[4]);
2073
2074 oncore_log_f(instance, LOG_INFO, "PPS Offset is set to %ld ns",
2075 instance->offset);
2076 }
2077
2078
2079
2080 /*
2081 * get Cable Delay
2082 */
2083
2084 static void
2085 oncore_msg_Az(
2086 struct instance *instance,
2087 u_char *buf,
2088 size_t len
2089 )
2090 {
2091 if (instance->saw_Az)
2092 return;
2093
2094 instance->saw_Az = 1;
2095
2096 instance->delay = buf_w32(&buf[4]);
2097
2098 oncore_log_f(instance, LOG_INFO, "Cable delay is set to %ld ns",
2099 instance->delay);
2100 }
2101
2102
2103
2104 /* Ba, Ea and Ha come here, these contain Position */
2105
2106 static void
2107 oncore_msg_BaEaHa(
2108 struct instance *instance,
2109 u_char *buf,
2110 size_t len
2111 )
2112 {
2113 const char *cp;
2114 int mode;
2115
2116 /* OK, we are close to the RUN state now.
2117 * But we have a few more items to initialize first.
2118 *
2119 * At the beginning of this routine there are several 'timers'.
2120 * We enter this routine 1/sec, and since the upper levels of NTP have usurped
2121 * the use of timers, we use the 1/sec entry to do things that
2122 * we would normally do with timers...
2123 */
2124
2125 if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */
2126 if (buf[2] == 'B') { /* 6chan */
2127 if (instance->chan_ck < 6) instance->chan_ck = 6;
2128 } else if (buf[2] == 'E') { /* 8chan */
2129 if (instance->chan_ck < 8) instance->chan_ck = 8;
2130 } else if (buf[2] == 'H') { /* 12chan */
2131 if (instance->chan_ck < 12) instance->chan_ck = 12;
2132 }
2133
2134 if (instance->count3++ < 5)
2135 return;
2136
2137 instance->count3 = 0;
2138
2139 if (instance->chan_in != -1) /* set in Input */
2140 instance->chan = instance->chan_in;
2141 else /* set from test */
2142 instance->chan = instance->chan_ck;
2143
2144 oncore_log_f(instance, LOG_INFO, "Input says chan = %d",
2145 instance->chan_in);
2146 oncore_log_f(instance, LOG_INFO, "Model # says chan = %d",
2147 instance->chan_id);
2148 oncore_log_f(instance, LOG_INFO, "Testing says chan = %d",
2149 instance->chan_ck);
2150 oncore_log_f(instance, LOG_INFO, "Using chan = %d",
2151 instance->chan);
2152
2153 instance->o_state = ONCORE_HAVE_CHAN;
2154 oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN");
2155
2156 instance->timeout = 4;
2157 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2158 return;
2159 }
2160
2161 if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
2162 return;
2163
2164 /* PAUSE 5sec - make sure results are stable, before using position */
2165
2166 if (instance->count) {
2167 if (instance->count++ < 5)
2168 return;
2169 instance->count = 0;
2170 }
2171
2172 memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */
2173
2174 /* check if we saw a response to Gc (M12 or M12+T */
2175
2176 if (instance->pps_control_msg_seen != -2) {
2177 if ((instance->pps_control_msg_seen == -1) && (instance->pps_control != -1)) {
2178 oncore_log(instance, LOG_INFO, "PPSCONTROL set, but not implemented (not M12)");
2179 }
2180 instance->pps_control_msg_seen = -2;
2181 }
2182
2183 /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
2184
2185 oncore_check_almanac(instance);
2186 oncore_check_antenna(instance);
2187
2188 /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
2189 /* When we have an almanac, we will start the Bn/En/@@Hn messages */
2190
2191 if (instance->o_state == ONCORE_ALMANAC)
2192 if (oncore_wait_almanac(instance))
2193 return;
2194
2195 /* do some things once when we get this far in BaEaHa */
2196
2197 if (instance->once) {
2198 instance->once = 0;
2199 instance->count2 = 1;
2200
2201 /* Have we seen an @@At (position hold) command response */
2202 /* if not, message out */
2203
2204 if (instance->chan != 12 && !instance->saw_At) {
2205 oncore_log(instance, LOG_NOTICE,
2206 "Not Good, no @@At command (no Position Hold), must be a GT/GT+");
2207 oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
2208 }
2209
2210 /* have an Almanac, can start the SiteSurvey
2211 * (actually only need to get past the almanac_load where we diddle with At
2212 * command,- we can't change it after we start the HW_SS below
2213 */
2214
2215 mode = instance->init_type;
2216 switch (mode) {
2217 case 0: /* NO initialization, don't change anything */
2218 case 1: /* Use given Position */
2219 case 3:
2220 instance->site_survey = ONCORE_SS_DONE;
2221 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
2222 break;
2223
2224 case 2:
2225 case 4: /* Site Survey */
2226 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING");
2227 instance->site_survey = ONCORE_SS_TESTING;
2228 instance->count1 = 1;
2229 if (instance->chan == 12)
2230 oncore_sendmsg(instance, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */
2231 else
2232 oncore_sendmsg(instance, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */
2233 break;
2234 }
2235
2236 /* Read back PPS Offset for Output */
2237 /* Nb. This will fail silently for early UT (no plus) and M12 models */
2238
2239 oncore_sendmsg(instance, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
2240
2241 /* Read back Cable Delay for Output */
2242
2243 oncore_sendmsg(instance, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
2244
2245 /* Read back Satellite Mask Angle for Output */
2246
2247 oncore_sendmsg(instance, oncore_cmd_Agx, sizeof(oncore_cmd_Agx));
2248 }
2249
2250
2251 /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
2252 * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
2253 * We must do the Gd3, and then wait a cycle or two for things to settle,
2254 * then check Ha[130]&0x10 to see if a SS is in progress.
2255 * We will set SW if HW has not been set after an appropriate delay.
2256 */
2257
2258 if (instance->site_survey == ONCORE_SS_TESTING) {
2259 if (instance->chan == 12) {
2260 if (instance->count1) {
2261 if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
2262 instance->count1 = 0;
2263 if (instance->BEHa[130]&0x10) {
2264 oncore_log(instance, LOG_NOTICE,
2265 "Initiating hardware 3D site survey");
2266
2267 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
2268 instance->site_survey = ONCORE_SS_HW;
2269 } else {
2270 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
2271 instance->site_survey = ONCORE_SS_SW;
2272 }
2273 }
2274 }
2275 } else {
2276 if (instance->count1) {
2277 if (instance->count1++ > 5) {
2278 instance->count1 = 0;
2279 /*
2280 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
2281 * wait after the @@At2/@@Gd3 command we have not changed the state to
2282 * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then
2283 * the variable would have been changed by now.
2284 * There are three possibilities:
2285 * 6/8chan
2286 * (a) We did not get a response to the @@At0 or @@At2 commands,
2287 * and it must be a GT/GT+/SL with no position hold mode.
2288 * We will have to do it ourselves.
2289 * (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
2290 * must be a VP or older UT which doesn't have Site Survey mode.
2291 * We will have to do it ourselves.
2292 * 12chan
2293 * (c) We saw the @@Gd command, and saw H[13]*0x10
2294 * We will have to do it ourselves (done above)
2295 */
2296
2297 oncore_log_f(instance, LOG_INFO,
2298 "Initiating software 3D site survey (%d samples)",
2299 POS_HOLD_AVERAGE);
2300
2301 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
2302 instance->site_survey = ONCORE_SS_SW;
2303
2304 instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
2305 if (instance->chan == 12)
2306 oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
2307 else {
2308 oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
2309 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
2310 }
2311 }
2312 }
2313 }
2314 }
2315
2316 /* check the mode we are in 0/2/3D */
2317
2318 if (instance->chan == 6) {
2319 if (instance->BEHa[64]&0x8)
2320 instance->mode = MODE_0D;
2321 else if (instance->BEHa[64]&0x10)
2322 instance->mode = MODE_2D;
2323 else if (instance->BEHa[64]&0x20)
2324 instance->mode = MODE_3D;
2325 } else if (instance->chan == 8) {
2326 if (instance->BEHa[72]&0x8)
2327 instance->mode = MODE_0D;
2328 else if (instance->BEHa[72]&0x10)
2329 instance->mode = MODE_2D;
2330 else if (instance->BEHa[72]&0x20)
2331 instance->mode = MODE_3D;
2332 } else if (instance->chan == 12) {
2333 int bits;
2334
2335 bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
2336 if (bits == 0x4)
2337 instance->mode = MODE_0D;
2338 else if (bits == 0x6)
2339 instance->mode = MODE_2D;
2340 else if (bits == 0x7)
2341 instance->mode = MODE_3D;
2342 }
2343
2344 /* copy the record to the (extra) location in SHMEM */
2345
2346 if (instance->shmem) {
2347 int i;
2348 u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */
2349
2350 switch(instance->chan) {
2351 case 6: smp = &instance->shmem[instance->shmem_Ba]; break;
2352 case 8: smp = &instance->shmem[instance->shmem_Ea]; break;
2353 case 12: smp = &instance->shmem[instance->shmem_Ha]; break;
2354 default: smp = (u_char *) NULL; break;
2355 }
2356
2357 switch (instance->mode) {
2358 case MODE_0D: i = 1; break; /* 0D, Position Hold */
2359 case MODE_2D: i = 2; break; /* 2D, Altitude Hold */
2360 case MODE_3D: i = 3; break; /* 3D fix */
2361 default: i = 0; break;
2362 }
2363
2364 if (i && smp != NULL) {
2365 i *= (len+6);
2366 smp[i + 2]++;
2367 memcpy(&smp[i+3], buf, (size_t) (len+3));
2368 }
2369 }
2370
2371 /*
2372 * check if traim timer active
2373 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
2374 */
2375
2376 if (instance->traim_delay) {
2377 if (instance->traim_delay++ > 5) {
2378 instance->traim = 0;
2379 instance->traim_delay = 0;
2380 cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2381 oncore_log(instance, LOG_INFO, cp);
2382
2383 oncore_set_traim(instance);
2384 } else
2385 return;
2386
2387 }
2388
2389 /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
2390
2391 if (!instance->have_dH && !instance->traim_delay)
2392 oncore_compute_dH(instance);
2393
2394 /*
2395 * must be ONCORE_RUN if we are here.
2396 * Have # chan and TRAIM by now.
2397 */
2398
2399 instance->pp->year = buf[6]*256+buf[7];
2400 instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
2401 instance->pp->hour = buf[8];
2402 instance->pp->minute = buf[9];
2403 instance->pp->second = buf[10];
2404
2405 /*
2406 * Are we doing a Hardware or Software Site Survey?
2407 */
2408
2409 if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
2410 oncore_ss(instance);
2411
2412 /* see if we ever saw a response from the @@Ayx above */
2413
2414 if (instance->count2) {
2415 if (instance->count2++ > 5) { /* this delay to check on @@Ay command */
2416 instance->count2 = 0;
2417
2418 /* Have we seen an Ay (1PPS time offset) command response */
2419 /* if not, and non-zero offset, zero the offset, and send message */
2420
2421 if (!instance->saw_Ay && instance->offset) {
2422 oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored");
2423 instance->offset = 0;
2424 }
2425 }
2426 }
2427
2428 /*
2429 * Check the leap second status once per day.
2430 */
2431
2432 oncore_check_leap_sec(instance);
2433
2434 /*
2435 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2436 */
2437
2438 if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
2439 oncore_shmem_get_3D(instance);
2440
2441 if (!instance->traim) /* NO traim, no BnEnHn, go get tick */
2442 oncore_get_timestamp(instance, instance->offset, instance->offset);
2443 }
2444
2445
2446
2447 /* Almanac Status */
2448
2449 static void
2450 oncore_msg_Bd(
2451 struct instance *instance,
2452 u_char *buf,
2453 size_t len
2454 )
2455 {
2456 oncore_log_f(instance, LOG_NOTICE,
2457 "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
2458 ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6],
2459 buf[7], w32(&buf[8]));
2460 }
2461
2462
2463
2464 /* get leap-second warning message */
2465
2466 /*
2467 * @@Bj does NOT behave as documented in current Oncore firmware.
2468 * It turns on the LEAP indicator when the data is set, and does not,
2469 * as documented, wait until the beginning of the month when the
2470 * leap second will occur.
2471 * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
2472 * @@Bj is only called in June/December.
2473 */
2474
2475 static void
2476 oncore_msg_Bj(
2477 struct instance *instance,
2478 u_char *buf,
2479 size_t len
2480 )
2481 {
2482 const char *cp;
2483
2484 instance->saw_Bj = 1;
2485
2486 switch(buf[4]) {
2487 case 1:
2488 instance->pp->leap = LEAP_ADDSECOND;
2489 cp = "Set pp.leap to LEAP_ADDSECOND";
2490 break;
2491 case 2:
2492 instance->pp->leap = LEAP_DELSECOND;
2493 cp = "Set pp.leap to LEAP_DELSECOND";
2494 break;
2495 case 0:
2496 default:
2497 instance->pp->leap = LEAP_NOWARNING;
2498 cp = "Set pp.leap to LEAP_NOWARNING";
2499 break;
2500 }
2501 oncore_log(instance, LOG_NOTICE, cp);
2502 }
2503
2504
2505
2506 static void
2507 oncore_msg_Bl(
2508 struct instance *instance,
2509 u_char *buf,
2510 size_t len
2511 )
2512 {
2513 int subframe, valid, page, i, j, tow;
2514 int day_now, day_lsf;
2515 const char *cp;
2516 enum {
2517 WARN_NOT_YET,
2518 WARN_0,
2519 WARN_PLUS,
2520 WARN_MINUS
2521 } warn;
2522
2523
2524 subframe = buf[6] & 017;
2525 valid = (buf[6] >> 4) & 017;
2526 page = buf[7];
2527
2528 if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) {
2529 instance->Bl.dt_ls = buf[32];
2530 instance->Bl.WN_lsf = buf[33];
2531 instance->Bl.DN_lsf = buf[34];
2532 instance->Bl.dt_lsf = buf[35];
2533 instance->Bl.lsf_flg++;
2534 }
2535 if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) {
2536 i = (buf[7+7]<<8) + buf[7+8];
2537 instance->Bl.WN = i >> 6;
2538 tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6];
2539 tow >>= 7;
2540 tow = tow & 0377777;
2541 tow <<= 2;
2542 instance->Bl.DN = tow/57600L + 1;
2543 instance->Bl.wn_flg++;
2544 }
2545 if (instance->Bl.wn_flg && instance->Bl.lsf_flg) {
2546 instance->Bl.wn_flg = instance->Bl.lsf_flg = 0;
2547 oncore_cmd_Bl[2] = 0;
2548 oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl);
2549 oncore_cmd_Bl[2] = 1;
2550
2551 i = instance->Bl.WN&01400;
2552 instance->Bl.WN_lsf |= i;
2553
2554 /* have everything I need, doit */
2555
2556 i = (instance->Bl.WN_lsf - instance->Bl.WN);
2557 if (i < 0)
2558 i += 1024;
2559 day_now = instance->Bl.DN;
2560 day_lsf = 7*i + instance->Bl.DN_lsf;
2561
2562 /* ignore if in past or more than a month in future */
2563
2564 warn = WARN_NOT_YET;
2565 if (day_lsf >= day_now && day_lsf - day_now < 32) {
2566 /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */
2567 if (day_lsf - day_now < 28 || instance->BEHa[5] < 20) {
2568 i = instance->Bl.dt_lsf - instance->Bl.dt_ls;
2569 switch (i) {
2570 case -1:
2571 warn = WARN_MINUS;
2572 break;
2573 case 0:
2574 warn = WARN_0;
2575 break;
2576 case 1:
2577 warn = WARN_PLUS;
2578 break;
2579 }
2580 }
2581 }
2582
2583 switch (warn) {
2584 case WARN_0:
2585 case WARN_NOT_YET:
2586 instance->peer->leap = LEAP_NOWARNING;
2587 cp = "Set peer.leap to LEAP_NOWARNING";
2588 break;
2589 case WARN_MINUS:
2590 instance->peer->leap = LEAP_DELSECOND;
2591 cp = "Set peer.leap to LEAP_DELSECOND";
2592 break;
2593 case WARN_PLUS:
2594 instance->peer->leap = LEAP_ADDSECOND;
2595 cp = "Set peer.leap to LEAP_ADDSECOND";
2596 break;
2597 default:
2598 cp = NULL;
2599 break;
2600 }
2601 oncore_log(instance, LOG_NOTICE, cp);
2602
2603 i = instance->Bl.dt_lsf-instance->Bl.dt_ls;
2604 if (i) {
2605 j = (i >= 0) ? i : -i; /* abs(i) */
2606 oncore_log_f(instance, LOG_NOTICE,
2607 "see Leap_Second (%c%d) in %d days",
2608 ((i >= 0) ? '+' : '-'), j,
2609 day_lsf-day_now);
2610 }
2611 }
2612
2613 /*
2614 * Reg only wants the following output for "deeper" driver debugging.
2615 * See Bug 2142 and Bug 1866
2616 */
2617 #if 0
2618 oncore_log_f(instance, LOG_DEBUG,
2619 "dt_ls = %d dt_lsf = %d WN = %d DN = %d WN_lsf = %d DNlsf = %d wn_flg = %d lsf_flg = %d Bl_day = %d",
2620 instance->Bl.dt_ls, instance->Bl.dt_lsf,
2621 instance->Bl.WN, instance->Bl.DN,
2622 instance->Bl.WN_lsf, instance->Bl.DN_lsf,
2623 instance->Bl.wn_flg, instance->Bl.lsf_flg,
2624 instance->Bl.Bl_day);
2625 #endif
2626 }
2627
2628
2629 static void
2630 oncore_msg_BnEnHn(
2631 struct instance *instance,
2632 u_char *buf,
2633 size_t len
2634 )
2635 {
2636 long dt1, dt2;
2637
2638 if (instance->o_state != ONCORE_RUN)
2639 return;
2640
2641 if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */
2642 instance->traim_ck = 1;
2643 instance->traim_delay = 0;
2644 oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON");
2645
2646 oncore_set_traim(instance);
2647 }
2648
2649 memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */
2650
2651 if (!instance->traim) /* BnEnHn will be turned off in any case */
2652 return;
2653
2654 /* If Time RAIM doesn't like it, don't trust it */
2655
2656 if (buf[2] == 'H') {
2657 if (instance->BEHn[6]) { /* bad TRAIM */
2658 oncore_log(instance, LOG_WARNING, "BAD TRAIM");
2659 return;
2660 }
2661
2662 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
2663 instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
2664 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
2665 } else {
2666 if (instance->BEHn[21]) /* bad TRAIM */
2667 return;
2668
2669 dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
2670 instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */
2671 dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
2672 }
2673
2674 oncore_get_timestamp(instance, dt1, dt2);
2675 }
2676
2677
2678
2679 /* Here for @@Ca, @@Fa and @@Ia messages */
2680
2681 /* These are Self test Commands for 6, 8, and 12 chan receivers.
2682 * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
2683 * It was found that under some circumstances the following
2684 * command would fail if issued immediately after the return from the
2685 * @@Fa, but a 2sec delay seemed to fix things. Since simply calling
2686 * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
2687 * itimer, we set a flag, and test it at the next POLL. If it hasn't
2688 * been cleared, we reissue the @@Cj that is issued below.
2689 * Note that we do a @@Cj at the beginning, and again here.
2690 * The first is to get the info, the 2nd is just used as a safe command
2691 * after the @@Fa for all Oncores (and it was in this posn in the
2692 * original code).
2693 */
2694
2695 static void
2696 oncore_msg_CaFaIa(
2697 struct instance *instance,
2698 u_char *buf,
2699 size_t len
2700 )
2701 {
2702 int i;
2703
2704 if (instance->o_state == ONCORE_TEST_SENT) {
2705 enum antenna_state antenna;
2706
2707 instance->timeout = 0;
2708
2709 #if ONCORE_VERBOSE_SELF_TEST
2710 if (debug > 2) {
2711 if (buf[2] == 'I')
2712 oncore_log_f(instance, LOG_DEBUG,
2713 ">>@@%ca %x %x %x", buf[2],
2714 buf[4], buf[5], buf[6]);
2715 else
2716 oncore_log_f(instance, LOG_DEBUG,
2717 ">>@@%ca %x %x", buf[2],
2718 buf[4], buf[5]);
2719 }
2720 #endif
2721
2722 antenna = (buf[4] & 0xc0) >> 6;
2723 buf[4] &= ~0xc0;
2724
2725 i = buf[4] || buf[5];
2726 if (buf[2] == 'I') i = i || buf[6];
2727 if (i) {
2728 if (buf[2] == 'I')
2729 oncore_log_f(instance, LOG_ERR,
2730 "self test failed: result %02x %02x %02x",
2731 buf[4], buf[5], buf[6]);
2732 else
2733 oncore_log_f(instance, LOG_ERR,
2734 "self test failed: result %02x %02x",
2735 buf[4], buf[5]);
2736
2737 oncore_log(instance, LOG_ERR,
2738 "ONCORE: self test failed, shutting down driver");
2739
2740 refclock_report(instance->peer, CEVNT_FAULT);
2741 oncore_shutdown(instance->unit, instance->peer);
2742 return;
2743 }
2744
2745 /* report the current antenna state */
2746
2747 oncore_antenna_report(instance, antenna);
2748
2749 instance->o_state = ONCORE_INIT;
2750 oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT");
2751
2752 instance->timeout = 4;
2753 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2754 }
2755 }
2756
2757
2758
2759 /*
2760 * Demultiplex the almanac into shmem
2761 */
2762
2763 static void
2764 oncore_msg_Cb(
2765 struct instance *instance,
2766 u_char *buf,
2767 size_t len
2768 )
2769 {
2770 int i;
2771
2772 if (instance->shmem == NULL)
2773 return;
2774
2775 if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
2776 i = buf[5];
2777 else if (buf[4] == 4 && buf[5] <= 5)
2778 i = buf[5] + 24;
2779 else if (buf[4] == 4 && buf[5] <= 10)
2780 i = buf[5] + 23;
2781 else if (buf[4] == 4 && buf[5] == 25)
2782 i = 34;
2783 else {
2784 oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC");
2785 return;
2786 }
2787
2788 i *= 36;
2789 instance->shmem[instance->shmem_Cb + i + 2]++;
2790 memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
2791
2792 #ifdef ONCORE_VERBOSE_MSG_CB
2793 oncore_log_f(instance, LOG_DEBUG, "See Cb [%d,%d]", buf[4],
2794 buf[5]);
2795 #endif
2796 }
2797
2798
2799
2800 /*
2801 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
2802 * not so for VP (eeprom) or any unit with a battery
2803 */
2804
2805 static void
2806 oncore_msg_Cf(
2807 struct instance *instance,
2808 u_char *buf,
2809 size_t len
2810 )
2811 {
2812 if (instance->o_state == ONCORE_RESET_SENT) {
2813 oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
2814 /* Reset set VP to IDLE */
2815 instance->o_state = ONCORE_TEST_SENT;
2816 oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
2817
2818 oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2819 }
2820 }
2821
2822
2823
2824 /*
2825 * This is the Grand Central Station for the Preliminary Initialization.
2826 * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
2827 *
2828 * We do an @@Cj whenever we need a safe command for all Oncores.
2829 * The @@Cj gets us back here where we can switch to the next phase of setup.
2830 *
2831 * o Once at the very beginning (in start) to get the Model number.
2832 * This info is printed, but no longer used.
2833 * o Again after we have determined the number of Channels in the receiver.
2834 * o And once later after we have done a reset and test, (which may hang),
2835 * as we are about to initialize the Oncore and start it running.
2836 * o We have one routine below for each case.
2837 */
2838
2839 static void
2840 oncore_msg_Cj(
2841 struct instance *instance,
2842 u_char *buf,
2843 size_t len
2844 )
2845 {
2846 int mode;
2847
2848 memcpy(instance->Cj, buf, len);
2849
2850 instance->timeout = 0;
2851 if (instance->o_state == ONCORE_CHECK_ID) {
2852 oncore_msg_Cj_id(instance, buf, len);
2853 oncore_chan_test(instance);
2854 } else if (instance->o_state == ONCORE_HAVE_CHAN) {
2855 mode = instance->init_type;
2856 if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */
2857 instance->o_state = ONCORE_RESET_SENT;
2858 oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT");
2859 oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
2860 } else {
2861 instance->o_state = ONCORE_TEST_SENT;
2862 oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
2863 }
2864 }
2865
2866 if (instance->o_state == ONCORE_TEST_SENT) {
2867 if (instance->chan == 6)
2868 oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
2869 else if (instance->chan == 8)
2870 oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
2871 else if (instance->chan == 12)
2872 oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
2873 } else if (instance->o_state == ONCORE_INIT)
2874 oncore_msg_Cj_init(instance, buf, len);
2875 }
2876
2877
2878
2879 /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
2880 * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
2881 * and from Motorola. Until recently Rick was the only source of
2882 * this information as Motorola didn't give the information out.
2883 *
2884 * Determine the Type from the Model #, this determines #chan and if TRAIM is
2885 * available.
2886 *
2887 * The Information from this routine is NO LONGER USED.
2888 * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
2889 */
2890
2891 static void
2892 oncore_msg_Cj_id(
2893 struct instance *instance,
2894 u_char *buf,
2895 size_t len
2896 )
2897 {
2898 char *cp2, Model[21];
2899 const char *cp, *cp1;
2900
2901 /* Write Receiver ID message to clockstats file */
2902
2903 instance->Cj[294] = '\0';
2904 for (cp= (char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
2905 char *cpw = strchr(cp, '\r');
2906 if (!cpw)
2907 cpw = (char *)&instance->Cj[294];
2908 *cpw = '\0';
2909 oncore_log(instance, LOG_NOTICE, cp);
2910 *cpw = '\r';
2911 cp = cpw+2;
2912 }
2913
2914 /* next, the Firmware Version and Revision numbers */
2915
2916 instance->version = atoi((char *) &instance->Cj[83]);
2917 instance->revision = atoi((char *) &instance->Cj[111]);
2918
2919 /* from model number decide which Oncore this is,
2920 and then the number of channels */
2921
2922 for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */
2923 ;
2924 cp1 = cp;
2925 cp2 = Model;
2926 for (; !isspace((unsigned char)*cp) && cp-cp1 < 20; cp++, cp2++)
2927 *cp2 = *cp;
2928 *cp2 = '\0';
2929
2930 cp = 0;
2931 if (!strncmp(Model, "PVT6", (size_t) 4)) {
2932 cp = "PVT6";
2933 instance->model = ONCORE_PVT6;
2934 } else if (Model[0] == 'A') {
2935 cp = "Basic";
2936 instance->model = ONCORE_BASIC;
2937 } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
2938 cp = "VP";
2939 instance->model = ONCORE_VP;
2940 } else if (Model[0] == 'P') {
2941 cp = "M12";
2942 instance->model = ONCORE_M12;
2943 } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
2944 if (Model[5] == 'N') {
2945 cp = "GT";
2946 instance->model = ONCORE_GT;
2947 } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
2948 cp = "GT+";
2949 instance->model = ONCORE_GTPLUS;
2950 } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
2951 cp = "UT";
2952 instance->model = ONCORE_UT;
2953 } else if (Model[1] == '5' && Model[5] == 'G') {
2954 cp = "UT+";
2955 instance->model = ONCORE_UTPLUS;
2956 } else if (Model[1] == '6' && Model[5] == 'G') {
2957 cp = "SL";
2958 instance->model = ONCORE_SL;
2959 } else {
2960 cp = "Unknown";
2961 instance->model = ONCORE_UNKNOWN;
2962 }
2963 } else {
2964 cp = "Unknown";
2965 instance->model = ONCORE_UNKNOWN;
2966 }
2967
2968 /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
2969
2970 oncore_log_f(instance, LOG_INFO,
2971 "This looks like an Oncore %s with version %d.%d firmware.",
2972 cp, instance->version, instance->revision);
2973
2974 instance->chan_id = 8; /* default */
2975 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2976 instance->chan_id = 6;
2977 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2978 instance->chan_id = 8;
2979 else if (instance->model == ONCORE_M12)
2980 instance->chan_id = 12;
2981
2982 instance->traim_id = 0; /* default */
2983 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2984 instance->traim_id = 0;
2985 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2986 instance->traim_id = 1;
2987 else if (instance->model == ONCORE_M12)
2988 instance->traim_id = -1;
2989
2990 oncore_log_f(instance, LOG_INFO, "Channels = %d, TRAIM = %s",
2991 instance->chan_id,
2992 ((instance->traim_id < 0)
2993 ? "UNKNOWN"
2994 : (instance->traim_id > 0)
2995 ? "ON"
2996 : "OFF"));
2997 }
2998
2999
3000
3001 /* OK, know type of Oncore, have possibly reset it, and have tested it.
3002 * We know the number of channels.
3003 * We will determine whether we have TRAIM before we actually start.
3004 * Now initialize.
3005 */
3006
3007 static void
3008 oncore_msg_Cj_init(
3009 struct instance *instance,
3010 u_char *buf,
3011 size_t len
3012 )
3013 {
3014 u_char Cmd[20];
3015 int mode;
3016
3017
3018 /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
3019 * start again if we go from 0D -> 3D, then loses them again when we
3020 * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM.
3021 * For NOW we will turn this aspect of filling SHMEM off for the M12
3022 */
3023
3024 if (instance->chan == 12) {
3025 instance->shmem_bad_Ea = 1;
3026 oncore_log_f(instance, LOG_NOTICE,
3027 "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***",
3028 instance->version, instance->revision);
3029 }
3030
3031 oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
3032 oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
3033 oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
3034 oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
3035 oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
3036 oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
3037 oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
3038
3039 mode = instance->init_type;
3040
3041 /* If there is Position input in the Config file
3042 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
3043 * or mode = (2,4) set it as INITIAL position, and do Site Survey.
3044 */
3045
3046 if (instance->posn_set) {
3047 oncore_log(instance, LOG_INFO, "Setting Posn from input data");
3048 oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */
3049 } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
3050 if (instance->chan != 12)
3051 oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
3052
3053 if (mode != 0) {
3054 /* cable delay in ns */
3055 memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
3056 w32_buf(&Cmd[-2+4], (int)instance->delay);
3057 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */
3058
3059 /* PPS offset in ns */
3060 memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */
3061 w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */
3062 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ay));
3063
3064 /* Satellite mask angle */
3065
3066 if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */
3067 memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
3068 Cmd[-2+4] = instance->Ag;
3069 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ag));
3070 }
3071 }
3072
3073 /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
3074 * now we're really running
3075 * these were ALL started in the chan test,
3076 * However, if we had mode=3,4 then commands got turned off, so we turn
3077 * them on again here just in case
3078 */
3079
3080 if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
3081 oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
3082 oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
3083 oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
3084 oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
3085 oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
3086 } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */
3087 oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
3088 oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
3089 oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
3090 oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
3091 oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
3092 } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */
3093 oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
3094 oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
3095 oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
3096 oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
3097 oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
3098 oncore_cmd_Gc[2] = (instance->pps_control < 0) ? 1 : instance->pps_control;
3099 oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* PPS off/continuous/Tracking 1+sat/TRAIM */
3100 }
3101
3102 instance->count = 1;
3103 instance->o_state = ONCORE_ALMANAC;
3104 oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC");
3105 }
3106
3107
3108
3109 /* 12chan position */
3110
3111 static void
3112 oncore_msg_Ga(
3113 struct instance *instance,
3114 u_char *buf,
3115 size_t len
3116 )
3117 {
3118 long lat, lon, ht;
3119 double Lat, Lon, Ht;
3120
3121
3122 lat = buf_w32(&buf[4]);
3123 lon = buf_w32(&buf[8]);
3124 ht = buf_w32(&buf[12]); /* GPS ellipsoid */
3125
3126 Lat = lat;
3127 Lon = lon;
3128 Ht = ht;
3129
3130 Lat /= 3600000;
3131 Lon /= 3600000;
3132 Ht /= 100;
3133
3134 oncore_log_f(instance, LOG_NOTICE,
3135 "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat,
3136 Lon, Ht);
3137
3138 instance->ss_lat = lat;
3139 instance->ss_long = lon;
3140 instance->ss_ht = ht;
3141
3142 oncore_print_posn(instance);
3143 }
3144
3145
3146
3147 /* 12 chan time/date */
3148
3149 static void
3150 oncore_msg_Gb(
3151 struct instance *instance,
3152 u_char *buf,
3153 size_t len
3154 )
3155 {
3156 const char * gmts;
3157 int mo, d, y, h, m, s, gmth, gmtm;
3158
3159 mo = buf[4];
3160 d = buf[5];
3161 y = 256*buf[6]+buf[7];
3162
3163 h = buf[8];
3164 m = buf[9];
3165 s = buf[10];
3166
3167 gmts = ((buf[11] == 0) ? "+" : "-");
3168 gmth = buf[12];
3169 gmtm = buf[13];
3170
3171 oncore_log_f(instance, LOG_NOTICE,
3172 "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
3173 d, months[mo-1], y, h, m, s, gmts, gmth, gmtm);
3174 }
3175
3176
3177
3178 /* Response to PPS Control message (M12 and M12+T only ) */
3179
3180 static void
3181 oncore_msg_Gc(
3182 struct instance *instance,
3183 u_char *buf,
3184 size_t len
3185 )
3186 {
3187 const char *tbl[] = {"OFF", "ON", "SATELLITE", "TRAIM" };
3188
3189 instance->pps_control_msg_seen = 1;
3190 oncore_log_f(instance, LOG_INFO, "PPS Control set to %s",
3191 tbl[buf[4]]);
3192 }
3193
3194
3195
3196 /* Leap Second for M12, gives all info from satellite message */
3197 /* also in UT v3.0 */
3198
3199 static void
3200 oncore_msg_Gj(
3201 struct instance *instance,
3202 u_char *buf,
3203 size_t len
3204 )
3205 {
3206 static const char * insrem[2] = {
3207 "removed",
3208 "inserted"
3209 };
3210
3211 int dt;
3212 const char *cp;
3213
3214 instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
3215
3216 /* print the message to verify whats there */
3217
3218 dt = buf[5] - buf[4];
3219
3220 oncore_log_f(instance, LOG_INFO,
3221 "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
3222 buf[4], buf[5], 256 * buf[6] + buf[7], buf[8],
3223 buf[9], buf[10],
3224 (buf[14] + 256 *
3225 (buf[13] + 256 * (buf[12] + 256 * buf[11]))),
3226 buf[15], buf[16], buf[17]);
3227
3228 /* There seems to be eternal confusion about when a leap second
3229 * takes place. It's the second *before* the new TAI offset
3230 * becomes effective. But since the ONCORE receiver tells us
3231 * just that, we would have to do some time/date calculations to
3232 * get the actual leap second -- that is, the one that is
3233 * deleted or inserted.
3234 *
3235 * Going through all this for a simple log is probably overkill,
3236 * so for fixing bug#1050 the message output is changed to
3237 * reflect the fact that it tells the second after the leap
3238 * second.
3239 */
3240 if (dt)
3241 oncore_log_f(instance, LOG_NOTICE,
3242 "Leap second %s (%d) before %04u-%02u-%02u/%02u:%02u:%02u",
3243 insrem[(dt > 0)], dt,
3244 256u * buf[6] + buf[7], buf[8], buf[9],
3245 buf[15], buf[16], buf[17]);
3246
3247 /* Only raise warning within a month of the leap second */
3248
3249 instance->pp->leap = LEAP_NOWARNING;
3250 cp = "Set pp.leap to LEAP_NOWARNING";
3251
3252 if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
3253 buf[8] == instance->BEHa[4]) { /* month */
3254 if (dt) {
3255 if (dt < 0) {
3256 instance->pp->leap = LEAP_DELSECOND;
3257 cp = "Set pp.leap to LEAP_DELSECOND";
3258 } else {
3259 instance->pp->leap = LEAP_ADDSECOND;
3260 cp = "Set pp.leap to LEAP_ADDSECOND";
3261 }
3262 }
3263 }
3264 oncore_log(instance, LOG_INFO, cp);
3265 }
3266
3267
3268
3269 /* Power on failure */
3270
3271 static void
3272 oncore_msg_Sz(
3273 struct instance *instance,
3274 u_char *buf,
3275 size_t len
3276 )
3277 {
3278 if (instance && instance->peer) {
3279 oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On");
3280 oncore_shutdown(instance->unit, instance->peer);
3281 }
3282 }
3283
3284 /************** Small Subroutines ***************/
3285
3286
3287 static void
3288 oncore_antenna_report(
3289 struct instance *instance,
3290 enum antenna_state new_state)
3291 {
3292 const char *cp;
3293
3294 if (instance->ant_state == new_state)
3295 return;
3296
3297 switch (new_state) {
3298 case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break;
3299 case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break;
3300 case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
3301 case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break;
3302 default: cp = "GPS antenna: ?"; break;
3303 }
3304
3305 instance->ant_state = new_state;
3306 oncore_log(instance, LOG_NOTICE, cp);
3307 }
3308
3309
3310
3311 static void
3312 oncore_chan_test(
3313 struct instance *instance
3314 )
3315 {
3316 /* subroutine oncore_Cj_id has determined the number of channels from the
3317 * model number of the attached oncore. This is not always correct since
3318 * the oncore could have non-standard firmware. Here we check (independently) by
3319 * trying a 6, 8, and 12 chan command, and see which responds.
3320 * Caution: more than one CAN respond.
3321 *
3322 * This #chan is used by the code rather than that calculated from the model number.
3323 */
3324
3325 instance->o_state = ONCORE_CHECK_CHAN;
3326 oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN");
3327
3328 instance->count3 = 1;
3329 oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
3330 oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
3331 oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
3332 }
3333
3334
3335
3336 /* check for a GOOD Almanac, have we got one yet? */
3337
3338 static void
3339 oncore_check_almanac(
3340 struct instance *instance
3341 )
3342 {
3343 if (instance->chan == 6) {
3344 instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
3345 instance->rsm.bad_fix = instance->BEHa[64]&0x52;
3346 } else if (instance->chan == 8) {
3347 instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
3348 instance->rsm.bad_fix = instance->BEHa[72]&0x52;
3349 } else if (instance->chan == 12) {
3350 int bits1, bits2, bits3;
3351
3352 bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
3353 bits2 = instance->BEHa[130];
3354 instance->rsm.bad_almanac = (bits2 & 0x80);
3355 instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2);
3356 /* too few sat Bad Geom */
3357
3358 bits3 = instance->BEHa[141]; /* UTC parameters */
3359 if (!instance->count5_set && (bits3 & 0xC0)) {
3360 instance->count5 = 4; /* was 2 [Bug 1766] */
3361 instance->count5_set = 1;
3362 }
3363 #ifdef ONCORE_VERBOSE_CHECK_ALMANAC
3364 oncore_log_f(instance, LOG_DEBUG,
3365 "DEBUG BITS: (%x %x), (%x %x %x), %x %x %x %x %x",
3366 instance->BEHa[129], instance->BEHa[130],
3367 bits1, bits2, bits3,
3368 instance->mode == MODE_0D,
3369 instance->mode == MODE_2D,
3370 instance->mode == MODE_3D,
3371 instance->rsm.bad_almanac,
3372 instance->rsm.bad_fix);
3373 }
3374 #endif
3375 }
3376 }
3377
3378
3379
3380 /* check the antenna for changes (did it get unplugged?) */
3381
3382 static void
oncore_check_antenna(struct instance * instance)3383 oncore_check_antenna(
3384 struct instance *instance
3385 )
3386 {
3387 enum antenna_state antenna; /* antenna state */
3388
3389 if (instance->chan == 12)
3390 antenna = (instance->BEHa[130] & 0x6 ) >> 1;
3391 else
3392 antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */
3393
3394 oncore_antenna_report (instance, antenna);
3395 }
3396
3397
3398
3399 /*
3400 * Check the leap second status once per day.
3401 *
3402 * Note that the ONCORE firmware for the Bj command is wrong at
3403 * least in the VP.
3404 * It starts advertising a LEAP SECOND as soon as the GPS satellite
3405 * data message (page 18, subframe 4) is updated to a date in the
3406 * future, and does not wait for the month that it will occur.
3407 * The event will usually be advertised several months in advance.
3408 * Since there is a one bit flag, there is no way to tell if it is
3409 * this month, or when...
3410 *
3411 * As such, we have the workaround below, of only checking for leap
3412 * seconds with the Bj command in June/December.
3413 *
3414 * The Gj command gives more information, and we can tell in which
3415 * month to apply the correction.
3416 *
3417 * Note that with the VP we COULD read the raw data message, and
3418 * interpret it ourselves, but since this is specific to this receiver
3419 * only, and the above workaround is adequate, we don't bother.
3420 */
3421
3422 static void
oncore_check_leap_sec(struct instance * instance)3423 oncore_check_leap_sec(
3424 struct instance *instance
3425 )
3426 {
3427 oncore_cmd_Bl[2] = 1; /* just to be sure */
3428 if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */
3429 instance->Bj_day = instance->BEHa[5];
3430
3431 if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */
3432 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3433 oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3434 oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
3435 return;
3436 }
3437
3438 if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */
3439 instance->count4 = 1;
3440
3441 oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
3442 return;
3443 }
3444
3445 /* Gj works for some 6/8 chan UT and the M12 */
3446 /* if no response from Gj in 5 sec, we try Bj */
3447 /* which isnt implemented in all the GT/UT either */
3448
3449 if (instance->count4) { /* delay, waiting for Gj response */
3450 if (instance->saw_Gj == 1)
3451 instance->count4 = 0;
3452 else if (instance->count4++ > 5) { /* delay, waiting for Gj response */
3453 instance->saw_Gj = -1; /* didnt see it, will use Bj */
3454 instance->count4 = 0;
3455 if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12)) {
3456 oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3457 oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
3458 }
3459 }
3460 }
3461 }
3462
3463
3464
3465 /* check the message checksum,
3466 * buf points to START of message ( @@ )
3467 * len is length WITH CR/LF.
3468 */
3469
3470 static int
oncore_checksum_ok(u_char * buf,int len)3471 oncore_checksum_ok(
3472 u_char *buf,
3473 int len
3474 )
3475 {
3476 int i, j;
3477
3478 j = 0;
3479 for (i = 2; i < len-3; i++)
3480 j ^= buf[i];
3481
3482 return(j == buf[len-3]);
3483 }
3484
3485
3486
3487 static void
oncore_compute_dH(struct instance * instance)3488 oncore_compute_dH(
3489 struct instance *instance
3490 )
3491 {
3492 int GPS, MSL;
3493
3494 /* Here calculate dH = GPS - MSL for output message */
3495 /* also set Altitude Hold mode if GT */
3496
3497 instance->have_dH = 1;
3498 if (instance->chan == 12) {
3499 GPS = buf_w32(&instance->BEHa[39]);
3500 MSL = buf_w32(&instance->BEHa[43]);
3501 } else {
3502 GPS = buf_w32(&instance->BEHa[23]);
3503 MSL = buf_w32(&instance->BEHa[27]);
3504 }
3505 instance->dH = GPS - MSL;
3506 instance->dH /= 100.;
3507
3508 /* if MSL is not set, the calculation is meaningless */
3509
3510 if (MSL) /* not set ! */
3511 oncore_log_f(instance, LOG_INFO,
3512 "dH = (GPS - MSL) = %.2fm", instance->dH);
3513 }
3514
3515
3516
3517 /*
3518 * try loading Almanac from shmem (where it was copied from shmem_old
3519 */
3520
3521 static void
oncore_load_almanac(struct instance * instance)3522 oncore_load_almanac(
3523 struct instance *instance
3524 )
3525 {
3526 u_char *cp, Cmd[20];
3527 int n;
3528 struct timeval tv;
3529 struct tm *tm;
3530
3531 if (!instance->shmem)
3532 return;
3533
3534 #ifndef ONCORE_VERBOSE_LOAD_ALMANAC
3535 for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
3536 cp += (n + 3)) {
3537 if (!strncmp((char *) cp, "@@Cb", 4) &&
3538 oncore_checksum_ok(cp, 33) &&
3539 (*(cp+4) == 4 || *(cp+4) == 5)) {
3540 write(instance->ttyfd, cp, n);
3541 oncore_print_Cb(instance, cp);
3542 }
3543 }
3544 #else /* ONCORE_VERBOSE_LOAD_ALMANAC follows */
3545 for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
3546 cp += (n+3)) {
3547 oncore_log_f(instance, LOG_DEBUG, "See %c%c%c%c %d",
3548 *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
3549
3550 if (!strncmp(cp, "@@Cb", 4)) {
3551 oncore_print_Cb(instance, cp);
3552 if (oncore_checksum_ok(cp, 33)) {
3553 if (*(cp+4) == 4 || *(cp+4) == 5) {
3554 oncore_log(instance, LOG_DEBUG, "GOOD SF");
3555 write(instance->ttyfd, cp, n);
3556 } else
3557 oncore_log(instance, LOG_DEBUG, "BAD SF");
3558 } else
3559 oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM");
3560 }
3561 }
3562 #endif
3563
3564 /* Must load position and time or the Almanac doesn't do us any good */
3565
3566 if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */
3567 oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM");
3568 for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3569 if ((instance->chan == 6 && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) ||
3570 (instance->chan == 8 && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) ||
3571 (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
3572 int ii, jj, kk;
3573
3574 instance->posn_set = 1;
3575 ii = buf_w32(cp + 15);
3576 jj = buf_w32(cp + 19);
3577 kk = buf_w32(cp + 23);
3578 #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
3579 oncore_log_f(instance, LOG_DEBUG,
3580 "SHMEM posn = %ld (%d, %d, %d)",
3581 (long)(cp-instance->shmem),
3582 ii, jj, kk);
3583 #endif
3584 if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
3585 instance->ss_lat = ii;
3586 instance->ss_long = jj;
3587 instance->ss_ht = kk;
3588 }
3589 }
3590 }
3591 }
3592 oncore_set_posn(instance);
3593
3594 /* and set time to time from Computer clock */
3595
3596 GETTIMEOFDAY(&tv, 0);
3597 tm = gmtime((const time_t *) &tv.tv_sec);
3598
3599 #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
3600 oncore_log_f(instance, LOG_DEBUG, "DATE %d %d %d, %d %d %d",
3601 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
3602 tm->tm_hour, tm->tm_min, tm->tm_sec);
3603 #endif
3604 if (instance->chan == 12) {
3605 memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
3606 Cmd[-2+4] = tm->tm_mon + 1;
3607 Cmd[-2+5] = tm->tm_mday;
3608 Cmd[-2+6] = (1900+tm->tm_year)/256;
3609 Cmd[-2+7] = (1900+tm->tm_year)%256;
3610 Cmd[-2+8] = tm->tm_hour;
3611 Cmd[-2+9] = tm->tm_min;
3612 Cmd[-2+10] = tm->tm_sec;
3613 Cmd[-2+11] = 0;
3614 Cmd[-2+12] = 0;
3615 Cmd[-2+13] = 0;
3616 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Gb));
3617 } else {
3618 /* First set GMT offset to zero */
3619
3620 oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
3621
3622 memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
3623 Cmd[-2+4] = tm->tm_mon + 1;
3624 Cmd[-2+5] = tm->tm_mday;
3625 Cmd[-2+6] = (1900+tm->tm_year)/256;
3626 Cmd[-2+7] = (1900+tm->tm_year)%256;
3627 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ac));
3628
3629 memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
3630 Cmd[-2+4] = tm->tm_hour;
3631 Cmd[-2+5] = tm->tm_min;
3632 Cmd[-2+6] = tm->tm_sec;
3633 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Aa));
3634 }
3635
3636 oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac");
3637 }
3638
3639
3640
3641 /* Almanac data input */
3642
3643 static void
oncore_print_Cb(struct instance * instance,u_char * cp)3644 oncore_print_Cb(
3645 struct instance *instance,
3646 u_char *cp
3647 )
3648 {
3649 #ifdef ONCORE_VERBOSE_CB
3650 int ii;
3651 char Msg[160], Msg2[10];
3652
3653 oncore_log_f(instance, LOG_DEBUG, "DEBUG: See: %c%c%c%c", *(cp),
3654 *(cp+1), *(cp+2), *(cp+3));
3655
3656 snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4),
3657 *(cp+5));
3658 for (ii = 0; ii < 33; ii++) {
3659 snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii));
3660 strlcat(Msg, Msg2, sizeof(Msg));
3661 }
3662 oncore_log(instance, LOG_DEBUG, Msg);
3663
3664 oncore_log_f(instance, LOG_DEBUG, "Debug: Cb: [%d,%d]", *(cp+4),
3665 *(cp+5));
3666 #endif
3667 }
3668
3669
3670 #if 0
3671 static void
oncore_print_array(u_char * cp,int n)3672 oncore_print_array(
3673 u_char *cp,
3674 int n
3675 )
3676 {
3677 int jj, i, j, nn;
3678
3679 nn = 0;
3680 printf("\nTOP\n");
3681 jj = n/16;
3682 for (j=0; j<jj; j++) {
3683 printf("%4d: ", nn);
3684 nn += 16;
3685 for (i=0; i<16; i++)
3686 printf(" %o", *cp++);
3687 printf("\n");
3688 }
3689 }
3690 #endif
3691
3692
3693 static void
oncore_print_posn(struct instance * instance)3694 oncore_print_posn(
3695 struct instance *instance
3696 )
3697 {
3698 char ew, ns;
3699 double xd, xm, xs, yd, ym, ys, hm, hft;
3700 int idx, idy, is, imx, imy;
3701 long lat, lon;
3702
3703 oncore_log(instance, LOG_INFO, "Posn:");
3704 ew = 'E';
3705 lon = instance->ss_long;
3706 if (lon < 0) {
3707 ew = 'W';
3708 lon = -lon;
3709 }
3710
3711 ns = 'N';
3712 lat = instance->ss_lat;
3713 if (lat < 0) {
3714 ns = 'S';
3715 lat = -lat;
3716 }
3717
3718 hm = instance->ss_ht/100.;
3719 hft= hm/0.3048;
3720
3721 xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */
3722 yd = lon/3600000.;
3723 oncore_log_f(instance, LOG_INFO,
3724 "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS",
3725 ns, xd, ew, yd, hm, hft);
3726
3727 idx = xd;
3728 idy = yd;
3729 imx = lat%3600000;
3730 imy = lon%3600000;
3731 xm = imx/60000.;
3732 ym = imy/60000.;
3733 oncore_log_f(instance, LOG_INFO,
3734 "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS",
3735 ns, idx, xm, ew, idy, ym, hm, hft);
3736
3737 imx = xm;
3738 imy = ym;
3739 is = lat%60000;
3740 xs = is/1000.;
3741 is = lon%60000;
3742 ys = is/1000.;
3743 oncore_log_f(instance, LOG_INFO,
3744 "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS",
3745 ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
3746 }
3747
3748
3749
3750 /*
3751 * write message to Oncore.
3752 */
3753
3754 static void
oncore_sendmsg(struct instance * instance,u_char * ptr,size_t len)3755 oncore_sendmsg(
3756 struct instance *instance,
3757 u_char *ptr,
3758 size_t len
3759 )
3760 {
3761 int fd;
3762 u_char cs = 0;
3763
3764 fd = instance->ttyfd;
3765 #ifdef ONCORE_VERBOSE_SENDMSG
3766 if (debug > 4) {
3767 oncore_log_f(instance, LOG_DEBUG, "ONCORE: Send @@%c%c %d",
3768 ptr[0], ptr[1], (int)len);
3769 }
3770 #endif
3771 write(fd, "@@", (size_t) 2);
3772 write(fd, ptr, len);
3773 while (len--)
3774 cs ^= *ptr++;
3775 write(fd, &cs, (size_t) 1);
3776 write(fd, "\r\n", (size_t) 2);
3777 }
3778
3779
3780
3781 static void
oncore_set_posn(struct instance * instance)3782 oncore_set_posn(
3783 struct instance *instance
3784 )
3785 {
3786 int mode;
3787 u_char Cmd[20];
3788
3789 /* Turn OFF position hold, it needs to be off to set position (for some units),
3790 will get set ON in @@Ea later */
3791
3792 if (instance->chan == 12)
3793 oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
3794 else {
3795 oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
3796 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
3797 }
3798
3799 mode = instance->init_type;
3800
3801 if (mode != 0) { /* first set posn hold position */
3802 memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */
3803 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3804 w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3805 w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
3806 Cmd[-2+16] = 0;
3807 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */
3808
3809 memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
3810 w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3811 Cmd[-2+8] = 0;
3812 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */
3813
3814 /* next set current position */
3815
3816 if (instance->chan == 12) {
3817 memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
3818 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3819 w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3820 w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
3821 Cmd[-2+16] = 0;
3822 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */
3823 } else {
3824 memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
3825 w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3826 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */
3827
3828 memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
3829 w32_buf(&Cmd[-2+4], (int) instance->ss_long);
3830 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */
3831
3832 memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
3833 w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3834 Cmd[-2+8] = 0;
3835 oncore_sendmsg(instance, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */
3836 }
3837
3838 /* Finally, turn on position hold */
3839
3840 if (instance->chan == 12)
3841 oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
3842 else
3843 oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1));
3844 }
3845 }
3846
3847
3848
3849 static void
oncore_set_traim(struct instance * instance)3850 oncore_set_traim(
3851 struct instance *instance
3852 )
3853 {
3854 if (instance->traim_in != -1) /* set in Input */
3855 instance->traim = instance->traim_in;
3856 else
3857 instance->traim = instance->traim_ck;
3858
3859 oncore_log_f(instance, LOG_INFO, "Input says TRAIM = %d",
3860 instance->traim_in);
3861 oncore_log_f(instance, LOG_INFO, "Model # says TRAIM = %d",
3862 instance->traim_id);
3863 oncore_log_f(instance, LOG_INFO, "Testing says TRAIM = %d",
3864 instance->traim_ck);
3865 oncore_log_f(instance, LOG_INFO, "Using TRAIM = %d",
3866 instance->traim);
3867
3868 if (instance->traim_ck == 1 && instance->traim == 0) {
3869 /* if it should be off, and I turned it on during testing,
3870 then turn it off again */
3871 if (instance->chan == 6)
3872 oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
3873 else if (instance->chan == 8)
3874 oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
3875 else /* chan == 12 */
3876 oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
3877 oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
3878 }
3879 }
3880
3881
3882
3883 /*
3884 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
3885 */
3886
3887 static void
oncore_shmem_get_3D(struct instance * instance)3888 oncore_shmem_get_3D(
3889 struct instance *instance
3890 )
3891 {
3892 if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */
3893 instance->shmem_reset = 1;
3894 if (instance->chan == 12) {
3895 if (instance->shmem_Posn == 2)
3896 oncore_sendmsg(instance, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */
3897 else
3898 oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */
3899 } else {
3900 if (instance->saw_At) { /* out of 0D -> 3D mode */
3901 oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0));
3902 if (instance->shmem_Posn == 2) /* 3D -> 2D mode */
3903 oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3904 } else
3905 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3906 }
3907 } else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
3908 instance->shmem_reset = 0;
3909 if (instance->chan == 12)
3910 oncore_sendmsg(instance, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */
3911 else {
3912 if (instance->saw_At) {
3913 if (instance->mode == MODE_2D) /* 2D -> 3D or 0D mode */
3914 oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3915 oncore_sendmsg(instance, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */
3916 } else
3917 oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3918 }
3919 }
3920 }
3921
3922
3923
3924 /*
3925 * Here we do the Software SiteSurvey.
3926 * We have to average our own position for the Position Hold Mode
3927 * We use Heights from the GPS ellipsoid.
3928 * We check for the END of either HW or SW SiteSurvey.
3929 */
3930
3931 static void
oncore_ss(struct instance * instance)3932 oncore_ss(
3933 struct instance *instance
3934 )
3935 {
3936 double lat, lon, ht;
3937
3938
3939 if (instance->site_survey == ONCORE_SS_HW) {
3940 /*
3941 * Check to see if Hardware SiteSurvey has Finished.
3942 */
3943
3944 if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) ||
3945 (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
3946 oncore_log(instance, LOG_INFO, "Now in 0D mode");
3947
3948 if (instance->chan == 12)
3949 oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
3950 else
3951 oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
3952
3953 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
3954 instance->site_survey = ONCORE_SS_DONE;
3955 }
3956 } else {
3957 /*
3958 * Must be a Software Site Survey.
3959 */
3960
3961 if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */
3962 return;
3963
3964 if (instance->mode != MODE_3D) /* Use only 3D Fixes */
3965 return;
3966
3967 instance->ss_lat += buf_w32(&instance->BEHa[15]);
3968 instance->ss_long += buf_w32(&instance->BEHa[19]);
3969 instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */
3970 instance->ss_count++;
3971
3972 if (instance->ss_count != POS_HOLD_AVERAGE)
3973 return;
3974
3975 instance->ss_lat /= POS_HOLD_AVERAGE;
3976 instance->ss_long /= POS_HOLD_AVERAGE;
3977 instance->ss_ht /= POS_HOLD_AVERAGE;
3978
3979 oncore_log_f(instance, LOG_NOTICE,
3980 "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
3981 instance->ss_lat, instance->ss_long,
3982 instance->ss_ht);
3983 lat = instance->ss_lat/3600000.;
3984 lon = instance->ss_long/3600000.;
3985 ht = instance->ss_ht/100;
3986 oncore_log_f(instance, LOG_NOTICE,
3987 "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
3988 lat, lon, ht);
3989
3990 oncore_set_posn(instance);
3991
3992 oncore_log(instance, LOG_INFO, "Now in 0D mode");
3993
3994 oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
3995 instance->site_survey = ONCORE_SS_DONE;
3996 }
3997 }
3998
3999
4000
4001 static int
oncore_wait_almanac(struct instance * instance)4002 oncore_wait_almanac(
4003 struct instance *instance
4004 )
4005 {
4006 if (instance->rsm.bad_almanac) {
4007 instance->counta++;
4008 if (instance->counta%5 == 0)
4009 oncore_log(instance, LOG_INFO, "Waiting for Almanac");
4010
4011 /*
4012 * If we get here (first time) then we don't have an almanac in memory.
4013 * Check if we have a SHMEM, and if so try to load whatever is there.
4014 */
4015
4016 if (!instance->almanac_from_shmem) {
4017 instance->almanac_from_shmem = 1;
4018 oncore_load_almanac(instance);
4019 }
4020 return(1);
4021 } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
4022 commands, and can finally check for TRAIM. Again, we set a delay
4023 (5sec) and wait for things to settle down */
4024
4025 if (instance->chan == 6)
4026 oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
4027 else if (instance->chan == 8)
4028 oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En));
4029 else if (instance->chan == 12) {
4030 oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
4031 oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
4032 oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
4033 }
4034 instance->traim_delay = 1;
4035
4036 oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC");
4037
4038 instance->o_state = ONCORE_RUN;
4039 oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN");
4040 }
4041 return(0);
4042 }
4043
4044
4045 static void
oncore_feed_clockproc(struct instance * instance)4046 oncore_feed_clockproc(
4047 struct instance * instance
4048 )
4049 {
4050 struct peer * const peer = instance->peer;
4051 struct refclockproc * const pp = instance->pp;
4052
4053 TCivilDate cd; /* calendar date + time */
4054 TGpsDatum gd; /* GPS datum, remapped into NTP epoch */
4055 l_fp fp; /* the reference time in NTP format */
4056
4057 if (pp->year >= 1980) {
4058 /* There are oncore receivers that run in a fixed
4059 * (possibly shifted) GPS era and fold back into that
4060 * era on every GPS week rollover.
4061 *
4062 * We do not trust the date we get and remap to a GPS
4063 * era defined by the GPS base date (derived from the
4064 * build time stamp or a 'tos basedate' config option.
4065 */
4066 ZERO(fp); /* has a zero to begin with */
4067 ZERO(cd); /* month == monthday == 0 -> use year+yearday */
4068 cd.year = pp->year;
4069 cd.yearday = pp->day;
4070 cd.hour = pp->hour;
4071 cd.minute = pp->minute;
4072 cd.second = pp->second;
4073
4074 /* the magic happens in the next line: */
4075 gd = gpscal_from_calendar(&cd, fp); /* fp should be zero here */
4076
4077 /* To avoid the trouble the day-of-year calculations in
4078 * 'refclock_process()' can cause we feed the time
4079 * stamps we have now directly. This also saves us two
4080 * full calendar calendar conversion cycles.
4081 */
4082 fp = ntpfp_from_gpsdatum(&gd);
4083 refclock_process_offset(pp, fp, pp->lastrec, pp->fudgetime1);
4084 } else {
4085 /* This is obviously a bad date/time... */
4086 refclock_report(peer, CEVNT_BADDATE);
4087 peer->flags &= ~FLAG_PPS; /* problem - clear PPS FLAG */
4088 return;
4089 }
4090 }
4091
4092 static void
oncore_log(struct instance * instance,int log_level,const char * msg)4093 oncore_log (
4094 struct instance *instance,
4095 int log_level,
4096 const char *msg
4097 )
4098 {
4099 msyslog(log_level, "ONCORE[%d]: %s", instance->unit, msg);
4100 mprintf_clock_stats(&instance->peer->srcadr, "ONCORE[%d]: %s",
4101 instance->unit, msg);
4102 }
4103
4104
4105 static int
oncore_log_f(struct instance * instance,int log_level,const char * fmt,...)4106 oncore_log_f(
4107 struct instance * instance,
4108 int log_level,
4109 const char * fmt,
4110 ...
4111 )
4112 {
4113 va_list ap;
4114 int rc;
4115 char msg[512];
4116
4117 va_start(ap, fmt);
4118 rc = mvsnprintf(msg, sizeof(msg), fmt, ap);
4119 va_end(ap);
4120 oncore_log(instance, log_level, msg);
4121
4122 #ifdef ONCORE_VERBOSE_ONCORE_LOG
4123 instance->max_len = max(strlen(msg), instance->max_len);
4124 instance->max_count++;
4125 if (instance->max_count % 100 == 0)
4126 oncore_log_f(instance, LOG_INFO,
4127 "Max Message Length so far is %d",
4128 instance->max_len);
4129 #endif
4130 return rc;
4131 }
4132
4133 #else
4134 int refclock_oncore_bs;
4135 #endif /* REFCLOCK && CLOCK_ONCORE */
4136