diff --git a/Documents/NMEA2000_library_reference.pdf b/Documents/NMEA2000_library_reference.pdf index 1e2ae541..d759eb9c 100644 Binary files a/Documents/NMEA2000_library_reference.pdf and b/Documents/NMEA2000_library_reference.pdf differ diff --git a/Examples/TemperatureMonitor/TemperatureMonitor.ino b/Examples/TemperatureMonitor/TemperatureMonitor.ino index c7692bfe..a7bd8909 100644 --- a/Examples/TemperatureMonitor/TemperatureMonitor.ino +++ b/Examples/TemperatureMonitor/TemperatureMonitor.ino @@ -4,19 +4,22 @@ #include // This will automatically choose right CAN library and create suitable NMEA2000 object #include +// List here messages your device will transmit. +const unsigned long TransmitMessages[] PROGMEM={130310L,130311L,130312L,0}; + void setup() { // Set Product information NMEA2000.SetProductInformation("00000001", // Manufacturer's Model serial code 100, // Manufacturer's product code "Simple temp monitor", // Manufacturer's Model ID - "1.0.0.11 (2015-08-03)", // Manufacturer's Software version code - "1.0.0.0 (2015-08-03)" // Manufacturer's Model version + "1.1.0.20 (2016-12-20)", // Manufacturer's Software version code + "1.1.0.0 (2016-12-20)" // Manufacturer's Model version ); // Det device information - NMEA2000.SetDeviceInformation(1, // Unique number. Use e.g. Serial number. + NMEA2000.SetDeviceInformation(112233, // Unique number. Use e.g. Serial number. 130, // Device function=Temperature. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf 75, // Device class=Sensor Communication Interface. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf - 2046 // Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf + 2040 // Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf ); // Uncomment 3 rows below to see, what device will send to bus Serial.begin(115200); @@ -27,6 +30,7 @@ void setup() { NMEA2000.SetMode(tNMEA2000::N2km_NodeOnly,22); //NMEA2000.SetDebugMode(tNMEA2000::dm_Actisense); // Uncomment this, so you can test code without CAN bus chips on Arduino Mega NMEA2000.EnableForward(false); // Disable all msg forwarding to USB (=Serial) + NMEA2000.ExtendTransmitMessages(TransmitMessages); NMEA2000.Open(); } @@ -37,7 +41,7 @@ void loop() { } double ReadCabinTemp() { - return CToKelvin(21.0); // Read here the true temperature e.g. from analog input + return 100.0; //CToKelvin(100.0); // Read here the true temperature e.g. from analog input } double ReadWaterTemp() { diff --git a/Examples/WindMonitor/WindMonitor.ino b/Examples/WindMonitor/WindMonitor.ino index 2a950615..435e9076 100644 --- a/Examples/WindMonitor/WindMonitor.ino +++ b/Examples/WindMonitor/WindMonitor.ino @@ -4,13 +4,16 @@ #include // This will automatically choose right CAN library and create suitable NMEA2000 object #include +// List here messages your device will transmit. +const unsigned long TransmitMessages[] PROGMEM={130306L,0}; + void setup() { // Set Product information NMEA2000.SetProductInformation("00000002", // Manufacturer's Model serial code 100, // Manufacturer's product code "Simple wind monitor", // Manufacturer's Model ID - "1.0.0.11 (2015-11-10)", // Manufacturer's Software version code - "1.0.0.0 (2015-11-10)" // Manufacturer's Model version + "1.1.0.21 (2016-12-20)", // Manufacturer's Software version code + "1.1.0.0 (2016-12-20)" // Manufacturer's Model version ); // Det device information NMEA2000.SetDeviceInformation(1, // Unique number. Use e.g. Serial number. @@ -27,6 +30,7 @@ void setup() { NMEA2000.SetMode(tNMEA2000::N2km_NodeOnly,23); // NMEA2000.SetDebugMode(tNMEA2000::dm_Actisense); // Uncomment this, so you can test code without CAN bus chips on Arduino Mega NMEA2000.EnableForward(false); + NMEA2000.ExtendTransmitMessages(TransmitMessages); NMEA2000.Open(); } diff --git a/NMEA2000.cpp b/NMEA2000.cpp index 171fb9fd..1ebb00f7 100644 --- a/NMEA2000.cpp +++ b/NMEA2000.cpp @@ -32,12 +32,27 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // lenght >=90 #define Max_conf_info_field_len 80 +const unsigned long DefTransmitMessages[] PROGMEM = { + 59392L /*ISO Acknowledgement*/, + 59904L /*ISO Request*/, + 60928L /*ISO Address Claim*/, + 126464L, /* PGN List (Transmit and Receive) */ + 126996L, /* Product information */ + 126998L, /* Configuration information */ + 0}; +const unsigned long DefReceiveMessages[] PROGMEM = { + 59392L /*ISO Acknowledgement*/, + 59904L /*ISO Request*/, + 60928L /*ISO Address Claim*/, + 0}; const unsigned long SingleFrameSystemMessages[] PROGMEM = { 59392L /*ISO Acknowledgement*/, - 59904L /*ISO Request*/, 60928L /*ISO Address Claim*/, + 59904L /*ISO Request*/, + 60928L /*ISO Address Claim*/, 0}; const unsigned long FastPacketSystemMessages[] PROGMEM = { - 126208L, + 126208L, /* NMEA - Request group function */ + 126464L, /* PGN List (Transmit and Receive) */ 0}; const unsigned long DefSingleFrameMessages[] PROGMEM = { 126992L, // System date/time @@ -120,6 +135,9 @@ void ClearSetCharBuf(const char *str, int MaxLen, char *buf) { //***************************************************************************** tNMEA2000::tNMEA2000() { + TransmitMessages=0; + ReceiveMessages=0; + SingleFrameMessages[0]=DefSingleFrameMessages; FastPacketMessages[0]=DefFastPacketMessages; for (int i=1; imillis()) ) return false; // Do not send during address claiming - if (N2kMsg.DataLen<=8) { // We can send single frame -// PrintBuf(ForwardStream,N2kMsg.DataLen, N2kMsg.Data,true); + if (N2kMsg.DataLen<=8 && !IsFastPacket(N2kMsg.PGN) ) { // We can send single frame + PrintBuf(ForwardStream,N2kMsg.DataLen, N2kMsg.Data,true); result=SendFrame(canId, N2kMsg.DataLen, N2kMsg.Data,false); if (!result && ForwardStream!=0 && ForwardType==tNMEA2000::fwdt_Text) { ForwardStream->print(F("PGN ")); ForwardStream->print(N2kMsg.PGN); ForwardStream->println(F(" send failed")); } } else { // Send it as fast packet in multiple frames @@ -481,6 +509,27 @@ void tNMEA2000::SetDebugMode(tDebugMode _dbMode) { dbMode=_dbMode; } +//***************************************************************************** +bool tNMEA2000::IsFastPacket(unsigned long PGN) { + int i; + + for (i=0; pgm_read_dword(&FastPacketSystemMessages[i])!=PGN && pgm_read_dword(&FastPacketSystemMessages[i])!=0; i++); + if (pgm_read_dword(&FastPacketSystemMessages[i])==PGN) { + return true; + } + + for (unsigned char igroup=0; (igroup void PROGMEM_readAnything (const T * sce, T& dest) } +//***************************************************************************** +void tNMEA2000::HandlePGNListRequest(unsigned char Destination, int DeviceIndex) { + if (Destination==0xff && DeviceIndex==-1) DeviceIndex=0; + + if ( DeviceIndex<0 || DeviceIndex>=DeviceCount) return; + + tN2kMsg RespondMsg(DeviceInformation[DeviceIndex].N2kSource); + unsigned long PGN; + + // First sent transmit messages + RespondMsg.Destination=Destination; + RespondMsg.SetPGN(126464L); + RespondMsg.Priority=6; + RespondMsg.AddByte(tN2kPGNList::N2kpgnl_transmit); + // First add default messages + for (int i=0; (PGN=pgm_read_dword(&DefTransmitMessages[i]))!=0; i++) { + RespondMsg.Add3ByteInt(PGN); + } + if (TransmitMessages!=0) { + for (int i=0; (PGN=pgm_read_dword(&TransmitMessages[i]))!=0; i++) { + RespondMsg.Add3ByteInt(PGN); + } + } + SendMsg(RespondMsg,DeviceIndex); + + // Then add receive messages + RespondMsg.Clear(); + RespondMsg.SetPGN(126464L); + RespondMsg.AddByte(tN2kPGNList::N2kpgnl_receive); + // First add default messages + for (int i=0; (PGN=pgm_read_dword(&DefReceiveMessages[i]))!=0; i++) { + RespondMsg.Add3ByteInt(PGN); + } + if (ReceiveMessages!=0) { + for (int i=0; (PGN=pgm_read_dword(&ReceiveMessages[i]))!=0; i++) { + RespondMsg.Add3ByteInt(PGN); + } + } + SendMsg(RespondMsg,DeviceIndex); +} + //***************************************************************************** void SetN2kPGN126996Progmem(tN2kMsg &N2kMsg, const tProductInformation *ProductInformation) { int i; @@ -749,6 +839,9 @@ void tNMEA2000::RespondISORequest(const tN2kMsg &N2kMsg, unsigned long Requested case 60928L: /*ISO Address Claim*/ // Someone is asking others to claim their addresses SendIsoAddressClaim(N2kMsg.Source,iDev); break; + case 126464L: + HandlePGNListRequest(N2kMsg.Source,iDev); + break; case 126996L: /* Product information */ // If query was for us, try to respond immediately if ( ( N2kMsg.Destination!=DeviceInformation[iDev].N2kSource ) || !SendProductInformation(iDev) ) { @@ -1021,10 +1114,24 @@ void SetN2kPGN59904(tN2kMsg &N2kMsg, uint8_t Destination, unsigned long Requeste bool ParseN2kPGN59904(const tN2kMsg &N2kMsg, unsigned long &RequestedPGN) { int result=((N2kMsg.DataLen>=3) && (N2kMsg.DataLen<=8)); RequestedPGN=0; - if (result) { RequestedPGN=((unsigned long)N2kMsg.Data[2])<<16 | ((unsigned long)N2kMsg.Data[1]) << 8 | ((unsigned long)N2kMsg.Data[0]); } return result; } + +//***************************************************************************** +// PGN List (Transmit and Receive) +void SetN2kPGN126464(tN2kMsg &N2kMsg, uint8_t Destination, tN2kPGNList tr, const unsigned long *PGNs) { + unsigned long PGN; + + N2kMsg.SetPGN(126464L); + N2kMsg.Destination=Destination; + N2kMsg.Priority=6; + N2kMsg.AddByte(tr); + + for (int i=0; (PGN=pgm_read_dword(&PGNs[i]))!=0; i++) { + N2kMsg.Add3ByteInt(PGN); + } +} diff --git a/NMEA2000.h b/NMEA2000.h index cfb735ec..a593aab9 100644 --- a/NMEA2000.h +++ b/NMEA2000.h @@ -195,7 +195,10 @@ class tNMEA2000 const unsigned long *SingleFrameMessages[N2kMessageGroups]; const unsigned long *FastPacketMessages[N2kMessageGroups]; - + + // Transmit and receive PGNs + const unsigned long *TransmitMessages; + const unsigned long *ReceiveMessages; class tCANSendFrame { @@ -242,10 +245,12 @@ class tNMEA2000 protected: int SetN2kCANBufMsg(unsigned long canId, unsigned char len, unsigned char *buf); + bool IsFastPacket(unsigned long PGN); bool CheckKnownMessage(unsigned long PGN, bool &SystemMessage, bool &FastPacket); bool HandleReceivedSystemMessage(int MsgIndex); void ForwardMessage(const tN2kMsg &N2kMsg); void ForwardMessage(const tN2kCANMsg &N2kCanMsg); + void HandlePGNListRequest(unsigned char Destination, int DeviceIndex); void RespondISORequest(const tN2kMsg &N2kMsg, unsigned long RequestedPGN, int iDev); void HandleISORequest(const tN2kMsg &N2kMsg); void HandleISOAddressClaim(const tN2kMsg &N2kMsg); @@ -310,6 +315,11 @@ class tNMEA2000 // Note that currently subsequent calls will override previously set list. void ExtendSingleFrameMessages(const unsigned long *_SingleFrameMessages); void ExtendFastPacketMessages (const unsigned long *_FastPacketMessages); + // Define information about PGNs, what your system can handle. Pointers must be in PROGMEM + // As default for request to PGN list library responds with default messages it handles intenally. + // With these messages you can extent that list. See example TemperatureMonitor + void ExtendTransmitMessages(const unsigned long *_SingleFrameMessages); + void ExtendReceiveMessages (const unsigned long *_FastPacketMessages); // Set default device information. // For keeping defaults use 0xffff/0xff for int/char values and nul ptr for pointers. @@ -472,4 +482,17 @@ inline bool ParseN2kPGNISORequest(const tN2kMsg &N2kMsg, unsigned long &Requeste return ParseN2kPGN59904(N2kMsg, RequestedPGN); } +enum tN2kPGNList {N2kpgnl_transmit=0, N2kpgnl_receive=1 }; + +//***************************************************************************** +// PGN List (Transmit and Receive) +// List of PGNs must be null terminated and +// defined as PROGMEM e.g. const unsigned long TransmitMessages[] PROGMEM={130310L,0}; +void SetN2kPGN126464(tN2kMsg &N2kMsg, uint8_t Destination, tN2kPGNList tr, const unsigned long *PGNs); + +inline void SetN2kPGNTransmitList(tN2kMsg &N2kMsg, uint8_t Destination, const unsigned long *PGNs) { + SetN2kPGN126464(N2kMsg,Destination,tN2kPGNList::N2kpgnl_transmit,PGNs); +} + + #endif diff --git a/README.adoc b/README.adoc index bfcf984f..88b2bc37 100644 --- a/README.adoc +++ b/README.adoc @@ -32,6 +32,10 @@ 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 == +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!