Skip to content

Commit

Permalink
Added support for PGN 126464L
Browse files Browse the repository at this point in the history
  • Loading branch information
ttlappalainen committed Dec 20, 2016
1 parent 5d0e058 commit 8512745
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 13 deletions.
Binary file modified Documents/NMEA2000_library_reference.pdf
Binary file not shown.
14 changes: 9 additions & 5 deletions Examples/TemperatureMonitor/TemperatureMonitor.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@
#include <NMEA2000_CAN.h> // This will automatically choose right CAN library and create suitable NMEA2000 object
#include <N2kMessages.h>

// 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);
Expand All @@ -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();
}

Expand All @@ -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() {
Expand Down
8 changes: 6 additions & 2 deletions Examples/WindMonitor/WindMonitor.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
#include <NMEA2000_CAN.h> // This will automatically choose right CAN library and create suitable NMEA2000 object
#include <N2kMessages.h>

// 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.
Expand All @@ -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();
}

Expand Down
117 changes: 112 additions & 5 deletions NMEA2000.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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; i<N2kMessageGroups; i++) {SingleFrameMessages[i]=0; FastPacketMessages[i]=0;}
Expand Down Expand Up @@ -271,6 +289,16 @@ void tNMEA2000::ExtendFastPacketMessages(const unsigned long *_FastPacketMessage
FastPacketMessages[1]=_FastPacketMessages;
}

//*****************************************************************************
void tNMEA2000::ExtendTransmitMessages(const unsigned long *_Messages) {
TransmitMessages=_Messages;
}

//*****************************************************************************
void tNMEA2000::ExtendReceiveMessages(const unsigned long *_Messages) {
ReceiveMessages=_Messages;
}

//*****************************************************************************
void tNMEA2000::SetMode(tN2kMode _N2kMode, unsigned long _N2kSource) {
N2kMode=_N2kMode;
Expand Down Expand Up @@ -420,8 +448,8 @@ bool tNMEA2000::SendMsg(const tN2kMsg &N2kMsg, int DeviceIndex) {

if ( (AddressClaimStarted!=0) && (AddressClaimStarted+N2kAddressClaimTimeout>millis()) ) 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
Expand Down Expand Up @@ -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<N2kMessageGroups); igroup++) {
if (FastPacketMessages[igroup]!=0) {
for (i=0; pgm_read_dword(&FastPacketMessages[igroup][i])!=PGN && pgm_read_dword(&FastPacketMessages[igroup][i])!=0; i++);
if (pgm_read_dword(&FastPacketMessages[igroup][i])==PGN) {
return true;
}
}
}

return false;
}

//*****************************************************************************
bool tNMEA2000::CheckKnownMessage(unsigned long PGN, bool &SystemMessage, bool &FastPacket) {
int i;
Expand Down Expand Up @@ -645,6 +694,47 @@ template <typename T> 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;
Expand Down Expand Up @@ -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) ) {
Expand Down Expand Up @@ -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);
}
}
25 changes: 24 additions & 1 deletion NMEA2000.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
4 changes: 4 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down

0 comments on commit 8512745

Please sign in to comment.