diff --git a/lib/obp60task/OBPDataOperations.h b/lib/obp60task/OBPDataOperations.h index 5ee604b..8422894 100644 --- a/lib/obp60task/OBPDataOperations.h +++ b/lib/obp60task/OBPDataOperations.h @@ -1,6 +1,5 @@ // Function lib for history buffer handling, true wind calculation, and other operations on boat data #pragma once -#include #include "OBPRingBuffer.h" #include "obp60task.h" @@ -17,8 +16,8 @@ private: 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) + RingBuffer awdHstry; // Circular buffer to store apparent wind direction values + RingBuffer awsHstry; // Circular buffer to store apparent xwind speed values (AWS) double twdHstryMin; // Min value for wind direction (TWD) in history buffer double twdHstryMax; // Max value for wind direction (TWD) in history buffer double twsHstryMin; diff --git a/lib/obp60task/OBPRingBuffer.h b/lib/obp60task/OBPRingBuffer.h index 15ad5c1..970245e 100644 --- a/lib/obp60task/OBPRingBuffer.h +++ b/lib/obp60task/OBPRingBuffer.h @@ -1,7 +1,8 @@ #pragma once -//#include "FreeRTOS.h" +#include "FreeRTOS.h" #include "GwSynchronized.h" #include +#include template struct PSRAMAllocator { diff --git a/lib/obp60task/OBPRingBuffer.tpp b/lib/obp60task/OBPRingBuffer.tpp index 281e89d..7d73f46 100644 --- a/lib/obp60task/OBPRingBuffer.tpp +++ b/lib/obp60task/OBPRingBuffer.tpp @@ -1,6 +1,7 @@ #include "OBPRingBuffer.h" #include #include +#include template void RingBuffer::initCommon() diff --git a/lib/obp60task/OBPcharts.cpp b/lib/obp60task/OBPcharts.cpp index 96954dc..be3fd43 100644 --- a/lib/obp60task/OBPcharts.cpp +++ b/lib/obp60task/OBPcharts.cpp @@ -17,7 +17,7 @@ Chart::Chart(RingBuffer& dataBuf, int8_t chrtDir, int8_t chrtSz, double df fgColor = commonData->fgcolor; bgColor = commonData->bgcolor; - LOG_DEBUG(GwLog::DEBUG, "Chart Init: dataBuf: %p", (void*)&dataBuf); + // LOG_DEBUG(GwLog::DEBUG, "Chart Init: Chart::dataBuf: %p, passed dataBuf: %p", (void*)&this->dataBuf, (void*)&dataBuf); dWidth = getdisplay().width(); dHeight = getdisplay().height(); @@ -104,8 +104,8 @@ Chart::~Chart() template void Chart::showChrt(int8_t chrtIntv, GwApi::BoatValue currValue) { - drawChrtTimeAxis(chrtIntv); drawChrt(chrtIntv, currValue); + drawChrtTimeAxis(chrtIntv); drawChrtValAxis(); } @@ -185,8 +185,8 @@ void Chart::drawChrt(int8_t chrtIntv, GwApi::BoatValue& currValue) } } - if (i >= (numBufVals / chrtIntv) - 4) // log chart data of 1 line (adjust for test purposes) - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %.4f, {x,y} {%d,%d}", i, chrtVal, x, y); + // if (i >= (numBufVals / chrtIntv) - 4) // log chart data of 1 line (adjust for test purposes) + // LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %.4f, {x,y} {%d,%d}", i, chrtVal, x, y); if ((i == 0) || (chrtPrevVal == dbMAX_VAL)) { // just a dot for 1st chart point or after some invalid values @@ -194,7 +194,6 @@ void Chart::drawChrt(int8_t chrtIntv, GwApi::BoatValue& currValue) prevY = y; } else if (chrtDataFmt != 0) { // cross borders check for degree values; shift values to [-PI..0..PI]; when crossing borders, range is 2x PI degrees - // Normalize both values relative to chrtMin (shift range to start at 0) double normCurr = WindUtils::to2PI(chrtVal - chrtMin); double normPrev = WindUtils::to2PI(chrtPrevVal - chrtMin); @@ -202,7 +201,7 @@ void Chart::drawChrt(int8_t chrtIntv, GwApi::BoatValue& currValue) bool crossedBorders = std::abs(normCurr - normPrev) > (chrtRng / 2.0); if (crossedBorders) { // If current value crosses chart borders compared to previous value, split line - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: crossedBorders: %d, chrtVal: %.2f, chrtPrevVal: %.2f", crossedBorders, chrtVal, chrtPrevVal); + // LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: crossedBorders: %d, chrtVal: %.2f, chrtPrevVal: %.2f", crossedBorders, chrtVal, chrtPrevVal); bool wrappingFromHighToLow = normCurr < normPrev; // Determine which edge we're crossing int xSplit = wrappingFromHighToLow ? (cStart.x + valAxis) : cStart.x; getdisplay().drawLine(prevX, prevY, xSplit, y, fgColor); @@ -215,11 +214,9 @@ void Chart::drawChrt(int8_t chrtIntv, GwApi::BoatValue& currValue) if (chrtDir == 0 || x == prevX) { // vertical line getdisplay().drawLine(prevX, prevY, x, y, fgColor); getdisplay().drawLine(prevX - 1, prevY, x - 1, y, fgColor); -// getdisplay().drawLine(prevX + 1, prevY, x - 1, y, fgColor); } else if (chrtDir == 1 || x != prevX) { // line with some horizontal trend -> normal state getdisplay().drawLine(prevX, prevY, x, y, fgColor); getdisplay().drawLine(prevX, prevY - 1, x, y - 1, fgColor); -// getdisplay().drawLine(prevX, prevY + 1, x, y - 1, fgColor); } chrtPrevVal = chrtVal; prevX = x; @@ -480,15 +477,15 @@ void Chart::drawChrtValAxis() intv = static_cast(round(cchrtRng / slots)); i = intv; - getdisplay().setFont(&Ubuntu_Bold10pt8b); + getdisplay().setFont(&Ubuntu_Bold12pt8b); for (int j = 60; j < valAxis - 30; j += 60) { LOG_DEBUG(GwLog::DEBUG, "ChartValAxis: chrtRng: %.2f, cchrtRng: %.2f, intv: %d, slots: %.1f, valAxis: %d, i: %d, j: %d", chrtRng, cchrtRng, intv, slots, valAxis, i, j); getdisplay().drawLine(cStart.x, cStart.y + j, cStart.x + timAxis, cStart.y + j, fgColor); - getdisplay().fillRect(cStart.x, cStart.y + j - 9, cStart.x + 32, 18, bgColor); // Clear small area to remove potential chart lines + getdisplay().fillRect(cStart.x, cStart.y + j - 11, cStart.x + 39, 21, bgColor); // Clear small area to remove potential chart lines String sVal = String(i); - getdisplay().setCursor((3 - sVal.length()) * 8, cStart.y + j + 6); // value right-formated + getdisplay().setCursor((3 - sVal.length()) * 10, cStart.y + j + 7); // value right-formated getdisplay().printf("%s", sVal); // Range value i += intv; @@ -498,9 +495,14 @@ void Chart::drawChrtValAxis() drawTextRalign(cStart.x + timAxis, cStart.y - 3, dbName); // buffer data name } else { // chrtDir == 1; vertical chart - getdisplay().setFont(&Ubuntu_Bold10pt8b); - + if (chrtSz == 0) { // full size chart -> use larger font + getdisplay().setFont(&Ubuntu_Bold12pt8b); + drawTextCenter(cStart.x + (valAxis / 4) + 25, cStart.y - 10, dbName); // buffer data name + } else { + getdisplay().setFont(&Ubuntu_Bold10pt8b); + } getdisplay().fillRect(cStart.x, top, valAxis, 2, fgColor); // top chart line + getdisplay().setCursor(cStart.x, cStart.y - 2); tmpBVal->value = chrtMin; cVal = formatValue(tmpBVal.get(), *commonData).cvalue; // value (converted) @@ -515,16 +517,16 @@ void Chart::drawChrtValAxis() tmpBVal->value = chrtMax; cVal = formatValue(tmpBVal.get(), *commonData).cvalue; // value (converted) snprintf(sVal, sizeof(sVal), "%.0f", round(cVal)); - drawTextRalign(cStart.x + valAxis - 1, cStart.y - 2, sVal); // Range high end + drawTextRalign(cStart.x + valAxis - 2, cStart.y - 2, sVal); // Range high end for (int j = 0; j <= valAxis + 2; j += ((valAxis + 2) / 2)) { getdisplay().drawLine(cStart.x + j, cStart.y, cStart.x + j, cStart.y + timAxis, fgColor); } - if (chrtSz == 0) { - getdisplay().setFont(&Ubuntu_Bold12pt8b); - drawTextCenter(cStart.x + (valAxis / 4) + 5, cStart.y - 11, dbName); // buffer data name - } +// if (chrtSz == 0) { +// getdisplay().setFont(&Ubuntu_Bold12pt8b); +// drawTextCenter(cStart.x + (valAxis / 4) + 15, cStart.y - 11, dbName); // buffer data name +// } LOG_DEBUG(GwLog::DEBUG, "ChartGrd: chrtRng: %.2f, intv: %d, slots: %.1f, valAxis: %d, i: %d", chrtRng, intv, slots, valAxis, i); } } @@ -547,7 +549,7 @@ void Chart::prntCurrValue(GwApi::BoatValue& currValue, const Pos chrtPos) LOG_DEBUG(GwLog::DEBUG, "Chart CurrValue: dbValue: %.2f, sdbValue: %s, fmrtDbValue: %.2f, dbFormat: %s, dbUnit: %s, Valid: %d, Name: %s, Address: %p", currValue.value, sdbValue, testdbValue, currValue.getFormat(), dbUnit, currValue.valid, currValue.getName(), currValue); - getdisplay().fillRect(xPosVal, yPosVal - 34, 121, 40, bgColor); // Clear area for TWS value + getdisplay().fillRect(xPosVal, yPosVal - 34, 122, 40, bgColor); // Clear area for TWS value getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b); getdisplay().setCursor(xPosVal + 1, yPosVal); if (useSimuData) { diff --git a/lib/obp60task/OBPcharts.h b/lib/obp60task/OBPcharts.h index c33f52e..581ab85 100644 --- a/lib/obp60task/OBPcharts.h +++ b/lib/obp60task/OBPcharts.h @@ -1,4 +1,4 @@ -// Function lib for display of boat data in various chart formats +// Function lib for display of boat data in various graphical chart formats #pragma once #include "Pagedata.h" diff --git a/lib/obp60task/PageWindPlot.cpp b/lib/obp60task/PageWindPlot.cpp index 4c5216c..b9fbc67 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -15,7 +15,7 @@ private: 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 showTruW = true; // Show true wind or apparent wind in chart area bool oldShowTruW = false; // remember recent user selection of wind data type int dataIntv = 1; // Update interval for wind history chart: @@ -102,16 +102,15 @@ public: virtual void displayNew(PageData& pageData) { #ifdef BOARD_OBP40S3 - String wndSrc; // Wind source true/apparant wind - preselection for OBP40 + String wndSrc; // Wind source true/apparent wind - preselection for OBP40 wndSrc = commonData->config->getString("page" + String(pageData.pageNumber) + "wndsrc"); if (wndSrc == "True wind") { showTruW = true; } else { - showTruW = false; // Wind source is apparant wind + showTruW = false; // Wind source is apparent wind } LOG_DEBUG(GwLog::LOG, "New PageWindPlot; wind source=%s", wndSrc); - // commonData->logger->logDebug(GwLog::LOG, "New PageWindPlot: wind source=%s", wndSrc); #endif oldShowTruW = !showTruW; // makes wind source being initialized at initial page call @@ -127,10 +126,18 @@ public: 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 std::unique_ptr> twdFlChart; // chart object for wind direction chart, full size - static std::unique_ptr> twsFlChart; // chart object for wind speed chart, full size - static std::unique_ptr> twdHfChart; // chart object for wind direction chart, half size - static std::unique_ptr> twsHfChart; // chart object for wind speed chart, half size + + // Separate chart objects for true wind and apparent wind + static std::unique_ptr> twdFlChart, awdFlChart; // chart object for wind direction chart, full size + static std::unique_ptr> twsFlChart, awsFlChart; // chart object for wind speed chart, full size + static std::unique_ptr> twdHfChart, awdHfChart; // chart object for wind direction chart, half size + static std::unique_ptr> twsHfChart, awsHfChart; // chart object for wind speed chart, half size + // Pointers to the currently active charts + static Chart* wdFlChart; + static Chart* wsFlChart; + static Chart* wdHfChart; + static Chart* wsHfChart; + static GwApi::BoatValue* wdBVal = new GwApi::BoatValue("TWD"); // temp BoatValue for wind direction unit identification; required by OBP60Formater static GwApi::BoatValue* wsBVal = new GwApi::BoatValue("TWS"); // temp BoatValue for wind speed unit identification; required by OBP60Formater */ double dfltRngWd = 60.0 * DEG_TO_RAD; // default range for course chart from min to max value in RAD @@ -154,22 +161,52 @@ public: } if (showTruW != oldShowTruW) { + if (!twdFlChart) { // Create true wind charts if they don't exist + + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Creating true wind charts"); + auto* twdHstry = pageData.boatHstry->hstryBufList.twdHstry; + auto* twsHstry = pageData.boatHstry->hstryBufList.twsHstry; + // LOG_DEBUG(GwLog::DEBUG,"History Buffer addresses PageWindPlot: twdBuf: %p, twsBuf: %p", (void*)pageData.boatHstry->hstryBufList.twdHstry, + // (void*)pageData.boatHstry->hstryBufList.twsHstry); + + twdFlChart = std::unique_ptr>(new Chart(*twdHstry, 1, 0, dfltRngWd, *commonData, useSimuData)); + twsFlChart = std::unique_ptr>(new Chart(*twsHstry, 0, 0, dfltRngWs, *commonData, useSimuData)); + twdHfChart = std::unique_ptr>(new Chart(*twdHstry, 1, 1, dfltRngWd, *commonData, useSimuData)); + twsHfChart = std::unique_ptr>(new Chart(*twsHstry, 1, 2, dfltRngWs, *commonData, useSimuData)); + // LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: twdHstry: %p, twsHstry: %p", (void*)twdHstry, (void*)twsHstry); + } + + if (!awdFlChart) { // Create apparent wind charts if they don't exist + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Creating apparent wind charts"); + auto* awdHstry = pageData.boatHstry->hstryBufList.awdHstry; + auto* awsHstry = pageData.boatHstry->hstryBufList.awsHstry; + + awdFlChart = std::unique_ptr>(new Chart(*awdHstry, 1, 0, dfltRngWd, *commonData, useSimuData)); + awsFlChart = std::unique_ptr>(new Chart(*awsHstry, 0, 0, dfltRngWs, *commonData, useSimuData)); + awdHfChart = std::unique_ptr>(new Chart(*awdHstry, 1, 1, dfltRngWd, *commonData, useSimuData)); + awsHfChart = std::unique_ptr>(new Chart(*awsHstry, 1, 2, dfltRngWs, *commonData, useSimuData)); + } + + // Switch active charts based on showTruW if (showTruW) { wdHstry = pageData.boatHstry->hstryBufList.twdHstry; wsHstry = pageData.boatHstry->hstryBufList.twsHstry; + wdFlChart = twdFlChart.get(); + wsFlChart = twsFlChart.get(); + wdHfChart = twdHfChart.get(); + wsHfChart = twsHfChart.get(); } else { wdHstry = pageData.boatHstry->hstryBufList.awdHstry; wsHstry = pageData.boatHstry->hstryBufList.awsHstry; + wdFlChart = awdFlChart.get(); + wsFlChart = awsFlChart.get(); + wdHfChart = awdHfChart.get(); + wsHfChart = awsHfChart.get(); } + wdHstry->getMetaData(wdName, wdFormat); wsHstry->getMetaData(wsName, wsFormat); - - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: *wdHstry: %p, *wsHstry: %p", wdHstry, wsHstry); - twdFlChart = std::unique_ptr>(new Chart(*wdHstry, 1, 0, dfltRngWd, *commonData, useSimuData)); - twsFlChart = std::unique_ptr>(new Chart(*wsHstry, 0, 0, dfltRngWs, *commonData, useSimuData)); - twdHfChart = std::unique_ptr>(new Chart(*wdHstry, 1, 1, dfltRngWd, *commonData, useSimuData)); - twsHfChart = std::unique_ptr>(new Chart(*wsHstry, 1, 2, dfltRngWs, *commonData, useSimuData)); - + oldShowTruW = showTruW; } @@ -183,12 +220,12 @@ public: if (chrtMode == 'D') { wdBVal->value = wdHstry->getLast(); wdBVal->valid = wdBVal->value != wdHstry->getMaxVal(); - twdFlChart->showChrt(dataIntv, *bvalue[0]); + wdFlChart->showChrt(dataIntv, *bvalue[0]); } else if (chrtMode == 'S') { wsBVal->value = wsHstry->getLast(); wsBVal->valid = wsBVal->value != wsHstry->getMaxVal(); - twsFlChart->showChrt(dataIntv, *bvalue[1]); + wsFlChart->showChrt(dataIntv, *bvalue[1]); } else if (chrtMode == 'B') { wdBVal->value = wdHstry->getLast(); @@ -197,11 +234,11 @@ public: wsBVal->valid = wsBVal->value != wsHstry->getMaxVal(); LOG_DEBUG(GwLog::DEBUG, "PageWindPlot showChrt: wsBVal.name: %s, format: %s, wsBVal.value: %.1f, valid: %d, address: %p", wsBVal->getName(), wsBVal->getFormat(), wsBVal->value, wsBVal->valid, wsBVal); - twdHfChart->showChrt(dataIntv, *bvalue[0]); - twsHfChart->showChrt(dataIntv, *bvalue[1]); + wdHfChart->showChrt(dataIntv, *bvalue[0]); + wsHfChart->showChrt(dataIntv, *bvalue[1]); } - LOG_DEBUG(GwLog::LOG, "PageWindPlot: runtime: %ldms", millis() - pageTime); + LOG_DEBUG(GwLog::LOG, "PageWindPlot: page time %ldms", millis() - pageTime); return PAGE_UPDATE; } }; diff --git a/lib/obp60task/gen_set.py b/lib/obp60task/gen_set.py index 9d1b0ff..97ca0cf 100755 --- a/lib/obp60task/gen_set.py +++ b/lib/obp60task/gen_set.py @@ -157,7 +157,7 @@ def create_json(device, no_of_pages, pagedata): "description": f"Wind source for page {page_no}: [true|apparent]", "list": [ "True wind", - "Apparant wind" + "Apparent wind" ], "category": category, "capabilities": capabilities,