#75: untested/intermediate - add some mappings for the pgn 130306 wind reference

This commit is contained in:
andreas 2024-10-06 20:06:15 +02:00
parent c266bddea3
commit 3c664b1480
5 changed files with 195 additions and 35 deletions

View File

@ -16,16 +16,62 @@
#define _GWCONVERTERCONFIG_H #define _GWCONVERTERCONFIG_H
#include "GWConfig.h" #include "GWConfig.h"
#include "N2kTypes.h"
#include <map>
//list of configs for the PGN 130306 wind references
static std::map<tN2kWindReference,String> windConfigs={
{N2kWind_True_water,GwConfigDefinitions::windmtra},
{N2kWind_Apparent,GwConfigDefinitions::windmawa},
{N2kWind_True_boat,GwConfigDefinitions::windmgna},
{N2kWind_Magnetic,GwConfigDefinitions::windmmgd},
{N2kWind_True_North,GwConfigDefinitions::windmtng},
};
class GwConverterConfig{ class GwConverterConfig{
public: public:
class WindMapping{
public:
using Wind0183Type=enum{
AWA_AWS,
TWA_TWS,
TWD_TWS,
GWA_GWS,
GWD_GWS
};
tN2kWindReference n2kType;
Wind0183Type nmea0183Type;
bool valid=false;
WindMapping(){}
WindMapping(const tN2kWindReference &n2k,const Wind0183Type &n183):
n2kType(n2k),nmea0183Type(n183),valid(true){}
WindMapping(const tN2kWindReference &n2k,const String &n183):
n2kType(n2k){
if (n183 == "twa_tws"){
nmea0183Type=TWA_TWS;
valid=true;
return;
}
if (n183 == "awa_aws"){
nmea0183Type=AWA_AWS;
valid=true;
return;
}
if (n183 == "twd_tws"){
nmea0183Type=TWD_TWS;
valid=true;
return;
}
}
};
int minXdrInterval=100; int minXdrInterval=100;
int starboardRudderInstance=0; int starboardRudderInstance=0;
int portRudderInstance=-1; //ignore int portRudderInstance=-1; //ignore
int min2KInterval=50; int min2KInterval=50;
int rmcInterval=1000; int rmcInterval=1000;
int rmcCheckTime=4000; int rmcCheckTime=4000;
void init(GwConfigHandler *config){ std::vector<WindMapping> windMappings;
void init(GwConfigHandler *config, GwLog*logger){
minXdrInterval=config->getInt(GwConfigDefinitions::minXdrInterval,100); minXdrInterval=config->getInt(GwConfigDefinitions::minXdrInterval,100);
starboardRudderInstance=config->getInt(GwConfigDefinitions::stbRudderI,0); starboardRudderInstance=config->getInt(GwConfigDefinitions::stbRudderI,0);
portRudderInstance=config->getInt(GwConfigDefinitions::portRudderI,-1); portRudderInstance=config->getInt(GwConfigDefinitions::portRudderI,-1);
@ -36,6 +82,29 @@ class GwConverterConfig{
rmcInterval=config->getInt(GwConfigDefinitions::sendRMCi,1000); rmcInterval=config->getInt(GwConfigDefinitions::sendRMCi,1000);
if (rmcInterval < 0) rmcInterval=0; if (rmcInterval < 0) rmcInterval=0;
if (rmcInterval > 0 && rmcInterval <100) rmcInterval=100; if (rmcInterval > 0 && rmcInterval <100) rmcInterval=100;
for (auto && it:windConfigs){
String cfg=config->getString(it.second);
WindMapping mapping(it.first,cfg);
if (mapping.valid){
LOG_DEBUG(GwLog::ERROR,"add wind mapping n2k=%d,nmea0183=%01d(%s)",
(int)(mapping.n2kType),(int)(mapping.nmea0183Type),cfg.c_str());
windMappings.push_back(mapping);
} }
}
}
const WindMapping findWindMapping(const tN2kWindReference &n2k) const{
for (const auto & it:windMappings){
if (it.n2kType == n2k) return it;
}
return WindMapping();
}
const WindMapping findWindMapping(const WindMapping::Wind0183Type &n183) const{
for (const auto & it:windMappings){
if (it.nmea0183Type == n183) return it;
}
return WindMapping();
}
}; };
#endif #endif

View File

@ -399,28 +399,29 @@ private:
return; return;
} }
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
tN2kWindReference n2kRef;
bool shouldSend=false; bool shouldSend=false;
WindAngle=formatDegToRad(WindAngle); WindAngle=formatDegToRad(WindAngle);
GwConverterConfig::WindMapping mapping;
switch(Reference){ switch(Reference){
case NMEA0183Wind_Apparent: case NMEA0183Wind_Apparent:
n2kRef=N2kWind_Apparent;
shouldSend=updateDouble(boatData->AWA,WindAngle,msg.sourceId) && shouldSend=updateDouble(boatData->AWA,WindAngle,msg.sourceId) &&
updateDouble(boatData->AWS,WindSpeed,msg.sourceId); updateDouble(boatData->AWS,WindSpeed,msg.sourceId);
if (WindSpeed != NMEA0183DoubleNA) boatData->MaxAws->updateMax(WindSpeed); if (WindSpeed != NMEA0183DoubleNA) boatData->MaxAws->updateMax(WindSpeed);
mapping=config.findWindMapping(GwConverterConfig::WindMapping::AWA_AWS);
break; break;
case NMEA0183Wind_True: case NMEA0183Wind_True:
n2kRef=N2kWind_True_water;
shouldSend=updateDouble(boatData->TWA,WindAngle,msg.sourceId) && shouldSend=updateDouble(boatData->TWA,WindAngle,msg.sourceId) &&
updateDouble(boatData->TWS,WindSpeed,msg.sourceId); updateDouble(boatData->TWS,WindSpeed,msg.sourceId);
if (WindSpeed != NMEA0183DoubleNA) boatData->MaxTws->updateMax(WindSpeed); if (WindSpeed != NMEA0183DoubleNA) boatData->MaxTws->updateMax(WindSpeed);
mapping=config.findWindMapping(GwConverterConfig::WindMapping::TWA_TWS);
break; break;
default: default:
LOG_DEBUG(GwLog::DEBUG,"unknown wind reference %d in %s",(int)Reference,msg.line); LOG_DEBUG(GwLog::DEBUG,"unknown wind reference %d in %s",(int)Reference,msg.line);
} }
if (shouldSend){ //TODO: try to compute TWD and get mapping for this one
SetN2kWindSpeed(n2kMsg,1,WindSpeed,WindAngle,n2kRef); if (shouldSend && mapping.valid){
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)n2kRef)); SetN2kWindSpeed(n2kMsg,1,WindSpeed,WindAngle,mapping.n2kType);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)mapping.n2kType));
} }
} }
void convertVWR(const SNMEA0183Msg &msg) void convertVWR(const SNMEA0183Msg &msg)
@ -460,8 +461,11 @@ private:
if (WindSpeed != NMEA0183DoubleNA) boatData->MaxAws->updateMax(WindSpeed); if (WindSpeed != NMEA0183DoubleNA) boatData->MaxAws->updateMax(WindSpeed);
if (shouldSend) if (shouldSend)
{ {
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindAngle, N2kWind_Apparent); const GwConverterConfig::WindMapping mapping=config.findWindMapping(GwConverterConfig::WindMapping::AWA_AWS);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_Apparent)); if (mapping.valid){
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindAngle, mapping.n2kType);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)mapping.n2kType));
}
} }
} }
@ -504,8 +508,16 @@ private:
double twa = WindDirection-boatData->HDT->getData(); double twa = WindDirection-boatData->HDT->getData();
if(twa<0) { twa+=2*M_PI; } if(twa<0) { twa+=2*M_PI; }
updateDouble(boatData->TWA, twa, msg.sourceId); updateDouble(boatData->TWA, twa, msg.sourceId);
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, twa, N2kWind_True_water); const GwConverterConfig::WindMapping mapping=config.findWindMapping(GwConverterConfig::WindMapping::TWA_TWS);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_True_water)); if (mapping.valid){
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, twa, mapping.n2kType);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)mapping.n2kType));
}
const GwConverterConfig::WindMapping mapping2=config.findWindMapping(GwConverterConfig::WindMapping::TWD_TWS);
if (mapping2.valid){
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindDirection, mapping2.n2kType);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)mapping2.n2kType));
}
} }
} }
} }

View File

@ -469,39 +469,66 @@ private:
unsigned char SID; unsigned char SID;
tN2kWindReference WindReference; tN2kWindReference WindReference;
double WindAngle=N2kDoubleNA, WindSpeed=N2kDoubleNA; double WindAngle=N2kDoubleNA, WindSpeed=N2kDoubleNA;
tNMEA0183WindReference NMEA0183Reference;
if (ParseN2kWindSpeed(N2kMsg, SID, WindSpeed, WindAngle, WindReference)) { if (ParseN2kWindSpeed(N2kMsg, SID, WindSpeed, WindAngle, WindReference)) {
tNMEA0183Msg NMEA0183Msg; tNMEA0183Msg NMEA0183Msg;
tNMEA0183WindReference NMEA0183Reference; GwConverterConfig::WindMapping mapping=config.findWindMapping(WindReference);
bool shouldSend = false; bool shouldSend = false;
// MWV sentence contains apparent/true ANGLE and SPEED // MWV sentence contains apparent/true ANGLE and SPEED
// https://gpsd.gitlab.io/gpsd/NMEA.html#_mwv_wind_speed_and_angle // https://gpsd.gitlab.io/gpsd/NMEA.html#_mwv_wind_speed_and_angle
// https://docs.vaisala.com/r/M211109EN-L/en-US/GUID-7402DEF8-5E82-446F-B63E-998F49F3D743/GUID-C77934C7-2A72-466E-BC52-CE6B8CC7ACB6 // https://docs.vaisala.com/r/M211109EN-L/en-US/GUID-7402DEF8-5E82-446F-B63E-998F49F3D743/GUID-C77934C7-2A72-466E-BC52-CE6B8CC7ACB6
if (mapping.valid)
if (WindReference == N2kWind_Apparent) { {
if (mapping.nmea0183Type == GwConverterConfig::WindMapping::AWA_AWS)
{
NMEA0183Reference = NMEA0183Wind_Apparent; NMEA0183Reference = NMEA0183Wind_Apparent;
updateDouble(boatData->AWA, WindAngle); updateDouble(boatData->AWA, WindAngle);
updateDouble(boatData->AWS, WindSpeed); updateDouble(boatData->AWS, WindSpeed);
setMax(boatData->MaxAws, boatData->AWS); setMax(boatData->MaxAws, boatData->AWS);
shouldSend = true; shouldSend = true;
} }
if (WindReference == N2kWind_True_water) { if (mapping.nmea0183Type == GwConverterConfig::WindMapping::TWA_TWS)
{
NMEA0183Reference = NMEA0183Wind_True; NMEA0183Reference = NMEA0183Wind_True;
updateDouble(boatData->TWA, WindAngle); updateDouble(boatData->TWA, WindAngle);
updateDouble(boatData->TWS, WindSpeed); updateDouble(boatData->TWS, WindSpeed);
setMax(boatData->MaxTws, boatData->TWS); setMax(boatData->MaxTws, boatData->TWS);
shouldSend = true; shouldSend = true;
if (boatData->HDT->isValid()) { if (boatData->HDT->isValid())
{
double twd = WindAngle + boatData->HDT->getData(); double twd = WindAngle + boatData->HDT->getData();
if (twd>2*M_PI) { twd-=2*M_PI; } if (twd > 2 * M_PI)
{
twd -= 2 * M_PI;
}
updateDouble(boatData->TWD, twd); updateDouble(boatData->TWD, twd);
} }
} }
if (mapping.nmea0183Type == GwConverterConfig::WindMapping::TWD_TWS)
{
NMEA0183Reference = NMEA0183Wind_True;
updateDouble(boatData->TWD, WindAngle);
updateDouble(boatData->TWS, WindSpeed);
setMax(boatData->MaxTws, boatData->TWS);
if (boatData->HDT->isValid())
{
shouldSend = true;
double twa = WindAngle - boatData->HDT->getData();
if (twa > 2 * M_PI)
{
twa -= 2 * M_PI;
}
updateDouble(boatData->TWA, twa);
WindAngle=twa;
}
}
if (shouldSend && NMEA0183SetMWV(NMEA0183Msg, formatCourse(WindAngle), NMEA0183Reference, WindSpeed, talkerId)) { if (shouldSend && NMEA0183SetMWV(NMEA0183Msg, formatCourse(WindAngle), NMEA0183Reference, WindSpeed, talkerId))
{
SendMessage(NMEA0183Msg); SendMessage(NMEA0183Msg);
} }
}
/* if (WindReference == N2kWind_Apparent && boatData->SOG->isValid()) /* if (WindReference == N2kWind_Apparent && boatData->SOG->isValid())
{ // Lets calculate and send TWS/TWA if SOG is available { // Lets calculate and send TWS/TWA if SOG is available

View File

@ -850,7 +850,7 @@ void setup() {
xdrMappings.begin(); xdrMappings.begin();
logger.flush(); logger.flush();
GwConverterConfig converterConfig; GwConverterConfig converterConfig;
converterConfig.init(&config); converterConfig.init(&config,&logger);
nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData, nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData,
[](const tNMEA0183Msg &msg, int sourceId){ [](const tNMEA0183Msg &msg, int sourceId){
SendNMEA0183Message(msg,sourceId,false); SendNMEA0183Message(msg,sourceId,false);

View File

@ -250,6 +250,58 @@
"description": "the n2k instance to be used as port rudder 0...253, -1 to disable", "description": "the n2k instance to be used as port rudder 0...253, -1 to disable",
"category": "converter" "category": "converter"
}, },
{
"name": "windmappings",
"type": "array",
"replace":[
{
"n": "tng",
"l": "true north ground",
"t": "True_North=0",
"d": "twa_tws"
},
{
"n": "mgd",
"l": "magnetic ground dir",
"t": "Magnetic=1",
"d":""
},
{
"n": "awa",
"l": "apparent angle",
"t": "Apparent=2",
"d":"awa_aws"
},
{
"n": "gna",
"l": "ground angle",
"t": "True_boat=3",
"d": ""
},
{
"n": "tra",
"l": "true angle",
"t": "True_water=4",
"d":""
}
],
"children":[
{
"name":"windm$n",
"type":"list",
"description": "mapping of the PGN 130306 wind reference $t",
"label":"wind $l",
"list":[
{"l": "-unset-","v":""},
{"l": "TWA/TWS","v":"twa_tws"},
{"l": "AWA/AWS", "v":"awa_aws"},
{"l": "TWD/TWS","v":"twd_tws"}
]
}
]
},
{ {
"name": "timeouts", "name": "timeouts",
"type": "array", "type": "array",