minmea2k is a minimalistic parser library written in C for decoding NMEA 2000 (CAN-based) PGNs. It is designed for embedded systems and resource-constrained environments, such as microcontrollers.
- No dynamic memory allocation.
- Designed for low memory usage and portability.
- Lightweight and simple to integrate (single source and header file).
- Fast packet support included.
- Easy to extend with new PGN decoders.
- Suitable for real-time CAN applications on boats, vehicles, and embedded devices.
Currently supported NMEA 2000 PGNs:
| PGN (Decimal) | PGN (Hex) | Description |
|---|---|---|
| 60928 | 0x00EE00 |
ISO Address Claim |
| 127488 | 0x01F200 |
Engine Parameters, Rapid Update |
| 127489 | 0x01F201 |
Engine Parameters, Dynamic |
| 127493 | 0x01F205 |
Transmission Parameters, Dynamic |
| 129026 | 0x1F802 |
COG & SOG, Rapid Update |
| 129025 | 0x1F801 |
Position, Rapid Update |
| 129028 | 0x1F804 |
GNSS Delta Altitude |
| 127250 | 0x1F112 |
Vessel Heading |
| 127251 | 0x1F113 |
Rate of Turn |
| 127257 | 0x1F119 |
Attitude |
| 127505 | 0x1F211 |
Fluid Level |
More PGNs will be added in future. You can contribute by adding them via pull requests.
Here's a minimal example of how to use minmea2k in a typical Linux environment with a CAN interface. It opens a socket on can0, reads messages in a loop, and prints decoded fluid level data.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "minmea2k.h"
int main(void) {
const char *iface = "can0";
int s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s < 0) {
perror("socket");
return 1;
}
struct ifreq ifr;
strcpy(ifr.ifr_name, iface);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror("ioctl");
return 1;
}
struct sockaddr_can addr = {
.can_family = AF_CAN,
.can_ifindex = ifr.ifr_ifindex,
};
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
struct can_frame frame;
while (1) {
ssize_t nbytes = read(s, &frame, sizeof(frame));
if (nbytes <= 0) continue;
uint8_t src, dest, pri;
uint32_t pgn = minmea2k_can_id_to_pgn(frame.can_id, &src, &dest, &pri);
if (dest != 0xFF) continue;
switch (pgn) {
case PGN_ID_FLUID_LEVEL: {
t_minmea2k_fluid_level fluid_level;
if (minmea2k_unpack_fluid_level(&fluid_level, frame.data, frame.can_dlc) == 0) {
printf("%d,%d,%.2f,%.1f\n",
fluid_level.instance,
fluid_level.type,
fluid_level.level,
fluid_level.capacity
);
}
break;
}
}
}
close(s);
return 0;
}You can adapt the switch statement to decode other PGNs using the corresponding minmea2k_unpack_* functions.
Simply add minmea2k.[ch] to your project and #include "minmea2k.h" in your source. No external dependencies required.
- Open an issue or submit a pull request via GitHub.
minmea2k is open source software. See the COPYING file for details. If licensing is an issue, contact the author for alternatives.
minmea2k is maintained by Riccardo Accomando riccardoaccoma@gmail.com Based on concepts from the original minmea library by Kosma Moczek and Patryk Szymczak.