From 72ddeb3cfb2060bba893df5df2e54fa992b8acef Mon Sep 17 00:00:00 2001 From: Ulrich Meine Date: Tue, 1 Jul 2025 01:27:41 +0200 Subject: [PATCH] Pointer correction -> no data copy; conc. access issues --- .vscode/settings.json | 3 +- lib/obp60task/OBPRingBuffer.h | 8 +- lib/obp60task/OBPRingBuffer.tpp | 54 +---------- lib/obp60task/OBPSensorTask.cpp | 65 +++++++------ lib/obp60task/OBPSensorTask.h | 10 ++ lib/obp60task/PageWindPlot.cpp | 156 +++++++++++++++++--------------- lib/obp60task/Pagedata.h | 9 ++ lib/obp60task/obp60task.cpp | 5 + 8 files changed, 159 insertions(+), 151 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index eb2cff6..55a7256 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,8 @@ "files.associations": { "stdexcept": "cpp", "limits": "cpp", - "functional": "cpp" + "functional": "cpp", + "*.tpp": "cpp" }, "github.copilot.nextEditSuggestions.enabled": false } \ No newline at end of file diff --git a/lib/obp60task/OBPRingBuffer.h b/lib/obp60task/OBPRingBuffer.h index 1a57266..7d4067f 100644 --- a/lib/obp60task/OBPRingBuffer.h +++ b/lib/obp60task/OBPRingBuffer.h @@ -1,4 +1,5 @@ #pragma once +#include "GwSynchronized.h" #include #include #include @@ -8,6 +9,7 @@ template class RingBuffer { private: + SemaphoreHandle_t locker; std::vector buffer; size_t capacity; size_t head; // Points to the next insertion position @@ -39,7 +41,6 @@ public: T getMax(size_t amount) const; // Get maximum value of the last values of buffer T getMid() const; // Get mid value between and value in buffer T getMid(size_t amount) const; // Get mid value between and value of the last values of buffer - T getRng(T center, size_t amount) const; // Get maximum difference of last of buffer values to center value T getMedian() const; // Get the median value in buffer T getMedian(size_t amount) const; // Get the median value of the last values of buffer size_t getCapacity() const; // Get the buffer capacity (maximum size) @@ -50,9 +51,8 @@ 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 - T operator[](size_t index); - std::vector getAllValues() const; // Operator[] for convenient access (same as get()) - + T operator[](size_t index); // Operator[] for convenient access (same as get()) + std::vector getAllValues() const; // Get all current values as a vector }; #include "OBPRingBuffer.tpp" \ No newline at end of file diff --git a/lib/obp60task/OBPRingBuffer.tpp b/lib/obp60task/OBPRingBuffer.tpp index c3814b8..e5589fd 100644 --- a/lib/obp60task/OBPRingBuffer.tpp +++ b/lib/obp60task/OBPRingBuffer.tpp @@ -20,6 +20,7 @@ RingBuffer::RingBuffer(size_t size) updFreq = MIN_VAL; smallest = MIN_VAL; largest = MAX_VAL; + buffer.resize(size, MIN_VAL); // return true; @@ -46,9 +47,9 @@ bool RingBuffer::getMetaData(String& name, String& format, int& updateFrequen name = dataName; format = dataFmt; - updFreq = updFreq; - smallest = smallest; - largest = largest; + updateFrequency = updFreq; + minValue = smallest; + maxValue = largest; return true; // Meta data successfully retrieved } @@ -78,12 +79,8 @@ void RingBuffer::add(const T& value) template T RingBuffer::get(size_t index) const { - if (isEmpty()) { - throw std::runtime_error("Buffer is empty"); - } - if (index < 0 || index >= count) { + if (isEmpty() || index < 0 || index >= count) { return MIN_VAL; - // throw std::out_of_range("Index out of range"); } size_t realIndex = (first + index) % capacity; @@ -103,7 +100,6 @@ T RingBuffer::getFirst() const { if (isEmpty()) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } return buffer[first]; } @@ -114,7 +110,6 @@ T RingBuffer::getLast() const { if (isEmpty()) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } return buffer[last]; } @@ -125,7 +120,6 @@ T RingBuffer::getMin() const { if (isEmpty()) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } T minVal = get(first); @@ -145,7 +139,6 @@ T RingBuffer::getMin(size_t amount) const { if (isEmpty() || amount <= 0) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } if (amount > count) amount = count; @@ -167,7 +160,6 @@ T RingBuffer::getMax() const { if (isEmpty()) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } T maxVal = get(first); @@ -187,7 +179,6 @@ T RingBuffer::getMax(size_t amount) const { if (isEmpty() || amount <= 0) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } if (amount > count) amount = count; @@ -209,7 +200,6 @@ T RingBuffer::getMid() const { if (isEmpty()) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } return (getMin() + getMax()) / static_cast(2); @@ -221,7 +211,6 @@ T RingBuffer::getMid(size_t amount) const { if (isEmpty() || amount <= 0) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } if (amount > count) @@ -230,44 +219,12 @@ T RingBuffer::getMid(size_t amount) const return (getMin(amount) + getMax(amount)) / static_cast(2); } -// ******************* works for wind direction only -> move out of here ******************************* -// Get maximum difference of last of buffer values to center value -template -T RingBuffer::getRng(T center, size_t amount) const -{ - if (isEmpty() || amount <= 0) { - return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); - } - if (amount > count) - amount = count; - - T value = 0; - T rng = 0; - T maxRng = MIN_VAL; - // Start from the newest value (last) and go backwards x times - for (size_t i = 0; i < amount; i++) { - value = get((last + capacity - i) % capacity); - if (value == MIN_VAL) { - continue; - } - rng = abs(((value - center + 540) % 360) - 180); - if (rng > maxRng) - maxRng = rng; - } - if (maxRng > 180) { - maxRng = 180; - } - return maxRng; -} - // Get the median value in the buffer template T RingBuffer::getMedian() const { if (isEmpty()) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } // Create a temporary vector with current valid elements @@ -297,7 +254,6 @@ T RingBuffer::getMedian(size_t amount) const { if (isEmpty() || amount <= 0) { return MIN_VAL; - // throw std::runtime_error("Buffer is empty"); } if (amount > count) amount = count; diff --git a/lib/obp60task/OBPSensorTask.cpp b/lib/obp60task/OBPSensorTask.cpp index 90ce62a..b0271a1 100644 --- a/lib/obp60task/OBPSensorTask.cpp +++ b/lib/obp60task/OBPSensorTask.cpp @@ -71,7 +71,7 @@ void sensorTask(void *param){ batC.begin(); // Create ring buffers for history storage of some boat data - // later read data types from config and specify buffers accordingly + // later read additonal data types from config and specify buffers accordingly 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) @@ -381,16 +381,18 @@ void sensorTask(void *param){ // later read data types from config and specify hstryvalList accordingly 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 *dbtBVal=new GwApi::BoatValue(GwBoatData::_STW); // STW just for testing GwApi::BoatValue *hstryValList[]={twdBVal, twsBVal, dbtBVal}; // List of boat values for history storage - int twdHstryMin = 0; - int twsHstryMin = 0; - int dbtHstryMin = 0; // Initialize history buffers with meta data api->getBoatDataValues(3,hstryValList); - twdHstry.setMetaData(twdBVal->getName(), twdBVal->getFormat(), 1000, twdHstryMin, 360); // Set meta data for TWD buffer: update frequency 1000ms, min value 0, max value 360 - twsHstry.setMetaData(twsBVal->getName(), twsBVal->getFormat(), 1000, twsHstryMin, 100); // Set meta data for TWS buffer: update frequency 1000ms, min value 0, max value 100 - dbtHstry.setMetaData(dbtBVal->getName(), dbtBVal->getFormat(), 1000, dbtHstryMin, 10928); // Set meta data for TWS buffer: update frequency 1000ms, min value 0, max value 10,928 + int hstryUpdFreq = 1000; // Update frequency for history buffers in ms + int hstryMinVal = 0; // Minimum value for history buffers + int twdHstryMax = 360; + int twsHstryMax = 100; + int dbtHstryMax = 327; // Max value for depth (due to signed 16 bit integer and decimals shift) + 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); // Internal RTC with NTP init ESP32Time rtc(0); @@ -800,37 +802,48 @@ void sensorTask(void *param){ // Read TWD, TWS, DBT data from boatData every 1000ms for history and windplot display if(millis() > starttime20 + 1000){ starttime20 = millis(); + int16_t val; api->getBoatDataValues(3,hstryValList); - int16_t bValue; if (twdBVal->valid) { - bValue = int16_t(RadToDeg(twdBVal->value)); - twdHstry.add(bValue); + val = static_cast(std::round(RadToDeg(twdBVal->value))); + if (val < hstryMinVal || val > twdHstryMax) { + val = INT16_MIN; // Add invalid value + } } else { - twdHstry.add(INT16_MIN); // Add invalid value + val = INT16_MIN; } + twdHstry.add(val); if (twsBVal->valid) { - bValue = int16_t(twsBVal->value); - twsHstry.add(bValue); + val = static_cast(twsBVal->value * 100); // Shift value to store decimals in int16_t + if (val < hstryMinVal || val > twsHstryMax) { + val = INT16_MIN; // Add invalid value + } } else { - twsHstry.add(INT16_MIN); // Add invalid value + val = INT16_MIN; } + twsHstry.add(val); if (dbtBVal->valid) { - bValue = int16_t(dbtBVal->value); - dbtHstry.add(bValue); + val = static_cast(dbtBVal->value * 100); // Shift value to store decimals in int16_t + if (val < hstryMinVal || val > dbtHstryMax) { + val = INT16_MIN; // Add invalid value + } } else { - dbtHstry.add(INT16_MIN); // Add invalid value + val = INT16_MIN; } - String TmpName; - String TmpFormat; - int TmpUpdFreq; - int TmpSmallest; - int TmpBiggest; - twdHstry.getMetaData(TmpName, TmpFormat, TmpUpdFreq, TmpSmallest, TmpBiggest); - api->getLogger()->logDebug(GwLog::ERROR,"History buffer TWD: name:%s format:%s Freq:%d, Min: %d, Max: %d", TmpName.c_str(), TmpFormat.c_str(), TmpUpdFreq, TmpSmallest, TmpBiggest); - api->getLogger()->logDebug(GwLog::ERROR,"History buffers: TWD:%d TWS:%d DBT:%d", twdHstry.getLast(), twsHstry.getLast(), dbtHstry.getLast()); + dbtHstry.add(val); + +// api->getLogger()->logDebug(GwLog::ERROR,"SensorTask pointer: TWD: %p, TWS: %p, STW: %p", twdHstry, twsHstry, dbtHstry); + api->getLogger()->logDebug(GwLog::ERROR,"SensorTask Data: TWD:%d TWS:%f DBT:%f", std::round(RadToDeg(twdBVal->value)), twsBVal->value, dbtBVal->value); + api->getLogger()->logDebug(GwLog::ERROR,"SensorTask buffers: TWD:%d TWS:%f DBT:%f", twdHstry.getLast(), twsHstry.getLast(), dbtHstry.getLast()); + } + // Add sensor and history data to shared memory for transfer to pages shared->setSensorData(sensors); + shared->setHstryBuf(twdHstry, twsHstry, dbtHstry); +// tBoatHstryData tmpHstryData = shared->getHstryBuf(); +// api->getLogger()->logDebug(GwLog::ERROR,"SensorTask tmpHstryData pointer: TWD: %p, TWS: %p, STW: %p", tmpHstryData.twdHstry, tmpHstryData.twsHstry, tmpHstryData.dbtHstry); + } vTaskDelete(NULL); } diff --git a/lib/obp60task/OBPSensorTask.h b/lib/obp60task/OBPSensorTask.h index 7dd9f24..352632a 100644 --- a/lib/obp60task/OBPSensorTask.h +++ b/lib/obp60task/OBPSensorTask.h @@ -8,6 +8,7 @@ class SharedData{ private: SemaphoreHandle_t locker; SensorData sensors; + tBoatHstryData boatHstry; public: GwApi *api=NULL; SharedData(GwApi *api){ @@ -22,6 +23,15 @@ class SharedData{ GWSYNCHRONIZED(&locker); return sensors; } + void setHstryBuf(RingBuffer twdHstry,RingBuffer twsHstry,RingBuffer dbtHstry) { + GWSYNCHRONIZED(&locker); + boatHstry={&twdHstry, &twsHstry, &dbtHstry}; +// api->getLogger()->logDebug(GwLog::ERROR, "SharedData setHstryBuf: TWD: %p, TWS: %p, STW: %p", boatHstry.twdHstry, boatHstry.twsHstry, boatHstry.dbtHstry); + } + tBoatHstryData getHstryBuf() { + GWSYNCHRONIZED(&locker); + return boatHstry; + } }; void createSensorTask(SharedData *shared); diff --git a/lib/obp60task/PageWindPlot.cpp b/lib/obp60task/PageWindPlot.cpp index cc50b58..bcd1dc3 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -4,6 +4,7 @@ #include "OBP60Extensions.h" #include "OBPRingBuffer.h" #include "Pagedata.h" +#include // just for RadToDeg function #include @@ -318,6 +319,7 @@ public: int twdValue; static const float radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees + bool isInitialized = false; // Flag to indicate that page is initialized bool wndDataValid = false; // Flag to indicate if wind data is valid bool simulation = false; bool holdValues = false; @@ -352,21 +354,21 @@ public: static float chrtScl; // Scale for wind values in pixels per degree int chrtVal; // Current wind value static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line - int distVals; // helper to check wndCenter crossing - int distMid; // helper to check wndCenter crossing +// int distVals; // helper to check wndCenter crossing +// int distMid; // helper to check wndCenter crossing - static RingBuffer windDirHstry(bufSize); // Circular buffer to store wind direction values - static RingBuffer windSpdHstry(bufSize); // Circular buffer to store wind speed values + // static RingBuffer windDirHstry(bufSize); // Circular buffer to store wind direction values + // static RingBuffer windSpdHstry(bufSize); // Circular buffer to store wind speed values LOG_DEBUG(GwLog::LOG, "Display page WindPlot"); unsigned long start = millis(); // Data initialization - if (windDirHstry.getCurrentSize() == 0) { - /* if (!windDirHstry.begin(bufSize)) { - logger->logDebug(GwLog::ERROR, "Failed to initialize wind direction history buffer"); - return; - } */ + LOG_DEBUG(GwLog::ERROR, "PageWindPlot buffers: TWD:%d TWS:%f DBT:%f", pageData.boatHstry.twdHstry->getLast(), + pageData.boatHstry.twsHstry->getLast() * 0.0194384, pageData.boatHstry.dbtHstry->getLast() / 100); + + // if (windDirHstry.getCurrentSize() == 0) { + if (!isInitialized) { simWnd = 0; simTWS = 0; twdValue = 0; @@ -374,6 +376,7 @@ public: linesToShow = 0; oldDataIntv = dataIntv; newDate = 0; + isInitialized = true; // Set flag to indicate that page is now initialized } // Get config data @@ -389,46 +392,47 @@ public: setFlashLED(false); } - // Read boatdata values for TWD, TWA, TWS, HDM, AWA, AWS, STW, COG, SOG, if available - for (int i = 0; i < numCfgValues; 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(dataName[i], 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; - dataSValue[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places - dataUnit[i] = formatValue(bvalue, *commonData).unit; - if (dataValid[i]) { - dataSValueOld[i] = dataSValue[i]; // Save old value - dataUnitOld[i] = dataUnit[i]; // Save old unit - } - } + /* // Read boatdata values for TWD, TWA, TWS, HDM, AWA, AWS, STW, COG, SOG, if available + for (int i = 0; i < numCfgValues; 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(dataName[i], 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; + dataSValue[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + dataUnit[i] = formatValue(bvalue, *commonData).unit; + if (dataValid[i]) { + dataSValueOld[i] = dataSValue[i]; // Save old value + dataUnitOld[i] = dataUnit[i]; // Save old unit + } + } - // Store TWD wind value in buffer, regardless of validity -> one value per second (if delivered in that frequency) - twdValue = int((dataValue[0] * radToDeg) + 0.5); // Read TWD value in degrees and round to integer - if (dataValid[0]) { // TWD data existing - wndDataValid = true; - } else { - // Try to calculate TWD value from other data, if available - // wndDataValid = windValues.calcTWD(&twdValue, dataValue[1], dataValue[2], dataValue[3], dataValue[4], dataValue[5], dataValue[6]); - } + // Store TWD wind value in buffer, regardless of validity -> one value per second (if delivered in that frequency) + twdValue = int((dataValue[0] * radToDeg) + 0.5); // Read TWD value in degrees and round to integer + if (dataValid[0]) { // TWD data existing + wndDataValid = true; + } else { + // Try to calculate TWD value from other data, if available + // wndDataValid = windValues.calcTWD(&twdValue, dataValue[1], dataValue[2], dataValue[3], dataValue[4], dataValue[5], dataValue[6]); + } - if (simulation) { - // Simulate data if simulation is enabled; use default simulation values for TWS - simWnd += random(simStep * -1, simStep); // random value between -simStep and +simStep - if (simWnd < 0) - simWnd += 360; - simWnd = simWnd % 360; - windDirHstry.add(simWnd); - // LOG_DEBUG(GwLog::DEBUG, "PageWindPlot simulation data: windValue: %d, windSpeed: %s", simWnd, dataSValue[2].c_str()); - } else if (wndDataValid) { - windDirHstry.add(twdValue); - } + if (simulation) { + // Simulate data if simulation is enabled; use default simulation values for TWS + simWnd += random(simStep * -1, simStep); // random value between -simStep and +simStep + if (simWnd < 0) + simWnd += 360; + simWnd = simWnd % 360; + windDirHstry.add(simWnd); + // LOG_DEBUG(GwLog::DEBUG, "PageWindPlot simulation data: windValue: %d, windSpeed: %s", simWnd, dataSValue[2].c_str()); + } else if (wndDataValid) { + windDirHstry.add(twdValue); + } */ // Identify buffer sizes and buffer position to print on the chart intvBufSize = cHeight * dataIntv; - count = windDirHstry.getCurrentSize(); + // count = windDirHstry.getCurrentSize(); + count = pageData.boatHstry.twdHstry->getCurrentSize(); numWndValues = min(count, intvBufSize); newDate++; if (dataIntv != oldDataIntv) { @@ -442,31 +446,34 @@ public: if (count == bufSize) { bufStart--; // show the latest wind values in buffer; keep 1st value constant in a rolling buffer when new data is added } - LOG_DEBUG(GwLog::ERROR, "PageWindPlot Dataset: TWD: %d, count: %d, intvBufSize: %d, numWndValues: %d, bufStart: %d, linesToShow: %d, newDate: %d", twdValue, count, intvBufSize, numWndValues, bufStart, linesToShow, newDate); + LOG_DEBUG(GwLog::ERROR, "PageWindPlot Dataset: TWD: %d, TWS: %f, STW: %f, count: %d, intvBufSize: %d, numWndValues: %d, bufStart: %d, linesToShow: %d, newDate: %d", pageData.boatHstry.twdHstry->getLast(), + pageData.boatHstry.twsHstry->getLast() * 0.0194384, pageData.boatHstry.dbtHstry->getLast() / 100, count, intvBufSize, numWndValues, bufStart, linesToShow, newDate); +// LOG_DEBUG(GwLog::ERROR, "PageWindPlot Pointer: TWD: %p, TWS: %p, STW: %p", pageData.boatHstry.twdHstry, pageData.boatHstry.twsHstry, pageData.boatHstry.dbtHstry); - if (bvalue == NULL) - return; - LOG_DEBUG(GwLog::LOG, "PageWindPlot, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, cnt: %d, valid0: %d", dataName[0].c_str(), dataValue[0], - dataName[1].c_str(), dataValue[1], dataName[2].c_str(), dataValue[2], dataName[3].c_str(), dataValue[3], dataName[4].c_str(), dataValue[4], - dataName[5].c_str(), dataValue[5], dataName[6].c_str(), dataValue[6], dataName[7].c_str(), dataValue[7], dataName[8].c_str(), dataValue[8], count, dataValid[0]); +// LOG_DEBUG(GwLog::LOG, "PageWindPlot, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, cnt: %d, valid0: %d", dataName[0].c_str(), dataValue[0], +// dataName[1].c_str(), dataValue[1], dataName[2].c_str(), dataValue[2], dataName[3].c_str(), dataValue[3], dataName[4].c_str(), dataValue[4], +// dataName[5].c_str(), dataValue[5], dataName[6].c_str(), dataValue[6], dataName[7].c_str(), dataValue[7], dataName[8].c_str(), dataValue[8], count, dataValid[0]); // initialize chart range values if (wndCenter == INT_MIN) { - wndCenter = max(0, int(windDirHstry.get(numWndValues - intvBufSize))); // get 1st value of current data interval + // wndCenter = max(0, int(windDirHstry.get(numWndValues - intvBufSize))); // get 1st value of current data interval + wndCenter = max(0, int(pageData.boatHstry.twdHstry->get(numWndValues - intvBufSize))); // 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; } else { // check and adjust range between left, center, and right chart limit - diffRng = getRng(windDirHstry, wndCenter, numWndValues); + // diffRng = getRng(windDirHstry, wndCenter, numWndValues); + diffRng = getRng(*pageData.boatHstry.twdHstry, wndCenter, numWndValues); diffRng = (diffRng == INT_MIN ? 0 : diffRng); if (diffRng > chrtRng) { chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 degree value } else if (diffRng + 10 < chrtRng) { // Reduce chart range for higher resolution if possible chrtRng = max(dfltRng, int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10); } - int debugMin = windDirHstry.getMin(numWndValues); - int debugMax = windDirHstry.getMax(numWndValues); + // int debugMin = windDirHstry.getMin(numWndValues); + int debugMin = pageData.boatHstry.twdHstry->getMin(numWndValues); + int debugMax = pageData.boatHstry.twdHstry->getMax(numWndValues); LOG_DEBUG(GwLog::ERROR, "PageWindPlot Range. wndCenter: %d, numWndValues: %d, min: %d, max: %d, diffrng: %d, chrtRng: %d ", wndCenter, numWndValues, debugMin, debugMax, diffRng, chrtRng); } chrtScl = float(width) / float(chrtRng) / 2.0; // Chart scale: pixels per degree @@ -512,20 +519,29 @@ public: getdisplay().drawCircle(width - 5, yOffset - 17, 2, commonData->fgcolor); // symbol getdisplay().drawCircle(width - 5, yOffset - 17, 3, commonData->fgcolor); // symbol + if (pageData.boatHstry.twdHstry->getMax() == INT16_MIN) { + wndDataValid = false; // only values in buffer -> no valid wind data available + } else { + wndDataValid = true; // At least some wind data available + } // Draw wind values in chart //*********************************************************** - if (wndDataValid || holdValues || simulation) { - // if (count == bufSize) - // bufStart--; // show the latest wind values in buffer; keep 1st value constant in a rolling buffer + if (wndDataValid) { for (int i = 0; i < linesToShow; i++) { - chrtVal = windDirHstry.get(bufStart + (i * dataIntv)); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer + // chrtVal = windDirHstry.get(bufStart + (i * dataIntv)); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer + chrtVal = pageData.boatHstry.twdHstry->get(bufStart + (i * dataIntv)); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer + if (chrtVal == INT16_MIN) { + chrtPrevVal = INT16_MIN; + continue; // skip invalid values + } x = ((chrtVal - wndLeft + 360) % 360) * chrtScl; y = yOffset + cHeight - i; // Position in chart area if (i > linesToShow - 15) LOG_DEBUG(GwLog::ERROR, "PageWindPlot Chart: i: %d, chrtVal: %d, chrtPrevVal: %d, bufStart: %d count: %d, linesToShow: %d", i, chrtVal, chrtPrevVal, bufStart, count, linesToShow); - if (i == 0) { - prevX = x; // just a dot for 1st chart point +// if (i == 0) { + if ((i == 0) || (chrtPrevVal == INT16_MIN)) { + prevX = x; // just a dot for 1st chart point or after some invalid values prevY = y; } else { // cross borders check; shift values to [-180..0..180]; when crossing borders, range is 2x 180 degrees @@ -540,7 +556,7 @@ public: getdisplay().drawLine(prevX, prevY, xSplit, y, commonData->fgcolor); getdisplay().drawLine(prevX, prevY - 1, ((xSplit != prevX) ? xSplit : xSplit - 1), ((xSplit != prevX) ? y - 1 : y), commonData->fgcolor); prevX = (((chrtVal180 > 0 ? wndRight : wndLeft) - wndLeft + 360) % 360) * chrtScl; - LOG_DEBUG(GwLog::ERROR, "PageWindPlot Cross: i: %d, chrtVal: %d, chrtPrevVal: %d, wndLeft: %d wndRight: %d, curr:{%d,%d} prev:{%d,%d}", i, chrtVal, chrtPrevVal, wndLeft, wndRight, x, y, prevX, prevY); + // LOG_DEBUG(GwLog::ERROR, "PageWindPlot Cross: i: %d, chrtVal: %d, chrtPrevVal: %d, wndLeft: %d wndRight: %d, curr:{%d,%d} prev:{%d,%d}", i, chrtVal, chrtPrevVal, wndLeft, wndRight, x, y, prevX, prevY); } } @@ -554,27 +570,25 @@ public: if (i == (cHeight - 1)) { // Reaching chart area top end () linesToShow -= min(40, cHeight); // free top 40 lines of chart for new values bufStart = max(0, count - (linesToShow * dataIntv)); // next start value in buffer to show - if ((windDirHstry.getMin(numWndValues) > wndCenter) || (windDirHstry.getMax(numWndValues) < wndCenter)) { + // if ((windDirHstry.getMin(numWndValues) > wndCenter) || (windDirHstry.getMax(numWndValues) < wndCenter)) { + if ((pageData.boatHstry.twdHstry->getMin(numWndValues) > wndCenter) || (pageData.boatHstry.twdHstry->getMax(numWndValues) < wndCenter)) { // Check if all wind value are left or right of center value -> optimize chart range - int mid = windDirHstry.getMid(numWndValues); - if (mid != INT_MIN) { + int mid = pageData.boatHstry.twdHstry->getMid(numWndValues); + if (mid != INT16_MIN) { wndCenter = int((mid + (mid >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value } } - LOG_DEBUG(GwLog::ERROR, "PageWindPlot FreeTop: cHeight: %d, LinesToShow: %d, numWndValues: %d, wndCenter: %d, bufStart: %d", cHeight, linesToShow, numWndValues, wndCenter, bufStart); + // LOG_DEBUG(GwLog::ERROR, "PageWindPlot FreeTop: cHeight: %d, LinesToShow: %d, numWndValues: %d, wndCenter: %d, bufStart: %d", cHeight, linesToShow, numWndValues, wndCenter, bufStart); break; } } - // LOG_DEBUG(GwLog::DEBUG, "PageWindPlot chart end: chrtVal: %d, x: %d, y: %d prevX: %d, prevY: %d, loop-Counter: %d", chrtVal, x, y, prevX, prevY, count); - } - else if (!wndDataValid) { + } else { // No valid data available LOG_DEBUG(GwLog::LOG, "PageWindPlot: No valid data available"); getdisplay().setFont(&Ubuntu_Bold10pt7b); - getdisplay().fillRect(xCenter - 66, height / 2 - 18, 146, 24, commonData->bgcolor); // Clear area for TWS value - getdisplay().setCursor(xCenter - 66, height / 2); - getdisplay().print("No sensor data"); + getdisplay().fillRect(xCenter - 66, height / 2 - 20, 146, 24, commonData->bgcolor); // Clear area for TWS value + drawTextCenter(xCenter, height / 2 - 10, "No sensor data"); } // Print TWS value diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h index 65bdc67..e518221 100644 --- a/lib/obp60task/Pagedata.h +++ b/lib/obp60task/Pagedata.h @@ -4,15 +4,24 @@ #include #include #include "LedSpiTask.h" +#include "OBPRingBuffer.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{ String pageName; uint8_t pageNumber; // page number in sequence of visible pages //the values will always contain the user defined values first ValueList values; + tBoatHstryData 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 091c771..8d14c18 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -837,6 +837,11 @@ void OBP60Task(GwApi *api){ currentPage->displayNew(pages[pageNumber].parameters); lastPage=pageNumber; } + pages[pageNumber].parameters.boatHstry = shared->getHstryBuf(); // Add boat history to page parameters + LOG_DEBUG(GwLog::ERROR,"obp60task buffers: TWD:%d TWS:%f DBT:%f", pages[pageNumber].parameters.boatHstry.twdHstry->getLast(), + pages[pageNumber].parameters.boatHstry.twsHstry->getLast() * 0.0194384, pages[pageNumber].parameters.boatHstry.dbtHstry->getLast() / 100); +// LOG_DEBUG(GwLog::ERROR, "obp60task pointer: TWD: %p, TWS: %p, STW: %p", pages[pageNumber].parameters.boatHstry.twdHstry, +// pages[pageNumber].parameters.boatHstry.twsHstry, pages[pageNumber].parameters.boatHstry.dbtHstry); //call the page code LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber); // Show footer if enabled (together with header)