Devuan fork of gpsd
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

609 lines
20 KiB

  1. /*
  2. * This file is Copyright (c) 2010-2018 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <stdbool.h>
  7. #include <stdio.h>
  8. #include "gpsd.h"
  9. #if defined(ONCORE_ENABLE) && defined(BINARY_ENABLE)
  10. #include "bits.h"
  11. #include "timespec.h"
  12. static char enableEa[] = { 'E', 'a', 1 };
  13. static char enableBb[] = { 'B', 'b', 1 };
  14. static char getfirmware[] = { 'C', 'j' };
  15. /*static char enableEn[] =
  16. { 'E', 'n', 1, 0, 100, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };*/
  17. /*static char enableAt2[] = { 'A', 't', 2, };*/
  18. static unsigned char pollAs[] =
  19. { 'A', 's', 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff,
  20. 0xff, 0xff, 0xff
  21. };
  22. static unsigned char pollAt[] = { 'A', 't', 0xff };
  23. static unsigned char pollAy[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
  24. static unsigned char pollBo[] = { 'B', 'o', 0x01 };
  25. static unsigned char pollEn[] = {
  26. 'E', 'n', 0xff, 0xff, 0xff, 0xff, 0xff,
  27. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  28. };
  29. /*
  30. * These routines are specific to this driver
  31. */
  32. static gps_mask_t oncore_parse_input(struct gps_device_t *);
  33. static gps_mask_t oncore_dispatch(struct gps_device_t *, unsigned char *,
  34. size_t);
  35. static gps_mask_t oncore_msg_navsol(struct gps_device_t *, unsigned char *,
  36. size_t);
  37. static gps_mask_t oncore_msg_utc_offset(struct gps_device_t *,
  38. unsigned char *, size_t);
  39. static gps_mask_t oncore_msg_pps_offset(struct gps_device_t *, unsigned char *,
  40. size_t);
  41. static gps_mask_t oncore_msg_svinfo(struct gps_device_t *, unsigned char *,
  42. size_t);
  43. static gps_mask_t oncore_msg_time_raim(struct gps_device_t *, unsigned char *,
  44. size_t);
  45. static gps_mask_t oncore_msg_firmware(struct gps_device_t *, unsigned char *,
  46. size_t);
  47. /*
  48. * These methods may be called elsewhere in gpsd
  49. */
  50. static ssize_t oncore_control_send(struct gps_device_t *, char *, size_t);
  51. static void oncore_event_hook(struct gps_device_t *, event_t);
  52. /*
  53. * Decode the navigation solution message
  54. *
  55. * @@Ea - Position/Status/Data Message
  56. @@EamdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC
  57. <CR><LF>
  58. *
  59. * Date
  60. * m - month 1 .. 12
  61. * d - day 1 .. 31
  62. * yy - year 1980 .. 2079
  63. *
  64. * Time
  65. * h - hours 0 .. 23
  66. * m - minutes 0 .. 59
  67. * s - seconds 0 .. 60
  68. * ffff - fractional second 0 .. 999,999,999
  69. * (0.0 .. 0.999999999)
  70. *
  71. * Position
  72. * aaaa - latitude in mas -324,000,000 .. 324,000,000
  73. * (-90 degrees .. 90 degrees)
  74. *
  75. * oooo - longitude in mas -648,000,000 .. 648,000,000
  76. * (-180 degrees .. 180 degrees)
  77. *
  78. * hhhh - ellipsoid height in cm -100,000 .. 1,800,000
  79. * (-1000.00 .. 18,000.00m)*
  80. *
  81. * mmmm - not used 0
  82. *
  83. * Velocity
  84. * vv - velocity in cm/s 0 .. 51,400 (0..514.00 m/s)*
  85. * hh - heading 0 .. 3599 (0.0..359.9 degrees)
  86. *
  87. * (true north res 0.1 degrees)
  88. *
  89. * Geometry
  90. * dd - current DOP (0.1 res) 0 .. 999 (0.0 to 99.9 DOP)
  91. * (0 = not computable, position-hold, or position propagate)
  92. *
  93. * t - DOP TYPE
  94. * 0 PDOP (3D)/antenna ok
  95. * 1 PDOP (3D)/antenna OK
  96. * 64 PDOP (3D)/antenna shorted
  97. * 65 PDOP (3D)/antenna shorted
  98. * 128 PDOP (3D)/antenna open
  99. * 129 PDOP (3D)/antenna open
  100. * 192 PDOP (3D)/antenna shorted
  101. * 193 PDOP (3D)/antenna shorted
  102. *
  103. * Satellite visibility and tracking status
  104. * n - num of visible sats 0 .. 12
  105. * t - num of satellites tracked 0 .. 8
  106. *
  107. * For each of eight receiver channels
  108. * i - sat ID 0 .. 37
  109. * m - channel tracking mode 0 .. 8
  110. * 0 = code search 5 = message sync detect
  111. * 1 = code acquire 6 = satellite time avail.
  112. * 2 = AGC set 7 = ephemeris acquire
  113. * 3 = prep acquire 8 = avail for position
  114. * 4 = bit sync detect
  115. *
  116. * s - carrier to noise density ratio
  117. * (C/No) 0 .. 255 db-Hz
  118. *
  119. * d - channel status flag
  120. * Each bit represents one of the following:
  121. * (msb) Bit 7: using for position fix
  122. * Bit 6: satellite momentum alert flag
  123. * Bit 5: satellite anti-spoof flag set
  124. * Bit 4: satellite reported unhealthy
  125. * Bit 3: satellite reported inaccurate
  126. * (> 16m)
  127. * Bit 2: spare
  128. * Bit 1: spare
  129. * (lsb) Bit 0: parity error
  130. *
  131. * End of channel dependent data
  132. * s - receiver status flag
  133. *
  134. * Each bit represents one of the following:
  135. * (msb) Bit 7: position propagate mode
  136. * Bit 6: poor geometry (DOP > 12)
  137. * Bit 5: 3D fix
  138. * Bit 4: 2D fix
  139. * Bit 3: acquiring satellites/position hold
  140. * Bit 2: spare
  141. * Bit 1: insufficient visible satellites
  142. * (< 3)
  143. * (lsb) Bit 0: bad almanac
  144. *
  145. * C - checksum
  146. * Message length: 76 bytes
  147. *
  148. */
  149. static gps_mask_t
  150. oncore_msg_navsol(struct gps_device_t *session, unsigned char *buf,
  151. size_t data_len)
  152. {
  153. gps_mask_t mask;
  154. unsigned char flags;
  155. double lat, lon, alt;
  156. float speed, track, dop;
  157. unsigned int i, j, st, nsv;
  158. int Bbused;
  159. struct tm unpacked_date;
  160. char ts_buf[TIMESPEC_LEN];
  161. if (data_len != 76)
  162. return 0;
  163. mask = ONLINE_SET;
  164. GPSD_LOG(LOG_DATA, &session->context->errout,
  165. "oncore NAVSOL - navigation data\n");
  166. flags = (unsigned char)getub(buf, 72);
  167. if (flags & 0x20) {
  168. session->gpsdata.status = STATUS_FIX;
  169. session->newdata.mode = MODE_3D;
  170. } else if (flags & 0x10) {
  171. session->gpsdata.status = STATUS_FIX;
  172. session->newdata.mode = MODE_2D;
  173. } else {
  174. GPSD_LOG(LOG_WARN, &session->context->errout,
  175. "oncore NAVSOL no fix - flags 0x%02x\n", flags);
  176. session->newdata.mode = MODE_NO_FIX;
  177. session->gpsdata.status = STATUS_NO_FIX;
  178. }
  179. mask |= MODE_SET;
  180. /* Unless we have seen non-zero utc offset data, the time is GPS time
  181. * and not UTC time. Do not use it.
  182. */
  183. if (session->context->leap_seconds) {
  184. unsigned int nsec;
  185. unpacked_date.tm_mon = (int)getub(buf, 4) - 1;
  186. unpacked_date.tm_mday = (int)getub(buf, 5);
  187. unpacked_date.tm_year = (int)getbeu16(buf, 6) - 1900;
  188. unpacked_date.tm_hour = (int)getub(buf, 8);
  189. unpacked_date.tm_min = (int)getub(buf, 9);
  190. unpacked_date.tm_sec = (int)getub(buf, 10);
  191. unpacked_date.tm_isdst = 0;
  192. unpacked_date.tm_wday = unpacked_date.tm_yday = 0;
  193. nsec = (unsigned int) getbeu32(buf, 11);
  194. session->newdata.time.tv_sec = mkgmtime(&unpacked_date);
  195. session->newdata.time.tv_nsec = nsec;
  196. mask |= TIME_SET;
  197. GPSD_LOG(LOG_DATA, &session->context->errout,
  198. "oncore NAVSOL - time: %04d-%02d-%02d %02d:%02d:%02d.%09d\n",
  199. unpacked_date.tm_year + 1900, unpacked_date.tm_mon + 1,
  200. unpacked_date.tm_mday, unpacked_date.tm_hour,
  201. unpacked_date.tm_min, unpacked_date.tm_sec, nsec);
  202. }
  203. lat = getbes32(buf, 15) / 3600000.0f;
  204. lon = getbes32(buf, 19) / 3600000.0f;
  205. alt = getbes32(buf, 23) / 100.0f;
  206. speed = getbeu16(buf, 31) / 100.0f;
  207. track = getbeu16(buf, 33) / 10.0f;
  208. dop = getbeu16(buf, 35) / 10.0f;
  209. GPSD_LOG(LOG_DATA, &session->context->errout,
  210. "oncore NAVSOL - %lf %lf %.2lfm | %.2fm/s %.1fdeg dop=%.1f\n",
  211. lat, lon, alt, speed, track,
  212. (float)dop);
  213. session->newdata.latitude = lat;
  214. session->newdata.longitude = lon;
  215. session->newdata.altHAE = alt; /* is WGS84 */
  216. session->newdata.speed = speed;
  217. session->newdata.track = track;
  218. mask |= LATLON_SET | ALTITUDE_SET | SPEED_SET | TRACK_SET;
  219. gpsd_zero_satellites(&session->gpsdata);
  220. /* Merge the satellite information from the Bb message. */
  221. Bbused = 0;
  222. nsv = 0;
  223. for (i = st = 0; i < 8; i++) {
  224. int sv, mode, sn, status;
  225. unsigned int off;
  226. off = 40 + 4 * i;
  227. sv = (int)getub(buf, off);
  228. mode = (int)getub(buf, off + 1);
  229. sn = (int)getub(buf, off + 2);
  230. status = (int)getub(buf, off + 3);
  231. GPSD_LOG(LOG_DATA, &session->context->errout,
  232. "%2d %2d %2d %3d %02x\n", i, sv, mode, sn, status);
  233. if (sn) {
  234. session->gpsdata.skyview[st].PRN = (short)sv;
  235. session->gpsdata.skyview[st].ss = (double)sn;
  236. for (j = 0; (int)j < session->driver.oncore.visible; j++)
  237. if (session->driver.oncore.PRN[j] == sv) {
  238. session->gpsdata.skyview[st].elevation =
  239. (double)session->driver.oncore.elevation[j];
  240. session->gpsdata.skyview[st].azimuth =
  241. (double)session->driver.oncore.azimuth[j];
  242. Bbused |= 1 << j;
  243. break;
  244. }
  245. /* bit 7 of the status word: sat used for position */
  246. session->gpsdata.skyview[st].used = false;
  247. if (status & 0x80) {
  248. session->gpsdata.skyview[st].used = true;
  249. nsv++;
  250. }
  251. /* bit 2 of the status word: using for time solution */
  252. if (status & 0x02)
  253. mask |= NTPTIME_IS | GOODTIME_IS;
  254. /*
  255. * The GOODTIME_IS mask bit exists distinctly from TIME_SET exactly
  256. * so an OnCore running in time-service mode (and other GPS clocks)
  257. * can signal that it's returning time even though no position fixes
  258. * have been available.
  259. */
  260. st++;
  261. }
  262. }
  263. for (j = 0; (int)j < session->driver.oncore.visible; j++)
  264. if (!(Bbused & (1 << j))) {
  265. session->gpsdata.skyview[st].PRN =
  266. (short)session->driver.oncore.PRN[j];
  267. session->gpsdata.skyview[st].elevation =
  268. (double)session->driver.oncore.elevation[j];
  269. session->gpsdata.skyview[st].azimuth =
  270. (double)session->driver.oncore.azimuth[j];
  271. st++;
  272. }
  273. session->gpsdata.skyview_time = session->newdata.time;
  274. session->gpsdata.satellites_used = (int)nsv;
  275. session->gpsdata.satellites_visible = (int)st;
  276. mask |= SATELLITE_SET | USED_IS;
  277. /* Some messages can only be polled. As they are not so
  278. * important, would be enough to poll e.g. one message per cycle.
  279. */
  280. (void)oncore_control_send(session, (char *)pollAs, sizeof(pollAs));
  281. (void)oncore_control_send(session, (char *)pollAt, sizeof(pollAt));
  282. (void)oncore_control_send(session, (char *)pollAy, sizeof(pollAy));
  283. (void)oncore_control_send(session, (char *)pollBo, sizeof(pollBo));
  284. (void)oncore_control_send(session, (char *)pollEn, sizeof(pollEn));
  285. GPSD_LOG(LOG_DATA, &session->context->errout,
  286. "NAVSOL: time=%s lat=%.2f lon=%.2f altMSL=%.2f speed=%.2f "
  287. "track=%.2f mode=%d status=%d visible=%d used=%d\n",
  288. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
  289. session->newdata.latitude,
  290. session->newdata.longitude, session->newdata.altHAE,
  291. session->newdata.speed, session->newdata.track,
  292. session->newdata.mode, session->gpsdata.status,
  293. session->gpsdata.satellites_used,
  294. session->gpsdata.satellites_visible);
  295. return mask;
  296. }
  297. /**
  298. * GPS Leap Seconds = UTC offset
  299. */
  300. static gps_mask_t
  301. oncore_msg_utc_offset(struct gps_device_t *session, unsigned char *buf,
  302. size_t data_len)
  303. {
  304. int utc_offset;
  305. if (data_len != 8)
  306. return 0;
  307. GPSD_LOG(LOG_DATA, &session->context->errout,
  308. "oncore UTCTIME - leap seconds\n");
  309. utc_offset = (int)getub(buf, 4);
  310. if (utc_offset == 0)
  311. return 0; /* that part of almanac not received yet */
  312. session->context->leap_seconds = utc_offset;
  313. session->context->valid |= LEAP_SECOND_VALID;
  314. return 0; /* no flag for leap seconds update */
  315. }
  316. /**
  317. * PPS offset
  318. */
  319. static gps_mask_t
  320. oncore_msg_pps_offset(struct gps_device_t *session, unsigned char *buf,
  321. size_t data_len)
  322. {
  323. int pps_offset_ns;
  324. if (data_len != 11)
  325. return 0;
  326. GPSD_LOG(LOG_DATA, &session->context->errout, "oncore PPS offset\n");
  327. pps_offset_ns = (int)getbes32(buf, 4);
  328. session->driver.oncore.pps_offset_ns = pps_offset_ns;
  329. return 0;
  330. }
  331. /**
  332. * GPS Satellite Info
  333. */
  334. static gps_mask_t
  335. oncore_msg_svinfo(struct gps_device_t *session, unsigned char *buf,
  336. size_t data_len)
  337. {
  338. unsigned int i, nchan;
  339. int j;
  340. if (data_len != 92)
  341. return 0;
  342. GPSD_LOG(LOG_DATA, &session->context->errout,
  343. "oncore SVINFO - satellite data\n");
  344. nchan = (unsigned int)getub(buf, 4);
  345. GPSD_LOG(LOG_DATA, &session->context->errout,
  346. "oncore SVINFO - %d satellites:\n", nchan);
  347. /* Then we clamp the value to not read outside the table. */
  348. if (nchan > 12)
  349. nchan = 12;
  350. session->driver.oncore.visible = (int)nchan;
  351. for (i = 0; i < nchan; i++) {
  352. /* get info for one channel/satellite */
  353. unsigned int off = 5 + 7 * i;
  354. int sv = (int)getub(buf, off);
  355. int el = (int)getub(buf, off + 3);
  356. int az = (int)getbeu16(buf, off + 4);
  357. GPSD_LOG(LOG_DATA, &session->context->errout,
  358. "%2d %2d %2d %3d\n", i, sv, el, az);
  359. /* Store for use when Ea messages come. */
  360. session->driver.oncore.PRN[i] = sv;
  361. session->driver.oncore.elevation[i] = (short)el;
  362. session->driver.oncore.azimuth[i] = (short)az;
  363. /* If it has an entry in the satellite list, update it! */
  364. for (j = 0; j < session->gpsdata.satellites_visible; j++)
  365. if (session->gpsdata.skyview[j].PRN == (short)sv) {
  366. session->gpsdata.skyview[j].elevation = (double)el;
  367. session->gpsdata.skyview[j].azimuth = (double)az;
  368. }
  369. }
  370. GPSD_LOG(LOG_DATA, &session->context->errout,
  371. "SVINFO: mask={SATELLITE}\n");
  372. return SATELLITE_SET;
  373. }
  374. /**
  375. * GPS Time RAIM
  376. */
  377. static gps_mask_t
  378. oncore_msg_time_raim(struct gps_device_t *session UNUSED,
  379. unsigned char *buf UNUSED, size_t data_len UNUSED)
  380. {
  381. int sawtooth_ns;
  382. if (data_len != 69)
  383. return 0;
  384. sawtooth_ns = (int)getub(buf, 25);
  385. GPSD_LOG(LOG_DATA, &session->context->errout,
  386. "oncore PPS sawtooth: %d\n",sawtooth_ns);
  387. /* session->driver.oncore.traim_sawtooth_ns = sawtooth_ns; */
  388. return 0;
  389. }
  390. /**
  391. * GPS Firmware
  392. */
  393. static gps_mask_t
  394. oncore_msg_firmware(struct gps_device_t *session UNUSED,
  395. unsigned char *buf UNUSED, size_t data_len UNUSED)
  396. {
  397. return 0;
  398. }
  399. #define ONCTYPE(id2,id3) ((((unsigned int)id2)<<8)|(id3))
  400. /**
  401. * Parse the data from the device
  402. */
  403. gps_mask_t oncore_dispatch(struct gps_device_t * session, unsigned char *buf,
  404. size_t len)
  405. {
  406. unsigned int type;
  407. if (len == 0)
  408. return 0;
  409. type = ONCTYPE(buf[2], buf[3]);
  410. /* we may need to dump the raw packet */
  411. GPSD_LOG(LOG_RAW, &session->context->errout,
  412. "raw Oncore packet type 0x%04x\n", type);
  413. session->cycle_end_reliable = true;
  414. switch (type) {
  415. case ONCTYPE('B', 'b'):
  416. return oncore_msg_svinfo(session, buf, len);
  417. case ONCTYPE('E', 'a'):
  418. return oncore_msg_navsol(session, buf, len) | (CLEAR_IS | REPORT_IS);
  419. case ONCTYPE('E', 'n'):
  420. return oncore_msg_time_raim(session, buf, len);
  421. case ONCTYPE('C', 'j'):
  422. return oncore_msg_firmware(session, buf, len);
  423. case ONCTYPE('B', 'o'):
  424. return oncore_msg_utc_offset(session, buf, len);
  425. case ONCTYPE('A', 's'):
  426. return 0; /* position hold mode */
  427. case ONCTYPE('A', 't'):
  428. return 0; /* position hold position */
  429. case ONCTYPE('A', 'y'):
  430. return oncore_msg_pps_offset(session, buf, len);
  431. default:
  432. /* FIX-ME: This gets noisy in a hurry. Change once your driver works */
  433. GPSD_LOG(LOG_WARN, &session->context->errout,
  434. "unknown packet id @@%c%c length %zd\n",
  435. type >> 8, type & 0xff, len);
  436. return 0;
  437. }
  438. }
  439. /**********************************************************
  440. *
  441. * Externally called routines below here
  442. *
  443. **********************************************************/
  444. /**
  445. * Write data to the device, doing any required padding or checksumming
  446. */
  447. static ssize_t oncore_control_send(struct gps_device_t *session,
  448. char *msg, size_t msglen)
  449. {
  450. size_t i;
  451. char checksum = 0;
  452. session->msgbuf[0] = '@';
  453. session->msgbuf[1] = '@';
  454. for (i = 0; i < msglen; i++) {
  455. checksum ^= session->msgbuf[i + 2] = msg[i];
  456. }
  457. session->msgbuf[msglen + 2] = checksum;
  458. session->msgbuf[msglen + 3] = '\r';
  459. session->msgbuf[msglen + 4] = '\n';
  460. session->msgbuflen = msglen + 5;
  461. GPSD_LOG(LOG_PROG, &session->context->errout,
  462. "writing oncore control type %c%c\n", msg[0], msg[1]);
  463. return gpsd_write(session, session->msgbuf, session->msgbuflen);
  464. }
  465. static void oncore_event_hook(struct gps_device_t *session, event_t event)
  466. {
  467. if (session->context->readonly)
  468. return;
  469. /*
  470. * Some oncore VP variants that have not been used after long
  471. * power-down will be silent on startup. Provoke
  472. * identification by requesting the firmware version.
  473. */
  474. if (event == event_wakeup)
  475. (void)oncore_control_send(session, getfirmware, sizeof(getfirmware));
  476. /*
  477. * FIX-ME: It might not be necessary to call this on reactivate.
  478. * Experiment to see if the holds its settings through a close.
  479. */
  480. if (event == event_identified || event == event_reactivate) {
  481. (void)oncore_control_send(session, enableEa, sizeof(enableEa));
  482. (void)oncore_control_send(session, enableBb, sizeof(enableBb));
  483. /*(void)oncore_control_send(session, enableEn, sizeof(enableEn)); */
  484. /*(void)oncore_control_send(session,enableAt2,sizeof(enableAt2)); */
  485. /*(void)oncore_control_send(session,pollAs,sizeof(pollAs)); */
  486. (void)oncore_control_send(session, (char*)pollBo, sizeof(pollBo));
  487. }
  488. }
  489. static double oncore_time_offset(struct gps_device_t *session UNUSED)
  490. {
  491. /*
  492. * Only one sentence (NAVSOL) ships time. 0.175 seems best at
  493. * 9600 for UT+, not sure what the fudge should be at other baud
  494. * rates or for other models.
  495. */
  496. return 0.175;
  497. }
  498. static gps_mask_t oncore_parse_input(struct gps_device_t *session)
  499. {
  500. if (session->lexer.type == ONCORE_PACKET) {
  501. return oncore_dispatch(session, session->lexer.outbuffer,
  502. session->lexer.outbuflen);
  503. #ifdef NMEA0183_ENABLE
  504. } else if (session->lexer.type == NMEA_PACKET) {
  505. return nmea_parse((char *)session->lexer.outbuffer, session);
  506. #endif /* NMEA0183_ENABLE */
  507. } else
  508. return 0;
  509. }
  510. /* This is everything we export */
  511. /* *INDENT-OFF* */
  512. const struct gps_type_t driver_oncore = {
  513. .type_name = "Motorola Oncore", /* Full name of type */
  514. .packet_type = ONCORE_PACKET, /* numeric packet type */
  515. .flags = DRIVER_STICKY, /* remember this */
  516. .trigger = NULL, /* identifying response */
  517. .channels = 12, /* device channel count */
  518. .probe_detect = NULL, /* no probe */
  519. .get_packet = generic_get, /* packet getter */
  520. .parse_packet = oncore_parse_input, /* packet parser */
  521. .rtcm_writer = gpsd_write, /* device accepts RTCM */
  522. .init_query = NULL, /* non-perturbing query */
  523. .event_hook = oncore_event_hook, /* lifetime event hook */
  524. #ifdef RECONFIGURE_ENABLE
  525. .speed_switcher = NULL, /* no speed setter */
  526. .mode_switcher = NULL, /* no mode setter */
  527. .rate_switcher = NULL, /* no speed setter */
  528. .min_cycle.tv_sec = 1, /* 1Hz */
  529. .min_cycle.tv_nsec = 0,
  530. #endif /* RECONFIGURE_ENABLE */
  531. #ifdef CONTROLSEND_ENABLE
  532. /* Control string sender - should provide checksum and headers/trailer */
  533. .control_send = oncore_control_send, /* to send control strings */
  534. #endif /* CONTROLSEND_ENABLE */
  535. .time_offset = oncore_time_offset, /* NTP offset array */
  536. };
  537. /* *INDENT-ON* */
  538. #endif /* defined(ONCORE_ENABLE) && defined(BINARY_ENABLE) */