diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index cf217b5..2767dfc 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -1,54 +1,29 @@ #include "GwBoatData.h" -GwBoatItem *GwBoatData::find(String name,bool doCreate){ - GwBoatItemMap::iterator it; - if ((it=values.find(name)) != values.end()){ - return it->second; - } - if (! doCreate) return NULL; - GwBoatItem *ni=new GwBoatItem(); - values[name]=ni; - return ni; -} GwBoatData::GwBoatData(GwLog *logger){ } GwBoatData::~GwBoatData(){ - GwBoatItemMap::iterator it; + GwBoatItemBase::GwBoatItemMap::iterator it; for (it=values.begin() ; it != values.end();it++){ delete it->second; } } -void GwBoatData::update(String name,const char *value){ - GwBoatItem *i=find(name); - i->update(value); -} -void GwBoatData::update(String name, String value){ - GwBoatItem *i=find(name); - i->update(value); -} -void GwBoatData::update(String name, long value){ - GwBoatItem *i=find(name); - i->update(value); -} -void GwBoatData::update(String name, double value){ - GwBoatItem *i=find(name); - i->update(value); -} -void GwBoatData::update(String name, bool value){ - GwBoatItem *i=find(name); - i->update(value); -} + String GwBoatData::toJson() const { - long minTime=millis() - maxAge; + long minTime=millis(); DynamicJsonDocument json(800); - GwBoatItemMap::const_iterator it; + GwBoatItemBase::GwBoatItemMap::const_iterator it; for (it=values.begin() ; it != values.end();it++){ if (it->second->isValid(minTime)){ - json[it->first]=it->second->getValue(); + it->second->toJsonDoc(&json,it->first); } } String buf; serializeJson(json,buf); return buf; +} + +GwBoatItemBase::GwBoatItemMap * GwBoatData::getValues(){ + return &values; } \ No newline at end of file diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index 27bc2bf..f00e2b1 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -6,62 +6,70 @@ #include #include #define GW_BOAT_VALUE_LEN 32 -class GwBoatItem{ - private: - char value[GW_BOAT_VALUE_LEN]; +class GwBoatItemBase{ + public: + static const long INVALID_TIME=60000; + typedef std::map GwBoatItemMap; + protected: long lastSet; + long invalidTime=INVALID_TIME; void uls(){ lastSet=millis(); } public: - const char * getValue() const{return value;} long getLastSet() const {return lastSet;} - bool isValid(long minTime) const {return lastSet > minTime;} - GwBoatItem(){ - value[0]=0; + bool isValid(long now) const { + return (lastSet + invalidTime) >= now; + } + GwBoatItemBase(long invalidTime=INVALID_TIME){ lastSet=-1; + this->invalidTime=invalidTime; } - void update(String nv){ - strncpy(value,nv.c_str(),GW_BOAT_VALUE_LEN-1); - uls(); - } - void update(const char * nv){ - strncpy(value,nv,GW_BOAT_VALUE_LEN-1); - } - void update(long nv){ - ltoa(nv,value,10); - uls(); - } - void update(bool nv){ - if (nv) strcpy_P(value,PSTR("true")); - else strcpy_P(value,PSTR("false")); - uls(); - } - void update(double nv){ - dtostrf(nv,3,7,value); - uls(); - } + virtual ~GwBoatItemBase(){} void invalidate(){ lastSet=0; } - + virtual void toJsonDoc(DynamicJsonDocument *doc,String name)=0; }; class GwBoatData{ - typedef std::map GwBoatItemMap; private: - const long maxAge=60000; //max age for valid data in ms GwLog *logger; - GwBoatItemMap values; - GwBoatItem *find(String name, bool doCreate=true); + GwBoatItemBase::GwBoatItemMap values; public: GwBoatData(GwLog *logger); - ~GwBoatData(); - void update(String name,const char *value); - void update(String name, String value); - void update(String name, long value); - void update(String name, bool value); - void update(String name, double value); + ~GwBoatData(); + GwBoatItemBase::GwBoatItemMap * getValues(); String toJson() const; - + friend class GwBoatItemBase; }; +template class GwBoatItem : public GwBoatItemBase{ + private: + T data; + public: + GwBoatItem(long invalidTime=INVALID_TIME): GwBoatItemBase(invalidTime){} + virtual ~GwBoatItem(){} + void update(T nv){ + data=nv; + uls(); + } + T getData(){ + return data; + } + virtual void toJsonDoc(DynamicJsonDocument *doc,String name){ + (*doc)[name]=data; + } + static GwBoatItem *findOrCreate(GwBoatData *handler, String name,bool doCreate=true, + long invalidTime=GwBoatItemBase::INVALID_TIME){ + GwBoatItemMap *values=handler->getValues(); + GwBoatItemMap::iterator it; + if ((it=values->find(name)) != values->end()){ + return (GwBoatItem *)it->second; + } + if (! doCreate) return NULL; + GwBoatItem *ni=new GwBoatItem(invalidTime); + (*values)[name]=ni; + return ni; + } +}; + #endif \ No newline at end of file diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp index 1b7629b..2b9b585 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp @@ -29,6 +29,30 @@ const double radToDeg = 180.0 / M_PI; +static void updateDouble(GwBoatItem *item,double value){ + if (value == N2kDoubleNA) return; + item->update(value); +} + +N2kDataToNMEA0183::N2kDataToNMEA0183(GwLog * logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tNMEA0183 *NMEA0183) : tNMEA2000::tMsgHandler(0,NMEA2000){ + SendNMEA0183MessageCallback=0; + pNMEA0183=NMEA0183; + Variation=N2kDoubleNA; COG=N2kDoubleNA; SOG=N2kDoubleNA; + SecondsSinceMidnight=N2kDoubleNA; DaysSince1970=N2kUInt16NA; + LastPosSend=0; + lastLoopTime=0; + NextRMCSend=millis()+RMCPeriod; + LastHeadingTime=0; + LastCOGSOGTime=0; + LastWindTime=0; + this->logger=logger; + this->boatData=boatData; + heading=GwBoatItem::findOrCreate(boatData,F("Heading"),true,2000); + latitude=GwBoatItem::findOrCreate(boatData,F("Latitude"),true,4000); + longitude=GwBoatItem::findOrCreate(boatData,F("Longitude"),true,4000); + altitude=GwBoatItem::findOrCreate(boatData,F("Altitude"),true,4000); + } + //***************************************************************************** void N2kDataToNMEA0183::HandleMsg(const tN2kMsg &N2kMsg) { switch (N2kMsg.PGN) { @@ -52,15 +76,10 @@ void N2kDataToNMEA0183::loop() { if ( now < (lastLoopTime + 100)) return; lastLoopTime=now; SendRMC(); - if ( (LastHeadingTime + 2000) < now ) Heading = N2kDoubleNA; if ( (LastCOGSOGTime + 2000) < now ) { COG = N2kDoubleNA; SOG = N2kDoubleNA; } - if ( (LastPositionTime + 4000) < now ) { - Latitude = N2kDoubleNA; - Longitude = N2kDoubleNA; - } if ( ( LastWindTime + 2000) < now ) { AWS = N2kDoubleNA; AWA = N2kDoubleNA; @@ -68,7 +87,7 @@ void N2kDataToNMEA0183::loop() { TWA = N2kDoubleNA; TWD = N2kDoubleNA; } - + /* boatData->update(F("Latitude"),Latitude); boatData->update(F("Longitude"),Longitude); boatData->update(F("Altitude"),Altitude); @@ -91,7 +110,7 @@ void N2kDataToNMEA0183::loop() { boatData->update(F("Variation"),Variation *radToDeg); boatData->update(F("GPSTime"),SecondsSinceMidnight); boatData->update(F("DaysSince1970"),(long)DaysSince1970); - + */ } //***************************************************************************** @@ -107,13 +126,13 @@ void N2kDataToNMEA0183::HandleHeading(const tN2kMsg &N2kMsg) { double _Deviation = 0; double _Variation; tNMEA0183Msg NMEA0183Msg; - + double Heading; if ( ParseN2kHeading(N2kMsg, SID, Heading, _Deviation, _Variation, ref) ) { if ( ref == N2khr_magnetic ) { if ( !N2kIsNA(_Variation) ) Variation = _Variation; // Update Variation if ( !N2kIsNA(Heading) && !N2kIsNA(Variation) ) Heading -= Variation; } - LastHeadingTime = millis(); + updateDouble(heading,Heading); if ( NMEA0183SetHDG(NMEA0183Msg, Heading, _Deviation, Variation) ) { SendMessage(NMEA0183Msg); } @@ -139,8 +158,8 @@ void N2kDataToNMEA0183::HandleBoatSpeed(const tN2kMsg &N2kMsg) { if ( ParseN2kBoatSpeed(N2kMsg, SID, WaterReferenced, GroundReferenced, SWRT) ) { tNMEA0183Msg NMEA0183Msg; STW=WaterReferenced; - double MagneticHeading = ( !N2kIsNA(Heading) && !N2kIsNA(Variation) ? Heading + Variation : NMEA0183DoubleNA); - if ( NMEA0183SetVHW(NMEA0183Msg, Heading, MagneticHeading, WaterReferenced) ) { + double MagneticHeading = ( heading->isValid(millis()) && !N2kIsNA(Variation) ? heading->getData() + Variation : NMEA0183DoubleNA); + if ( NMEA0183SetVHW(NMEA0183Msg, heading->getData(), MagneticHeading, WaterReferenced) ) { SendMessage(NMEA0183Msg); } } @@ -169,9 +188,11 @@ void N2kDataToNMEA0183::HandleDepth(const tN2kMsg &N2kMsg) { //***************************************************************************** void N2kDataToNMEA0183::HandlePosition(const tN2kMsg &N2kMsg) { - + double Latitude; + double Longitude; if ( ParseN2kPGN129025(N2kMsg, Latitude, Longitude) ) { - LastPositionTime = millis(); + updateDouble(latitude,Latitude); + updateDouble(longitude,Longitude); } } @@ -207,11 +228,15 @@ void N2kDataToNMEA0183::HandleGNSS(const tN2kMsg &N2kMsg) { tN2kGNSStype ReferenceStationType; uint16_t ReferenceSationID; double AgeOfCorrection; - + double Latitude; + double Longitude; + double Altitude; if ( ParseN2kGNSS(N2kMsg, SID, DaysSince1970, SecondsSinceMidnight, Latitude, Longitude, Altitude, GNSStype, GNSSmethod, nSatellites, HDOP, PDOP, GeoidalSeparation, nReferenceStations, ReferenceStationType, ReferenceSationID, AgeOfCorrection) ) { - LastPositionTime = millis(); + updateDouble(latitude,Latitude); + updateDouble(longitude,Longitude); + updateDouble(altitude,Altitude); } } @@ -241,7 +266,7 @@ void N2kDataToNMEA0183::HandleWind(const tN2kMsg &N2kMsg) { if (WindReference == N2kWind_Apparent && SOG != N2kDoubleNA) { // Lets calculate and send TWS/TWA if SOG is available - AWD=WindAngle*radToDeg + Heading*radToDeg; + AWD=WindAngle*radToDeg + heading->getData()*radToDeg; if (AWD>360) AWD=AWD-360; if (AWD<0) AWD=AWD+360; @@ -280,9 +305,10 @@ void N2kDataToNMEA0183::HandleWind(const tN2kMsg &N2kMsg) { } //***************************************************************************** void N2kDataToNMEA0183::SendRMC() { - if ( NextRMCSend <= millis() && !N2kIsNA(Latitude) ) { + long now=millis(); + if ( NextRMCSend <= millis() && latitude->isValid(now) ) { tNMEA0183Msg NMEA0183Msg; - if ( NMEA0183SetRMC(NMEA0183Msg, SecondsSinceMidnight, Latitude, Longitude, COG, SOG, DaysSince1970, Variation) ) { + if ( NMEA0183SetRMC(NMEA0183Msg, SecondsSinceMidnight, latitude->getData(), longitude->getData(), COG, SOG, DaysSince1970, Variation) ) { SendMessage(NMEA0183Msg); } SetNextRMCSend(); diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.h b/lib/nmea2kto0183/N2kDataToNMEA0183.h index 9b8aed6..45cbad9 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.h +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.h @@ -36,11 +36,11 @@ public: protected: static const unsigned long RMCPeriod=500; - double Latitude; - double Longitude; - double Altitude; + GwBoatItem *latitude; + GwBoatItem *longitude; + GwBoatItem * altitude; double Variation; - double Heading; + GwBoatItem *heading; double COG; double SOG; double STW; @@ -68,7 +68,6 @@ protected: unsigned long LastHeadingTime; unsigned long LastCOGSOGTime; - unsigned long LastPositionTime; unsigned long LastPosSend; unsigned long LastWindTime; unsigned long NextRMCSend; @@ -99,22 +98,7 @@ protected: void SendMessage(const tNMEA0183Msg &NMEA0183Msg); public: - N2kDataToNMEA0183(GwLog * logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tNMEA0183 *NMEA0183) : tNMEA2000::tMsgHandler(0,NMEA2000) { - SendNMEA0183MessageCallback=0; - pNMEA0183=NMEA0183; - Latitude=N2kDoubleNA; Longitude=N2kDoubleNA; Altitude=N2kDoubleNA; - Variation=N2kDoubleNA; Heading=N2kDoubleNA; COG=N2kDoubleNA; SOG=N2kDoubleNA; - SecondsSinceMidnight=N2kDoubleNA; DaysSince1970=N2kUInt16NA; - LastPosSend=0; - lastLoopTime=0; - NextRMCSend=millis()+RMCPeriod; - LastHeadingTime=0; - LastCOGSOGTime=0; - LastPositionTime=0; - LastWindTime=0; - this->logger=logger; - this->boatData=boatData; - } + N2kDataToNMEA0183(GwLog * logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tNMEA0183 *NMEA0183) ; void HandleMsg(const tN2kMsg &N2kMsg); void SetSendNMEA0183MessageCallback(tSendNMEA0183MessageCallback _SendNMEA0183MessageCallback) { SendNMEA0183MessageCallback=_SendNMEA0183MessageCallback;