SELKIELogger  1.0.0
N2KMessages.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include <math.h>
25 
26 #include "N2KMessages.h"
27 #include "N2KTypes.h"
28 
34 uint8_t n2k_get_uint8(const n2k_act_message *n, size_t offset) {
35  return n->data[offset];
36 }
37 
43 int8_t n2k_get_int8(const n2k_act_message *n, size_t offset) {
44  uint8_t u = n2k_get_uint8(n, offset);
45  int8_t v = (u & 0x7F);
46  if (u & 0x80) { v = -1 * ((1 << 7) - v); }
47  return v;
48 }
49 
55 int16_t n2k_get_int16(const n2k_act_message *n, size_t offset) {
56  uint16_t u = n2k_get_uint16(n, offset);
57  int16_t v = (u & 0x7FFF);
58  if (u & 0x8000) { v = -1 * ((1 << 15) - v); }
59  return v;
60 }
61 
67 uint16_t n2k_get_uint16(const n2k_act_message *n, size_t offset) {
68  return n->data[offset] + (n->data[offset + 1] << 8);
69 }
70 
76 int32_t n2k_get_int32(const n2k_act_message *n, size_t offset) {
77  uint32_t u = n2k_get_uint32(n, offset);
78  int32_t v = (u & 0x7FFFFFFFUL);
79  if (u & 0x80000000UL) { v = -1 * ((1UL << 31) - v); }
80  return v;
81 }
82 
88 uint32_t n2k_get_uint32(const n2k_act_message *n, size_t offset) {
89  uint32_t v = n->data[offset] + ((uint32_t)(n->data[offset + 1]) << 8) +
90  ((uint32_t)(n->data[offset + 2]) << 16) + ((uint32_t)(n->data[offset + 3]) << 24);
91  return v;
92 }
93 
99 int64_t n2k_get_int64(const n2k_act_message *n, size_t offset) {
100  uint64_t u = n2k_get_uint64(n, offset);
101  int64_t v = (u & 0x7FFFFFFFFFFFFFFFULL);
102  if (u & 0x8000000000000000ULL) { v = -1 * ((1ULL << 63) - v); }
103  return v;
104 }
105 
111 uint64_t n2k_get_uint64(const n2k_act_message *n, size_t offset) {
112  uint64_t v = n->data[offset] + ((uint64_t)(n->data[offset + 1]) << 8) +
113  ((uint64_t)(n->data[offset + 2]) << 16) + ((uint64_t)(n->data[offset + 3]) << 24) +
114  ((uint64_t)(n->data[offset + 4]) << 32) + ((uint64_t)(n->data[offset + 5]) << 40) +
115  ((uint64_t)(n->data[offset + 6]) << 48) + ((uint64_t)(n->data[offset + 7]) << 56);
116  return v;
117 }
118 
125 double n2k_get_double(const n2k_act_message *n, size_t offset, uint8_t size) {
126  double d = 0;
127  if (size == 8) {
128  int8_t v = n2k_get_int8(n, offset);
129  if (v == INT8_MAX || v == INT8_MIN) { return NAN; }
130  d = v;
131  } else if (size == 16) {
132  int16_t v = n2k_get_int16(n, offset);
133  if (v == INT16_MAX || v == INT16_MIN) { return NAN; }
134  d = v;
135  } else if (size == 32) {
136  int32_t v = n2k_get_int32(n, offset);
137  if (v == INT32_MAX || v == INT32_MIN) { return NAN; }
138  d = v;
139  } else if (size == 64) {
140  int64_t v = n2k_get_int64(n, offset);
141  if (v == INT64_MAX || v == INT64_MIN) { return NAN; }
142  d = v;
143  }
144  return d;
145 }
146 
153 double n2k_get_udouble(const n2k_act_message *n, size_t offset, uint8_t size) {
154  double d = 0;
155  if (size == 8) {
156  uint8_t v = n2k_get_uint8(n, offset);
157  if (v == UINT8_MAX) { return NAN; }
158  d = v;
159  } else if (size == 16) {
160  uint16_t v = n2k_get_uint16(n, offset);
161  if (v == UINT16_MAX) { return NAN; }
162  d = v;
163  } else if (size == 32) {
164  uint32_t v = n2k_get_uint32(n, offset);
165  if (v == UINT32_MAX) { return NAN; }
166  d = v;
167  } else if (size == 64) {
168  uint64_t v = n2k_get_uint64(n, offset);
169  if (v == UINT64_MAX) { return NAN; }
170  d = v;
171  }
172  return d;
173 }
174 
187 bool n2k_60928_values(const n2k_act_message *n, uint32_t *id, uint16_t *mfr, uint8_t *inst, uint8_t *fn, uint8_t *class,
188  uint8_t *sys, uint8_t *ind, bool *cfg) {
189  if (!n || n->PGN != 60928 || !n->data || n->datalen < 8) { return false; }
190  bool success = true;
191  if (id) { (*id) = n2k_get_uint32(n, 0) & 0x1FFFFF; }
192  if (mfr) { (*mfr) = n2k_get_uint16(n, 2) >> 5; }
193  if (inst) { (*inst) = n2k_get_uint8(n, 4); }
194  if (fn) { (*fn) = n2k_get_uint8(n, 5); }
195  if (class) { (*class) = (n2k_get_uint8(n, 6) & 0xFE) >> 1; } // Discard single reserved bit
196  uint8_t si = n2k_get_uint8(n, 7);
197  if (cfg) { (*cfg) = (si & 0x80) == 0x80; }
198  if (ind) { (*ind) = (si & 0x70) >> 4; }
199  if (sys) { (*sys) = (si & 0x0F); }
200  return success;
201 }
202 
212 bool n2k_127250_values(const n2k_act_message *n, uint8_t *seq, double *hdg, double *dev, double *var, uint8_t *ref) {
213  if (!n || n->PGN != 127250 || !n->data || n->datalen < 8) { return false; }
214 
215  if (seq) { (*seq) = n2k_get_uint8(n, 0); }
216 
217  bool success = true;
218  if (hdg) {
219  (*hdg) = n2k_get_udouble(n, 1, 16) * N2K_TO_DEGREES;
220  success &= isfinite((*hdg));
221  }
222 
223  if (dev) {
224  (*dev) = n2k_get_double(n, 3, 16) * N2K_TO_DEGREES;
225  success &= isfinite((*dev));
226  }
227  if (var) {
228  (*var) = n2k_get_double(n, 5, 16) * N2K_TO_DEGREES;
229  success &= isfinite((*var));
230  }
231 
232  if (ref) { (*ref) = n2k_get_uint8(n, 7) & 0x03; }
233 
234  return success;
235 }
236 
243 bool n2k_127251_values(const n2k_act_message *n, uint8_t *seq, double *rate) {
244  if (!n || n->PGN != 127251 || !n->data || n->datalen < 8) { return false; }
245 
246  if (seq) { (*seq) = n2k_get_uint8(n, 0); }
247 
248  if (rate) {
249  (*rate) = n2k_get_double(n, 1, 32) / 3200 * N2K_TO_DEGREES;
250  if (!isfinite((*rate))) { return false; }
251  }
252 
253  return true;
254 }
255 
264 bool n2k_127257_values(const n2k_act_message *n, uint8_t *seq, double *yaw, double *pitch, double *roll) {
265  if (!n || n->PGN != 127257 || !n->data || n->datalen < 7) { return false; }
266  if (seq) { *seq = n2k_get_uint8(n, 0); }
267  bool success = true;
268  if (yaw) {
269  (*yaw) = n2k_get_double(n, 1, 16) * N2K_TO_DEGREES;
270  success &= isfinite(*yaw);
271  }
272  if (pitch) {
273  (*pitch) = n2k_get_double(n, 3, 16) * N2K_TO_DEGREES;
274  success &= isfinite(*pitch);
275  }
276  if (roll) {
277  (*roll) = n2k_get_double(n, 5, 16) * N2K_TO_DEGREES;
278  success &= isfinite(*roll);
279  }
280  return success;
281 }
282 
291 bool n2k_128267_values(const n2k_act_message *n, uint8_t *seq, double *depth, double *offset, double *range) {
292  if (!n || n->PGN != 128267 || !n->data || n->datalen < 8) { return false; }
293 
294  bool success = true;
295  if (seq) { *seq = n2k_get_uint8(n, 0); }
296 
297  if (depth) {
298  (*depth) = n2k_get_udouble(n, 1, 32) * 0.01;
299  success &= isfinite((*depth));
300  }
301 
302  if (offset) {
303  (*offset) = n2k_get_double(n, 5, 16) * 0.01;
304  success &= isfinite((*offset));
305  }
306  if (range) {
307  (*range) = n2k_get_double(n, 7, 8) * 10.0;
308  success &= isfinite((*range));
309  }
310 
311  return success;
312 }
313 
320 bool n2k_129025_values(const n2k_act_message *n, double *lat, double *lon) {
321  if (!n || n->PGN != 129025 || !n->data || n->datalen < 8) { return false; }
322  bool success = true;
323  if (lat) {
324  (*lat) = n2k_get_double(n, 0, 32) * 1E-7;
325  success &= isfinite((*lat));
326  }
327  if (lon) {
328  (*lon) = n2k_get_double(n, 4, 32) * 1E-7;
329  success &= isfinite((*lon));
330  }
331  return success;
332 }
333 
342 bool n2k_129026_values(const n2k_act_message *n, uint8_t *seq, uint8_t *mag, double *course, double *speed) {
343  if (!n || n->PGN != 129026 || !n->data || n->datalen < 8) { return false; }
344  if (seq) { *seq = n2k_get_uint8(n, 0); }
345  if (mag) { (*mag) = n2k_get_uint8(n, 1) & 0x03; }
346 
347  bool success = true;
348  if (course) {
349  (*course) = n2k_get_udouble(n, 2, 16) * N2K_TO_DEGREES;
350  success &= isfinite((*course));
351  }
352  if (speed) {
353  (*speed) = n2k_get_double(n, 4, 16) * 0.01;
354  success &= isfinite((*speed));
355  }
356  return success;
357 }
358 
380 bool n2k_129029_values(const n2k_act_message *n, uint8_t *seq, uint16_t *epochDays, double *seconds, double *lat,
381  double *lon, double *alt, uint8_t *type, uint8_t *method, uint8_t *integ, uint8_t *nsv,
382  double *hdop, double *pdop, double *geos, uint8_t *rs, uint8_t *rst, uint16_t *rsid,
383  double *dgnssa) {
384  if (!n || n->PGN != 129029 || !n->data || n->datalen < 43) { return false; }
385  bool success = true;
386  if (seq) { (*seq) = n2k_get_uint8(n, 0); }
387  if (epochDays) { (*epochDays) = n2k_get_uint16(n, 1); }
388  if (seconds) {
389  (*seconds) = n2k_get_uint32(n, 3) * 0.0001;
390  success &= isfinite((*seconds));
391  }
392 
393  if (lat) {
394  (*lat) = n2k_get_double(n, 7, 64) * 1E-16;
395  success &= isfinite((*lat));
396  }
397 
398  if (lon) {
399  (*lon) = n2k_get_double(n, 15, 64) * 1E-16;
400  success &= isfinite((*lon));
401  }
402 
403  if (alt) {
404  (*alt) = n2k_get_double(n, 23, 64) * 1E-6;
405  success &= isfinite((*alt));
406  }
407 
408  uint8_t tm = n2k_get_uint8(n, 31);
409  if (type) { (*type) = (tm & 0x0F); }
410  if (method) { (*method) = (tm & 0xF0) >> 4; }
411  if (integ) { (*integ) = (n2k_get_uint8(n, 32) & 0xC0) >> 12; }
412 
413  if (nsv) { (*nsv) = n2k_get_uint8(n, 33); }
414  if (hdop) {
415  (*hdop) = n2k_get_double(n, 34, 16) * 0.01;
416  success &= isfinite((*hdop));
417  }
418 
419  if (pdop) {
420  (*pdop) = n2k_get_double(n, 36, 16) * 0.01;
421  success &= isfinite((*pdop));
422  }
423 
424  if (geos) {
425  (*geos) = n2k_get_double(n, 38, 16) * 0.01;
426  success &= isfinite((*geos));
427  }
428 
429  if (rs) { (*rs) = n2k_get_uint8(n, 40); }
430  uint16_t rsdetails = n2k_get_uint16(n, 41);
431  if (rst) { (*rst) = rsdetails & 0x000F; }
432  if (rsid) { (*rsid) = (rsdetails & 0xFFF0) >> 4; }
433 
434  if (dgnssa && n->datalen >= 45) {
435  (*dgnssa) = n2k_get_double(n, 43, 16) * 0.01;
436  success &= isfinite((*dgnssa));
437  }
438  return success;
439 }
440 
448 bool n2k_129033_values(const n2k_act_message *n, uint16_t *epochDays, double *seconds, int16_t *utcMins) {
449  if (!n || n->PGN != 129033 || !n->data || n->datalen < 8) { return false; }
450 
451  if (epochDays) { *epochDays = n2k_get_uint16(n, 0); }
452  if (seconds) { *seconds = 0.0001 * n2k_get_uint32(n, 2); }
453  if (utcMins) { *utcMins = n2k_get_int16(n, 6); }
454  if ((*utcMins >= 1440) || (*utcMins <= -1440)) {
455  *utcMins = 0;
456  return false;
457  }
458 
459  return true;
460 }
461 
470 bool n2k_130306_values(const n2k_act_message *n, uint8_t *seq, uint8_t *ref, double *speed, double *angle) {
471  if (!n || n->PGN != 130306 || !n->data || n->datalen < 8) { return false; }
472 
473  if (seq) { *seq = n2k_get_uint8(n, 0); }
474 
475  if (ref) { *ref = n2k_get_uint8(n, 5) & 0x07; }
476 
477  bool success = true;
478  if (speed) {
479  (*speed) = n2k_get_double(n, 1, 16) * 0.01;
480  success &= isfinite((*speed));
481  }
482 
483  if (angle) {
484  (*angle) = n2k_get_udouble(n, 3, 16) * N2K_TO_DEGREES;
485  success &= isfinite((*angle));
486  }
487  return success;
488 }
489 
501 bool n2k_130311_values(const n2k_act_message *n, uint8_t *seq, uint8_t *tid, uint8_t *hid, double *temp, double *humid,
502  double *press) {
503  if (!n || n->PGN != 130311 || !n->data || n->datalen < 8) { return false; }
504 
505  if (seq) { (*seq) = n2k_get_uint8(n, 0); }
506 
507  bool success = true;
508  uint8_t ids = n2k_get_uint8(n, 1);
509  if (tid) { (*tid) = ids & 0x3F; }
510  if (hid) { (*hid) = (ids & 0xC0) >> 6; }
511  if (temp) {
512  (*temp) = n2k_get_udouble(n, 2, 16) * 0.01 - 273.15;
513  success &= isfinite((*temp));
514  }
515  if (humid) {
516  (*humid) = n2k_get_double(n, 4, 16) * 0.004;
517  success &= (isfinite((*humid)) || ((*hid) == 3));
518  }
519  if (press) {
520  (*press) = n2k_get_udouble(n, 6, 16);
521  success &= isfinite((*press));
522  }
523 
524  return success;
525 }
526 
528  if (!n) { return; }
529  uint32_t id = 0; // Really 21 bits
530  uint16_t mfr = 0; // Really 11 bits
531  uint8_t instance = 0;
532  uint8_t function = 0;
533  uint8_t class = 0;
534  uint8_t system = 0;
535  uint8_t industry = 0;
536  bool configurable = false;
537 
538  fprintf(stdout, "%.3f\t", (float)(n->timestamp / 1000.0));
539  if (!n2k_60928_values(n, &id, &mfr, &instance, &function, &class, &system, &industry, &configurable)) {
540  fprintf(stdout, "[!] ");
541  }
542  fprintf(stdout, "Address claim - ID: %08u, Manufacturer: %05u\n", id, mfr);
543 }
544 
549 void n2k_header_print(const n2k_act_message *n, const char d) {
550  char delim = '\n';
551  if (d) { delim = d; }
552  fprintf(stdout, "%.3f\t", (float)(n->timestamp / 1000.0));
553  if (n->dst == 255) {
554  fprintf(stdout, "PGN %06d broadcast from %03d%c", n->PGN, n->src, delim);
555  } else {
556  fprintf(stdout, "PGN %06d sent from %03d to %03d%c", n->PGN, n->src, n->dst, delim);
557  }
558 }
559 
564  if (!n) { return; }
565  n2k_header_print(n, '\t');
566  fprintf(stdout, "-- Not parsed --\n");
567 }
568 
573  if (!n) { return; }
574 
575  uint8_t seq = 0;
576  double hdg = 0;
577  double dev = 0;
578  double var = 0;
579  uint8_t ref = 0;
580 
581  n2k_header_print(n, '\t');
582  if (!n2k_127250_values(n, &seq, &hdg, &dev, &var, &ref)) { fprintf(stdout, "[!] "); }
583 
584  char *magStr = NULL;
585  switch (ref) {
586  case 0:
587  magStr = "True";
588  break;
589  case 1:
590  magStr = "Magnetic";
591  break;
592  default:
593  magStr = "Unknown Reference";
594  break;
595  }
596 
597  fprintf(stdout, "Heading: %.3lf [%s], Deviation: %+.3lf, Variation: %+.3lf. Seq. ID %03d\n", hdg, magStr, dev,
598  var, seq);
599 }
600 
605  if (!n) { return; }
606 
607  uint8_t seq = 0;
608  double rot = 0;
609 
610  n2k_header_print(n, '\t');
611  if (!n2k_127251_values(n, &seq, &rot)) { fprintf(stdout, "[!] "); }
612  fprintf(stdout, "Rate of turn: %+.3lf. Seq. ID %03d\n", rot, seq);
613 }
614 
619  if (!n) { return; }
620 
621  uint8_t seq = 0;
622  double yaw = 0;
623  double pitch = 0;
624  double roll = 0;
625 
626  n2k_header_print(n, '\t');
627  if (!n2k_127257_values(n, &seq, &yaw, &pitch, &roll)) { fprintf(stdout, "[!] "); }
628 
629  fprintf(stdout, "Pitch: %.3lf, Roll: %.3lf, Yaw: %.3lf. Seq. ID: %03d\n", pitch, roll, yaw, seq);
630 }
631 
636  if (!n) { return; }
637 
638  uint8_t seq = 0;
639  double depth = 0;
640  double offset = 0;
641  double range = 0;
642 
643  n2k_header_print(n, '\t');
644  if (!n2k_128267_values(n, &seq, &depth, &offset, &range)) { fprintf(stdout, "[!] "); }
645 
646  fprintf(stdout, "Water Depth: %.2lfm (Offset: %.2lf, Range: %.0lf) Seq. ID %03d\n", depth, offset, range, seq);
647 }
648 
653  if (!n) { return; }
654 
655  double lat = 0;
656  double lon = 0;
657 
658  n2k_header_print(n, '\t');
659  if (!n2k_129025_values(n, &lat, &lon)) { fprintf(stdout, "[!] "); }
660 
661  fprintf(stdout, "GPS Position: %lf, %lf\n", lat, lon);
662 }
663 
668  if (!n) { return; }
669 
670  uint8_t seq = 0;
671  uint8_t magnetic = 0;
672  double course = 0;
673  double speed = 0;
674 
675  n2k_header_print(n, '\t');
676  if (!n2k_129026_values(n, &seq, &magnetic, &course, &speed)) { fprintf(stdout, "[!] "); }
677 
678  char *magStr = NULL;
679  switch (magnetic) {
680  case 0:
681  magStr = "True";
682  break;
683  case 1:
684  magStr = "Magnetic";
685  break;
686  default:
687  magStr = "Unknown Reference";
688  break;
689  }
690 
691  fprintf(stdout, "Speed: %.2lf @ %.3lf degrees [%s]. Seq. ID %03d\n", speed, course, magStr, seq);
692 }
693 
698  if (!n) { return; }
699 
700  uint8_t seq = 0;
701  uint16_t days = 0;
702  double secs = 0;
703 
704  double lat = NAN;
705  double lon = NAN;
706  double alt = NAN;
707 
708  uint8_t type = 0;
709  uint8_t method = 0;
710  uint8_t integrity = 0;
711 
712  uint8_t numSV = 0;
713 
714  double hdop = NAN;
715  double pdop = NAN;
716 
717  double geos = NAN;
718  uint8_t rs = 0;
719  uint8_t rsType = 0;
720  uint16_t rsID = 0;
721 
722  double dgnssa = NAN;
723 
724  n2k_header_print(n, '\t');
725  if (!n2k_129029_values(n, &seq, &days, &secs, &lat, &lon, &alt, &type, &method, &integrity, &numSV, &hdop,
726  &pdop, &geos, &rs, &rsType, &rsID, &dgnssa)) {
727  fprintf(stdout, "[!] ");
728  }
729  fprintf(stdout,
730  "Position: (%+.10lf,%+.10lf), Altitude: %.4lf m. %d SVs in use. HDOP %+.2lf, PDOP %+.2lf, Geoid Sep. %+.2lf m\n",
731  lat, lon, alt, numSV, hdop, pdop, geos);
732 }
733 
738  if (!n) { return; }
739 
740  uint16_t days = 0;
741  double secs = 0;
742  int16_t utcOff = 0;
743 
744  n2k_header_print(n, '\t');
745  if (!n2k_129033_values(n, &days, &secs, &utcOff)) { fprintf(stdout, "[!] "); }
746 
747  long timetemp = (long)(86400 * days + secs);
748  struct tm dt = {0};
749  gmtime_r(&timetemp, &dt);
750 
751  char timeS[30] = {0};
752  strftime(timeS, sizeof(timeS), "%F %T", &dt);
753  fprintf(stdout, "%s %+02.2f\n", timeS, utcOff / 60.0);
754 }
755 
760  if (!n) { return; }
761 
762  uint8_t seq = 0;
763  double speed = 0;
764  double angle = 0;
765  uint8_t ref = 0;
766 
767  n2k_header_print(n, '\t');
768  if (!n2k_130306_values(n, &seq, &ref, &speed, &angle)) { fprintf(stdout, "[!] "); }
769 
770  char *refStr = NULL;
771  switch (ref) {
772  case 0:
773  refStr = "Relative to North";
774  break;
775  case 1:
776  refStr = "Magnetic";
777  break;
778  case 2:
779  refStr = "Apparent";
780  break;
781  case 3:
782  refStr = "Relative to boat";
783  break;
784  default:
785  refStr = "Unknown reference";
786  break;
787  }
788 
789  fprintf(stdout, "Wind Speed: %.2lf @ %.3lf degrees [%s]. Seq. ID %03d\n", speed, angle, refStr, seq);
790 }
791 
796  if (!n) { return; }
797 
798  uint8_t seq = 0;
799  uint8_t tid = 0;
800  uint8_t hid = 0;
801  double t = 0;
802  double h = 0;
803  double p = 0;
804 
805  n2k_header_print(n, '\t');
806  if (!n2k_130311_values(n, &seq, &tid, &hid, &t, &h, &p)) { fprintf(stdout, "[!] "); }
807 
808  char *tSrc = NULL;
809  switch (tid) {
810  case 0:
811  tSrc = "Sea Water";
812  break;
813  case 1:
814  tSrc = "External";
815  break;
816  case 2:
817  tSrc = "Internal";
818  break;
819  case 3:
820  tSrc = "Engine Room";
821  break;
822  case 4:
823  tSrc = "Cabin";
824  break;
825  default:
826  tSrc = "Unknown";
827  break;
828  }
829 
830  char *hSrc = NULL;
831  switch (hid) {
832  case 0:
833  hSrc = "Internal";
834  break;
835  case 1:
836  hSrc = "External";
837  break;
838  case 3:
839  hSrc = "Unavailable";
840  break;
841  default:
842  hSrc = "Unknown";
843  break;
844  }
845 
846  fprintf(stdout, "Environmental data: %+.2lfC (%s), %+.3lf%% RH (%s), %.0lf mbar. Seq ID %03d\n", t, tSrc, h,
847  hSrc, p, seq);
848 }
bool n2k_127251_values(const n2k_act_message *n, uint8_t *seq, double *rate)
Extract values from PGN 127251: Rate of Turn.
Definition: N2KMessages.c:243
void n2k_basic_print(const n2k_act_message *n)
Print basic PGN details to standard output.
Definition: N2KMessages.c:563
void n2k_128267_print(const n2k_act_message *n)
Print PGN 128267 (Water depth) to standard output.
Definition: N2KMessages.c:635
void n2k_129029_print(const n2k_act_message *n)
Print PGN 129029 (GNSS Position) to standard output.
Definition: N2KMessages.c:697
void n2k_130311_print(const n2k_act_message *n)
Print PGN 130311 (Environmental data) to standard output.
Definition: N2KMessages.c:795
void n2k_129026_print(const n2k_act_message *n)
Print PGN 129026 (Course and Speed) to standard output.
Definition: N2KMessages.c:667
void n2k_129025_print(const n2k_act_message *n)
Print PGN 129025 (Device position) to standard output.
Definition: N2KMessages.c:652
void n2k_130306_print(const n2k_act_message *n)
Print PGN 130306 (Wind speed and direction) to standard output.
Definition: N2KMessages.c:759
bool n2k_130311_values(const n2k_act_message *n, uint8_t *seq, uint8_t *tid, uint8_t *hid, double *temp, double *humid, double *press)
Extract values from PGN 130311: Environmental data.
Definition: N2KMessages.c:501
void n2k_60928_print(const n2k_act_message *n)
Print PGN 60928 (Address claim) to standard output.
Definition: N2KMessages.c:527
bool n2k_129025_values(const n2k_act_message *n, double *lat, double *lon)
Extract values from PGN 129025: Device position.
Definition: N2KMessages.c:320
bool n2k_130306_values(const n2k_act_message *n, uint8_t *seq, uint8_t *ref, double *speed, double *angle)
Extract values from PGN 130306: Wind speed and direction.
Definition: N2KMessages.c:470
void n2k_127250_print(const n2k_act_message *n)
Print PGN 127250 (Vessel Heading) to standard output.
Definition: N2KMessages.c:572
void n2k_header_print(const n2k_act_message *n, const char d)
Print common message elements.
Definition: N2KMessages.c:549
bool n2k_129029_values(const n2k_act_message *n, uint8_t *seq, uint16_t *epochDays, double *seconds, double *lat, double *lon, double *alt, uint8_t *type, uint8_t *method, uint8_t *integ, uint8_t *nsv, double *hdop, double *pdop, double *geos, uint8_t *rs, uint8_t *rst, uint16_t *rsid, double *dgnssa)
Extract values from PGN 129029: GNSS Position.
Definition: N2KMessages.c:380
void n2k_127251_print(const n2k_act_message *n)
Print PGN 127251 (Rate of Turn) to standard output.
Definition: N2KMessages.c:604
bool n2k_127250_values(const n2k_act_message *n, uint8_t *seq, double *hdg, double *dev, double *var, uint8_t *ref)
Extract values from PGN 127250: Vessel Heading.
Definition: N2KMessages.c:212
bool n2k_127257_values(const n2k_act_message *n, uint8_t *seq, double *yaw, double *pitch, double *roll)
Extract values from PGN 127257: Device orientation.
Definition: N2KMessages.c:264
bool n2k_129033_values(const n2k_act_message *n, uint16_t *epochDays, double *seconds, int16_t *utcMins)
Extract values from PGN 129033: Date/Time.
Definition: N2KMessages.c:448
bool n2k_128267_values(const n2k_act_message *n, uint8_t *seq, double *depth, double *offset, double *range)
Extract values from PGN 128267: Water depth.
Definition: N2KMessages.c:291
void n2k_127257_print(const n2k_act_message *n)
Print PGN 127257 (Device orientation) to standard output.
Definition: N2KMessages.c:618
bool n2k_129026_values(const n2k_act_message *n, uint8_t *seq, uint8_t *mag, double *course, double *speed)
Extract values from PGN 129026: Course and speed.
Definition: N2KMessages.c:342
bool n2k_60928_values(const n2k_act_message *n, uint32_t *id, uint16_t *mfr, uint8_t *inst, uint8_t *fn, uint8_t *class, uint8_t *sys, uint8_t *ind, bool *cfg)
Extract values from PGN 60928: ISO Adddress Claim.
Definition: N2KMessages.c:187
void n2k_129033_print(const n2k_act_message *n)
Print PGN 129033 (Date and Time) to standard output.
Definition: N2KMessages.c:737
#define N2K_TO_DEGREES
Convert raw angular value to degrees.
Definition: N2KMessages.h:41
uint16_t n2k_get_uint16(const n2k_act_message *n, size_t offset)
Extract unsigned 16-bit integer from N2K Message.
Definition: N2KMessages.c:67
int16_t n2k_get_int16(const n2k_act_message *n, size_t offset)
Extract signed 16-bit integer from N2K Message.
Definition: N2KMessages.c:55
double n2k_get_double(const n2k_act_message *n, size_t offset, uint8_t size)
Extract double from underlying integer data.
Definition: N2KMessages.c:125
double n2k_get_udouble(const n2k_act_message *n, size_t offset, uint8_t size)
Extract double from underlying unsigned integer data.
Definition: N2KMessages.c:153
int8_t n2k_get_int8(const n2k_act_message *n, size_t offset)
Extract signed byte from N2K Message.
Definition: N2KMessages.c:43
uint32_t n2k_get_uint32(const n2k_act_message *n, size_t offset)
Extract unsigned 32-bit integer from N2K Message.
Definition: N2KMessages.c:88
uint64_t n2k_get_uint64(const n2k_act_message *n, size_t offset)
Extract unsigned 64-bit integer from N2K Message.
Definition: N2KMessages.c:111
int64_t n2k_get_int64(const n2k_act_message *n, size_t offset)
Extract signed 64-bit integer from N2K Message.
Definition: N2KMessages.c:99
int32_t n2k_get_int32(const n2k_act_message *n, size_t offset)
Extract signed 32-bit integer from N2K Message.
Definition: N2KMessages.c:76
uint8_t n2k_get_uint8(const n2k_act_message *n, size_t offset)
Extract unsigned byte from N2K Message.
Definition: N2KMessages.c:34
uint32_t PGN
24 bit PGN identifier
Definition: N2KTypes.h:84
uint8_t * data
Message payload.
Definition: N2KTypes.h:89
uint8_t datalen
Length of *data.
Definition: N2KTypes.h:88
uint8_t dst
Message destination.
Definition: N2KTypes.h:85
uint32_t timestamp
Message timestamp.
Definition: N2KTypes.h:87
uint8_t src
Message source.
Definition: N2KTypes.h:86