nmea2000 C++ Library

repository·master·Indexed 20 days ago

https://github.com/ttlappalainen/nmea2000

An object-oriented C++ library for developing NMEA2000 bus devices that automatically handles mandatory protocol requirements. Compatible with Arduino, Teensy, ESP, MBED, and Raspberry Pi, it supports the creation of sensor transducers, information displays, and protocol converters. The library utilizes hardware-specific inherited classes (such as tNMEA2000_mcp, tNMEA2000_esp32, and tNMEA2000_teensy) to interface with various CAN controllers.

Tokens
16.2K
Snippets
24
Records
56
Agent score
70%

What's inside nmea2000

  1. Overview of the NMEA2000 to NMEA0183 converter example

    master

    This example demonstrates how to read specific messages from an NMEA2000 bus and convert them into the NMEA0183 format. The converted data is output to NMEA0183_out, which can be configured as a Serial port on Arduino/Teensy or as /dev/ttyUSB0 (or similar) on a Raspberry Pi. Additionally, the example forwards all raw NMEA2000 bus messages in Actisense format.

    Common Use Cases:

    • Sending NMEA2000 data to OpenCPN on a Raspberry Pi using a PiCAN2 shield.
    • Providing NMEA0183 and NMEA2000 data to a PC via an Arduino or Teensy board.
  2. Overview of the NMEA2000 C++ library

    master

    The NMEA2000 library is an object-oriented C++ library designed for developing NMEA2000 bus devices. It automatically handles mandatory NMEA 2000 requirements, allowing developers to focus on specific data handling logic.

    Common use cases include creating:

    • Sensor transducers (e.g., battery, temperature, wind, engine)
    • NMEA2000 information displays
    • NMEA2000 to PC interfaces (similar to Actisense NGT1)
    • Protocol converters (NMEA0183 <-> NMEA2000)

    The library is compatible with various platforms including Arduino, Teensy, ESP, MBED, and Raspberry Pi. It can be used on other systems by implementing a compatible CAN driver and necessary hardware-specific classes.

  3. Understand NMEA2000 bus electrical characteristics

    master

    The NMEA2000 bus is electrically a CAN bus based on the SAE_J1939 protocol, specifically adapted for marine environments.

    Key Characteristics:

    • Fixed Speed: Unlike standard CAN which can be variable, NMEA2000 bus speed is fixed to 250kb.
    • Topology: It is a multi-device bus (similar to Ethernet) where all devices can communicate; there is no single bus master.
    • Cabling: Uses DeviceNet standard cabling. Standard color coding is:
      • + (Power): Red
      • - (GND): Black/Grey
      • CAN-H: White
      • CAN-L: Blue
      • Shield: Shield wire
  4. Select hardware transceiver and isolation strategy

    master

    NMEA2000 is based on CAN. Your hardware choice depends on whether your MCU has an internal CAN controller and your isolation requirements:

    Isolation Requirements

    • Isolated Transceivers: Required if you feed power to your device directly or use engine sensors for measuring. This avoids ground loops. Example: ISO1050.
    • Unisolated Transceivers: Can be used if you take power directly from the NMEA2000 bus and your device is not connected to ground anywhere else. Examples: MCP2551, MCP2562, or SN65HVD234.

    Hardware Examples

    • Teensy 4.0/4.1: Supports internal CAN. Available unisolated adapters exist.
    • ESP32: Supports internal CAN.
    • Arduino Due: Supports internal CAN.
    • Arduino Mega / ESP8266: Typically requires an external MCP2515 CAN controller via SPI.
    • Pi Pico: Can use the Adafruit CAN Cowbell Hat.

    Note on Crystal Frequency: Some CAN shields use an 8 MHz crystal instead of the default 16 MHz. This must be configured before including NMEA2000_CAN.h.

  5. How to use Sequence Identifiers (SID)

    master

    The Sequence Identifier (SID) is used to link different Parameter Group Numbers (PGNs) that were sampled or calculated at the same time. This allows receiving devices to synchronize data from multiple PGNs for more accurate calculations (e.g., linking GPS position, speed, and heading data).

    Implementation Guidelines

    • Range: Use values between 0 and 252.
    • Reserved Values: 253 and 254 are reserved. 255 (0xff) indicates that data is not available.
    • Sending: If you do not need synchronization, you can simply use 0xff for the SID.
    • Synchronization Logic: To use SID effectively, increment the value in synchronization with your sampling cycle. If you sample faster than you transmit, increment the SID only after all related messages for a specific sample have been sent.

    Thread Safety and Multitasking

    When using a multitasking system, you must lock your data during both the sampling and sending phases to prevent data from changing mid-task. This ensures the SID and the sensor values remain consistent across all related PGNs.

    // Incrementing SID logic
    SensorSID++; 
    if (SensorSID > 252) SensorSID = 0;
    
    // Example Sampling Task with Locking
    SampleSensors(Sensor1, Sensor2);
    LockSend();
    Sensor1Out = Sensor1;
    Sensor2Out = Sensor2;
    SensorsSID++; 
    if (SensorsSID > 252) SensorsSID = 0;
    ReleaseSend();
    
    // Example Sending Task with Locking
    LockSend();
    double S1 = Sensor1Out;
    double S2 = Sensor2Out;
    SID = SensorsSID;
    ReleaseSend();
    SendSensorsData(SID, S1, S2);
  6. Handle NMEA2000 messages with tNMEA2000::tMsgHandler

    master

    To process incoming NMEA2000 messages, inherit from the abstract base class tNMEA2000::tMsgHandler.

    When ParseMessages() is called, all attached handlers that match the incoming message's PGN will be executed.

    • To handle a single PGN: Set the PGN of the handler instance to that specific PGN.
    • To handle all messages: Set the PGN of the base class to 0.

    You can attach or detach handlers from the tNMEA2000 object at runtime.

  7. How address claiming works in the library

    master

    NMEA2000 uses address claiming to assign a source address (0-251) to each device. The library automates the address claiming process, including the required silence delays and handling priority conflicts based on the device NAME.

    Because the library manages this automatically, a device's source address might change during operation if a conflict is resolved. To detect if your device's address has been changed by the library, call tNMEA2000::ReadResetAddressChanged().

    // Check if the source address was changed during address claiming
    if (tNMEA2000::ReadResetAddressChanged()) {
        // Handle address change
    }
  8. Understand the relation between CAN ID and NMEA2000

    master

    NMEA2000 uses the extended 29-bit CAN identifier format (based on SAE J1939). The 29-bit ID is structured as follows:

    BitsNameDescription
    28-26PriorityArbitration priority (0 is highest, 7 is lowest)
    25EDPExtended Data Page
    24DPData Page (J1939 set to Page 0, Page 1 for NMEA2000)
    23-16PDU FormatDefines the parameter group (PGN) type
    15-8PDU SpecificDestination device address
    7-0Source AddressSource device address
  9. Supported hardware and platforms

    master

    While originally developed for Arduino-based boards, the library is compatible with several platforms including:

    • Teensy
    • ESP
    • Various Arduino boards
    • MBED
    • Raspberry Pi

    To use the library on other systems, you must write a compatible CAN driver and the necessary classes for hardware-specific functions.

  10. Understand NMEA2000 instances

    master

    Instances are used to distinguish between multiple similar products on the same network (e.g., distinguishing between two different battery monitors). There are three main types of instances:

    1. Device instance: Part of the device information (stored in tNMEA2000::tDeviceInformation). It combines the Device Instance Lower (ISO ECU Instance) and Device Instance Upper (ISO Function Instance) and is sent in PGN 60928. It is often used for grouping and synchronizing devices (e.g., Victron chargers).
    2. Data instance: These are embedded within specific PGNs (e.g., Battery Instance, Switch bank instance) to identify specific data sets. They can be modified via PGN 126208 (Complex Request Group Function Code 5).
    3. System instance: Also part of tNMEA2000::tDeviceInformation and sent in PGN 60928 (field 8). It indicates device occurrence in redundant or parallel NMEA2000 networks. For most simple vessels, this is set to 0.
  11. Prerequisites for the NMEA2000 to NMEA0183 converter

    master

    To run this example, you must have the following libraries and environments installed:

    Required Libraries:

    • NMEA2000 library
    • NMEA0183 library
    • Relevant CAN bus libraries (specific to your hardware)

    Hardware/Platform Specifics:

    • Arduino/Teensy: Works with default settings.
    • Raspberry Pi (e.g., RPi3B with PiCAN2 shield): Requires the following additional setup:
      • Code Block environment
      • tty0tty (virtual null modem cable)
      • Socket CAN