convert RMC from 0183 to 2k, avoid cores

This commit is contained in:
andreas 2021-10-31 21:20:27 +01:00
parent c14ed4cfe9
commit 470dec92ad
6 changed files with 155 additions and 71 deletions

View File

@ -36,6 +36,7 @@ class GwBoatItemBase{
} }
virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime)=0; virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime)=0;
virtual size_t getJsonSize(){return JSON_OBJECT_SIZE(4);} virtual size_t getJsonSize(){return JSON_OBJECT_SIZE(4);}
virtual int getLastSource()=0;
}; };
class GwBoatData; class GwBoatData;
template<class T> class GwBoatItem : public GwBoatItemBase{ template<class T> class GwBoatItem : public GwBoatItemBase{
@ -75,6 +76,7 @@ template<class T> class GwBoatItem : public GwBoatItemBase{
o[F("source")]=lastUpdateSource; o[F("source")]=lastUpdateSource;
o[F("valid")]=isValid(minTime); o[F("valid")]=isValid(minTime);
} }
virtual int getLastSource(){return lastUpdateSource;}
}; };
static double formatCourse(double cv) static double formatCourse(double cv)

View File

@ -27,53 +27,19 @@ private:
pgn = NULL; pgn = NULL;
converter = NULL; converter = NULL;
} }
ConverterEntry(unsigned long pgn, LConverter cv) ConverterEntry(int num,unsigned long *pgn, LConverter cv)
{ {
lconverter = cv; lconverter = cv;
this->pgn = new unsigned long[1]; numPgn=num;
this->pgn[0] = pgn; this->pgn = pgn;
} }
ConverterEntry(unsigned long pgn, Converter cv = NULL) ConverterEntry(int num,unsigned long *pgn, Converter cv)
{ {
converter = cv; converter = cv;
numPgn = 1; numPgn=num;
this->pgn = new unsigned long[1]; this->pgn = pgn;
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, LConverter cv = NULL)
{
lconverter = 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;
}
ConverterEntry(unsigned long pgn1, unsigned long pgn2, unsigned long pgn3, LConverter cv = NULL)
{
lconverter = 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; typedef std::map<String, ConverterEntry> ConverterMap;
ConverterMap converters; ConverterMap converters;
@ -85,32 +51,62 @@ public:
**/ **/
void registerConverter(unsigned long pgn, Converter converter) void registerConverter(unsigned long pgn, Converter converter)
{ {
ConverterEntry e(pgn, converter); unsigned long *lpgn=new unsigned long[1]{pgn};
ConverterEntry e(1,lpgn, converter);
converters[String(pgn)] = e; converters[String(pgn)] = e;
} }
void registerConverter(unsigned long pgn, LConverter converter) void registerConverter(unsigned long pgn, LConverter converter)
{ {
ConverterEntry e(pgn, converter); unsigned long *lpgn=new unsigned long[1]{pgn};
ConverterEntry e(1,lpgn, converter);
converters[String(pgn)] = e; converters[String(pgn)] = e;
} }
void registerConverter(unsigned long pgn, String sentence, Converter converter) void registerConverter(unsigned long pgn, String sentence, Converter converter)
{ {
ConverterEntry e(pgn, converter); unsigned long *lpgn=new unsigned long[1]{pgn};
ConverterEntry e(1,lpgn, converter);
converters[sentence] = e; converters[sentence] = e;
} }
void registerConverter(unsigned long pgn, String sentence, LConverter converter) void registerConverter(unsigned long pgn, String sentence, LConverter converter)
{ {
ConverterEntry e(pgn, converter); unsigned long *lpgn=new unsigned long[1]{pgn};
ConverterEntry e(1,lpgn, converter);
converters[sentence] = e; converters[sentence] = e;
} }
void registerConverter(unsigned long pgn, unsigned long pgn2, String sentence, Converter converter) void registerConverter(unsigned long pgn, unsigned long pgn2, String sentence, Converter converter)
{ {
ConverterEntry e(pgn, pgn2, converter); unsigned long *lpgn=new unsigned long[2]{pgn,pgn2};
ConverterEntry e(2, lpgn, converter);
converters[sentence] = e; converters[sentence] = e;
} }
void registerConverter(unsigned long pgn, unsigned long pgn2, String sentence, LConverter converter) void registerConverter(unsigned long pgn, unsigned long pgn2, String sentence, LConverter converter)
{ {
ConverterEntry e(pgn, pgn2, converter); unsigned long *lpgn=new unsigned long[2]{pgn,pgn2};
ConverterEntry e(2, lpgn, converter);
converters[sentence] = e;
}
void registerConverter(unsigned long pgn, unsigned long pgn2, unsigned long pgn3,String sentence, Converter converter)
{
unsigned long *lpgn=new unsigned long[3]{pgn,pgn2,pgn3};
ConverterEntry e(3, lpgn,converter);
converters[sentence] = e;
}
void registerConverter(unsigned long pgn, unsigned long pgn2, unsigned long pgn3,String sentence, LConverter converter)
{
unsigned long *lpgn=new unsigned long[3]{pgn,pgn2,pgn3};
ConverterEntry e(3, lpgn,converter);
converters[sentence] = e;
}
void registerConverter(unsigned long pgn, unsigned long pgn2, unsigned long pgn3,unsigned long pgn4,String sentence, Converter converter)
{
unsigned long *lpgn=new unsigned long[4]{pgn,pgn2,pgn3,pgn4};
ConverterEntry e(4, lpgn,converter);
converters[sentence] = e;
}
void registerConverter(unsigned long pgn, unsigned long pgn2, unsigned long pgn3,unsigned long pgn4,String sentence, LConverter converter)
{
unsigned long *lpgn=new unsigned long[4]{pgn,pgn2,pgn3,pgn4};
ConverterEntry e(4, lpgn,converter);
converters[sentence] = e; converters[sentence] = e;
} }
@ -139,13 +135,13 @@ public:
virtual unsigned long *handledPgns() virtual unsigned long *handledPgns()
{ {
//for now max 3 pgns per converter //for now max 4 pgns per converter
unsigned long *rt = new unsigned long[converters.size() * 3 + 1]; unsigned long *rt = new unsigned long[converters.size() * 4 + 1];
int idx = 0; int idx = 0;
for (auto it = converters.begin(); for (auto it = converters.begin();
it != converters.end(); it++) it != converters.end(); it++)
{ {
for (int i = 0; i < it->second.numPgn && i < 3; i++) for (int i = 0; i < it->second.numPgn && i < 4; i++)
{ {
bool found = false; bool found = false;
for (int e = 0; e < idx; e++) for (int e = 0; e < idx; e++)

View File

@ -1,6 +1,8 @@
#include "NMEA0183DataToN2K.h" #include "NMEA0183DataToN2K.h"
#include "NMEA0183Messages.h" #include "NMEA0183Messages.h"
#include "N2kMessages.h"
#include "ConverterList.h" #include "ConverterList.h"
#include <map>
NMEA0183DataToN2K::NMEA0183DataToN2K(GwLog *logger, GwBoatData *boatData,N2kSender callback) NMEA0183DataToN2K::NMEA0183DataToN2K(GwLog *logger, GwBoatData *boatData,N2kSender callback)
{ {
this->sender = callback; this->sender = callback;
@ -14,47 +16,127 @@ bool NMEA0183DataToN2K::parseAndSend(const char *buffer, int sourceId) {
return false; return false;
} }
class SNMEA0183Msg {
public:
int sourceId;
const char *line;
tNMEA0183Msg msg;
};
class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K
{ {
private: private:
double dummy = 0; double dummy = 0;
ConverterList<NMEA0183DataToN2KFunctions, tNMEA0183Msg> converters; ConverterList<NMEA0183DataToN2KFunctions, SNMEA0183Msg> converters;
void createBoatData() std::map<unsigned long,unsigned long> lastSends;
{
bool send(tN2kMsg &msg,unsigned long minDiff=50){
unsigned long now=millis();
unsigned long pgn=msg.PGN;
auto it=lastSends.find(pgn);
if (it == lastSends.end()){
lastSends[pgn]=now;
sender(msg);
return true;
}
if ((it->second + minDiff) < now){
lastSends[pgn]=now;
sender(msg);
return true;
}
return false;
} }
void convertRMB(const tNMEA0183Msg &msg) bool updateDouble(GwBoatItem<double> *target,double v, int sourceId){
if (v != NMEA0183DoubleNA){
target->update(v,sourceId);
return true;
}
return false;
}
bool updateUint32(GwBoatItem<uint32_t> *target,uint32_t v, int sourceId){
if (v != NMEA0183UInt32NA){
target->update(v,sourceId);
return true;
}
return v;
}
uint32_t getUint32(GwBoatItem<uint32_t> *src){
return src->getDataWithDefault(N2kUInt32NA);
}
void convertRMB(const SNMEA0183Msg &msg)
{ {
LOG_DEBUG(GwLog::DEBUG + 1, "convert RMB"); LOG_DEBUG(GwLog::DEBUG + 1, "convert RMB");
} }
#define UD(item) updateDouble(boatData->item, item, msg.sourceId)
#define UI(item) updateUint32(boatData->item, item, msg.sourceId)
void convertRMC(const SNMEA0183Msg &msg)
{
double SecondsSinceMidnight=0, Latitude=0, Longitude=0, COG=0, SOG=0, Variation=0;
unsigned long DaysSince1970=0;
time_t DateTime;
char status;
if (!NMEA0183ParseRMC_nc(msg.msg, SecondsSinceMidnight, status, Latitude, Longitude, COG, SOG, DaysSince1970, Variation, &DateTime))
{
logger->logDebug(GwLog::DEBUG, "failed to parse RMC %s", msg.line);
return;
}
tN2kMsg n2kMsg;
if (
UD(SecondsSinceMidnight) &&
UI(DaysSince1970)
)
{
SetN2kSystemTime(n2kMsg, 1, DaysSince1970, SecondsSinceMidnight);
send(n2kMsg);
}
if (UD(Latitude) &&
UD(Longitude)){
SetN2kLatLonRapid(n2kMsg,Latitude,Longitude);
send(n2kMsg);
}
if (UD(COG) && UD(SOG)){
SetN2kCOGSOGRapid(n2kMsg,1,N2khr_true,COG,SOG);
send(n2kMsg);
}
if (UD(Variation)){
SetN2kMagneticVariation(n2kMsg,1,N2kmagvar_Calc,
getUint32(boatData->DaysSince1970), Variation);
send(n2kMsg);
}
}
//shortcut for lambda converters //shortcut for lambda converters
#define CVL [](const tNMEA0183Msg &msg, NMEA0183DataToN2KFunctions *p) -> void #define CVL [](const SNMEA0183Msg &msg, NMEA0183DataToN2KFunctions *p) -> void
void registerConverters() void registerConverters()
{ {
converters.registerConverter(129283UL, String(F("RMB")), &NMEA0183DataToN2KFunctions::convertRMB); converters.registerConverter(129283UL, String(F("RMB")), &NMEA0183DataToN2KFunctions::convertRMB);
converters.registerConverter( converters.registerConverter(
123UL, String(F("RMC")), CVL 126992UL,129025UL,129026UL,127258UL, String(F("RMC")),
{ &NMEA0183DataToN2KFunctions::convertRMC);
p->dummy++;
p->logger->logDebug(GwLog::DEBUG, "RMC converter");
});
} }
public: public:
virtual bool parseAndSend(const char *buffer, int sourceId) virtual bool parseAndSend(const char *buffer, int sourceId)
{ {
LOG_DEBUG(GwLog::DEBUG + 1, "NMEA0183DataToN2K[%d] parsing %s", sourceId, buffer) LOG_DEBUG(GwLog::DEBUG + 1, "NMEA0183DataToN2K[%d] parsing %s", sourceId, buffer)
tNMEA0183Msg msg; SNMEA0183Msg msg;
if (!msg.SetMessage(buffer)) msg.sourceId=sourceId;
msg.line=buffer;
if (!msg.msg.SetMessage(buffer))
{ {
LOG_DEBUG(GwLog::DEBUG, "NMEA0183DataToN2K[%d] invalid message %s", sourceId, buffer) LOG_DEBUG(GwLog::DEBUG, "NMEA0183DataToN2K[%d] invalid message %s", sourceId, buffer)
return false; return false;
} }
String code = msg.MessageCode(); String code = msg.msg.MessageCode();
bool rt = converters.handleMessage(code, msg, this); bool rt = converters.handleMessage(code, msg, this);
if (!rt) if (!rt)
{ {
LOG_DEBUG(GwLog::DEBUG, "NMEA0183DataToN2K[%d] no handler for %s", sourceId, buffer); LOG_DEBUG(GwLog::DEBUG, "NMEA0183DataToN2K[%d] no handler for %s", sourceId, buffer);
} }
else{
LOG_DEBUG(GwLog::DEBUG+1, "NMEA0183DataToN2K[%d] handler done ", sourceId);
}
return rt; return rt;
} }
@ -66,7 +148,6 @@ public:
NMEA0183DataToN2KFunctions(GwLog *logger, GwBoatData *boatData, N2kSender callback) NMEA0183DataToN2KFunctions(GwLog *logger, GwBoatData *boatData, N2kSender callback)
: NMEA0183DataToN2K(logger, boatData, callback) : NMEA0183DataToN2K(logger, boatData, callback)
{ {
createBoatData();
registerConverters(); registerConverters();
LOG_DEBUG(GwLog::LOG, "NMEA0183DataToN2KFunctions: registered %d converters", converters.numConverters()); LOG_DEBUG(GwLog::LOG, "NMEA0183DataToN2KFunctions: registered %d converters", converters.numConverters());
} }

View File

@ -48,7 +48,6 @@ void N2kDataToNMEA0183::loop() {
//***************************************************************************** //*****************************************************************************
void N2kDataToNMEA0183::SendMessage(const tNMEA0183Msg &NMEA0183Msg) { void N2kDataToNMEA0183::SendMessage(const tNMEA0183Msg &NMEA0183Msg) {
if ( pNMEA0183 != 0 ) pNMEA0183->SendMessage(NMEA0183Msg);
if ( SendNMEA0183MessageCallback != 0 ) SendNMEA0183MessageCallback(NMEA0183Msg, sourceId); if ( SendNMEA0183MessageCallback != 0 ) SendNMEA0183MessageCallback(NMEA0183Msg, sourceId);
} }
@ -340,7 +339,10 @@ private:
void SendRMC() void SendRMC()
{ {
long now = millis(); long now = millis();
if (NextRMCSend <= millis() && boatData->Latitude->isValid(now)) if (NextRMCSend <= millis() &&
boatData->Latitude->isValid(now) &&
boatData->Latitude->getLastSource() == sourceId
)
{ {
tNMEA0183Msg NMEA0183Msg; tNMEA0183Msg NMEA0183Msg;
if (NMEA0183SetRMC(NMEA0183Msg, if (NMEA0183SetRMC(NMEA0183Msg,

View File

@ -38,7 +38,6 @@ public:
protected: protected:
GwLog *logger; GwLog *logger;
GwBoatData *boatData; GwBoatData *boatData;
tNMEA0183 *pNMEA0183;
int sourceId; int sourceId;
tSendNMEA0183MessageCallback SendNMEA0183MessageCallback; tSendNMEA0183MessageCallback SendNMEA0183MessageCallback;
void SendMessage(const tNMEA0183Msg &NMEA0183Msg); void SendMessage(const tNMEA0183Msg &NMEA0183Msg);

View File

@ -12,7 +12,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define VERSION "0.2.1" #define VERSION "0.3.1"
//#define GW_MESSAGE_DEBUG_ENABLED //#define GW_MESSAGE_DEBUG_ENABLED
//#define FALLBACK_SERIAL //#define FALLBACK_SERIAL
const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
@ -292,7 +293,8 @@ void setup() {
SendNMEA0183Message, N2K_CHANNEL_ID); SendNMEA0183Message, N2K_CHANNEL_ID);
toN2KConverter= NMEA0183DataToN2K::create(&logger,&boatData,[](const tN2kMsg &msg)->bool{ toN2KConverter= NMEA0183DataToN2K::create(&logger,&boatData,[](const tN2kMsg &msg)->bool{
logger.logDebug(GwLog::DEBUG+1,"send N2K"); logger.logDebug(GwLog::DEBUG+2,"send N2K %ld",msg.PGN);
NMEA2000.SendMsg(msg);
return true; return true;
}); });
@ -328,6 +330,7 @@ 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);
NMEA2000.SetForwardOwnMessages(false);
// Set the information for other bus devices, which messages we support // Set the information for other bus devices, which messages we support
NMEA2000.ExtendTransmitMessages(toN2KConverter->handledPgns()); NMEA2000.ExtendTransmitMessages(toN2KConverter->handledPgns());
NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns()); NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns());
@ -363,9 +366,10 @@ void sendBufferToChannels(const char * buffer, int sourceId){
//***************************************************************************** //*****************************************************************************
void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId) { void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId) {
if ( ! sendTCP->asBoolean() && ! sendUsb->asBoolean() ) return; if ( ! sendTCP->asBoolean() && ! sendUsb->asBoolean() ) return;
logger.logDebug(GwLog::DEBUG+2,"SendNMEA0183(1)");
char buf[MAX_NMEA0183_MESSAGE_SIZE+3]; char buf[MAX_NMEA0183_MESSAGE_SIZE+3];
if ( !NMEA0183Msg.GetMessage(buf, MAX_NMEA0183_MESSAGE_SIZE) ) return; if ( !NMEA0183Msg.GetMessage(buf, MAX_NMEA0183_MESSAGE_SIZE) ) return;
logger.logDebug(GwLog::DEBUG+2,"SendNMEA0183: %s",buf);
size_t len=strlen(buf); size_t len=strlen(buf);
buf[len]=0x0d; buf[len]=0x0d;
buf[len+1]=0x0a; buf[len+1]=0x0a;