Merge branch 'wellenvogel:master' into master
This commit is contained in:
commit
6a4d6229aa
|
@ -1,6 +1,7 @@
|
||||||
#include "GwBoatData.h"
|
#include "GwBoatData.h"
|
||||||
#include <GwJsonDocument.h>
|
#include <GwJsonDocument.h>
|
||||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||||
|
#include "GWConfig.h"
|
||||||
#define GWTYPE_DOUBLE 1
|
#define GWTYPE_DOUBLE 1
|
||||||
#define GWTYPE_UINT32 2
|
#define GWTYPE_UINT32 2
|
||||||
#define GWTYPE_UINT16 3
|
#define GWTYPE_UINT16 3
|
||||||
|
@ -35,6 +36,23 @@ GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalid
|
||||||
this->format = format;
|
this->format = format;
|
||||||
this->type = 0;
|
this->type = 0;
|
||||||
this->lastUpdateSource = -1;
|
this->lastUpdateSource = -1;
|
||||||
|
this->toType=TOType::user;
|
||||||
|
}
|
||||||
|
GwBoatItemBase::GwBoatItemBase(String name, String format, GwBoatItemBase::TOType toType)
|
||||||
|
{
|
||||||
|
lastSet = 0;
|
||||||
|
this->invalidTime = INVALID_TIME;
|
||||||
|
this->toType=toType;
|
||||||
|
this->name = name;
|
||||||
|
this->format = format;
|
||||||
|
this->type = 0;
|
||||||
|
this->lastUpdateSource = -1;
|
||||||
|
this->toType=TOType::user;
|
||||||
|
}
|
||||||
|
void GwBoatItemBase::setInvalidTime(unsigned long it, bool force){
|
||||||
|
if (toType != TOType::user || force ){
|
||||||
|
invalidTime=it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
size_t GwBoatItemBase::getJsonSize() { return JSON_OBJECT_SIZE(10); }
|
size_t GwBoatItemBase::getJsonSize() { return JSON_OBJECT_SIZE(10); }
|
||||||
#define STRING_SIZE 40
|
#define STRING_SIZE 40
|
||||||
|
@ -113,6 +131,16 @@ GwBoatItem<T>::GwBoatItem(String name, String formatInfo, unsigned long invalidT
|
||||||
(*map)[name] = this;
|
(*map)[name] = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
template <class T>
|
||||||
|
GwBoatItem<T>::GwBoatItem(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map) : GwBoatItemBase(name, formatInfo, toType)
|
||||||
|
{
|
||||||
|
T dummy;
|
||||||
|
this->type = GwBoatItemTypes::getType(dummy);
|
||||||
|
if (map)
|
||||||
|
{
|
||||||
|
(*map)[name] = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
bool GwBoatItem<T>::update(T nv, int source)
|
bool GwBoatItem<T>::update(T nv, int source)
|
||||||
|
@ -246,14 +274,13 @@ void GwSatInfoList::houseKeeping(unsigned long ts)
|
||||||
sats.end(),
|
sats.end(),
|
||||||
[ts, this](const GwSatInfo &info)
|
[ts, this](const GwSatInfo &info)
|
||||||
{
|
{
|
||||||
return (info.timestamp + lifeTime) < ts;
|
return info.validTill < ts;
|
||||||
}),
|
}),
|
||||||
sats.end());
|
sats.end());
|
||||||
}
|
}
|
||||||
void GwSatInfoList::update(GwSatInfo entry)
|
void GwSatInfoList::update(GwSatInfo entry, unsigned long validTill)
|
||||||
{
|
{
|
||||||
unsigned long now = millis();
|
entry.validTill = validTill;
|
||||||
entry.timestamp = now;
|
|
||||||
for (auto it = sats.begin(); it != sats.end(); it++)
|
for (auto it = sats.begin(); it != sats.end(); it++)
|
||||||
{
|
{
|
||||||
if (it->PRN == entry.PRN)
|
if (it->PRN == entry.PRN)
|
||||||
|
@ -267,7 +294,7 @@ void GwSatInfoList::update(GwSatInfo entry)
|
||||||
sats.push_back(entry);
|
sats.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime, GwBoatItemMap *map) : GwBoatItem<GwSatInfoList>(name, formatInfo, invalidTime, map) {}
|
GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map) : GwBoatItem<GwSatInfoList>(name, formatInfo, toType, map) {}
|
||||||
|
|
||||||
bool GwBoatDataSatList::update(GwSatInfo info, int source)
|
bool GwBoatDataSatList::update(GwSatInfo info, int source)
|
||||||
{
|
{
|
||||||
|
@ -284,7 +311,7 @@ bool GwBoatDataSatList::update(GwSatInfo info, int source)
|
||||||
}
|
}
|
||||||
lastUpdateSource = source;
|
lastUpdateSource = source;
|
||||||
uls(now);
|
uls(now);
|
||||||
data.update(info);
|
data.update(info,now+invalidTime);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
|
void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
|
||||||
|
@ -293,9 +320,31 @@ void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
|
||||||
GwBoatItem<GwSatInfoList>::toJsonDoc(doc, minTime);
|
GwBoatItem<GwSatInfoList>::toJsonDoc(doc, minTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
GwBoatData::GwBoatData(GwLog *logger)
|
GwBoatData::GwBoatData(GwLog *logger, GwConfigHandler *cfg)
|
||||||
{
|
{
|
||||||
this->logger = logger;
|
this->logger = logger;
|
||||||
|
for (auto &&it : values){
|
||||||
|
unsigned long timeout=GwBoatItemBase::INVALID_TIME;
|
||||||
|
switch(it.second->getToType()){
|
||||||
|
case GwBoatItemBase::TOType::ais:
|
||||||
|
timeout=cfg->getInt(GwConfigDefinitions::timoAis);
|
||||||
|
break;
|
||||||
|
case GwBoatItemBase::TOType::def:
|
||||||
|
timeout=cfg->getInt(GwConfigDefinitions::timoDefault);
|
||||||
|
break;
|
||||||
|
case GwBoatItemBase::TOType::lng:
|
||||||
|
timeout=cfg->getInt(GwConfigDefinitions::timoLong);
|
||||||
|
break;
|
||||||
|
case GwBoatItemBase::TOType::sensor:
|
||||||
|
timeout=cfg->getInt(GwConfigDefinitions::timoSensor);
|
||||||
|
break;
|
||||||
|
case GwBoatItemBase::TOType::keep:
|
||||||
|
timeout=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
it.second->setInvalidTime(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
GwBoatData::~GwBoatData()
|
GwBoatData::~GwBoatData()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define _GWBOATDATA_H
|
#define _GWBOATDATA_H
|
||||||
|
|
||||||
#include "GwLog.h"
|
#include "GwLog.h"
|
||||||
|
#include "GWConfig.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -15,6 +16,14 @@
|
||||||
class GwJsonDocument;
|
class GwJsonDocument;
|
||||||
class GwBoatItemBase{
|
class GwBoatItemBase{
|
||||||
public:
|
public:
|
||||||
|
using TOType=enum{
|
||||||
|
def=1,
|
||||||
|
ais=2,
|
||||||
|
sensor=3,
|
||||||
|
lng=4,
|
||||||
|
user=5,
|
||||||
|
keep=6
|
||||||
|
};
|
||||||
class StringWriter{
|
class StringWriter{
|
||||||
uint8_t *buffer =NULL;
|
uint8_t *buffer =NULL;
|
||||||
uint8_t *wp=NULL;
|
uint8_t *wp=NULL;
|
||||||
|
@ -31,7 +40,7 @@ class GwBoatItemBase{
|
||||||
bool baseFilled();
|
bool baseFilled();
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
static const unsigned long INVALID_TIME=60000;
|
static const long INVALID_TIME=60000;
|
||||||
//the formatter names that must be known in js
|
//the formatter names that must be known in js
|
||||||
GWSC(formatCourse);
|
GWSC(formatCourse);
|
||||||
GWSC(formatKnots);
|
GWSC(formatKnots);
|
||||||
|
@ -51,10 +60,11 @@ class GwBoatItemBase{
|
||||||
protected:
|
protected:
|
||||||
int type;
|
int type;
|
||||||
unsigned long lastSet=0;
|
unsigned long lastSet=0;
|
||||||
unsigned long invalidTime=INVALID_TIME;
|
long invalidTime=INVALID_TIME;
|
||||||
String name;
|
String name;
|
||||||
String format;
|
String format;
|
||||||
StringWriter writer;
|
StringWriter writer;
|
||||||
|
TOType toType=TOType::def;
|
||||||
void uls(unsigned long ts=0){
|
void uls(unsigned long ts=0){
|
||||||
if (ts) lastSet=ts;
|
if (ts) lastSet=ts;
|
||||||
else lastSet=millis();
|
else lastSet=millis();
|
||||||
|
@ -65,7 +75,8 @@ class GwBoatItemBase{
|
||||||
int getCurrentType(){return type;}
|
int getCurrentType(){return type;}
|
||||||
unsigned long getLastSet() const {return lastSet;}
|
unsigned long getLastSet() const {return lastSet;}
|
||||||
bool isValid(unsigned long now=0) const ;
|
bool isValid(unsigned long now=0) const ;
|
||||||
GwBoatItemBase(String name,String format,unsigned long invalidTime=INVALID_TIME);
|
GwBoatItemBase(String name,String format,TOType toType);
|
||||||
|
GwBoatItemBase(String name,String format,unsigned long invalidTime);
|
||||||
virtual ~GwBoatItemBase(){}
|
virtual ~GwBoatItemBase(){}
|
||||||
void invalidate(){
|
void invalidate(){
|
||||||
lastSet=0;
|
lastSet=0;
|
||||||
|
@ -82,6 +93,8 @@ class GwBoatItemBase{
|
||||||
virtual double getDoubleValue()=0;
|
virtual double getDoubleValue()=0;
|
||||||
String getName(){return name;}
|
String getName(){return name;}
|
||||||
const String & getFormat() const{return format;}
|
const String & getFormat() const{return format;}
|
||||||
|
virtual void setInvalidTime(unsigned long it, bool force=true);
|
||||||
|
TOType getToType(){return toType;}
|
||||||
};
|
};
|
||||||
class GwBoatData;
|
class GwBoatData;
|
||||||
template<class T> class GwBoatItem : public GwBoatItemBase{
|
template<class T> class GwBoatItem : public GwBoatItemBase{
|
||||||
|
@ -90,6 +103,7 @@ template<class T> class GwBoatItem : public GwBoatItemBase{
|
||||||
bool lastStringValid=false;
|
bool lastStringValid=false;
|
||||||
public:
|
public:
|
||||||
GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL);
|
GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL);
|
||||||
|
GwBoatItem(String name,String formatInfo,TOType toType,GwBoatItemMap *map=NULL);
|
||||||
virtual ~GwBoatItem(){}
|
virtual ~GwBoatItem(){}
|
||||||
bool update(T nv, int source=-1);
|
bool update(T nv, int source=-1);
|
||||||
bool updateMax(T nv,int sourceId=-1);
|
bool updateMax(T nv,int sourceId=-1);
|
||||||
|
@ -118,14 +132,14 @@ class GwSatInfo{
|
||||||
uint32_t Elevation;
|
uint32_t Elevation;
|
||||||
uint32_t Azimut;
|
uint32_t Azimut;
|
||||||
uint32_t SNR;
|
uint32_t SNR;
|
||||||
unsigned long timestamp;
|
unsigned long validTill;
|
||||||
};
|
};
|
||||||
class GwSatInfoList{
|
class GwSatInfoList{
|
||||||
public:
|
public:
|
||||||
static const unsigned long lifeTime=32000;
|
static const GwBoatItemBase::TOType toType=GwBoatItemBase::TOType::lng;
|
||||||
std::vector<GwSatInfo> sats;
|
std::vector<GwSatInfo> sats;
|
||||||
void houseKeeping(unsigned long ts=0);
|
void houseKeeping(unsigned long ts=0);
|
||||||
void update(GwSatInfo entry);
|
void update(GwSatInfo entry, unsigned long validTill);
|
||||||
int getNumSats() const{
|
int getNumSats() const{
|
||||||
return sats.size();
|
return sats.size();
|
||||||
}
|
}
|
||||||
|
@ -139,7 +153,7 @@ class GwSatInfoList{
|
||||||
class GwBoatDataSatList : public GwBoatItem<GwSatInfoList>
|
class GwBoatDataSatList : public GwBoatItem<GwSatInfoList>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime = INVALID_TIME, GwBoatItemMap *map = NULL);
|
GwBoatDataSatList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map = NULL);
|
||||||
bool update(GwSatInfo info, int source);
|
bool update(GwSatInfo info, int source);
|
||||||
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime);
|
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime);
|
||||||
GwSatInfo *getAt(int idx){
|
GwSatInfo *getAt(int idx){
|
||||||
|
@ -164,55 +178,59 @@ public:
|
||||||
virtual unsigned long getInvalidTime(){ return GwBoatItemBase::INVALID_TIME;}
|
virtual unsigned long getInvalidTime(){ return GwBoatItemBase::INVALID_TIME;}
|
||||||
virtual ~GwBoatItemNameProvider() {}
|
virtual ~GwBoatItemNameProvider() {}
|
||||||
};
|
};
|
||||||
#define GWBOATDATA(type,name,time,fmt) \
|
#define GWBOATDATAT(type,name,toType,fmt) \
|
||||||
static constexpr const char* _##name=#name; \
|
static constexpr const char* _##name=#name; \
|
||||||
GwBoatItem<type> *name=new GwBoatItem<type>(#name,GwBoatItemBase::fmt,time,&values) ;
|
GwBoatItem<type> *name=new GwBoatItem<type>(#name,GwBoatItemBase::fmt,toType,&values) ;
|
||||||
#define GWSPECBOATDATA(clazz,name,time,fmt) \
|
#define GWBOATDATA(type,name,fmt) GWBOATDATAT(type,name,GwBoatItemBase::TOType::def,fmt)
|
||||||
clazz *name=new clazz(#name,GwBoatItemBase::fmt,time,&values) ;
|
#define GWSPECBOATDATA(clazz,name,toType,fmt) \
|
||||||
|
clazz *name=new clazz(#name,GwBoatItemBase::fmt,toType,&values) ;
|
||||||
class GwBoatData{
|
class GwBoatData{
|
||||||
|
static const unsigned long DEF_TIME=4000;
|
||||||
private:
|
private:
|
||||||
GwLog *logger;
|
GwLog *logger;
|
||||||
GwBoatItemBase::GwBoatItemMap values;
|
GwBoatItemBase::GwBoatItemMap values;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GWBOATDATA(double,COG,4000,formatCourse)
|
GWBOATDATA(double,COG,formatCourse) // course over ground
|
||||||
GWBOATDATA(double,TWD,4000,formatCourse)
|
GWBOATDATA(double,SOG,formatKnots) // speed over ground
|
||||||
GWBOATDATA(double,SOG,4000,formatKnots)
|
GWBOATDATA(double,HDT,formatCourse) // true heading
|
||||||
GWBOATDATA(double,STW,4000,formatKnots)
|
GWBOATDATA(double,HDM,formatCourse) // magnetic heading
|
||||||
GWBOATDATA(double,TWS,4000,formatKnots)
|
GWBOATDATA(double,STW,formatKnots) // water speed
|
||||||
GWBOATDATA(double,AWS,4000,formatKnots)
|
GWBOATDATA(double,VAR,formatWind) // variation
|
||||||
GWBOATDATA(double,MaxTws,0,formatKnots)
|
GWBOATDATA(double,DEV,formatWind) // deviation
|
||||||
GWBOATDATA(double,MaxAws,0,formatKnots)
|
GWBOATDATA(double,AWA,formatWind) // apparent wind ANGLE
|
||||||
GWBOATDATA(double,AWA,4000,formatWind)
|
GWBOATDATA(double,AWS,formatKnots) // apparent wind speed
|
||||||
GWBOATDATA(double,HDG,4000,formatCourse) //true heading
|
GWBOATDATAT(double,MaxAws,GwBoatItemBase::TOType::keep,formatKnots)
|
||||||
GWBOATDATA(double,MHDG,4000,formatCourse) //magnetic heading
|
GWBOATDATA(double,TWD,formatCourse) // true wind DIRECTION
|
||||||
GWBOATDATA(double,ROT,4000,formatRot)
|
GWBOATDATA(double,TWA,formatWind) // true wind ANGLE
|
||||||
GWBOATDATA(double,VAR,4000,formatCourse) //Variation
|
GWBOATDATA(double,TWS,formatKnots) // true wind speed
|
||||||
GWBOATDATA(double,DEV,4000,formatCourse) //Deviation
|
|
||||||
GWBOATDATA(double,HDOP,4000,formatDop)
|
GWBOATDATAT(double,MaxTws,GwBoatItemBase::TOType::keep,formatKnots)
|
||||||
GWBOATDATA(double,PDOP,4000,formatDop)
|
GWBOATDATA(double,ROT,formatRot) // rate of turn
|
||||||
GWBOATDATA(double,VDOP,4000,formatDop)
|
GWBOATDATA(double,RPOS,formatWind) // rudder position
|
||||||
GWBOATDATA(double,RPOS,4000,formatWind) //RudderPosition
|
GWBOATDATA(double,PRPOS,formatWind) // secondary rudder position
|
||||||
GWBOATDATA(double,PRPOS,4000,formatWind) //second rudder pos
|
GWBOATDATA(double,LAT,formatLatitude)
|
||||||
GWBOATDATA(double,LAT,4000,formatLatitude)
|
GWBOATDATA(double,LON,formatLongitude)
|
||||||
GWBOATDATA(double,LON,4000,formatLongitude)
|
GWBOATDATA(double,ALT,formatFixed0) //altitude
|
||||||
GWBOATDATA(double,ALT,4000,formatFixed0) //altitude
|
GWBOATDATA(double,HDOP,formatDop)
|
||||||
GWBOATDATA(double,DBS,4000,formatDepth) //waterDepth (below surface)
|
GWBOATDATA(double,PDOP,formatDop)
|
||||||
GWBOATDATA(double,DBT,4000,formatDepth) //DepthTransducer
|
GWBOATDATA(double,VDOP,formatDop)
|
||||||
GWBOATDATA(double,GPST,4000,formatTime) //GpsTime
|
GWBOATDATA(double,DBS,formatDepth) //waterDepth (below surface)
|
||||||
GWBOATDATA(double,WTemp,4000,kelvinToC)
|
GWBOATDATA(double,DBT,formatDepth) //DepthTransducer
|
||||||
GWBOATDATA(double,XTE,4000,formatXte)
|
GWBOATDATA(double,GPST,formatTime) // GPS time (seconds of day)
|
||||||
GWBOATDATA(double,DTW,4000,mtr2nm) //distance wp
|
GWBOATDATA(uint32_t,GPSD,formatDate) // GPS date (days since 1979-01-01)
|
||||||
GWBOATDATA(double,BTW,4000,formatCourse) //bearing wp
|
GWBOATDATAT(int16_t,TZ,GwBoatItemBase::TOType::lng,formatFixed0)
|
||||||
GWBOATDATA(double,WPLat,4000,formatLatitude)
|
GWBOATDATA(double,WTemp,kelvinToC)
|
||||||
GWBOATDATA(double,WPLon,4000,formatLongitude)
|
GWBOATDATAT(uint32_t,Log,GwBoatItemBase::TOType::lng,mtr2nm)
|
||||||
GWBOATDATA(uint32_t,Log,16000,mtr2nm)
|
GWBOATDATAT(uint32_t,TripLog,GwBoatItemBase::TOType::lng,mtr2nm)
|
||||||
GWBOATDATA(uint32_t,TripLog,16000,mtr2nm)
|
GWBOATDATA(double,DTW,mtr2nm) // distance to waypoint
|
||||||
GWBOATDATA(uint32_t,GPSD,4000,formatDate) //Date
|
GWBOATDATA(double,BTW,formatCourse) // bearing to waypoint
|
||||||
GWBOATDATA(int16_t,TZ,8000,formatFixed0)
|
GWBOATDATA(double,XTE,formatXte) // cross track error
|
||||||
GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::lifeTime,formatFixed0);
|
GWBOATDATA(double,WPLat,formatLatitude) // waypoint latitude
|
||||||
|
GWBOATDATA(double,WPLon,formatLongitude) // waypoint longitude
|
||||||
|
GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::toType,formatFixed0);
|
||||||
public:
|
public:
|
||||||
GwBoatData(GwLog *logger);
|
GwBoatData(GwLog *logger, GwConfigHandler *cfg);
|
||||||
~GwBoatData();
|
~GwBoatData();
|
||||||
template<class T> GwBoatItem<T> *getOrCreate(T initial,GwBoatItemNameProvider *provider);
|
template<class T> GwBoatItem<T> *getOrCreate(T initial,GwBoatItemNameProvider *provider);
|
||||||
template<class T> bool update(T value,int source,GwBoatItemNameProvider *provider);
|
template<class T> bool update(T value,int source,GwBoatItemNameProvider *provider);
|
||||||
|
|
|
@ -406,13 +406,13 @@ private:
|
||||||
case NMEA0183Wind_Apparent:
|
case NMEA0183Wind_Apparent:
|
||||||
n2kRef=N2kWind_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);
|
||||||
break;
|
break;
|
||||||
case NMEA0183Wind_True:
|
case NMEA0183Wind_True:
|
||||||
n2kRef=N2kWind_True_North;
|
n2kRef=N2kWind_True_water;
|
||||||
shouldSend=updateDouble(boatData->TWD,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);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -467,8 +467,7 @@ private:
|
||||||
|
|
||||||
void convertMWD(const SNMEA0183Msg &msg)
|
void convertMWD(const SNMEA0183Msg &msg)
|
||||||
{
|
{
|
||||||
double WindAngle = NMEA0183DoubleNA, WindAngleMagnetic=NMEA0183DoubleNA,
|
double WindDirection = NMEA0183DoubleNA, WindDirectionMagnetic=NMEA0183DoubleNA, WindSpeed = NMEA0183DoubleNA;
|
||||||
WindSpeed = NMEA0183DoubleNA;
|
|
||||||
if (msg.FieldCount() < 8 )
|
if (msg.FieldCount() < 8 )
|
||||||
{
|
{
|
||||||
LOG_DEBUG(GwLog::DEBUG, "failed to parse MWD %s", msg.line);
|
LOG_DEBUG(GwLog::DEBUG, "failed to parse MWD %s", msg.line);
|
||||||
|
@ -476,11 +475,11 @@ private:
|
||||||
}
|
}
|
||||||
if (msg.FieldLen(0) > 0 && msg.Field(1)[0] == 'T')
|
if (msg.FieldLen(0) > 0 && msg.Field(1)[0] == 'T')
|
||||||
{
|
{
|
||||||
WindAngle = formatDegToRad(atof(msg.Field(0)));
|
WindDirection = formatDegToRad(atof(msg.Field(0)));
|
||||||
}
|
}
|
||||||
if (msg.FieldLen(2) > 0 && msg.Field(3)[0] == 'M')
|
if (msg.FieldLen(2) > 0 && msg.Field(3)[0] == 'M')
|
||||||
{
|
{
|
||||||
WindAngleMagnetic = formatDegToRad(atof(msg.Field(2)));
|
WindDirectionMagnetic = formatDegToRad(atof(msg.Field(2)));
|
||||||
}
|
}
|
||||||
if (msg.FieldLen(4) > 0 && msg.Field(5)[0] == 'N')
|
if (msg.FieldLen(4) > 0 && msg.Field(5)[0] == 'N')
|
||||||
{
|
{
|
||||||
|
@ -497,32 +496,30 @@ private:
|
||||||
}
|
}
|
||||||
tN2kMsg n2kMsg;
|
tN2kMsg n2kMsg;
|
||||||
bool shouldSend = false;
|
bool shouldSend = false;
|
||||||
if (WindAngle != NMEA0183DoubleNA){
|
if (WindDirection != NMEA0183DoubleNA){
|
||||||
shouldSend = updateDouble(boatData->TWD, WindAngle, msg.sourceId) &&
|
shouldSend = updateDouble(boatData->TWD, WindDirection, 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);
|
||||||
}
|
if(shouldSend && boatData->HDT->isValid()) {
|
||||||
if (shouldSend)
|
double twa = WindDirection-boatData->HDT->getData();
|
||||||
{
|
if(twa<0) { twa+=2*M_PI; }
|
||||||
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindAngle, N2kWind_True_North);
|
updateDouble(boatData->TWA, twa, msg.sourceId);
|
||||||
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_True_North));
|
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, twa, N2kWind_True_water);
|
||||||
}
|
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_True_water));
|
||||||
if (WindAngleMagnetic != NMEA0183DoubleNA && shouldSend){
|
}
|
||||||
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindAngleMagnetic, N2kWind_Magnetic);
|
|
||||||
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_Magnetic));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void convertHDM(const SNMEA0183Msg &msg){
|
void convertHDM(const SNMEA0183Msg &msg){
|
||||||
double MHDG=NMEA0183DoubleNA;
|
double HDM=NMEA0183DoubleNA;
|
||||||
if (!NMEA0183ParseHDM_nc(msg, MHDG))
|
if (!NMEA0183ParseHDM_nc(msg, HDM))
|
||||||
{
|
{
|
||||||
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(MHDG)) return;
|
if (! UD(HDM)) return;
|
||||||
tN2kMsg n2kMsg;
|
tN2kMsg n2kMsg;
|
||||||
SetN2kMagneticHeading(n2kMsg,1,MHDG,
|
SetN2kMagneticHeading(n2kMsg,1,HDM,
|
||||||
boatData->VAR->getDataWithDefault(N2kDoubleNA),
|
boatData->VAR->getDataWithDefault(N2kDoubleNA),
|
||||||
boatData->DEV->getDataWithDefault(N2kDoubleNA)
|
boatData->DEV->getDataWithDefault(N2kDoubleNA)
|
||||||
);
|
);
|
||||||
|
@ -530,28 +527,29 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void convertHDT(const SNMEA0183Msg &msg){
|
void convertHDT(const SNMEA0183Msg &msg){
|
||||||
double HDG=NMEA0183DoubleNA;
|
double HDT=NMEA0183DoubleNA;
|
||||||
if (!NMEA0183ParseHDT_nc(msg, HDG))
|
if (!NMEA0183ParseHDT_nc(msg, HDT))
|
||||||
{
|
{
|
||||||
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(HDG)) return;
|
if (! UD(HDT)) return;
|
||||||
tN2kMsg n2kMsg;
|
tN2kMsg n2kMsg;
|
||||||
SetN2kTrueHeading(n2kMsg,1,HDG);
|
SetN2kTrueHeading(n2kMsg,1,HDT);
|
||||||
send(n2kMsg,msg.sourceId);
|
send(n2kMsg,msg.sourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void convertHDG(const SNMEA0183Msg &msg){
|
void convertHDG(const SNMEA0183Msg &msg){
|
||||||
double MHDG=NMEA0183DoubleNA;
|
double HDM=NMEA0183DoubleNA;
|
||||||
double VAR=NMEA0183DoubleNA;
|
|
||||||
double DEV=NMEA0183DoubleNA;
|
double DEV=NMEA0183DoubleNA;
|
||||||
|
double VAR=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){
|
||||||
MHDG=formatDegToRad(atof(msg.Field(0)));
|
HDM=formatDegToRad(atof(msg.Field(0)));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
return;
|
return;
|
||||||
|
@ -565,11 +563,11 @@ private:
|
||||||
if (msg.Field(4)[0] == 'W') VAR=-VAR;
|
if (msg.Field(4)[0] == 'W') VAR=-VAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! UD(MHDG)) return;
|
if (! UD(HDM)) return;
|
||||||
UD(VAR);
|
UD(VAR);
|
||||||
UD(DEV);
|
UD(DEV);
|
||||||
tN2kMsg n2kMsg;
|
tN2kMsg n2kMsg;
|
||||||
SetN2kMagneticHeading(n2kMsg,1,MHDG,DEV,VAR);
|
SetN2kMagneticHeading(n2kMsg,1,HDM,DEV,VAR);
|
||||||
send(n2kMsg,msg.sourceId,"127250M");
|
send(n2kMsg,msg.sourceId,"127250M");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,11 +703,11 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tN2kMsg n2kMsg;
|
tN2kMsg n2kMsg;
|
||||||
if (updateDouble(boatData->HDG,TrueHeading,msg.sourceId)){
|
if (updateDouble(boatData->HDT,TrueHeading,msg.sourceId)){
|
||||||
SetN2kTrueHeading(n2kMsg,1,TrueHeading);
|
SetN2kTrueHeading(n2kMsg,1,TrueHeading);
|
||||||
send(n2kMsg,msg.sourceId);
|
send(n2kMsg,msg.sourceId);
|
||||||
}
|
}
|
||||||
if(updateDouble(boatData->MHDG,MagneticHeading,msg.sourceId)){
|
if(updateDouble(boatData->HDM,MagneticHeading,msg.sourceId)){
|
||||||
SetN2kMagneticHeading(n2kMsg,1,MagneticHeading,
|
SetN2kMagneticHeading(n2kMsg,1,MagneticHeading,
|
||||||
boatData->DEV->getDataWithDefault(N2kDoubleNA),
|
boatData->DEV->getDataWithDefault(N2kDoubleNA),
|
||||||
boatData->VAR->getDataWithDefault(N2kDoubleNA)
|
boatData->VAR->getDataWithDefault(N2kDoubleNA)
|
||||||
|
|
|
@ -185,13 +185,13 @@ private:
|
||||||
if (N2kIsNA(Variation)){
|
if (N2kIsNA(Variation)){
|
||||||
//no variation
|
//no variation
|
||||||
if (ref == N2khr_magnetic){
|
if (ref == N2khr_magnetic){
|
||||||
updateDouble(boatData->MHDG,Heading);
|
updateDouble(boatData->HDM,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->HDG,Heading);
|
updateDouble(boatData->HDT,Heading);
|
||||||
if (NMEA0183SetHDT(NMEA0183Msg,Heading,talkerId)){
|
if (NMEA0183SetHDT(NMEA0183Msg,Heading,talkerId)){
|
||||||
SendMessage(NMEA0183Msg);
|
SendMessage(NMEA0183Msg);
|
||||||
}
|
}
|
||||||
|
@ -206,8 +206,8 @@ private:
|
||||||
if (ref == N2khr_true){
|
if (ref == N2khr_true){
|
||||||
MagneticHeading=Heading-Variation;
|
MagneticHeading=Heading-Variation;
|
||||||
}
|
}
|
||||||
updateDouble(boatData->MHDG,MagneticHeading);
|
updateDouble(boatData->HDM,MagneticHeading);
|
||||||
updateDouble(boatData->HDG,Heading);
|
updateDouble(boatData->HDT,Heading);
|
||||||
if (!N2kIsNA(MagneticHeading)){
|
if (!N2kIsNA(MagneticHeading)){
|
||||||
if (NMEA0183SetHDG(NMEA0183Msg, MagneticHeading,_Deviation,
|
if (NMEA0183SetHDG(NMEA0183Msg, MagneticHeading,_Deviation,
|
||||||
Variation,talkerId))
|
Variation,talkerId))
|
||||||
|
@ -252,8 +252,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->HDG->isValid(now) && boatData->VAR->isValid(now)) ? boatData->HDG->getData() + boatData->VAR->getData() : NMEA0183DoubleNA;
|
double MagneticHeading = (boatData->HDT->isValid(now) && boatData->VAR->isValid(now)) ? boatData->HDT->getData() + boatData->VAR->getData() : NMEA0183DoubleNA;
|
||||||
if (NMEA0183SetVHW(NMEA0183Msg, boatData->HDG->getDataWithDefault(NMEA0183DoubleNA), MagneticHeading, WaterReferenced,talkerId))
|
if (NMEA0183SetVHW(NMEA0183Msg, boatData->HDT->getDataWithDefault(NMEA0183DoubleNA), MagneticHeading, WaterReferenced,talkerId))
|
||||||
{
|
{
|
||||||
SendMessage(NMEA0183Msg);
|
SendMessage(NMEA0183Msg);
|
||||||
}
|
}
|
||||||
|
@ -468,37 +468,46 @@ private:
|
||||||
{
|
{
|
||||||
unsigned char SID;
|
unsigned char SID;
|
||||||
tN2kWindReference WindReference;
|
tN2kWindReference WindReference;
|
||||||
tNMEA0183WindReference NMEA0183Reference = NMEA0183Wind_True;
|
|
||||||
|
|
||||||
double x, y;
|
|
||||||
double WindAngle=N2kDoubleNA, WindSpeed=N2kDoubleNA;
|
double WindAngle=N2kDoubleNA, WindSpeed=N2kDoubleNA;
|
||||||
|
|
||||||
if (ParseN2kWindSpeed(N2kMsg, SID, WindSpeed, WindAngle, WindReference))
|
if (ParseN2kWindSpeed(N2kMsg, SID, WindSpeed, WindAngle, WindReference)) {
|
||||||
{
|
|
||||||
tNMEA0183Msg NMEA0183Msg;
|
tNMEA0183Msg NMEA0183Msg;
|
||||||
|
tNMEA0183WindReference NMEA0183Reference;
|
||||||
|
bool shouldSend = false;
|
||||||
|
|
||||||
if (WindReference == N2kWind_Apparent)
|
// MWV sentence contains apparent/true ANGLE and SPEED
|
||||||
{
|
// 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
|
||||||
|
|
||||||
|
if (WindReference == N2kWind_Apparent) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
if (WindReference == N2kWind_True_North)
|
if (WindReference == N2kWind_True_water) {
|
||||||
{
|
|
||||||
NMEA0183Reference = NMEA0183Wind_True;
|
NMEA0183Reference = NMEA0183Wind_True;
|
||||||
updateDouble(boatData->TWD, WindAngle);
|
updateDouble(boatData->TWA, WindAngle);
|
||||||
updateDouble(boatData->TWS, WindSpeed);
|
updateDouble(boatData->TWS, WindSpeed);
|
||||||
|
setMax(boatData->MaxTws, boatData->TWS);
|
||||||
|
shouldSend = true;
|
||||||
|
if (boatData->HDT->isValid()) {
|
||||||
|
double twd = WindAngle+boatData->HDT->getData();
|
||||||
|
if (twd>2*M_PI) { twd-=2*M_PI; }
|
||||||
|
updateDouble(boatData->TWD, twd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (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
|
||||||
|
|
||||||
x = WindSpeed * cos(WindAngle);
|
double x = WindSpeed * cos(WindAngle);
|
||||||
y = WindSpeed * sin(WindAngle);
|
double y = WindSpeed * sin(WindAngle);
|
||||||
|
|
||||||
updateDouble(boatData->TWD, atan2(y, -boatData->SOG->getData() + x));
|
updateDouble(boatData->TWD, atan2(y, -boatData->SOG->getData() + x));
|
||||||
updateDouble(boatData->TWS, sqrt((y * y) + ((-boatData->SOG->getData() + x) * (-boatData->SOG->getData() + x))));
|
updateDouble(boatData->TWS, sqrt((y * y) + ((-boatData->SOG->getData() + x) * (-boatData->SOG->getData() + x))));
|
||||||
|
@ -534,7 +543,7 @@ private:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SendMessage(NMEA0183Msg);
|
SendMessage(NMEA0183Msg);
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
@ -657,12 +666,14 @@ private:
|
||||||
double _Heading=N2kDoubleNA;
|
double _Heading=N2kDoubleNA;
|
||||||
double _ROT=N2kDoubleNA;
|
double _ROT=N2kDoubleNA;
|
||||||
tN2kAISNavStatus _NavStatus;
|
tN2kAISNavStatus _NavStatus;
|
||||||
|
tN2kAISTransceiverInformation _AISTransceiverInformation;
|
||||||
|
uint8_t _SID;
|
||||||
|
|
||||||
uint8_t _MessageType = 1;
|
uint8_t _MessageType = 1;
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
|
||||||
if (ParseN2kPGN129038(N2kMsg, SID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, _Seconds,
|
if (ParseN2kPGN129038(N2kMsg, SID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, _Seconds,
|
||||||
_COG, _SOG, _Heading, _ROT, _NavStatus))
|
_COG, _SOG, _Heading, _ROT, _NavStatus,_AISTransceiverInformation,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
@ -746,12 +757,13 @@ private:
|
||||||
tN2kGNSStype _GNSStype;
|
tN2kGNSStype _GNSStype;
|
||||||
tN2kAISTransceiverInformation _AISinfo;
|
tN2kAISTransceiverInformation _AISinfo;
|
||||||
tN2kAISDTE _DTE;
|
tN2kAISDTE _DTE;
|
||||||
|
uint8_t _SID;
|
||||||
|
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
|
||||||
if (ParseN2kPGN129794(N2kMsg, _MessageID, _Repeat, _UserID, _IMONumber, _Callsign, _Name, _VesselType,
|
if (ParseN2kPGN129794(N2kMsg, _MessageID, _Repeat, _UserID, _IMONumber, _Callsign, 8, _Name,21, _VesselType,
|
||||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,
|
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,21,
|
||||||
_AISversion, _GNSStype, _DTE, _AISinfo))
|
_AISversion, _GNSStype, _DTE, _AISinfo,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef SERIAL_PRINT_AIS_FIELDS
|
#ifdef SERIAL_PRINT_AIS_FIELDS
|
||||||
|
@ -855,9 +867,10 @@ private:
|
||||||
bool _Display, _DSC, _Band, _Msg22, _State;
|
bool _Display, _DSC, _Band, _Msg22, _State;
|
||||||
tN2kAISMode _Mode;
|
tN2kAISMode _Mode;
|
||||||
tN2kAISTransceiverInformation _AISTranceiverInformation;
|
tN2kAISTransceiverInformation _AISTranceiverInformation;
|
||||||
|
uint8_t _SID;
|
||||||
|
|
||||||
if (ParseN2kPGN129039(N2kMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
if (ParseN2kPGN129039(N2kMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
||||||
_Seconds, _COG, _SOG, _AISTranceiverInformation, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State))
|
_Seconds, _COG, _SOG, _AISTranceiverInformation, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
@ -896,8 +909,10 @@ private:
|
||||||
tN2kAISRepeat _Repeat;
|
tN2kAISRepeat _Repeat;
|
||||||
uint32_t _UserID; // MMSI
|
uint32_t _UserID; // MMSI
|
||||||
char _Name[21];
|
char _Name[21];
|
||||||
|
tN2kAISTransceiverInformation _AISInfo;
|
||||||
|
uint8_t _SID;
|
||||||
|
|
||||||
if (ParseN2kPGN129809(N2kMsg, _MessageID, _Repeat, _UserID, _Name))
|
if (ParseN2kPGN129809(N2kMsg, _MessageID, _Repeat, _UserID, _Name,21,_AISInfo,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
@ -923,9 +938,11 @@ private:
|
||||||
double _Beam=N2kDoubleNA;
|
double _Beam=N2kDoubleNA;
|
||||||
double _PosRefStbd=N2kDoubleNA;
|
double _PosRefStbd=N2kDoubleNA;
|
||||||
double _PosRefBow=N2kDoubleNA;
|
double _PosRefBow=N2kDoubleNA;
|
||||||
|
tN2kAISTransceiverInformation _AISInfo;
|
||||||
|
uint8_t _SID;
|
||||||
|
|
||||||
if (ParseN2kPGN129810(N2kMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor, _Callsign,
|
if (ParseN2kPGN129810(N2kMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor,4, _Callsign,8,
|
||||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID))
|
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID,_AISInfo,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1121,8 +1138,8 @@ private:
|
||||||
int16_t ETADate=0;
|
int16_t ETADate=0;
|
||||||
double BearingOriginToDestinationWaypoint=N2kDoubleNA;
|
double BearingOriginToDestinationWaypoint=N2kDoubleNA;
|
||||||
double BearingPositionToDestinationWaypoint=N2kDoubleNA;
|
double BearingPositionToDestinationWaypoint=N2kDoubleNA;
|
||||||
uint8_t OriginWaypointNumber;
|
uint32_t OriginWaypointNumber;
|
||||||
uint8_t DestinationWaypointNumber;
|
uint32_t DestinationWaypointNumber;
|
||||||
double DestinationLatitude=N2kDoubleNA;
|
double DestinationLatitude=N2kDoubleNA;
|
||||||
double DestinationLongitude=N2kDoubleNA;
|
double DestinationLongitude=N2kDoubleNA;
|
||||||
double WaypointClosingVelocity=N2kDoubleNA;
|
double WaypointClosingVelocity=N2kDoubleNA;
|
||||||
|
|
|
@ -355,6 +355,7 @@ void GwXDRMappings::begin()
|
||||||
GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list, int instance, const char *key)
|
GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list, int instance, const char *key)
|
||||||
{
|
{
|
||||||
GwXDRMapping *candidate = NULL;
|
GwXDRMapping *candidate = NULL;
|
||||||
|
unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor);
|
||||||
for (auto mit = list->begin(); mit != list->end(); mit++)
|
for (auto mit = list->begin(); mit != list->end(); mit++)
|
||||||
{
|
{
|
||||||
GwXDRMappingDef *def = (*mit)->definition;
|
GwXDRMappingDef *def = (*mit)->definition;
|
||||||
|
@ -369,7 +370,7 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,
|
||||||
{
|
{
|
||||||
LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d",
|
LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d",
|
||||||
def->toString().c_str(), key, instance);
|
def->toString().c_str(), key, instance);
|
||||||
return GwXDRFoundMapping(*mit, instance);
|
return GwXDRFoundMapping(*mit,invalidTime, instance);
|
||||||
}
|
}
|
||||||
if (instance < 0)
|
if (instance < 0)
|
||||||
{
|
{
|
||||||
|
@ -393,7 +394,7 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,
|
||||||
{
|
{
|
||||||
LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d",
|
LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d",
|
||||||
candidate->definition->toString().c_str(), key, instance);
|
candidate->definition->toString().c_str(), key, instance);
|
||||||
return GwXDRFoundMapping(candidate, instance>=0?instance:candidate->definition->instanceId);
|
return GwXDRFoundMapping(candidate, invalidTime,instance>=0?instance:candidate->definition->instanceId);
|
||||||
}
|
}
|
||||||
LOG_DEBUG(GwLog::DEBUG + 1, "no instance mapping found for key=%s, i=%d", key, instance);
|
LOG_DEBUG(GwLog::DEBUG + 1, "no instance mapping found for key=%s, i=%d", key, instance);
|
||||||
return GwXDRFoundMapping();
|
return GwXDRFoundMapping();
|
||||||
|
@ -472,8 +473,9 @@ String GwXDRMappings::getXdrEntry(String mapping, double value,int instance){
|
||||||
}
|
}
|
||||||
GwXDRType *type = findType(code, &typeIndex);
|
GwXDRType *type = findType(code, &typeIndex);
|
||||||
bool first=true;
|
bool first=true;
|
||||||
|
unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor);
|
||||||
while (type){
|
while (type){
|
||||||
GwXDRFoundMapping found(def,type);
|
GwXDRFoundMapping found(def,type,invalidTime);
|
||||||
found.instanceId=instance;
|
found.instanceId=instance;
|
||||||
if (first) first=false;
|
if (first) first=false;
|
||||||
else rt+=",";
|
else rt+=",";
|
||||||
|
|
|
@ -167,15 +167,18 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{
|
||||||
GwXDRType *type=NULL;
|
GwXDRType *type=NULL;
|
||||||
int instanceId=-1;
|
int instanceId=-1;
|
||||||
bool empty=true;
|
bool empty=true;
|
||||||
GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type){
|
unsigned long timeout=0;
|
||||||
|
GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type, unsigned long timeout){
|
||||||
this->definition=definition;
|
this->definition=definition;
|
||||||
this->type=type;
|
this->type=type;
|
||||||
|
this->timeout=timeout;
|
||||||
empty=false;
|
empty=false;
|
||||||
}
|
}
|
||||||
GwXDRFoundMapping(GwXDRMapping* mapping,int instance=0){
|
GwXDRFoundMapping(GwXDRMapping* mapping,unsigned long timeout,int instance){
|
||||||
this->definition=mapping->definition;
|
this->definition=mapping->definition;
|
||||||
this->type=mapping->type;
|
this->type=mapping->type;
|
||||||
this->instanceId=instance;
|
this->instanceId=instance;
|
||||||
|
this->timeout=timeout;
|
||||||
empty=false;
|
empty=false;
|
||||||
}
|
}
|
||||||
GwXDRFoundMapping(){}
|
GwXDRFoundMapping(){}
|
||||||
|
@ -195,6 +198,9 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{
|
||||||
return "formatXdr:"+type->xdrtype+":"+type->boatDataUnit;
|
return "formatXdr:"+type->xdrtype+":"+type->boatDataUnit;
|
||||||
};
|
};
|
||||||
virtual ~GwXDRFoundMapping(){}
|
virtual ~GwXDRFoundMapping(){}
|
||||||
|
virtual unsigned long getInvalidTime() override{
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//the class GwXDRMappings is not intended to be deleted
|
//the class GwXDRMappings is not intended to be deleted
|
||||||
|
|
|
@ -18,8 +18,8 @@ extra_configs=
|
||||||
|
|
||||||
[basedeps]
|
[basedeps]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ttlappalainen/NMEA2000-library @ 4.18.9
|
ttlappalainen/NMEA2000-library @ 4.22.0
|
||||||
ttlappalainen/NMEA0183 @ 1.9.1
|
ttlappalainen/NMEA0183 @ 1.10.1
|
||||||
ArduinoJson @ 6.18.5
|
ArduinoJson @ 6.18.5
|
||||||
AsyncTCP-esphome @ 2.0.1
|
AsyncTCP-esphome @ 2.0.1
|
||||||
ottowinter/ESPAsyncWebServer-esphome@2.0.1
|
ottowinter/ESPAsyncWebServer-esphome@2.0.1
|
||||||
|
|
|
@ -138,7 +138,7 @@ bool fixedApPass=true;
|
||||||
#endif
|
#endif
|
||||||
GwWifi gwWifi(&config,&logger,fixedApPass);
|
GwWifi gwWifi(&config,&logger,fixedApPass);
|
||||||
GwChannelList channels(&logger,&config);
|
GwChannelList channels(&logger,&config);
|
||||||
GwBoatData boatData(&logger);
|
GwBoatData boatData(&logger,&config);
|
||||||
GwXDRMappings xdrMappings(&logger,&config);
|
GwXDRMappings xdrMappings(&logger,&config);
|
||||||
bool sendOutN2k=true;
|
bool sendOutN2k=true;
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,46 @@
|
||||||
"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": "timeouts",
|
||||||
|
"type": "array",
|
||||||
|
"replace":[
|
||||||
|
{
|
||||||
|
"n":"Default",
|
||||||
|
"d":"4000",
|
||||||
|
"l": "default",
|
||||||
|
"t": "NMEA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n":"Sensor",
|
||||||
|
"d":"60000",
|
||||||
|
"l": "sensor",
|
||||||
|
"t": "sensor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n":"Long",
|
||||||
|
"d":"32000",
|
||||||
|
"l": "long",
|
||||||
|
"t": "special NMEA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n":"Ais",
|
||||||
|
"d":"120000",
|
||||||
|
"l": "ais",
|
||||||
|
"t": "ais"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"name":"timo$n",
|
||||||
|
"label":"timeout $l",
|
||||||
|
"default": "$d",
|
||||||
|
"type": "number",
|
||||||
|
"description": "data timeouts(ms) for $t data",
|
||||||
|
"category": "converter"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "usbActisense",
|
"name": "usbActisense",
|
||||||
"label": "USB mode",
|
"label": "USB mode",
|
||||||
|
|
Loading…
Reference in New Issue