256 lines
9.1 KiB
C++
256 lines
9.1 KiB
C++
#ifndef _GWBOATDATA_H
|
|
#define _GWBOATDATA_H
|
|
|
|
#include "GwLog.h"
|
|
#include "GWConfig.h"
|
|
#include <Arduino.h>
|
|
#include <map>
|
|
#include <vector>
|
|
#define GW_BOAT_VALUE_LEN 32
|
|
#define GWSC(name) static constexpr const char* name=#name
|
|
|
|
//see https://github.com/wellenvogel/esp32-nmea2000/issues/44
|
|
//factor to convert from N2k/SI rad/s to current NMEA rad/min
|
|
#define ROT_WA_FACTOR 60
|
|
|
|
class GwJsonDocument;
|
|
class GwBoatData;
|
|
|
|
class GwBoatItemBase{
|
|
public:
|
|
using TOType=enum{
|
|
def=1,
|
|
ais=2,
|
|
sensor=3,
|
|
lng=4,
|
|
user=5,
|
|
keep=6
|
|
};
|
|
class StringWriter{
|
|
uint8_t *buffer =NULL;
|
|
uint8_t *wp=NULL;
|
|
size_t bufferSize=0;
|
|
size_t baseOffset=0;
|
|
void ensure(size_t size);
|
|
public:
|
|
StringWriter();
|
|
size_t write(uint8_t c);
|
|
size_t write(const uint8_t* s, size_t n);
|
|
const char * c_str() const;
|
|
int getSize() const;
|
|
void setBase();
|
|
bool baseFilled();
|
|
void reset();
|
|
};
|
|
static const long INVALID_TIME=60000;
|
|
//the formatter names that must be known in js
|
|
GWSC(formatCourse);
|
|
GWSC(formatKnots);
|
|
GWSC(formatWind);
|
|
GWSC(formatLatitude);
|
|
GWSC(formatLongitude);
|
|
GWSC(formatXte);
|
|
GWSC(formatFixed0);
|
|
GWSC(formatDepth);
|
|
GWSC(kelvinToC);
|
|
GWSC(mtr2nm);
|
|
GWSC(formatDop);
|
|
GWSC(formatRot);
|
|
GWSC(formatDate);
|
|
GWSC(formatTime);
|
|
protected:
|
|
int type;
|
|
unsigned long lastSet=0;
|
|
long invalidTime=INVALID_TIME;
|
|
String name;
|
|
String format;
|
|
StringWriter writer;
|
|
TOType toType=TOType::def;
|
|
void uls(unsigned long ts=0){
|
|
if (ts) lastSet=ts;
|
|
else lastSet=millis();
|
|
writer.reset(); //value has changed
|
|
}
|
|
int lastUpdateSource;
|
|
public:
|
|
int getCurrentType(){return type;}
|
|
unsigned long getLastSet() const {return lastSet;}
|
|
bool isValid(unsigned long now=0) const ;
|
|
GwBoatItemBase(String name,String format,TOType toType);
|
|
GwBoatItemBase(String name,String format,unsigned long invalidTime);
|
|
virtual ~GwBoatItemBase(){}
|
|
void invalidate(){
|
|
lastSet=0;
|
|
}
|
|
const char *getDataString(){
|
|
fillString();
|
|
return writer.c_str();
|
|
}
|
|
virtual void fillString()=0;
|
|
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime)=0;
|
|
virtual size_t getJsonSize();
|
|
virtual int getLastSource(){return lastUpdateSource;}
|
|
virtual void refresh(unsigned long ts=0){uls(ts);}
|
|
virtual double getDoubleValue()=0;
|
|
String getName(){return name;}
|
|
const String & getFormat() const{return format;}
|
|
virtual void setInvalidTime(GwConfigHandler *cfg);
|
|
TOType getToType(){return toType;}
|
|
class GwBoatItemMap : public std::map<String,GwBoatItemBase*>{
|
|
GwBoatData *boatData;
|
|
public:
|
|
GwBoatItemMap(GwBoatData *bd):boatData(bd){}
|
|
void add(const String &name,GwBoatItemBase *item);
|
|
};
|
|
};
|
|
template<class T> class GwBoatItem : public GwBoatItemBase{
|
|
protected:
|
|
T data;
|
|
bool lastStringValid=false;
|
|
public:
|
|
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(){}
|
|
bool update(T nv, int source);
|
|
bool updateMax(T nv,int sourceId);
|
|
T getData(){
|
|
return data;
|
|
}
|
|
T getDataWithDefault(T defaultv){
|
|
if (! isValid(millis())) return defaultv;
|
|
return data;
|
|
}
|
|
virtual double getDoubleValue(){return (double)data;}
|
|
virtual void fillString();
|
|
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime);
|
|
virtual int getLastSource(){return lastUpdateSource;}
|
|
};
|
|
double formatCourse(double cv);
|
|
double formatDegToRad(double deg);
|
|
double formatWind(double cv);
|
|
double formatKnots(double cv);
|
|
double formatKmh(double cv);
|
|
uint32_t mtr2nm(uint32_t m);
|
|
double mtr2nm(double m);
|
|
|
|
class GwSatInfo{
|
|
public:
|
|
unsigned char PRN;
|
|
uint32_t Elevation;
|
|
uint32_t Azimut;
|
|
uint32_t SNR;
|
|
unsigned long validTill;
|
|
};
|
|
class GwSatInfoList{
|
|
public:
|
|
static const GwBoatItemBase::TOType toType=GwBoatItemBase::TOType::lng;
|
|
std::vector<GwSatInfo> sats;
|
|
void houseKeeping(unsigned long ts=0);
|
|
void update(GwSatInfo entry, unsigned long validTill);
|
|
int getNumSats() const{
|
|
return sats.size();
|
|
}
|
|
GwSatInfo *getAt(int idx){
|
|
if (idx >= 0 && idx < sats.size()) return &sats.at(idx);
|
|
return NULL;
|
|
}
|
|
operator double(){ return getNumSats();}
|
|
};
|
|
|
|
class GwBoatDataSatList : public GwBoatItem<GwSatInfoList>
|
|
{
|
|
public:
|
|
GwBoatDataSatList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map = NULL);
|
|
bool update(GwSatInfo info, int source);
|
|
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime);
|
|
GwSatInfo *getAt(int idx){
|
|
if (! isValid()) return NULL;
|
|
return data.getAt(idx);
|
|
}
|
|
int getNumSats(){
|
|
if (! isValid()) return 0;
|
|
return data.getNumSats();
|
|
}
|
|
virtual double getDoubleValue(){
|
|
return (double)(data.getNumSats());
|
|
}
|
|
|
|
};
|
|
|
|
class GwBoatItemNameProvider
|
|
{
|
|
public:
|
|
virtual String getBoatItemName() = 0;
|
|
virtual String getBoatItemFormat() = 0;
|
|
virtual unsigned long getInvalidTime(){ return GwBoatItemBase::INVALID_TIME;}
|
|
virtual ~GwBoatItemNameProvider() {}
|
|
};
|
|
#define GWBOATDATAT(type,name,toType,fmt) \
|
|
static constexpr const char* _##name=#name; \
|
|
GwBoatItem<type> *name=new GwBoatItem<type>(#name,GwBoatItemBase::fmt,toType,&values) ;
|
|
#define GWBOATDATA(type,name,fmt) GWBOATDATAT(type,name,GwBoatItemBase::TOType::def,fmt)
|
|
#define GWSPECBOATDATA(clazz,name,toType,fmt) \
|
|
clazz *name=new clazz(#name,GwBoatItemBase::fmt,toType,&values) ;
|
|
class GwBoatData{
|
|
private:
|
|
GwLog *logger=nullptr;
|
|
GwConfigHandler *config=nullptr;
|
|
GwBoatItemBase::GwBoatItemMap values{this};
|
|
public:
|
|
|
|
GWBOATDATA(double,COG,formatCourse) // course over ground
|
|
GWBOATDATA(double,SOG,formatKnots) // speed over ground
|
|
GWBOATDATA(double,HDT,formatCourse) // true heading
|
|
GWBOATDATA(double,HDM,formatCourse) // magnetic heading
|
|
GWBOATDATA(double,STW,formatKnots) // water speed
|
|
GWBOATDATA(double,VAR,formatWind) // variation
|
|
GWBOATDATA(double,DEV,formatWind) // deviation
|
|
GWBOATDATA(double,AWA,formatWind) // apparent wind ANGLE
|
|
GWBOATDATA(double,AWS,formatKnots) // apparent wind speed
|
|
GWBOATDATAT(double,MaxAws,GwBoatItemBase::TOType::keep,formatKnots)
|
|
GWBOATDATA(double,TWD,formatCourse) // true wind DIRECTION
|
|
GWBOATDATA(double,TWA,formatWind) // true wind ANGLE
|
|
GWBOATDATA(double,TWS,formatKnots) // true wind speed
|
|
|
|
GWBOATDATAT(double,MaxTws,GwBoatItemBase::TOType::keep,formatKnots)
|
|
GWBOATDATA(double,ROT,formatRot) // rate of turn
|
|
GWBOATDATA(double,RPOS,formatWind) // rudder position
|
|
GWBOATDATA(double,PRPOS,formatWind) // secondary rudder position
|
|
GWBOATDATA(double,LAT,formatLatitude)
|
|
GWBOATDATA(double,LON,formatLongitude)
|
|
GWBOATDATA(double,ALT,formatFixed0) //altitude
|
|
GWBOATDATA(double,HDOP,formatDop)
|
|
GWBOATDATA(double,PDOP,formatDop)
|
|
GWBOATDATA(double,VDOP,formatDop)
|
|
GWBOATDATA(double,DBS,formatDepth) //waterDepth (below surface)
|
|
GWBOATDATA(double,DBT,formatDepth) //DepthTransducer
|
|
GWBOATDATA(double,GPST,formatTime) // GPS time (seconds of day)
|
|
GWBOATDATA(uint32_t,GPSD,formatDate) // GPS date (days since 1979-01-01)
|
|
GWBOATDATAT(int16_t,TZ,GwBoatItemBase::TOType::lng,formatFixed0)
|
|
GWBOATDATA(double,WTemp,kelvinToC)
|
|
GWBOATDATAT(uint32_t,Log,GwBoatItemBase::TOType::lng,mtr2nm)
|
|
GWBOATDATAT(uint32_t,TripLog,GwBoatItemBase::TOType::lng,mtr2nm)
|
|
GWBOATDATA(double,DTW,mtr2nm) // distance to waypoint
|
|
GWBOATDATA(double,BTW,formatCourse) // bearing to waypoint
|
|
GWBOATDATA(double,XTE,formatXte) // cross track error
|
|
GWBOATDATA(double,WPLat,formatLatitude) // waypoint latitude
|
|
GWBOATDATA(double,WPLon,formatLongitude) // waypoint longitude
|
|
GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::toType,formatFixed0);
|
|
public:
|
|
GwBoatData(GwLog *logger, GwConfigHandler *cfg);
|
|
~GwBoatData();
|
|
void begin();
|
|
template<class T> GwBoatItem<T> *getOrCreate(T initial,GwBoatItemNameProvider *provider);
|
|
template<class T> bool update(T value,int source,GwBoatItemNameProvider *provider);
|
|
template<class T> T getDataWithDefault(T defaultv, GwBoatItemNameProvider *provider);
|
|
void setInvalidTime(GwBoatItemBase *item);
|
|
bool isValid(String name);
|
|
double getDoubleValue(String name,double defaultv);
|
|
GwBoatItemBase *getBase(String name);
|
|
String toJson() const;
|
|
String toString();
|
|
};
|
|
|
|
|
|
#endif
|