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