/NMEA2000

NMEA2000 library for Arduino

Primary LanguageC++

NMEA2000 library for C++

Object oriented NMEA2000 library for Arduino, MBED and Rasberry type Boards. These board types has been tested, but library may work also in other systems.

Library gives you easy way to make different kind of NMEA2000 bus devices like NMEA2000→PC interface (like Actisense NGT1), NMEA0183→NMEA2000 converter, sensor (e.g. temperature, wind) node.

Library tries to fulfil NMEA 2000 mandatory functions and behaviour, so it looks a bit complex inside. With default settings it requires about 23 kB rom and 3.3kB RAM in normal operation. So I prefer to use at least Arduino Mega, Due or Teensy 3.2 boards. Arduino Uno board has too little memory for full functionality. See "Memory requirements" later.

To use Arduino Due board internal CAN you will also need NMEA2000_due library and due_can library, which you can download from https://github.com/ttlappalainen/due_can

To use Arduino boards with MCP2515 CAN bus controller, you will also need NMEA2000_mcp library and mcp_can library. Use mcp_can library found on https://github.com/ttlappalainen/CAN_BUS_Shield, which is developed version of mcp_can library. This allows also to use 8MHz clock and has been tested with Maple Mini. mcp_can library can be originally found on https://github.com/Seeed-Studio/CAN_BUS_Shield, but these improvements has not been implemented to Seeed-Studio.

To use a Teensy 3.1/3.2 or 3.5/3.6 board internal CAN with a MCP2562 or MCP2551 CAN-bus transeiver (or similar, see FlexCAN documentation), you will need the NMEA2000_teensy library contributed by (Thomas Sarlandie and the (FlexCAN library. FlexCan library is already included in Teensyduino extension. In order to use my fork, you have to remove FlexCAN library from C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\FlexCAN

To use avr processors internal CAN you need also NMEA2000_avr library and avr_can library, which you can download from https://github.com/thomasonw/avr_can

To use MBED boards you need also NMEA2000_mbed library and other related libraries. See origin for MBED port on https://github.com/thomasonw/NMEA2000_mbed

To use Rasberry boards you need also NMEA2000_socketCAN library and other related libraries. See origin for Rasberry port on https://github.com/thomasonw/NMEA2000_socketCAN

Thanks

I thank Kees Verruijt for his excellent CanBoat project and Dr Andrew Mason for OpenSkipper project. I originally started to learn NMEA 2000 via OpenSkipper project, which development I continued. PGN library on OpenSkipper and so on this library is mostly based on Kees work. Also it appeared that some code parts are probably originally from CanBoat even I have found them from other sources. Actisense message format handling I have learned from OpenSkipper project.

I also thank for anybody who has extended library with new PGNs or processor support.

Changes

31.08.2017

  • Support for changing configuration information fields InstallationDescription1 and InstallationDescription2 on runtime e.g. with NMEA Reader. Meaning of those fields is define their "installation description". So if you have two engine monitor devices, you can set e.g. InstallationDescription1 field to "Port engine" for one and "Starboard engine" for other. So it is not necessary to hardcode those setting. Of coarse your code must support parameter saving to e.g. EEPROM as with other parameters (see ReadResetInstallationDescriptionChanged, ReadResetAddressChanged and ReadResetDeviceInformationChanged). I have example under construction for handling parameter changes.

  • Changed some indexes to size_t. This may effect compatibility, if you have used those functions.

31.07.2017

29.07.2017

  • Fixed setting device instances on N2kGroupFunctionDefaultHandlers

  • Fixed wind PGN 130306 output with reserved field.

  • New abstract class tNEMA2000:tMsgHandler and functions AttachMsgHandler/DetachMsgHandler. With these you can have multiple handlers. It also allow PGN specific handlers. See how it has been used on example DeviceAnalyzer. Other simple example is under construction.

  • New class tN2kDeviceList. See more on library reference and on example DeviceAnalyzer.

  • Improved message type checking. This will be done for every message, so speed in important. For Arduino Mega average test time was dropped from about 90 us to 9 us and for Teensy from 3.5 us to 0.9 us.

26.06.2017 Example updates

  • ActisenseListenerSender can be used to listen and send data to NMEA 2000 bus. This is almost same as TeensyActisenseListenerSender, but read and forward ports can be chosen with #define.

  • ActisenseListener uses now SetN2kCANReceiveFrameBufSize.

  • Removed FromPCToN2k. ActisenseListenerSender replaces this.

25.06.2017 Fix and cosmetic changes

  • ForwardStream initialization was accidentaly deleted

  • Clean code and more debug options.

22.06.2017 Fixes and cosmetic changes

  • Crashed, if ForwardStream was not defined. I accidentaly forgot to comment some debug code.

  • Definition of tDeviceInformation changed to fixed sized data so that compiler can not mix them.

  • Added debug definitions to avoid first bug.

  • Some cosmetic changes and tests.

19.06.2017 Changes due to different revisions of FlexCAN library for Teeansy boards. NOTE! You must update NMEA2000_Teensy library. I also forked and developed FlexCAN library from collin80 and also send pull request for him. Until updated there my fork has more features for use with NMEA2000 library.

13.06.2017 NOTE! Some compatibility changes.

  • !NOTE compatibility change. tProductInformation has been moved inside tNMEA2000 class. If you have defined tProductInformation to PROGMEM as in example BatteryMonitor, you need to change definition const tProductInformation…​ to const tNMEA2000::tProductInformation…​ See example BatteryMonitor.

  • Multi device support should work now. So you can show several devices on bus with single hw. See example MultiDevice.

  • !NOTE compatibility change. tDeviceInformation has been moved inside tNMEA2000 class. This was used only internally until 11.06.2017 release.

11.06.2017 Added NMEA 2000 mandatory features. Some bug fixes.

  • !NOTE compatibility change. PROGMEM configuration information did not work and actually wasted RAM. You should define each configuration information string alone as PROGMEM and call changed SetProgmemConfigurationInformation. See sample BatteryMonitor

  • Due to new mandatory features library requires more RAM and program memory. It is possible to squeeze requirements with compiler options. See more info on NMEA2000_CompilerDefns.h.

  • Added new class tN2kGroupFunctionHandler (N2kGroupFunction.h/.cpp) for NMEA 2000 group function (PGN 126208) handling. Group function can be used to e.g. to set "temperature instance" or "set temperature" fields on PGN 130316.

  • Added automatic Heartbeat, which is mandatory for certified NMEA 2000 devices. If you do not want it to be sent, you have to set heartbeat interval to 0. Added also function SetHeartbeatInterval, GetHeartbeatInterval and SendHeartbeat.

  • Added group function handling for PGN 60928 (ISO Address) and PGN 126993 (Heartbeat). Handlers can be found on N2kGroupFunctionDefaultHandlers module.

  • Added functions ReadResetDeviceInformationChanged, SetDeviceInformationInstances, GetDeviceInformation for checking, setting and reading device instance changes. See more info on document.

  • Added ISO Multi-packet handling. Changed logic on SetN2kCANBufMsg due this.

05.06.2017

  • Added PGN 130314 by sarfata.

  • Added PGN 127245 rudder parser

  • Fixed Device Information, last bit must be set to 1

  • Fixed response to ISO Address Claim request. Seems that all new devices respond allways with broadcast instead of caller address.

28.05.2017 Changed default NMEA2000 variable definition in NMEA2000_CAN.h to reference. So now it is possible to refer it in other modules with definition: extern tNMEA2000 &NMEA2000;

08.04.2017 Added Binary status report (PGN 127501) handling. See updated examples MessageSender and DataDisplay2.

09.03.2017 Added PGN 129539 support and PGN 129283, 129284 parsers by denravonska.

07.03.2017 Debug mode check for DeviceReady and ParseMessages.

05.03.2017 RPi socketCAN auto selection and MBED compiler portability fix by thomasonw.

08.02.2017 Fixed Heading PGN 127250 parsing

22.01.2017 Replace pointer casting with memcpy to avoid unaligned access, and add endian support. Thanks to denravonska.

  • Handle for PGN 65240 "Commanded address". E.g. diagnostic device may command your device to change address.

01.01.2017 Document and some example fixes to match library portability changes.

20.12.2016 Added support for PGN 126464L, PGN List (Transmit and Receive). Library will automatically respond to this message. You need only add message lists and call to methods ExtendTransmitMessages and/or ExtendReceiveMessages. See e.g. example TemperatureMonitor.

17.12.2016 Fixes to avoid compiler warnings

16.12.2016 Portability fixes. Thanks to denravonska and thomasonw!

  • NOTE! compatibility issue! There is no more default stream set on library constuctor. So in case you are using forwarding, you need to setup it (like in examples) NMEA2000.SetForwardStream(&Serial);

  • This reduces the Arduino dependency, allowing the library to more easily be used on other platforms. Check all changes under ttlappalainen#35

01.12.2016 License change to MIT for more permissive

  • Also some started to remove platform dependent code.

12.11.2016 PGN129025 parser added and some fixes by KimBP

11.11.2016 Added support for PGN 127258 - magnetic variation by adwuk.

18.10.2016 Added parsing for PGN 130311 by adwuk. Typo fix for system date comment by sarfata.

19.09.2016 Lot of testing behind - hopefully works now better.

  • NOTE! New method SetN2kCANSendFrameBufSize. Added buffer for frames to be sent. This takes more RAM and may be critical for low RAM systems.

  • If frame sending fails, system now buffers frames to be sent automatically and tries to resend them on next call for ParseMessages. With this feature it solved my problem that time to time my MFD could not receive important GNSS or SOG/GOG messages and informed error.

  • System now also has more reliable response to the Product Information ISO request (PGN 126998). Unfortunately if your system does not poll often enough incoming messages (ParseMessages), you still may loose the request itself. This is specially the case if you system spends some time reading sensors like 1-wire system. Even with 1-wire asynchronous read, it may spend 10 ms interrupts disabled. Within 10 ms there may be about 30 messages on bus.

  • New methods SetConfigurationInformation and SetProgmemConfigurationInformation. System can now also handle Configuration Information ISO request to (PGN 126998). Default configuration information is saved to PROGMEM.

  • NOTE! Reload also NMEA2000_due!

17.09.2016 Temporary fix for problem to respond product information ISO request.

12.09.2016 Thanks for people (usauerbrey, OzOns), who noted below problems

  • NOTE! If you are using NMEA2000_can, remember to update that too!

  • Fix for ISORequest handling. Now responds allways also for broadcasts.

  • Some fixes to avoid compiler warnings.

  • Fix for parsing PGN 127257/Attitude

09.08.2016 NOTE! Fixed PGN 130310, PGN 130311 and added SetHandleOnlyKnownMessages(), which effects backward compatibility. See below.

  • NOTE! On PGN 130310 and PGN 130311 description says that "Atmospheric pressure in Pascals. Use function mBarToPascal". There was scaling error and now they works like description. After update you have to provide value on Pascals and really use mBarToPascal, if you have your value in mBar.

  • NOTE! Added SetHandleOnlyKnownMessages(). If you have called SetForwardOnlyKnownMessages(true), library did not handle unknown messages. After update, this effects only message forwarding - as it should have been. So call also SetHandleOnlyKnownMessages(true), if you want to disable any handling for unknown messages.

  • NMEA 2000 Library reference update.

  • Added ExtendSingleFrameMessages and ExtendFastPacketMessages. With these one can own list of known messages so that it is not necessary to duplicate message list as, if used only SetSingleFrameMessages and SetFastPacketMessages.

  • Added discrete status flags for transmission parameters (PGN 127493), thanks for testing Jason.

06.08.2016 Added SetISORqstHandler for setting handler for ISO requests. Thanks thomasonw.

30.07.2016 NMEA 2000 Library reference update.

Added example TeensyActisenseListenerSender. Example contains code, schematics and document.

19.07.2016 Fixed discrete status on engine dynamic parameters (PGN 127489), thanks Jason.

Added new PGN 127257, vessel attitude. Only sending has been tested with NMEA Reader

12.07.2016 Added to API — Optional message lists by thomasonw

25.06.2016 Corrected Battery Current in ParseN2kPGN127508 by thomasonw.

23.03.2016 Additional PGN 129038, PGN 129039, PGN 129285, PGN 130074 support by adwuk.

13.03.2016 Fix of using PROGMEM. Now also product information defined to PROGMEM works right.

13.03.2016 Fix of using PROGMEM. Still does not work right with product information in PROGMEM. So all changes after 09.03 are still under validation.

13.03.2016 More memory optimization - thanks for thomasonw. Constant message strings has been marked with F(…​) moving them to flash instead of RAM.

Note also that there is new function void tNMEA2000::SetProductInformation(const tProductInformation *_ProductInformation); So one can save memory by defining product information to flash by using syntax:

const tProductInformation BatteryMonitorProductInformation PROGMEM={
1300,               // N2kVersion
...

See example BatteryMonitor.ino

12.03.2016 Memory tuning. Currently multi device and user definable message filters has not been implemented, so I changed buffer sizes to minimum.

There is also new function void tNMEA2000::SetN2kCANMsgBufSize(const unsigned char _MaxN2kCANMsgs); to define buffer size for received N2k messages. Note that library has to collect fast packet frames, which may arrive fragmented from different devices, so as default this buffer size has been set to 5. If your device is only sending some data (mode is tNMEA2000::N2km_NodeOnly), you do not need to catch all fast packet messages (if any), so you can set buffer size smaller.

09.03.2016 Additional PGN 127250, PGN 128275 Support by adwuk.

08.03.2016 AVR CAN support by thomasonw.

02.02.2016 NOTE! Updates, which effects backward compatibility. See list below.

  • PGN 127489, SetN2kPGN127489 EngineOilTemp and EngineCoolantTemp is in Kelvins as in other temperature functions. So add for call to this function CToKelvin(…​)

  • Some function names withing N2kMessages have been changed. Change function names listed below!
    SetN2kPGNSystemTime → SetN2kSystemTime
    ParseN2kPGNSystemTime → ParseN2kSystemTime
    SetN2kPGNTrueHeading → SetN2kTrueHeading
    SetN2kPGNMagneticHeading → SetN2kMagneticHeading

  • Variable types has been changed on some functions in N2kMessages. So when you get an compiler error about functions in N2kMessages, check carefully all parameter definitions for function from N2kMessages.h.

  • If you do not have value for some parameter for functions in N2kMessages, use related N2kxxxxNA constant defined in N2kMsg.h. So e.g. if you only have wind speed, call
    SetN2kWindSpeed(N2kMsg, 1, ReadWindSpeed(),N2kDoubleNA,N2kWind_Apprent);

  • If you are reading values from N2k bus, you can now check does some value exist by using function N2kIsNA. So if you e.g. call
    ParseN2kOutsideEnvironmentalParameters(N2kMsg,SID,WaterTemperature,OutsideAmbientAirTemperature,AtmosphericPressure);
    then check pressure value with
    if ( !N2kIsNA(AtmosphericPressure) ) { // It is available, so we can show it!

  • Added reference document to the documents, which hopefully helps to get started.

23.01.2016 Added PGN 127493 support. NMEA2000_mcp has now interrupt support. Some other fixes.

23.01.2016 Added some comments to samples and several new message readers. Also added support for 130316 extended temperature. Added new include N2kMessagesEnumToStr.h for translating library enums to clear text. This is now just for preliminary so I may changes texts in coming future. Added also new examples DataDisplay2.ini and MessageSender.ino. They are extended versions of DataDisplay.ino and TemperatureMonitor.ino.

05.12.2015 Added NMEA2000_CAN.h and some fixes. Library has been originally developed with Arduino Software 1.6.5 On Arduino Software 1.6.6 it is possible to include libraries within included files, so now it is possible to just include one file NMEA2000_CAN.h, which automatically selects right CAN library according. So you can have same code for different hw. Currently supported CAN libraries are mcp_can, due_can and teensy. Note! NMEA2000_CAN.h is now used on examples TemperatureMonitor and WindMonitor!

Memory requirements

I have tried to measure memory used by library, but it is not so simple, since there are some automated operations. With version 11.06.2017 I got results:

  • Approximate ROM 26.9 kB

  • Approximate RAM 3.4 kB

This is with simple TemperatureMonitor example. This can be squeezed by setting:

  • NMEA2000.SetN2kCANMsgBufSize(2); NMEA2000.SetN2kCANSendFrameBufSize(15); inside setup() before NMEA2000.Open();

  • Defining ProductInformation to PROGMEM as in BatteryMonitor example.

  • Disabling all extra features. See NMEA2000_CompilerDefns.h

  • Disable interrupt receiving.

With those setting you can go down to appr. 19 kB ROM and 1.9 kB RAM. So for 2 kB devices like Arduino Uno, there is not much for your own code.

Hardware setup

To use Arduino NMEA2000 library you will need either

  • Arduino Due and CAN-bus_transceiver chip e.g. MCP2562 or SN65HVD234. I used MCP2562, since that was available also in DIP package. Under Documents there is file ArduinoDUE_CAN_with_MCP2562.pdf for using MCP2562 and file ArduinoDue_CAN_with_SN65HVD234.jpg for using SN65HVD234.

  • Arduino Mega and MCP2515 CAN-bus controller + MCP2551 CAN-bus_transceiver or buy CAN_BUS shield card. Under documents there is file ArduinoMega_CAN_with_MCP2515_MCP2551.pdf for layout to build CAN-bus interface by yourself. MCP2515, MCP2551, ocillator and few components cost only few euros, if you are handy and used to use soldering device.

  • Teensy 3.1/3.2 or 3.5/3.6 board with a MCP2562 or MCP2551 CAN-bus transeiver transeiver (or similar, see FlexCAN documentation).

Library has been also used with Maple Mini board, which is much cheaper than arduino.

If you using Arduino for transfering all messages to PC, I’ll prefere Due version, since it is more powerful. I Also prefere it, if you use handle messages (like GNSS) containing 8 byte double values. Arduino Mega has only 4 byte double, so you may loose some accuracy.

Software setup

You need at least Arduino Software 1.6.6 for this sample. I’ll expect you are familiar with Arduino and using libraries. When your Arduino environment is ready,

  • Download NMEA2000 library zip.

  • Download either NMEA2000_due, NMEA2000_mcp or NMEA2000_teensy library zip depending you hw.

  • Download either due_can or mcp_can library zip depending you hw or install Teensyduino for Teensy 3.1/3.2 or 3.5/3.6 boards.

  • Install all libraries (Add .ZIP library).

  • Open NMEA2000\Examples\TemperatureMonitor.

  • Connect you Arduino to USB and NMEA2000 bus.

  • Send sketch to Arduino.

  • If you have Multi Function Display (e.g. Garmin GMI-20) on your NMEA2000 bus, you should see on it’s NMEA2000 bus devices new device "Simple temp monitor" on the list.

So you are ready to play with your own device. Check also the NMEA2000\Examples\ActisenseListener, which reads all data from NEMA2000 bus and sends it to PC.

Using Arduino Software older than 1.6.6

With latest version of Arduino sw it is possible to simply include NMEA2000_CAN.h, which automatically selects necessary CAN libraries. For older versions you have to add library includes to main project file. So depending on board add lines:

For use board with MCP2515 SPI can bus tranceiver and mcp_can library

#include <N2kMsg.h>
#include <NMEA2000.h>
#include <SPI.h>
#include <mcp_can.h> // https://github.com/ttlappalainen/CAN_BUS_Shield
#include <NMEA2000_mcp.h>
#define N2k_SPI_CS_PIN 53  // Pin for SPI Can Select
tNMEA2000_mcp NMEA2000(N2k_SPI_CS_PIN);

For use with Arduino due and due_can library

#include <N2kMsg.h>
#include <NMEA2000.h>
#include <due_can.h>  // https://github.com/ttlappalainen/due_can
#include <NMEA2000_due.h>
tNMEA2000_due NMEA2000;

For use with Teensy 3.1/3.2 board and FlexCan>

#include <N2kMsg.h>
#include <NMEA2000.h>
#include <FlexCAN.h>
#include <NMEA2000_teensy.h> // https://github.com/sarfata/NMEA2000_teensy>
tNMEA2000_teensy NMEA2000;

For use with Atmel AVR processors internal CAN controller

#include <N2kMsg.h>
#include <NMEA2000.h>
#include <avr_can.h>            // https://github.com/thomasonw/avr_can
#include <NMEA2000_avr.h>       // https://github.com/thomasonw/NMEA2000_avr
tNMEA2000_avr NMEA2000;

References

License

Copyright (c) 2015-2017 Timo Lappalainen, Kave Oy, www.kave.fi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.