Merge branch 'wellenvogel:master' into master

This commit is contained in:
norbert-walter 2022-03-02 11:42:39 +01:00 committed by GitHub
commit f7496dfd9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 269 additions and 183 deletions

View File

@ -145,6 +145,22 @@ For details refer to the [example description](lib/exampletask/Readme.md).
Changelog Changelog
--------- ---------
[20220302](../../releases/tag/20220302)
*********
* add export and import of config data.<br>
HINT: **passwords are not included**
* add a HELP tab that points to this description<br>
The url can be changed using the HELP_URL capability
[20220301](../../releases/tag/20220301)
*********
* change [boat data names to shorter ones](../../issues/17)
* correct [bug with boatData config items](../../issues/16)
* allow for shorter conditions in config items (use arrays of allowed values for "or" condition)
* add some static variables at BoatData to reference the known items (see [exampletask](lib/exampletask/GwExampleTask.cpp#L95))
* make the known config names static members of GwConfigHandler
* remove unused AWD boat data item
[20220124](../../releases/tag/20220124) [20220124](../../releases/tag/20220124)
********* *********
* make the serial input and output working again * make the serial input and output working again

View File

@ -131,7 +131,7 @@ def generateCfg(inFile,outFile,addDirs=[]):
continue continue
if len(n) > 15: if len(n) > 15:
raise Exception("%s: config names must be max 15 caracters"%n) raise Exception("%s: config names must be max 15 caracters"%n)
data+=' const String %s=F("%s");\n'%(n,n) data+=' static constexpr const __FlashStringHelper* %s=F("%s");\n'%(n,n)
data+=' protected:\n' data+=' protected:\n'
data+=' GwConfigInterface *configs[%d]={\n'%(l) data+=' GwConfigInterface *configs[%d]={\n'%(l)
first=True first=True

View File

@ -129,4 +129,7 @@ class GwApi{
#ifndef DECLARE_CAPABILITY #ifndef DECLARE_CAPABILITY
#define DECLARE_CAPABILITY(name,value) #define DECLARE_CAPABILITY(name,value)
#endif #endif
#ifndef DECLARE_STRING_CAPABILITY
#define DECLARE_STRING_CAPABILITY(name,value)
#endif
#endif #endif

View File

@ -160,6 +160,7 @@ public:
virtual ~GwBoatItemNameProvider() {} virtual ~GwBoatItemNameProvider() {}
}; };
#define GWBOATDATA(type,name,time,fmt) \ #define GWBOATDATA(type,name,time,fmt) \
static constexpr const __FlashStringHelper* _##name=F(#name); \
GwBoatItem<type> *name=new GwBoatItem<type>(F(#name),GwBoatItemBase::fmt,time,&values) ; GwBoatItem<type> *name=new GwBoatItem<type>(F(#name),GwBoatItemBase::fmt,time,&values) ;
#define GWSPECBOATDATA(clazz,name,time,fmt) \ #define GWSPECBOATDATA(clazz,name,time,fmt) \
clazz *name=new clazz(F(#name),GwBoatItemBase::fmt,time,&values) ; clazz *name=new clazz(F(#name),GwBoatItemBase::fmt,time,&values) ;
@ -171,7 +172,6 @@ class GwBoatData{
GWBOATDATA(double,COG,4000,formatCourse) GWBOATDATA(double,COG,4000,formatCourse)
GWBOATDATA(double,TWD,4000,formatCourse) GWBOATDATA(double,TWD,4000,formatCourse)
GWBOATDATA(double,AWD,4000,formatCourse)
GWBOATDATA(double,SOG,4000,formatKnots) GWBOATDATA(double,SOG,4000,formatKnots)
GWBOATDATA(double,STW,4000,formatKnots) GWBOATDATA(double,STW,4000,formatKnots)
GWBOATDATA(double,TWS,4000,formatKnots) GWBOATDATA(double,TWS,4000,formatKnots)
@ -179,31 +179,31 @@ class GwBoatData{
GWBOATDATA(double,MaxTws,0,formatKnots) GWBOATDATA(double,MaxTws,0,formatKnots)
GWBOATDATA(double,MaxAws,0,formatKnots) GWBOATDATA(double,MaxAws,0,formatKnots)
GWBOATDATA(double,AWA,4000,formatWind) GWBOATDATA(double,AWA,4000,formatWind)
GWBOATDATA(double,Heading,4000,formatCourse) //true GWBOATDATA(double,HDG,4000,formatCourse) //true heading
GWBOATDATA(double,MagneticHeading,4000,formatCourse) GWBOATDATA(double,MHDG,4000,formatCourse) //magnetic heading
GWBOATDATA(double,ROT,4000,formatRot) GWBOATDATA(double,ROT,4000,formatRot)
GWBOATDATA(double,Variation,4000,formatCourse) GWBOATDATA(double,VAR,4000,formatCourse) //Variation
GWBOATDATA(double,Deviation,4000,formatCourse) GWBOATDATA(double,DEV,4000,formatCourse) //Deviation
GWBOATDATA(double,HDOP,4000,formatDop) GWBOATDATA(double,HDOP,4000,formatDop)
GWBOATDATA(double,PDOP,4000,formatDop) GWBOATDATA(double,PDOP,4000,formatDop)
GWBOATDATA(double,VDOP,4000,formatDop) GWBOATDATA(double,VDOP,4000,formatDop)
GWBOATDATA(double,RudderPosition,4000,formatCourse) GWBOATDATA(double,RPOS,4000,formatCourse) //RudderPosition
GWBOATDATA(double,Latitude,4000,formatLatitude) GWBOATDATA(double,LAT,4000,formatLatitude)
GWBOATDATA(double,Longitude,4000,formatLongitude) GWBOATDATA(double,LON,4000,formatLongitude)
GWBOATDATA(double,Altitude,4000,formatFixed0) GWBOATDATA(double,ALT,4000,formatFixed0) //altitude
GWBOATDATA(double,WaterDepth,4000,formatDepth) GWBOATDATA(double,DBS,4000,formatDepth) //waterDepth (below surface)
GWBOATDATA(double,DepthTransducer,4000,formatDepth) GWBOATDATA(double,DBT,4000,formatDepth) //DepthTransducer
GWBOATDATA(double,GpsTime,4000,formatTime) GWBOATDATA(double,GPST,4000,formatTime) //GpsTime
GWBOATDATA(double,WaterTemperature,4000,kelvinToC) GWBOATDATA(double,WTemp,4000,kelvinToC)
GWBOATDATA(double,XTE,4000,formatXte) GWBOATDATA(double,XTE,4000,formatXte)
GWBOATDATA(double,DTW,4000,mtr2nm) GWBOATDATA(double,DTW,4000,mtr2nm) //distance wp
GWBOATDATA(double,BTW,4000,formatCourse) GWBOATDATA(double,BTW,4000,formatCourse) //bearing wp
GWBOATDATA(double,WPLatitude,4000,formatLatitude) GWBOATDATA(double,WPLat,4000,formatLatitude)
GWBOATDATA(double,WPLongitude,4000,formatLongitude) GWBOATDATA(double,WPLon,4000,formatLongitude)
GWBOATDATA(uint32_t,Log,16000,mtr2nm) GWBOATDATA(uint32_t,Log,16000,mtr2nm)
GWBOATDATA(uint32_t,TripLog,16000,mtr2nm) GWBOATDATA(uint32_t,TripLog,16000,mtr2nm)
GWBOATDATA(uint32_t,GpsDate,4000,formatDate) GWBOATDATA(uint32_t,GPSD,4000,formatDate) //Date
GWBOATDATA(int16_t,Timezone,8000,formatFixed0) GWBOATDATA(int16_t,TZ,8000,formatFixed0)
GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::lifeTime,formatFixed0); GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::lifeTime,formatFixed0);
public: public:
GwBoatData(GwLog *logger); GwBoatData(GwLog *logger);

View File

@ -42,8 +42,8 @@ class GetBoatDataRequest: public GwMessage{
so be sure to use a value that never will be a valid one so be sure to use a value that never will be a valid one
alternatively you can check using the isValid() method at each boatData item alternatively you can check using the isValid() method at each boatData item
*/ */
latitude=api->getBoatData()->Latitude->getDataWithDefault(INVALID_COORD); latitude=api->getBoatData()->LAT->getDataWithDefault(INVALID_COORD);
longitude=api->getBoatData()->Longitude->getDataWithDefault(INVALID_COORD); longitude=api->getBoatData()->LON->getDataWithDefault(INVALID_COORD);
}; };
}; };
@ -52,13 +52,13 @@ String formatValue(GwApi::BoatValue *value){
static const int bsize=30; static const int bsize=30;
char buffer[bsize+1]; char buffer[bsize+1];
buffer[0]=0; buffer[0]=0;
if (value->getFormat() == "formatDate"){ if (value->getFormat() == GwBoatItemBase::formatDate){
time_t tv=tNMEA0183Msg::daysToTime_t(value->value); time_t tv=tNMEA0183Msg::daysToTime_t(value->value);
tmElements_t parts; tmElements_t parts;
tNMEA0183Msg::breakTime(tv,parts); tNMEA0183Msg::breakTime(tv,parts);
snprintf(buffer,bsize,"%04d/%02d/%02d",parts.tm_year+1900,parts.tm_mon+1,parts.tm_mday); snprintf(buffer,bsize,"%04d/%02d/%02d",parts.tm_year+1900,parts.tm_mon+1,parts.tm_mday);
} }
else if(value->getFormat() == "formatTime"){ else if(value->getFormat() == GwBoatItemBase::formatTime){
double inthr; double inthr;
double intmin; double intmin;
double intsec; double intsec;
@ -68,7 +68,7 @@ String formatValue(GwApi::BoatValue *value){
modf(val*60.0,&intsec); modf(val*60.0,&intsec);
snprintf(buffer,bsize,"%02.0f:%02.0f:%02.0f",inthr,intmin,intsec); snprintf(buffer,bsize,"%02.0f:%02.0f:%02.0f",inthr,intmin,intsec);
} }
else if (value->getFormat() == "formatFixed0"){ else if (value->getFormat() == GwBoatItemBase::formatFixed0){
snprintf(buffer,bsize,"%.0f",value->value); snprintf(buffer,bsize,"%.0f",value->value);
} }
else{ else{
@ -90,10 +90,10 @@ void exampleTask(GwApi *api){
//------ //------
bool hasPosition=false; bool hasPosition=false;
bool hasPosition2=false; bool hasPosition2=false;
LOG_DEBUG(GwLog::DEBUG,"example switch ist %s",exampleSwitch?"true":"false"); LOG_DEBUG(GwLog::LOG,"example switch is %s",exampleSwitch?"true":"false");
LOG_DEBUG(GwLog::DEBUG,"minXdrInterval=%d",api->getConfig()->getInt(api->getConfig()->minXdrInterval)); LOG_DEBUG(GwLog::LOG,"minXdrInterval=%d",api->getConfig()->getInt(api->getConfig()->minXdrInterval));
GwApi::BoatValue *longitude=new GwApi::BoatValue(F("Longitude")); GwApi::BoatValue *longitude=new GwApi::BoatValue(GwBoatData::_LON);
GwApi::BoatValue *latitude=new GwApi::BoatValue(F("Latitude")); GwApi::BoatValue *latitude=new GwApi::BoatValue(GwBoatData::_LAT);
GwApi::BoatValue *testValue=new GwApi::BoatValue(boatItemName); GwApi::BoatValue *testValue=new GwApi::BoatValue(boatItemName);
GwApi::BoatValue *valueList[]={longitude,latitude,testValue}; GwApi::BoatValue *valueList[]={longitude,latitude,testValue};
GwApi::Status status; GwApi::Status status;

View File

@ -46,4 +46,6 @@ DECLARE_CAPABILITY(testboard2,true);
//hide some config value //hide some config value
//just set HIDE + the name of the config item to true //just set HIDE + the name of the config item to true
DECLARE_CAPABILITY(HIDEminXdrInterval,true); DECLARE_CAPABILITY(HIDEminXdrInterval,true);
//example for a user defined help url that will be shown when clicking the help button
DECLARE_STRING_CAPABILITY(HELP_URL,"https://www.wellenvogel.de");
#endif #endif

View File

@ -15,8 +15,11 @@ Files
This file is completely optional. This file is completely optional.
You only need this if you want to You only need this if you want to
extend the base configuration - we add a dummy library here and define one additional build environment (board) extend the base configuration - we add a dummy library here and define one additional build environment (board)
* [GwExampleTask.h](GwExampleTask.h) the name of this include must match the name of the directory (ignoring case) with a "gw" in front. This file includes our special hardware definitions and registers our task at the core (DECLARE_USERTASK in the code). Optionally it can define some capabilities (using DECLARE_CAPABILITY) that can be used in the config UI (see below). * [GwExampleTask.h](GwExampleTask.h) the name of this include must match the name of the directory (ignoring case) with a "gw" in front. This file includes our special hardware definitions and registers our task at the core (DECLARE_USERTASK in the code). Avoid including headers from other libraries in this file as this could interfere with the main code. Just only include them in your .cpp files (or in other headers).
Avoid including headers from other libraries in this file as this could interfere with the main code. Just only include them in your .cpp files (or in other headers). Optionally it can define some capabilities (using DECLARE_CAPABILITY) that can be used in the config UI (see below)
There are some special capabilities you can set:
* HIDEsomeName: will hide the configItem "someName"
* HELP_URL: will set the url that is loaded when clicking the HELP tab (user DECLARE_STRING_CAPABILITY)
* [GwExampleTaks.cpp](GwExampleTask.cpp) includes the implementation of our task. This tasks runs in an own thread - see the comments in the code. * [GwExampleTaks.cpp](GwExampleTask.cpp) includes the implementation of our task. This tasks runs in an own thread - see the comments in the code.
We can have as many cpp (and header files) as we need to structure our code. We can have as many cpp (and header files) as we need to structure our code.
* [config.json](config.json)<br> * [config.json](config.json)<br>

View File

@ -340,8 +340,8 @@ private:
uint8_t sourceId=getWaypointId(rmb.originID); uint8_t sourceId=getWaypointId(rmb.originID);
if (boatData->DTW->update(rmb.dtw,msg.sourceId) if (boatData->DTW->update(rmb.dtw,msg.sourceId)
&& boatData->BTW->update(rmb.btw,msg.sourceId) && boatData->BTW->update(rmb.btw,msg.sourceId)
&& boatData->WPLatitude->update(rmb.latitude,msg.sourceId) && boatData->WPLat->update(rmb.latitude,msg.sourceId)
&& boatData->WPLongitude->update(rmb.longitude,msg.sourceId) && boatData->WPLon->update(rmb.longitude,msg.sourceId)
){ ){
SetN2kNavigationInfo(n2kMsg,1,rmb.dtw,N2khr_true, SetN2kNavigationInfo(n2kMsg,1,rmb.dtw,N2khr_true,
false, false,
@ -365,37 +365,37 @@ private:
} }
void convertRMC(const SNMEA0183Msg &msg) void convertRMC(const SNMEA0183Msg &msg)
{ {
double GpsTime=0, Latitude=0, Longitude=0, COG=0, SOG=0, Variation=0; double GPST=0, LAT=0, LON=0, COG=0, SOG=0, VAR=0;
unsigned long GpsDate=0; unsigned long GPSD=0;
time_t DateTime; time_t DateTime;
char status; char status;
if (!NMEA0183ParseRMC_nc(msg, GpsTime, status, Latitude, Longitude, COG, SOG, GpsDate, Variation, &DateTime)) if (!NMEA0183ParseRMC_nc(msg, GPST, status, LAT, LON, COG, SOG, GPSD, VAR, &DateTime))
{ {
LOG_DEBUG(GwLog::DEBUG, "failed to parse RMC %s", msg.line); LOG_DEBUG(GwLog::DEBUG, "failed to parse RMC %s", msg.line);
return; return;
} }
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
if ( if (
UD(GpsTime) && UD(GPST) &&
UI(GpsDate) UI(GPSD)
) )
{ {
SetN2kSystemTime(n2kMsg, 1, GpsDate, GpsTime); SetN2kSystemTime(n2kMsg, 1, GPSD, GPST);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
if (UD(Latitude) && if (UD(LAT) &&
UD(Longitude)){ UD(LON)){
SetN2kLatLonRapid(n2kMsg,Latitude,Longitude); SetN2kLatLonRapid(n2kMsg,LAT,LON);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
if (UD(COG) && UD(SOG)){ if (UD(COG) && UD(SOG)){
SetN2kCOGSOGRapid(n2kMsg,1,N2khr_true,COG,SOG); SetN2kCOGSOGRapid(n2kMsg,1,N2khr_true,COG,SOG);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
if (UD(Variation)){ if (UD(VAR)){
SetN2kMagneticVariation(n2kMsg,1,N2kmagvar_Calc, SetN2kMagneticVariation(n2kMsg,1,N2kmagvar_Calc,
getUint32(boatData->GpsDate), Variation); getUint32(boatData->GPSD), VAR);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
@ -529,62 +529,62 @@ private:
} }
void convertHDM(const SNMEA0183Msg &msg){ void convertHDM(const SNMEA0183Msg &msg){
double MagneticHeading=NMEA0183DoubleNA; double MHDG=NMEA0183DoubleNA;
if (!NMEA0183ParseHDM_nc(msg, MagneticHeading)) if (!NMEA0183ParseHDM_nc(msg, MHDG))
{ {
LOG_DEBUG(GwLog::DEBUG, "failed to parse HDM %s", msg.line); LOG_DEBUG(GwLog::DEBUG, "failed to parse HDM %s", msg.line);
return; return;
} }
if (! UD(MagneticHeading)) return; if (! UD(MHDG)) return;
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kMagneticHeading(n2kMsg,1,MagneticHeading, SetN2kMagneticHeading(n2kMsg,1,MHDG,
boatData->Variation->getDataWithDefault(N2kDoubleNA), boatData->VAR->getDataWithDefault(N2kDoubleNA),
boatData->Deviation->getDataWithDefault(N2kDoubleNA) boatData->DEV->getDataWithDefault(N2kDoubleNA)
); );
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
void convertHDT(const SNMEA0183Msg &msg){ void convertHDT(const SNMEA0183Msg &msg){
double Heading=NMEA0183DoubleNA; double HDG=NMEA0183DoubleNA;
if (!NMEA0183ParseHDT_nc(msg, Heading)) if (!NMEA0183ParseHDT_nc(msg, HDG))
{ {
LOG_DEBUG(GwLog::DEBUG, "failed to parse HDT %s", msg.line); LOG_DEBUG(GwLog::DEBUG, "failed to parse HDT %s", msg.line);
return; return;
} }
if (! UD(Heading)) return; if (! UD(HDG)) return;
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kTrueHeading(n2kMsg,1,Heading); SetN2kTrueHeading(n2kMsg,1,HDG);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
void convertHDG(const SNMEA0183Msg &msg){ void convertHDG(const SNMEA0183Msg &msg){
double MagneticHeading=NMEA0183DoubleNA; double MHDG=NMEA0183DoubleNA;
double Variation=NMEA0183DoubleNA; double VAR=NMEA0183DoubleNA;
double Deviation=NMEA0183DoubleNA; double DEV=NMEA0183DoubleNA;
if (msg.FieldCount() < 5) if (msg.FieldCount() < 5)
{ {
LOG_DEBUG(GwLog::DEBUG, "failed to parse HDG %s", msg.line); LOG_DEBUG(GwLog::DEBUG, "failed to parse HDG %s", msg.line);
return; return;
} }
if (msg.FieldLen(0)>0){ if (msg.FieldLen(0)>0){
MagneticHeading=formatDegToRad(atof(msg.Field(0))); MHDG=formatDegToRad(atof(msg.Field(0)));
} }
else{ else{
return; return;
} }
if (msg.FieldLen(1)>0){ if (msg.FieldLen(1)>0){
Deviation=formatDegToRad(atof(msg.Field(1))); DEV=formatDegToRad(atof(msg.Field(1)));
if (msg.Field(2)[0] == 'W') Deviation=-Deviation; if (msg.Field(2)[0] == 'W') DEV=-DEV;
} }
if (msg.FieldLen(3)>0){ if (msg.FieldLen(3)>0){
Variation=formatDegToRad(atof(msg.Field(3))); VAR=formatDegToRad(atof(msg.Field(3)));
if (msg.Field(4)[0] == 'W') Variation=-Variation; if (msg.Field(4)[0] == 'W') VAR=-VAR;
} }
if (! UD(MagneticHeading)) return; if (! UD(MHDG)) return;
UD(Variation); UD(VAR);
UD(Deviation); UD(DEV);
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kMagneticHeading(n2kMsg,1,MagneticHeading,Deviation,Variation); SetN2kMagneticHeading(n2kMsg,1,MHDG,DEV,VAR);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
@ -607,10 +607,10 @@ private:
} }
//offset == 0? SK does not allow this //offset == 0? SK does not allow this
if (Offset != NMEA0183DoubleNA && Offset>=0 ){ if (Offset != NMEA0183DoubleNA && Offset>=0 ){
if (! boatData->WaterDepth->update(DepthBelowTransducer+Offset)) return; if (! boatData->DBS->update(DepthBelowTransducer+Offset)) return;
} }
if (Offset == NMEA0183DoubleNA) Offset=N2kDoubleNA; if (Offset == NMEA0183DoubleNA) Offset=N2kDoubleNA;
if (! boatData->DepthTransducer->update(DepthBelowTransducer)) return; if (! boatData->DBT->update(DepthBelowTransducer)) return;
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kWaterDepth(n2kMsg,1,DepthBelowTransducer,Offset); SetN2kWaterDepth(n2kMsg,1,DepthBelowTransducer,Offset);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((Offset != N2kDoubleNA)?1:0)); send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((Offset != N2kDoubleNA)?1:0));
@ -645,7 +645,7 @@ private:
continue; continue;
} }
if (dt == DBT){ if (dt == DBT){
if (! boatData->DepthTransducer->update(Depth,msg.sourceId)) return; if (! boatData->DBT->update(Depth,msg.sourceId)) return;
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kWaterDepth(n2kMsg,1,Depth,N2kDoubleNA); SetN2kWaterDepth(n2kMsg,1,Depth,N2kDoubleNA);
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String(0)); send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String(0));
@ -653,8 +653,8 @@ private:
} }
//we can only send if we have a valid depth beloww tranducer //we can only send if we have a valid depth beloww tranducer
//to compute the offset //to compute the offset
if (! boatData->DepthTransducer->isValid()) return; if (! boatData->DBT->isValid()) return;
double offset=Depth-boatData->DepthTransducer->getData(); double offset=Depth-boatData->DBT->getData();
if (offset >= 0 && dt == DBT){ if (offset >= 0 && dt == DBT){
logger->logDebug(GwLog::DEBUG, "strange DBK - more depth then transducer %s", msg.line); logger->logDebug(GwLog::DEBUG, "strange DBK - more depth then transducer %s", msg.line);
return; return;
@ -664,7 +664,7 @@ private:
return; return;
} }
if (dt == DBS){ if (dt == DBS){
if (! boatData->WaterDepth->update(Depth,msg.sourceId)) return; if (! boatData->DBS->update(Depth,msg.sourceId)) return;
} }
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kWaterDepth(n2kMsg,1,Depth,offset); SetN2kWaterDepth(n2kMsg,1,Depth,offset);
@ -683,7 +683,7 @@ private:
} }
void convertRSA(const SNMEA0183Msg &msg){ void convertRSA(const SNMEA0183Msg &msg){
double RudderPosition=NMEA0183DoubleNA; double RPOS=NMEA0183DoubleNA;
if (msg.FieldCount() < 4) if (msg.FieldCount() < 4)
{ {
LOG_DEBUG(GwLog::DEBUG, "failed to parse RSA %s", msg.line); LOG_DEBUG(GwLog::DEBUG, "failed to parse RSA %s", msg.line);
@ -691,10 +691,10 @@ private:
} }
if (msg.FieldLen(0)>0){ if (msg.FieldLen(0)>0){
if (msg.Field(1)[0] != 'A') return; if (msg.Field(1)[0] != 'A') return;
RudderPosition=degToRad*atof(msg.Field(0)); RPOS=degToRad*atof(msg.Field(0));
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
if (! UD(RudderPosition)) return; if (! UD(RPOS)) return;
SetN2kRudder(n2kMsg,RudderPosition); SetN2kRudder(n2kMsg,RPOS);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);
} }
@ -708,7 +708,7 @@ private:
return; return;
} }
if (! updateDouble(boatData->STW,STW,msg.sourceId)) return; if (! updateDouble(boatData->STW,STW,msg.sourceId)) return;
if (! updateDouble(boatData->Heading,TrueHeading,msg.sourceId)) return; if (! updateDouble(boatData->HDG,TrueHeading,msg.sourceId)) return;
if (MagneticHeading == NMEA0183DoubleNA) MagneticHeading=N2kDoubleNA; if (MagneticHeading == NMEA0183DoubleNA) MagneticHeading=N2kDoubleNA;
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kBoatSpeed(n2kMsg,1,STW); SetN2kBoatSpeed(n2kMsg,1,STW);
@ -741,12 +741,12 @@ private:
tmElements_t parts; tmElements_t parts;
tNMEA0183Msg::breakTime(DateTime,parts); tNMEA0183Msg::breakTime(DateTime,parts);
double GpsTime=parts.tm_sec+60*parts.tm_min+3600*parts.tm_hour; double GpsTime=parts.tm_sec+60*parts.tm_min+3600*parts.tm_hour;
if (! boatData->GpsDate->update(DaysSince1970,msg.sourceId)) return; if (! boatData->GPSD->update(DaysSince1970,msg.sourceId)) return;
if (! boatData->GpsTime->update(GpsTime,msg.sourceId)) return; if (! boatData->GPST->update(GpsTime,msg.sourceId)) return;
bool timezoneValid=false; bool timezoneValid=false;
if (msg.FieldLen(4) > 0 && msg.FieldLen(5)>0){ if (msg.FieldLen(4) > 0 && msg.FieldLen(5)>0){
Timezone=Timezone/60; //N2K has offset in minutes Timezone=Timezone/60; //N2K has offset in minutes
if (! boatData->Timezone->update(Timezone,msg.sourceId)) return; if (! boatData->TZ->update(Timezone,msg.sourceId)) return;
timezoneValid=true; timezoneValid=true;
} }
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
@ -774,16 +774,16 @@ private:
LOG_DEBUG(GwLog::DEBUG, "failed to parse GGA %s", msg.line); LOG_DEBUG(GwLog::DEBUG, "failed to parse GGA %s", msg.line);
return; return;
} }
if (! updateDouble(boatData->GpsTime,GPSTime,msg.sourceId)) return; if (! updateDouble(boatData->GPST,GPSTime,msg.sourceId)) return;
if (! updateDouble(boatData->Latitude,Latitude,msg.sourceId)) return; if (! updateDouble(boatData->LAT,Latitude,msg.sourceId)) return;
if (! updateDouble(boatData->Longitude,Longitude,msg.sourceId)) return; if (! updateDouble(boatData->LON,Longitude,msg.sourceId)) return;
if (! updateDouble(boatData->Altitude,Altitude,msg.sourceId)) return; if (! updateDouble(boatData->ALT,Altitude,msg.sourceId)) return;
if (! updateDouble(boatData->HDOP,HDOP,msg.sourceId)) return; if (! updateDouble(boatData->HDOP,HDOP,msg.sourceId)) return;
if (! boatData->GpsDate->isValid()) return; if (! boatData->GPSD->isValid()) return;
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
tN2kGNSSmethod method=N2kGNSSm_noGNSS; tN2kGNSSmethod method=N2kGNSSm_noGNSS;
if (GPSQualityIndicator <=5 ) method= (tN2kGNSSmethod)GPSQualityIndicator; if (GPSQualityIndicator <=5 ) method= (tN2kGNSSmethod)GPSQualityIndicator;
SetN2kGNSS(n2kMsg,1, boatData->GpsDate->getData(), SetN2kGNSS(n2kMsg,1, boatData->GPSD->getData(),
GPSTime, Latitude, Longitude, Altitude, GPSTime, Latitude, Longitude, Altitude,
N2kGNSSt_GPS, method, N2kGNSSt_GPS, method,
SatelliteCount, HDOP, boatData->PDOP->getDataWithDefault(N2kDoubleNA), 0, SatelliteCount, HDOP, boatData->PDOP->getDataWithDefault(N2kDoubleNA), 0,
@ -881,9 +881,9 @@ private:
return; return;
} }
if (GLL.status != 'A') return; if (GLL.status != 'A') return;
if (! updateDouble(boatData->Latitude,GLL.latitude,msg.sourceId)) return; if (! updateDouble(boatData->LAT,GLL.latitude,msg.sourceId)) return;
if (! updateDouble(boatData->Longitude,GLL.longitude,msg.sourceId)) return; if (! updateDouble(boatData->LON,GLL.longitude,msg.sourceId)) return;
if (! updateDouble(boatData->GpsTime,GLL.GPSTime,msg.sourceId)) return; if (! updateDouble(boatData->GPST,GLL.GPSTime,msg.sourceId)) return;
tN2kMsg n2kMsg; tN2kMsg n2kMsg;
SetN2kLatLonRapid(n2kMsg,GLL.latitude,GLL.longitude); SetN2kLatLonRapid(n2kMsg,GLL.latitude,GLL.longitude);
send(n2kMsg,msg.sourceId); send(n2kMsg,msg.sourceId);

View File

@ -182,22 +182,22 @@ private:
//if we have no variation we send either HDM or HDT //if we have no variation we send either HDM or HDT
if (ParseN2kHeading(N2kMsg, SID, Heading, _Deviation, Variation, ref)) if (ParseN2kHeading(N2kMsg, SID, Heading, _Deviation, Variation, ref))
{ {
updateDouble(boatData->Variation,Variation); updateDouble(boatData->VAR,Variation);
updateDouble(boatData->Deviation,_Deviation); updateDouble(boatData->DEV,_Deviation);
if (N2kIsNA(Variation)){ if (N2kIsNA(Variation)){
//maybe we still have a valid variation //maybe we still have a valid variation
Variation=boatData->Variation->getDataWithDefault(N2kDoubleNA); Variation=boatData->VAR->getDataWithDefault(N2kDoubleNA);
} }
if (N2kIsNA(Variation)){ if (N2kIsNA(Variation)){
//no variation //no variation
if (ref == N2khr_magnetic){ if (ref == N2khr_magnetic){
updateDouble(boatData->MagneticHeading,Heading); updateDouble(boatData->MHDG,Heading);
if (NMEA0183SetHDM(NMEA0183Msg,Heading,talkerId)){ if (NMEA0183SetHDM(NMEA0183Msg,Heading,talkerId)){
SendMessage(NMEA0183Msg); SendMessage(NMEA0183Msg);
} }
} }
if (ref == N2khr_true){ if (ref == N2khr_true){
updateDouble(boatData->Heading,Heading); updateDouble(boatData->HDG,Heading);
if (NMEA0183SetHDT(NMEA0183Msg,Heading,talkerId)){ if (NMEA0183SetHDT(NMEA0183Msg,Heading,talkerId)){
SendMessage(NMEA0183Msg); SendMessage(NMEA0183Msg);
} }
@ -212,8 +212,8 @@ private:
if (ref == N2khr_true){ if (ref == N2khr_true){
MagneticHeading=Heading-Variation; MagneticHeading=Heading-Variation;
} }
updateDouble(boatData->MagneticHeading,MagneticHeading); updateDouble(boatData->MHDG,MagneticHeading);
updateDouble(boatData->Heading,Heading); updateDouble(boatData->HDG,Heading);
if (!N2kIsNA(MagneticHeading)){ if (!N2kIsNA(MagneticHeading)){
if (NMEA0183SetHDG(NMEA0183Msg, MagneticHeading,_Deviation, if (NMEA0183SetHDG(NMEA0183Msg, MagneticHeading,_Deviation,
Variation,talkerId)) Variation,talkerId))
@ -240,9 +240,9 @@ private:
uint16_t DaysSince1970; uint16_t DaysSince1970;
double Variation; double Variation;
ParseN2kMagneticVariation(N2kMsg, SID, Source, DaysSince1970, Variation); ParseN2kMagneticVariation(N2kMsg, SID, Source, DaysSince1970, Variation);
updateDouble(boatData->Variation, Variation); updateDouble(boatData->VAR, Variation);
if (DaysSince1970 != N2kUInt16NA && DaysSince1970 != 0) if (DaysSince1970 != N2kUInt16NA && DaysSince1970 != 0)
boatData->GpsDate->update(DaysSince1970,sourceId); boatData->GPSD->update(DaysSince1970,sourceId);
} }
//***************************************************************************** //*****************************************************************************
@ -258,8 +258,8 @@ private:
tNMEA0183Msg NMEA0183Msg; tNMEA0183Msg NMEA0183Msg;
updateDouble(boatData->STW, WaterReferenced); updateDouble(boatData->STW, WaterReferenced);
unsigned long now = millis(); unsigned long now = millis();
double MagneticHeading = (boatData->Heading->isValid(now) && boatData->Variation->isValid(now)) ? boatData->Heading->getData() + boatData->Variation->getData() : NMEA0183DoubleNA; double MagneticHeading = (boatData->HDG->isValid(now) && boatData->VAR->isValid(now)) ? boatData->HDG->getData() + boatData->VAR->getData() : NMEA0183DoubleNA;
if (NMEA0183SetVHW(NMEA0183Msg, boatData->Heading->getDataWithDefault(NMEA0183DoubleNA), MagneticHeading, WaterReferenced,talkerId)) if (NMEA0183SetVHW(NMEA0183Msg, boatData->HDG->getDataWithDefault(NMEA0183DoubleNA), MagneticHeading, WaterReferenced,talkerId))
{ {
SendMessage(NMEA0183Msg); SendMessage(NMEA0183Msg);
} }
@ -278,8 +278,8 @@ private:
{ {
WaterDepth = DepthBelowTransducer + Offset; WaterDepth = DepthBelowTransducer + Offset;
updateDouble(boatData->WaterDepth, WaterDepth); updateDouble(boatData->DBS, WaterDepth);
updateDouble(boatData->DepthTransducer,DepthBelowTransducer); updateDouble(boatData->DBT,DepthBelowTransducer);
tNMEA0183Msg NMEA0183Msg; tNMEA0183Msg NMEA0183Msg;
if (NMEA0183SetDPT(NMEA0183Msg, DepthBelowTransducer, Offset,talkerId)) if (NMEA0183SetDPT(NMEA0183Msg, DepthBelowTransducer, Offset,talkerId))
{ {
@ -299,8 +299,8 @@ private:
double Longitude; double Longitude;
if (ParseN2kPGN129025(N2kMsg, Latitude, Longitude)) if (ParseN2kPGN129025(N2kMsg, Latitude, Longitude))
{ {
updateDouble(boatData->Latitude, Latitude); updateDouble(boatData->LAT, Latitude);
updateDouble(boatData->Longitude, Longitude); updateDouble(boatData->LON, Longitude);
} }
} }
@ -316,13 +316,13 @@ private:
{ {
updateDouble(boatData->COG, COG); updateDouble(boatData->COG, COG);
updateDouble(boatData->SOG, SOG); updateDouble(boatData->SOG, SOG);
double MCOG = (!N2kIsNA(COG) && boatData->Variation->isValid()) ? COG - boatData->Variation->getData() : NMEA0183DoubleNA; double MCOG = (!N2kIsNA(COG) && boatData->VAR->isValid()) ? COG - boatData->VAR->getData() : NMEA0183DoubleNA;
if (HeadingReference == N2khr_magnetic) if (HeadingReference == N2khr_magnetic)
{ {
MCOG = COG; MCOG = COG;
if (boatData->Variation->isValid()) if (boatData->VAR->isValid())
{ {
COG -= boatData->Variation->getData(); COG -= boatData->VAR->getData();
updateDouble(boatData->COG, COG); updateDouble(boatData->COG, COG);
} }
} }
@ -382,14 +382,14 @@ private:
nSatellites, HDOP, PDOP, GeoidalSeparation, nSatellites, HDOP, PDOP, GeoidalSeparation,
nReferenceStations, ReferenceStationType, ReferenceSationID, AgeOfCorrection)) nReferenceStations, ReferenceStationType, ReferenceSationID, AgeOfCorrection))
{ {
updateDouble(boatData->Latitude, Latitude); updateDouble(boatData->LAT, Latitude);
updateDouble(boatData->Longitude, Longitude); updateDouble(boatData->LON, Longitude);
updateDouble(boatData->Altitude, Altitude); updateDouble(boatData->ALT, Altitude);
updateDouble(boatData->GpsTime, GpsTime); updateDouble(boatData->GPST, GpsTime);
updateDouble(boatData->HDOP,HDOP); updateDouble(boatData->HDOP,HDOP);
updateDouble(boatData->PDOP,PDOP); updateDouble(boatData->PDOP,PDOP);
if (DaysSince1970 != N2kUInt16NA && DaysSince1970 != 0) if (DaysSince1970 != N2kUInt16NA && DaysSince1970 != 0)
boatData->GpsDate->update(DaysSince1970,sourceId); boatData->GPSD->update(DaysSince1970,sourceId);
int quality=0; int quality=0;
if ((int)GNSSmethod <= 5) quality=(int)GNSSmethod; if ((int)GNSSmethod <= 5) quality=(int)GNSSmethod;
tNMEA0183AISMsg nmeaMsg; tNMEA0183AISMsg nmeaMsg;
@ -518,8 +518,8 @@ private:
boatData->TWS->getDataWithDefault(NMEA0183DoubleNA),talkerId)) boatData->TWS->getDataWithDefault(NMEA0183DoubleNA),talkerId))
SendMessage(NMEA0183Msg); SendMessage(NMEA0183Msg);
double magnetic = boatData->TWD->getData(); double magnetic = boatData->TWD->getData();
if (boatData->Variation->isValid()) if (boatData->VAR->isValid())
magnetic -= boatData->Variation->getData(); magnetic -= boatData->VAR->getData();
if (!NMEA0183Msg.Init("MWD", talkerId)) if (!NMEA0183Msg.Init("MWD", talkerId))
return; return;
if (!NMEA0183Msg.AddDoubleField(formatCourse(boatData->TWD->getData()))) if (!NMEA0183Msg.AddDoubleField(formatCourse(boatData->TWD->getData())))
@ -548,20 +548,20 @@ private:
{ {
long now = millis(); long now = millis();
if (NextRMCSend <= millis() && if (NextRMCSend <= millis() &&
boatData->Latitude->isValid(now) && boatData->LAT->isValid(now) &&
boatData->Latitude->getLastSource() == sourceId boatData->LAT->getLastSource() == sourceId
) )
{ {
tNMEA0183Msg NMEA0183Msg; tNMEA0183Msg NMEA0183Msg;
if (NMEA0183SetRMC(NMEA0183Msg, if (NMEA0183SetRMC(NMEA0183Msg,
boatData->GpsTime->getDataWithDefault(NMEA0183DoubleNA), boatData->GPST->getDataWithDefault(NMEA0183DoubleNA),
boatData->Latitude->getDataWithDefault(NMEA0183DoubleNA), boatData->LAT->getDataWithDefault(NMEA0183DoubleNA),
boatData->Longitude->getDataWithDefault(NMEA0183DoubleNA), boatData->LON->getDataWithDefault(NMEA0183DoubleNA),
boatData->COG->getDataWithDefault(NMEA0183DoubleNA), boatData->COG->getDataWithDefault(NMEA0183DoubleNA),
boatData->SOG->getDataWithDefault(NMEA0183DoubleNA), boatData->SOG->getDataWithDefault(NMEA0183DoubleNA),
boatData->GpsDate->getDataWithDefault(NMEA0183UInt32NA), boatData->GPSD->getDataWithDefault(NMEA0183UInt32NA),
boatData->Variation->getDataWithDefault(NMEA0183DoubleNA), boatData->VAR->getDataWithDefault(NMEA0183DoubleNA),
talkerId)) talkerId))
{ {
SendMessage(NMEA0183Msg); SendMessage(NMEA0183Msg);
@ -583,7 +583,7 @@ private:
if (TripLog != N2kUInt32NA) if (TripLog != N2kUInt32NA)
boatData->TripLog->update(TripLog,sourceId); boatData->TripLog->update(TripLog,sourceId);
if (DaysSince1970 != N2kUInt16NA && DaysSince1970 != 0) if (DaysSince1970 != N2kUInt16NA && DaysSince1970 != 0)
boatData->GpsDate->update(DaysSince1970,sourceId); boatData->GPSD->update(DaysSince1970,sourceId);
tNMEA0183Msg NMEA0183Msg; tNMEA0183Msg NMEA0183Msg;
if (!NMEA0183Msg.Init("VLW", talkerId)) if (!NMEA0183Msg.Init("VLW", talkerId))
@ -613,7 +613,7 @@ private:
if (ParseN2kRudder(N2kMsg, RudderPosition, Instance, RudderDirectionOrder, AngleOrder)) if (ParseN2kRudder(N2kMsg, RudderPosition, Instance, RudderDirectionOrder, AngleOrder))
{ {
updateDouble(boatData->RudderPosition, RudderPosition); updateDouble(boatData->RPOS, RudderPosition);
if (Instance != 0) if (Instance != 0)
return; return;
@ -1003,26 +1003,26 @@ private:
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN); LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
return; return;
} }
updateDouble(boatData->GpsTime,GpsTime); updateDouble(boatData->GPST,GpsTime);
if (DaysSince1970 != N2kUInt16NA) boatData->GpsDate->update(DaysSince1970,sourceId); if (DaysSince1970 != N2kUInt16NA) boatData->GPSD->update(DaysSince1970,sourceId);
if (boatData->GpsDate->isValid() && boatData->GpsTime->isValid()){ if (boatData->GPSD->isValid() && boatData->GPST->isValid()){
tNMEA0183Msg nmeaMsg; tNMEA0183Msg nmeaMsg;
nmeaMsg.Init("ZDA",talkerId); nmeaMsg.Init("ZDA",talkerId);
char utc[7]; char utc[7];
double seconds=boatData->GpsTime->getData(); double seconds=boatData->GPST->getData();
int hours=floor(seconds/3600.0); int hours=floor(seconds/3600.0);
int minutes=floor(seconds/60) - hours *60; int minutes=floor(seconds/60) - hours *60;
int sec=floor(seconds)-60*minutes-3600*hours; int sec=floor(seconds)-60*minutes-3600*hours;
snprintf(utc,7,"%02d%02d%02d",hours,minutes,sec); snprintf(utc,7,"%02d%02d%02d",hours,minutes,sec);
nmeaMsg.AddStrField(utc); nmeaMsg.AddStrField(utc);
tmElements_t timeParts; tmElements_t timeParts;
tNMEA0183Msg::breakTime(tNMEA0183Msg::daysToTime_t(boatData->GpsDate->getData()),timeParts); tNMEA0183Msg::breakTime(tNMEA0183Msg::daysToTime_t(boatData->GPSD->getData()),timeParts);
nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetDay(timeParts)); nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetDay(timeParts));
nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetMonth(timeParts)); nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetMonth(timeParts));
nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetYear(timeParts)); nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetYear(timeParts));
if (boatData->Timezone->isValid()){ if (boatData->TZ->isValid()){
int hours=boatData->Timezone->getData()/60; int hours=boatData->TZ->getData()/60;
int minutes=boatData->Timezone->getData() - 60 *hours; int minutes=boatData->TZ->getData() - 60 *hours;
nmeaMsg.AddDoubleField(hours,1,"%02.0f"); nmeaMsg.AddDoubleField(hours,1,"%02.0f");
nmeaMsg.AddDoubleField(minutes,1,"%02.0f"); nmeaMsg.AddDoubleField(minutes,1,"%02.0f");
} }
@ -1042,9 +1042,9 @@ private:
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN); LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
return; return;
} }
updateDouble(boatData->GpsTime,GpsTime); updateDouble(boatData->GPST,GpsTime);
if (DaysSince1970 != N2kUInt16NA) boatData->GpsDate->update(DaysSince1970,sourceId); if (DaysSince1970 != N2kUInt16NA) boatData->GPSD->update(DaysSince1970,sourceId);
if (LocalOffset != N2kInt16NA) boatData->Timezone->update(LocalOffset,sourceId); if (LocalOffset != N2kInt16NA) boatData->TZ->update(LocalOffset,sourceId);
} }
void HandleROT(const tN2kMsg &msg){ void HandleROT(const tN2kMsg &msg){
unsigned char SID=0; unsigned char SID=0;
@ -1137,17 +1137,17 @@ private:
return; return;
} }
if (BearingReference == N2khr_magnetic){ if (BearingReference == N2khr_magnetic){
if (! boatData->Variation->isValid()){ if (! boatData->VAR->isValid()){
LOG_DEBUG(GwLog::DEBUG,"missing variation to compute true heading for %d ", msg.PGN); LOG_DEBUG(GwLog::DEBUG,"missing variation to compute true heading for %d ", msg.PGN);
return; return;
} }
BearingPositionToDestinationWaypoint-=boatData->Variation->getData(); BearingPositionToDestinationWaypoint-=boatData->VAR->getData();
} }
if (! updateDouble(boatData->DTW,DistanceToWaypoint)) return; if (! updateDouble(boatData->DTW,DistanceToWaypoint)) return;
if (! updateDouble(boatData->BTW,BearingPositionToDestinationWaypoint)) return; if (! updateDouble(boatData->BTW,BearingPositionToDestinationWaypoint)) return;
if (! updateDouble(boatData->WPLatitude,DestinationLatitude)) return; if (! updateDouble(boatData->WPLat,DestinationLatitude)) return;
if (! updateDouble(boatData->WPLongitude,DestinationLongitude)) return; if (! updateDouble(boatData->WPLon,DestinationLongitude)) return;
tNMEA0183Msg nmeaMsg; tNMEA0183Msg nmeaMsg;
if (! nmeaMsg.Init("RMB",talkerId)) return; if (! nmeaMsg.Init("RMB",talkerId)) return;
if (! nmeaMsg.AddStrField("A")) return; if (! nmeaMsg.AddStrField("A")) return;
@ -1242,7 +1242,7 @@ private:
double WaterTemperature; double WaterTemperature;
if (ParseN2kPGN130310(N2kMsg, SID, WaterTemperature, OutsideAmbientAirTemperature, AtmosphericPressure)) if (ParseN2kPGN130310(N2kMsg, SID, WaterTemperature, OutsideAmbientAirTemperature, AtmosphericPressure))
{ {
updateDouble(boatData->WaterTemperature, WaterTemperature); updateDouble(boatData->WTemp, WaterTemperature);
tNMEA0183Msg NMEA0183Msg; tNMEA0183Msg NMEA0183Msg;
if (!NMEA0183Msg.Init("MTW", talkerId)) if (!NMEA0183Msg.Init("MTW", talkerId))

View File

@ -42,6 +42,7 @@ class GwUserCapability{
#define DECLARE_USERTASK_PARAM(task,...) GwUserTaskDef __##task##__(task,#task,__VA_ARGS__); #define DECLARE_USERTASK_PARAM(task,...) GwUserTaskDef __##task##__(task,#task,__VA_ARGS__);
#define DECLARE_INITFUNCTION(task) GwInitTask __Init##task##__(task,#task); #define DECLARE_INITFUNCTION(task) GwInitTask __Init##task##__(task,#task);
#define DECLARE_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,#value); #define DECLARE_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,#value);
#define DECLARE_STRING_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,value);
#include "GwApi.h" #include "GwApi.h"
#include "GwUserTasks.h" #include "GwUserTasks.h"
class TaskApi : public GwApi class TaskApi : public GwApi

View File

@ -21,6 +21,7 @@
<div class="tab" data-page="xdrPage">XDR</div> <div class="tab" data-page="xdrPage">XDR</div>
<div class="tab" data-page="dashboardPage">Data</div> <div class="tab" data-page="dashboardPage">Data</div>
<div class="tab" data-page="updatePage">Update</div> <div class="tab" data-page="updatePage">Update</div>
<div class="tab" data-url="https://github.com/wellenvogel/esp32-nmea2000" data-window="help" id="helpButton">Help</div>
</div> </div>
<div id="statusPage" class="tabPage"> <div id="statusPage" class="tabPage">
<div id="statusPageContent"> <div id="statusPageContent">
@ -62,6 +63,8 @@
<button id="resetForm">ReloadConfig</button> <button id="resetForm">ReloadConfig</button>
<button id="forgetPass">ForgetPass</button> <button id="forgetPass">ForgetPass</button>
<button id="changeConfig">Save&Restart</button> <button id="changeConfig">Save&Restart</button>
<button id="exportConfig">Export</button>
<button id="importConfig">Import</button>
<button id="factoryReset">FactoryReset</button> <button id="factoryReset">FactoryReset</button>
</div> </div>
<div class="configFormRows"> <div class="configFormRows">

View File

@ -121,7 +121,12 @@ function resetForm(ev) {
} }
} }
} }
el.value = v; if (el.tagName === 'SELECT') {
setSelect(el,v);
}
else{
el.value = v;
}
el.setAttribute('data-loaded', v); el.setAttribute('data-loaded', v);
let changeEvent = new Event('change'); let changeEvent = new Event('change');
el.dispatchEvent(changeEvent); el.dispatchEvent(changeEvent);
@ -199,39 +204,46 @@ function checkXDR(v,allValues){
} }
} }
} }
function getAllConfigs(omitPass) {
let values = document.querySelectorAll('.configForm select , .configForm input');
let allValues = {};
for (let i = 0; i < values.length; i++) {
let v = values[i];
let name = v.getAttribute('name');
if (!name) continue;
if (name.indexOf("_") >= 0) continue;
let def = getConfigDefition(name);
if (def.type === 'password' && ( v.value == '' || omitPass)) {
continue;
}
let check = v.getAttribute('data-check');
if (check) {
if (typeof (self[check]) === 'function') {
let res = self[check](v.value, allValues, getConfigDefition(name));
if (res) {
let value = v.value;
if (v.type === 'password') value = "******";
alert("invalid config for " + v.getAttribute('name') + "(" + value + "):\n" + res);
return;
}
}
}
allValues[name] = v.value;
}
return allValues;
}
function changeConfig() { function changeConfig() {
ensurePass() ensurePass()
.then(function (pass) { .then(function (pass) {
let newAdminPass; let newAdminPass;
let url = "/api/setConfig?_hash="+encodeURIComponent(pass)+"&"; let url = "/api/setConfig?_hash="+encodeURIComponent(pass)+"&";
let values = document.querySelectorAll('.configForm select , .configForm input'); let allValues=getAllConfigs();
let allValues = {}; if (!allValues) return;
for (let i = 0; i < values.length; i++) { for (let name in allValues){
let v = values[i];
let name = v.getAttribute('name');
if (!name) continue;
if (name.indexOf("_") >= 0) continue;
let def = getConfigDefition(name);
if (def.type === 'password' && v.value == '') {
continue;
}
let check = v.getAttribute('data-check');
if (check) {
if (typeof (self[check]) === 'function') {
let res = self[check](v.value, allValues, getConfigDefition(name));
if (res) {
let value = v.value;
if (v.type === 'password') value = "******";
alert("invalid config for " + v.getAttribute('name') + "(" + value + "):\n" + res);
return;
}
}
}
if (name == 'adminPassword'){ if (name == 'adminPassword'){
newAdminPass=v.value; newAdminPass=allValues[name];
} }
allValues[name] = v.value; url += name + "=" + encodeURIComponent(allValues[name]) + "&";
url += name + "=" + encodeURIComponent(v.value) + "&";
} }
getJson(url) getJson(url)
.then(function (status) { .then(function (status) {
@ -249,7 +261,7 @@ function changeConfig() {
} }
}) })
}) })
.catch(function (e) { alert("Invalid password"); }) .catch(function (e) { alert(e); })
} }
function factoryReset() { function factoryReset() {
ensurePass() ensurePass()
@ -386,12 +398,19 @@ function checkCondition(element){
let condition=getConditions(name); let condition=getConditions(name);
if (! condition) return; if (! condition) return;
let visible=false; let visible=false;
if (! condition instanceof Array) condition=[condition];
condition.forEach(function(cel){ condition.forEach(function(cel){
let lvis=true; let lvis=true;
for (let k in cel){ for (let k in cel){
let item=document.querySelector('[name='+k+']'); let item=document.querySelector('[name='+k+']');
if (item){ if (item){
if (item.value != cel[k]) lvis=false; let compare=cel[k];
if (compare instanceof Array){
if (compare.indexOf(item.value) < 0) lvis=false;
}
else{
if (item.value != cel[k]) lvis=false;
}
} }
} }
if (lvis) visible=true; if (lvis) visible=true;
@ -459,14 +478,30 @@ function createInput(configItem, frame,clazz) {
return el; return el;
} }
function updateSelectList(item,slist){ function setSelect(item,value){
item.innerHTML=''; if (!item) return;
item.value=value;
if (item.value !== value){
//missing option with his value
let o=addEl('option',undefined,item,value);
o.setAttribute('value',value);
item.value=value;
}
}
function updateSelectList(item,slist,opt_keepValue){
let idx=0; let idx=0;
let value;
if (opt_keepValue) value=item.value;
item.innerHTML='';
slist.forEach(function (sitem) { slist.forEach(function (sitem) {
let sitemEl = addEl('option','',item,sitem.l); let sitemEl = addEl('option','',item,sitem.l);
sitemEl.setAttribute('value', sitem.v !== undefined?sitem.v:idx); sitemEl.setAttribute('value', sitem.v !== undefined?sitem.v:idx);
idx++; idx++;
}) })
if (value !== undefined){
setSelect(item,value);
}
} }
function getXdrCategories(){ function getXdrCategories(){
let rt=[]; let rt=[];
@ -833,6 +868,19 @@ function formatDate(d){
else rt+=v; else rt+=v;
return rt; return rt;
} }
function downloadData(data,name){
let url="data:application/octet-stream,"+encodeURIComponent(JSON.stringify(data,undefined,2));
let target=document.getElementById('downloadXdr');
if (! target) return;
target.setAttribute('href',url);
target.setAttribute('download',name);
target.click();
}
function exportConfig(){
let data=getAllConfigs(true);
if (! data) return;
downloadData(data,"config"+formatDate()+".json");
}
function exportXdr(){ function exportXdr(){
let data={}; let data={};
forEl('.xdrvalue',function(el) { forEl('.xdrvalue',function(el) {
@ -845,18 +893,14 @@ function exportXdr(){
} }
data[name]=value; data[name]=value;
}) })
let url="data:application/octet-stream,"+encodeURIComponent(JSON.stringify(data,undefined,2)); downloadData(data,"xdr"+formatDate()+".json");
let target=document.getElementById('downloadXdr');
if (! target) return;
target.setAttribute('href',url);
target.setAttribute('download',"xdr"+formatDate()+".json");
target.click();
} }
function importXdr(){ function importJson(opt_keyPattern){
forEl('.uploadXdr',function(ul){ let clazz='importJson';
forEl('.'+clazz,function(ul){
ul.remove(); ul.remove();
}); });
let ip=addEl('input','uploadXdr',document.body); let ip=addEl('input',clazz,document.body);
ip.setAttribute('type','file'); ip.setAttribute('type','file');
ip.addEventListener('change',function(ev){ ip.addEventListener('change',function(ev){
if (ip.files.length > 0){ if (ip.files.length > 0){
@ -867,7 +911,7 @@ function importXdr(){
let idata=JSON.parse(reader.result); let idata=JSON.parse(reader.result);
let hasOverwrites=false; let hasOverwrites=false;
for (let k in idata){ for (let k in idata){
if (! k.match(/^XDR[0-9][0-9]*/)){ if (opt_keyPattern && ! k.match(opt_keyPattern)){
alert("file contains invalid key "+k); alert("file contains invalid key "+k);
return; return;
} }
@ -898,6 +942,12 @@ function importXdr(){
}); });
ip.click(); ip.click();
} }
function importXdr(){
importJson(new RegExp(/^XDR[0-9][0-9]*/));
}
function importConfig(){
importJson();
}
function toggleClass(el,id,classList){ function toggleClass(el,id,classList){
let nc=classList[id]; let nc=classList[id];
let rt=false; let rt=false;
@ -1023,6 +1073,10 @@ function createConfigDefinitions(parent, capabilities, defs,includeXdr) {
function loadConfigDefinitions() { function loadConfigDefinitions() {
getJson("api/capabilities") getJson("api/capabilities")
.then(function (capabilities) { .then(function (capabilities) {
if (capabilities.HELP_URL){
let el=document.getElementById('helpButton');
if (el) el.setAttribute('data-url',capabilities.HELP_URL);
}
getJson("config.json") getJson("config.json")
.then(function (defs) { .then(function (defs) {
getJson("xdrconfig.json") getJson("xdrconfig.json")
@ -1141,7 +1195,11 @@ function converterInfo() {
} }
function handleTab(el) { function handleTab(el) {
let activeName = el.getAttribute('data-page'); let activeName = el.getAttribute('data-page');
if (!activeName) return; if (!activeName) {
let extUrl= el.getAttribute('data-url');
if (! extUrl) return;
window.open(extUrl,el.getAttribute('data-window')||'_');
}
let activeTab = document.getElementById(activeName); let activeTab = document.getElementById(activeName);
if (!activeTab) return; if (!activeTab) return;
let all = document.querySelectorAll('.tabPage'); let all = document.querySelectorAll('.tabPage');
@ -1462,7 +1520,7 @@ function updateDashboard(data) {
} }
if (selectChanged){ if (selectChanged){
forEl('.boatDataSelect',function(el){ forEl('.boatDataSelect',function(el){
updateSelectList(el,selectList); updateSelectList(el,selectList,true);
}); });
} }
} }