gpsdecode.c 23 KB

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