From 636b1596f5a0117a444ee431d1a1442a3977df9e Mon Sep 17 00:00:00 2001 From: Ulrich Meine Date: Sat, 23 Aug 2025 01:41:39 +0200 Subject: [PATCH] Code cleanup: moved buffer + wind calc to OBPDataOperations; header to obp60task.h; tws 3 decimals --- lib/obp60task/BoatDataCalibration.h | 3 +- lib/obp60task/OBPDataOperations.cpp | 204 +++++++++++++++++++-- lib/obp60task/OBPDataOperations.h | 68 ++++++- lib/obp60task/OBPRingBuffer.h | 9 +- lib/obp60task/OBPRingBuffer.tpp | 72 ++++++-- lib/obp60task/PageWindPlot.cpp | 87 ++++----- lib/obp60task/Pagedata.h | 3 +- lib/obp60task/obp60task.cpp | 271 +++------------------------- lib/obp60task/obp60task.h | 14 ++ 9 files changed, 388 insertions(+), 343 deletions(-) diff --git a/lib/obp60task/BoatDataCalibration.h b/lib/obp60task/BoatDataCalibration.h index 5a0606b..d906fa9 100644 --- a/lib/obp60task/BoatDataCalibration.h +++ b/lib/obp60task/BoatDataCalibration.h @@ -3,7 +3,8 @@ #ifndef _BOATDATACALIBRATION_H #define _BOATDATACALIBRATION_H -#include "Pagedata.h" +// #include "Pagedata.h" +#include "GwApi.h" #include #include diff --git a/lib/obp60task/OBPDataOperations.cpp b/lib/obp60task/OBPDataOperations.cpp index 5e463e4..937a326 100644 --- a/lib/obp60task/OBPDataOperations.cpp +++ b/lib/obp60task/OBPDataOperations.cpp @@ -1,5 +1,147 @@ #include "OBPDataOperations.h" +// --- Class HstryBuf --------------- +// Init history buffers for selected boat data +void HstryBuf::init(BoatValueList* boatValues, GwLog *log) { + + logger = log; + + int hstryUpdFreq = 1000; // Update frequency for history buffers in ms + int hstryMinVal = 0; // Minimum value for these history buffers + twdHstryMax = 6283; // Max value for wind direction (TWD, AWD) in rad [0...2*PI], shifted by 1000 for 3 decimals + twsHstryMax = 65000; // Max value for wind speed (TWS, AWS) in m/s [0..65], shifted by 1000 for 3 decimals + awdHstryMax = twdHstryMax; + awsHstryMax = twsHstryMax; + twdHstryMin = hstryMinVal; + twsHstryMin = hstryMinVal; + awdHstryMin = hstryMinVal; + awsHstryMin = hstryMinVal; + const double DBL_MIN = std::numeric_limits::lowest(); + + // Initialize history buffers with meta data + hstryBufList.twdHstry->setMetaData("TWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax); + hstryBufList.twsHstry->setMetaData("TWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax); + hstryBufList.awdHstry->setMetaData("AWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax); + hstryBufList.awsHstry->setMetaData("AWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax); + + // create boat values for history data types, if they don't exist yet + twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName()); + twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName()); + twaBVal = boatValues->findValueOrCreate("TWA"); + awdBVal = boatValues->findValueOrCreate(hstryBufList.awdHstry->getName()); + awsBVal = boatValues->findValueOrCreate(hstryBufList.awsHstry->getName()); + + if (!awdBVal->valid) { // AWD usually does not exist + awdBVal->setFormat(hstryBufList.awdHstry->getFormat()); + awdBVal->value = DBL_MIN; + } + + // collect boat values for true wind calculation + awaBVal = boatValues->findValueOrCreate("AWA"); + hdtBVal = boatValues->findValueOrCreate("HDT"); + hdmBVal = boatValues->findValueOrCreate("HDM"); + varBVal = boatValues->findValueOrCreate("VAR"); + cogBVal = boatValues->findValueOrCreate("COG"); + sogBVal = boatValues->findValueOrCreate("SOG"); +} + +// Handle history buffers for TWD, TWS, AWD, AWS +//void HstryBuf::handleHstryBuf(GwApi* api, BoatValueList* boatValues, bool useSimuData) { +void HstryBuf::handleHstryBuf(bool useSimuData) { + + static int16_t twd = 20; //initial value only relevant if we use simulation data + static uint16_t tws = 20; //initial value only relevant if we use simulation data + static double awd, aws, hdt = 20; //initial value only relevant if we use simulation data + GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here + + LOG_DEBUG(GwLog::DEBUG,"obp60task handleHstryBuf: TWD_isValid? %d, twdBVal: %.1f, twaBVal: %.1f, twsBVal: %.1f", twdBVal->valid, twdBVal->value * RAD_TO_DEG, + twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852); + + if (twdBVal->valid) { + calBVal = new GwApi::BoatValue("TWD"); // temporary solution for calibration of history buffer values + calBVal->setFormat(twdBVal->getFormat()); + calBVal->value = twdBVal->value; + calBVal->valid = twdBVal->valid; + calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated + twd = static_cast(std::round(calBVal->value * 1000.0)); + if (twd >= twdHstryMin && twd <= twdHstryMax) { + hstryBufList.twdHstry->add(twd); + } + delete calBVal; + calBVal = nullptr; + } else if (useSimuData) { + twd += random(-20, 20); + twd = WindUtils::to360(twd); + hstryBufList.twdHstry->add(static_cast(DegToRad(twd) * 1000.0)); + } + + if (twsBVal->valid) { + calBVal = new GwApi::BoatValue("TWS"); // temporary solution for calibration of history buffer values + calBVal->setFormat(twsBVal->getFormat()); + calBVal->value = twsBVal->value; + calBVal->valid = twsBVal->valid; + calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated + tws = static_cast(std::round(calBVal->value * 1000)); + if (tws >= twsHstryMin && tws <= twsHstryMax) { + hstryBufList.twsHstry->add(tws); + } + delete calBVal; + calBVal = nullptr; + } else if (useSimuData) { + tws += random(-5000, 5000); // TWS value in m/s; expands to 3 decimals + tws = constrain(tws, 0, 25000); // Limit TWS to [0..25] m/s + hstryBufList.twsHstry->add(tws); + } + + if (awaBVal->valid) { + if (hdtBVal->valid) { + hdt = hdtBVal->value; // Use HDT if available + } else { + hdt = WindUtils::calcHDT(&hdmBVal->value, &varBVal->value, &cogBVal->value, &sogBVal->value); + } + + awd = awaBVal->value + hdt; + awd = WindUtils::to2PI(awd); + calBVal = new GwApi::BoatValue("AWD"); // temporary solution for calibration of history buffer values + calBVal->value = awd; + calBVal->setFormat(awdBVal->getFormat()); + calBVal->valid = true; + calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated + awdBVal->value = calBVal->value; + awdBVal->valid = true; + awd = std::round(calBVal->value * 1000.0); + if (awd >= awdHstryMin && awd <= awdHstryMax) { + hstryBufList.awdHstry->add(static_cast(awd)); + } + delete calBVal; + calBVal = nullptr; + } else if (useSimuData) { + awd += random(-20, 20); + awd = WindUtils::to360(awd); + hstryBufList.awdHstry->add(static_cast(DegToRad(awd) * 1000.0)); + } + + if (awsBVal->valid) { + calBVal = new GwApi::BoatValue("AWS"); // temporary solution for calibration of history buffer values + calBVal->setFormat(awsBVal->getFormat()); + calBVal->value = awsBVal->value; + calBVal->valid = awsBVal->valid; + calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated + aws = std::round(calBVal->value * 1000); + if (aws >= awsHstryMin && aws <= awsHstryMax) { + hstryBufList.awsHstry->add(static_cast(aws)); + } + delete calBVal; + calBVal = nullptr; + } else if (useSimuData) { + aws += random(-5000, 5000); // TWS value in m/s; expands to 1 decimal + aws = constrain(aws, 0, 25000); // Limit TWS to [0..25] m/s + hstryBufList.awsHstry->add(aws); + } +} +// --- Class HstryBuf --------------- + +// --- Class WindUtils -------------- double WindUtils::to2PI(double a) { a = fmod(a, 2 * M_PI); @@ -68,13 +210,11 @@ void WindUtils::calcTwdSA(const double* AWA, const double* AWS, double awd = *AWA + *HDT; awd = to2PI(awd); double stw = -*STW; - // Serial.println("\ncalcTwdSA: AWA: " + String(*AWA) + ", AWS: " + String(*AWS) + ", CTW: " + String(*CTW) + ", STW: " + String(*STW) + ", HDT: " + String(*HDT)); addPolar(&awd, AWS, CTW, &stw, TWD, TWS); // Normalize TWD and TWA to 0-360° *TWD = to2PI(*TWD); *TWA = toPI(*TWD - *HDT); - // Serial.println("calcTwdSA: TWD: " + String(*TWD) + ", TWS: " + String(*TWS)); } double WindUtils::calcHDT(const double* hdmVal, const double* varVal, const double* cogVal, const double* sogVal) @@ -83,7 +223,6 @@ double WindUtils::calcHDT(const double* hdmVal, const double* varVal, const doub double minSogVal = 0.1; // SOG below this value (m/s) is assumed to be data noise from GPS sensor static const double DBL_MIN = std::numeric_limits::lowest(); - // Serial.println("\ncalcTrueWind: HDT: " + String(*hdtVal) + ", HDM: " + String(*hdmVal) + ", VAR: " + String(*varVal) + ", SOG: " + String(*sogVal) + ", COG: " + String(*cogVal)); if (*hdmVal != DBL_MIN) { hdt = *hdmVal + (*varVal != DBL_MIN ? *varVal : 0.0); // Use corrected HDM if HDT is not available (or just HDM if VAR is not available) hdt = to2PI(hdt); @@ -105,19 +244,6 @@ bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal, double minSogVal = 0.1; // SOG below this value (m/s) is assumed to be data noise from GPS sensor static const double DBL_MIN = std::numeric_limits::lowest(); - // Serial.println("\ncalcTrueWind: HDT: " + String(*hdtVal) + ", HDM: " + String(*hdmVal) + ", VAR: " + String(*varVal) + ", SOG: " + String(*sogVal) + ", COG: " + String(*cogVal)); -/* if (*hdtVal != DBL_MIN) { - hdt = *hdtVal; // Use HDT if available - } else { - if (*hdmVal != DBL_MIN) { - hdt = *hdmVal + (*varVal != DBL_MIN ? *varVal : 0.0); // Use corrected HDM if HDT is not available (or just HDM if VAR is not available) - hdt = to2PI(hdt); - } else if (*cogVal != DBL_MIN && *sogVal >= minSogVal) { - hdt = *cogVal; // Use COG as fallback if HDT and HDM are not available, and SOG is not data noise - } else { - return false; // Cannot calculate without valid HDT or HDM+VAR or COG - } - } */ if (*hdtVal != DBL_MIN) { hdt = *hdtVal; // Use HDT if available } else { @@ -152,4 +278,48 @@ bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal, return true; } -} \ No newline at end of file +} + +// Calculate true wind data and add to obp60task boat data list +bool WindUtils::addTrueWind(GwApi* api, BoatValueList* boatValues, GwLog* log) { + + GwLog* logger = log; + + double awaVal, awsVal, cogVal, stwVal, sogVal, hdtVal, hdmVal, varVal; + double twd, tws, twa; + bool isCalculated = false; + const double DBL_MIN = std::numeric_limits::lowest(); + + awaVal = awaBVal->valid ? awaBVal->value : DBL_MIN; + awsVal = awsBVal->valid ? awsBVal->value : DBL_MIN; + cogVal = cogBVal->valid ? cogBVal->value : DBL_MIN; + stwVal = stwBVal->valid ? stwBVal->value : DBL_MIN; + sogVal = sogBVal->valid ? sogBVal->value : DBL_MIN; + hdtVal = hdtBVal->valid ? hdtBVal->value : DBL_MIN; + hdmVal = hdmBVal->valid ? hdmBVal->value : DBL_MIN; + varVal = varBVal->valid ? varBVal->value : DBL_MIN; + LOG_DEBUG(GwLog::DEBUG,"obp60task addTrueWind: AWA %.1f, AWS %.1f, COG %.1f, STW %.1f, SOG %.2f, HDT %.1f, HDM %.1f, VAR %.1f", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852, + cogBVal->value * RAD_TO_DEG, stwBVal->value * 3.6 / 1.852, sogBVal->value * 3.6 / 1.852, hdtBVal->value * RAD_TO_DEG, hdmBVal->value * RAD_TO_DEG, varBVal->value * RAD_TO_DEG); + + isCalculated = calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &sogVal, &hdtVal, &hdmVal, &varVal, &twd, &tws, &twa); + + if (isCalculated) { // Replace values only, if successfully calculated and not already available + if (!twdBVal->valid) { + twdBVal->value = twd; + twdBVal->valid = true; + } + if (!twsBVal->valid) { + twsBVal->value = tws; + twsBVal->valid = true; + } + if (!twaBVal->valid) { + twaBVal->value = twa; + twaBVal->valid = true; + } + } + LOG_DEBUG(GwLog::DEBUG,"obp60task addTrueWind: isCalculated %d, TWD %.1f, TWA %.1f, TWS %.1f", isCalculated, twdBVal->value * RAD_TO_DEG, + twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852); + + return isCalculated; +} +// --- Class WindUtils -------------- diff --git a/lib/obp60task/OBPDataOperations.h b/lib/obp60task/OBPDataOperations.h index 912a8d8..6e7083f 100644 --- a/lib/obp60task/OBPDataOperations.h +++ b/lib/obp60task/OBPDataOperations.h @@ -1,39 +1,89 @@ #pragma once -#include "GwApi.h" +#include #include "OBPRingBuffer.h" -// #include +#include "BoatDataCalibration.h" // Functions lib for data instance calibration +#include "obp60task.h" #include typedef struct { RingBuffer* twdHstry; - RingBuffer* twsHstry; + RingBuffer* twsHstry; RingBuffer* awdHstry; - RingBuffer* awsHstry; + RingBuffer* awsHstry; } tBoatHstryData; // Holds pointers to all history buffers for boat data class HstryBuf { +private: + GwLog *logger; + + RingBuffer twdHstry; // Circular buffer to store true wind direction values + RingBuffer twsHstry; // Circular buffer to store true wind speed values (TWS) + RingBuffer awdHstry; // Circular buffer to store apparant wind direction values + RingBuffer awsHstry; // Circular buffer to store apparant xwind speed values (AWS) + int16_t twdHstryMin; // Min value for wind direction (TWD) in history buffer + int16_t twdHstryMax; // Max value for wind direction (TWD) in history buffer + uint16_t twsHstryMin; + uint16_t twsHstryMax; + int16_t awdHstryMin; + int16_t awdHstryMax; + uint16_t awsHstryMin; + uint16_t awsHstryMax; + + // boat values for buffers and for true wind calculation + GwApi::BoatValue *twdBVal, *twsBVal, *twaBVal, *awdBVal, *awsBVal; + GwApi::BoatValue *awaBVal, *hdtBVal, *hdmBVal, *varBVal, *cogBVal, *sogBVal; public: + tBoatHstryData hstryBufList; + HstryBuf(){ + hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; // Generate history buffers of zero size + }; + HstryBuf(int size) { + hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; + hstryBufList.twdHstry->resize(960); // store 960 TWD values for 16 minutes history + hstryBufList.twsHstry->resize(960); + hstryBufList.awdHstry->resize(960); + hstryBufList.awsHstry->resize(960); + }; + void init(BoatValueList* boatValues, GwLog *log); + void handleHstryBuf(bool useSimuData); }; class WindUtils { +private: + GwApi::BoatValue *twdBVal, *twsBVal, *twaBVal; + GwApi::BoatValue *awaBVal, *awsBVal, *cogBVal, *stwBVal, *sogBVal, *hdtBVal, *hdmBVal, *varBVal; public: + WindUtils(BoatValueList* boatValues){ + twdBVal = boatValues->findValueOrCreate("TWD"); + twsBVal = boatValues->findValueOrCreate("TWS"); + twaBVal = boatValues->findValueOrCreate("TWA"); + awaBVal = boatValues->findValueOrCreate("AWA"); + awsBVal = boatValues->findValueOrCreate("AWS"); + cogBVal = boatValues->findValueOrCreate("COG"); + stwBVal = boatValues->findValueOrCreate("STW"); + sogBVal = boatValues->findValueOrCreate("SOG"); + hdtBVal = boatValues->findValueOrCreate("HDT"); + hdmBVal = boatValues->findValueOrCreate("HDM"); + varBVal = boatValues->findValueOrCreate("VAR"); + }; static double to2PI(double a); static double toPI(double a); static double to360(double a); static double to180(double a); - static void toCart(const double* phi, const double* r, double* x, double* y); - static void toPol(const double* x, const double* y, double* phi, double* r); - static void addPolar(const double* phi1, const double* r1, + void toCart(const double* phi, const double* r, double* x, double* y); + void toPol(const double* x, const double* y, double* phi, double* r); + void addPolar(const double* phi1, const double* r1, const double* phi2, const double* r2, double* phi, double* r); - static void calcTwdSA(const double* AWA, const double* AWS, + void calcTwdSA(const double* AWA, const double* AWS, const double* CTW, const double* STW, const double* HDT, double* TWD, double* TWS, double* TWA); static double calcHDT(const double* hdmVal, const double* varVal, const double* cogVal, const double* sogVal); - static bool calcTrueWind(const double* awaVal, const double* awsVal, + bool calcTrueWind(const double* awaVal, const double* awsVal, const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal, const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal); + bool addTrueWind(GwApi* api, BoatValueList* boatValues, GwLog *log); }; \ No newline at end of file diff --git a/lib/obp60task/OBPRingBuffer.h b/lib/obp60task/OBPRingBuffer.h index 79840de..e4b30fa 100644 --- a/lib/obp60task/OBPRingBuffer.h +++ b/lib/obp60task/OBPRingBuffer.h @@ -9,8 +9,7 @@ template class RingBuffer { private: - mutable SemaphoreHandle_t bufLocker; - std::vector buffer; + std::vector buffer; // THE buffer vector size_t capacity; size_t head; // Points to the next insertion position size_t first; // Points to the first (oldest) valid element @@ -19,6 +18,7 @@ private: bool is_Full; // Indicates that all buffer elements are used and ringing is in use T MIN_VAL; // lowest possible value of buffer T MAX_VAL; // highest possible value of buffer of type + mutable SemaphoreHandle_t bufLocker; // metadata for buffer String dataName; // Name of boat data in buffer @@ -27,10 +27,14 @@ private: T smallest; // Value range of buffer: smallest value T largest; // Value range of buffer: biggest value + void initCommon(); + public: + RingBuffer(); RingBuffer(size_t size); void setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue); // Set meta data for buffer bool getMetaData(String& name, String& format, int& updateFrequency, T& minValue, T& maxValue); // Get meta data of buffer + bool getMetaData(String& name, String& format); String getName() const; // Get buffer name String getFormat() const; // Get buffer data format void add(const T& value); // Add a new value to buffer @@ -54,6 +58,7 @@ public: T getMinVal() const; // Get lowest possible value for buffer; used for initialized buffer data T getMaxVal() const; // Get highest possible value for buffer void clear(); // Clear buffer + void resize(size_t size); // Delete buffer and set new size T operator[](size_t index) const; // Operator[] for convenient access (same as get()) std::vector getAllValues() const; // Get all current values as a vector }; diff --git a/lib/obp60task/OBPRingBuffer.tpp b/lib/obp60task/OBPRingBuffer.tpp index 2f7cc13..f361ec6 100644 --- a/lib/obp60task/OBPRingBuffer.tpp +++ b/lib/obp60task/OBPRingBuffer.tpp @@ -1,5 +1,30 @@ #include "OBPRingBuffer.h" +template +void RingBuffer::initCommon() { + MIN_VAL = std::numeric_limits::lowest(); + MAX_VAL = std::numeric_limits::max(); + dataName = ""; + dataFmt = ""; + updFreq = -1; + smallest = MIN_VAL; + largest = MAX_VAL; + bufLocker = xSemaphoreCreateMutex(); +} + +template +RingBuffer::RingBuffer() + : capacity(0) + , head(0) + , first(0) + , last(0) + , count(0) + , is_Full(false) +{ + initCommon(); + // stays empty +} + template RingBuffer::RingBuffer(size_t size) : capacity(size) @@ -9,23 +34,8 @@ RingBuffer::RingBuffer(size_t size) , count(0) , is_Full(false) { - bufLocker = xSemaphoreCreateMutex(); - - if (size == 0) { - // return false; - } - - MIN_VAL = std::numeric_limits::lowest(); - MAX_VAL = std::numeric_limits::max(); - dataName = ""; - dataFmt = ""; - updFreq = -1; - smallest = MIN_VAL; - largest = MAX_VAL; - + initCommon(); buffer.resize(size, MIN_VAL); - - // return true; } // Specify meta data of buffer content @@ -57,6 +67,20 @@ bool RingBuffer::getMetaData(String& name, String& format, int& updateFrequen return true; } +// Get meta data of buffer content +template +bool RingBuffer::getMetaData(String& name, String& format) +{ + if (dataName == "" || dataFmt == "") { + return false; // Meta data not set + } + + GWSYNCHRONIZED(&bufLocker); + name = dataName; + format = dataFmt; + return true; +} + // Get buffer name template String RingBuffer::getName() const @@ -368,6 +392,22 @@ void RingBuffer::clear() is_Full = false; } +// Delete buffer and set new size +template +void RingBuffer::resize(size_t newSize) +{ + GWSYNCHRONIZED(&bufLocker); + capacity = newSize; + head = 0; + first = 0; + last = 0; + count = 0; + is_Full = false; + + buffer.clear(); + buffer.resize(newSize, MIN_VAL); +} + // Get all current values as a vector template std::vector RingBuffer::getAllValues() const diff --git a/lib/obp60task/PageWindPlot.cpp b/lib/obp60task/PageWindPlot.cpp index 497fd44..8ebd55f 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -1,9 +1,10 @@ #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 -#include "BoatDataCalibration.h" +#include "Pagedata.h" #include "OBP60Extensions.h" #include "OBPRingBuffer.h" -#include "Pagedata.h" +#include "OBPDataOperations.h" +#include "BoatDataCalibration.h" #include static const double radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees @@ -20,7 +21,7 @@ int getCntr(const RingBuffer& windDirHstry, size_t amount) if (amount > count) amount = count; - int16_t midWndDir, minWndDir, maxWndDir = 0; + uint16_t midWndDir, minWndDir, maxWndDir = 0; int wndCenter = 0; midWndDir = windDirHstry.getMid(amount); @@ -78,6 +79,8 @@ class PageWindPlot : public Page { bool keylock = false; // Keylock char chrtMode = 'D'; // Chart mode: 'D' for TWD, 'S' for TWS, 'B' for both bool showTruW = true; // Show true wind or apparant wind in chart area + bool oldShowTruW = false; // remember recent user selection of wind data type + int dataIntv = 1; // Update interval for wind history chart: // (1)|(2)|(3)|(4) seconds for approx. 4, 8, 12, 16 min. history chart bool useSimuData; @@ -169,34 +172,26 @@ public: } commonData->logger->logDebug(GwLog::LOG,"New PageWindPlot: wind source=%s", wndSrc); #endif + oldShowTruW = !showTruW; // makes wind source being initialized at initial page call } - - int displayPage(PageData& pageData) { GwConfigHandler* config = commonData->config; GwLog* logger = commonData->logger; static RingBuffer* wdHstry; // Wind direction data buffer - static RingBuffer* wsHstry; // Wind speed data buffer + static RingBuffer* wsHstry; // Wind speed data buffer static String wdName, wdFormat; // Wind direction name and format static String wsName, wsFormat; // Wind speed name and format - static int updFreq; // Update frequency for wind direction - static int16_t wdLowest, wdHighest; // Wind direction range float wsValue; // Wind speed value in chart area String wsUnit; // Wind speed unit in chart area static GwApi::BoatValue* wsBVal = new GwApi::BoatValue("TWS"); // temp BoatValue for wind speed unit identification; required by OBP60Formater - // current boat data values; TWD/AWD only for validation test, TWS/AWS for display of current value - const int numBoatData = 4; + // current boat data values; TWD/AWD only for validation test + const int numBoatData = 2; GwApi::BoatValue* bvalue; - String BDataName[numBoatData]; - double BDataValue[numBoatData]; bool BDataValid[numBoatData]; - String BDataText[numBoatData]; - String BDataUnit[numBoatData]; - String BDataFormat[numBoatData]; static bool isInitialized = false; // Flag to indicate that page is initialized static bool wndDataValid = false; // Flag to indicate if wind data is valid @@ -217,7 +212,6 @@ public: static size_t lastIdx; // Last index of TWD history buffer static size_t lastAddedIdx = 0; // Last index of TWD history buffer when new data was added static int oldDataIntv; // remember recent user selection of data interval - static bool oldShowTruW; // remember recent user selection of wind data type static int wndCenter; // chart wind center value position static int wndLeft; // chart wind left value position @@ -234,13 +228,8 @@ public: static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line LOG_DEBUG(GwLog::LOG, "Display PageWindPlot"); + ulong timer = millis(); -/* // Get config data - bool useSimuData = config->getBool(config->useSimuData); - // holdValues = config->getBool(config->holdvalues); - String flashLED = config->getString(config->flashLED); - String backlightMode = config->getString(config->backlight); -*/ if (!isInitialized) { width = getdisplay().width(); height = getdisplay().height(); @@ -249,17 +238,8 @@ public: numNoData = 0; bufStart = 0; oldDataIntv = 0; - oldShowTruW = false; // we want to initialize wind buffers at 1st time routine runs - wdHstry = pageData.boatHstry.twdHstry; - bufSize = wdHstry->getCapacity(); - wsHstry = pageData.boatHstry.twsHstry; - bufSize = wsHstry->getCapacity(); - wdHstry->getMetaData(wdName, wdFormat, updFreq, wdLowest, wdHighest); - wsHstry->getMetaData(wsName, wsFormat, updFreq, wdLowest, wdHighest); wsValue = 0; - wsBVal->setFormat(wsHstry->getFormat()); numAddedBufVals, currIdx, lastIdx = 0; - lastAddedIdx = wdHstry->getLastIdx(); wndCenter = INT_MIN; midWndDir = 0; diffRng = dfltRng; @@ -271,14 +251,7 @@ public: // read boat data values; TWD only for validation test, TWS for display of current value for (int i = 0; i < numBoatData; i++) { bvalue = pageData.values[i]; - BDataName[i] = xdrDelete(bvalue->getName()); - BDataName[i] = BDataName[i].substring(0, 6); // String length limit for value name - calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated - BDataValue[i] = bvalue->value; // Value as double in SI unit BDataValid[i] = bvalue->valid; - BDataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places - BDataUnit[i] = formatValue(bvalue, *commonData).unit; - BDataFormat[i] = bvalue->getFormat(); // Unit of value } // Optical warning by limit violation (unused) @@ -289,16 +262,17 @@ public: if (showTruW != oldShowTruW) { if (showTruW) { - wdHstry = pageData.boatHstry.twdHstry; - wsHstry = pageData.boatHstry.twsHstry; + wdHstry = pageData.boatHstry->hstryBufList.twdHstry; + wsHstry = pageData.boatHstry->hstryBufList.twsHstry; } else { - wdHstry = pageData.boatHstry.awdHstry; - wsHstry = pageData.boatHstry.awsHstry; + wdHstry = pageData.boatHstry->hstryBufList.awdHstry; + wsHstry = pageData.boatHstry->hstryBufList.awsHstry; } - wdHstry->getMetaData(wdName, wdFormat, updFreq, wdLowest, wdHighest); - wsHstry->getMetaData(wsName, wsFormat, updFreq, wdLowest, wdHighest); + wdHstry->getMetaData(wdName, wdFormat); + wsHstry->getMetaData(wsName, wsFormat); bufSize = wdHstry->getCapacity(); wsBVal->setFormat(wsHstry->getFormat()); + lastAddedIdx = wdHstry->getLastIdx(); oldShowTruW = showTruW; } @@ -321,15 +295,15 @@ public: bufStart = max(0, bufStart - numAddedBufVals); } } - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Dataset: count: %d, xWD: %.0f, xWS: %.1f, xWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, wind source: %s", - count, wdHstry->getLast() / 1000.0 * radToDeg, wsHstry->getLast() / 10.0 * 1.94384, BDataValid[0], intvBufSize, numWndVals, bufStart, numAddedBufVals, wdHstry->getLastIdx(), + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Dataset: count: %d, xWD: %.1f, xWS: %.2f, xWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, wind source: %s", + count, wdHstry->getLast() / 1000.0 * radToDeg, wsHstry->getLast() / 1000.0 * 1.94384, BDataValid[0], intvBufSize, numWndVals, bufStart, numAddedBufVals, wdHstry->getLastIdx(), showTruW ? "True" : "App"); // Set wndCenter from 1st real buffer value if (wndCenter == INT_MIN || (wndCenter == 0 && count == 1)) { wndCenter = getCntr(*wdHstry, numWndVals); - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, xWD: %.0f, wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", count, wdHstry->getLast() / 1000.0 * radToDeg, - wndCenter, diffRng, chrtRng, wdHstry->getMin(numWndVals) / 1000.0 * radToDeg, wdHstry->getMax(numWndVals) / 1000.0 * radToDeg); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, xWD: %.1f, wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", count, wdHstry->getLast() / 10000.0 * radToDeg, + wndCenter, diffRng, chrtRng, wdHstry->getMin(numWndVals) / 10000.0 * radToDeg, wdHstry->getMax(numWndVals) / 10000.0 * radToDeg); } else { // check and adjust range between left, center, and right chart limit diffRng = getRng(*wdHstry, wndCenter, numWndVals); @@ -365,7 +339,6 @@ public: char sWndLbl[4]; // char buffer for Wind angle label getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setCursor(xCenter - 88, yOffset - 3); -// getdisplay().print("TWD"); // Wind data name getdisplay().print(wdName); // Wind data name snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter); drawTextCenter(xCenter, yOffset - 11, sWndLbl); @@ -473,22 +446,24 @@ public: lastZone = currentZone; wsValue = wsHstry->getLast(); - wsBVal->value = wsValue; // temp variable to retreive data unit from OBP60Formater - wsBVal->valid = (static_cast(wsValue) != wsHstry->getMinVal()); + wsBVal->value = wsValue / 1000.0; // temp variable to retreive data unit from OBP60Formater + wsBVal->valid = (static_cast(wsValue) != wsHstry->getMinVal()); + String swsValue = formatValue(wsBVal, *commonData).svalue; // value (string) wsUnit = formatValue(wsBVal, *commonData).unit; // Unit of value getdisplay().fillRect(xPosTws - 4, yPosTws - 38, 142, 44, commonData->bgcolor); // Clear area for TWS value getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b); getdisplay().setCursor(xPosTws, yPosTws); - if (!wsBVal->valid) { + getdisplay().print(swsValue); // Value +/* if (!wsBVal->valid) { getdisplay().print("--.-"); } else { - wsValue = wsValue / 10.0 * 1.94384; // Wind speed value in knots + wsValue = wsValue / 1000.0 * 1.94384; // Wind speed value in knots if (wsValue < 10.0) { getdisplay().printf("!%3.1f", wsValue); // Value, round to 1 decimal } else { getdisplay().printf("%4.1f", wsValue); // Value, round to 1 decimal } - } + } */ getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setCursor(xPosTws + 82, yPosTws - 14); getdisplay().print(wsName); // Name @@ -523,6 +498,7 @@ public: getdisplay().printf("%3d", chrtLbl); // Wind value label } + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot time: %ld", millis() - timer); return PAGE_UPDATE; }; }; @@ -541,7 +517,8 @@ PageDescription registerPageWindPlot( "WindPlot", // Page name createPage, // Action 0, // Number of bus values depends on selection in Web configuration - { "TWD", "TWS", "AWD", "AWS" }, // Bus values we need in the page +// { "TWD", "TWS", "AWD", "AWS" }, // Bus values we need in the page + { "TWD", "AWD" }, // Bus values we need in the page true // Show display header on/off ); diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h index 58a0a57..7649ab6 100644 --- a/lib/obp60task/Pagedata.h +++ b/lib/obp60task/Pagedata.h @@ -4,7 +4,6 @@ #include #include #include "LedSpiTask.h" -#include "OBPRingBuffer.h" #include "OBPDataOperations.h" #define MAX_PAGE_NUMBER 10 // Max number of pages for show data @@ -16,7 +15,7 @@ typedef struct{ uint8_t pageNumber; // page number in sequence of visible pages //the values will always contain the user defined values first ValueList values; - tBoatHstryData boatHstry; + HstryBuf* boatHstry; } PageData; // Sensor data structure (only for extended sensors, not for NMEA bus sensors) diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 0ca3532..26f1dcc 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -13,7 +13,6 @@ #include "OBP60Extensions.h" // Functions lib for extension board #include "OBP60Keypad.h" // Functions for keypad #include "BoatDataCalibration.h" // Functions lib for data instance calibration -#include "OBPRingBuffer.h" // Functions lib with ring buffer for history storage of some boat data #include "OBPDataOperations.h" // Functions lib for data operations such as true wind calculation #ifdef BOARD_OBP40S3 @@ -151,39 +150,32 @@ void keyboardTask(void *param){ vTaskDelete(NULL); } -class BoatValueList{ - public: - static const int MAXVALUES=100; - //we create a list containing all our BoatValues - //this is the list we later use to let the api fill all the values - //additionally we put the necessary values into the paga data - see below - GwApi::BoatValue *allBoatValues[MAXVALUES]; - int numValues=0; - - bool addValueToList(GwApi::BoatValue *v){ - for (int i=0;i to make class available for other functions +// --- Class BoatValueList -------------- +bool BoatValueList::addValueToList(GwApi::BoatValue *v){ + for (int i=0;i= MAXVALUES) return false; - allBoatValues[numValues]=v; - numValues++; - return true; } - //helper to ensure that each BoatValue is only queried once - GwApi::BoatValue *findValueOrCreate(String name){ - for (int i=0;igetName() == name) { - return allBoatValues[i]; - } + if (numValues >= MAXVALUES) return false; + allBoatValues[numValues]=v; + numValues++; + return true; +} +//helper to ensure that each BoatValue is only queried once +GwApi::BoatValue *BoatValueList::findValueOrCreate(String name){ + for (int i=0;igetName() == name) { + return allBoatValues[i]; } - GwApi::BoatValue *rt=new GwApi::BoatValue(name); - addValueToList(rt); - return rt; } -}; + GwApi::BoatValue *rt=new GwApi::BoatValue(name); + addValueToList(rt); + return rt; +} +// --- Class BoatValueList -------------- //we want to have a list that has all our page definitions //this way each page can easily be added here @@ -333,202 +325,6 @@ void underVoltageDetection(GwApi *api, CommonData &common){ } } -// Calculate true wind data and add to obp60task boat data list -bool addTrueWind(GwApi* api, BoatValueList* boatValues) { - - double awaVal, awsVal, cogVal, stwVal, sogVal, hdtVal, hdmVal, varVal; - double twd, tws, twa; - bool isCalculated = false; - const double DBL_MIN = std::numeric_limits::lowest(); - - GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate("TWD"); - GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate("TWS"); - GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA"); - GwApi::BoatValue *awaBVal = boatValues->findValueOrCreate("AWA"); - GwApi::BoatValue *awsBVal = boatValues->findValueOrCreate("AWS"); - GwApi::BoatValue *cogBVal = boatValues->findValueOrCreate("COG"); - GwApi::BoatValue *stwBVal = boatValues->findValueOrCreate("STW"); - GwApi::BoatValue *sogBVal = boatValues->findValueOrCreate("SOG"); - GwApi::BoatValue *hdtBVal = boatValues->findValueOrCreate("HDT"); - GwApi::BoatValue *hdmBVal = boatValues->findValueOrCreate("HDM"); - GwApi::BoatValue *varBVal = boatValues->findValueOrCreate("VAR"); - awaVal = awaBVal->valid ? awaBVal->value : DBL_MIN; - awsVal = awsBVal->valid ? awsBVal->value : DBL_MIN; - cogVal = cogBVal->valid ? cogBVal->value : DBL_MIN; - stwVal = stwBVal->valid ? stwBVal->value : DBL_MIN; - sogVal = sogBVal->valid ? sogBVal->value : DBL_MIN; - hdtVal = hdtBVal->valid ? hdtBVal->value : DBL_MIN; - hdmVal = hdmBVal->valid ? hdmBVal->value : DBL_MIN; - varVal = varBVal->valid ? varBVal->value : DBL_MIN; - api->getLogger()->logDebug(GwLog::DEBUG,"obp60task addTrueWind: AWA %.1f, AWS %.1f, COG %.1f, STW %.1f, SOG %.2f, HDT %.1f, HDM %.1f, VAR %.1f", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852, - cogBVal->value * RAD_TO_DEG, stwBVal->value * 3.6 / 1.852, sogBVal->value * 3.6 / 1.852, hdtBVal->value * RAD_TO_DEG, hdmBVal->value * RAD_TO_DEG, varBVal->value * RAD_TO_DEG); - - isCalculated = WindUtils::calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &sogVal, &hdtVal, &hdmVal, &varVal, &twd, &tws, &twa); - - if (isCalculated) { // Replace values only, if successfully calculated and not already available - if (!twdBVal->valid) { - twdBVal->value = twd; - twdBVal->valid = true; - } - if (!twsBVal->valid) { - twsBVal->value = tws; - twsBVal->valid = true; - } - if (!twaBVal->valid) { - twaBVal->value = twa; - twaBVal->valid = true; - } - } - api->getLogger()->logDebug(GwLog::DEBUG,"obp60task addTrueWind: isCalculated %d, TWD %.1f, TWA %.1f, TWS %.1f", isCalculated, twdBVal->value * RAD_TO_DEG, - twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852); - - return isCalculated; -} - -// Init history buffers for selected boat data -void initHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList) { - - GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here - const double DBL_MIN = std::numeric_limits::lowest(); - - int hstryUpdFreq = 1000; // Update frequency for history buffers in ms - int hstryMinVal = 0; // Minimum value for these history buffers - int twdHstryMax = 6283; // Max value for wind direction (TWD, AWD) in rad (0...2*PI), shifted by 1000 for 3 decimals - int twsHstryMax = 1000; // Max value for wind speed (TWS, AWS) in m/s, shifted by 10 for 1 decimal - // Initialize history buffers with meta data - hstryBufList.twdHstry->setMetaData("TWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax); - hstryBufList.twsHstry->setMetaData("TWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax); - hstryBufList.awdHstry->setMetaData("AWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax); - hstryBufList.awsHstry->setMetaData("AWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax); - - // create boat values for history data types, if they don't exist yet - GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName()); - GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName()); - GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA"); - GwApi::BoatValue *awdBVal = boatValues->findValueOrCreate(hstryBufList.awdHstry->getName()); - GwApi::BoatValue *awsBVal = boatValues->findValueOrCreate(hstryBufList.awsHstry->getName()); - - if (!awdBVal->valid) { // AWD usually does not exist - awdBVal->setFormat(hstryBufList.awdHstry->getFormat()); - awdBVal->value = DBL_MIN; - } -} - -void handleHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList, bool useSimuData) { - // Handle history buffers for TWD, TWS - - GwLog *logger = api->getLogger(); - - int16_t twdHstryMin = hstryBufList.twdHstry->getMinVal(); - int16_t twdHstryMax = hstryBufList.twdHstry->getMaxVal(); - int16_t twsHstryMin = hstryBufList.twsHstry->getMinVal(); - int16_t twsHstryMax = hstryBufList.twsHstry->getMaxVal(); - int16_t awdHstryMin = hstryBufList.awdHstry->getMinVal(); - int16_t awdHstryMax = hstryBufList.awdHstry->getMaxVal(); - int16_t awsHstryMin = hstryBufList.awsHstry->getMinVal(); - int16_t awsHstryMax = hstryBufList.awsHstry->getMaxVal(); - static int16_t twd, tws = 20; //initial value only relevant if we use simulation data - static double awd, aws, hdt = 20; //initial value only relevant if we use simulation data - GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here - - GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName()); - GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName()); - GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA"); - GwApi::BoatValue *awdBVal = boatValues->findValueOrCreate(hstryBufList.awdHstry->getName()); - GwApi::BoatValue *awsBVal = boatValues->findValueOrCreate(hstryBufList.awsHstry->getName()); - GwApi::BoatValue *awaBVal = boatValues->findValueOrCreate("AWA"); - GwApi::BoatValue *hdtBVal = boatValues->findValueOrCreate("HDT"); - GwApi::BoatValue *hdmBVal = boatValues->findValueOrCreate("HDM"); - GwApi::BoatValue *varBVal = boatValues->findValueOrCreate("VAR"); - GwApi::BoatValue *cogBVal = boatValues->findValueOrCreate("COG"); - GwApi::BoatValue *sogBVal = boatValues->findValueOrCreate("SOG"); - - api->getLogger()->logDebug(GwLog::DEBUG,"obp60task handleHstryBuf: TWD_isValid? %d, twdBVal: %.1f, twaBVal: %.1f, twsBVal: %.1f", twdBVal->valid, twdBVal->value * RAD_TO_DEG, - twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852); - - if (twdBVal->valid) { - calBVal = new GwApi::BoatValue("TWD"); // temporary solution for calibration of history buffer values - calBVal->setFormat(twdBVal->getFormat()); - calBVal->value = twdBVal->value; - calBVal->valid = twdBVal->valid; - calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated - twd = static_cast(std::round(calBVal->value * 1000)); - if (twd >= twdHstryMin && twd <= twdHstryMax) { - hstryBufList.twdHstry->add(twd); - } - delete calBVal; - calBVal = nullptr; - } else if (useSimuData) { - twd += random(-20, 20); - twd = WindUtils::to360(twd); - hstryBufList.twdHstry->add(static_cast(DegToRad(twd) * 1000.0)); - } - - if (twsBVal->valid) { - calBVal = new GwApi::BoatValue("TWS"); // temporary solution for calibration of history buffer values - calBVal->setFormat(twsBVal->getFormat()); - calBVal->value = twsBVal->value; - calBVal->valid = twsBVal->valid; - calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated - tws = static_cast(std::round(calBVal->value * 10)); - if (tws >= twsHstryMin && tws <= twsHstryMax) { - hstryBufList.twsHstry->add(tws); - } - delete calBVal; - calBVal = nullptr; - } else if (useSimuData) { - tws += random(-50, 50); // TWS value in m/s; expands to 1 decimal - tws = constrain(tws, 0, 250); // Limit TWS to [0..25] m/s - hstryBufList.twsHstry->add(tws); - } - - if (awaBVal->valid) { - if (hdtBVal->valid) { - hdt = hdtBVal->value; // Use HDT if available - } else { - hdt = WindUtils::calcHDT(&hdmBVal->value, &varBVal->value, &cogBVal->value, &sogBVal->value); - } - - awd = awaBVal->value + hdt; - awd = WindUtils::to2PI(awd); - calBVal = new GwApi::BoatValue("AWD"); // temporary solution for calibration of history buffer values - calBVal->value = awd; - calBVal->setFormat(awdBVal->getFormat()); - calBVal->valid = true; - calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated - awdBVal->value = calBVal->value; - awdBVal->valid = true; - awd = std::round(calBVal->value * 1000); - if (awd >= awdHstryMin && awd <= awdHstryMax) { - hstryBufList.awdHstry->add(static_cast(awd)); - } - delete calBVal; - calBVal = nullptr; - } else if (useSimuData) { - awd += random(-20, 20); - awd = WindUtils::to360(awd); - hstryBufList.awdHstry->add(static_cast(DegToRad(awd) * 1000.0)); - } - - if (awsBVal->valid) { - calBVal = new GwApi::BoatValue("AWS"); // temporary solution for calibration of history buffer values - calBVal->setFormat(awsBVal->getFormat()); - calBVal->value = awsBVal->value; - calBVal->valid = awsBVal->valid; - calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated - aws = std::round(calBVal->value * 10); - if (aws >= awsHstryMin && aws <= awsHstryMax) { - hstryBufList.awsHstry->add(static_cast(aws)); - } - delete calBVal; - calBVal = nullptr; - } else if (useSimuData) { - aws += random(-50, 50); // TWS value in m/s; expands to 1 decimal - aws = constrain(aws, 0, 250); // Limit TWS to [0..25] m/s - hstryBufList.awsHstry->add(aws); - } -} - // OBP60 Task //#################################################################################### void OBP60Task(GwApi *api){ @@ -639,16 +435,11 @@ void OBP60Task(GwApi *api){ int lastPage=pageNumber; BoatValueList boatValues; //all the boat values for the api query + HstryBuf hstryBufList(960); // Create ring buffers for history storage of some boat data + WindUtils trueWind(&boatValues); // Create helper object for true wind calculation //commonData.distanceformat=config->getString(xxx); //add all necessary data to common data - // Create ring buffers for history storage of some boat data - RingBuffer twdHstry(960); // Circular buffer to store true wind direction values; store 960 TWD values for 16 minutes history - RingBuffer twsHstry(960); // Circular buffer to store true wind speed values (TWS) - RingBuffer awdHstry(960); // Circular buffer to store appearant wind direction values; store 960 AWD values for 16 minutes history - RingBuffer awsHstry(960); // Circular buffer to store appearant xwind speed values (AWS) - tBoatHstryData hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; - //fill the page data from config numPages=config->getInt(config->visiblePages,1); if (numPages < 1) numPages=1; @@ -687,10 +478,8 @@ void OBP60Task(GwApi *api){ LOG_DEBUG(GwLog::DEBUG,"added fixed value %s to page %d",value->getName().c_str(),i); pages[i].parameters.values.push_back(value); } - if (pages[i].description->pageName == "WindPlot") { - // Add boat history data to page parameters - pages[i].parameters.boatHstry = hstryBufList; - } + // Add boat history data to page parameters + pages[i].parameters.boatHstry = &hstryBufList; } // add out of band system page (always available) Page *syspage = allPages.pages[0]->creator(commonData); @@ -698,12 +487,12 @@ void OBP60Task(GwApi *api){ // Read all calibration data settings from config calibrationData.readConfig(config, logger); - // Check user setting for true wind calculation + // Check user settings for true wind calculation bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false); bool useSimuData = api->getConfig()->getBool(api->getConfig()->useSimuData, false); // Initialize history buffer for certain boat data - initHstryBuf(api, &boatValues, hstryBufList); + hstryBufList.init(&boatValues, logger); // Display screenshot handler for HTTP request // http://192.168.15.1/api/user/OBP60Task/screenshot @@ -1013,10 +802,10 @@ void OBP60Task(GwApi *api){ api->getStatus(commonData.status); if (calcTrueWnds) { - addTrueWind(api, &boatValues); + trueWind.addTrueWind(api, &boatValues, logger); } // Handle history buffers for TWD, TWS for wind plot page and other usage - handleHstryBuf(api, &boatValues, hstryBufList, useSimuData); + hstryBufList.handleHstryBuf(useSimuData); // Clear display // getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor); diff --git a/lib/obp60task/obp60task.h b/lib/obp60task/obp60task.h index 4d959f0..a087c5c 100644 --- a/lib/obp60task/obp60task.h +++ b/lib/obp60task/obp60task.h @@ -42,4 +42,18 @@ DECLARE_CAPABILITY(obp40,true) #endif DECLARE_STRING_CAPABILITY(HELP_URL, "https://obp60-v2-docu.readthedocs.io/de/latest/"); // Link to help pages + + class BoatValueList{ + public: + static const int MAXVALUES=100; + //we create a list containing all our BoatValues + //this is the list we later use to let the api fill all the values + //additionally we put the necessary values into the paga data - see below + GwApi::BoatValue *allBoatValues[MAXVALUES]; + int numValues=0; + + bool addValueToList(GwApi::BoatValue *v); + //helper to ensure that each BoatValue is only queried once + GwApi::BoatValue *findValueOrCreate(String name); + }; #endif