driver_nmea2000.c 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980
  1. /*
  2. * NMEA2000 over CAN.
  3. *
  4. * NMEA2000 is proprietary and the doc is not public.
  5. * Much of this code is reverse engineered or built from
  6. * the sparse doc some vendors provide on their interpretation
  7. * of the specification.
  8. *
  9. * Here is one good source of reverse engineered info:
  10. * https://github.com/canboat/canboat
  11. *
  12. * Message contents can be had from canboat/analyzer:
  13. * analyzer -explain
  14. *
  15. * This file is Copyright 2012 by the GPSD project
  16. * SPDX-License-Identifier: BSD-2-clause
  17. */
  18. #include "../include/gpsd_config.h" /* must be before all includes */
  19. #if defined(NMEA2000_ENABLE)
  20. #include <ctype.h>
  21. #include <fcntl.h>
  22. #include <linux/can.h>
  23. #include <linux/can/raw.h>
  24. #include <math.h>
  25. #include <net/if.h>
  26. #include <stdarg.h>
  27. #include <stdbool.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/socket.h>
  33. #include <time.h>
  34. #include <unistd.h>
  35. #include "../include/gpsd.h"
  36. #include "../include/libgps.h"
  37. #include "../include/driver_nmea2000.h"
  38. #include "../include/bits.h"
  39. #include "../include/timespec.h"
  40. #define LOG_FILE 1
  41. #define NMEA2000_NETS 4
  42. #define NMEA2000_UNITS 256
  43. #define CAN_NAMELEN 32
  44. #define MIN(a,b) ((a < b) ? a : b)
  45. #define NMEA2000_DEBUG_AIS 0
  46. #define NMEA2000_FAST_DEBUG 0
  47. static struct gps_device_t *nmea2000_units[NMEA2000_NETS][NMEA2000_UNITS];
  48. static char can_interface_name[NMEA2000_NETS][CAN_NAMELEN+1];
  49. typedef struct PGN
  50. {
  51. unsigned int pgn;
  52. unsigned int fast;
  53. unsigned int type;
  54. gps_mask_t (* func)(unsigned char *bu, int len, struct PGN *pgn,
  55. struct gps_device_t *session);
  56. const char *name;
  57. } PGN;
  58. #if LOG_FILE
  59. FILE *logFile = NULL;
  60. #endif /* of if LOG_FILE */
  61. extern bool __attribute__ ((weak)) gpsd_add_device(const char *device_name,
  62. bool flag_nowait);
  63. #define SHIFT32 0x100000000l
  64. static int scale_int(int32_t var, const int64_t factor)
  65. {
  66. int64_t ret;
  67. ret = var;
  68. ret *= factor;
  69. ret >>= 32;
  70. return((int)ret);
  71. }
  72. static void print_data(struct gps_context_t *context,
  73. unsigned char *buffer, int len, PGN *pgn)
  74. {
  75. if ((libgps_debuglevel >= LOG_IO) != 0) {
  76. int l1, l2, ptr;
  77. char bu[128];
  78. ptr = 0;
  79. l2 = sprintf(&bu[ptr], "got data:%6u:%3d: ", pgn->pgn, len);
  80. ptr += l2;
  81. for (l1=0;l1<len;l1++) {
  82. if (((l1 % 20) == 0) && (l1 != 0)) {
  83. GPSD_LOG(LOG_IO, &context->errout, "%s\n", bu);
  84. ptr = 0;
  85. l2 = sprintf(&bu[ptr], " : ");
  86. ptr += l2;
  87. }
  88. l2 = sprintf(&bu[ptr], "%02ux ", (unsigned int)buffer[l1]);
  89. ptr += l2;
  90. }
  91. GPSD_LOG(LOG_IO, &context->errout, "%s\n", bu);
  92. }
  93. }
  94. static gps_mask_t get_mode(struct gps_device_t *session)
  95. {
  96. if (session->driver.nmea2000.mode_valid & 1) {
  97. session->newdata.mode = session->driver.nmea2000.mode;
  98. } else {
  99. session->newdata.mode = MODE_NOT_SEEN;
  100. }
  101. if (session->driver.nmea2000.mode_valid & 2) {
  102. return MODE_SET | USED_IS;
  103. } else {
  104. return MODE_SET;
  105. }
  106. }
  107. static int decode_ais_header(struct gps_context_t *context,
  108. unsigned char *bu, int len, struct ais_t *ais, unsigned int mask)
  109. {
  110. if (len > 4) {
  111. ais->type = (unsigned int) ( bu[0] & 0x3f);
  112. ais->repeat = (unsigned int) ((bu[0] >> 6) & 0x03);
  113. ais->mmsi = (unsigned int) getleu32(bu, 1);
  114. ais->mmsi &= mask;
  115. GPSD_LOG(LOG_INF, &context->errout,
  116. "NMEA2000 AIS message type %u, MMSI %09d:\n",
  117. ais->type, ais->mmsi);
  118. return(1);
  119. } else {
  120. ais->type = 0;
  121. ais->repeat = 0;
  122. ais->mmsi = 0;
  123. GPSD_LOG(LOG_ERROR, &context->errout,
  124. "NMEA2000 AIS message type %u, too short message.\n",
  125. ais->type);
  126. }
  127. return(0);
  128. }
  129. static void decode_ais_channel_info(unsigned char *bu,
  130. int len,
  131. unsigned int offset,
  132. struct gps_device_t *session)
  133. {
  134. unsigned int pos, bpos;
  135. uint16_t x;
  136. pos = offset / 8;
  137. bpos = offset % 8;
  138. if (pos >= (unsigned int)len) {
  139. session->driver.aivdm.ais_channel = 'A';
  140. return;
  141. }
  142. x = getleu16(bu, pos);
  143. x = (uint16_t)((x >> bpos) & 0x1f);
  144. switch (x) {
  145. case 1:
  146. case 3:
  147. session->driver.aivdm.ais_channel = 'B';
  148. break;
  149. default:
  150. session->driver.aivdm.ais_channel = 'A';
  151. break;
  152. }
  153. return;
  154. }
  155. static int ais_turn_rate(int rate)
  156. {
  157. if (rate < 0) {
  158. return(-ais_turn_rate(-rate));
  159. }
  160. return((int)(4.733 * sqrt(rate * RAD_2_DEG * .0001 * 60.0)));
  161. }
  162. static double ais_direction(unsigned int val, double scale)
  163. {
  164. if ((val == 0xffff) && (scale == 1.0)) {
  165. return(511.0);
  166. }
  167. return(val * RAD_2_DEG * 0.0001 * scale);
  168. }
  169. /*
  170. * PGN 59392: ISO Acknowledgment
  171. */
  172. static gps_mask_t hnd_059392(unsigned char *bu, int len, PGN *pgn,
  173. struct gps_device_t *session)
  174. {
  175. print_data(session->context, bu, len, pgn);
  176. GPSD_LOG(LOG_DATA, &session->context->errout,
  177. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  178. return(0);
  179. }
  180. /*
  181. * PGN 60928: ISO Address Claim
  182. */
  183. static gps_mask_t hnd_060928(unsigned char *bu, int len, PGN *pgn,
  184. struct gps_device_t *session)
  185. {
  186. print_data(session->context, bu, len, pgn);
  187. GPSD_LOG(LOG_DATA, &session->context->errout,
  188. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  189. return(0);
  190. }
  191. /*
  192. * PGN 126208: NMEA Command/Request/Acknowledge
  193. */
  194. static gps_mask_t hnd_126208(unsigned char *bu, int len, PGN *pgn,
  195. struct gps_device_t *session)
  196. {
  197. print_data(session->context, bu, len, pgn);
  198. GPSD_LOG(LOG_DATA, &session->context->errout,
  199. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  200. return(0);
  201. }
  202. /*
  203. * PGN 126464: ISO Transmit/Receive PGN List
  204. */
  205. static gps_mask_t hnd_126464(unsigned char *bu, int len, PGN *pgn,
  206. struct gps_device_t *session)
  207. {
  208. print_data(session->context, bu, len, pgn);
  209. GPSD_LOG(LOG_DATA, &session->context->errout,
  210. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  211. return(0);
  212. }
  213. /*
  214. * PGN 126996: ISO Product Information
  215. */
  216. static gps_mask_t hnd_126996(unsigned char *bu, int len, PGN *pgn,
  217. struct gps_device_t *session)
  218. {
  219. print_data(session->context, bu, len, pgn);
  220. GPSD_LOG(LOG_DATA, &session->context->errout,
  221. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  222. return(0);
  223. }
  224. /*
  225. * PGN 127258: GNSS Magnetic Variation
  226. *
  227. * 1 Sequence ID
  228. * 2 Variation Source
  229. * 3 Reserved Bits
  230. * 4 Age of Service (Date)
  231. * 5 Variation
  232. * 6 Reserved B
  233. */
  234. static gps_mask_t hnd_127258(unsigned char *bu, int len, PGN *pgn,
  235. struct gps_device_t *session)
  236. {
  237. print_data(session->context, bu, len, pgn);
  238. /* FIXME? Get magnetic variation */
  239. GPSD_LOG(LOG_DATA, &session->context->errout,
  240. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  241. return(0);
  242. }
  243. /*
  244. * PGN 129025: GNSS Position Rapid Update
  245. */
  246. static gps_mask_t hnd_129025(unsigned char *bu, int len, PGN *pgn,
  247. struct gps_device_t *session)
  248. {
  249. print_data(session->context, bu, len, pgn);
  250. GPSD_LOG(LOG_DATA, &session->context->errout,
  251. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  252. session->newdata.latitude = getles32(bu, 0) * 1e-7;
  253. session->newdata.longitude = getles32(bu, 4) * 1e-7;
  254. return LATLON_SET | get_mode(session);
  255. }
  256. /*
  257. * PGN 129026: GNSS COG and SOG Rapid Update
  258. */
  259. static gps_mask_t hnd_129026(unsigned char *bu, int len, PGN *pgn,
  260. struct gps_device_t *session)
  261. {
  262. print_data(session->context, bu, len, pgn);
  263. GPSD_LOG(LOG_DATA, &session->context->errout,
  264. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  265. session->driver.nmea2000.sid[0] = bu[0];
  266. session->newdata.track = getleu16(bu, 2) * 1e-4 * RAD_2_DEG;
  267. session->newdata.speed = getleu16(bu, 4) * 1e-2;
  268. return SPEED_SET | TRACK_SET | get_mode(session);
  269. }
  270. /*
  271. * PGN: 126992 / 00370020 / 1F010 - 8 - System Time
  272. *
  273. * Field #1: SID
  274. * Bits: 8
  275. * Signed: false
  276. * Field #2: Source
  277. * Bits: 4
  278. * Type: Lookup table
  279. * Signed: false
  280. * Lookup: 0=GPS
  281. * Lookup: 1=GLONASS
  282. * Lookup: 2=Radio Station
  283. * Lookup: 3=Local Cesium clock
  284. * Lookup: 4=Local Rubidium clock
  285. * Lookup: 5=Local Crystal clock
  286. * Field #3: Reserved - Reserved
  287. * Bits: 4
  288. * Type: Binary data
  289. * Signed: false
  290. * Field #4: Date - Days since January 1, 1970
  291. * Bits: 16
  292. * Units: days
  293. * Type: Date
  294. * Resolution: 1
  295. * Signed: false
  296. * Field #5: Time - Seconds since midnight
  297. * Bits: 32
  298. * Units: s
  299. * Type: Time
  300. * Resolution: 0.0001
  301. * Signed: false
  302. *
  303. */
  304. static gps_mask_t hnd_126992(unsigned char *bu, int len, PGN *pgn,
  305. struct gps_device_t *session)
  306. {
  307. // uint8_t sid;
  308. // uint8_t source;
  309. uint64_t usecs; /* time in us */
  310. print_data(session->context, bu, len, pgn);
  311. GPSD_LOG(LOG_DATA, &session->context->errout,
  312. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  313. // sid = bu[0];
  314. // source = bu[1] & 0x0f;
  315. usecs = getleu32(bu, 4) * (uint64_t)100;
  316. USTOTS(&session->newdata.time, usecs);
  317. session->newdata.time.tv_sec += (time_t)(getleu16(bu, 2) * 24 * 60 * 60);
  318. return TIME_SET | get_mode(session);
  319. }
  320. static const int mode_tab[] = {MODE_NO_FIX, MODE_2D, MODE_3D, MODE_NO_FIX,
  321. MODE_NO_FIX, MODE_NO_FIX, MODE_NO_FIX,
  322. MODE_NO_FIX};
  323. /*
  324. * PGN 129539: GNSS DOPs
  325. */
  326. static gps_mask_t hnd_129539(unsigned char *bu, int len, PGN *pgn,
  327. struct gps_device_t *session)
  328. {
  329. gps_mask_t mask;
  330. unsigned int req_mode;
  331. unsigned int act_mode;
  332. print_data(session->context, bu, len, pgn);
  333. GPSD_LOG(LOG_DATA, &session->context->errout,
  334. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  335. mask = 0;
  336. session->driver.nmea2000.sid[1] = bu[0];
  337. session->driver.nmea2000.mode_valid |= 1;
  338. req_mode = (unsigned int)((bu[1] >> 0) & 0x07);
  339. act_mode = (unsigned int)((bu[1] >> 3) & 0x07);
  340. /* This is a workaround for some GARMIN plotter,
  341. * actual mode auto makes no sense for me! */
  342. if ((act_mode == 3) && (req_mode != 3)) {
  343. act_mode = req_mode;
  344. }
  345. session->driver.nmea2000.mode = mode_tab[act_mode];
  346. session->gpsdata.dop.hdop = getleu16(bu, 2) * 1e-2;
  347. session->gpsdata.dop.vdop = getleu16(bu, 4) * 1e-2;
  348. session->gpsdata.dop.tdop = getleu16(bu, 6) * 1e-2;
  349. mask |= DOP_SET;
  350. GPSD_LOG(LOG_DATA, &session->context->errout,
  351. "pgn %6d(%3d): sid:%02x hdop:%5.2f vdop:%5.2f tdop:%5.2f\n",
  352. pgn->pgn,
  353. session->driver.nmea2000.unit,
  354. session->driver.nmea2000.sid[1],
  355. session->gpsdata.dop.hdop,
  356. session->gpsdata.dop.vdop,
  357. session->gpsdata.dop.tdop);
  358. return mask | get_mode(session);
  359. }
  360. /*
  361. * PGN 129540: GNSS Satellites in View
  362. */
  363. static gps_mask_t hnd_129540(unsigned char *bu, int len, PGN *pgn,
  364. struct gps_device_t *session)
  365. {
  366. int l1;
  367. print_data(session->context, bu, len, pgn);
  368. GPSD_LOG(LOG_DATA, &session->context->errout,
  369. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  370. session->driver.nmea2000.sid[2] = bu[0];
  371. session->gpsdata.satellites_visible = (int)bu[2];
  372. memset(session->gpsdata.skyview, '\0', sizeof(session->gpsdata.skyview));
  373. for (l1=0;l1<session->gpsdata.satellites_visible;l1++) {
  374. int svt;
  375. double azi, elev, snr;
  376. elev = getles16(bu, 3+12*l1+1) * 1e-4 * RAD_2_DEG;
  377. azi = getleu16(bu, 3+12*l1+3) * 1e-4 * RAD_2_DEG;
  378. snr = getles16(bu, 3+12*l1+5) * 1e-2;
  379. svt = (int)(bu[3+12*l1+11] & 0x0f);
  380. session->gpsdata.skyview[l1].elevation = (short) (round(elev));
  381. session->gpsdata.skyview[l1].azimuth = (short) (round(azi));
  382. session->gpsdata.skyview[l1].ss = snr;
  383. session->gpsdata.skyview[l1].PRN = (short)bu[3+12*l1+0];
  384. session->gpsdata.skyview[l1].used = false;
  385. if ((svt == 2) || (svt == 5)) {
  386. session->gpsdata.skyview[l1].used = true;
  387. }
  388. }
  389. session->driver.nmea2000.mode_valid |= 2;
  390. return SATELLITE_SET | USED_IS;
  391. }
  392. /*
  393. * PGN: 129029 / 00374005 / 1F805 - 51 - GNSS Position Data
  394. *
  395. * The last 3 fields repeat until the data is exhausted.
  396. *
  397. * Field #1: SID
  398. * Bits: 8
  399. * Signed: false
  400. * Field #2: Date - Days since January 1, 1970
  401. * Bits: 16
  402. * Units: days
  403. * Type: Date
  404. * Resolution: 1
  405. * Signed: false
  406. * Field #3: Time - Seconds since midnight
  407. * Bits: 32
  408. * Units: s
  409. * Type: Time
  410. * Resolution: 0.0001
  411. * Signed: false
  412. * Field #4: Latitude
  413. * Bits: 64
  414. * Units: deg
  415. * Type: Latitude
  416. * Resolution: 0.0000000000000001
  417. * Signed: true
  418. * Field #5: Longitude
  419. * Bits: 64
  420. * Units: deg
  421. * Type: Longitude
  422. * Resolution: 0.0000000000000001
  423. * Signed: true
  424. * Field #6: Altitude - Altitude referenced to WGS-84
  425. * Bits: 64
  426. * Units: m
  427. * Resolution: 1e-06
  428. * Signed: true
  429. * Field #7: GNSS type
  430. * Bits: 4
  431. * Type: Lookup table
  432. * Signed: false
  433. * Lookup: 0=GPS
  434. * Lookup: 1=GLONASS
  435. * Lookup: 2=GPS+GLONASS
  436. * Lookup: 3=GPS+SBAS/WAAS
  437. * Lookup: 4=GPS+SBAS/WAAS+GLONASS
  438. * Lookup: 5=Chayka
  439. * Lookup: 6=integrated
  440. * Lookup: 7=surveyed
  441. * Lookup: 8=Galileo
  442. * Field #8: Method
  443. * Bits: 4
  444. * Type: Lookup table
  445. * Signed: false
  446. * Lookup: 0=no GNSS
  447. * Lookup: 1=GNSS fix
  448. * Lookup: 2=DGNSS fix
  449. * Lookup: 3=Precise GNSS
  450. * Lookup: 4=RTK Fixed Integer
  451. * Lookup: 5=RTK float
  452. * Lookup: 6=Estimated (DR) mode
  453. * Lookup: 7=Manual Input
  454. * Lookup: 8=Simulate mode
  455. * Field #9: Integrity
  456. * Bits: 2
  457. * Type: Lookup table
  458. * Signed: false
  459. * Lookup: 0=No integrity checking
  460. * Lookup: 1=Safe
  461. * Lookup: 2=Caution
  462. * Field #10: Reserved - Reserved
  463. * Bits: 6
  464. * Type: Binary data
  465. * Signed: false
  466. * Field #11: Number of SVs - Number of satellites used in solution
  467. * Bits: 8
  468. * Signed: false
  469. * Field #12: HDOP - Horizontal dilution of precision
  470. * Bits: 16
  471. * Resolution: 0.01
  472. * Signed: true
  473. * Field #13: PDOP - Probable dilution of precision
  474. * Bits: 16
  475. * Resolution: 0.01
  476. * Signed: true
  477. * Field #14: Geoidal Separation - Geoidal Separation
  478. * Bits: 32
  479. * Units: m
  480. * Resolution: 0.01
  481. * Signed: true
  482. * Field #15: Reference Stations - Number of reference stations
  483. * Bits: 8
  484. * Signed: false
  485. * Field #16: Reference Station Type
  486. * Bits: 4
  487. * Type: Lookup table
  488. * Signed: false
  489. * Lookup: 0=GPS
  490. * Lookup: 1=GLONASS
  491. * Lookup: 2=GPS+GLONASS
  492. * Lookup: 3=GPS+SBAS/WAAS
  493. * Lookup: 4=GPS+SBAS/WAAS+GLONASS
  494. * Lookup: 5=Chayka
  495. * Lookup: 6=integrated
  496. * Lookup: 7=surveyed
  497. * Lookup: 8=Galileo
  498. * Field #17: Reference Station ID
  499. * Bits: 12
  500. * Units:
  501. * Signed: false
  502. * Field #18: Age of DGNSS Corrections
  503. * Bits: 16
  504. * Units: s
  505. * Resolution: 0.01
  506. * Signed: false
  507. *
  508. */
  509. static gps_mask_t hnd_129029(unsigned char *bu, int len, PGN *pgn,
  510. struct gps_device_t *session)
  511. {
  512. gps_mask_t mask;
  513. uint64_t usecs; /* time in us */
  514. print_data(session->context, bu, len, pgn);
  515. GPSD_LOG(LOG_DATA, &session->context->errout,
  516. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  517. mask = 0;
  518. session->driver.nmea2000.sid[3] = bu[0];
  519. // field 3 is time in 0.1 ms
  520. usecs = getleu32(bu, 3) * (uint64_t)100;
  521. USTOTS(&session->newdata.time, usecs);
  522. // add in the date from field 2
  523. session->newdata.time.tv_sec += (time_t)(getleu16(bu,1) * 24 * 60 * 60);
  524. mask |= TIME_SET;
  525. session->newdata.latitude = getles64(bu, 7) * 1e-16;
  526. session->newdata.longitude = getles64(bu, 15) * 1e-16;
  527. mask |= LATLON_SET;
  528. session->newdata.altHAE = getles64(bu, 23) * 1e-6;
  529. mask |= ALTITUDE_SET;
  530. // printf("mode %x %x\n", (bu[31] >> 4) & 0x0f, bu[31]);
  531. switch ((bu[31] >> 4) & 0x0f) {
  532. case 0:
  533. session->newdata.status = STATUS_UNK;
  534. break;
  535. case 1:
  536. session->newdata.status = STATUS_GPS;
  537. break;
  538. case 2:
  539. session->newdata.status = STATUS_DGPS;
  540. break;
  541. case 3:
  542. case 4:
  543. case 5:
  544. session->newdata.status = STATUS_GPS; // Is this correct ?
  545. break;
  546. default:
  547. session->newdata.status = STATUS_UNK;
  548. break;
  549. }
  550. mask |= STATUS_SET;
  551. session->newdata.geoid_sep = getles32(bu, 38) / 100.0;
  552. session->gpsdata.satellites_used = (int)bu[33];
  553. session->gpsdata.dop.hdop = getleu16(bu, 34) * 0.01;
  554. session->gpsdata.dop.pdop = getleu16(bu, 36) * 0.01;
  555. mask |= DOP_SET;
  556. return mask | get_mode(session);
  557. }
  558. /*
  559. * PGN 129038: AIS Class A Position Report
  560. */
  561. static gps_mask_t hnd_129038(unsigned char *bu, int len, PGN *pgn,
  562. struct gps_device_t *session)
  563. {
  564. struct ais_t *ais;
  565. ais = &session->gpsdata.ais;
  566. print_data(session->context, bu, len, pgn);
  567. GPSD_LOG(LOG_DATA, &session->context->errout,
  568. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  569. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  570. ais->type1.lon = (int)scale_int(getles32(bu, 5),
  571. (int64_t)(SHIFT32 *.06L));
  572. ais->type1.lat = (int)scale_int(getles32(bu, 9),
  573. (int64_t)(SHIFT32 *.06L));
  574. ais->type1.accuracy = (bool) ((bu[13] >> 0) & 0x01);
  575. ais->type1.raim = (bool) ((bu[13] >> 1) & 0x01);
  576. ais->type1.second = (unsigned int) ((bu[13] >> 2) & 0x3f);
  577. ais->type1.course = (unsigned int)ais_direction(
  578. (unsigned int)getleu16(bu, 14), 10.0);
  579. ais->type1.speed = (unsigned int)(getleu16(bu, 16) *
  580. MPS_TO_KNOTS * 0.01 / 0.1);
  581. ais->type1.radio = (unsigned int) (getleu32(bu, 18) & 0x7ffff);
  582. ais->type1.heading =
  583. (unsigned int)ais_direction((unsigned int)getleu16(bu, 21), 1.0);
  584. ais->type1.turn = ais_turn_rate((int)getles16(bu, 23));
  585. ais->type1.status = (unsigned int) ((bu[25] >> 0) & 0x0f);
  586. ais->type1.maneuver = 0; /* Not transmitted ???? */
  587. decode_ais_channel_info(bu, len, 163, session);
  588. return(ONLINE_SET | AIS_SET);
  589. }
  590. return(0);
  591. }
  592. /*
  593. * PGN 129039: AIS Class B Position Report
  594. */
  595. static gps_mask_t hnd_129039(unsigned char *bu, int len, PGN *pgn,
  596. struct gps_device_t *session)
  597. {
  598. struct ais_t *ais;
  599. ais = &session->gpsdata.ais;
  600. print_data(session->context, bu, len, pgn);
  601. GPSD_LOG(LOG_DATA, &session->context->errout,
  602. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  603. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  604. ais->type18.lon = (int)scale_int(getles32(bu, 5),
  605. (int64_t)(SHIFT32 *.06L));
  606. ais->type18.lat = (int)scale_int(getles32(bu, 9),
  607. (int64_t)(SHIFT32 *.06L));
  608. ais->type18.accuracy = (bool) ((bu[13] >> 0) & 0x01);
  609. ais->type18.raim = (bool) ((bu[13] >> 1) & 0x01);
  610. ais->type18.second = (unsigned int) ((bu[13] >> 2) & 0x3f);
  611. ais->type18.course =
  612. (unsigned int)ais_direction((unsigned int) getleu16(bu, 14), 10.0);
  613. ais->type18.speed = (unsigned int)(getleu16(bu, 16) *
  614. MPS_TO_KNOTS * 0.01 / 0.1);
  615. ais->type18.radio = (unsigned int) (getleu32(bu, 18) & 0x7ffff);
  616. ais->type18.heading =
  617. (unsigned int)ais_direction((unsigned int) getleu16(bu, 21), 1.0);
  618. ais->type18.reserved = 0;
  619. ais->type18.regional = (unsigned int) ((bu[24] >> 0) & 0x03);
  620. ais->type18.cs = (bool) ((bu[24] >> 2) & 0x01);
  621. ais->type18.display = (bool) ((bu[24] >> 3) & 0x01);
  622. ais->type18.dsc = (bool) ((bu[24] >> 4) & 0x01);
  623. ais->type18.band = (bool) ((bu[24] >> 5) & 0x01);
  624. ais->type18.msg22 = (bool) ((bu[24] >> 6) & 0x01);
  625. ais->type18.assigned = (bool) ((bu[24] >> 7) & 0x01);
  626. decode_ais_channel_info(bu, len, 163, session);
  627. return(ONLINE_SET | AIS_SET);
  628. }
  629. return(0);
  630. }
  631. /*
  632. * PGN 129040: AIS Class B Extended Position Report
  633. */
  634. /* No test case for this message at the moment */
  635. static gps_mask_t hnd_129040(unsigned char *bu, int len, PGN *pgn,
  636. struct gps_device_t *session)
  637. {
  638. struct ais_t *ais;
  639. ais = &session->gpsdata.ais;
  640. print_data(session->context, bu, len, pgn);
  641. GPSD_LOG(LOG_DATA, &session->context->errout,
  642. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  643. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  644. uint16_t length, beam, to_bow, to_starboard;
  645. int l;
  646. ais->type19.lon = (int)scale_int(getles32(bu, 5),
  647. (int64_t)(SHIFT32 *.06L));
  648. ais->type19.lat = (int)scale_int(getles32(bu, 9),
  649. (int64_t)(SHIFT32 *.06L));
  650. ais->type19.accuracy = (bool) ((bu[13] >> 0) & 0x01);
  651. ais->type19.raim = (bool) ((bu[13] >> 1) & 0x01);
  652. ais->type19.second = (unsigned int) ((bu[13] >> 2) & 0x3f);
  653. ais->type19.course =
  654. (unsigned int)ais_direction((unsigned int)getleu16(bu, 14), 10.0);
  655. ais->type19.speed =
  656. (unsigned int)(getleu16(bu, 16) * MPS_TO_KNOTS * 0.01 / 0.1);
  657. ais->type19.reserved = (unsigned int) ((bu[18] >> 0) & 0xff);
  658. ais->type19.regional = (unsigned int) ((bu[19] >> 0) & 0x0f);
  659. ais->type19.shiptype = (unsigned int) ((bu[20] >> 0) & 0xff);
  660. ais->type19.heading =
  661. (unsigned int) ais_direction((unsigned int) getleu16(bu, 21), 1.0);
  662. length = getleu16(bu, 24);
  663. beam = getleu16(bu, 26);
  664. to_starboard = getleu16(bu, 28);
  665. to_bow = getleu16(bu, 30);
  666. if ((length == 0xffff) || (to_bow == 0xffff)) {
  667. length = 0;
  668. to_bow = 0;
  669. }
  670. if ((beam == 0xffff) || (to_starboard == 0xffff)) {
  671. beam = 0;
  672. to_starboard = 0;
  673. }
  674. ais->type19.to_bow = (unsigned int) (to_bow/10);
  675. ais->type19.to_stern = (unsigned int) ((length-to_bow)/10);
  676. ais->type19.to_port = (unsigned int) ((beam-to_starboard)/10);
  677. ais->type19.to_starboard = (unsigned int) (to_starboard/10);
  678. ais->type19.epfd = (unsigned int) ((bu[23] >> 4) & 0x0f);
  679. ais->type19.dte = (unsigned int) ((bu[52] >> 0) & 0x01);
  680. ais->type19.assigned = (bool) ((bu[52] >> 1) & 0x01);
  681. for (l=0;l<AIS_SHIPNAME_MAXLEN;l++) {
  682. ais->type19.shipname[l] = (char) bu[32+l];
  683. }
  684. ais->type19.shipname[AIS_SHIPNAME_MAXLEN] = (char) 0;
  685. decode_ais_channel_info(bu, len, 422, session);
  686. return(ONLINE_SET | AIS_SET);
  687. }
  688. return(0);
  689. }
  690. /*
  691. * PGN 129793: AIS UTC and Date Report
  692. */
  693. static gps_mask_t hnd_129793(unsigned char *bu, int len, PGN *pgn,
  694. struct gps_device_t *session)
  695. {
  696. struct ais_t *ais;
  697. ais = &session->gpsdata.ais;
  698. print_data(session->context, bu, len, pgn);
  699. GPSD_LOG(LOG_DATA, &session->context->errout,
  700. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  701. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  702. uint32_t time;
  703. uint32_t date;
  704. time_t date1;
  705. struct tm date2;
  706. ais->type4.lon = (int)scale_int(getles32(bu, 5),
  707. (int64_t)(SHIFT32 *.06L));
  708. ais->type4.lat = (int)scale_int(getles32(bu, 9),
  709. (int64_t)(SHIFT32 *.06L));
  710. ais->type4.accuracy = (bool) ((bu[13] >> 0) & 0x01);
  711. ais->type4.raim = (bool) ((bu[13] >> 1) & 0x01);
  712. time = getleu32(bu, 14);
  713. if (time != 0xffffffff) {
  714. time = time / 10000;
  715. ais->type4.second = time % 60; time = time / 60;
  716. ais->type4.minute = time % 60; time = time / 60;
  717. ais->type4.hour = time % 24;
  718. } else {
  719. ais->type4.second = AIS_SECOND_NOT_AVAILABLE;
  720. ais->type4.minute = AIS_MINUTE_NOT_AVAILABLE;
  721. ais->type4.hour = AIS_HOUR_NOT_AVAILABLE;
  722. }
  723. ais->type4.radio = (unsigned int) (getleu32(bu, 18) & 0x7ffff);
  724. date = getleu16(bu, 21);
  725. if (date != 0xffff) {
  726. date1 = (time_t)date * (24L *60L *60L);
  727. (void) gmtime_r(&date1, &date2);
  728. ais->type4.year = (unsigned int) (date2.tm_year+1900);
  729. ais->type4.month = (unsigned int) (date2.tm_mon+1);
  730. ais->type4.day = (unsigned int) (date2.tm_mday);
  731. } else {
  732. ais->type4.day = AIS_DAY_NOT_AVAILABLE;
  733. ais->type4.month = AIS_MONTH_NOT_AVAILABLE;
  734. ais->type4.year = AIS_YEAR_NOT_AVAILABLE;
  735. }
  736. ais->type4.epfd = (unsigned int) ((bu[23] >> 4) & 0x0f);
  737. decode_ais_channel_info(bu, len, 163, session);
  738. return(ONLINE_SET | AIS_SET);
  739. }
  740. return(0);
  741. }
  742. /*
  743. * PGN 129794: AIS Class A Static and Voyage Related Data
  744. */
  745. static gps_mask_t hnd_129794(unsigned char *bu, int len, PGN *pgn,
  746. struct gps_device_t *session)
  747. {
  748. struct ais_t *ais;
  749. ais = &session->gpsdata.ais;
  750. print_data(session->context, bu, len, pgn);
  751. GPSD_LOG(LOG_DATA, &session->context->errout,
  752. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  753. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  754. uint16_t length, beam, to_bow, to_starboard, date;
  755. int l;
  756. uint32_t time;
  757. time_t date1;
  758. struct tm date2;
  759. int cpy_stop;
  760. ais->type5.ais_version = (unsigned int) ((bu[73] >> 0) & 0x03);
  761. ais->type5.imo = (unsigned int) getleu32(bu, 5);
  762. if (ais->type5.imo == 0xffffffffU) {
  763. ais->type5.imo = 0;
  764. }
  765. ais->type5.shiptype = (unsigned int) ((bu[36] >> 0) & 0xff);
  766. length = getleu16(bu, 37);
  767. beam = getleu16(bu, 39);
  768. to_starboard = getleu16(bu, 41);
  769. to_bow = getleu16(bu, 43);
  770. if ((length == 0xffff) || (to_bow == 0xffff)) {
  771. length = 0;
  772. to_bow = 0;
  773. }
  774. if ((beam == 0xffff) || (to_starboard == 0xffff)) {
  775. beam = 0;
  776. to_starboard = 0;
  777. }
  778. ais->type5.to_bow = (unsigned int) (to_bow/10);
  779. ais->type5.to_stern = (unsigned int) ((length-to_bow)/10);
  780. ais->type5.to_port = (unsigned int) ((beam-to_starboard)/10);
  781. ais->type5.to_starboard = (unsigned int) (to_starboard/10);
  782. ais->type5.epfd = (unsigned int) ((bu[73] >> 2) & 0x0f);
  783. date = getleu16(bu, 45);
  784. time = getleu32(bu, 47);
  785. date1 = (time_t) (date*24*60*60);
  786. (void) gmtime_r(&date1, &date2);
  787. ais->type5.month = (unsigned int) (date2.tm_mon+1);
  788. ais->type5.day = (unsigned int) (date2.tm_mday);
  789. ais->type5.minute = (unsigned int) (time/(10000*60));
  790. ais->type5.hour = (unsigned int) (ais->type5.minute/60);
  791. ais->type5.minute =
  792. (unsigned int)(ais->type5.minute-(ais->type5.hour * 60));
  793. ais->type5.draught = (unsigned int) (getleu16(bu, 51)/10);
  794. ais->type5.dte = (unsigned int) ((bu[73] >> 6) & 0x01);
  795. for (l=0,cpy_stop=0;l<7;l++) {
  796. char next;
  797. next = (char) bu[9+l];
  798. if ((next < ' ') || (next > 0x7e)) {
  799. cpy_stop = 1;
  800. }
  801. if (cpy_stop == 0) {
  802. ais->type5.callsign[l] = next;
  803. } else {
  804. ais->type5.callsign[l] = 0;
  805. }
  806. }
  807. ais->type5.callsign[7] = (char) 0;
  808. for (l=0,cpy_stop=0;l<AIS_SHIPNAME_MAXLEN;l++) {
  809. char next;
  810. next = (char) bu[16+l];
  811. if ((next < ' ') || (next > 0x7e)) {
  812. cpy_stop = 1;
  813. }
  814. if (cpy_stop == 0) {
  815. ais->type5.shipname[l] = next;
  816. } else {
  817. ais->type5.shipname[l] = 0;
  818. }
  819. }
  820. ais->type5.shipname[AIS_SHIPNAME_MAXLEN] = (char) 0;
  821. for (l=0,cpy_stop=0;l<20;l++) {
  822. char next;
  823. next = (char) bu[53+l];
  824. if ((next < ' ') || (next > 0x7e)) {
  825. cpy_stop = 1;
  826. }
  827. if (cpy_stop == 0) {
  828. ais->type5.destination[l] = next;
  829. } else {
  830. ais->type5.destination[l] = 0;
  831. }
  832. }
  833. ais->type5.destination[20] = (char) 0;
  834. #if NMEA2000_DEBUG_AIS
  835. printf("AIS: MMSI: %09u\n",
  836. ais->mmsi);
  837. printf("AIS: name: %-20.20s i:%8u c:%-8.8s b:%6u s:%6u p:%6u"
  838. "s:%6u dr:%4.1f\n",
  839. ais->type5.shipname,
  840. ais->type5.imo,
  841. ais->type5.callsign,
  842. ais->type5.to_bow,
  843. ais->type5.to_stern,
  844. ais->type5.to_port,
  845. ais->type5.to_starboard,
  846. ais->type5.draught/10.0);
  847. printf("AIS: arrival:%-20.20s at %02u-%02u-%04d %02u:%0u\n",
  848. ais->type5.destination,
  849. ais->type5.day,
  850. ais->type5.month,
  851. date2.tm_year+1900,
  852. ais->type5.hour,
  853. ais->type5.minute);
  854. #endif /* of #if NMEA2000_DEBUG_AIS */
  855. decode_ais_channel_info(bu, len, 592, session);
  856. return(ONLINE_SET | AIS_SET);
  857. }
  858. return(0);
  859. }
  860. /*
  861. * PGN 129798: AIS SAR Aircraft Position Report
  862. */
  863. /* No test case for this message at the moment */
  864. static gps_mask_t hnd_129798(unsigned char *bu, int len, PGN *pgn,
  865. struct gps_device_t *session)
  866. {
  867. struct ais_t *ais;
  868. ais = &session->gpsdata.ais;
  869. print_data(session->context, bu, len, pgn);
  870. GPSD_LOG(LOG_DATA, &session->context->errout,
  871. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  872. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  873. ais->type9.lon = (int)scale_int(getles32(bu, 5),
  874. (int64_t)(SHIFT32 *.06L));
  875. ais->type9.lat = (int)scale_int(getles32(bu, 9),
  876. (int64_t)(SHIFT32 *.06L));
  877. ais->type9.accuracy = (bool) ((bu[13] >> 0) & 0x01);
  878. ais->type9.raim = (bool) ((bu[13] >> 1) & 0x01);
  879. ais->type9.second = (unsigned int) ((bu[13] >> 2) & 0x3f);
  880. ais->type9.course =
  881. (unsigned int)ais_direction((unsigned int)getleu16(bu, 14), 10.0);
  882. ais->type9.speed =
  883. (unsigned int)(getleu16(bu, 16) * MPS_TO_KNOTS * 0.01 / 0.1);
  884. ais->type9.radio = (unsigned int) (getleu32(bu, 18) & 0x7ffff);
  885. ais->type9.alt = (unsigned int) (getleu64(bu, 21)/1000000);
  886. ais->type9.regional = (unsigned int) ((bu[29] >> 0) & 0xff);
  887. ais->type9.dte = (unsigned int) ((bu[30] >> 0) & 0x01);
  888. /* ais->type9.spare = (bu[30] >> 1) & 0x7f; */
  889. ais->type9.assigned = 0; /* Not transmitted ???? */
  890. decode_ais_channel_info(bu, len, 163, session);
  891. return(ONLINE_SET | AIS_SET);
  892. }
  893. return(0);
  894. }
  895. /*
  896. * PGN 129802: AIS Safety Related Broadcast Message
  897. */
  898. /* No test case for this message at the moment */
  899. static gps_mask_t hnd_129802(unsigned char *bu, int len, PGN *pgn,
  900. struct gps_device_t *session)
  901. {
  902. struct ais_t *ais;
  903. ais = &session->gpsdata.ais;
  904. print_data(session->context, bu, len, pgn);
  905. GPSD_LOG(LOG_DATA, &session->context->errout,
  906. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  907. if (decode_ais_header(session->context, bu, len, ais, 0x3fffffff) != 0) {
  908. int l;
  909. /* ais->type14.channel = (bu[ 5] >> 0) & 0x1f; */
  910. for (l=0;l<36;l++) {
  911. ais->type14.text[l] = (char) bu[6+l];
  912. }
  913. ais->type14.text[36] = (char) 0;
  914. decode_ais_channel_info(bu, len, 40, session);
  915. return(ONLINE_SET | AIS_SET);
  916. }
  917. return(0);
  918. }
  919. /*
  920. * PGN 129809: AIS Class B CS Static Data Report, Part A
  921. */
  922. static gps_mask_t hnd_129809(unsigned char *bu, int len, PGN *pgn,
  923. struct gps_device_t *session)
  924. {
  925. struct ais_t *ais;
  926. ais = &session->gpsdata.ais;
  927. print_data(session->context, bu, len, pgn);
  928. GPSD_LOG(LOG_DATA, &session->context->errout,
  929. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  930. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  931. int l;
  932. int index = session->driver.aivdm.context[0].type24_queue.index;
  933. struct ais_type24a_t *saveptr =
  934. &session->driver.aivdm.context[0].type24_queue.ships[index];
  935. GPSD_LOG(LOG_PROG, &session->context->errout,
  936. "NMEA2000: AIS message 24A from %09u stashed.\n",
  937. ais->mmsi);
  938. for (l=0;l<AIS_SHIPNAME_MAXLEN;l++) {
  939. ais->type24.shipname[l] = (char) bu[ 5+l];
  940. saveptr->shipname[l] = (char) bu[ 5+l];
  941. }
  942. ais->type24.shipname[AIS_SHIPNAME_MAXLEN] = (char) 0;
  943. saveptr->shipname[AIS_SHIPNAME_MAXLEN] = (char) 0;
  944. saveptr->mmsi = ais->mmsi;
  945. index += 1;
  946. index %= MAX_TYPE24_INTERLEAVE;
  947. session->driver.aivdm.context[0].type24_queue.index = index;
  948. decode_ais_channel_info(bu, len, 200, session);
  949. ais->type24.part = part_a;
  950. return(ONLINE_SET | AIS_SET);
  951. }
  952. return(0);
  953. }
  954. /*
  955. * PGN 129810: AIS Class B CS Static Data Report, Part B
  956. */
  957. static gps_mask_t hnd_129810(unsigned char *bu, int len, PGN *pgn,
  958. struct gps_device_t *session)
  959. {
  960. struct ais_t *ais;
  961. ais = &session->gpsdata.ais;
  962. print_data(session->context, bu, len, pgn);
  963. GPSD_LOG(LOG_DATA, &session->context->errout,
  964. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  965. if (decode_ais_header(session->context, bu, len, ais, 0xffffffffU) != 0) {
  966. int l, i;
  967. ais->type24.shiptype = (unsigned int) ((bu[ 5] >> 0) & 0xff);
  968. for (l=0;l<7;l++) {
  969. ais->type24.vendorid[l] = (char) bu[ 6+l];
  970. }
  971. ais->type24.vendorid[7] = (char) 0;
  972. for (l=0;l<7;l++) {
  973. ais->type24.callsign[l] = (char) bu[13+l];
  974. }
  975. ais->type24.callsign[7] = (char )0;
  976. ais->type24.model = 0;
  977. ais->type24.serial = 0;
  978. if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
  979. ais->type24.mothership_mmsi = (unsigned int) (getleu32(bu, 28));
  980. } else {
  981. uint16_t length, beam, to_bow, to_starboard;
  982. length = getleu16(bu, 20);
  983. beam = getleu16(bu, 22);
  984. to_starboard = getleu16(bu, 24);
  985. to_bow = getleu16(bu, 26);
  986. if ((length == 0xffff) || (to_bow == 0xffff)) {
  987. length = 0;
  988. to_bow = 0;
  989. }
  990. if ((beam == 0xffff) || (to_starboard == 0xffff)) {
  991. beam = 0;
  992. to_starboard = 0;
  993. }
  994. ais->type24.dim.to_bow = (unsigned int) (to_bow/10);
  995. ais->type24.dim.to_stern = (unsigned int) ((length-to_bow)/10);
  996. ais->type24.dim.to_port = (unsigned int) ((beam-to_starboard)/10);
  997. ais->type24.dim.to_starboard = (unsigned int) (to_starboard/10);
  998. }
  999. for (i = 0; i < MAX_TYPE24_INTERLEAVE; i++) {
  1000. if (session->driver.aivdm.context[0].type24_queue.ships[i].mmsi ==
  1001. ais->mmsi) {
  1002. for (l=0;l<AIS_SHIPNAME_MAXLEN;l++) {
  1003. ais->type24.shipname[l] =
  1004. (char)(session->driver.aivdm.context[0].type24_queue.ships[i].shipname[l]);
  1005. }
  1006. ais->type24.shipname[AIS_SHIPNAME_MAXLEN] = (char) 0;
  1007. GPSD_LOG(LOG_PROG, &session->context->errout,
  1008. "NMEA2000: AIS 24B from %09u matches a 24A.\n",
  1009. ais->mmsi);
  1010. /* prevent false match if a 24B is repeated */
  1011. session->driver.aivdm.context[0].type24_queue.ships[i].mmsi = 0;
  1012. #if NMEA2000_DEBUG_AIS
  1013. printf("AIS: MMSI: %09u\n", ais->mmsi);
  1014. printf("AIS: name: %-20.20s v:%-8.8s c:%-8.8s b:%6u "
  1015. "s:%6u p:%6u s:%6u\n",
  1016. ais->type24.shipname,
  1017. ais->type24.vendorid,
  1018. ais->type24.callsign,
  1019. ais->type24.dim.to_bow,
  1020. ais->type24.dim.to_stern,
  1021. ais->type24.dim.to_port,
  1022. ais->type24.dim.to_starboard);
  1023. #endif /* of #if NMEA2000_DEBUG_AIS */
  1024. decode_ais_channel_info(bu, len, 264, session);
  1025. ais->type24.part = both;
  1026. return(ONLINE_SET | AIS_SET);
  1027. }
  1028. }
  1029. #if NMEA2000_DEBUG_AIS
  1030. printf("AIS: MMSI : %09u\n", ais->mmsi);
  1031. printf("AIS: vendor: %-8.8s c:%-8.8s b:%6u s:%6u p:%6u s:%6u\n",
  1032. ais->type24.vendorid,
  1033. ais->type24.callsign,
  1034. ais->type24.dim.to_bow,
  1035. ais->type24.dim.to_stern,
  1036. ais->type24.dim.to_port,
  1037. ais->type24.dim.to_starboard);
  1038. #endif /* of #if NMEA2000_DEBUG_AIS */
  1039. decode_ais_channel_info(bu, len, 264, session);
  1040. ais->type24.part = part_b;
  1041. return(ONLINE_SET | AIS_SET);
  1042. }
  1043. return(0);
  1044. }
  1045. /*
  1046. * PGN 127506: PWR DC Detailed Status
  1047. */
  1048. static gps_mask_t hnd_127506(unsigned char *bu, int len, PGN *pgn,
  1049. struct gps_device_t *session)
  1050. {
  1051. print_data(session->context, bu, len, pgn);
  1052. GPSD_LOG(LOG_DATA, &session->context->errout,
  1053. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1054. return(0);
  1055. }
  1056. /*
  1057. * PGN 127508: PWR Battery Status
  1058. */
  1059. static gps_mask_t hnd_127508(unsigned char *bu, int len, PGN *pgn,
  1060. struct gps_device_t *session)
  1061. {
  1062. print_data(session->context, bu, len, pgn);
  1063. GPSD_LOG(LOG_DATA, &session->context->errout,
  1064. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1065. return(0);
  1066. }
  1067. /*
  1068. * PGN 127513: PWR Battery Configuration Status
  1069. */
  1070. static gps_mask_t hnd_127513(unsigned char *bu, int len, PGN *pgn,
  1071. struct gps_device_t *session)
  1072. {
  1073. print_data(session->context, bu, len, pgn);
  1074. GPSD_LOG(LOG_DATA, &session->context->errout,
  1075. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1076. return(0);
  1077. }
  1078. /*
  1079. * PGN 127245: NAV Rudder
  1080. */
  1081. static gps_mask_t hnd_127245(unsigned char *bu, int len, PGN *pgn,
  1082. struct gps_device_t *session)
  1083. {
  1084. print_data(session->context, bu, len, pgn);
  1085. GPSD_LOG(LOG_DATA, &session->context->errout,
  1086. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1087. return(0);
  1088. }
  1089. /*
  1090. * PGN 127250: NAV Vessel Heading
  1091. */
  1092. static gps_mask_t hnd_127250(unsigned char *bu, int len,
  1093. PGN *pgn, struct gps_device_t *session)
  1094. {
  1095. int aux;
  1096. print_data(session->context, bu, len, pgn);
  1097. session->gpsdata.attitude.heading = getleu16(bu, 1) * RAD_2_DEG * 0.0001;
  1098. // printf("ATT 0:%8.3f\n",session->gpsdata.attitude.heading);
  1099. aux = getles16(bu, 3);
  1100. if (aux != 0x07fff) {
  1101. session->gpsdata.attitude.heading += aux * RAD_2_DEG * 0.0001;
  1102. }
  1103. // printf("ATT 1:%8.3f %6x\n",session->gpsdata.attitude.heading, aux);
  1104. aux = getles16(bu, 5);
  1105. if (aux != 0x07fff) {
  1106. session->gpsdata.attitude.heading += aux * RAD_2_DEG * 0.0001;
  1107. }
  1108. // printf("ATT 2:%8.3f %6x\n",session->gpsdata.attitude.heading, aux);
  1109. GPSD_LOG(LOG_DATA, &session->context->errout,
  1110. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1111. return(ONLINE_SET | ATTITUDE_SET);
  1112. }
  1113. /*
  1114. * PGN 128259: NAV Speed
  1115. */
  1116. static gps_mask_t hnd_128259(unsigned char *bu, int len, PGN *pgn,
  1117. struct gps_device_t *session)
  1118. {
  1119. print_data(session->context, bu, len, pgn);
  1120. GPSD_LOG(LOG_DATA, &session->context->errout,
  1121. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1122. return(0);
  1123. }
  1124. /*
  1125. * PGN 128267: NAV Water Depth
  1126. */
  1127. static gps_mask_t hnd_128267(unsigned char *bu, int len, PGN *pgn,
  1128. struct gps_device_t *session)
  1129. {
  1130. print_data(session->context, bu, len, pgn);
  1131. session->gpsdata.attitude.depth = getleu32(bu, 1) *.01;
  1132. GPSD_LOG(LOG_DATA, &session->context->errout,
  1133. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1134. return(ONLINE_SET | ATTITUDE_SET);
  1135. }
  1136. /*
  1137. * PGN 128275: NAV Distance Log
  1138. */
  1139. static gps_mask_t hnd_128275(unsigned char *bu, int len, PGN *pgn,
  1140. struct gps_device_t *session)
  1141. {
  1142. print_data(session->context, bu, len, pgn);
  1143. GPSD_LOG(LOG_DATA, &session->context->errout,
  1144. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1145. return(0);
  1146. }
  1147. /*
  1148. * PGN 129283: NAV Cross Track Error
  1149. */
  1150. static gps_mask_t hnd_129283(unsigned char *bu, int len, PGN *pgn,
  1151. struct gps_device_t *session)
  1152. {
  1153. print_data(session->context, bu, len, pgn);
  1154. GPSD_LOG(LOG_DATA, &session->context->errout,
  1155. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1156. return(0);
  1157. }
  1158. /*
  1159. * PGN 129284: NAV Navigation Data
  1160. */
  1161. static gps_mask_t hnd_129284(unsigned char *bu, int len, PGN *pgn,
  1162. struct gps_device_t *session)
  1163. {
  1164. print_data(session->context, bu, len, pgn);
  1165. GPSD_LOG(LOG_DATA, &session->context->errout,
  1166. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1167. return(0);
  1168. }
  1169. /*
  1170. * PGN 129285: NAV Navigation - Route/WP Information
  1171. */
  1172. static gps_mask_t hnd_129285(unsigned char *bu, int len, PGN *pgn,
  1173. struct gps_device_t *session)
  1174. {
  1175. print_data(session->context, bu, len, pgn);
  1176. GPSD_LOG(LOG_DATA, &session->context->errout,
  1177. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1178. return(0);
  1179. }
  1180. /*
  1181. * PGN 130306: NAV Wind Data
  1182. */
  1183. static gps_mask_t hnd_130306(unsigned char *bu, int len, PGN *pgn,
  1184. struct gps_device_t *session)
  1185. {
  1186. print_data(session->context, bu, len, pgn);
  1187. GPSD_LOG(LOG_DATA, &session->context->errout,
  1188. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1189. return(0);
  1190. }
  1191. /*
  1192. * PGN 130310: NAV Water Temp., Outside Air Temp., Atmospheric Pressure
  1193. */
  1194. static gps_mask_t hnd_130310(unsigned char *bu, int len, PGN *pgn,
  1195. struct gps_device_t *session)
  1196. {
  1197. print_data(session->context, bu, len, pgn);
  1198. GPSD_LOG(LOG_DATA, &session->context->errout,
  1199. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1200. return(0);
  1201. }
  1202. /*
  1203. * PGN 130311: NAV Environmental Parameters
  1204. */
  1205. static gps_mask_t hnd_130311(unsigned char *bu, int len, PGN *pgn,
  1206. struct gps_device_t *session)
  1207. {
  1208. print_data(session->context, bu, len, pgn);
  1209. GPSD_LOG(LOG_DATA, &session->context->errout,
  1210. "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit);
  1211. return(0);
  1212. }
  1213. static const char msg_059392[] = {"ISO Acknowledgment"};
  1214. static const char msg_060928[] = {"ISO Address Claim"};
  1215. static const char msg_126208[] = {"NMEA Command/Request/Acknowledge"};
  1216. static const char msg_126464[] = {"ISO Transmit/Receive PGN List"};
  1217. static const char msg_126992[] = {"GNSS System Time"};
  1218. static const char msg_126996[] = {"ISO Product Information"};
  1219. static const char msg_127506[] = {"PWR DC Detailed Status"};
  1220. static const char msg_127508[] = {"PWR Battery Status"};
  1221. static const char msg_127513[] = {"PWR Battery Configuration Status"};
  1222. static const char msg_127258[] = {"GNSS Magnetic Variation"};
  1223. static const char msg_129025[] = {"GNSS Position Rapid Update"};
  1224. static const char msg_129026[] = {"GNSS COG and SOG Rapid Update"};
  1225. static const char msg_129029[] = {"GNSS Positition Data"};
  1226. static const char msg_129539[] = {"GNSS DOPs"};
  1227. static const char msg_129540[] = {"GNSS Satellites in View"};
  1228. static const char msg_129038[] = {"AIS Class A Position Report"};
  1229. static const char msg_129039[] = {"AIS Class B Position Report"};
  1230. static const char msg_129040[] = {"AIS Class B Extended Position Report"};
  1231. static const char msg_129793[] = {"AIS UTC and Date report"};
  1232. static const char msg_129794[] = {"AIS Class A Static and Voyage Related Data"};
  1233. static const char msg_129798[] = {"AIS SAR Aircraft Position Report"};
  1234. static const char msg_129802[] = {"AIS Safety Related Broadcast Message"};
  1235. static const char msg_129809[] = {"AIS Class B CS Static Data Report, Part A"};
  1236. static const char msg_129810[] = {"AIS Class B CS Static Data Report, Part B"};
  1237. static const char msg_127245[] = {"NAV Rudder"};
  1238. static const char msg_127250[] = {"NAV Vessel Heading"};
  1239. static const char msg_128259[] = {"NAV Speed"};
  1240. static const char msg_128267[] = {"NAV Water Depth"};
  1241. static const char msg_128275[] = {"NAV Distance Log"};
  1242. static const char msg_129283[] = {"NAV Cross Track Error"};
  1243. static const char msg_129284[] = {"NAV Navigation Data"};
  1244. static const char msg_129285[] = {"NAV Navigation - Route/WP Information"};
  1245. static const char msg_130306[] = {"NAV Wind Data"};
  1246. static const char msg_130310[] = {"NAV Water Temp., Outside Air Temp.,"
  1247. "Atmospheric Pressure"};
  1248. static const char msg_130311[] = {"NAV Environmental Parameters"};
  1249. static const char msg_error [] = {"**error**"};
  1250. static PGN gpspgn[] = {{ 59392, 0, 0, hnd_059392, &msg_059392[0]},
  1251. { 60928, 0, 0, hnd_060928, &msg_060928[0]},
  1252. {126208, 0, 0, hnd_126208, &msg_126208[0]},
  1253. {126464, 1, 0, hnd_126464, &msg_126464[0]},
  1254. {126992, 0, 0, hnd_126992, &msg_126992[0]},
  1255. {126996, 1, 0, hnd_126996, &msg_126996[0]},
  1256. {127258, 0, 0, hnd_127258, &msg_127258[0]},
  1257. {129025, 0, 1, hnd_129025, &msg_129025[0]},
  1258. {129026, 0, 1, hnd_129026, &msg_129026[0]},
  1259. {129029, 1, 1, hnd_129029, &msg_129029[0]},
  1260. {129283, 0, 0, hnd_129283, &msg_129283[0]},
  1261. {129284, 1, 0, hnd_129284, &msg_129284[0]},
  1262. {129285, 1, 0, hnd_129285, &msg_129285[0]},
  1263. {129539, 0, 1, hnd_129539, &msg_129539[0]},
  1264. {129540, 1, 1, hnd_129540, &msg_129540[0]},
  1265. {0 , 0, 0, NULL, &msg_error [0]}};
  1266. static PGN aispgn[] = {{ 59392, 0, 0, hnd_059392, &msg_059392[0]},
  1267. { 60928, 0, 0, hnd_060928, &msg_060928[0]},
  1268. {126208, 0, 0, hnd_126208, &msg_126208[0]},
  1269. {126464, 1, 0, hnd_126464, &msg_126464[0]},
  1270. {126992, 0, 0, hnd_126992, &msg_126992[0]},
  1271. {126996, 1, 0, hnd_126996, &msg_126996[0]},
  1272. {129038, 1, 2, hnd_129038, &msg_129038[0]},
  1273. {129039, 1, 2, hnd_129039, &msg_129039[0]},
  1274. {129040, 1, 2, hnd_129040, &msg_129040[0]},
  1275. {129793, 1, 2, hnd_129793, &msg_129793[0]},
  1276. {129794, 1, 2, hnd_129794, &msg_129794[0]},
  1277. {129798, 1, 2, hnd_129798, &msg_129798[0]},
  1278. {129802, 1, 2, hnd_129802, &msg_129802[0]},
  1279. {129809, 1, 2, hnd_129809, &msg_129809[0]},
  1280. {129810, 1, 2, hnd_129810, &msg_129810[0]},
  1281. {0 , 0, 0, NULL, &msg_error [0]}};
  1282. static PGN pwrpgn[] = {{ 59392, 0, 0, hnd_059392, &msg_059392[0]},
  1283. { 60928, 0, 0, hnd_060928, &msg_060928[0]},
  1284. {126208, 0, 0, hnd_126208, &msg_126208[0]},
  1285. {126464, 1, 0, hnd_126464, &msg_126464[0]},
  1286. {126992, 0, 0, hnd_126992, &msg_126992[0]},
  1287. {126996, 1, 0, hnd_126996, &msg_126996[0]},
  1288. {127506, 1, 3, hnd_127506, &msg_127506[0]},
  1289. {127508, 1, 3, hnd_127508, &msg_127508[0]},
  1290. {127513, 1, 3, hnd_127513, &msg_127513[0]},
  1291. {0 , 0, 0, NULL, &msg_error [0]}};
  1292. static PGN navpgn[] = {{ 59392, 0, 0, hnd_059392, &msg_059392[0]},
  1293. { 60928, 0, 0, hnd_060928, &msg_060928[0]},
  1294. {126208, 0, 0, hnd_126208, &msg_126208[0]},
  1295. {126464, 1, 0, hnd_126464, &msg_126464[0]},
  1296. {126992, 0, 0, hnd_126992, &msg_126992[0]},
  1297. {126996, 1, 0, hnd_126996, &msg_126996[0]},
  1298. {127245, 0, 4, hnd_127245, &msg_127245[0]},
  1299. {127250, 0, 4, hnd_127250, &msg_127250[0]},
  1300. {127258, 0, 0, hnd_127258, &msg_127258[0]},
  1301. {128259, 0, 4, hnd_128259, &msg_128259[0]},
  1302. {128267, 0, 4, hnd_128267, &msg_128267[0]},
  1303. {128275, 1, 4, hnd_128275, &msg_128275[0]},
  1304. {129283, 0, 0, hnd_129283, &msg_129283[0]},
  1305. {129284, 1, 0, hnd_129284, &msg_129284[0]},
  1306. {129285, 1, 0, hnd_129285, &msg_129285[0]},
  1307. {130306, 0, 4, hnd_130306, &msg_130306[0]},
  1308. {130310, 0, 4, hnd_130310, &msg_130310[0]},
  1309. {130311, 0, 4, hnd_130311, &msg_130311[0]},
  1310. {0 , 0, 0, NULL, &msg_error [0]}};
  1311. static PGN *search_pgnlist(unsigned int pgn, PGN *pgnlist)
  1312. {
  1313. int l1;
  1314. PGN *work;
  1315. l1 = 0;
  1316. work = NULL;
  1317. while (pgnlist[l1].pgn != 0) {
  1318. if (pgnlist[l1].pgn == pgn) {
  1319. work = &pgnlist[l1];
  1320. break;
  1321. } else {
  1322. l1 = l1 + 1;
  1323. }
  1324. }
  1325. return work;
  1326. }
  1327. static void find_pgn(struct can_frame *frame, struct gps_device_t *session)
  1328. {
  1329. unsigned int can_net;
  1330. session->driver.nmea2000.workpgn = NULL;
  1331. can_net = session->driver.nmea2000.can_net;
  1332. if (can_net > (NMEA2000_NETS-1)) {
  1333. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1334. "NMEA2000 find_pgn: Invalid can network %d.\n", can_net);
  1335. return;
  1336. }
  1337. if (frame->can_id & 0x80000000) {
  1338. unsigned int source_prio;
  1339. unsigned int daddr;
  1340. unsigned int source_pgn;
  1341. unsigned int source_unit;
  1342. #if LOG_FILE
  1343. if (logFile != NULL) {
  1344. struct timespec msgTime;
  1345. clock_gettime(CLOCK_REALTIME, &msgTime);
  1346. (void)fprintf(logFile,
  1347. "(%010lld.%06ld) can0 %08x#",
  1348. (long long)msgTime.tv_sec,
  1349. msgTime.tv_nsec / 1000,
  1350. frame->can_id & 0x1ffffff);
  1351. if ((frame->can_dlc & 0x0f) > 0) {
  1352. int l1;
  1353. for(l1=0;l1<(frame->can_dlc & 0x0f);l1++) {
  1354. (void)fprintf(logFile, "%02x", frame->data[l1]);
  1355. }
  1356. }
  1357. (void)fprintf(logFile, "\n");
  1358. }
  1359. #endif /* of if LOG_FILE */
  1360. session->driver.nmea2000.can_msgcnt += 1;
  1361. source_pgn = (frame->can_id >> 8) & 0x1ffff;
  1362. source_prio = (frame->can_id >> 26) & 0x7;
  1363. source_unit = frame->can_id & 0x0ff;
  1364. if (((source_pgn & 0x0ff00) >> 8) < 240) {
  1365. daddr = source_pgn & 0x000ff;
  1366. source_pgn = source_pgn & 0x1ff00;
  1367. } else {
  1368. daddr = 0xff;
  1369. }
  1370. GPSD_LOG(LOG_DATA, &session->context->errout,
  1371. "nmea2000: source_prio %u daddr %u",
  1372. source_prio, daddr);
  1373. if (!session->driver.nmea2000.unit_valid) {
  1374. unsigned int l1, l2;
  1375. for (l1=0;l1<NMEA2000_NETS;l1++) {
  1376. for (l2=0;l2<NMEA2000_UNITS;l2++) {
  1377. if (session == nmea2000_units[l1][l2]) {
  1378. session->driver.nmea2000.unit = l2;
  1379. session->driver.nmea2000.unit_valid = true;
  1380. session->driver.nmea2000.can_net = l1;
  1381. can_net = l1;
  1382. }
  1383. }
  1384. }
  1385. session->driver.nmea2000.unit = source_unit;
  1386. session->driver.nmea2000.unit_valid = true;
  1387. nmea2000_units[can_net][source_unit] = session;
  1388. }
  1389. if (source_unit == session->driver.nmea2000.unit) {
  1390. PGN *work;
  1391. if (session->driver.nmea2000.pgnlist != NULL) {
  1392. work = search_pgnlist(source_pgn,
  1393. session->driver.nmea2000.pgnlist);
  1394. } else {
  1395. PGN *pgnlist;
  1396. pgnlist = &gpspgn[0];
  1397. work = search_pgnlist(source_pgn, pgnlist);
  1398. if (work == NULL) {
  1399. pgnlist = &aispgn[0];
  1400. work = search_pgnlist(source_pgn, pgnlist);
  1401. }
  1402. if (work == NULL) {
  1403. pgnlist = &pwrpgn[0];
  1404. work = search_pgnlist(source_pgn, pgnlist);
  1405. }
  1406. if (work == NULL) {
  1407. pgnlist = &navpgn[0];
  1408. work = search_pgnlist(source_pgn, pgnlist);
  1409. }
  1410. if ((work != NULL) && (work->type > 0)) {
  1411. session->driver.nmea2000.pgnlist = pgnlist;
  1412. }
  1413. }
  1414. if (work != NULL) {
  1415. if (work->fast == 0) {
  1416. size_t l2;
  1417. GPSD_LOG(LOG_DATA, &session->context->errout,
  1418. "pgn %6d:%s \n", work->pgn, work->name);
  1419. session->driver.nmea2000.workpgn = (void *) work;
  1420. session->lexer.outbuflen = frame->can_dlc & 0x0f;
  1421. for (l2=0;l2<session->lexer.outbuflen;l2++) {
  1422. session->lexer.outbuffer[l2]= frame->data[l2];
  1423. }
  1424. } else if ((frame->data[0] & 0x1f) == 0) {
  1425. unsigned int l2;
  1426. session->driver.nmea2000.fast_packet_len = frame->data[1];
  1427. session->driver.nmea2000.idx = frame->data[0];
  1428. #if NMEA2000_FAST_DEBUG
  1429. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1430. "Set idx %2x %2x %2x %6d\n",
  1431. frame->data[0],
  1432. session->driver.nmea2000.unit,
  1433. frame->data[1],
  1434. source_pgn);
  1435. #endif /* of #if NMEA2000_FAST_DEBUG */
  1436. session->lexer.inbuflen = 0;
  1437. session->driver.nmea2000.idx += 1;
  1438. for (l2=2;l2<8;l2++) {
  1439. session->lexer.inbuffer[session->lexer.inbuflen++] =
  1440. frame->data[l2];
  1441. }
  1442. GPSD_LOG(LOG_DATA, &session->context->errout,
  1443. "pgn %6d:%s \n", work->pgn, work->name);
  1444. } else if (frame->data[0] == session->driver.nmea2000.idx) {
  1445. unsigned int l2;
  1446. for (l2=1;l2<8;l2++) {
  1447. if (session->driver.nmea2000.fast_packet_len >
  1448. session->lexer.inbuflen) {
  1449. session->lexer.inbuffer[session->lexer.inbuflen++] =
  1450. frame->data[l2];
  1451. }
  1452. }
  1453. if (session->lexer.inbuflen ==
  1454. session->driver.nmea2000.fast_packet_len) {
  1455. #if NMEA2000_FAST_DEBUG
  1456. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1457. "Fast done %2x %2x %2x %2x %6d\n",
  1458. session->driver.nmea2000.idx,
  1459. frame->data[0],
  1460. session->driver.nmea2000.unit,
  1461. (unsigned int)session->driver.nmea2000.fast_packet_len,
  1462. source_pgn);
  1463. #endif /* of #if NMEA2000_FAST_DEBUG */
  1464. session->driver.nmea2000.workpgn = (void *) work;
  1465. session->lexer.outbuflen =
  1466. session->driver.nmea2000.fast_packet_len;
  1467. for(l2 = 0;l2 < (unsigned int)session->lexer.outbuflen;
  1468. l2++) {
  1469. session->lexer.outbuffer[l2] =
  1470. session->lexer.inbuffer[l2];
  1471. }
  1472. session->driver.nmea2000.fast_packet_len = 0;
  1473. } else {
  1474. session->driver.nmea2000.idx += 1;
  1475. }
  1476. } else {
  1477. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1478. "Fast error %2x %2x %2x %2x %6d\n",
  1479. session->driver.nmea2000.idx,
  1480. frame->data[0],
  1481. session->driver.nmea2000.unit,
  1482. (unsigned int)session->driver.nmea2000.fast_packet_len,
  1483. source_pgn);
  1484. }
  1485. } else {
  1486. GPSD_LOG(LOG_WARN, &session->context->errout,
  1487. "PGN not found %08d %08x \n",
  1488. source_pgn, source_pgn);
  1489. }
  1490. } else {
  1491. // we got a unknown unit number
  1492. if (nmea2000_units[can_net][source_unit] == NULL) {
  1493. char buffer[55];
  1494. (void) snprintf(buffer,
  1495. sizeof(buffer),
  1496. "nmea2000://%s:%u",
  1497. can_interface_name[can_net],
  1498. source_unit);
  1499. if (gpsd_add_device != NULL) {
  1500. (void) gpsd_add_device(buffer, true);
  1501. }
  1502. }
  1503. }
  1504. } else {
  1505. // we got RTR or 2.0A CAN frame, not used
  1506. }
  1507. }
  1508. static ssize_t nmea2000_get(struct gps_device_t *session)
  1509. {
  1510. struct can_frame frame;
  1511. ssize_t status;
  1512. session->lexer.outbuflen = 0;
  1513. status = read(session->gpsdata.gps_fd, &frame, sizeof(frame));
  1514. if (status == (ssize_t)sizeof(frame)) {
  1515. session->lexer.type = NMEA2000_PACKET;
  1516. find_pgn(&frame, session);
  1517. return frame.can_dlc & 0x0f;
  1518. }
  1519. return 0;
  1520. }
  1521. static gps_mask_t nmea2000_parse_input(struct gps_device_t *session)
  1522. {
  1523. gps_mask_t mask;
  1524. PGN *work;
  1525. // printf("NMEA2000 parse_input called\n");
  1526. mask = 0;
  1527. work = (PGN *) session->driver.nmea2000.workpgn;
  1528. if (work != NULL) {
  1529. mask = (work->func)(&session->lexer.outbuffer[0],
  1530. (int)session->lexer.outbuflen, work, session);
  1531. session->driver.nmea2000.workpgn = NULL;
  1532. }
  1533. session->lexer.outbuflen = 0;
  1534. return mask;
  1535. }
  1536. int nmea2000_open(struct gps_device_t *session)
  1537. {
  1538. char interface_name[GPS_PATH_MAX];
  1539. socket_t sock;
  1540. int status;
  1541. int unit_number;
  1542. int can_net;
  1543. unsigned int l;
  1544. struct ifreq ifr;
  1545. struct sockaddr_can addr;
  1546. char *unit_ptr;
  1547. INVALIDATE_SOCKET(session->gpsdata.gps_fd);
  1548. session->driver.nmea2000.can_net = 0;
  1549. can_net = -1;
  1550. unit_number = -1;
  1551. (void)strlcpy(interface_name, session->gpsdata.dev.path + 11,
  1552. sizeof(interface_name));
  1553. unit_ptr = NULL;
  1554. for (l=0;l<strnlen(interface_name,sizeof(interface_name));l++) {
  1555. if (interface_name[l] == ':') {
  1556. unit_ptr = &interface_name[l+1];
  1557. interface_name[l] = 0;
  1558. continue;
  1559. }
  1560. if (unit_ptr != NULL) {
  1561. if (isdigit(interface_name[l]) == 0) {
  1562. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1563. "NMEA2000 open: Invalid character in unit number.\n");
  1564. return -1;
  1565. }
  1566. }
  1567. }
  1568. if (unit_ptr != NULL) {
  1569. unit_number = atoi(unit_ptr);
  1570. if ((unit_number < 0) || (unit_number > (NMEA2000_UNITS-1))) {
  1571. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1572. "NMEA2000 open: Unit number out of range.\n");
  1573. return -1;
  1574. }
  1575. for (l = 0; l < NMEA2000_NETS; l++) {
  1576. if (strncmp(can_interface_name[l],
  1577. interface_name,
  1578. MIN(sizeof(interface_name),
  1579. sizeof(can_interface_name[l]))) == 0) {
  1580. can_net = l;
  1581. break;
  1582. }
  1583. }
  1584. if (can_net < 0) {
  1585. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1586. "NMEA2000 open: CAN device not open: %s .\n",
  1587. interface_name);
  1588. return -1;
  1589. }
  1590. } else {
  1591. for (l = 0; l < NMEA2000_NETS; l++) {
  1592. if (strncmp(can_interface_name[l],
  1593. interface_name,
  1594. MIN(sizeof(interface_name),
  1595. sizeof(can_interface_name[l]))) == 0) {
  1596. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1597. "NMEA2000 open: CAN device duplicate open: %s .\n",
  1598. interface_name);
  1599. return -1;
  1600. }
  1601. }
  1602. for (l = 0; l < NMEA2000_NETS; l++) {
  1603. if (can_interface_name[l][0] == 0) {
  1604. can_net = l;
  1605. break;
  1606. }
  1607. }
  1608. if (can_net < 0) {
  1609. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1610. "NMEA2000 open: Too many CAN networks open.\n");
  1611. return -1;
  1612. }
  1613. }
  1614. /* Create the socket */
  1615. sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
  1616. if (BAD_SOCKET(sock)) {
  1617. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1618. "NMEA2000 open: can not get socket.\n");
  1619. return -1;
  1620. }
  1621. status = fcntl(sock, F_SETFL, O_NONBLOCK);
  1622. if (status != 0) {
  1623. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1624. "NMEA2000 open: can not set socket to O_NONBLOCK.\n");
  1625. close(sock);
  1626. return -1;
  1627. }
  1628. /* Locate the interface you wish to use */
  1629. strlcpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name));
  1630. status = ioctl(sock, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled
  1631. * with that device's index */
  1632. if (status != 0) {
  1633. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1634. "NMEA2000 open: can not find CAN device.\n");
  1635. close(sock);
  1636. return -1;
  1637. }
  1638. /* Select that CAN interface, and bind the socket to it. */
  1639. addr.can_family = AF_CAN;
  1640. addr.can_ifindex = ifr.ifr_ifindex;
  1641. status = bind(sock, (struct sockaddr*)&addr, sizeof(addr) );
  1642. if (status != 0) {
  1643. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1644. "NMEA2000 open: bind failed.\n");
  1645. close(sock);
  1646. return -1;
  1647. }
  1648. gpsd_switch_driver(session, "NMEA2000");
  1649. session->gpsdata.gps_fd = sock;
  1650. session->sourcetype = SOURCE_CAN;
  1651. session->servicetype = SERVICE_SENSOR;
  1652. session->driver.nmea2000.can_net = can_net;
  1653. if (unit_ptr != NULL) {
  1654. nmea2000_units[can_net][unit_number] = session;
  1655. session->driver.nmea2000.unit = unit_number;
  1656. session->driver.nmea2000.unit_valid = true;
  1657. } else {
  1658. strlcpy(can_interface_name[can_net],
  1659. interface_name,
  1660. MIN(sizeof(can_interface_name[0]), sizeof(interface_name)));
  1661. session->driver.nmea2000.unit_valid = false;
  1662. for (l=0;l<NMEA2000_UNITS;l++) {
  1663. nmea2000_units[can_net][l] = NULL;
  1664. }
  1665. }
  1666. session->gpsdata.dev.parity = 'N';
  1667. session->gpsdata.dev.baudrate = 250000;
  1668. session->gpsdata.dev.stopbits = 0;
  1669. return session->gpsdata.gps_fd;
  1670. }
  1671. void nmea2000_close(struct gps_device_t *session)
  1672. {
  1673. if (!BAD_SOCKET(session->gpsdata.gps_fd)) {
  1674. GPSD_LOG(LOG_SPIN, &session->context->errout,
  1675. "close(%d) in nmea2000_close(%s)\n",
  1676. session->gpsdata.gps_fd, session->gpsdata.dev.path);
  1677. (void)close(session->gpsdata.gps_fd);
  1678. INVALIDATE_SOCKET(session->gpsdata.gps_fd);
  1679. if (session->driver.nmea2000.unit_valid) {
  1680. unsigned int l1, l2;
  1681. for (l1=0;l1<NMEA2000_NETS;l1++) {
  1682. for (l2=0;l2<NMEA2000_UNITS;l2++) {
  1683. if (session == nmea2000_units[l1][l2]) {
  1684. session->driver.nmea2000.unit_valid = false;
  1685. session->driver.nmea2000.unit = 0;
  1686. session->driver.nmea2000.can_net = 0;
  1687. nmea2000_units[l1][l2] = NULL;
  1688. }
  1689. }
  1690. }
  1691. }
  1692. }
  1693. }
  1694. /* *INDENT-OFF* */
  1695. const struct gps_type_t driver_nmea2000 = {
  1696. .type_name = "NMEA2000", /* full name of type */
  1697. .packet_type = NMEA2000_PACKET, /* associated lexer packet type */
  1698. .flags = DRIVER_STICKY, /* remember this */
  1699. .trigger = NULL, /* detect their main sentence */
  1700. .channels = 12, /* not an actual GPS at all */
  1701. .probe_detect = NULL,
  1702. .get_packet = nmea2000_get, /* how to get a packet */
  1703. .parse_packet = nmea2000_parse_input, /* how to interpret a packet */
  1704. .rtcm_writer = NULL, /* Don't send RTCM to this */
  1705. .init_query = NULL, /* non-perturbing query */
  1706. .event_hook = NULL,
  1707. .speed_switcher = NULL, /* no speed switcher */
  1708. .mode_switcher = NULL, /* no mode switcher */
  1709. .rate_switcher = NULL, /* no rate switcher */
  1710. .min_cycle.tv_sec = 1, /* not relevant, no rate switch */
  1711. .min_cycle.tv_nsec = 0, /* not relevant, no rate switch */
  1712. .control_send = NULL, /* how to send control strings */
  1713. .time_offset = NULL,
  1714. };
  1715. /* *INDENT-ON* */
  1716. /* end */
  1717. #else /* of defined(NMEA2000_ENABLE) */
  1718. /* dummy variable to some old linkers do not complain about empty
  1719. * object file */
  1720. int nmea2000_dummy = 1;
  1721. #endif /* of defined(NMEA2000_ENABLE) */
  1722. // vim: set expandtab shiftwidth=4