diff --git a/lib/obp60task/OBPDataOperations.cpp b/lib/obp60task/OBPDataOperations.cpp index daca553..cc6ac2a 100644 --- a/lib/obp60task/OBPDataOperations.cpp +++ b/lib/obp60task/OBPDataOperations.cpp @@ -1,45 +1,51 @@ #include "OBPDataOperations.h" -void WindUtils::to2PI(double* a) +double WindUtils::to2PI(double a) { - while (*a < 0) { - *a += 2 * M_PI; + a = fmod(a, 2 * M_PI); + if (a < 0.0) { + a += 2 * M_PI; } - *a = fmod(*a, 2 * M_PI); + return a; } -void WindUtils::toPI(double* a) +double WindUtils::toPI(double a) { - *a += M_PI; - to2PI(a); - *a -= M_PI; + a += M_PI; + a = to2PI(a); + a -= M_PI; + + return a; } -void WindUtils::to360(double* a) +double WindUtils::to360(double a) { - while (*a < 0) { - *a += 360; + a = fmod(a, 360); + if (a < 0.0) { + a += 360; } - *a = fmod(*a, 360); + return a; } -void WindUtils::to180(double* a) +double WindUtils::to180(double a) { - *a += 180; - to360(a); - *a -= 180; + a += 180; + a = to360(a); + a -= 180; + + return a; } void WindUtils::toCart(const double* phi, const double* r, double* x, double* y) { - *x = *r * sin(radians(*phi)); - *y = *r * cos(radians(*phi)); + *x = *r * sin(*phi); + *y = *r * cos(*phi); } void WindUtils::toPol(const double* x, const double* y, double* phi, double* r) { - *phi = 90 - degrees(atan2(*y, *x)); - to360(phi); + *phi = (M_PI / 2) - atan2(*y, *x); + *phi = to2PI(*phi); *r = sqrt(*x * *x + *y * *y); } @@ -57,80 +63,96 @@ void WindUtils::addPolar(const double* phi1, const double* r1, void WindUtils::calcTwdSA(const double* AWA, const double* AWS, const double* CTW, const double* STW, const double* HDT, - double* TWD, double* TWS) + double* TWD, double* TWS, double* TWA) { - double AWD = *AWA + *HDT; + double awd = *AWA + *HDT; + awd = to2PI(awd); double stw = -*STW; - Serial.println("calcTwdSA: AWA: " + String(*AWA) + ", AWS: " + String(*AWS) + ", CTW: " + String(*CTW) + ", STW: " + String(*STW) + ", HDT: " + String(*HDT)); - addPolar(&AWD, AWS, CTW, &stw, TWD, TWS); + // 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 to 0-360° - while (*TWD < 0) - *TWD += 360; - while (*TWD >= 360) - *TWD -= 360; - - Serial.println("calcTwdSA: TWD: " + String(*TWD) + ", TWS: " + String(*TWS)); + // Normalize TWD and TWA to 0-360° + *TWD = to2PI(*TWD); + *TWA = toPI(*TWD - *HDT); + // Serial.println("calcTwdSA: TWD: " + String(*TWD) + ", TWS: " + String(*TWS)); } bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal, - const double* cogVal, const double* stwVal, const double* hdtVal, - const double* hdmVal, double* twdVal, double* twsVal) + const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal, + const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal) { - double hdt, ctw; - double hdmVar = 3.0; // Magnetic declination, can be set from config if needed - double twd, tws; + double stw, hdt, ctw; + double twd, tws, twa; + static const double DBL_MIN = std::numeric_limits::lowest(); - if (*hdtVal == __DBL_MIN__) { - if (*hdmVal != __DBL_MIN__) { - hdt = *hdmVal + hdmVar; // Use corrected HDM if HDT is not available + if (*hdtVal != DBL_MIN) { + hdt = *hdtVal; // Use HDT if available + } else { + if (*hdmVal != DBL_MIN && *varVal != DBL_MIN) { + hdt = *hdmVal + *varVal; // Use corrected HDM if HDT is not available + hdt = to2PI(hdt); + } else if (*cogVal != DBL_MIN) { + hdt = *cogVal; // Use COG as fallback if HDT and HDM are not available } else { return false; // Cannot calculate without valid HDT or HDM } } - ctw = *hdtVal + ((*cogVal - *hdtVal) / 2); // Estimate CTW from COG - if ((*awaVal == __DBL_MIN__) || (*awsVal == __DBL_MIN__) || (*cogVal == __DBL_MIN__) || (*stwVal == __DBL_MIN__)) { + if (*cogVal != DBL_MIN) { + ctw = *cogVal; // Use COG as CTW if available + // ctw = *cogVal + ((*cogVal - hdt) / 2); // Estimate CTW from COG + } else { + ctw = hdt; // 2nd approximation for CTW; + return false; + } + + if (*stwVal != DBL_MIN) { + stw = *stwVal; // Use STW if available + } else if (*sogVal != DBL_MIN) { + stw = *sogVal; + } else { + // If STW and SOG are not available, we cannot calculate true wind + return false; + } + + if ((*awaVal == DBL_MIN) || (*awsVal == DBL_MIN) || (*cogVal == DBL_MIN) || (*stwVal == DBL_MIN)) { // Cannot calculate true wind without valid AWA, AWS, COG, or STW return false; } else { - calcTwdSA(awaVal, awsVal, cogVal, stwVal, hdtVal, &twd, &tws); + calcTwdSA(awaVal, awsVal, &ctw, stwVal, &hdt, &twd, &tws, &twa); *twdVal = twd; *twsVal = tws; + *twaVal = twa; return true; } } -/* -// make function available in Python for testing -static PyObject* true_wind(PyObject* self, PyObject* args) { - double AWA,AWS,CTW,STW,HDT,TWS,TWD; - if (!PyArg_ParseTuple(args, "ddddd", &AWA, &AWS, &CTW, &STW, &HDT)) { - return NULL; +void HstryBuf::fillWndBufSimData(tBoatHstryData& hstryBufs) +// Fill most part of TWD and TWS history buffer with simulated data +{ + double value = 20.0; + int16_t value2 = 0; + for (int i = 0; i < 900; i++) { + value += random(-20, 20); + value = WindUtils::to360(value); + value2 = static_cast(value * DEG_TO_RAD * 1000); + hstryBufs.twdHstry->add(value2); } - - calc_true_wind(&AWA, &AWS, &CTW, &STW, &HDT, &TWD, &TWS); - - PyObject* twd = PyFloat_FromDouble(TWD); - PyObject* tws = PyFloat_FromDouble(TWS); - PyObject* tw = PyTuple_Pack(2,twd,tws); - return tw; } -static PyMethodDef methods[] = { - {"true_wind", true_wind, METH_VARARGS, NULL}, - {NULL, NULL, 0, NULL} -}; +/* double genTwdSimDat() +{ + simTwd += random(-20, 20); + if (simTwd < 0.0) + simTwd += 360.0; + if (simTwd >= 360.0) + simTwd -= 360.0; -static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "truewind", // Module name - NULL, // Optional docstring - -1, - methods -}; + int16_t z = static_cast(DegToRad(simTwd) * 1000.0); + pageData.boatHstry.twdHstry->add(z); // Fill the buffer with some test data -PyMODINIT_FUNC PyInit_truewind(void) { - return PyModule_Create(&module); -}*/ \ No newline at end of file + simTws += random(-200, 150) / 10.0; // TWS value in knots + simTws = constrain(simTws, 0.0f, 50.0f); // Ensure TWS is between 0 and 50 knots + twsValue = simTws; +}*/ diff --git a/lib/obp60task/OBPDataOperations.h b/lib/obp60task/OBPDataOperations.h index 2ea8fdc..c9e4386 100644 --- a/lib/obp60task/OBPDataOperations.h +++ b/lib/obp60task/OBPDataOperations.h @@ -1,48 +1,36 @@ #pragma once -// #include #include "GwApi.h" +#include "OBPRingBuffer.h" #include #include -// #define radians(a) (a*0.017453292519943295) -// #define degrees(a) (a*57.29577951308232) +typedef struct { + RingBuffer* twdHstry; + RingBuffer* twsHstry; +} tBoatHstryData; // Holds pointers to all history buffers for boat data + +class HstryBuf { + +public: + void fillWndBufSimData(tBoatHstryData& hstryBufs); // Fill most part of the TWD and TWS history buffer with simulated data +}; class WindUtils { public: - static void to360(double* a); - static void to180(double* a); - static void to2PI(double* a); - static void toPI(double* a); + 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, const double* phi2, const double* r2, double* phi, double* r); - static bool calcTrueWind(const double* awaVal, const double* awsVal, - const double* cogVal, const double* stwVal, const double* hdtVal, - const double* hdmVal, double* twdVal, double* twsVal); static void calcTwdSA(const double* AWA, const double* AWS, const double* CTW, const double* STW, const double* HDT, - double* TWD, double* TWS); -}; - -/* -// make function available in Python for testing -static PyObject* true_wind(PyObject* self, PyObject* args); -static PyMethodDef methods[] = { - {"true_wind", true_wind, METH_VARARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - -static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "truewind", // Module name - NULL, // Optional docstring - -1, - methods -}; - -PyMODINIT_FUNC PyInit_truewind(void) { - return PyModule_Create(&module); -} */ \ No newline at end of file + double* TWD, double* TWS, double* TWA); + static 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); +}; \ No newline at end of file diff --git a/lib/obp60task/OBPRingBuffer.h b/lib/obp60task/OBPRingBuffer.h index 3aba92b..4b5e5bd 100644 --- a/lib/obp60task/OBPRingBuffer.h +++ b/lib/obp60task/OBPRingBuffer.h @@ -31,6 +31,7 @@ public: 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 + String getName() const; // Get buffer name void add(const T& value); // Add a new value to buffer T get(size_t index) const; // Get value at specific position (0-based index from oldest to newest) T getFirst() const; // Get the first (oldest) value in buffer diff --git a/lib/obp60task/OBPRingBuffer.tpp b/lib/obp60task/OBPRingBuffer.tpp index 4c9580f..a0da425 100644 --- a/lib/obp60task/OBPRingBuffer.tpp +++ b/lib/obp60task/OBPRingBuffer.tpp @@ -57,6 +57,13 @@ bool RingBuffer::getMetaData(String& name, String& format, int& updateFrequen return true; } +// Get buffer name +template +String RingBuffer::getName() const +{ + return dataName; +} + // Add a new value to buffer template void RingBuffer::add(const T& value) @@ -129,9 +136,9 @@ T RingBuffer::getMin() const return MIN_VAL; } - T minVal = getFirst(); + T minVal = MAX_VAL; T value; - for (size_t i = 1; i < count; i++) { + for (size_t i = 0; i < count; i++) { value = get(i); if (value < minVal && value != MIN_VAL) { minVal = value; @@ -150,7 +157,7 @@ T RingBuffer::getMin(size_t amount) const if (amount > count) amount = count; - T minVal = getLast(); + T minVal = MAX_VAL; T value; for (size_t i = 0; i < amount; i++) { value = get(count - 1 - i); @@ -169,9 +176,9 @@ T RingBuffer::getMax() const return MIN_VAL; } - T maxVal = getFirst(); + T maxVal = MIN_VAL; T value; - for (size_t i = 1; i < count; i++) { + for (size_t i = 0; i < count; i++) { value = get(i); if (value > maxVal && value != MIN_VAL) { maxVal = value; @@ -190,7 +197,7 @@ T RingBuffer::getMax(size_t amount) const if (amount > count) amount = count; - T maxVal = getLast(); + T maxVal = MIN_VAL; T value; for (size_t i = 0; i < amount; i++) { value = get(count - 1 - i); @@ -328,7 +335,7 @@ bool RingBuffer::isFull() const return is_Full; } -// Get lowest possible value for buffer; used for initialized buffer data +// Get lowest possible value for buffer; used for non-set buffer data template T RingBuffer::getMinVal() const { diff --git a/lib/obp60task/PageWindPlot.cpp b/lib/obp60task/PageWindPlot.cpp index a07c03c..1a209d1 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -4,20 +4,17 @@ #include "OBP60Extensions.h" #include "OBPRingBuffer.h" #include "Pagedata.h" -#include // just for RadToDeg function #include static const double radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees -// #define radians(a) (a * 0.017453292519943295) -// #define degrees(a) (a * 57.29577951308232) // Get maximum difference of last of TWD ringbuffer values to center chart int getRng(const RingBuffer& windDirHstry, int center, size_t amount) { int minVal = windDirHstry.getMinVal(); size_t count = windDirHstry.getCurrentSize(); -// size_t capacity = windDirHstry.getCapacity(); -// size_t last = windDirHstry.getLastIdx(); + // size_t capacity = windDirHstry.getCapacity(); + // size_t last = windDirHstry.getLastIdx(); if (windDirHstry.isEmpty() || amount <= 0) { return minVal; @@ -30,7 +27,7 @@ int getRng(const RingBuffer& windDirHstry, int center, size_t amount) int maxRng = minVal; // Start from the newest value (last) and go backwards x times for (size_t i = 0; i < amount; i++) { -// value = windDirHstry.get(((last - i) % capacity + capacity) % capacity); + // value = windDirHstry.get(((last - i) % capacity + capacity) % capacity); value = windDirHstry.get(count - 1 - i); if (value == minVal) { @@ -49,43 +46,6 @@ int getRng(const RingBuffer& windDirHstry, int center, size_t amount) return maxRng; } -void fillSimData(PageData& pageData) -// Fill part of the TWD history buffer with simulated data -{ - int value = 20; - int16_t value2 = 0; - for (int i = 0; i < 900; i++) { - value += random(-20, 20); - if (value < 0) - value += 360; - if (value >= 360) - value -= 360; - value2 = static_cast(DegToRad(value) * 1000.0); - pageData.boatHstry.twdHstry->add(value2); - } -} - -void fillTstBuffer(PageData& pageData) -{ - float value = 0; - int value2 = 0; - for (int i = 0; i < 60; i++) { - pageData.boatHstry.twdHstry->add(-10); // -> irregular data - } - for (int i = 0; i < 20; i++) { - for (int j = 0; j < 20; j++) { - value += 10; - value2 = static_cast(DegToRad(value) * 1000.0); - pageData.boatHstry.twdHstry->add(value2); - } - for (int j = 0; j < 20; j++) { - value -= 10; - value2 = static_cast(DegToRad(value) * 1000.0); - pageData.boatHstry.twdHstry->add(value2); - } - } -} - // **************************************************************** class PageWindPlot : public Page { @@ -105,7 +65,7 @@ public: virtual void setupKeys() { Page::setupKeys(); - commonData->keydata[0].label = "MODE"; + // commonData->keydata[0].label = "MODE"; commonData->keydata[1].label = "INTV"; commonData->keydata[4].label = "TWS"; } @@ -113,7 +73,7 @@ public: // Key functions virtual int handleKey(int key) { - // Set chart mode TWD | TWS + // Set chart mode TWD | TWS -> to be implemented if (key == 1) { if (chrtMode == 'D') { chrtMode = 'S'; @@ -159,9 +119,10 @@ public: GwLog* logger = commonData->logger; float twsValue; // TWS value in chart area - String twdName, twdUnit; // TWD name and unit - int updFreq; // Update frequency for TWD - int16_t twdLowest, twdHighest; // TWD range + static String twdName, twdUnit; // TWD name and unit + static int updFreq; // Update frequency for TWD + static int16_t twdLowest, twdHighest; // TWD range + // static int16_t twdBufMinVal; // lowest possible twd buffer value; used for non-set data static bool isInitialized = false; // Flag to indicate that page is initialized static bool wndDataValid = false; // Flag to indicate if wind data is valid @@ -191,6 +152,7 @@ public: static int chrtRng; // Range of wind values from mid wind value to min/max wind value in degrees int diffRng; // Difference between mid and current wind value static const int dfltRng = 40; // Default range for chart + int midWndDir; // New value for wndCenter after chart start / shift static int simTwd; // Simulation value for TWD static float simTws; // Simulation value for TWS @@ -201,7 +163,7 @@ public: static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line LOG_DEBUG(GwLog::LOG, "Display page WindPlot"); - unsigned long start = millis(); + unsigned long WndPlotStart = millis(); // Get config data simulation = config->getBool(config->useSimuData); @@ -210,11 +172,6 @@ public: String backlightMode = config->getString(config->backlight); if (!isInitialized) { - - if (simulation) { - fillSimData(pageData); // Fill the buffer with some test data - } - width = getdisplay().width(); height = getdisplay().height(); xCenter = width / 2; @@ -230,8 +187,33 @@ public: lastAddedIdx = pageData.boatHstry.twdHstry->getLastIdx(); pageData.boatHstry.twdHstry->getMetaData(twdName, twdUnit, updFreq, twdLowest, twdHighest); wndCenter = INT_MIN; + midWndDir = 0; + diffRng = dfltRng; + chrtRng = dfltRng; + isInitialized = true; // Set flag to indicate that page is now initialized - LOG_DEBUG(GwLog::ERROR, "PageWindPlot Start1: lastAddedIdx: %d, simTwd: %.1f, isInitialized: %d, SimData: %d", lastAddedIdx, simTwd / 1000 + radToDeg, isInitialized, simulation); + } + + const int numBoatData = 2; + GwApi::BoatValue* bvalue; + String DataName[numBoatData]; + double DataValue[numBoatData]; + bool DataValid[numBoatData]; + String DataText[numBoatData]; + String DataUnit[numBoatData]; + String DataFormat[numBoatData]; + + // 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]; + DataName[i] = xdrDelete(bvalue->getName()); + DataName[i] = DataName[i].substring(0, 6); // String length limit for value name + calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated + DataValue[i] = bvalue->value; // Value as double in SI unit + DataValid[i] = bvalue->valid; + DataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + DataUnit[i] = formatValue(bvalue, *commonData).unit; + DataFormat[i] = bvalue->getFormat(); // Unit of value } // Optical warning by limit violation (unused) @@ -240,30 +222,11 @@ public: setFlashLED(false); } - if (simulation) { - simTwd += random(-20, 20); - if (simTwd < 0.0) - simTwd += 360.0; - if (simTwd >= 360.0) - simTwd -= 360.0; - - int16_t z = static_cast(DegToRad(simTwd) * 1000.0); - LOG_DEBUG(GwLog::ERROR, "PageWindPlot Simulation: getLast TWD: %.0f, lastIdx: %d", pageData.boatHstry.twdHstry->getLast() / 1000.0 * RAD_TO_DEG, pageData.boatHstry.twdHstry->getLastIdx()); - pageData.boatHstry.twdHstry->add(z); // Fill the buffer with some test data - LOG_DEBUG(GwLog::ERROR, "PageWindPlot Simulation: getAdded TWD: %.0f, lastIdx: %d", pageData.boatHstry.twdHstry->getLast() / 1000.0 * RAD_TO_DEG, pageData.boatHstry.twdHstry->getLastIdx()); - - simTws += random(-200, 150) / 10.0; // TWS value in knots - simTws = constrain(simTws, 0.0f, 50.0f); // Ensure TWS is between 0 and 50 knots - twsValue = simTws; - } else { - twsValue = pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384; // TWS value in knots - } - // Identify buffer size and buffer start position for chart count = pageData.boatHstry.twdHstry->getCurrentSize(); currIdx = pageData.boatHstry.twdHstry->getLastIdx(); numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display - if (dataIntv != oldDataIntv) { + if (dataIntv != oldDataIntv || count == 1) { // new data interval selected by user intvBufSize = cHeight * dataIntv; numWndVals = min(count, (cHeight - 60) * dataIntv); @@ -277,16 +240,21 @@ public: bufStart = max(0, bufStart - numAddedBufVals); } } - LOG_DEBUG(GwLog::ERROR, "PageWindPlot Dataset: TWD: %.0f, TWS: %.1f, DBT: %.1f, count: %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d", - pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384, pageData.boatHstry.dbtHstry->getLast() / 10.0, - count, intvBufSize, numWndVals, bufStart, numAddedBufVals, pageData.boatHstry.twdHstry->getLastIdx()); + LOG_DEBUG(GwLog::ERROR, "PageWindPlot Dataset: count: %d, TWD: %.0f, TWS: %.1f, TWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, old: %d, act: %d", + count, pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384, DataValid[0], + intvBufSize, numWndVals, bufStart, numAddedBufVals, pageData.boatHstry.twdHstry->getLastIdx(), oldDataIntv, dataIntv); - // initialize chart range values - if (wndCenter == INT_MIN) { - wndCenter = max(0, int(pageData.boatHstry.twdHstry->get(numWndVals - intvBufSize) / 1000.0 * radToDeg)); // get 1st value of current data interval - wndCenter = (int((wndCenter + (wndCenter >= 0 ? 5 : -5)) / 10) * 10) % 360; // Set new center value; round to nearest 10 degree value; 360° -> 0° - diffRng = dfltRng; - chrtRng = dfltRng; + // Set wndCenter from 1st real buffer value + if (wndCenter == INT_MIN || (wndCenter == 0 && count == 1)) { + midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals); + if (midWndDir != INT16_MIN) { + midWndDir = midWndDir / 1000.0 * radToDeg; + wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value + } else { + wndCenter = 0; + } + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, TWD: %.0f, wndCenter: %d, diffRng: %d, chrtRng: %d", count, pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, + wndCenter, diffRng, chrtRng); } else { // check and adjust range between left, center, and right chart limit diffRng = getRng(*pageData.boatHstry.twdHstry, wndCenter, numWndVals); @@ -304,8 +272,6 @@ public: wndRight = (chrtRng < 180 ? wndCenter + chrtRng : wndCenter + chrtRng - 1); if (wndRight >= 360) wndRight -= 360; - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FirstVal: %f, LastVal: %d, count: %d, diffRng: %d, chartRng: %d, Center: %d, scale: %f", pageData.boatHstry.twdHstry->getFirst() / 1000.0 * radToDeg, - pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, count, diffRng, chrtRng, wndCenter, chrtScl); // Draw page //*********************************************************************** @@ -322,11 +288,9 @@ public: char sWndLbl[4]; // char buffer for Wind angle label getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setCursor(xCenter - 88, yOffset - 3); - getdisplay().print("TWD"); // Wind name - // getdisplay().setCursor(xCenter - 20, yOffset - 3); + getdisplay().print("TWD"); // Wind data name snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter); drawTextCenter(xCenter, yOffset - 11, sWndLbl); - // getdisplay().print(sWndLbl); // Wind center value getdisplay().drawCircle(xCenter + 25, yOffset - 17, 2, commonData->fgcolor); // symbol getdisplay().drawCircle(xCenter + 25, yOffset - 17, 3, commonData->fgcolor); // symbol getdisplay().setCursor(1, yOffset - 3); @@ -343,7 +307,19 @@ public: if (pageData.boatHstry.twdHstry->getMax() == pageData.boatHstry.twdHstry->getMinVal()) { // only values in buffer -> no valid wind data available wndDataValid = false; + } else if (!DataValid[0]) { + // currently no valid TWD data available + numNoData++; + wndDataValid = true; + if (numNoData > 3) { + // If more than 4 invalid values in a row, send message + wndDataValid = false; + getdisplay().setFont(&Ubuntu_Bold10pt8b); + getdisplay().fillRect(xCenter - 66, height / 2 - 20, 146, 24, commonData->bgcolor); // Clear area for TWS value + drawTextCenter(xCenter, height / 2 - 10, "No sensor data"); + } } else { + numNoData = 0; // reset data error counter wndDataValid = true; // At least some wind data available } // Draw wind values in chart @@ -361,17 +337,17 @@ public: } if (numNoData > 4) { // If more than 4 invalid values in a row, send message - getdisplay().setFont(&Ubuntu_Bold10pt7b); + getdisplay().setFont(&Ubuntu_Bold10pt8b); getdisplay().fillRect(xCenter - 66, height / 2 - 20, 146, 24, commonData->bgcolor); // Clear area for TWS value drawTextCenter(xCenter, height / 2 - 10, "No sensor data"); } */ } else { - chrtVal = (chrtVal / 1000.0 * radToDeg) + 0.5; // Convert to degrees and round + chrtVal = static_cast((chrtVal / 1000.0 * radToDeg) + 0.5); // Convert to degrees and round x = ((chrtVal - wndLeft + 360) % 360) * chrtScl; y = yOffset + cHeight - i; // Position in chart area if (i >= (numWndVals / dataIntv) - 10) - LOG_DEBUG(GwLog::ERROR, "PageWindPlot Chart: i: %d, chrtVal: %d, bufStart: %d count: %d, linesToShow: %d", i, chrtVal, bufStart, count, (numWndVals / dataIntv)); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %d, bufStart: %d, count: %d, linesToShow: %d", i, chrtVal, bufStart, count, (numWndVals / dataIntv)); if ((i == 0) || (chrtPrevVal == INT16_MIN)) { // just a dot for 1st chart point or after some invalid values @@ -404,15 +380,15 @@ public: int minWndDir = pageData.boatHstry.twdHstry->getMin(numWndVals) / 1000.0 * radToDeg; int maxWndDir = pageData.boatHstry.twdHstry->getMax(numWndVals) / 1000.0 * radToDeg; - LOG_DEBUG(GwLog::ERROR, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter); - if ((minWndDir > wndCenter) || (maxWndDir < wndCenter)) { + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter); + if ((minWndDir + 540 >= wndCenter + 540) || (maxWndDir + 540 <= wndCenter + 540)) { // Check if all wind value are left or right of center value -> optimize chart range - int midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals) / 1000.0 * radToDeg; + midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals) / 1000.0 * radToDeg; if (midWndDir != INT16_MIN) { wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value } } - LOG_DEBUG(GwLog::ERROR, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter); break; } } @@ -433,6 +409,8 @@ public: int xPosTws; static const int yPosTws = yOffset + 40; + twsValue = pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384; // TWS value in knots + xPosTws = flipTws ? 20 : width - 138; currentZone = (y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146) ? 1 : 0; // Define current zone for TWS value if (currentZone != lastZone) { @@ -447,21 +425,24 @@ public: getdisplay().fillRect(xPosTws - 4, yPosTws - 38, 142, 44, commonData->bgcolor); // Clear area for TWS value getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b); getdisplay().setCursor(xPosTws, yPosTws); - if (twsValue < 0 || twsValue >= 100) { + if (!DataValid[1]) { getdisplay().print("--.-"); } else { - if (twsValue < 10.0) { - getdisplay().printf("!%3.1f", twsValue); // Value + if (DataValue[1] < 9.95) { + getdisplay().printf("!%3.1f", DataValue[1] + 0.05); // Value, round to 1 decimal } else { - getdisplay().printf("%4.1f", twsValue); // Value} + getdisplay().printf("%4.1f", DataValue[1] + 0.05); // Value, round to 1 decimal } } getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setCursor(xPosTws + 82, yPosTws - 14); - getdisplay().print("TWS"); // Name +// getdisplay().print("TWS"); // Name + getdisplay().print(DataName[1]); // Name getdisplay().setFont(&Ubuntu_Bold8pt8b); - getdisplay().setCursor(xPosTws + 78, yPosTws + 1); - getdisplay().printf(" kn"); // Unit +// getdisplay().setCursor(xPosTws + 78, yPosTws + 1); + getdisplay().setCursor(xPosTws + 82, yPosTws + 1); +// getdisplay().printf(" kn"); // Unit + getdisplay().print(DataUnit[1]); // Unit } // chart Y axis labels; print at last to overwrite potential chart lines in label area @@ -471,7 +452,7 @@ public: for (int i = 1; i <= 3; i++) { yPos = yOffset + (i * 60); getdisplay().fillRect(0, yPos, width, 1, commonData->fgcolor); - getdisplay().fillRect(0, yPos - 8, 26, 16, commonData->bgcolor); // Clear small area to remove potential chart lines + getdisplay().fillRect(0, yPos - 8, 24, 16, commonData->bgcolor); // Clear small area to remove potential chart lines getdisplay().setCursor(1, yPos + 4); if (count >= intvBufSize) { // Calculate minute value for label @@ -483,8 +464,8 @@ public: getdisplay().printf("%3d", chrtLbl); // Wind value label } - unsigned long finish = millis() - start; -// LOG_DEBUG(GwLog::ERROR, "PageWindPlot Time: %lu", finish); + unsigned long finish = millis() - WndPlotStart; + LOG_DEBUG(GwLog::ERROR, "PageWindPlot Time: %lu", finish); // Update display getdisplay().nextPage(); // Partial update (fast) }; @@ -505,9 +486,9 @@ PageDescription registerPageWindPlot( "WindPlot", // Page name createPage, // Action 0, // Number of bus values depends on selection in Web configuration -// { "TWD", "TWA", "TWS", "HDM", "AWA", "AWS", "STW", "COG", "SOG" }, // Bus values we need in the page - { }, // Bus values we need in the page + { "TWD", "TWS" }, // Bus values we need in the page +// {}, // Bus values we need in the page true // Show display header on/off ); -#endif +#endif \ No newline at end of file diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h index e518221..ad252ea 100644 --- a/lib/obp60task/Pagedata.h +++ b/lib/obp60task/Pagedata.h @@ -5,15 +5,10 @@ #include #include "LedSpiTask.h" #include "OBPRingBuffer.h" +#include "OBPDataOperations.h" #define MAX_PAGE_NUMBER 10 // Max number of pages for show data -typedef struct{ - RingBuffer* twdHstry; - RingBuffer* twsHstry; - RingBuffer* dbtHstry; -} tBoatHstryData; - typedef std::vector ValueList; typedef struct{ diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json index da8be86..c1f9ab8 100644 --- a/lib/obp60task/config.json +++ b/lib/obp60task/config.json @@ -219,6 +219,17 @@ "obp60":"true" } }, + { + "name": "calcTrueWnds", + "label": "Calculate True Wind", + "type": "boolean", + "default": "false", + "description": "If not available, calculate true wind data from appearant wind and other boat data", + "category": "OBP60 Settings", + "capabilities": { + "obp60": "true" + } + }, { "name": "lengthFormat", "label": "Length Format", diff --git a/lib/obp60task/config_obp40.json b/lib/obp60task/config_obp40.json index 782e7f0..8747e4e 100644 --- a/lib/obp60task/config_obp40.json +++ b/lib/obp60task/config_obp40.json @@ -219,6 +219,17 @@ "obp40": "true" } }, + { + "name": "calcTrueWnds", + "label": "Calculate True Wind", + "type": "boolean", + "default": "false", + "description": "If not available, calculate true wind data from appearant wind and other boat data", + "category": "OBP40 Settings", + "capabilities": { + "obp40": "true" + } + }, { "name": "lengthFormat", "label": "Length Format", diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 2d4e72b..505d89c 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -376,6 +376,112 @@ void underVoltageDetection(GwApi *api, CommonData &common){ } } +//bool addTrueWind(GwApi* api, BoatValueList* boatValues, double *twd, double *tws, double *twa) { +bool addTrueWind(GwApi* api, BoatValueList* boatValues) { + // Calculate true wind data and add to obp60task boat data list + + double awaVal, awsVal, cogVal, stwVal, sogVal, hdtVal, hdmVal, varVal; + 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::ERROR,"obp60task addTrueWind: AWA: %.1f, AWS: %.1f, COG: %.1f, STW: %.1f, 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, 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, &twdBVal->value, &twsBVal->value, &twaBVal->value); + twdBVal->valid = isCalculated; + twsBVal->valid = isCalculated; + twaBVal->valid = isCalculated; + + api->getLogger()->logDebug(GwLog::ERROR,"obp60task calcTrueWind: TWD_Valid? %d, TWD=%.1f, TWS=%.1f, TWA=%.1f, isCalculated? %d", twdBVal->valid, twdBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852, + twaBVal->value * RAD_TO_DEG, isCalculated); + + return isCalculated; +} + +void initHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList) { + // Init history buffers for TWD, TWS + + GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here + + 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) in rad (0...2*PI), shifted by 1000 for 3 decimals + int twsHstryMax = 1000; // Max value for wind speed (TWS) 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); + + GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName()); + GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName()); + GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA"); +} + +void handleHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList) { + // 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 twdBuf, twsBuf; + 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"); + + api->getLogger()->logDebug(GwLog::ERROR,"obp60task handleHstryBuf: twdBVal: %f, twsBVal: %f, twaBVal: %f, TWD_isValid? %d", twdBVal->value * RAD_TO_DEG, + twsBVal->value * 3.6 / 1.852, twaBVal->value * RAD_TO_DEG, twdBVal->valid); + calBVal = new GwApi::BoatValue("TWD"); // temporary solution for calibration of history buffer values + calBVal->setFormat(twdBVal->getFormat()); + if (twdBVal->valid) { + calBVal->value = twdBVal->value; + calBVal->valid = twdBVal->valid; + calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated + twdBuf = static_cast(std::round(calBVal->value * 1000)); + if (twdBuf >= twdHstryMin && twdBuf <= twdHstryMax) { + hstryBufList.twdHstry->add(twdBuf); + } + } + delete calBVal; + calBVal = nullptr; + + calBVal = new GwApi::BoatValue("TWS"); // temporary solution for calibration of history buffer values + calBVal->setFormat(twsBVal->getFormat()); + if (twsBVal->valid) { + calBVal->value = twsBVal->value; + calBVal->valid = twsBVal->valid; + calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated + twsBuf = static_cast(std::round(calBVal->value * 10)); + if (twsBuf >= twsHstryMin && twsBuf <= twsHstryMax) { + hstryBufList.twsHstry->add(twsBuf); + } + } + delete calBVal; + calBVal = nullptr; +} + // OBP60 Task //#################################################################################### void OBP60Task(GwApi *api){ @@ -392,11 +498,6 @@ void OBP60Task(GwApi *api){ commonData.logger=logger; commonData.config=config; - // Create ring buffers for history storage of some boat data - RingBuffer twdHstry(960); // Circular buffer to store wind direction values; store 960 TWD values for 16 minutes history - RingBuffer twsHstry(960); // Circular buffer to store wind speed values (TWS) - RingBuffer dbtHstry(960); // Circular buffer to store water depth values (DBT) - #ifdef HARDWARE_V21 // Keyboard coordinates for page footer initKeys(commonData); @@ -494,6 +595,11 @@ void OBP60Task(GwApi *api){ //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 wind direction values; store 960 TWD values for 16 minutes history + RingBuffer twsHstry(960); // Circular buffer to store wind speed values (TWS) + tBoatHstryData hstryBufList = {&twdHstry, &twsHstry}; + //fill the page data from config numPages=config->getInt(config->visiblePages,1); if (numPages < 1) numPages=1; @@ -532,8 +638,10 @@ 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); } - // Add boat history data to page parameters - pages[i].parameters.boatHstry = {&twdHstry, &twsHstry, &dbtHstry}; + if (pages[i].description->pageName == "WindPlot") { + // 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); @@ -541,32 +649,12 @@ void OBP60Task(GwApi *api){ // Read all calibration data settings from config calibrationData.readConfig(config, logger); - // List of boat values for history storage - GwApi::BoatValue *twdBVal=new GwApi::BoatValue(GwBoatData::_TWD); - GwApi::BoatValue *twsBVal=new GwApi::BoatValue(GwBoatData::_TWS); - GwApi::BoatValue *dbtBVal=new GwApi::BoatValue(GwBoatData::_DBT); - GwApi::BoatValue *hstryValList[]={twdBVal, twsBVal, dbtBVal}; - api->getBoatDataValues(3, hstryValList); - // Boat data history buffer initialization - 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) in rad (0...2*PI), shifted by 1000 for 3 decimals - int twsHstryMax = 1000; // Max value for wind speed (TWS) in m/s, shifted by 10 for 1 decimal - int dbtHstryMax = 3276; // Max value for depth in m (=327), shifted by 10 for 1 decimal - // Initialize history buffers with meta data - twdHstry.setMetaData(twdBVal->getName(), twdBVal->getFormat(), hstryUpdFreq, hstryMinVal, twdHstryMax); - twsHstry.setMetaData(twsBVal->getName(), twsBVal->getFormat(), hstryUpdFreq, hstryMinVal, twsHstryMax); - dbtHstry.setMetaData(dbtBVal->getName(), dbtBVal->getFormat(), hstryUpdFreq, hstryMinVal, dbtHstryMax); - bool simulation = api->getConfig()->getBool(api->getConfig()->useSimuData, false); + // Check user setting for true wind calculation + bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false); + // bool simulation = api->getConfig()->getBool(api->getConfig()->useSimuData, false); - // List of boat values for true winds calculation - GwApi::BoatValue *awaBVal=new GwApi::BoatValue(GwBoatData::_AWA); - GwApi::BoatValue *awsBVal=new GwApi::BoatValue(GwBoatData::_AWS); - GwApi::BoatValue *cogBVal=new GwApi::BoatValue(GwBoatData::_COG); - GwApi::BoatValue *stwBVal=new GwApi::BoatValue(GwBoatData::_STW); - GwApi::BoatValue *hdtBVal=new GwApi::BoatValue(GwBoatData::_HDT); - GwApi::BoatValue *hdmBVal=new GwApi::BoatValue(GwBoatData::_HDM); - GwApi::BoatValue *WndCalcValList[]={awaBVal, awsBVal, cogBVal, stwBVal, hdtBVal, hdmBVal}; + // Initialize history buffer for certain boat data + initHstryBuf(api, &boatValues, hstryBufList); // Display screenshot handler for HTTP request // http://192.168.15.1/api/user/OBP60Task/screenshot @@ -623,18 +711,6 @@ void OBP60Task(GwApi *api){ GwApi::BoatValue *lon = boatValues.findValueOrCreate("LON"); // Load GpsLongitude GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP -/* // Boat values for wind conversion for main loop; will be calculated in case values are not available by sensors - GwApi::BoatValue *twd = boatValues.findValueOrCreate("TWD"); // True Wind Direction - GwApi::BoatValue *tws = boatValues.findValueOrCreate("TWS"); // True Wind Speed - GwApi::BoatValue *twa = boatValues.findValueOrCreate("TWA"); // True Wind Angle - GwApi::BoatValue *awaBVal = boatValues.findValueOrCreate("AWA"); // Apparent Wind Angle - GwApi::BoatValue *awsBVal = boatValues.findValueOrCreate("AWS"); // Apparent Wind Speed - GwApi::BoatValue *cogBVal = boatValues.findValueOrCreate("COG"); // Course Over Ground - GwApi::BoatValue *stwBVal = boatValues.findValueOrCreate("STW"); // Speed Through Water - GwApi::BoatValue *hdtBVal = boatValues.findValueOrCreate("HDT"); // Heading True - GwApi::BoatValue *ctwBVal = boatValues.findValueOrCreate("CTW"); // Course Through Water - GwApi::BoatValue *hdmBVal = boatValues.findValueOrCreate("HDM"); // Heading Magnetic -*/ LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop"); commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime @@ -648,7 +724,6 @@ void OBP60Task(GwApi *api){ long starttime3 = millis(); // Display update all 1s long starttime4 = millis(); // Delayed display update after 4s when select a new page long starttime5 = millis(); // Calculate sunrise and sunset all 1s - unsigned long starttime10 = millis(); // Get history TWD, TWS, DBT data and calculate true winds each 1s pages[pageNumber].page->setupKeys(); // Initialize keys for first page @@ -836,62 +911,8 @@ void OBP60Task(GwApi *api){ getdisplay().fillScreen(commonData.bgcolor); // Clear display getdisplay().nextPage(); // Full update } - } - - // Read TWD, TWS, DBT data from boatData each 1000ms for history and windplot display - if((millis() > starttime10 + 1000) && !simulation) { - double twdVal, twsVal, dbtVal; - double awaVal, awsVal, cogVal, stwVal, hdtVal, hdmVal; - double DBL_MIN = std::numeric_limits::lowest(); - - starttime10 = millis(); - LOG_DEBUG(GwLog::DEBUG,"History buffer write cycle"); - api->getBoatDataValues(3, hstryValList); - - if (!twdBVal->valid || !twsBVal->valid) { - api->getBoatDataValues(6, WndCalcValList); // Get all values for true wind calculation - awaVal = awaBVal->valid ? awaBVal->value * RAD_TO_DEG : __DBL_MIN__; - awsVal = awsBVal->valid ? awsBVal->value : __DBL_MIN__; - cogVal = cogBVal->valid ? cogBVal->value * RAD_TO_DEG : __DBL_MIN__; - stwVal = stwBVal->valid ? stwBVal->value : __DBL_MIN__; - hdtVal = hdtBVal->valid ? hdtBVal->value * RAD_TO_DEG : __DBL_MIN__; - hdmVal = hdmBVal->valid ? hdmBVal->value * RAD_TO_DEG : __DBL_MIN__; - LOG_DEBUG(GwLog::ERROR,"obp60task - Read data: AWA: %f, AWS: %f, COG: %f, STW: %f, HDT: %f, TWD=%f, TWS=%f", awaBVal->value, awsBVal->value, - cogBVal->value, stwBVal->value, hdtBVal->value, twdBVal->value, twsBVal->value); - - bool isCalculated = WindUtils::calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &cogVal, &hdmVal, &twdVal, &twsVal); // Calculate true wind if TWD not available -// bool isCalculated = WindUtils::calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &hdtVal, &hdmVal, &twdVal, &twsVal); // Calculate true wind if TWD not available - LOG_DEBUG(GwLog::ERROR,"obp60task - calc Wind: AWA: %f, AWS: %f, COG: %f, STW: %f, HDT: %f, TWD=%f, TWS=%f, converted? %d", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852, - cogBVal->value * RAD_TO_DEG, stwBVal->value * 3.6 / 1.852, hdtBVal->value * RAD_TO_DEG, twdVal, twsVal, isCalculated); - } - if (twdBVal->valid) { - twdVal = std::round(twdBVal->value * 1000); // Shift value to store decimals in int16_t); - if (twdVal < hstryMinVal || twdVal > twdHstryMax) { - twdVal = INT16_MIN; // Add invalid value - } - } - twdHstry.add(static_cast(twdVal)); - - if (twsBVal->valid) { - twsVal = static_cast(twsBVal->value * 10); // Shift value to store decimals in int16_t - if (twsVal < hstryMinVal || twsVal > twsHstryMax) { - twsVal = INT16_MIN; // Add invalid value - } - } - twsHstry.add(twsVal); - - if (dbtBVal->valid) { - dbtVal = dbtBVal->value * 10; // Shift value to store decimals in int16_t - if (dbtVal < hstryMinVal || dbtVal > dbtHstryMax) { - dbtVal = INT16_MIN; // Add invalid value - } - dbtHstry.add(dbtVal); - } - - int counttime = millis() - starttime10; - LOG_DEBUG(GwLog::ERROR,"obp60task: History buffer write time: %d", counttime); - } - + } + // Refresh display data, default all 1s currentPage = pages[pageNumber].page; int pagetime = 1000; @@ -907,6 +928,12 @@ void OBP60Task(GwApi *api){ api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues); api->getStatus(commonData.status); + if (calcTrueWnds) { + addTrueWind(api, &boatValues); + } + // Handle history buffers for TWD, TWS for wind plot page and other usage + handleHstryBuf(api, &boatValues, hstryBufList); + // Clear display // getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor); getdisplay().fillScreen(commonData.bgcolor); // Clear display