gpsdecode.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. /*
  2. * This file is Copyright 2010 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <stdbool.h>
  9. #include <string.h>
  10. #include <stdarg.h>
  11. #include <unistd.h>
  12. #include "gpsd.h"
  13. #include "bits.h"
  14. #include "gps_json.h"
  15. #include "strfuncs.h"
  16. static int verbose = 0;
  17. static bool scaled = true;
  18. static bool json = true;
  19. static bool pseudonmea = false;
  20. static bool split24 = false;
  21. static bool minlength = false;
  22. static unsigned int ntypes = 0;
  23. static unsigned int typelist[32];
  24. static struct gps_context_t context;
  25. /**************************************************************************
  26. *
  27. * Generic machinery
  28. *
  29. **************************************************************************/
  30. #ifdef AIVDM_ENABLE
  31. static const char *raw_hexdump(char *scbuf, size_t scbuflen, int structured,
  32. char *binbuf, size_t binbuflen)
  33. {
  34. if (!structured)
  35. return gpsd_hexdump(scbuf, scbuflen, binbuf, binbuflen);
  36. /* Data parsed as structured doesn't have correct raw data */
  37. #ifndef SQUELCH_ENABLE
  38. size_t len =
  39. (size_t) ((binbuflen >
  40. MAX_PACKET_LENGTH) ? MAX_PACKET_LENGTH : binbuflen) * 2;
  41. if (len > scbuflen - 1) len = scbuflen - 1;
  42. memset(scbuf, 'x', len);
  43. scbuf[len] = '\0';
  44. #else /* SQUELCH defined */
  45. scbuf[0] = '\0';
  46. #endif /* SQUELCH_ENABLE */
  47. return scbuf;
  48. }
  49. static void aivdm_csv_dump(struct ais_t *ais, char *buf, size_t buflen)
  50. {
  51. char scratchbuf[MAX_PACKET_LENGTH*2+1];
  52. bool imo = false;
  53. (void)snprintf(buf, buflen, "%u|%u|%09u|", ais->type, ais->repeat,
  54. ais->mmsi);
  55. switch (ais->type) {
  56. case 1: /* Position Report */
  57. case 2:
  58. case 3:
  59. str_appendf(buf, buflen,
  60. "%u|%d|%u|%u|%d|%d|%u|%u|%u|0x%x|%u|0x%x",
  61. ais->type1.status,
  62. ais->type1.turn,
  63. ais->type1.speed,
  64. (unsigned int) ais->type1.accuracy,
  65. ais->type1.lon,
  66. ais->type1.lat,
  67. ais->type1.course,
  68. ais->type1.heading,
  69. ais->type1.second,
  70. ais->type1.maneuver,
  71. (unsigned int) ais->type1.raim, ais->type1.radio);
  72. break;
  73. case 4: /* Base Station Report */
  74. case 11: /* UTC/Date Response */
  75. str_appendf(buf, buflen,
  76. "%04u-%02u-%02uT%02u:%02u:%02uZ|%u|%d|%d|%u|%u|0x%x",
  77. ais->type4.year,
  78. ais->type4.month,
  79. ais->type4.day,
  80. ais->type4.hour,
  81. ais->type4.minute,
  82. ais->type4.second,
  83. (unsigned int) ais->type4.accuracy,
  84. ais->type4.lon,
  85. ais->type4.lat,
  86. ais->type4.epfd,
  87. (unsigned int) ais->type4.raim, ais->type4.radio);
  88. break;
  89. case 5: /* Ship static and voyage related data */
  90. str_appendf(buf, buflen,
  91. "%u|%u|%s|%s|%u|%u|%u|%u|%u|%u|%02u-%02uT%02u:%02uZ"
  92. "|%u|%s|%u",
  93. ais->type5.imo,
  94. ais->type5.ais_version,
  95. ais->type5.callsign,
  96. ais->type5.shipname,
  97. ais->type5.shiptype,
  98. ais->type5.to_bow,
  99. ais->type5.to_stern,
  100. ais->type5.to_port,
  101. ais->type5.to_starboard,
  102. ais->type5.epfd,
  103. ais->type5.month,
  104. ais->type5.day,
  105. ais->type5.hour,
  106. ais->type5.minute,
  107. ais->type5.draught,
  108. ais->type5.destination, ais->type5.dte);
  109. break;
  110. case 6: /* Binary Message */
  111. str_appendf(buf, buflen,
  112. "%u|%u|%u|%u|%u",
  113. ais->type6.seqno,
  114. ais->type6.dest_mmsi,
  115. (unsigned int) ais->type6.retransmit,
  116. ais->type6.dac,
  117. ais->type6.fid);
  118. switch(ais->type6.dac) {
  119. case 235: /* UK */
  120. case 250: /* Rep. Of Ireland */
  121. switch(ais->type6.fid) {
  122. case 10: /* GLA - AtoN monitoring */
  123. str_appendf(buf, buflen,
  124. "|%u|%u|%u|%u|%u|%u|%u|%u",
  125. ais->type6.dac235fid10.ana_int,
  126. ais->type6.dac235fid10.ana_ext1,
  127. ais->type6.dac235fid10.ana_ext2,
  128. ais->type6.dac235fid10.racon,
  129. ais->type6.dac235fid10.light,
  130. (unsigned int)ais->type6.dac235fid10.alarm,
  131. ais->type6.dac235fid10.stat_ext,
  132. (unsigned int)ais->type6.dac235fid10.off_pos);
  133. imo = true;
  134. break;
  135. }
  136. break;
  137. }
  138. if (!imo)
  139. str_appendf(buf, buflen,
  140. "|%zd:%s",
  141. ais->type6.bitcount,
  142. raw_hexdump(scratchbuf, sizeof(scratchbuf),
  143. ais->type6.structured,
  144. ais->type6.bitdata,
  145. BITS_TO_BYTES(ais->type6.bitcount)));
  146. break;
  147. case 7: /* Binary Acknowledge */
  148. case 13: /* Safety Related Acknowledge */
  149. str_appendf(buf, buflen,
  150. "%u|%u|%u|%u",
  151. ais->type7.mmsi1,
  152. ais->type7.mmsi2, ais->type7.mmsi3, ais->type7.mmsi4);
  153. break;
  154. case 8: /* Binary Broadcast Message */
  155. str_appendf(buf, buflen, "%u|%u", ais->type8.dac, ais->type8.fid);
  156. switch(ais->type8.dac) {
  157. case 1: /* International */
  158. switch(ais->type8.fid) {
  159. case 11: /* IMO236 - Met/Hydro message */
  160. str_appendf(buf, buflen,
  161. "|%d|%d|%02uT%02u:%02uZ|%u|%u|%u|%u|%u|%u|%u"
  162. "|%u|%u|%u|%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u"
  163. "|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
  164. ais->type8.dac1fid11.lon,
  165. ais->type8.dac1fid11.lat,
  166. ais->type8.dac1fid11.day,
  167. ais->type8.dac1fid11.hour,
  168. ais->type8.dac1fid11.minute,
  169. ais->type8.dac1fid11.wspeed,
  170. ais->type8.dac1fid11.wgust,
  171. ais->type8.dac1fid11.wdir,
  172. ais->type8.dac1fid11.wgustdir,
  173. ais->type8.dac1fid11.airtemp,
  174. ais->type8.dac1fid11.humidity,
  175. ais->type8.dac1fid11.dewpoint,
  176. ais->type8.dac1fid11.pressure,
  177. ais->type8.dac1fid11.pressuretend,
  178. ais->type8.dac1fid11.visibility,
  179. ais->type8.dac1fid11.waterlevel,
  180. ais->type8.dac1fid11.leveltrend,
  181. ais->type8.dac1fid11.cspeed,
  182. ais->type8.dac1fid11.cdir,
  183. ais->type8.dac1fid11.cspeed2,
  184. ais->type8.dac1fid11.cdir2,
  185. ais->type8.dac1fid11.cdepth2,
  186. ais->type8.dac1fid11.cspeed3,
  187. ais->type8.dac1fid11.cdir3,
  188. ais->type8.dac1fid11.cdepth3,
  189. ais->type8.dac1fid11.waveheight,
  190. ais->type8.dac1fid11.waveperiod,
  191. ais->type8.dac1fid11.wavedir,
  192. ais->type8.dac1fid11.swellheight,
  193. ais->type8.dac1fid11.swellperiod,
  194. ais->type8.dac1fid11.swelldir,
  195. ais->type8.dac1fid11.seastate,
  196. ais->type8.dac1fid11.watertemp,
  197. ais->type8.dac1fid11.preciptype,
  198. ais->type8.dac1fid11.salinity,
  199. ais->type8.dac1fid11.ice);
  200. imo = true;
  201. break;
  202. case 31: /* IMO289 - Met/Hydro message */
  203. str_appendf(buf, buflen,
  204. "|%d|%d|%02uT%02u:%02uZ|%u|%u|%u|%u|%d|%u|%d|%u"
  205. "|%u|%u|%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u"
  206. "|%u|%u|%u|%u|%d|%u|%u|%u",
  207. ais->type8.dac1fid31.lon,
  208. ais->type8.dac1fid31.lat,
  209. ais->type8.dac1fid31.day,
  210. ais->type8.dac1fid31.hour,
  211. ais->type8.dac1fid31.minute,
  212. ais->type8.dac1fid31.wspeed,
  213. ais->type8.dac1fid31.wgust,
  214. ais->type8.dac1fid31.wdir,
  215. ais->type8.dac1fid31.wgustdir,
  216. ais->type8.dac1fid31.airtemp,
  217. ais->type8.dac1fid31.humidity,
  218. ais->type8.dac1fid31.dewpoint,
  219. ais->type8.dac1fid31.pressure,
  220. ais->type8.dac1fid31.pressuretend,
  221. ais->type8.dac1fid31.visibility,
  222. ais->type8.dac1fid31.waterlevel,
  223. ais->type8.dac1fid31.leveltrend,
  224. ais->type8.dac1fid31.cspeed,
  225. ais->type8.dac1fid31.cdir,
  226. ais->type8.dac1fid31.cspeed2,
  227. ais->type8.dac1fid31.cdir2,
  228. ais->type8.dac1fid31.cdepth2,
  229. ais->type8.dac1fid31.cspeed3,
  230. ais->type8.dac1fid31.cdir3,
  231. ais->type8.dac1fid31.cdepth3,
  232. ais->type8.dac1fid31.waveheight,
  233. ais->type8.dac1fid31.waveperiod,
  234. ais->type8.dac1fid31.wavedir,
  235. ais->type8.dac1fid31.swellheight,
  236. ais->type8.dac1fid31.swellperiod,
  237. ais->type8.dac1fid31.swelldir,
  238. ais->type8.dac1fid31.seastate,
  239. ais->type8.dac1fid31.watertemp,
  240. ais->type8.dac1fid31.preciptype,
  241. ais->type8.dac1fid31.salinity,
  242. ais->type8.dac1fid31.ice);
  243. imo = true;
  244. break;
  245. }
  246. break;
  247. }
  248. if (!imo)
  249. str_appendf(buf, buflen,
  250. "|%zd:%s",
  251. ais->type8.bitcount,
  252. raw_hexdump(scratchbuf, sizeof(scratchbuf),
  253. ais->type8.structured,
  254. ais->type8.bitdata,
  255. BITS_TO_BYTES(ais->type8.bitcount)));
  256. break;
  257. case 9:
  258. str_appendf(buf, buflen,
  259. "%u|%u|%u|%d|%d|%u|%u|0x%x|%u|%u|0x%x",
  260. ais->type9.alt,
  261. ais->type9.speed,
  262. (unsigned int) ais->type9.accuracy,
  263. ais->type9.lon,
  264. ais->type9.lat,
  265. ais->type9.course,
  266. ais->type9.second,
  267. ais->type9.regional,
  268. ais->type9.dte,
  269. (unsigned int) ais->type9.raim, ais->type9.radio);
  270. break;
  271. case 10: /* UTC/Date Inquiry */
  272. str_appendf(buf, buflen, "%u", ais->type10.dest_mmsi);
  273. break;
  274. case 12: /* Safety Related Message */
  275. str_appendf(buf, buflen,
  276. "%u|%u|%u|%s",
  277. ais->type12.seqno,
  278. ais->type12.dest_mmsi,
  279. (unsigned int) ais->type12.retransmit, ais->type12.text);
  280. break;
  281. case 14: /* Safety Related Broadcast Message */
  282. str_appendf(buf, buflen, "%s", ais->type14.text);
  283. break;
  284. case 15:
  285. str_appendf(buf, buflen,
  286. "%u|%u|%u|%u|%u|%u|%u|%u",
  287. ais->type15.mmsi1,
  288. ais->type15.type1_1,
  289. ais->type15.offset1_1,
  290. ais->type15.type1_2,
  291. ais->type15.offset1_2,
  292. ais->type15.mmsi2,
  293. ais->type15.type2_1, ais->type15.offset2_1);
  294. break;
  295. case 16:
  296. str_appendf(buf, buflen,
  297. "%u|%u|%u|%u|%u|%u",
  298. ais->type16.mmsi1,
  299. ais->type16.offset1,
  300. ais->type16.increment1,
  301. ais->type16.mmsi2,
  302. ais->type16.offset2, ais->type16.increment2);
  303. break;
  304. case 17:
  305. str_appendf(buf, buflen,
  306. "%d|%d|%zd:%s",
  307. ais->type17.lon,
  308. ais->type17.lat,
  309. ais->type17.bitcount,
  310. gpsd_hexdump(scratchbuf, sizeof(scratchbuf),
  311. ais->type17.bitdata,
  312. BITS_TO_BYTES(ais->type17.bitcount)));
  313. break;
  314. case 18:
  315. str_appendf(buf, buflen,
  316. "%u|%u|%u|%d|%d|%u|%u|%u|0x%x|%u|%u|%u|%u|%u|%u|0x%x",
  317. ais->type18.reserved,
  318. ais->type18.speed,
  319. (unsigned int) ais->type18.accuracy,
  320. ais->type18.lon,
  321. ais->type18.lat,
  322. ais->type18.course,
  323. ais->type18.heading,
  324. ais->type18.second,
  325. ais->type18.regional,
  326. (unsigned int) ais->type18.cs,
  327. (unsigned int) ais->type18.display,
  328. (unsigned int) ais->type18.dsc,
  329. (unsigned int) ais->type18.band,
  330. (unsigned int) ais->type18.msg22,
  331. (unsigned int) ais->type18.raim, ais->type18.radio);
  332. break;
  333. case 19:
  334. str_appendf(buf, buflen,
  335. "%u|%u|%u|%d|%d|%u|%u|%u|0x%x|%s|%u|%u|%u|%u|%u|%u|%u|%u|%u",
  336. ais->type19.reserved,
  337. ais->type19.speed,
  338. (unsigned int) ais->type19.accuracy,
  339. ais->type19.lon,
  340. ais->type19.lat,
  341. ais->type19.course,
  342. ais->type19.heading,
  343. ais->type19.second,
  344. ais->type19.regional,
  345. ais->type19.shipname,
  346. ais->type19.shiptype,
  347. ais->type19.to_bow,
  348. ais->type19.to_stern,
  349. ais->type19.to_port,
  350. ais->type19.to_starboard,
  351. ais->type19.epfd,
  352. (unsigned int) ais->type19.raim,
  353. ais->type19.dte, (unsigned int) ais->type19.assigned);
  354. break;
  355. case 20: /* Data Link Management Message */
  356. str_appendf(buf, buflen,
  357. "%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
  358. ais->type20.offset1,
  359. ais->type20.number1,
  360. ais->type20.timeout1,
  361. ais->type20.increment1,
  362. ais->type20.offset2,
  363. ais->type20.number2,
  364. ais->type20.timeout2,
  365. ais->type20.increment2,
  366. ais->type20.offset3,
  367. ais->type20.number3,
  368. ais->type20.timeout3,
  369. ais->type20.increment3,
  370. ais->type20.offset4,
  371. ais->type20.number4,
  372. ais->type20.timeout4, ais->type20.increment4);
  373. break;
  374. case 21: /* Aid to Navigation */
  375. str_appendf(buf, buflen,
  376. "%u|%s|%u|%d|%d|%u|%u|%u|%u|%u|%u|%u|0x%x|%u|%u",
  377. ais->type21.aid_type,
  378. ais->type21.name,
  379. (unsigned int) ais->type21.accuracy,
  380. ais->type21.lon,
  381. ais->type21.lat,
  382. ais->type21.to_bow,
  383. ais->type21.to_stern,
  384. ais->type21.to_port,
  385. ais->type21.to_starboard,
  386. ais->type21.epfd,
  387. ais->type21.second,
  388. ais->type21.regional,
  389. (unsigned int) ais->type21.off_position,
  390. (unsigned int) ais->type21.raim,
  391. (unsigned int) ais->type21.virtual_aid);
  392. break;
  393. case 22: /* Channel Management */
  394. if (!ais->type22.addressed)
  395. str_appendf(buf, buflen,
  396. "%u|%u|%u|%u|%d|%d|%d|%d|%u|%u|%u|%u",
  397. ais->type22.channel_a,
  398. ais->type22.channel_b,
  399. ais->type22.txrx,
  400. (unsigned int) ais->type22.power,
  401. ais->type22.area.ne_lon,
  402. ais->type22.area.ne_lat,
  403. ais->type22.area.sw_lon,
  404. ais->type22.area.sw_lat,
  405. (unsigned int)ais->type22.addressed,
  406. (unsigned int)ais->type22.band_a,
  407. (unsigned int)ais->type22.band_b,
  408. ais->type22.zonesize);
  409. else
  410. str_appendf(buf, buflen,
  411. "%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
  412. ais->type22.channel_a,
  413. ais->type22.channel_b,
  414. ais->type22.txrx,
  415. (unsigned int) ais->type22.power,
  416. ais->type22.mmsi.dest1,
  417. ais->type22.mmsi.dest2,
  418. (unsigned int) ais->type22.addressed,
  419. (unsigned int) ais->type22.band_a,
  420. (unsigned int) ais->type22.band_b,
  421. ais->type22.zonesize);
  422. break;
  423. case 23: /* Group Management Command */
  424. str_appendf(buf, buflen,
  425. "%d|%d|%d|%d|%u|%u|%u|%u|%u",
  426. ais->type23.ne_lon,
  427. ais->type23.ne_lat,
  428. ais->type23.sw_lon,
  429. ais->type23.sw_lat,
  430. ais->type23.stationtype,
  431. ais->type23.shiptype,
  432. ais->type23.txrx,
  433. ais->type23.interval, ais->type23.quiet);
  434. break;
  435. case 24: /* Class B CS Static Data Report */
  436. str_appendf(buf, buflen, "%s|", ais->type24.shipname);
  437. str_appendf(buf, buflen, "%u|", ais->type24.shiptype);
  438. str_appendf(buf, buflen, "%s|", ais->type24.vendorid);
  439. str_appendf(buf, buflen, "%u|", ais->type24.model);
  440. str_appendf(buf, buflen, "%u|", ais->type24.serial);
  441. str_appendf(buf, buflen, "%s|", ais->type24.callsign);
  442. if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
  443. str_appendf(buf, buflen, "%u", ais->type24.mothership_mmsi);
  444. } else {
  445. str_appendf(buf, buflen,
  446. "%u|%u|%u|%u",
  447. ais->type24.dim.to_bow,
  448. ais->type24.dim.to_stern,
  449. ais->type24.dim.to_port,
  450. ais->type24.dim.to_starboard);
  451. }
  452. break;
  453. case 25: /* Binary Message, Single Slot */
  454. str_appendf(buf, buflen,
  455. "%u|%u|%u|%u|%zd:%s",
  456. (unsigned int) ais->type25.addressed,
  457. (unsigned int) ais->type25.structured,
  458. ais->type25.dest_mmsi,
  459. ais->type25.app_id,
  460. ais->type25.bitcount,
  461. gpsd_hexdump(scratchbuf, sizeof(scratchbuf),
  462. ais->type25.bitdata,
  463. BITS_TO_BYTES(ais->type25.bitcount)));
  464. break;
  465. case 26: /* Binary Message, Multiple Slot */
  466. str_appendf(buf, buflen,
  467. "%u|%u|%u|%u|%zd:%s:%u",
  468. (unsigned int) ais->type26.addressed,
  469. (unsigned int) ais->type26.structured,
  470. ais->type26.dest_mmsi,
  471. ais->type26.app_id,
  472. ais->type26.bitcount,
  473. gpsd_hexdump(scratchbuf, sizeof(scratchbuf),
  474. ais->type26.bitdata,
  475. BITS_TO_BYTES(ais->type26.bitcount)),
  476. ais->type26.radio);
  477. break;
  478. case 27: /* Long Range AIS Broadcast message */
  479. str_appendf(buf, buflen,
  480. "%u|%u|%d|%d|%u|%u|%u|%u",
  481. ais->type27.status,
  482. (unsigned int)ais->type27.accuracy,
  483. ais->type27.lon,
  484. ais->type27.lat,
  485. ais->type27.speed,
  486. ais->type27.course,
  487. (unsigned int)ais->type27.raim,
  488. (unsigned int)ais->type27.gnss);
  489. break;
  490. default:
  491. str_appendf(buf, buflen, "unknown AIVDM message content.");
  492. break;
  493. }
  494. (void)strlcat(buf, "\r\n", buflen);
  495. }
  496. #endif
  497. /* say whether a given message should be visible */
  498. static bool filter(gps_mask_t changed, struct gps_device_t *session)
  499. {
  500. if (ntypes == 0)
  501. return true;
  502. else {
  503. unsigned int i, t;
  504. if ((changed & AIS_SET)!=0)
  505. t = session->gpsdata.ais.type;
  506. else if ((changed & RTCM2_SET)!=0)
  507. t = session->gpsdata.rtcm2.type;
  508. else if ((changed & RTCM3_SET)!=0)
  509. t = session->gpsdata.rtcm3.type;
  510. else
  511. return true;
  512. for (i = 0; i < ntypes; i++)
  513. if (t == typelist[i])
  514. return true;
  515. }
  516. return false;
  517. }
  518. /* report pseudo-NMEA in appropriate circumstances */
  519. static void pseudonmea_report(gps_mask_t changed, struct gps_device_t *device)
  520. {
  521. if (GPS_PACKET_TYPE(device->lexer.type)
  522. && !TEXTUAL_PACKET_TYPE(device->lexer.type)) {
  523. char buf[MAX_PACKET_LENGTH * 3 + 2];
  524. if ((changed & REPORT_IS) != 0) {
  525. nmea_tpv_dump(device, buf, sizeof(buf));
  526. (void)fputs(buf, stdout);
  527. }
  528. if ((changed & SATELLITE_SET) != 0) {
  529. nmea_sky_dump(device, buf, sizeof(buf));
  530. (void)fputs(buf, stdout);
  531. }
  532. if ((changed & SUBFRAME_SET) != 0) {
  533. nmea_subframe_dump(device, buf, sizeof(buf));
  534. (void)fputs(buf, stdout);
  535. }
  536. #ifdef AIVDM_ENABLE
  537. if ((changed & AIS_SET) != 0) {
  538. nmea_ais_dump(device, buf, sizeof(buf));
  539. (void)fputs(buf, stdout);
  540. }
  541. #endif /* AIVDM_ENABLE */
  542. }
  543. }
  544. /* sensor data on fpin to dump format on fpout */
  545. static void decode(FILE *fpin, FILE*fpout)
  546. {
  547. struct gps_device_t session;
  548. struct gps_policy_t policy;
  549. size_t minima[PACKET_TYPES+1];
  550. #if defined(SOCKET_EXPORT_ENABLE) || defined(AIVDM_ENABLE)
  551. char buf[GPS_JSON_RESPONSE_MAX * 4];
  552. #endif
  553. int i;
  554. //This looks like a good idea, but it breaks regression tests
  555. //(void)strlcpy(session.gpsdata.dev.path, "stdin",
  556. // sizeof(session.gpsdata.dev.path));
  557. memset(&policy, '\0', sizeof(policy));
  558. policy.json = json;
  559. policy.scaled = scaled;
  560. policy.nmea = pseudonmea;
  561. gpsd_time_init(&context, time(NULL));
  562. context.readonly = true;
  563. gpsd_init(&session, &context, NULL);
  564. gpsd_clear(&session);
  565. session.gpsdata.gps_fd = fileno(fpin);
  566. session.gpsdata.dev.baudrate = 38400; /* hack to enable subframes */
  567. (void)strlcpy(session.gpsdata.dev.path,
  568. "stdin",
  569. sizeof(session.gpsdata.dev.path));
  570. for (i = 0; i < (int)(sizeof(minima)/sizeof(minima[0])); i++)
  571. minima[i] = MAX_PACKET_LENGTH+1;
  572. for (;;)
  573. {
  574. gps_mask_t changed = gpsd_poll(&session);
  575. if (changed == ERROR_SET || changed == NODATA_IS)
  576. break;
  577. if (session.lexer.type == COMMENT_PACKET)
  578. gpsd_set_century(&session);
  579. if (verbose >= 1 && TEXTUAL_PACKET_TYPE(session.lexer.type))
  580. (void)fputs((char *)session.lexer.outbuffer, fpout);
  581. if (session.lexer.outbuflen < minima[session.lexer.type+1])
  582. minima[session.lexer.type+1] = session.lexer.outbuflen;
  583. /* mask should match what's in report_data() */
  584. if ((changed & (REPORT_IS|GST_SET|SATELLITE_SET|SUBFRAME_SET|
  585. ATTITUDE_SET|RTCM2_SET|RTCM3_SET|AIS_SET|
  586. PASSTHROUGH_IS)) == 0)
  587. continue;
  588. if (!filter(changed, &session))
  589. continue;
  590. else if (json) {
  591. if ((changed & PASSTHROUGH_IS) != 0) {
  592. (void)fputs((char *)session.lexer.outbuffer, fpout);
  593. (void)fputs("\n", fpout);
  594. }
  595. #ifdef SOCKET_EXPORT_ENABLE
  596. else {
  597. if ((changed & AIS_SET)!=0) {
  598. if (session.gpsdata.ais.type == 24 &&
  599. session.gpsdata.ais.type24.part != both && !split24)
  600. continue;
  601. }
  602. json_data_report(changed,
  603. &session, &policy,
  604. buf, sizeof(buf));
  605. (void)fputs(buf, fpout);
  606. }
  607. #endif /* SOCKET_EXPORT_ENABLE */
  608. #ifdef AIVDM_ENABLE
  609. } else if (session.lexer.type == AIVDM_PACKET) {
  610. if ((changed & AIS_SET)!=0) {
  611. if (session.gpsdata.ais.type == 24 &&
  612. session.gpsdata.ais.type24.part != both && !split24)
  613. continue;
  614. aivdm_csv_dump(&session.gpsdata.ais, buf, sizeof(buf));
  615. (void)fputs(buf, fpout);
  616. }
  617. #endif /* AIVDM_ENABLE */
  618. }
  619. if (policy.nmea)
  620. pseudonmea_report(changed, &session);
  621. }
  622. if (minlength)
  623. {
  624. for (i = 0; i < (int)(sizeof(minima)/sizeof(minima[0])); i++) {
  625. /* dump all minima, ignoring comments */
  626. if (i != 1 && minima[i] < MAX_PACKET_LENGTH+1) {
  627. const struct gps_type_t **dp;
  628. char *np = "Unknown";
  629. for (dp = gpsd_drivers; *dp; dp++) {
  630. if ((*dp)->packet_type == i-1) {
  631. np = (*dp)->type_name;
  632. break;
  633. }
  634. }
  635. printf("%s (%d): %u\n", np, i-1, (unsigned int)minima[i]);
  636. }
  637. }
  638. }
  639. }
  640. #ifdef SOCKET_EXPORT_ENABLE
  641. /* JSON format on fpin to JSON on fpout - idempotency test */
  642. static void encode(FILE *fpin, FILE *fpout)
  643. {
  644. char inbuf[BUFSIZ];
  645. struct gps_policy_t policy;
  646. struct gps_device_t session;
  647. int lineno = 0;
  648. memset(&policy, '\0', sizeof(policy));
  649. memset(&session, '\0', sizeof(session));
  650. session.context = &context;
  651. context.errout.debug = LOG_SHOUT;
  652. context.errout.label = "gpsdecode";
  653. (void)strlcpy(session.gpsdata.dev.path,
  654. "stdin",
  655. sizeof(session.gpsdata.dev.path));
  656. policy.json = true;
  657. policy.nmea = pseudonmea;
  658. /* Parsing is always made in unscaled mode,
  659. * this policy applies to the dumping */
  660. policy.scaled = scaled;
  661. while (fgets(inbuf, (int)sizeof(inbuf), fpin) != NULL) {
  662. int status;
  663. ++lineno;
  664. if (inbuf[0] == '#')
  665. continue;
  666. status = libgps_json_unpack(inbuf, &session.gpsdata, NULL);
  667. if (status != 0) {
  668. (void)fprintf(stderr,
  669. "gpsdecode: dying with status %d (%s) on line %d\n",
  670. status, json_error_string(status), lineno);
  671. exit(EXIT_FAILURE);
  672. }
  673. json_data_report(session.gpsdata.set,
  674. &session, &policy,
  675. inbuf, sizeof(inbuf));
  676. (void)fputs(inbuf, fpout);
  677. }
  678. }
  679. #endif /* SOCKET_EXPORT_ENABLE */
  680. int main(int argc, char **argv)
  681. {
  682. int c;
  683. enum { doencode, dodecode } mode = dodecode;
  684. gps_context_init(&context, "gpsdecode");
  685. while ((c = getopt(argc, argv, "cdejmnpst:uvVD:")) != EOF) {
  686. switch (c) {
  687. case 'c':
  688. json = false;
  689. break;
  690. case 'd':
  691. mode = dodecode;
  692. break;
  693. case 'e':
  694. mode = doencode;
  695. break;
  696. case 'j':
  697. json = true;
  698. break;
  699. case 'm':
  700. minlength = true;
  701. json = false;
  702. break;
  703. case 'n':
  704. pseudonmea = true;
  705. break;
  706. case 's':
  707. split24 = true;
  708. break;
  709. case 't':
  710. typelist[ntypes++] = (unsigned int)atoi(strtok(optarg, ","));
  711. for(;;) {
  712. char *next = strtok(NULL, ",");
  713. if (next == NULL)
  714. break;
  715. typelist[ntypes++] = (unsigned int)atoi(next);
  716. }
  717. break;
  718. case 'u':
  719. scaled = false;
  720. break;
  721. case 'v':
  722. verbose = 1;
  723. break;
  724. case 'D':
  725. context.errout.debug = verbose = atoi(optarg);
  726. json_enable_debug(verbose - 2, stderr);
  727. break;
  728. case 'V':
  729. (void)fprintf(stderr, "gpsdecode revision " VERSION "\n");
  730. exit(EXIT_SUCCESS);
  731. case '?':
  732. default:
  733. (void)fputs("gpsdecode [-v]\n", stderr);
  734. exit(EXIT_FAILURE);
  735. }
  736. }
  737. //argc -= optind;
  738. //argv += optind;
  739. if (mode == doencode) {
  740. #ifdef SOCKET_EXPORT_ENABLE
  741. encode(stdin, stdout);
  742. #else
  743. (void)fprintf(stderr, "gpsdecode: encoding support isn't compiled.\n");
  744. exit(EXIT_FAILURE);
  745. #endif /* SOCKET_EXPORT_ENABLE */
  746. } else
  747. decode(stdin, stdout);
  748. exit(EXIT_SUCCESS);
  749. }
  750. /* gpsdecode.c ends here */
  751. // vim: set expandtab shiftwidth=4