Skip to content
canboatPublic

About

CAN Boat provides NMEA 2000 and NMEA 0183 utilities. It contains a NMEA 2000 PGN decoder and can read and write N2K messages. It is not meant as an end-user tool but as a discovery mechanism for delving into NMEA 2000 networks.

Topics

Resources

Contributing

Stars

660 stars

Watchers

60 watching

Forks

Latest commit

 

History

1,940 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CANBOAT

A small but effective set of command-line utilities to work with CAN networks on BOATs. The most common version of CAN networks on board, and in fact at the moment the only ones that this suite can analyse, is NMEA 2000.

The NMEA 2000 database and implementation is copyrighted by the NMEA (National Marine Electronics Association). Access is restricted to members and parties that pay for it. If they do so they are not able to divulge the content of the database, thus making it impossible for open source developers to get access to it.

For this reason we have reverse engineered the NMEA 2000 database by network observation and assembling data from public sources.

Quick reference

If you just want to know how the NMEA 2000 protocol works, with an explanation of all reverse engineered data, please go to the documentation page.

To use the programs included in this project you may need a supported CAN interface. This can be a marketed-as-such NMEA 2000 Gateway or a non NMEA specific CAN interface.

For more information go to the CANBoat Wiki.

The programs

CANboat ships two implementations. Both are tier 1 — supported, tested and released together — and they are interchangeable for the jobs they both do.

C tools. analyzer and the *-serial gateway drivers are the originals and stay tier 1. They are small, dependency-light and build with nothing but make and a C compiler.

analyzer decode NMEA 2000 into text or JSON
actisense-serial Actisense NGT-1 / W2K-1 gateways
ikonvert-serial Digital Yacht iKonvert
socketcan-serial Linux SocketCAN
maretron-ipg Maretron IPG100
candump2analyzer, replay, iptee, nmea0183-serial, analyzer-j1939 converters and helpers

canboat, the Rust binary. One executable with subcommands. convert and the gateway support are tier 1 alongside their C counterparts; everything with no C equivalent is tier 1 as the only implementation.

canboat convert decode a capture between any supported formats
canboat interface bridge a live gateway (NGT-1 / iKonvert / Maretron / SocketCAN)
canboat n2kd multiplex an analyzer-JSON stream to TCP clients
canboat server the whole device → analyzer → n2kd pipeline in one process
canboat tui interactive terminal browser for a live stream or a capture
canboat format-message build a single frame from field values, for any PGN
canboat replay pace a capture at its original wall-clock rhythm

canboat install-shims drops symlinks so the subcommands answer to the old names (analyzer, n2kd, actisense-serial, …). It never takes a name that another program already holds, so it is safe to run in a directory that has the C tools installed — it reports what it left alone.

The remaining C converters, the helper scripts in util/ (PHP, perl and ksh) and the Python tooling will most likely move to Rust in time; the C n2kd and n2kd_monitor already have, and were removed in v8.

Device quirks

Some devices misbehave in ways CANboat can cover for. Each workaround is a named quirk, and every one of them is off by default — they all rewrite or invent data, so you switch on the ones you need:

Quirk What it does Where
gps-rollover Corrects GNSS dates from a receiver that never learned about the GPS 1024-week rollover and reports one or two epochs in the past (PGN 129029, 129033, and 126992 when its source is GPS) analyzer -quirk gps-rollover, canboat convert --quirk gps-rollover, canboat server --quirk gps-rollover
gps-rollover=<device>,… The same, plus every date the listed devices stamp from that clock — a DSC radio's Date of Receipt on PGN 129808, a converter's System Time, and so on. A device is a source address (4), its manufacturer code and unique number (1851:491603), or its ISO NAME in hex (0x…); all means every device on the bus same three commands
gps-relay Re-sends the data PGNs the devices listed in gps-rollover=… broadcast (not their network management, and not anything addressed), from canboat's own address with the dates corrected, so other devices on the bus can select canboat as their GPS and time source instead of the rolled-over one. The original keeps transmitting; you pick the source in each display. Needs a real device list — gps-rollover=all is refused here canboat server --quirk gps-rollover=<device> --quirk gps-relay (needs a writable backend)
scx20 Answers a PGN 59904 request for a Furuno SCX-20's Product Information on its behalf, so the Furuno Setting Tool can find it canboat server --quirk scx20 (needs --socketcan)
wmm Computes magnetic variation locally with WMM 2025 and emits its own PGN 127258, asking older-WMM sources to stop canboat server --quirk wmm
motion Impersonates a B&G H5000 Motion Sensor so a Navico Hercules accepts an SCX-20 canboat server --quirk motion (needs --socketcan)

gps-rollover is the odd one out: it corrects a decoded value rather than putting a frame on the bus, which is why it is available when decoding a capture file too. Do not use it on a capture made before April 2019 — it cannot tell a rolled-over date from a genuinely old one, and will move the whole log forward twenty years.

Without a device list it only touches the dates a GNSS receiver produced, because those are the only ones whose origin the PGN itself tells us. Any other device that takes its clock from the bus repeats the wrong date, and nothing in its PGNs says so; that is what the device list is for. Naming a device by manufacturer and unique number, or by NAME, needs its PGN 60928 Address Claim to have gone by — canboat server asks for those at startup, a capture has to contain one. The AIS reports (129793, 129794) relay another station's clock and 127258 carries the variation model's date, so those are never corrected.

None of that helps a display that reads the broken GPS directly. gps-relay is the nearest thing to a fix short of replacing the receiver: canboat server re-sends every broadcast PGN from the listed devices — position, COG/SOG, satellites, not just the dated ones, or no display would accept it as a GPS — from its own address, byte for byte except for the corrected dates. The other devices then see a second GPS source, canboat, and you select it in each of them. That needs devices with real source selection, which not every brand gets right, and it leaves the old receiver on the bus, since it is where the data comes from.

The library

The decoder is also a Rust crate, canboat, so you can embed NMEA 2000 handling instead of parsing another program's output. One crate, a small public API, and features that gate the weight you pay for:

feature
decode sans-I/O: PGN database, parsers, reassembly, decode, encode, output formatters. No threads, no sockets. The database is compiled in — nothing to load at runtime
io readers for captures and bus::open_* for a live NGT-1 / iKonvert / SocketCAN link
node be a compliant NMEA 2000 node: ISO NAME, address claim, the standard responses
bridge the whole canboat server pipeline as a library: device → decode → quirks → TCP serving
cli the canboat binary itself (the default; library users turn it off)

The crate's own README has the quick start and is what crates.io shows; the API reference is on docs.rs and its design in crates/doc/library-api-plan.md.

Performance

Same decode work — -json -nv over 1.26 M PGN frames (canboat's dirona-actisense-serial.raw × 50) on an M4 Pro, release build:

Implementation Wall time vs canboat
canboatjs (Node 25) 27.8 s 8.1 ×
canboat C 9.1 s 2.6 ×
canboat convert 3.4 s 1.0 ×

canboat server goes one step further and collapses the canboat convert | canboat n2kd pipeline into a single process with no JSON text serialisation between stages:

Pipeline Wall time Throughput
canboat convert alone (PGN decode only) 3.3 s 380 k frames / s
canboat convert | canboat n2kd (piped, 2 proc) 6.5 s 194 k sentences / s
canboat server (single proc) 3.5 s 360 k sentences / s

That's 46 % less wall time than the piped setup while doing strictly more work (it's a long-running service with TCP fan-out); on CPU time the ratio is closer to 3.4 ×.

A capture as a live bus (--replay)

canboat server --replay <capture> plays a capture as if it were a gateway, so you can test a consumer such as Signal K without a boat. It reads any format canboat reads, keeps the capture's pacing but stamps every frame with the current time, and starts over at the end. The TCP ports are the same as for a real gateway, the input port included: frames written to it go to --replay-sent <file> as PLAIN/FAST lines, or are dropped, and are not echoed back.

canboat server --replay samples/dirona-actisense-serial.raw --replay-sent sent.raw

Transmit and receive PGN lists (--tx-pgn, --rx-pgn)

Other devices ask a node which PGNs it sends and reads (PGN 126464). canboat server --tx-pgn <pgn>[,…] --rx-pgn <pgn>[,…] (or BridgeConfig::pgn_lists in the library) names the PGNs your application sends and reads, so the gateway can answer truthfully. What happens with them depends on the gateway:

Gateway Transmit list Receive list
SocketCAN Advertised by canboat itself. Nothing is filtered. Advertised
iKonvert Written into the gateway, which only transmits what is on it Written into the gateway; filters only in --ikonvert-rx (NORMAL) mode
NGT-1 Missing PGNs enabled in the gateway's Transmit PGN Enable list (EEPROM, only when something is missing); it only transmits what is on it Not supported
Others Ignored, with a warning Ignored, with a warning

Warning

ON AN iKONVERT OR NGT-1, THE TRANSMIT LIST IS FINAL

Once you name any transmit PGN (--tx-pgn, --ikonvert-tx, or pgn_lists.tx), canboat REFUSES TO SEND EVERY PGN THAT IS NOT ON THE LIST. The gateway only transmits the PGNs in its list, and canboat sets that list once, when it starts, so canboat drops the rest up front, logging each refused PGN once, instead of handing the gateway frames it will reject.

Decide the complete list before you start. Only the ISO/NMEA network-management PGNs, and the PGNs of the quirks you enabled (such as wmm's 127258), are allowed without being named. With no transmit PGN named, nothing is refused and the gateway's own list decides.

File formats

analyzer reads NMEA 2000 data from a number of text formats on stdin and turns each message into human readable text or JSON. Some formats it understands directly; capture formats from specific gateways or CAN tools are first turned into the analyzer's PLAIN format by a small helper program that you pipe into analyzer:

  • Directly by analyzer — text logs that already contain decoded CAN identifiers. The format is auto-detected, or can be forced with -format <NAME>.
  • Via actisense-serial — Actisense NGT-1 binary streams and log files. actisense-serial -r <file> | analyzer
  • Via candump2analyzer — Linux can-utils dumps and other raw CAN captures. candump2analyzer <file> | analyzer

The full list of understood formats:

Format Origin Example line How to read
PLAIN canboat native, one CAN frame per line 2016-02-28T19:57:41.000Z,3,126208,40,72,8,01,0d,f2,01,f8,01,03,01 analyzer (auto, or -format PLAIN)
FAST canboat native, a whole fast-packet message per line 2021-01-18T01:23:06.960Z,6,129540,26,255,216,ec,ff,… analyzer (auto, or -format FAST)
AIRMAR Airmar weather/depth devices 0123 -8 09F80 … analyzer (auto)
CHETCO Chetco devices $PCDIN,01F119,00000000,0F,FFFFFFFFFFFFFFFF*21 analyzer (auto)
GARMIN_CSV1 / GARMIN_CSV2 Garmin CSV export 0,486942,127508,Battery Status,Garmin,6,255,2,1,8,0x017505FF7FFFFFFF analyzer (auto)
YDWG02 Yacht Devices RAW (YDWG-02 / YDNU-02) 19:07:21.014 R 09F8017F 50 C3 … analyzer (auto)
ACTISENSE_N2K_ASCII Actisense N2K ASCII A173321.107 23FF7 1F513 012F… analyzer (auto)
Actisense NGT-1 binary Actisense NGT-1 USB / serial / TCP gateway (binary) actisense-serial -r <dev> | analyzer
Actisense EBL Actisense .ebl log files (binary) actisense-serial -r <file.ebl> | analyzer
Actisense W2K-1 W2K-1 gateway capture {"pgn":60928,"payload":[147,19,6,0,238,…]} actisense-serial -r <file> | analyzer
candump (Angstrom) Linux can-utils <0x18eeff01> [8] 05 a0 be 1c 00 a0 a0 c0 candump2analyzer <file> | analyzer
candump (Debian) Linux can-utils can0 09F8027F [8] 00 FC FF FF 00 00 FF FF candump2analyzer <file> | analyzer
candump log Linux can-utils (candump -l) (1502979132.106111) slcan0 09F50374#000A00FFFF00FFFF candump2analyzer <file> | analyzer
tshark / pcap Wireshark text export of a CAN pcap … CAN 16 XTD: 0x09fd0223 00 49 02 1c a7 fa ff ff candump2analyzer <file> | analyzer
Navico (TCP port 8086) Navico raw dump 0021200 0e 1d ff 9d 08 00 00 00 80 df 3f 9f 34 12 ff 0d candump2analyzer <file> | analyzer
PCAN-View PEAK PCAN-View v1.1 trace 1) 2.7 Rx 09F11324 8 53 84 9E 01 00 FF FF FF candump2analyzer <file> | analyzer

pcap2candump can additionally turn a raw .pcap capture into the candump log format for candump2analyzer. Example captures for many of these formats live in the samples/ directory.

Building, Development and Testing

make builds the C tools into rel/<platform>/; make rust builds canboat and keel into target/release/. Neither needs the other — you can build just the side you care about.

Use make rust rather than a bare cargo build if you have edited database/: the Rust PGN tables are generated by keel and committed, so cargo alone will compile against the previous ones.

Full instructions are in BUILDING.md, and the Wiki covers per-platform detail and how to start extending the PGN database.

Adding or fixing a PGN

PGN definitions live as YAML under database/ (one file per PGN variant in pgns/, one per enumeration in lookups/). The easiest way to add a new message or correct an existing one is the built-in, evidence-first editor:

./keel/keel edit

Paste one or more real captures, and the local web editor stacks the bytes, decodes them live as you define fields, suggests an existing definition to clone when your frame nearly matches one, and lets you save your captures as regression tests — all rule-checked before it will write. See AGENTS.md §9 for the full workflow (editor and by-hand) and CONTRIBUTING.md for the evidence and commit rules.

Contributing

Pull requests are welcome! See CONTRIBUTING.md for how to write your PR title (it becomes the release changelog entry), the source/generated lockstep rule, and what evidence a database change needs.

Using the definitions in your own project

If you just want to use the definitions in XML or JSON format, use the versions in the docs directory, e.g. (./docs/canboat.xml) or (./docs/canboat.json). We recommend that you pin your retrieval to a particular release. Semantic versioning is used to warn you of major (x.0.0) or minor (0.x.0) changes to the definitions.

Version history

See Changelog.

Related Projects

Sibling projects (same authors)

  • canboatjs — pure JavaScript NMEA 2000 decoder and encoder

(The Rust library used to live separately as canboat-rs; it was merged into this repository in v8 and is the canboat-* crates described above.)

Other projects using the CANboat PGN definitions

Snapshot of early October 2026. The CANboat version each project uses and when it was last updated were taken from GitHub on 7 October 2026 and will drift. The current CANboat release is v8.3.0. The survey behind this table, with more projects, is in research/downstream-survey-2026-10.md. Maintain one of these, or another project built on CANboat? Open an issue to correct your entry or to be notified of new major and minor releases.

Project What it is Uses CANboat as CANboat version Project last updated
AvNav Chart plotter NMEA 2000 data from the n2kd server binaries 2026-10
boatkit n2k Go NMEA 2000 library Go types generated from canboat.json at a pinned release v8.1.0 2026-10
CanLab CAN, J1939 and NMEA 2000 analysis workbench (Python) PGN table built from canboat.json v8.2.1 2026-09
canboat_vendor ROS 2 package builds the CANboat tools 2026-08 (pre-v8.0.0-beta3) 2026-08
go-nmea-client Go NMEA 2000 library canboat.json loaded at runtime whichever file is supplied 2023-07
korri-n2k NMEA 2000 stack for embedded Rust code generated from canboat.json v7.1.0 2026-09
maritime-dissector Wireshark dissectors for maritime protocols NMEA 2000 dissector generated from canboat.json latest, at generation time 2026-03
n2k Erlang NMEA 2000 library vendored CANboat definitions v4.12.0 2026-04
nmea2000 Python NMEA 2000 decoder and encoder vendored canboat.json, synced weekly v8.1.0 2026-10
nmea2000 Home Assistant integration NMEA 2000 PGNs as Home Assistant devices and entities through nmea2000 v8.1.0 2026-10
NMEA2000-Analyzer Windows GUI canboat.json downloaded from master at runtime latest 2026-07
nmea2000-rs Rust NMEA 2000 decoder and encoder code generated from canboat.json at build time v6.1.3 2026-02
open-ships n2k Go NMEA 2000 library and bus node decoders generated from a vendored canboat.json v7.1.0 2026-09
pgntui Terminal UI for NMEA 2000 (Python) vendored canboat.json v6.2.0 2026-06
signalk-server-go Signal K server in Go decodes NMEA 2000 with a vendored canboat.xml v6.2.2 2026-09
Smart Boat Innovations integrations ha-smart2000usb and ha-smart2000esp: NMEA 2000 into Home Assistant over USB-CAN or an ESP32 decoders generated from canboat.json v5.0.3 2026-04

For non-technical sailors

CANboat and its sibling canboatjs are command-line tools. If you just want to use your NMEA 2000 network, these projects build on them and provide a friendlier experience:

Sponsorship

If you find CANboat useful, please consider supporting its development via GitHub Sponsors.


(C) 2009-2026, Kees Verruijt, Harlingen, The Netherlands.

This file is part of CANboat.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

About

CAN Boat provides NMEA 2000 and NMEA 0183 utilities. It contains a NMEA 2000 PGN decoder and can read and write N2K messages. It is not meant as an end-user tool but as a discovery mechanism for delving into NMEA 2000 networks.

Topics

Resources

Contributing

Stars

660 stars

Watchers

60 watching

Forks

Releases

Packages

Used by

Contributors

Languages