NMEA2000 Library
0.1
Library to handle NMEA 2000 Communication written in C++
|
NMEA2000 library is object oriented C++ library for developing NMEA2000 bus devices. Library fulfills automatically NMEA 2000 mandatory requirements (see NMEA2000 certification) leaving only interesting data handling for developer. Library has been used in several commercial certified NMEA2000 devices.
To use NMEA2000 library you need basic skills for programming. For beginners I have tried to write simple instructions to start from scratch with Arduino IDE. When I started library development and even I had been doing sw and hw development for years, it took some time to dig information from internet to get started with Arduino based boards and do even simple tasks like installing library.
For using NMEA2000 library I prefer Teensy 4.0, 4.1, (or 3.2, 3.5, 3.6 which are end of life) or ESP32 with isolated ISO1050 or unisolated MCP2562 chip. For experienced users and big projects RPi can be also used.
For simple things Arduino Mega with CANBUS shield or schematics found under documents is ok. I have not tested smaller boards and I prefer to forget any board less than 8 kB RAM.
I started library development 2015 because I wanted to get rid of limitations of expensive devices on market. Also those did not had features I wanted. With my first own device for my yacht, I replaced three devices – NMEA0183 combiner, NMEA0183->NMEA2000 Converter, NMEA2000->PC converter - with single Arduino Due board and few extra chips.
On 2017 library was chosen for first commercial certified device. Later there has been several other commercial devices using my library. That has also made it important to keep it combatible and ready for certificated devices.
Since 2015 my personal work has moved more and more towards NMEA2000. I do commercially different NMEA2000 projects and consulting.
Lets think you have temperature sensor and you like to have it visible on NMEA2000 bus. Here I expect that:
At first we have to download and install necessary libraries for Arduino and other useful tools.
Download and install Arduino libraries according to your hardware see Hardware depended libraries.
If you want to read or decode NMEA2000 messages, you can download and install “NMEA Reader”-application from http://www.actisense.com/media/?product=nmea-reader-and-ebl-reader
Now we are ready to try sample without N2k bus connection. So you need only Arduino board and PC. No CANBUS shield or extra chips yet!
and comment line
within setup() function.
within setup() function.
We need to do this, since Mega board does not have build in CAN bus controller, so the library would fail, when it tries to open CAN on non debug mode.
Now you should see:
messages on “NMEA Reader”.
First note that if you want to modify and save this sample, you have to save it on other location.
If you are happy with sending only cabin and water temperatures to the N2k bus, you simply change functions double ReadCabinTemp() and double ReadWaterTemp(). So e.g. if you have sensor providing 10 mV/ °C, you can change the function:
Do the same for ReadWaterTemp() (naturally you have to use other analog input e.g. A1) and you have your own ready NMEA2000 temperature monitor.
With the library N2k messages will be sent by call NMEA2000.SendMsg(N2kMsg). Before sending you have to setup the variable N2kMsg. In that example it has been done for Temperature message with call:
So if you do not need cabin temperature message (PGN 130312), simply delete that call SetN2kTemperature(…) and next call NMEA2000.SendMsg(N2kMsg); Similarly if you do not provide water temperature, delete calls SetN2kOutsideEnvironmentalParameters(…) and call NMEA2000.SendMsg(N2kMsg); after that.
Now just upload sketch and open right port to “NMEA Reader” and you should see only "ISO address claim" (PGN 60928) and "Environmental parameters" (PGN 130311) on “NMEA Reader”.
On NMEA2000 bus each device will tell to the bus what it is (see also NAME). This can be found on sample under setup() function. Call SetDeviceInformation is important for right functionality on the bus. If you have only this own device on the bus, you can leave it like it is. In other case take deeper look in to the explanation for the function. Note that if you add several own devices to the bus, you have to configure parameters for this function so that each device will get unique NAME as a combination of these parameters.
Call SetProductInformation is not so important for own boat, but defines nice to know information. If you have some “Multi Function Display” (MFD) on the bus, it will show on the device list information set by this function. So you can e.g. set the “Manufacturer's Model ID” to “Jack’s temperature monitor” and version code and model version as you like, so on your MFD you can see that and choose right device.
So now we have sketch, which works on the PC. If your sketch runs and shows information in “NMEA Reader”, it can be easily connected to the N2k bus. For electrical connection you need either CANBUS shield for Arduino Mega or you can build your own shield. You can find more information at Setting Up Hardware Environment.
There is also drawing for Teensy on Teensy_Actisense_listener_sender_schematics.pdf, which has additional USB with Pololu chip, which is only required for two USB solutions. So Prepare physical connection to the NMEA2000 bus and comment line:
within setup() function, if you have previously uncommented it. Upload the sketch and check the result.
On your NMEA2000 “Multi Function Display” (MFD, like Garmin GMI20) add temperature reading visible. For that I can not give more help, since each MFD has different user interface. Now you should see the temperature reading on your MFD.
If you are not interested in N2k bus messages and you want to add your own debug code, you have to disable message forwarding by uncommenting line:
WindMonitor.ino is similar as TemperatureMonitor, but sends wind data to the bus. Only necessary function names has been changed. So follow the “Try NMEA2000 library with TemperatureMonitor example”.
Select right board for IDE from Tools-Board
Now you are ready for your own developing.
Arduino has both system wide and user libraries.
Arduino has both system wide and user libraries.
Arduino IDE installation automatically installs system wide libraries. When you add library with Arduino IDE, it will be added as default can make some library visible for all users by moving installed library from your personal libraries to system wide libraries.
If someone points you direct link as .zip file to Arduino library, you need only:
So now you should have that library on your personal libraries.
Importing library from GitHub is also very simple. So you have heard or found good link to someone GitHub page.
NMEA2000 is closed standard. You can buy documents for it for high price. As far as I have understood, then you also accept that you are not allowed to tell any third party about document contents. So all the information and experience I have has been collected from free documents and mostly from OpenSkipper project, which development I have been continued. So there may be errors on library. Anyway have tried to make it simple to use, but still giving “NMEA2000 compatibility”.
The tNMEA2000 class contains functions for NMEA2000 handling like e.g. sending and reading messages. This is purely an abstract class and to use a real device you must use an appropriate inherited class. Normally you use functions within this class.
Inherit this class for your own message handler. When new message arrives, all attached handlers, which matches message PGN, will be called by ParseMessages. You can define this handler for single PGN or for all by setting PGN for base class to 0. You can also attach and detach class handler from tNMEA2000 object.
There are own inherited class for each CAN interface type. As described below e.g. for Arduino Due you use due_can and NMEA2000_due libraries. Since Arduino IDE 1.6.6 it has been possible to include libraries within other headers, so to use any of currently tested board you can simply add includes
"#include <NMEA2000_CAN.h>" will then automatically select right library according to the board you have selected on IDE (see USE_N2K_CAN). If you want strictly control includes or the board will not be selected right by NMEA2000_CAN.h, use includes described on each inherited class or force selection with define before include. E.g.
The tNMEA2000_mcp is class for using library with CANBUS shield or according to schematic ArduinoMega_CAN_with_MCP2515_MCP2551.pdf, which I have made for sample.
To use this class, you need to include in your project beginning:
If you use automatic library selection, you need to any define CS pin (default 53) and interrupt pin (default 21), if they differ from defaults.
You can find the mcp_can library from https://github.com/ttlappalainen/CAN_BUS_Shield/archive/master.zip. Originally it was developed by SeedStudio https://github.com/Seeed-Studio/CAN_BUS_Shield. That library was last merged 18.09.2017. I have not yet tested changes after that.
The tNMEA2000_due class is for using library with Arduino Due, which has internal can bus controller. I personally prefer this board, since it is more powerful. It also has separate USB port. Also the physical interface to the bus is simpler. You can find sample schematic on ArduinoDUE_CAN_with_MCP2562.pdf.
To use this class, you need to include in your project beginning:
You can find the due_can library from due_can. That had been originally forked from https://github.com/collin80/due_can, but Collin library has some changes I have not tested.
The tNMEA2000_teensy class is for using library with Teensy 3.2, 3.5, 3.6 boards, which has internal can bus controller. Physical interface is similar as with Arduino Due.
To use this class, you need to include in your project beginning:
The tNMEA2000_Teensyx class is for using library with Teensy 3.2, 3.5, 3.6, 4.0, 4.1 boards, which has internal can bus controller. Physical interface is similar as with Arduino Due.
To use this class, you need to include in your project beginning:
At the moment automatic automatic library selection uses as default NMEA2000_teensy.h for Teensy 3.2, 3.5, 3.6. NMEA2000_Teensyx works reliably with old boards too so you can force it for automatic library selection
The tNMEA2000_esp32 class is for using library with ESP32 based boards, which has internal can bus controller. Physical interface is similar as with Arduino Due or Teensy.
To use this class, you need to include in your project beginning:
The tNMEA2000_teensy class is for using library avr based boards. I have not yet experience of them, but thomasonw uses them. To use this class, you need to include in your project beginning:
This is the class for containing N2k (PGN) message. It contains pure data and functions to handle it. At least for now there is no automated system, which could you easily fill or read data for specific PGN. You have to know the PGN information fields like for NMEA0183 data fields. I and other developers have written functions, which has been defined on N2kMessages.h, which helps you the fill or read data on tN2kMsg object.
As in example TemperatureMonitor you send PGN 130312 (Temperature) message with simple code:
So as you see, you do not need to know much about tN2kMsg to use it. It is simple container.
NMEA 2000 definition requires than devices should respond group function messages. This class is default handler, which simply responds “unsupported” for all queries.
see tN2kGroupFunctionHandler
This class can be used to read devices on the connected NMEA 2000 bus. When class has been attached to tNMEA2000 object, it will automatically collect and update information of devices on the bus. On the NMEA 2000 bus all devices (also called nodes) has own source address. The source addressmay be changed due to address claiming on power up or when new device will be added to the bus. For this reason source address can not be used as only filter for similar messages like position data. By using tN2kDeviceList source address related to NAME can be easily found at any time with tN2kDeviceList functions.
In principle on steady system source will stay unchanged. The safer way is to use device NAME which should be unique. So if you e.g., have two speed logs and you want to specify the one you want to use, you can use tN2kDeviceList class to search source address for specified NAME and then read log messages from that source.
See also example DeviceAnalyzer.ino.
There are several examples for using library with different functions like for only listen bus data (ActisenseListener.ino), sending temperature (TemperatureMonitor.ino) or wind data (WindMonitor.ino) from your own sources or displaying bus data somehow (DisplayData.ino and DisplayData2.ino).
Library core has all functionalities to communicate with NMEA2000 bus and N2kMessages.h has simple functions to read and set most common messages. And you can add own modules to support missing messages. Rest is up to your imagination.
Below is short description of member functions, which hopefully gives you better knowledge why something has been used on samples.
For historical reasons library offers several message handling modes. One idea was that CAN controller specific drivers could drop some data handling, but it is not implemented on any of them. Practically only modes
would be enough.
"Listen" in mode definition refers to message forwarding. Mode definitions without "Listen" passes forward functionality. On the other hand forwarding can be enabled or disabled with tNMEA2000::EnableForward(), which then makes other modes less necessary. Also mode can not be changed after open, but forward can be enabled or disabled at any time - this makes listen modes be more usefull. And last since drivers does not limit messages by mode message handlers will be called anyway allowing you to control messages in your code and even build own "message forwarding".
Although there should be no reason to use other than N2km_ListenAndNode or N2km_ListenAndSend modes, below is table of different modes effect.
(x) means that feature is not limited by core library, but could have limit on "driver".
Mode | Tx | Rx | Dev | Fen | S |
---|---|---|---|---|---|
N2km_NodeOnly | x | x | x | ||
N2km_ListenAndNode | x | x | x | x | x |
N2km_ListenAndSend | x | x | x | ||
N2km_ListenOnly | x | x | x | ||
N2km_SendOnly | x | (x) |
NMEA2000 requires that all devices should act as active device (also called node) on the NMEA2000 bus. Total electrical bus load can be then calculated and there will not be any hidden devices. If you take care that bus load will not be exceeded, it should not be risky to make listen only devices for you own boat.
You can set your device mode on setup with function tNMEA2000::SetMode(). See also tNMEA2000::tN2kMode .
Message forwarding offers simple way to forward messages to defined stream in Actisense format. I build this functionality inside library to easily analyze bus messages even device does have its own functionality like temperature sensor. Now when I have mostly used ESP32 with WiFi, I can enable forwarding on the fly to UDP stream for any device and use it as analyzer.
In any listen mode, the device will read all messages from N2k bus and forwards them to the defined forward stream. For forwarding you just define a forward stream - e.g., serial port, UDP stream - with function tNMEA2000::SetForwardStream and enable forward with tNMEA2000::EnableForward(true). Naturally you also need to open a stream first e.g. with Serial.begin(115200);
Messages will be forwarded as default in Actisense format. This format is supported by at least some PC chart plotter applications. You can show Actisence format messages with “NMEA Reader”, which I refer time to. Best program for bus data analyzing is my NMEA Simulator http://www.kave.fi/Apps/. For data visualizer you can use e.g., OpenSkipper, on which you can tailor your own displays.
If message forwarding is enabled, own messages send with tNMEA2000::SendMsg will be forwarded as default even when your device has been set to node only mode. If this disturbs your developing, if you e.g. want to write own clear text messages within your code, you can disable that by either:
Debug mode is as default set to tNMEA2000::dm_None. In other debug modes device will not send anything to the N2k bus. Debug mode tNMEA2000::dm_Actisense is usefull, if you do not have board with internal CAN bus controller, because in that mode it does not try to open CAN bus during sending message. Instead it simply writes message to the forward stream, which you can read e.g. with “NMEA Reader” and see that your device is sending message right.
Debug mode tNMEA2000::dm_ClearText defines that messages will be send to forward stream as clear text. Unfortunately on clear text there are only source, destination, priority data length and PGN shown as clear text. Data itself will be shown as hex.
In NMEA 2000 bus you have devices or also called nodes. Normally each physical device is one device on the bus. I have not seen any requirement that a device could not serve as engine information (device class 50 – propulsion) or sensor information (device class 75 - Sensor Communication Interface) interface at same time and just use device class 25 (Inter/Intranetwork Device) and function 132 (Analog to NMEA 2000 Gateway). Anyway I have found that e.g. B&G Vulcan 7 chartplotter acts as multi device. I do not know are these devices different chips inside Vulcan or are they within same code as my multi device.
If you like show different functions as own device on the bus, you can do that with multi device support. All you need to do is to first set device count (see tNMEA2000::SetDeviceCount), set device and product information for each device and on sending messages use right device index. See example MultiDevice.
Library has been designed to work without need for multitasking system. After setup it is critical to call tNMEA2000::ParseMessages in loop as fast as possible. By that call library handles many basic required features like address claiming, responding to system requests, heartbeat sending etc.
Fast loop requirement means that you are not allowed to use any delay on your loop or any other library using delay or blocking read. Delays withing loop in worst case causes that other devices on your NMEA2000 bus drops your device from the list and then pops it up again. If you have e.g., configured your MFD to show temperature from your device, it may appear and disappear on the screen.
A practice has shown that random 10-50 ms delay is acceptable. In average loop time should be less than 2 ms. Also it is important that if you can have up 50 ms random delay, you may get in burst up to 90 frames (=1800 frames/s *0.05 s) during that time. This means that if your receive frame buffer is smaller, your device may loose some critical system messages. In small boat this amount is a bit theory, but anyway there are a lot of large messages just from GPS system so that they may occur time to time at same time. So it is better to prepare your device work in nearly any condition.
If you use DallasTemperature library as default you may block loop up to 700 ms. By using it "asynchronously", delays are smaller and may be acceptable. Best solution would be to use some kind of hardware based library like esp32-owb for ESP32.
Some ADC libraries blocks loop during conversion, which may be 200-400 ms for high resolution ADC with averaging. ADC:s should be always used so that conversion will be started and then quickly checked, when conversion is ready. Even better if you know conversion time and check it after you expect it should be ready.
Some displays are very slow for writing. Writing some text may take 100 ms causing too long delay and problems with bus. Depending of library, it may also have some kind of buffering to get write request and flag, when it has been finished without blocking call. If there is not, it is often possible write own higher level buffering, which finally writes to display letter by letter and so spent only short time on each call.
With serial line use always available and availableForWrite features to avoid blocking. Also it helps if you can define bigger harware buffers.
In multitasking system someone had defined tNMEA2000::ParseMessages task time to 100 ms. I do not wonder, if there will random strange problems with that device. 1 ms task time would be acceptable.
Library has been designed to do automatically as many required features as possible. In this way user can concentrate to his own code and does not need to know everything about NMEA2000 low level. There is several system messages, which are handled automatically and user does not need to take care of.
Set the Product Information of this device. With this function you define how your device will show up for other devices on NMEA2000 bus.
Define your product information. Defaults will be set on initialization. For keeping defaults use 0xffff/0xff for int/char values and null ptr for pointers. LoadEquivalency is multiplication of 50 mA, what your device will take power from NMEA2000 bus. E.g. for Arduino only it can be 1 (=50mA). If your device does not take power from bus, set this to 0.
If you use device modes tNMEA2000::N2km_ListenOnly, tNMEA2000::N2km_ListenAndSend or N2km_SendOnly, function does not have effect.
_ModelSerialCode | Default="00000001". Max 32 chars. Manufacturer's Model serial code |
_ProductCode | Default=666. Manufacturer's product code. For certified devices this number will be given by NMEA organization. |
_ModelID | Default="Arduino N2k->PC". Max 33 chars. Manufacturer's Model ID |
_SwCode | Default="1.0.0.0". Max 40 chars. Manufacturer's software version code |
_ModelVersion | Default="1.0.0". Max 24 chars. Manufacturer's Model version |
_LoadEquivalency | Default=1. x * 50 mA |
_N2kVersion | Default=2101 |
_CertificationLevel | Default=1 |
iDev | index of the device on Devices |
Set the Device Information. See also NAME. If you use device modes tNMEA2000::N2km_NodeOnly or tNMEA2000::N2km_ListenAndNode, it is critical that you set this information.
Device information will be used to choose right address for your device (also called node) on the bus. Each device must have an own address. Library will do this automatically, so it is enough that you call this function on setup to define your device.
For keeping defaults use 0xffff/0xff for int/char values and null ptr for pointers.
I just decided to use number one below maximum for ManufacturerCode as Open Source devices - this is not any number given by NMEA.
_UniqueNumber | Default=1. 21 bit resolution, max 2097151. Each device from same manufacturer should have unique number. |
_DeviceFunction | Default=130, PC Gateway. See codes on https://web.archive.org/web/20190531120557/https://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf |
_DeviceClass | Default=25, Inter/Intranetwork Device. See codes on https://web.archive.org/web/20190531120557/https://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf |
_ManufacturerCode | Default=2046. Maximum 2046. See the list of codes on https://web.archive.org/web/20190529161431/http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf |
_IndustryGroup | Default=4, Marine. |
iDev | index of the device on Devices |
Set the Device Information Instances. With this function you can set device instance lower, device instance upper and system instance values.
For certified devices there is requirement that device instances can be externally changed. Library handles that as default, but developer has to take care that changed instances will be saved and restored on devices start.
_DeviceInstanceLower | 0xff means no change |
_DeviceInstanceUpper | |
_SystemInstance | |
iDev | index of the device on Devices |
Get the Device Information. With this function you can read current device information. Normally device information contains what you have set during initializing with tNMEA2000::SetDeviceInformation and tNMEA2000::SetDeviceInformationInstances functions.
iDev | index of the device on Devices |
Set the Configuration Information of this device. With this function you can set configuration information for your device.
Configuration information contains some extra information about device installation and manufacturer. Some MFD shows it, some does not. NMEA Reader can show configuration information. InstallationDescription1 and InstallationDescription2 can be changed as default during runtime by NMEA 2000 group function commands. That can be done e.g. with NMEA Reader.
ManufacturerInformation | Buffer for Manufacturer information. Use e.g., company name and web address. |
InstallationDescription1 | Buffer for Installation Description 1. Installation Description 1 and 2 may be used by device installer e.g., for location of physical device to help to find it. To handle externally updated Installation Description you should listen changes of them. See tNMEA2000::ReadResetInstallationDescriptionChanged |
InstallationDescription2 | Buffer for Installation Description 2. |
Set the Configuration Information located on PROGMEM. With this function you can set configuration information, which will be saved on device program memory. See example BatteryMonitor.ino.
This function is useful only on MCUs with very small RAM. By using PROGMEM, installation description can not be changed by group function.
As default system has build in configuration information on progmem. If you do not want to have configuration information at all, you can disable it by calling SetConfigurationInformation(0);
ManufacturerInformation | Buffer for Manufacturer information |
InstallationDescription1 | Buffer for Installation Description 1 |
InstallationDescription2 | Buffer for Installation Description 2 |
Set the library mode and start source address. With SetMode you can define how your node acts on N2k bus and set start source address. Source address setting has effect only on modes N2km_NodeOnly and N2km_ListenAndNode.
NMEA2000 standard requires that once your device has been connected to the bus, it uses last used address on next start. Due to address claiming, your device may change its source address, when you add new devices to the bus. So you should save last used address to e.g. EEPROM and on setup use it as parameter for SetMode. You can check if your address you set originally by SetMode has changed by using function tNMEA2000::ReadResetAddressChanged() and you can read current address by function tNMEA2000::GetN2kSource().
_N2kMode | Mode for this node, see tN2kMode |
_N2kSource | Source address for this node |
Example how to init and save device source address.
Extend the list of Transmitted Messages. Define list of extra PGNs, what your system will transmit. System messages will be automatically included. Pointers must be in PROGMEM
Library responds automatically to PGN 126464 request about transmit or receive messages. With this function you extend library list of messages your device own logic sends.
This has only effect for device modes tNMEA2000::N2km_NodeOnly and tNMEA2000::N2km_ListenAndNode.
_TransmitMessages | Buffer holding list of extra PGNs device will transmit. |
iDev | index of the device on Devices |
Extend the list of Received Messages. Define list of extra PGNs, what your system will handle. System messages will be automatically included.
Pointers must be in PROGMEM.
Library responds automatically to PGN 126464 request about transmit or receive messages. With this function you extend library list of messages your device own logic listens.
This has only effect for device modes tNMEA2000::N2km_NodeOnly and tNMEA2000::N2km_ListenAndNode.
_ReceiveMessages | Buffer holding list of extra PGNs device will handle. |
iDev | index of the device on Devices |
Set OnOpen callback function. OnOpen will be called, when communication really opens and starts initial address claiming. You can use this to init your message sending to synchronize them with e.g., heartbeat.
Send message to the NMEA2000 bus. Call this to send message to NMEA2000 bus. Before calling SendMsg() you have to prepare tN2kMsg type of message e.g. by using PGN specific function in N2kMessages.h.
The function returns true, if the message was sent or buffered successfully, otherwise it return false. SendMsg may fail, if there is not room for message frames on sending buffer, device is not yet open or not ready to send.
If you sent single frame message time to time, it will normally go directly to CAN controller sent "mailbox", where controller sends it as soon as it gets time from bus. Sending fastpacket message will always buffer at least other than first frame. Internally sent buffer is devided to driver buffer and library buffer. Driver buffer will empty by interrupt and library buffer on call to SendMsg or ParseMessages, which moves frames to driver buffer. To have reliable sending, you need a sending buffer, which is large enough for your device needs. See tNMEA2000::SetN2kCANSendFrameBufSize.
See example TemperatureMonitor.ino.
N2kMsg | Reference to a N2kMsg Object |
DeviceIndex | index of the device on Devices Setting DeviceIndex to -1 forces library to use source address of N2kMsg instead of device source address. This is useful with e.g., passthrough gateway devices. |
true | Message sent or buffered successfully. |
false | Open has not finished. Address claiming has not finished. There is no more room on send buffer, which may be caused by too small send buffer or CAN controller can not sent messages bus. |
Parse all incoming Messages. You have to call this periodically on loop() to handle N2k messages, otherwise tNMEA2000 object will not work at all.
With NMEA2000 library you should use only nonblocking calls/libraries in your loop. Any library you use, should work asynchronously and not cause long delays on loop. Randomly caused 10-40 ms delays are acceptable. E.g., simple ADC conversion may block loop for 300 ms, which you will then see by other device dropping your device from the list.
See example TemperatureMonitor.ino.
Set the message handler for incoming NMEA2000 messages. If you want to do something with messages read from N2k bus, easiest is to set message handler, which will be then called by ParseMessages for each new message.
If you have LCD display on your device and you want to show e.g., fluid level on it, create message handler, parse fluid level messages and draw value to display.
See example DataDisplay.ino or DataDisplay2.ino
_MsgHandler | Old style - callback function pointer |
Attach a message handler for incoming N2kMessages. tNMEA2000::SetMsgHandler allows you to define only one handler to your system. If you like to do it by using classes, I prefer to use AttachMsgHandler. In this way you can e.g. define own class for each PGN and attach/detach them within your program.
Example NMEA2000ToNMEA0183 uses AttachMsgHandler. Due to logic it still has single class and so handles all PGNs.
_MsgHandler | Message handler |
Detach a message handler for incoming N2kMessages. With DetachMsgHandler you can remove your handler from the handler stack. This is useful, if you do not want to handle some messages anymore.
_MsgHandler | Message handler |
Set the message handler for incoming ISO Requests. Devices on N2k bus may request PGN from your device. Certified devices should respond to requests to any transmit PGN listed. Write your own request handler and set it with this function.
The handler will be called by tNMEA2000::ParseMessages, if there is ISO request.
ISORequestHandler | Message handler |
Read address for current device. With this function you can get you device current source address on the N2k bus.
DeviceIndex | index of the device on Devices |
Set source for the given device. With this function you can set you device source address on the N2k bus. This is meant to be use for multi device on basic configuration to restore source address changed by address claiming.
This function has to be called after tNMEA2000::SetMode() and before tNMEA2000::Open()
_iAddr | Address of the device |
_iDev | index of the device on Devices |
Check if this device has changed its address. With this function you can check has your device address you initiated with SetMode been changed after last call.
When you call this, tNMEA2000::AddressChanged will be reset. Anyway, if system for some reason needs to change its address again, tNMEA2000::AddressChanged will be set. So you can e.g. in every 10 min check has address changed and if it has, save it.
true | Some device source address changed. Read new values and save them. |
false | Nothing changed, no further actions required. |
Check if this device has changed its DeviceInstances or SystemInstance. With this function you can check has your device device instances or system instances changed.
true | Some device information changed. Read new values and save them. |
false | Nothing changed, no further actions required. |
Check if this device has changed its Install Description.
true | Installation description changed. Read new values and save them. |
false | Nothing changed, no further actions required. |
Set the count of devices library shows on bus. With this function you can enable multi device support. As default there is only one device.
_DeviceCount | Maximum number of devices that can be hold in Devices |
Set incoming CAN message (tNMEA2000::N2kCANMsgBuf) buffer size. With this function you can set size of buffer, where system builds incoming messages. The default size is 5 messages. Some messages are just single frame messages and they will be read in and handled immediately on call to ParseMessages. NMEA2000 fast packet message contains several frames sent sequentially. Anyway there can be other message frames between fast packet message frames, so these messages will be buffered and saved until all frames has been received. NMEA2000 requires that device should be able to read 2 concurrent fast packet and 2 ISO TP message. Since also single frame message requires one buffer slot buffer default size has been set to 5.
If buffer size is too small, there is risk that all fast packet messages will not be handled. Even your own logic does not listen any fast packet messages, internal logic listens group functions PGN 126208, which may contain important requests library should respond. If library does not respond to all required requests, there is risk that other devices drops your device information.
Since ISO TP messages are rarely used, with buffer size 5 library can handle 4 concurrent fast packet messages. Due to priorities this is enough in most cases. If bus has lot of devices sending fast packets and you have enough memory on MCU, you can increase buffer size. Buffer size 10 should be enough even on heavy traffic.
Function has to be called before communication opens. See tNMEA2000::Open().
Do not mix this with tNMEA2000::SetN2kCANReceiveFrameBufSize(), which has different meaning.
_MaxN2kCANMsgs | Number of CAN messages that can be stored in tNMEA2000::N2kCANMsgBuf |
Set CAN send frame buffer size. With this function you can set size of buffer, where system saves frames of messages to be sent. Given buffer size will be devided to driver buffer and library buffer. Driver buffer will empty by driver interrupt and library buffer by call to SendMsg or ParseMessages, which moves frames to driver buffer. If driver can handle large buffer, library buffer will be set to minimum.
When sending long messages like ProductInformation or GNSS data, there may not be enough buffers for successfully send data. This depends of your hw and device source. Device source has effect due to priority of getting sending time. If your data is critical, use buffer size, which is large enough (default 40 frames).
E.g. Product information takes totally 134 bytes. This needs 20 frames. If you also send GNSS 47 bytes=7 frames. If you want to be sure that both will be sent on any situation, you need at least 27 frame buffer size.
If you use this function, call it once before tNMEA2000::Open() and before any device related function like tNMEA2000::SetProductInformation. If you call it later, function has no effect.
Driver may override your setting, if you set too small or too large buffer size. This is driver dependent behaviour.
_MaxCANSendFrames | Maximum number of CAN frames that can be buffered in tNMEA2000::CANSendFrameBuf |
Set CAN receive frame buffer size. Some CAN drivers allows interrupted receive frame buffering. You can set receive buffer size with this function. If you use this function, call it once before tNMEA2000::Open();
Driver may override your setting, if you set too small or too large buffer size. This is driver dependent behaviour.
_MaxCANReceiveFrames | {type} |
Set the list of known Single Frame Messages. Call these if you wish to override the default message packets supported. Pointers must be in PROGMEM
As a default library has a list of known messages. With this function user can override default list of single frame messages.
Known single frame message lists has only effect if you limit handling with tNMEA2000::HandleOnlyKnownMessages or use message forwarding and limit it with tNMEA2000::SetForwardOnlyKnownMessages
_SingleFrameMessages | Buffer holding single frame messages |
Set the list of known Fast Packet Messages. Call these if you wish to override the default message packets supported. Pointers must be in PROGMEM
As a default library has a list of known messages. With this function user can override default list of fast packet messages. Build in default list contains all fastpackets found from open information.
_FastPacketMessages | Buffer holding fast packet messages |
Set the list of known Extended Single Frame Messages. Call these if you wish to add own list of supported message packets. Pointers must be in PROGMEM
As a default library has a list of known messages. With this function user can add own list of known single frame messages.
Known single frame message lists has only effect if you limit handling with tNMEA2000::HandleOnlyKnownMessages or use message forwarding and limit it with tNMEA2000::SetForwardOnlyKnownMessages
_SingleFrameMessages | Buffer holding single frame messages |
Set the list of known Extended Fast Packet Messages. Call these if you wish to extent list of fast packet messages. Pointers must be in PROGMEM
As a default library has a list of known messages. With this function user can extent default list of fast packet messages.
_FastPacketMessages | Buffer holding extended fast packet messages |
This is automatically used by class. You only need to use this, if you want to write your own behavior for address claiming.
This is automatically used by class. You only need to use this, if you want to write your own behavior for providing product information.
This is automatically used by class. You only need to use this, if you want to write your own behavior for providing configuration information.
Set the Heartbeat Interval and Offset for a device. Library will automatically start heartbeat with default interval 60 s and offset 10 s.
According to document NMEA Heartbeat Corrigendum all NMEA devices shall transmit heartbeat PGN 126993. With this function you can set transmission interval in ms (range 1000-655320ms , default 60000). Set interval 0 to disable heartbeat
Function allows to set interval over 60 s or 0 to disable sending for test purposes.
interval | Heartbeat Interval in ms. 0xffffffff=keep current, 0xfffffffe=restore default |
offset | Heartbeat Offset in ms. 0xffffffff=keep current, 0xfffffffe=restore default |
iDev | Index of the device on Devices or -1 to set for all. |
Get the Heartbeat Interval of a device. Heartbeat interval may be changed by e.g. MFD by group function. I have not yet found should changed value be saved for next startup or not.
iDev | index of the device on Devices |
uint_32 | Device heartbeat interval in ms |
Library will automatically send heartbeat, if interval is >0. You can also manually send it any time or force sent, if interval=0;
Set the Forward Streaming Type. With this function user can set how messages will be forwarded to the stream. Possible values are:
fwdType | Format type see tNMEA2000::tForwardType, default = fwdt_Actisense |
Set the Forward Stream object. As default, forward stream has been set to null. For e.g. Arduino Due you can set it to SerialUSB, so you can use Serial for other things. You can of coarse use any stream available on your device.
See example ActisenseListenerSender.ino.
_stream | Stream to be used for message forwarding |
Open the CAN device. You can call this on Setup(). It will be called anyway automatically by first call of tNMEA2000::ParseMessages(). When system is finally opened, OnOpen callback will be executed. See tNMEA2000::SetOnOpen
true | |
false |
Enable message forwarding to stream. Set true as default. With this you can control if bus messages will be forwarded to forward stream.
v | Enable, default = true |
Enable System Messages for forwarding. Set true as default. With this you can control if system messages like address claiming, device information will be forwarded to forward stream. If you set this false, system messages will not be forwarded to the stream.
v | Enable, default = true |
Enable Only Known Messages for forwarding. Set false as default. With this you can control if unknown messages will be forwarded to forward stream. If you set this true, all unknown message will not be forwarded to the stream.
v | Enable, default = false |
Enable Own Messages for forwarding. Set true as default. With this you can control if messages your device sends to bus will be forwarded to forward stream.
v | Enable, default = true |
Set the Handle Only Known Messages. Set false as default. With this you can control if unknown messages will be handled at all. Known messages are listed on library.
v | Enable, default = false |
Set the Debug Mode of the system. If you do not have physical N2k bus connection and you like to test your board without even CAN controller, you can use this function.
_dbMode | Debug mode, see tNMEA2000::tDebugMode |