driver_nmea2000.c 69 KB

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