intermediate: add nmea0183 to n2k
This commit is contained in:
parent
0b4aa58d71
commit
c8778e4ceb
|
@ -0,0 +1,132 @@
|
||||||
|
#include "NMEA0183DataToN2K.h"
|
||||||
|
#include "NMEA0183Messages.h"
|
||||||
|
NMEA0183DataToN2K::NMEA0183DataToN2K(GwLog *logger, GwBoatData *boatData,N2kSender callback)
|
||||||
|
{
|
||||||
|
this->sender = callback;
|
||||||
|
this->logger = logger;
|
||||||
|
this->boatData=boatData;
|
||||||
|
LOG_DEBUG(GwLog::LOG,"NMEA0183DataToN2K created %p",this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NMEA0183DataToN2K::parseAndSend(const char *buffer, int sourceId) {
|
||||||
|
LOG_DEBUG(GwLog::DEBUG,"NMEA0183DataToN2K[%d] parsing %s",sourceId,buffer)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K{
|
||||||
|
public:
|
||||||
|
typedef void (NMEA0183DataToN2KFunctions::*Converter)(const tNMEA0183Msg &msg);
|
||||||
|
private:
|
||||||
|
class ConverterEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unsigned long count = 0;
|
||||||
|
unsigned long *pgn;
|
||||||
|
unsigned int numPgn=0;
|
||||||
|
Converter converter;
|
||||||
|
ConverterEntry(){
|
||||||
|
pgn=NULL;
|
||||||
|
converter=NULL;
|
||||||
|
}
|
||||||
|
ConverterEntry(unsigned long pgn,Converter cv = NULL) {
|
||||||
|
converter = cv;
|
||||||
|
numPgn=1;
|
||||||
|
this->pgn=new unsigned long[1];
|
||||||
|
this->pgn[0]=pgn;
|
||||||
|
}
|
||||||
|
ConverterEntry(unsigned long pgn1,unsigned long pgn2,Converter cv = NULL) {
|
||||||
|
converter = cv;
|
||||||
|
numPgn=2;
|
||||||
|
this->pgn=new unsigned long[2];
|
||||||
|
this->pgn[0]=pgn1;
|
||||||
|
this->pgn[1]=pgn2;
|
||||||
|
}
|
||||||
|
ConverterEntry(unsigned long pgn1,unsigned long pgn2,unsigned long pgn3,Converter cv = NULL) {
|
||||||
|
converter = cv;
|
||||||
|
numPgn=3;
|
||||||
|
this->pgn=new unsigned long[3];
|
||||||
|
this->pgn[0]=pgn1;
|
||||||
|
this->pgn[1]=pgn2;
|
||||||
|
this->pgn[2]=pgn3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef std::map<String, ConverterEntry> ConverterMap;
|
||||||
|
ConverterMap converters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register a converter
|
||||||
|
* each of the converter functions must be registered in the constructor
|
||||||
|
**/
|
||||||
|
void registerConverter(unsigned long pgn, String sentence,Converter converter)
|
||||||
|
{
|
||||||
|
ConverterEntry e(pgn,converter);
|
||||||
|
converters[sentence] = e;
|
||||||
|
}
|
||||||
|
void registerConverter(unsigned long pgn,unsigned long pgn2, String sentence,Converter converter)
|
||||||
|
{
|
||||||
|
ConverterEntry e(pgn,pgn2,converter);
|
||||||
|
converters[sentence] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertRMB(const tNMEA0183Msg &msg){
|
||||||
|
LOG_DEBUG(GwLog::DEBUG+1,"convert RMB");
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual bool parseAndSend(const char *buffer, int sourceId) {
|
||||||
|
LOG_DEBUG(GwLog::DEBUG+1,"NMEA0183DataToN2K[%d] parsing %s",sourceId,buffer)
|
||||||
|
tNMEA0183Msg msg;
|
||||||
|
if (! msg.SetMessage(buffer)){
|
||||||
|
LOG_DEBUG(GwLog::DEBUG,"NMEA0183DataToN2K[%d] invalid message %s",sourceId,buffer)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String code=String(msg.MessageCode());
|
||||||
|
ConverterMap::iterator it=converters.find(code);
|
||||||
|
if (it != converters.end()){
|
||||||
|
(it->second).count++;
|
||||||
|
//call to member function - see e.g. https://isocpp.org/wiki/faq/pointers-to-members
|
||||||
|
((*this).*((it->second).converter))(msg);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
LOG_DEBUG(GwLog::DEBUG,"NMEA0183DataToN2K[%d] no handler for %s",sourceId,code.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual unsigned long *handledPgns()
|
||||||
|
{
|
||||||
|
logger->logString("CONV: # %d handled PGNS", (int)converters.size());
|
||||||
|
//for now max 3 pgns per converter
|
||||||
|
unsigned long *rt = new unsigned long[converters.size() *3 + 1];
|
||||||
|
int idx = 0;
|
||||||
|
for (ConverterMap::iterator it = converters.begin();
|
||||||
|
it != converters.end(); it++)
|
||||||
|
{
|
||||||
|
for (int i=0;i<it->second.numPgn && i < 3;i++){
|
||||||
|
bool found=false;
|
||||||
|
for (int e=0;e<idx;e++){
|
||||||
|
if (rt[e] == it->second.pgn[i]){
|
||||||
|
found=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! found){
|
||||||
|
rt[idx] = it->second.pgn[i];
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rt[idx] = 0;
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
NMEA0183DataToN2KFunctions(GwLog *logger,GwBoatData *boatData,N2kSender callback)
|
||||||
|
:NMEA0183DataToN2K(logger,boatData,callback){
|
||||||
|
registerConverter(129283UL,String(F("RMB")),&NMEA0183DataToN2KFunctions::convertRMB);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
NMEA0183DataToN2K* NMEA0183DataToN2K::create(GwLog *logger,GwBoatData *boatData,N2kSender callback){
|
||||||
|
return new NMEA0183DataToN2KFunctions(logger, boatData,callback);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef _NMEA0183DATATON2K_H
|
||||||
|
#define _NMEA0183DATATON2K_H
|
||||||
|
#include "GwLog.h"
|
||||||
|
#include "GwBoatData.h"
|
||||||
|
#include "N2kMessages.h"
|
||||||
|
|
||||||
|
class NMEA0183DataToN2K{
|
||||||
|
public:
|
||||||
|
typedef bool (*N2kSender)(const tN2kMsg &msg);
|
||||||
|
protected:
|
||||||
|
GwLog * logger;
|
||||||
|
GwBoatData *boatData;
|
||||||
|
N2kSender sender;
|
||||||
|
public:
|
||||||
|
NMEA0183DataToN2K(GwLog *logger,GwBoatData *boatData,N2kSender callback);
|
||||||
|
virtual bool parseAndSend(const char *buffer, int sourceId);
|
||||||
|
virtual unsigned long *handledPgns()=0;
|
||||||
|
static NMEA0183DataToN2K* create(GwLog *logger,GwBoatData *boatData,N2kSender callback);
|
||||||
|
};
|
||||||
|
#endif
|
25
src/main.cpp
25
src/main.cpp
|
@ -41,6 +41,7 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
|
||||||
#include "GwMessage.h"
|
#include "GwMessage.h"
|
||||||
#include "GwSerial.h"
|
#include "GwSerial.h"
|
||||||
#include "GwWebServer.h"
|
#include "GwWebServer.h"
|
||||||
|
#include "NMEA0183DataToN2K.h"
|
||||||
|
|
||||||
|
|
||||||
//NMEA message channels
|
//NMEA message channels
|
||||||
|
@ -70,11 +71,8 @@ int NodeAddress; // To store last Node Address
|
||||||
|
|
||||||
Preferences preferences; // Nonvolatile storage on ESP32 - To store LastDeviceAddress
|
Preferences preferences; // Nonvolatile storage on ESP32 - To store LastDeviceAddress
|
||||||
N2kDataToNMEA0183 *nmea0183Converter=NULL;
|
N2kDataToNMEA0183 *nmea0183Converter=NULL;
|
||||||
|
NMEA0183DataToN2K *toN2KConverter=NULL;
|
||||||
|
|
||||||
// Set the information for other bus devices, which messages we support
|
|
||||||
const unsigned long TransmitMessages[] PROGMEM = {127489L, // Engine dynamic
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg,int id);
|
void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg,int id);
|
||||||
|
|
||||||
|
@ -86,6 +84,8 @@ GwConfigInterface *sendUsb=NULL;
|
||||||
GwConfigInterface *sendTCP=NULL;
|
GwConfigInterface *sendTCP=NULL;
|
||||||
GwConfigInterface *sendSeasmart=NULL;
|
GwConfigInterface *sendSeasmart=NULL;
|
||||||
GwConfigInterface *systemName=NULL;
|
GwConfigInterface *systemName=NULL;
|
||||||
|
GwConfigInterface *n2kFromUSB=NULL;
|
||||||
|
GwConfigInterface *n2kFromTCP=NULL;
|
||||||
|
|
||||||
GwSerial usbSerial(NULL, UART_NUM_0, USB_CHANNEL_ID);
|
GwSerial usbSerial(NULL, UART_NUM_0, USB_CHANNEL_ID);
|
||||||
class GwSerialLog : public GwLogWriter{
|
class GwSerialLog : public GwLogWriter{
|
||||||
|
@ -254,6 +254,8 @@ void setup() {
|
||||||
sendTCP=config.getConfigItem(config.sendTCP,true);
|
sendTCP=config.getConfigItem(config.sendTCP,true);
|
||||||
sendSeasmart=config.getConfigItem(config.sendSeasmart,true);
|
sendSeasmart=config.getConfigItem(config.sendSeasmart,true);
|
||||||
systemName=config.getConfigItem(config.systemName,true);
|
systemName=config.getConfigItem(config.systemName,true);
|
||||||
|
n2kFromTCP=config.getConfigItem(config.tcpToN2k,true);
|
||||||
|
n2kFromUSB=config.getConfigItem(config.usbToN2k,true);
|
||||||
MDNS.begin(config.getConfigItem(config.systemName)->asCString());
|
MDNS.begin(config.getConfigItem(config.systemName)->asCString());
|
||||||
gwWifi.setup();
|
gwWifi.setup();
|
||||||
|
|
||||||
|
@ -289,6 +291,11 @@ void setup() {
|
||||||
nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData,&NMEA2000,
|
nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData,&NMEA2000,
|
||||||
SendNMEA0183Message, N2K_CHANNEL_ID);
|
SendNMEA0183Message, N2K_CHANNEL_ID);
|
||||||
|
|
||||||
|
toN2KConverter= NMEA0183DataToN2K::create(&logger,&boatData,[](const tN2kMsg &msg)->bool{
|
||||||
|
logger.logDebug(GwLog::DEBUG+1,"send N2K");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
NMEA2000.SetN2kCANMsgBufSize(8);
|
NMEA2000.SetN2kCANMsgBufSize(8);
|
||||||
NMEA2000.SetN2kCANReceiveFrameBufSize(250);
|
NMEA2000.SetN2kCANReceiveFrameBufSize(250);
|
||||||
NMEA2000.SetN2kCANSendFrameBufSize(250);
|
NMEA2000.SetN2kCANSendFrameBufSize(250);
|
||||||
|
@ -321,8 +328,8 @@ void setup() {
|
||||||
logger.logDebug(GwLog::LOG,"NodeAddress=%d\n", NodeAddress);
|
logger.logDebug(GwLog::LOG,"NodeAddress=%d\n", NodeAddress);
|
||||||
|
|
||||||
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress);
|
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress);
|
||||||
|
// Set the information for other bus devices, which messages we support
|
||||||
NMEA2000.ExtendTransmitMessages(TransmitMessages);
|
NMEA2000.ExtendTransmitMessages(toN2KConverter->handledPgns());
|
||||||
NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns());
|
NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns());
|
||||||
NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){
|
NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){
|
||||||
numCan++;
|
numCan++;
|
||||||
|
@ -367,8 +374,10 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleReceivedNmeaMessage(const char *buf, int sourceId){
|
void handleReceivedNmeaMessage(const char *buf, int sourceId){
|
||||||
//TODO - for now only send out again
|
if ((sourceId == USB_CHANNEL_ID && n2kFromUSB->asBoolean())||
|
||||||
//add the conversion to N2K here
|
(sourceId >= MIN_TCP_CHANNEL_ID && n2kFromTCP->asBoolean())
|
||||||
|
)
|
||||||
|
toN2KConverter->parseAndSend(buf,sourceId);
|
||||||
sendBufferToChannels(buf,sourceId);
|
sendBufferToChannels(buf,sourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,13 @@
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "receive NMEA data on the USB port"
|
"description": "receive NMEA data on the USB port"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "usbToN2k",
|
||||||
|
"label": "USB to NMEA2000",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "convert NMEA0183 from the USB port to NMEA2000"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "serverPort",
|
"name": "serverPort",
|
||||||
"label": "TCP port",
|
"label": "TCP port",
|
||||||
|
@ -53,11 +60,18 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "readTCP",
|
"name": "readTCP",
|
||||||
"label": "NMEA from TCP",
|
"label": "TCP to NMEA2000",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "receive NMEA data from connected TCP clients"
|
"description": "receive NMEA data from connected TCP clients"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "tcpToN2k",
|
||||||
|
"label": "NMEA from TCP",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "convert NMEA0183 from TCP clients to NMEA2000"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "sendSeasmart",
|
"name": "sendSeasmart",
|
||||||
"label": "Seasmart to TCP",
|
"label": "Seasmart to TCP",
|
||||||
|
|
Loading…
Reference in New Issue