/contrib/ntp/ntpd/refclock_oncore.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 3732 lines · 2485 code · 595 blank · 652 comment · 705 complexity · c5431bce34bce5c87b214f45f81694fc MD5 · raw file

Large files are truncated click here to view the full file

  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 (Feb 2006)
  56. * Fix some gcc4 compiler complaints
  57. * Fix possible segfault in oncore_init_shmem
  58. * change all (possible) fprintf(stderr, to record_clock_stats
  59. * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
  60. * immediately after new Almanac Read.
  61. * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
  62. * now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
  63. * the new one. Compiles depending on timepps.h seen.
  64. * --------------------------------------------------------------------------
  65. * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
  66. * (the oncore driver was setting the wrong ntpd variable)
  67. * --------------------------------------------------------------------------
  68. * Reg.Clemens (Mar 2004)
  69. * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
  70. * SCO, you now need to use one of the timepps.h files in the root dir.
  71. * this driver will 'grab' it for you if you dont have one in /usr/include
  72. * --------------------------------------------------------------------------
  73. * This code uses the two devices
  74. * /dev/oncore.serial.n
  75. * /dev/oncore.pps.n
  76. * which may be linked to the same device.
  77. * and can read initialization data from the file
  78. * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
  79. * n or N are the unit number, viz 127.127.30.N.
  80. * --------------------------------------------------------------------------
  81. * Reg.Clemens <reg@dwf.com> Sep98.
  82. * Original code written for FreeBSD.
  83. * With these mods it works on FreeBSD, SunOS, Solaris and Linux
  84. * (SunOS 4.1.3 + ppsclock)
  85. * (Solaris7 + MU4)
  86. * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
  87. *
  88. * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
  89. * state machine state) are printed to CLOCKSTATS if that file is enabled
  90. * in /etc/ntp.conf.
  91. *
  92. * --------------------------------------------------------------------------
  93. *
  94. * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
  95. * doing an average of 10000 valid 2D and 3D fixes is what the automatic
  96. * site survey mode does. Looking at the output from the receiver
  97. * it seems like it is only using 3D fixes.
  98. * When we do it ourselves, take 10000 3D fixes.
  99. */
  100. #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */
  101. /*
  102. * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
  103. * "STATUS" line in the oncore config file, which contains the most recent
  104. * copy of all types of messages we recognize. This file can be mmap(2)'ed
  105. * by monitoring and statistics programs.
  106. *
  107. * See separate HTML documentation for this option.
  108. */
  109. #ifdef HAVE_CONFIG_H
  110. #include <config.h>
  111. #endif
  112. #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
  113. #include "ntpd.h"
  114. #include "ntp_io.h"
  115. #include "ntp_unixtime.h"
  116. #include "ntp_refclock.h"
  117. #include "ntp_stdlib.h"
  118. #include <stdio.h>
  119. #include <ctype.h>
  120. #include <sys/stat.h>
  121. #ifdef ONCORE_SHMEM_STATUS
  122. # ifdef HAVE_SYS_MMAN_H
  123. # include <sys/mman.h>
  124. # ifndef MAP_FAILED
  125. # define MAP_FAILED ((u_char *) -1)
  126. # endif /* MAP_FAILED */
  127. # endif /* HAVE_SYS_MMAN_H */
  128. #endif /* ONCORE_SHMEM_STATUS */
  129. #ifdef HAVE_PPSAPI
  130. # include "ppsapi_timepps.h"
  131. #endif
  132. #ifdef HAVE_SYS_SIO_H
  133. # include <sys/sio.h>
  134. #endif
  135. enum receive_state {
  136. ONCORE_NO_IDEA,
  137. ONCORE_CHECK_ID,
  138. ONCORE_CHECK_CHAN,
  139. ONCORE_HAVE_CHAN,
  140. ONCORE_RESET_SENT,
  141. ONCORE_TEST_SENT,
  142. ONCORE_INIT,
  143. ONCORE_ALMANAC,
  144. ONCORE_RUN
  145. };
  146. enum site_survey_state {
  147. ONCORE_SS_UNKNOWN,
  148. ONCORE_SS_TESTING,
  149. ONCORE_SS_HW,
  150. ONCORE_SS_SW,
  151. ONCORE_SS_DONE
  152. };
  153. enum antenna_state {
  154. ONCORE_ANTENNA_UNKNOWN = -1,
  155. ONCORE_ANTENNA_OK = 0,
  156. ONCORE_ANTENNA_OC = 1,
  157. ONCORE_ANTENNA_UC = 2,
  158. ONCORE_ANTENNA_NV = 3
  159. };
  160. /* Model Name, derived from the @@Cj message.
  161. * Used to initialize some variables.
  162. */
  163. enum oncore_model {
  164. ONCORE_BASIC,
  165. ONCORE_PVT6,
  166. ONCORE_VP,
  167. ONCORE_UT,
  168. ONCORE_UTPLUS,
  169. ONCORE_GT,
  170. ONCORE_GTPLUS,
  171. ONCORE_SL,
  172. ONCORE_M12,
  173. ONCORE_UNKNOWN
  174. };
  175. /* the bits that describe these properties are in the same place
  176. * on the VP/UT, but have moved on the M12. As such we extract
  177. * them, and use them from this struct.
  178. *
  179. */
  180. struct RSM {
  181. u_char posn0D;
  182. u_char posn2D;
  183. u_char posn3D;
  184. u_char bad_almanac;
  185. u_char bad_fix;
  186. };
  187. /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
  188. * see what mode it is in. The bits on the M12 are multiplexed with
  189. * other messages, so we have to 'keep' the last known mode here.
  190. */
  191. enum posn_mode {
  192. MODE_UNKNOWN,
  193. MODE_0D,
  194. MODE_2D,
  195. MODE_3D
  196. };
  197. struct instance {
  198. int unit; /* 127.127.30.unit */
  199. struct refclockproc *pp;
  200. struct peer *peer;
  201. int ttyfd; /* TTY file descriptor */
  202. int ppsfd; /* PPS file descriptor */
  203. int shmemfd; /* Status shm descriptor */
  204. pps_handle_t pps_h;
  205. pps_params_t pps_p;
  206. enum receive_state o_state; /* Receive state */
  207. enum posn_mode mode; /* 0D, 2D, 3D */
  208. enum site_survey_state site_survey; /* Site Survey state */
  209. enum antenna_state ant_state; /* antenna state */
  210. int Bj_day;
  211. u_long delay; /* ns */
  212. long offset; /* ns */
  213. u_char *shmem;
  214. char *shmem_fname;
  215. u_int shmem_Cb;
  216. u_int shmem_Ba;
  217. u_int shmem_Ea;
  218. u_int shmem_Ha;
  219. u_char shmem_reset;
  220. u_char shmem_Posn;
  221. u_char shmem_bad_Ea;
  222. u_char almanac_from_shmem;
  223. double ss_lat;
  224. double ss_long;
  225. double ss_ht;
  226. double dH;
  227. int ss_count;
  228. u_char posn_set;
  229. enum oncore_model model;
  230. u_int version;
  231. u_int revision;
  232. u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
  233. s_char traim; /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
  234. /* the following 7 are all timing counters */
  235. u_char traim_delay; /* seconds counter, waiting for reply */
  236. u_char count; /* cycles thru Ea before starting */
  237. u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */
  238. u_char count2; /* cycles thru Ea after count, to check for @@Ea */
  239. u_char count3; /* cycles thru Ea checking for # channels */
  240. u_char count4; /* cycles thru leap after Gj to issue Bj */
  241. u_char count5; /* cycles thru get_timestamp waiting for valid UTC correction */
  242. u_char count5_set; /* only set count5 once */
  243. u_char pollcnt;
  244. u_char timeout; /* count to retry Cj after Fa self-test */
  245. struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */
  246. u_char printed;
  247. u_char polled;
  248. u_long ev_serial;
  249. int Rcvptr;
  250. u_char Rcvbuf[500];
  251. u_char BEHa[160]; /* Ba, Ea or Ha */
  252. u_char BEHn[80]; /* Bn , En , or Hn */
  253. u_char Cj[300];
  254. u_char Ag; /* Satellite mask angle */
  255. u_char saw_At;
  256. u_char saw_Ay;
  257. u_char saw_Az;
  258. s_char saw_Gj;
  259. u_char have_dH;
  260. u_char init_type;
  261. s_char saw_tooth;
  262. s_char chan_in; /* chan number from INPUT, will always use it */
  263. u_char chan_id; /* chan number determined from part number */
  264. u_char chan_ck; /* chan number determined by sending commands to hardware */
  265. s_char traim_in; /* TRAIM from INPUT, will always use ON/OFF specified */
  266. s_char traim_id; /* TRAIM determined from part number */
  267. u_char traim_ck; /* TRAIM determined by sending commands to hardware */
  268. u_char once; /* one pass code at top of BaEaHa */
  269. s_char assert;
  270. u_char hardpps;
  271. };
  272. #define rcvbuf instance->Rcvbuf
  273. #define rcvptr instance->Rcvptr
  274. static int oncore_start P((int, struct peer *));
  275. static void oncore_poll P((int, struct peer *));
  276. static void oncore_shutdown P((int, struct peer *));
  277. static void oncore_consume P((struct instance *));
  278. static void oncore_read_config P((struct instance *));
  279. static void oncore_receive P((struct recvbuf *));
  280. static int oncore_ppsapi P((struct instance *));
  281. static void oncore_get_timestamp P((struct instance *, long, long));
  282. static void oncore_init_shmem P((struct instance *));
  283. static void oncore_antenna_report P((struct instance *, enum antenna_state));
  284. static void oncore_chan_test P((struct instance *));
  285. static void oncore_check_almanac P((struct instance *));
  286. static void oncore_check_antenna P((struct instance *));
  287. static void oncore_check_leap_sec P((struct instance *));
  288. static int oncore_checksum_ok P((u_char *, int));
  289. static void oncore_compute_dH P((struct instance *));
  290. static void oncore_load_almanac P((struct instance *));
  291. static void oncore_print_Cb P((struct instance *, u_char *));
  292. /* static void oncore_print_array P((u_char *, int)); */
  293. static void oncore_print_posn P((struct instance *));
  294. static void oncore_sendmsg P((int, u_char *, size_t));
  295. static void oncore_set_posn P((struct instance *));
  296. static void oncore_set_traim P((struct instance *));
  297. static void oncore_shmem_get_3D P((struct instance *));
  298. static void oncore_ss P((struct instance *));
  299. static int oncore_wait_almanac P((struct instance *));
  300. static void oncore_msg_any P((struct instance *, u_char *, size_t, int));
  301. static void oncore_msg_Adef P((struct instance *, u_char *, size_t));
  302. static void oncore_msg_Ag P((struct instance *, u_char *, size_t));
  303. static void oncore_msg_As P((struct instance *, u_char *, size_t));
  304. static void oncore_msg_At P((struct instance *, u_char *, size_t));
  305. static void oncore_msg_Ay P((struct instance *, u_char *, size_t));
  306. static void oncore_msg_Az P((struct instance *, u_char *, size_t));
  307. static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t));
  308. static void oncore_msg_Bd P((struct instance *, u_char *, size_t));
  309. static void oncore_msg_Bj P((struct instance *, u_char *, size_t));
  310. static void oncore_msg_BnEnHn P((struct instance *, u_char *, size_t));
  311. static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t));
  312. static void oncore_msg_Cb P((struct instance *, u_char *, size_t));
  313. static void oncore_msg_Cf P((struct instance *, u_char *, size_t));
  314. static void oncore_msg_Cj P((struct instance *, u_char *, size_t));
  315. static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t));
  316. static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
  317. static void oncore_msg_Ga P((struct instance *, u_char *, size_t));
  318. static void oncore_msg_Gb P((struct instance *, u_char *, size_t));
  319. static void oncore_msg_Gj P((struct instance *, u_char *, size_t));
  320. static void oncore_msg_Sz P((struct instance *, u_char *, size_t));
  321. struct refclock refclock_oncore = {
  322. oncore_start, /* start up driver */
  323. oncore_shutdown, /* shut down driver */
  324. oncore_poll, /* transmit poll message */
  325. noentry, /* not used */
  326. noentry, /* not used */
  327. noentry, /* not used */
  328. NOFLAGS /* not used */
  329. };
  330. /*
  331. * Understanding the next bit here is not easy unless you have a manual
  332. * for the the various Oncore Models.
  333. */
  334. static struct msg_desc {
  335. const char flag[3];
  336. const int len;
  337. void (*handler) P((struct instance *, u_char *, size_t));
  338. const char *fmt;
  339. int shmem;
  340. } oncore_messages[] = {
  341. /* Ea and En first since they're most common */
  342. { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
  343. { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
  344. { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
  345. { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
  346. { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
  347. { "Hn", 78, oncore_msg_BnEnHn, "" },
  348. { "Ab", 10, 0, "" },
  349. { "Ac", 11, 0, "" },
  350. { "Ad", 11, oncore_msg_Adef, "" },
  351. { "Ae", 11, oncore_msg_Adef, "" },
  352. { "Af", 15, oncore_msg_Adef, "" },
  353. { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */
  354. { "As", 20, oncore_msg_As, "" },
  355. { "At", 8, oncore_msg_At, "" },
  356. { "Au", 12, 0, "" },
  357. { "Av", 8, 0, "" },
  358. { "Aw", 8, 0, "" },
  359. { "Ay", 11, oncore_msg_Ay, "" },
  360. { "Az", 11, oncore_msg_Az, "" },
  361. { "AB", 8, 0, "" },
  362. { "Bb", 92, 0, "" },
  363. { "Bd", 23, oncore_msg_Bd, "" },
  364. { "Bj", 8, oncore_msg_Bj, "" },
  365. { "Ca", 9, oncore_msg_CaFaIa, "" },
  366. { "Cb", 33, oncore_msg_Cb, "" },
  367. { "Cf", 7, oncore_msg_Cf, "" },
  368. { "Cg", 8, 0, "" },
  369. { "Ch", 9, 0, "" },
  370. { "Cj", 294, oncore_msg_Cj, "" },
  371. { "Ek", 71, 0, "" },
  372. { "Fa", 9, oncore_msg_CaFaIa, "" },
  373. { "Ga", 20, oncore_msg_Ga, "" },
  374. { "Gb", 17, oncore_msg_Gb, "" },
  375. { "Gc", 8, 0, "" },
  376. { "Gd", 8, 0, "" },
  377. { "Ge", 8, 0, "" },
  378. { "Gj", 21, oncore_msg_Gj, "" },
  379. { "Ia", 10, oncore_msg_CaFaIa, "" },
  380. { "Sz", 8, oncore_msg_Sz, "" },
  381. { {0}, 7, 0, "" }
  382. };
  383. static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */
  384. static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */
  385. static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */
  386. static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */
  387. static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */
  388. static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */
  389. static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */
  390. static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */
  391. static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */
  392. 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 */
  393. static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */
  394. 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */
  395. 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */
  396. static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */
  397. static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */
  398. static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */
  399. static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */
  400. static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */
  401. static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */
  402. static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */
  403. static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */
  404. static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */
  405. static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */
  406. static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */
  407. static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */
  408. static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */
  409. static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */
  410. static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */
  411. static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */
  412. static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */
  413. static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */
  414. 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 */
  415. 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 */
  416. 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 */
  417. static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */
  418. static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */
  419. static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */
  420. static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */
  421. static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */
  422. static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */
  423. static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */
  424. 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 */
  425. 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 */
  426. 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 */
  427. static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */
  428. static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */
  429. static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */
  430. 0xff, 0xff, 0xff, 0xff, /* */
  431. 0xff, 0xff, 0xff, 0xff, 0xff }; /* */
  432. static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */
  433. static u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */
  434. static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */
  435. static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */
  436. static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */
  437. static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */
  438. static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */
  439. static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */
  440. static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */
  441. static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */
  442. static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */
  443. static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */
  444. static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */
  445. static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */
  446. /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
  447. * the GT had Au,Av, but not As,At
  448. * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
  449. * Bj in UT at v1.3
  450. * dont see Bd in UT/GT thru 1999
  451. * Gj in UT as of 3.0, 1999 , Bj as of 1.3
  452. */
  453. static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
  454. "Aug", "Sep", "Oct", "Nov", "Dec" };
  455. #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */
  456. #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */
  457. #define SPEED B9600 /* Oncore Binary speed (9600 bps) */
  458. /*
  459. * Assemble and disassemble 32bit signed quantities from a buffer.
  460. *
  461. */
  462. /* to buffer, int w, u_char *buf */
  463. #define w32_buf(buf,w) { u_int i_tmp; \
  464. i_tmp = (w<0) ? (~(-w)+1) : (w); \
  465. (buf)[0] = (i_tmp >> 24) & 0xff; \
  466. (buf)[1] = (i_tmp >> 16) & 0xff; \
  467. (buf)[2] = (i_tmp >> 8) & 0xff; \
  468. (buf)[3] = (i_tmp ) & 0xff; \
  469. }
  470. #define w32(buf) (((buf)[0]&0xff) << 24 | \
  471. ((buf)[1]&0xff) << 16 | \
  472. ((buf)[2]&0xff) << 8 | \
  473. ((buf)[3]&0xff) )
  474. /* from buffer, char *buf, result to an int */
  475. #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
  476. /*
  477. * oncore_start - initialize data for processing
  478. */
  479. static int
  480. oncore_start(
  481. int unit,
  482. struct peer *peer
  483. )
  484. {
  485. #define STRING_LEN 32
  486. register struct instance *instance;
  487. struct refclockproc *pp;
  488. int fd1, fd2, num;
  489. char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
  490. const char *cp;
  491. struct stat stat1, stat2;
  492. /* create instance structure for this unit */
  493. if (!(instance = (struct instance *) malloc(sizeof *instance))) {
  494. perror("malloc");
  495. return (0);
  496. }
  497. memset((char *) instance, 0, sizeof *instance);
  498. /* initialize miscellaneous variables */
  499. pp = peer->procptr;
  500. pp->unitptr = (caddr_t) instance;
  501. instance->pp = pp;
  502. instance->unit = unit;
  503. instance->peer = peer;
  504. instance->assert = 1;
  505. instance->once = 1;
  506. instance->Bj_day = -1;
  507. instance->traim = -1;
  508. instance->traim_in = -1;
  509. instance->chan_in = -1;
  510. instance->model = ONCORE_UNKNOWN;
  511. instance->mode = MODE_UNKNOWN;
  512. instance->site_survey = ONCORE_SS_UNKNOWN;
  513. instance->Ag = 0xff; /* Satellite mask angle, unset by user */
  514. instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
  515. peer->precision = -26;
  516. peer->minpoll = 4;
  517. peer->maxpoll = 4;
  518. pp->clockdesc = "Motorola Oncore GPS Receiver";
  519. memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
  520. cp = "ONCORE DRIVER -- CONFIGURING";
  521. record_clock_stats(&(instance->peer->srcadr), cp);
  522. instance->o_state = ONCORE_NO_IDEA;
  523. cp = "state = ONCORE_NO_IDEA";
  524. record_clock_stats(&(instance->peer->srcadr), cp);
  525. /* Now open files.
  526. * This is a bit complicated, a we dont want to open the same file twice
  527. * (its a problem on some OS), and device2 may not exist for the new PPS
  528. */
  529. (void)sprintf(device1, DEVICE1, unit);
  530. (void)sprintf(device2, DEVICE2, unit);
  531. /* OPEN DEVICES */
  532. /* opening different devices for fd1 and fd2 presents no problems */
  533. /* opening the SAME device twice, seems to be OS dependent.
  534. (a) on Linux (no streams) no problem
  535. (b) on SunOS (and possibly Solaris, untested), (streams)
  536. never see the line discipline.
  537. Since things ALWAYS work if we only open the device once, we check
  538. to see if the two devices are in fact the same, then proceed to
  539. do one open or two.
  540. */
  541. if (stat(device1, &stat1)) {
  542. sprintf(Msg, "Can't stat fd1 (%s)\n", device1);
  543. record_clock_stats(&(instance->peer->srcadr), Msg);
  544. exit(1);
  545. }
  546. if (stat(device2, &stat2)) {
  547. sprintf(Msg, "Can't stat fd2 (%s)\n", device2);
  548. record_clock_stats(&(instance->peer->srcadr), Msg);
  549. exit(1);
  550. }
  551. if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
  552. sprintf(Msg, "Can't open fd1 (%s)\n", device1);
  553. record_clock_stats(&(instance->peer->srcadr), Msg);
  554. exit(1);
  555. }
  556. if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) /* same device here */
  557. fd2 = fd1;
  558. else { /* different devices here */
  559. if ((fd2=open(device2, O_RDWR)) < 0) {
  560. sprintf(Msg, "Can't open fd2 (%s)\n", device2);
  561. record_clock_stats(&(instance->peer->srcadr), Msg);
  562. exit(1);
  563. }
  564. }
  565. num = fd2;
  566. /* open ppsapi soure */
  567. if (time_pps_create(num, &instance->pps_h) < 0) {
  568. record_clock_stats(&(instance->peer->srcadr), "PPSAPI not found in kernel");
  569. return(0);
  570. }
  571. /* continue initialization */
  572. instance->ttyfd = fd1;
  573. instance->ppsfd = fd2;
  574. /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
  575. oncore_read_config(instance);
  576. if (!oncore_ppsapi(instance))
  577. return(0);
  578. pp->io.clock_recv = oncore_receive;
  579. pp->io.srcclock = (caddr_t)peer;
  580. pp->io.datalen = 0;
  581. pp->io.fd = fd1;
  582. if (!io_addclock(&pp->io)) {
  583. record_clock_stats(&(instance->peer->srcadr), "ONCORE: io_addclock");
  584. (void) close(fd1);
  585. free(instance);
  586. return (0);
  587. }
  588. #ifdef ONCORE_SHMEM_STATUS
  589. /*
  590. * Before starting ONCORE, lets setup SHMEM
  591. * This will include merging an old SHMEM into the new one if
  592. * an old one is found.
  593. */
  594. oncore_init_shmem(instance);
  595. #endif
  596. /*
  597. * This will return the Model of the Oncore receiver.
  598. * and start the Initialization loop in oncore_msg_Cj.
  599. */
  600. instance->o_state = ONCORE_CHECK_ID;
  601. cp = "state = ONCORE_CHECK_ID";
  602. record_clock_stats(&(instance->peer->srcadr), cp);
  603. instance->timeout = 4;
  604. oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
  605. oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
  606. instance->pollcnt = 2;
  607. return (1);
  608. }
  609. /*
  610. * oncore_shutdown - shut down the clock
  611. */
  612. static void
  613. oncore_shutdown(
  614. int unit,
  615. struct peer *peer
  616. )
  617. {
  618. register struct instance *instance;
  619. struct refclockproc *pp;
  620. pp = peer->procptr;
  621. instance = (struct instance *) pp->unitptr;
  622. io_closeclock(&pp->io);
  623. time_pps_destroy (instance->pps_h);
  624. close(instance->ttyfd);
  625. if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
  626. close(instance->ppsfd);
  627. if (instance->shmemfd)
  628. close(instance->shmemfd);
  629. free(instance);
  630. }
  631. /*
  632. * oncore_poll - called by the transmit procedure
  633. */
  634. static void
  635. oncore_poll(
  636. int unit,
  637. struct peer *peer
  638. )
  639. {
  640. struct instance *instance;
  641. instance = (struct instance *) peer->procptr->unitptr;
  642. if (instance->timeout) {
  643. char *cp;
  644. instance->timeout--;
  645. if (instance->timeout == 0) {
  646. cp = "Oncore: No response from @@Cj, shutting down driver";
  647. record_clock_stats(&(instance->peer->srcadr), cp);
  648. oncore_shutdown(unit, peer);
  649. } else {
  650. oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
  651. cp = "Oncore: Resend @@Cj";
  652. record_clock_stats(&(instance->peer->srcadr), cp);
  653. }
  654. return;
  655. }
  656. if (!instance->pollcnt)
  657. refclock_report(peer, CEVNT_TIMEOUT);
  658. else
  659. instance->pollcnt--;
  660. peer->procptr->polls++;
  661. instance->polled = 1;
  662. }
  663. /*
  664. * Initialize PPSAPI
  665. */
  666. static int
  667. oncore_ppsapi(
  668. struct instance *instance
  669. )
  670. {
  671. int cap, mode, mode1;
  672. char *cp, Msg[160];
  673. if (time_pps_getcap(instance->pps_h, &cap) < 0) {
  674. msyslog(LOG_ERR, "time_pps_getcap failed: %m");
  675. return (0);
  676. }
  677. if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
  678. msyslog(LOG_ERR, "time_pps_getparams failed: %m");
  679. return (0);
  680. }
  681. /* nb. only turn things on, if someone else has turned something
  682. * on before we get here, leave it alone!
  683. */
  684. if (instance->assert) {
  685. cp = "Assert.";
  686. mode = PPS_CAPTUREASSERT;
  687. mode1 = PPS_OFFSETASSERT;
  688. } else {
  689. cp = "Clear.";
  690. mode = PPS_CAPTURECLEAR;
  691. mode1 = PPS_OFFSETCLEAR;
  692. }
  693. sprintf(Msg, "Initializing timeing to %s.", cp);
  694. record_clock_stats(&(instance->peer->srcadr), Msg);
  695. if (!(mode & cap)) {
  696. sprintf(Msg, "Can't set timeing to %s, exiting...", cp);
  697. record_clock_stats(&(instance->peer->srcadr), Msg);
  698. return(0);
  699. }
  700. if (!(mode1 & cap)) {
  701. sprintf(Msg, "Can't set PPS_%sCLEAR, this will increase jitter.", cp);
  702. record_clock_stats(&(instance->peer->srcadr), Msg);
  703. mode1 = 0;
  704. }
  705. /* only set what is legal */
  706. instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
  707. if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
  708. record_clock_stats(&(instance->peer->srcadr), "ONCORE: time_pps_setparams fails");
  709. exit(1);
  710. }
  711. /* If HARDPPS is on, we tell kernel */
  712. if (instance->hardpps) {
  713. int i;
  714. record_clock_stats(&(instance->peer->srcadr), "HARDPPS Set.");
  715. if (instance->assert)
  716. i = PPS_CAPTUREASSERT;
  717. else
  718. i = PPS_CAPTURECLEAR;
  719. /* we know that 'i' is legal from above */
  720. if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
  721. PPS_TSFMT_TSPEC) < 0) {
  722. msyslog(LOG_ERR, "time_pps_kcbind failed: %m");
  723. record_clock_stats(&(instance->peer->srcadr), "HARDPPS failed, abort...");
  724. return (0);
  725. }
  726. pps_enable = 1;
  727. }
  728. return(1);
  729. }
  730. #ifdef ONCORE_SHMEM_STATUS
  731. static void
  732. oncore_init_shmem(
  733. struct instance *instance
  734. )
  735. {
  736. int i, l, n, fd, shmem_old_size, n1;
  737. char Msg[160];
  738. u_char *cp, *cp1, *buf, *shmem_old;
  739. struct msg_desc *mp;
  740. struct stat sbuf;
  741. size_t shmem_length;
  742. /*
  743. * The first thing we do is see if there is an instance->shmem_fname file (still)
  744. * out there from a previous run. If so, we copy it in and use it to initialize
  745. * shmem (so we won't lose our almanac if we need it).
  746. */
  747. shmem_old = 0;
  748. shmem_old_size = 0;
  749. if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
  750. record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open SHMEM file");
  751. else {
  752. fstat(fd, &sbuf);
  753. shmem_old_size = sbuf.st_size;
  754. if (shmem_old_size != 0) {
  755. shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
  756. if (shmem_old == NULL)
  757. record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem_old");
  758. else
  759. read(fd, shmem_old, shmem_old_size);
  760. }
  761. close(fd);
  762. }
  763. /* OK, we now create the NEW SHMEM. */
  764. if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
  765. record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open shmem");
  766. if (shmem_old)
  767. free(shmem_old);
  768. return;
  769. }
  770. /* see how big it needs to be */
  771. n = 1;
  772. for (mp=oncore_messages; mp->flag[0]; mp++) {
  773. mp->shmem = n;
  774. /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
  775. if (!strcmp(mp->flag, "Cb")) {
  776. instance->shmem_Cb = n;
  777. n += (mp->len + 3) * 34;
  778. }
  779. if (!strcmp(mp->flag, "Ba")) {
  780. instance->shmem_Ba = n;
  781. n += (mp->len + 3) * 3;
  782. }
  783. if (!strcmp(mp->flag, "Ea")) {
  784. instance->shmem_Ea = n;
  785. n += (mp->len + 3) * 3;
  786. }
  787. if (!strcmp(mp->flag, "Ha")) {
  788. instance->shmem_Ha = n;
  789. n += (mp->len + 3) * 3;
  790. }
  791. n += (mp->len + 3);
  792. }
  793. shmem_length = n + 2;
  794. buf = malloc(shmem_length);
  795. if (buf == NULL) {
  796. record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem");
  797. close(instance->shmemfd);
  798. if (shmem_old)
  799. free(shmem_old);
  800. return;
  801. }
  802. memset(buf, 0, shmem_length);
  803. /* next build the new SHMEM buffer in memory */
  804. for (mp=oncore_messages; mp->flag[0]; mp++) {
  805. l = mp->shmem;
  806. buf[l + 0] = mp->len >> 8;
  807. buf[l + 1] = mp->len & 0xff;
  808. buf[l + 2] = 0;
  809. buf[l + 3] = '@';
  810. buf[l + 4] = '@';
  811. buf[l + 5] = mp->flag[0];
  812. buf[l + 6] = mp->flag[1];
  813. if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
  814. if (!strcmp(mp->flag, "Cb"))
  815. n = 35;
  816. else
  817. n = 4;
  818. for (i=1; i<n; i++) {
  819. buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
  820. buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
  821. buf[l + i * (mp->len+3) + 2] = 0;
  822. buf[l + i * (mp->len+3) + 3] = '@';
  823. buf[l + i * (mp->len+3) + 4] = '@';
  824. buf[l + i * (mp->len+3) + 5] = mp->flag[0];
  825. buf[l + i * (mp->len+3) + 6] = mp->flag[1];
  826. }
  827. }
  828. }
  829. /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
  830. * copying the data in shmem_old to buf.
  831. * When we are done we write it out and free both buffers.
  832. * If the structure sizes dont agree, I will not copy.
  833. * This could be due to an addition/deletion or a problem with the disk file.
  834. */
  835. if (shmem_old) {
  836. if (shmem_old_size == shmem_length) {
  837. for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) {
  838. n1 = 256*(*(cp1-3)) + *(cp1-2);
  839. if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
  840. break;
  841. memcpy(cp, cp1, (size_t) n);
  842. }
  843. }
  844. free(shmem_old);
  845. }
  846. i = write(instance->shmemfd, buf, shmem_length);
  847. free(buf);
  848. if (i != shmem_length) {
  849. record_clock_stats(&(instance->peer->srcadr), "ONCORE: error writing shmem");
  850. close(instance->shmemfd);
  851. return;
  852. }
  853. instance->shmem = (u_char *) mmap(0, shmem_length,
  854. PROT_READ | PROT_WRITE,
  855. #ifdef MAP_HASSEMAPHORE
  856. MAP_HASSEMAPHORE |
  857. #endif
  858. MAP_SHARED, instance->shmemfd, (off_t)0);
  859. if (instance->shmem == (u_char *)MAP_FAILED) {
  860. instance->shmem = 0;
  861. close(instance->shmemfd);
  862. return;
  863. }
  864. sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s",
  865. (u_long) shmem_length, instance->shmem_fname);
  866. record_clock_stats(&(instance->peer->srcadr), Msg);
  867. }
  868. #endif /* ONCORE_SHMEM_STATUS */
  869. /*
  870. * Read Input file if it exists.
  871. */
  872. static void
  873. oncore_read_config(
  874. struct instance *instance
  875. )
  876. {
  877. /*
  878. * First we try to open the configuration file
  879. * /etc/oncoreN
  880. * where N is the unit number viz 127.127.30.N.
  881. * If we don't find it we try
  882. * /etc/ntp.oncore.N
  883. * and then
  884. * /etc/ntp.oncore
  885. *
  886. * If we don't find any then we don't have the cable delay or PPS offset
  887. * and we choose MODE (4) below.
  888. *
  889. * Five Choices for MODE
  890. * (0) ONCORE is preinitialized, don't do anything to change it.
  891. * nb, DON'T set 0D mode, DON'T set Delay, position...
  892. * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
  893. * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
  894. * lock this in, go to 0D mode.
  895. * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
  896. * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
  897. * lock this in, go to 0D mode.
  898. * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
  899. * then this position is set as the INITIAL position of the ONCORE.
  900. * This can reduce the time to first fix.
  901. * -------------------------------------------------------------------------------
  902. * Note that an Oncore UT without a battery backup retains NO information if it is
  903. * power cycled, with a Battery Backup it remembers the almanac, etc.
  904. * For an Oncore VP, there is an eeprom that will contain this data, along with the
  905. * option of Battery Backup.
  906. * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
  907. * power cycle, since there is nowhere to store the data.
  908. * -------------------------------------------------------------------------------
  909. *
  910. * If we open one or the other of the files, we read it looking for
  911. * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
  912. * STATUS, POSN3D, POSN2D, CHAN, TRAIM
  913. * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must
  914. * be present or mode reverts to (2,4).
  915. *
  916. * Read input file.
  917. *
  918. * # is comment to end of line
  919. * = allowed between 1st and 2nd fields.
  920. *
  921. * Expect to see one line with 'MODE' as first field, followed by an integer
  922. * in the range 0-4 (default = 4).
  923. *
  924. * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
  925. * All numbers are floating point.
  926. * DDD.ddd
  927. * DDD MMM.mmm
  928. * DDD MMM SSS.sss
  929. *
  930. * Expect to see one line with 'HT' as first field,
  931. * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'
  932. * for feet or meters. HT is the height above the GPS ellipsoid.
  933. * If the receiver reports height in both GPS and MSL, then we will report
  934. * the difference GPS-MSL on the clockstats file.
  935. *
  936. * There is an optional line, starting with DELAY, followed
  937. * by 1 or two fields. The first is a number (a time) the second is
  938. * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
  939. * DELAY is cable delay, typically a few tens of ns.
  940. *
  941. * There is an optional line, starting with OFFSET, followed
  942. * by 1 or two fields. The first is a number (a time) the second is
  943. * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
  944. * OFFSET is the offset of the PPS pulse from 0. (only fully implemented
  945. * with the PPSAPI, we need to be able to tell the Kernel about this
  946. * offset if the Kernel PLL is in use, but can only do this presently
  947. * when using the PPSAPI interface. If not using the Kernel PLL,
  948. * then there is no problem.
  949. *
  950. * There is an optional line, with either ASSERT or CLEAR on it, which
  951. * determine which transition of the PPS signal is used for timing by the
  952. * PPSAPI. If neither is present, then ASSERT is assumed.
  953. * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
  954. * For Flag2, ASSERT=0, and hence is default.
  955. *
  956. * There is an optional line, with HARDPPS on it. Including this line causes
  957. * the PPS signal to control the kernel PLL.
  958. * HARDPPS can also be set with FLAG3 of the ntp.conf input.
  959. * For Flag3, 0 is disabled, and the default.
  960. *
  961. * There are three options that have to do with using the shared memory option.
  962. * First, to enable the option there must be a SHMEM line with a file name.
  963. * The file name is the file associated with the shared memory.
  964. *
  965. * In shared memory, there is one 'record' for each returned variable.
  966. * For the @@Ea data there are three 'records' containing position data.
  967. * There will always be data in the record corresponding to the '0D' @@Ea record,
  968. * and the user has a choice of filling the '3D' record by specifying POSN3D,
  969. * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D'
  970. * record is filled once every 15s.
  971. *
  972. * Two additional variables that can be set are CHAN and TRAIM. These should be
  973. * set correctly by the code examining the @@Cj record, but we bring them out here
  974. * to allow the user to override either the # of channels, or the existence of TRAIM.
  975. * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
  976. * followed by YES or NO.
  977. *
  978. * There is an optional line with MASK on it followed by one integer field in the
  979. * range 0 to 89. This sets the satellite mask angle and will determine the minimum
  980. * elevation angle for satellites to be tracked by the receiver. The default value
  981. * is 10 deg for the VP and 0 deg for all other receivers.
  982. *
  983. * So acceptable input would be
  984. * # these are my coordinates (RWC)
  985. * LON -106 34.610
  986. * LAT 35 08.999
  987. * HT 1589 # could equally well say HT 5215 FT
  988. * DELAY 60 ns
  989. */
  990. FILE *fd;
  991. char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp;
  992. char *dirs[] = { "/etc/ntp", "/etc", 0 };
  993. int i, sign, lat_flg, long_flg, ht_flg, mode, mask;
  994. double f1, f2, f3;
  995. fd = NULL; /* just to shutup gcc complaint */
  996. for (cpp=dirs; *cpp; cpp++) {
  997. cp = *cpp;
  998. sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */
  999. if ((fd=fopen(device, "r")))
  1000. break;
  1001. sprintf(device, "%s/ntp.oncore%d", cp, instance->unit); /* try "ntp.oncore0" */
  1002. if ((fd=fopen(device, "r")))
  1003. break;
  1004. sprintf(device, "%s/ntp.oncore", cp); /* and finally "ntp.oncore" */
  1005. if ((fd=fopen(device, "r")))
  1006. break;
  1007. }
  1008. if (!fd) { /* no inputfile, default to the works ... */
  1009. instance->init_type = 4;
  1010. return;
  1011. }
  1012. mode = mask = 0;
  1013. lat_flg = long_flg = ht_flg = 0;
  1014. while (fgets(line, 100, fd)) {
  1015. /* Remove comments */
  1016. if ((cp = strchr(line, '#')))
  1017. *cp = '\0';
  1018. /* Remove trailing space */
  1019. for (i = strlen(line);
  1020. i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
  1021. )
  1022. line[--i] = '\0';
  1023. /* Remove leading space */
  1024. for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
  1025. continue;
  1026. /* Stop if nothing left */
  1027. if (!*cc)
  1028. continue;
  1029. /* Uppercase the command and find the arg */
  1030. for (ca = cc; *ca; ca++) {
  1031. if (isascii((int)*ca)) {
  1032. if (islower((int)*ca)) {
  1033. *ca = toupper(*ca);
  1034. } else if (isspace((int)*ca) || (*ca == '='))
  1035. break;
  1036. }
  1037. }
  1038. /* Remove space (and possible =) leading the arg */
  1039. for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
  1040. continue;
  1041. if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
  1042. i = strlen(ca);
  1043. instance->shmem_fname = (char *) malloc((unsigned) (i+1));
  1044. strcpy(instance->shmem_fname, ca);
  1045. continue;
  1046. }
  1047. /* Uppercase argument as well */
  1048. for (cp = ca; *cp; cp++)
  1049. if (isascii((int)*cp) && islower((int)*cp))
  1050. *cp = toupper(*cp);
  1051. if (!strncmp(cc, "LAT", (size_t) 3)) {
  1052. f1 = f2 = f3 = 0;
  1053. sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
  1054. sign = 1;
  1055. if (f1 < 0) {
  1056. f1 = -f1;
  1057. sign = -1;
  1058. }
  1059. instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
  1060. lat_flg++;
  1061. } else if (!strncmp(cc, "LON", (size_t) 3)) {
  1062. f1 = f2 = f3 = 0;
  1063. sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
  1064. sign = 1;
  1065. if (f1 < 0) {
  1066. f1 = -f1;
  1067. sign = -1;
  1068. }
  1069. instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
  1070. long_flg++;
  1071. } else if (!strncmp(cc, "HT", (size_t) 2)) {
  1072. f1 = 0;
  1073. units[0] = '\0';
  1074. sscanf(ca, "%lf %1s", &f1, units);
  1075. if (units[0] == 'F')
  1076. f1 = 0.3048 * f1;
  1077. instance->ss_ht = 100 * f1; /* cm */
  1078. ht_flg++;
  1079. } else if (!strncmp(cc, "DELAY", (size_t) 5)) {
  1080. f1 = 0;
  1081. units[0] = '\0';
  1082. sscanf(ca, "%lf %1s", &f1, units);
  1083. if (units[0] == 'N')
  1084. ;
  1085. else if (units[0] == 'U')
  1086. f1 = 1000 * f1;
  1087. else if (units[0] == 'M')
  1088. f1 = 1000000 * f1;
  1089. else
  1090. f1 = 1000000000 * f1;
  1091. if (f1 < 0 || f1 > 1.e9)
  1092. f1 = 0;
  1093. if (f1 < 0 || f1 > 999999) {
  1094. sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
  1095. record_clock_stats(&(instance->peer->srcadr), Msg);
  1096. } else
  1097. instance->delay = f1; /* delay in ns */
  1098. } else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
  1099. f1 = 0;
  1100. units[0] = '\0';
  1101. sscanf(ca, "%lf %1s", &f1, units);
  1102. if (units[0] == 'N')
  1103. ;
  1104. else if (units[0] == 'U')
  1105. f1 = 1000 * f1;
  1106. else if (units[0] == 'M')
  1107. f1 = 1000000 * f1;
  1108. else
  1109. f1 = 1000000000 * f1;
  1110. if (f1 < 0 || f1 > 1.e9)
  1111. f1 = 0;
  1112. if (f1 < 0 || f1 > 999999999.) {
  1113. sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
  1114. record_clock_stats(&(instance->peer->srcadr), Msg);
  1115. } else
  1116. instance->offset = f1; /* offset in ns */
  1117. } else if (!strncmp(cc, "MODE", (size_t) 4)) {
  1118. sscanf(ca, "%d", &mode);
  1119. if (mode < 0 || mode > 4)
  1120. mode = 4;
  1121. } else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
  1122. instance->assert = 1;
  1123. } else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
  1124. instance->assert = 0;
  1125. } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
  1126. instance->hardpps = 1;
  1127. } else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
  1128. instance->shmem_Posn = 2;
  1129. } else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
  1130. instance->shmem_Posn = 3;
  1131. } else if (!strncmp(cc, "CHAN", (size_t) 4)) {
  1132. sscanf(ca, "%d", &i);
  1133. if ((i == 6) || (i == 8) || (i == 12))
  1134. instance->chan_in = i;
  1135. } else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
  1136. instance->traim_in = 1; /* so TRAIM alone is YES */
  1137. if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */
  1138. instance->traim_in = 0;
  1139. } else if (!strncmp(cc, "MASK", (size_t) 4)) {
  1140. sscanf(ca, "%d", &mask);
  1141. if (mask > -1 && mask < 90)
  1142. instance->Ag = mask; /* Satellite mask angle */
  1143. }
  1144. }
  1145. fclose(fd);
  1146. /*
  1147. * OK, have read all of data file, and extracted the good stuff.
  1148. * If lat/long/ht specified they ALL must be specified for mode = (1,3).
  1149. */
  1150. instance->posn_set = 1;
  1151. if (!( lat_flg && long_flg && ht_flg )) {
  1152. printf("ONCORE: incomplete data on %s\n", device);
  1153. instance->posn_set = 0;
  1154. if (mode == 1 || mode == 3) {
  1155. sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
  1156. record_clock_stats(&(instance->peer->srcadr), Msg);
  1157. mode++;
  1158. }
  1159. }
  1160. instance->init_type = mode;
  1161. sprintf(Msg, "Input mode = %d", mode);
  1162. record_clock_stats(&(instance->peer->srcadr), Msg);
  1163. }
  1164. /*
  1165. * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
  1166. */
  1167. static void
  1168. oncore_receive(
  1169. struct recvbuf *rbufp
  1170. )
  1171. {
  1172. size_t i;
  1173. u_char *p;
  1174. struct peer *peer;
  1175. struct instance *instance;
  1176. peer = (struct peer *)rbufp->recv_srcclock;
  1177. instance = (struct instance *) peer->procptr->unitptr;
  1178. p = (u_char *) &rbufp->recv_space;
  1179. #if 0
  1180. if (debug > 4) {
  1181. int i;
  1182. printf("ONCORE: >>>");
  1183. for(i=0; i<rbufp->recv_length; i++)
  1184. printf("%02x ", p[i]);
  1185. printf("\n");
  1186. printf("ONCORE: >>>");
  1187. for(i=0; i<rbufp->recv_length; i++)
  1188. printf("%03o ", p[i]);
  1189. printf("\n");
  1190. }
  1191. #endif
  1192. i = rbufp->recv_length;
  1193. if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
  1194. i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */
  1195. memcpy(rcvbuf+rcvptr, p, i);
  1196. rcvptr += i;
  1197. oncore_consume(instance);
  1198. }
  1199. /*
  1200. * Deal with any complete messages
  1201. */
  1202. static void
  1203. oncore_consume(
  1204. struct instance *instance
  1205. )
  1206. {
  1207. int i, m;
  1208. unsigned l;
  1209. while (rcvptr >= 7) {
  1210. if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
  1211. /* We're not in sync, lets try to get there */
  1212. for (i=1; i < rcvptr-1; i++)
  1213. if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
  1214. break;
  1215. #ifdef DEBUG
  1216. if (debug > 4)
  1217. printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
  1218. #endif
  1219. if (i != rcvptr)
  1220. memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
  1221. rcvptr -= i;
  1222. continue;
  1223. }
  1224. /* Ok, we have a header now */
  1225. l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
  1226. for(m=0; m<l; m++)
  1227. if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
  1228. break;
  1229. if (m == l) {
  1230. #ifdef DEBUG
  1231. if (debug > 4)
  1232. printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
  1233. #endif
  1234. memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
  1235. rcvptr -= 4;
  1236. continue;
  1237. }
  1238. l = oncore_messages[m].len;
  1239. #if 0
  1240. if (debug > 3)
  1241. printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
  1242. #endif
  1243. /* Got the entire message ? */
  1244. if (rcvptr < l)
  1245. return;
  1246. /* are we at the end of message? should be <Cksum><CR><LF> */
  1247. if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
  1248. #ifdef DEBUG
  1249. if (debug)
  1250. printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
  1251. #endif
  1252. } else { /* check the CheckSum */
  1253. if (oncore_checksum_ok(rcvbuf, l)) {
  1254. if (instance->shmem != NULL) {
  1255. instance->shmem[oncore_messages[m].shmem + 2]++;
  1256. memcpy(instance->shmem + oncore_messages[m].shmem + 3,
  1257. rcvbuf, (size_t) l);
  1258. }
  1259. oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
  1260. if (oncore_messages[m].handler)
  1261. oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
  1262. }
  1263. #ifdef DEBUG
  1264. else if (debug) {
  1265. printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit);
  1266. printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
  1267. for (i=4; i<l; i++)
  1268. printf("%03o ", rcvbuf[i]);
  1269. printf("\n");
  1270. }
  1271. #endif
  1272. }
  1273. if (l != rcvptr)
  1274. memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
  1275. rcvptr -= l;
  1276. }
  1277. }
  1278. static void
  1279. oncore_get_timestamp(
  1280. struct instance *instance,
  1281. long dt1, /* tick offset THIS time step */
  1282. long dt2 /* tick offset NEXT time step */
  1283. )
  1284. {
  1285. int Rsm;
  1286. u_long j;
  1287. l_fp ts, ts_tmp;
  1288. double dmy;
  1289. #ifdef HAVE_STRUCT_TIMESPEC
  1290. struct timespec *tsp = 0;
  1291. #else
  1292. struct timeval *tsp = 0;
  1293. #endif
  1294. int current_mode;
  1295. u_long i;
  1296. pps_params_t current_params;
  1297. struct timespec timeout;
  1298. pps_info_t pps_i;
  1299. #if 1
  1300. /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
  1301. * If we have Finished the SiteSurvey, then we fall thru for the 14/15
  1302. * times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
  1303. * This gives good time, which gets better when the SS is done.
  1304. */
  1305. if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
  1306. #else
  1307. /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
  1308. if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
  1309. #endif
  1310. return;
  1311. /* Don't do anything without an almanac to define the GPS->UTC delta */
  1312. if (instance->rsm.bad_almanac)
  1313. return;
  1314. /* Once the Almanac is valid, the M12+T does not produce valid UTC
  1315. * immediately.
  1316. * Wait for UTC offset decode valid, then wait one message more
  1317. * so we are not off by 13 seconds after reset.
  1318. */
  1319. if (instance->count5) {
  1320. instance->count5--;
  1321. return;
  1322. }
  1323. j = instance->ev_serial;
  1324. timeout.tv_sec = 0;
  1325. timeout.tv_ns