driver_skytraq.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /*
  2. * This is the gpsd driver for Skytraq GPSes operating in binary mode.
  3. *
  4. * SkyTraq is Big Endian
  5. *
  6. * This file is Copyright 2016 by the GPSD project
  7. * SPDX-License-Identifier: BSD-2-clause
  8. */
  9. #include "../include/gpsd_config.h" // must be before all includes
  10. #include <ctype.h>
  11. #include <math.h>
  12. #include <stdbool.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h> // for strlcpy()
  16. #include <strings.h>
  17. #include <unistd.h>
  18. #include "../include/gpsd.h"
  19. #include "../include/bits.h"
  20. #include "../include/strfuncs.h"
  21. #if defined(SKYTRAQ_ENABLE)
  22. #include "../include/timespec.h"
  23. #define HI(n) ((n) >> 8)
  24. #define LO(n) ((n) & 0xff)
  25. /*
  26. * No ACK/NAK? Just rety after 6 seconds
  27. */
  28. #define SKY_RETRY_TIME 6
  29. #define SKY_CHANNELS 48 /* max channels allowed in format */
  30. static gps_mask_t sky_parse(struct gps_device_t *, unsigned char *, size_t);
  31. static gps_mask_t sky_msg_80(struct gps_device_t *, unsigned char *, size_t);
  32. static gps_mask_t sky_msg_DC(struct gps_device_t *, unsigned char *, size_t);
  33. static gps_mask_t sky_msg_DD(struct gps_device_t *, unsigned char *, size_t);
  34. static gps_mask_t sky_msg_DE(struct gps_device_t *, unsigned char *, size_t);
  35. static gps_mask_t sky_msg_DF(struct gps_device_t *, unsigned char *, size_t);
  36. static gps_mask_t sky_msg_E0(struct gps_device_t *, unsigned char *, size_t);
  37. static gps_mask_t sky_msg_E2(struct gps_device_t *, unsigned char *, size_t);
  38. static gps_mask_t sky_msg_E3(struct gps_device_t *, unsigned char *, size_t);
  39. #ifdef __UNUSED
  40. /* Poll Software Version MID 2 */
  41. static unsigned char versionprobe[] = {
  42. 0xa0, 0xa1, 0x00, 0x02,
  43. 0x02, /* MID 2 */
  44. 0x01, /* System */
  45. 0x00, 0x0d, 0x0a
  46. };
  47. // cppcheck-suppress unusedFunction
  48. static bool sky_write(struct gps_device_t *session, unsigned char *msg)
  49. {
  50. unsigned int crc;
  51. size_t i, len;
  52. bool ok;
  53. unsigned int type = (unsigned int)msg[4];
  54. len = (size_t) ((msg[2] << 8) | msg[3]);
  55. /* calculate Checksum */
  56. crc = 0;
  57. /* coverity_submit[tainted_data] */
  58. for (i = 0; i < len; i++)
  59. crc ^= (int)msg[4 + i];
  60. /* enter CRC after payload */
  61. msg[len + 4] = (unsigned char)(crc & 0x00ff);
  62. GPSD_LOG(LOG_PROG, &session->context->errout,
  63. "Skytraq: Writing control type %02x:\n", type);
  64. ok = (gpsd_write(session, (const char *)msg, len+7) == (ssize_t) (len+7));
  65. return (ok);
  66. }
  67. #endif /* __UNUSED */
  68. /*
  69. * Convert PRN to gnssid and svid
  70. */
  71. static void PRN2_gnssId_svId(short PRN, uint8_t *gnssId, uint8_t *svId)
  72. {
  73. /* fit into gnssid:svid */
  74. if (0 == PRN) {
  75. /* skip 0 PRN */
  76. *gnssId = 0;
  77. *svId = 0;
  78. } else if ((1 <= PRN) && (32 >= PRN)) {
  79. /* GPS */
  80. *gnssId = 0;
  81. *svId = PRN;
  82. } else if ((65 <= PRN) && (96 >= PRN)) {
  83. /* GLONASS */
  84. *gnssId = 6;
  85. *svId = PRN - 64;
  86. } else if ((120 <= PRN) && (158 >= PRN)) {
  87. /* SBAS */
  88. *gnssId = 1;
  89. *svId = PRN;
  90. } else if ((201 <= PRN) && (239 >= PRN)) {
  91. /* BeiDou */
  92. *gnssId = 3;
  93. *svId = PRN - 200;
  94. } else if ((240 <= PRN) && (254 >= PRN)) {
  95. /* IRNSS */
  96. *gnssId = 20;
  97. *svId = PRN - 240;
  98. } else {
  99. /* huh? */
  100. *gnssId = 0;
  101. *svId = 0;
  102. }
  103. return;
  104. }
  105. /*
  106. * decode MID 0x80, Software Version
  107. *
  108. * 10 bytes
  109. */
  110. static gps_mask_t sky_msg_80(struct gps_device_t *session,
  111. unsigned char *buf, size_t len)
  112. {
  113. unsigned int kver_x; // kernel version
  114. unsigned int kver_y; // kernel version
  115. unsigned int kver_z; // kernel version
  116. unsigned int over_x; // ODM version
  117. unsigned int over_y; // ODM version
  118. unsigned int over_z; // ODM version
  119. unsigned int rev_yy; // revision
  120. unsigned int rev_mm; // revision
  121. unsigned int rev_dd; // revision
  122. if ( 14 != len)
  123. return 0;
  124. kver_x = getbeu16(buf, 2);
  125. kver_y = getub(buf, 4);
  126. kver_z = getub(buf, 5);
  127. over_x = getbeu16(buf, 6);
  128. over_y = getub(buf, 8);
  129. over_z = getub(buf, 9);
  130. rev_yy = getbeu16(buf, 10);
  131. rev_mm = getub(buf, 12);
  132. rev_dd = getub(buf, 13);
  133. (void)snprintf(session->subtype, sizeof(session->subtype) - 1,
  134. "kver %u.%u,%u over %u.%u,%u, rev %02u.%02u.%02u",
  135. kver_x, kver_y, kver_z,
  136. over_x, over_y, over_z,
  137. rev_yy, rev_mm, rev_dd);
  138. GPSD_LOG(LOG_DATA, &session->context->errout,
  139. "Skytraq: MID 0x80: %s\n",
  140. session->subtype);
  141. return 0;
  142. }
  143. /*
  144. * decode MID 0xDC, Measurement Time
  145. *
  146. * 10 bytes
  147. */
  148. static gps_mask_t sky_msg_DC(struct gps_device_t *session,
  149. unsigned char *buf, size_t len)
  150. {
  151. unsigned int iod; // Issue of data 0 - 255
  152. unsigned int wn; // week number 0 - 65535
  153. unsigned int tow; // receiver tow 0 - 604799999 in mS
  154. unsigned int mp; // measurement period 1 - 1000 ms
  155. char ts_buf[TIMESPEC_LEN];
  156. timespec_t ts_tow;
  157. if (10 != len) {
  158. return 0;
  159. }
  160. iod = (unsigned int)getub(buf, 1);
  161. wn = getbeu16(buf, 2);
  162. tow = getbeu32(buf, 4);
  163. mp = getbeu16(buf, 8);
  164. MSTOTS(&ts_tow, tow);
  165. // should this be newdata.skyview_time?
  166. session->gpsdata.skyview_time = gpsd_gpstime_resolv(session, wn, ts_tow);
  167. GPSD_LOG(LOG_DATA, &session->context->errout,
  168. "Skytraq: MID 0xDC: iod %u wn %u tow %u mp %u t%s\n",
  169. iod, wn, tow, mp,
  170. timespec_str(&session->gpsdata.skyview_time, ts_buf,
  171. sizeof(ts_buf)));
  172. return 0;
  173. }
  174. /*
  175. * decode MID 0xDD, Raw Measurements
  176. *
  177. */
  178. static gps_mask_t sky_msg_DD(struct gps_device_t *session,
  179. unsigned char *buf, size_t len UNUSED)
  180. {
  181. unsigned int iod; /* Issue of data 0 - 255 */
  182. unsigned int nmeas; /* number of measurements */
  183. unsigned int i; /* generic loop variable */
  184. iod = (unsigned int)getub(buf, 1);
  185. nmeas = (unsigned int)getub(buf, 2);
  186. GPSD_LOG(LOG_DATA, &session->context->errout,
  187. "Skytraq: MID 0xDD: iod=%u, nmeas=%u\n",
  188. iod, nmeas);
  189. /* check IOD? */
  190. session->gpsdata.raw.mtime = session->gpsdata.skyview_time;
  191. /* zero the measurement data */
  192. /* so we can tell which meas never got set */
  193. memset(session->gpsdata.raw.meas, 0, sizeof(session->gpsdata.raw.meas));
  194. for (i = 0; i < nmeas; i++) {
  195. const char *obs_code;
  196. int off = 3 + (23 * i);
  197. uint8_t PRN = getub(buf, off + 0);
  198. /* carrier-to-noise density ratio dB-Hz */
  199. uint8_t cno = getub(buf, off + 1);
  200. /* pseudorange in meters */
  201. double prMes = getbed64((const char *)buf, off + 2);
  202. /* carrier phase in cycles */
  203. double cpMes = getbed64((const char *)buf, off + 10);
  204. /* doppler in Hz, positive towards sat */
  205. double doMes = getbef32((const char *)buf, off + 18);
  206. /* tracking stat
  207. * bit 0 - prMes valid
  208. * bit 1 - doppler valid
  209. * bit 2 - cpMes valid
  210. * bit 3 - cp slip
  211. * bit 4 - Coherent integration time?
  212. */
  213. uint8_t trkStat = getub(buf, off + 22);
  214. uint8_t gnssId = 0;
  215. uint8_t svId = 0;
  216. PRN2_gnssId_svId(PRN, &gnssId, &svId);
  217. session->gpsdata.raw.meas[i].gnssid = gnssId;
  218. switch (gnssId) {
  219. case 0: /* GPS */
  220. case 5: /* QZSS */
  221. case 20: /* IRNSS, just guessing here */
  222. obs_code = "L1C"; /* u-blox calls this L1C/A */
  223. break;
  224. case 1: /* SBAS */
  225. svId -= 100; /* adjust for RINEX 3 svid */
  226. obs_code = "L1C"; /* u-blox calls this L1C/A */
  227. break;
  228. case 2: /* GALILEO */
  229. obs_code = "L1B"; /* u-blox calls this E1OS */
  230. break;
  231. case 3: /* BeiDou */
  232. obs_code = "L2I"; /* u-blox calls this B1I */
  233. break;
  234. default: /* huh? */
  235. case 4: /* IMES. really? */
  236. obs_code = ""; /* u-blox calls this L1 */
  237. break;
  238. case 6: /* GLONASS */
  239. obs_code = "L1C"; /* u-blox calls this L1OF */
  240. break;
  241. }
  242. (void)strlcpy(session->gpsdata.raw.meas[i].obs_code, obs_code,
  243. sizeof(session->gpsdata.raw.meas[i].obs_code));
  244. session->gpsdata.raw.meas[i].svid = svId;
  245. session->gpsdata.raw.meas[i].snr = cno;
  246. session->gpsdata.raw.meas[i].satstat = trkStat;
  247. if (trkStat & 1) {
  248. /* prMes valid */
  249. session->gpsdata.raw.meas[i].pseudorange = prMes;
  250. } else {
  251. session->gpsdata.raw.meas[i].pseudorange = NAN;
  252. }
  253. if (trkStat & 2) {
  254. /* doppler valid */
  255. session->gpsdata.raw.meas[i].doppler = doMes;
  256. } else {
  257. session->gpsdata.raw.meas[i].doppler = NAN;
  258. }
  259. if (trkStat & 4) {
  260. /* cpMes valid */
  261. session->gpsdata.raw.meas[i].carrierphase = cpMes;
  262. } else {
  263. session->gpsdata.raw.meas[i].carrierphase = NAN;
  264. }
  265. session->gpsdata.raw.meas[i].codephase = NAN;
  266. session->gpsdata.raw.meas[i].deltarange = NAN;
  267. /* skytraq does not report locktime, so assume max */
  268. session->gpsdata.raw.meas[i].locktime = LOCKMAX;
  269. if (trkStat & 8) {
  270. /* possible slip */
  271. session->gpsdata.raw.meas[i].lli = 2;
  272. }
  273. GPSD_LOG(LOG_DATA, &session->context->errout,
  274. "PRN %u (%u:%u) prMes %f cpMes %f doMes %f\n"
  275. "cno %u rtkStat %u\n", PRN,
  276. gnssId, svId, prMes, cpMes, doMes, cno, trkStat);
  277. }
  278. // return RAW_IS; /* WIP */
  279. return 0;
  280. }
  281. /*
  282. * decode MID 0xDE, SV and channel status
  283. *
  284. * max payload: 3 + (Num_sats * 10) = 483 bytes
  285. */
  286. static gps_mask_t sky_msg_DE(struct gps_device_t *session,
  287. unsigned char *buf, size_t len UNUSED)
  288. {
  289. int st, nsv;
  290. unsigned int i;
  291. unsigned int iod; /* Issue of data 0 - 255 */
  292. unsigned int nsvs; /* number of SVs in this packet */
  293. iod = (unsigned int)getub(buf, 1);
  294. nsvs = (unsigned int)getub(buf, 2);
  295. /* too many sats? */
  296. if ( SKY_CHANNELS < nsvs )
  297. return 0;
  298. gpsd_zero_satellites(&session->gpsdata);
  299. for (i = st = nsv = 0; i < nsvs; i++) {
  300. int off = 3 + (10 * i); /* offset into buffer of start of this sat */
  301. bool good; /* do we have a good record ? */
  302. unsigned short sv_stat;
  303. unsigned short chan_stat;
  304. unsigned short ura;
  305. short PRN;
  306. uint8_t gnssId = 0;
  307. uint8_t svId = 0;
  308. PRN = (short)getub(buf, off + 1);
  309. /* fit into gnssid:svid */
  310. if (0 == PRN) {
  311. /* skip 0 PRN */
  312. continue;
  313. }
  314. PRN2_gnssId_svId(PRN, &gnssId, &svId);
  315. session->gpsdata.skyview[st].gnssid = gnssId;
  316. session->gpsdata.skyview[st].svid = svId;
  317. session->gpsdata.skyview[st].PRN = PRN;
  318. sv_stat = (unsigned short)getub(buf, off + 2);
  319. ura = (unsigned short)getub(buf, off + 3);
  320. session->gpsdata.skyview[st].ss = (double)getub(buf, off + 4);
  321. session->gpsdata.skyview[st].elevation =
  322. (double)getbes16(buf, off + 5);
  323. session->gpsdata.skyview[st].azimuth =
  324. (double)getbes16(buf, off + 7);
  325. chan_stat = (unsigned short)getub(buf, off + 9);
  326. session->gpsdata.skyview[st].used = (bool)(chan_stat & 0x30);
  327. good = session->gpsdata.skyview[st].PRN != 0 &&
  328. session->gpsdata.skyview[st].azimuth != 0 &&
  329. session->gpsdata.skyview[st].elevation != 0;
  330. GPSD_LOG(LOG_DATA, &session->context->errout,
  331. "Skytraq: PRN=%2d El=%4.0f Az=%5.0f ss=%3.2f stat=%02x,%02x "
  332. "ura=%d %c\n",
  333. session->gpsdata.skyview[st].PRN,
  334. session->gpsdata.skyview[st].elevation,
  335. session->gpsdata.skyview[st].azimuth,
  336. session->gpsdata.skyview[st].ss,
  337. chan_stat, sv_stat, ura,
  338. good ? '*' : ' ');
  339. if ( good ) {
  340. st += 1;
  341. if (session->gpsdata.skyview[st].used)
  342. nsv++;
  343. }
  344. }
  345. session->gpsdata.satellites_visible = st;
  346. session->gpsdata.satellites_used = nsv;
  347. GPSD_LOG(LOG_DATA, &session->context->errout,
  348. "Skytraq: MID 0xDE: nsvs=%u visible=%u iod=%u\n", nsvs,
  349. session->gpsdata.satellites_visible, iod);
  350. return SATELLITE_SET | USED_IS;
  351. }
  352. /*
  353. * decode MID 0xDF, Nav status (PVT)
  354. *
  355. * 81 bytes
  356. */
  357. static gps_mask_t sky_msg_DF(struct gps_device_t *session,
  358. unsigned char *buf, size_t len)
  359. {
  360. unsigned int iod; /* Issue of data 0 - 255 */
  361. unsigned short navstat;
  362. unsigned int wn; /* week number 0 - 65535 */
  363. double f_tow; /* receiver tow Sec */
  364. double clock_bias;
  365. double clock_drift;
  366. gps_mask_t mask = 0;
  367. timespec_t ts_tow;
  368. char ts_buf[TIMESPEC_LEN];
  369. if ( 81 != len)
  370. return 0;
  371. iod = (unsigned int)getub(buf, 1);
  372. /* fix status is byte 2 */
  373. navstat = (unsigned short)getub(buf, 2);
  374. session->newdata.status = STATUS_UNK;
  375. session->newdata.mode = MODE_NO_FIX;
  376. switch ( navstat ) {
  377. case 1:
  378. /* fix prediction, ignore */
  379. break;
  380. case 2:
  381. session->newdata.status = STATUS_GPS;
  382. session->newdata.mode = MODE_2D;
  383. break;
  384. case 3:
  385. session->newdata.status = STATUS_GPS;
  386. session->newdata.mode = MODE_3D;
  387. break;
  388. case 4:
  389. session->newdata.status = STATUS_DGPS;
  390. session->newdata.mode = MODE_3D;
  391. break;
  392. default:
  393. break;
  394. }
  395. wn = getbeu16(buf, 3);
  396. f_tow = getbed64((const char *)buf, 5);
  397. DTOTS(&ts_tow, f_tow);
  398. /* position/velocity is bytes 13-48, meters and m/s */
  399. session->newdata.ecef.x = (double)getbed64((const char *)buf, 13),
  400. session->newdata.ecef.y = (double)getbed64((const char *)buf, 21),
  401. session->newdata.ecef.z = (double)getbed64((const char *)buf, 29),
  402. session->newdata.ecef.vx = (double)getbef32((const char *)buf, 37),
  403. session->newdata.ecef.vy = (double)getbef32((const char *)buf, 41),
  404. session->newdata.ecef.vz = (double)getbef32((const char *)buf, 45);
  405. mask |= ECEF_SET | VECEF_SET;
  406. clock_bias = getbed64((const char *)buf, 49);
  407. clock_drift = getbes32(buf, 57);
  408. session->gpsdata.dop.gdop = getbef32((const char *)buf, 61);
  409. session->gpsdata.dop.pdop = getbef32((const char *)buf, 65);
  410. session->gpsdata.dop.hdop = getbef32((const char *)buf, 69);
  411. session->gpsdata.dop.vdop = getbef32((const char *)buf, 73);
  412. session->gpsdata.dop.tdop = getbef32((const char *)buf, 77);
  413. mask |= DOP_SET;
  414. session->newdata.time = gpsd_gpstime_resolv(session, wn, ts_tow );
  415. GPSD_LOG(LOG_DATA, &session->context->errout,
  416. "Skytraq: MID 0xDF: iod=%u, stat=%u, wn=%u, tow=%f, t=%s "
  417. "cb: %f, cd: %f "
  418. "gdop: %.2f, pdop: %.2f, hdop: %.2f, vdop: %.2f, tdop: %.2f\n",
  419. iod, navstat, wn, f_tow,
  420. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
  421. clock_bias, clock_drift,
  422. session->gpsdata.dop.gdop,
  423. session->gpsdata.dop.pdop,
  424. session->gpsdata.dop.hdop,
  425. session->gpsdata.dop.vdop,
  426. session->gpsdata.dop.tdop);
  427. mask |= TIME_SET | STATUS_SET | MODE_SET | CLEAR_IS | REPORT_IS;
  428. return mask;
  429. }
  430. /*
  431. * decode MID 0xE0, GPS Subframe data
  432. *
  433. * len 33 bytes
  434. *
  435. */
  436. static gps_mask_t sky_msg_E0(struct gps_device_t *session,
  437. unsigned char *buf, size_t len UNUSED)
  438. {
  439. int i;
  440. unsigned int prn; /* GPS sat PRN */
  441. unsigned int subf; /* subframe 1-5 */
  442. /* the words are preprocessed, not raw, just the 24bits of data */
  443. uint32_t words[10]; /* subframe 1-5 */
  444. if ( 33 != len)
  445. return 0;
  446. prn = (unsigned int)getub(buf, 1);
  447. subf = (unsigned int)getub(buf, 2);
  448. for ( i = 0; i < 10; i++ ) {
  449. words[i] = (uint32_t)getbeu24(buf, 3 + (i * 3));
  450. }
  451. GPSD_LOG(LOG_DATA, &session->context->errout,
  452. "Skytraq: 50B MID 0xE0: prn=%u, subf=%u\n",
  453. prn, subf);
  454. // could be SBAS?
  455. return gpsd_interpret_subframe(session, GNSSID_GPS, prn, words);
  456. }
  457. /*
  458. * pretend to decode MID 0xE2, Beiduo D1 Subframe data
  459. *
  460. * from Beidou Standard BDS-SIS-ICD-2.0
  461. * D1, with the data rate of 50 bps, is broadcasted by the MEO/IGSO satellites
  462. *
  463. * len 31 bytes
  464. *
  465. */
  466. static gps_mask_t sky_msg_E2(struct gps_device_t *session,
  467. unsigned char *buf, size_t len)
  468. {
  469. int i;
  470. unsigned int prn; /* BeidouPS sat PRN 206-214 */
  471. unsigned int subf; /* subframe 1-5 */
  472. /* the words are preprocessed, not raw, just the 28 bytes of data */
  473. uint8_t bytes[28]; /* raw data */
  474. if ( 31 != len)
  475. return 0;
  476. prn = (unsigned int)getub(buf, 1);
  477. subf = (unsigned int)getub(buf, 2);
  478. for ( i = 0; i < 28; i++ ) {
  479. bytes[i] = getub(buf, 3 + i);
  480. }
  481. /* extra guard prevents expensive hexdump calls */
  482. if (session->context->errout.debug >= LOG_PROG) {
  483. GPSD_LOG(LOG_PROG, &session->context->errout,
  484. "Skytraq: Beidou D1 subframe PRN %d Subframe %d "
  485. "length %zd byte:%s\n",
  486. prn, subf,
  487. len,
  488. gpsd_hexdump(session->msgbuf, sizeof(session->msgbuf),
  489. (char *)bytes, 28));
  490. }
  491. return ONLINE_SET;
  492. }
  493. /*
  494. * pretend to decode MID 0xE3, Beiduo D2 Subframe data
  495. *
  496. * from Beidou Standard BDS-SIS-ICD-2.0
  497. * D2, with the data rate of 500 bps, is broadcasted by the GEO satellites.
  498. *
  499. * len 31 bytes
  500. *
  501. */
  502. static gps_mask_t sky_msg_E3(struct gps_device_t *session,
  503. unsigned char *buf, size_t len)
  504. {
  505. int i;
  506. unsigned int prn; /* BeidouPS sat PRN 201-205 */
  507. unsigned int subf; /* subframe 1-5 */
  508. /* the words are preprocessed, not raw, just the 28 bytes of data */
  509. uint8_t bytes[28]; /* raw data */
  510. if ( 31 != len)
  511. return 0;
  512. prn = (unsigned int)getub(buf, 1);
  513. subf = (unsigned int)getub(buf, 2);
  514. for ( i = 0; i < 28; i++ ) {
  515. bytes[i] = getub(buf, 3 + i);
  516. }
  517. /* extra guard prevents expensive hexdump calls */
  518. if (session->context->errout.debug >= LOG_PROG) {
  519. GPSD_LOG(LOG_PROG, &session->context->errout,
  520. "Skytraq: Beidou D2 subframe PRN %d Subframe %d "
  521. "length %zd byte:%s\n",
  522. prn, subf,
  523. len,
  524. gpsd_hexdump(session->msgbuf, sizeof(session->msgbuf),
  525. (char *)bytes, 28));
  526. }
  527. return ONLINE_SET;
  528. }
  529. static gps_mask_t sky_parse(struct gps_device_t * session, unsigned char *buf,
  530. size_t len)
  531. {
  532. gps_mask_t mask = 0;
  533. if (len == 0)
  534. return mask;
  535. buf += 4; /* skip the leaders and length */
  536. len -= 7; /* don't count the leaders, length, csum and terminators */
  537. // session->driver.sirf.lastid = buf[0];
  538. /* check the checksum?? */
  539. /* could change if the set of messages we enable does */
  540. /* session->cycle_end_reliable = true; */
  541. switch (buf[0]) {
  542. case 0x80:
  543. // 128
  544. return sky_msg_80(session, buf, len);
  545. case 0x83:
  546. // 131 - ACK
  547. GPSD_LOG(LOG_PROG, &session->context->errout,
  548. "Skytraq: ACK to MID %#02x\n", buf[1]);
  549. break;
  550. case 0x84:
  551. // 132 - NACK
  552. GPSD_LOG(LOG_INF, &session->context->errout,
  553. "Skytraq: NACK to MID %#02x\n", buf[1]);
  554. break;
  555. case 0xDC:
  556. // 220
  557. return sky_msg_DC(session, buf, len);
  558. case 0xDD:
  559. // 221
  560. return sky_msg_DD(session, buf, len);
  561. case 0xDE:
  562. // 222
  563. return sky_msg_DE(session, buf, len);
  564. case 0xDF:
  565. // 223 - Nave status (PVT)
  566. return sky_msg_DF(session, buf, len);
  567. case 0xE0:
  568. // 224
  569. return sky_msg_E0(session, buf, len);
  570. case 0xE2:
  571. // 226 - Beidou2 D1 Subframe data
  572. return sky_msg_E2(session, buf, len);
  573. case 0xE3:
  574. // 227 - Beidou2 D2 Subframe data
  575. return sky_msg_E3(session, buf, len);
  576. default:
  577. GPSD_LOG(LOG_PROG, &session->context->errout,
  578. "Skytraq: Unknown packet id %#02x length %zd\n",
  579. buf[0], len);
  580. }
  581. return mask;
  582. }
  583. static gps_mask_t skybin_parse_input(struct gps_device_t *session)
  584. {
  585. if (SKY_PACKET == session->lexer.type) {
  586. return sky_parse(session, session->lexer.outbuffer,
  587. session->lexer.outbuflen);
  588. }
  589. if (NMEA_PACKET == session->lexer.type) {
  590. return nmea_parse((char *)session->lexer.outbuffer, session);
  591. }
  592. return 0;
  593. }
  594. // this is everything we export
  595. // *INDENT-OFF*
  596. const struct gps_type_t driver_skytraq =
  597. {
  598. .type_name = "Skytraq", // full name of type
  599. .packet_type = SKY_PACKET, // associated lexer packet type
  600. .flags = DRIVER_STICKY, // remember this
  601. .trigger = NULL, // no trigger
  602. .channels = SKY_CHANNELS, // consumer-grade GPS
  603. .probe_detect = NULL, // no probe
  604. .get_packet = generic_get, // be prepared for Skytraq or NMEA
  605. .parse_packet = skybin_parse_input, // parse message packets
  606. .rtcm_writer = gpsd_write, // send RTCM data straight
  607. .init_query = NULL, // non-perturbing initial qury
  608. .event_hook = NULL, // lifetime event handler
  609. };
  610. // *INDENT-ON*
  611. #endif // defined( SKYTRAQ_ENABLE) && defined(BINARY_ENABLE)
  612. // vim: set expandtab shiftwidth=4