diff --git a/lib/obp60task/OBPDataOperations.h b/lib/obp60task/OBPDataOperations.h index c93c1fe..b819e15 100644 --- a/lib/obp60task/OBPDataOperations.h +++ b/lib/obp60task/OBPDataOperations.h @@ -1,3 +1,4 @@ +// Function lib for history buffer handling, true wind calculation, and other operations on boat data #pragma once #include #include "OBPRingBuffer.h" diff --git a/lib/obp60task/OBPcharts.cpp b/lib/obp60task/OBPcharts.cpp new file mode 100644 index 0000000..44c782e --- /dev/null +++ b/lib/obp60task/OBPcharts.cpp @@ -0,0 +1,75 @@ +// Function lib for display of boat data in various chart formats +#include "OBPcharts.h" + +// --- Class Chart --------------- +void Chart::drawChrtHdr() { + // chart header label + lines + int i; + getdisplay().fillRect(0, top, cWidth, 2, commonData->fgcolor); + + // horizontal chart labels + getdisplay().drawLine(cStart.x, cStart.y, cWidth, cStart.y); + getdisplay().fillRect(cStart.x, cStart.y, cWidth, 2, commonData->fgcolor); + + getdisplay().setFont(&Ubuntu_Bold10pt8b); + getdisplay().setCursor(cStart.x, cStart.y + 12); + getdisplay().print(dbName); // Wind data name + + getdisplay().setFont(&Ubuntu_Bold12pt8b); + if (chrtSze == 0) { + i = -1 * (chrtIntv / 8 - 2); + } else { + i = -1 * (chrtIntv / 4 - 2); + } + for (int j = 50; j <= (cWidth - 50); j += 50 ) { + getdisplay().setCursor(cStart.x + j - 16, cStart.y + 12); + getdisplay().print(i++); // time interval + // i++; + getdisplay().drawLine(cStart.x + j - 30, cStart.y, cStart.x - 30, cHeight + top); + } +} + +void Chart::drawChrtGrd(const int chrtRng) { + // chart Y axis labels + lines + int i; + + getdisplay().setFont(&Ubuntu_Bold8pt8b); + if (chrtDir == 0) { + i = -1 * (chrtRng / 4 - 2); + for (int j = cStart.x; j <= (cHeight - (cHeight / 4)); j += cHeight / 4 ) { + getdisplay().drawLine(0, cStart.y, cWidth, cStart.y); + getdisplay().setCursor(0, cStart.y + 12); + if (i < 10) + getdisplay().printf("!!%1d", i); // Range value + else if (i < 100) + getdisplay().printf("!%2d", i); // Range value + else + getdisplay().printf("%3d", i); // Range value + i += (chrtRng / 4); + } + } else { + i = -1 * (chrtRng / 8 - 2); + for (int j = cStart.x; j <= (cHeight - (cHeight / 8)); j += cHeight / 8 ) { + getdisplay().drawLine(cStart.x + j - 30, cStart.y, cStart.x - 30, cHeight + top); + getdisplay().setCursor(0, cStart.y + 12); + if (i < 10) + getdisplay().printf("!!%1d", i); // Range value + else if (i < 100) + getdisplay().printf("!%2d", i); // Range value + else + getdisplay().printf("%3d", i); // Range value + i += (chrtRng / 4); + } + } +} + +bool Chart::drawChrt(int8_t chrtIntv, int dfltRng) { +// hstryBuf = buffer to display +// bValue = present value to display additionally to chart +// chrtDir = chart direction: [0] = vertical, [1] = horizontal +// chrtSze = chart size: [0] = full size, [1] = half size left half/top, [2] half size right half/bottom +// chrtIntv = chart time interval: [1] 4 min., [2] 8 min., [3] 12 min., [4] 16 min., [5] 32 min. +// dfltRng = default range of chart, e.g. 30 = [0..30] + +} +// --- Class Chart --------------- diff --git a/lib/obp60task/OBPcharts.h b/lib/obp60task/OBPcharts.h new file mode 100644 index 0000000..813c2da --- /dev/null +++ b/lib/obp60task/OBPcharts.h @@ -0,0 +1,103 @@ +// Function lib for display of boat data in various chart formats +#pragma once +#include "OBP60Extensions.h" +#include "Pagedata.h" +// #include "OBPDataOperations.h" +// #include "OBPRingBuffer.h" + +struct Point { + int x; + int y; +}; + +class Chart { +protected: + RingBuffer* dataBuf; // Buffer to display + GwApi::BoatValue* bValue; // Present value to display additionally to chart + int8_t chrtDir; // Chart direction: [0] = vertical, [1] = horizontal + int8_t chrtSze; // Chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom + int8_t chrtIntv; // Chart time interval: [4] 4 min., [8] 8 min., [12] 12 min., [16] 16 min., [32] 32 min. + int dfltRng; // Default range of chart, e.g. 30 = [0..30] + + int top = 48; // display top header lines + int bottom = 22; // display bottom lines + int gap = 4; // gap between 2 charts; actual gap is 2x + int cWidth; + int cHeight; + Point cStart; // start point for chart area + int cLines; // number of chart lines + int xCenter; // x center point of chart + + String dbName, dbFormat; + int16_t dbMAX_VAL; + size_t bufSize; + GwApi::BoatValue* bValue; + +public: + Chart(RingBuffer* dataBuf, GwApi::BoatValue* bValue, int8_t chrtDir, int8_t chrtSz, int8_t chrtIntv, int dfltRng, GwLog* logger) + : dataBuf(dataBuf) + , bValue(bValue) + , chrtDir(chrtDir) + , chrtSze(chrtSze) + , chrtIntv(chrtIntv) + , dfltRng(dfltRng) + { + cWidth = getdisplay().width(); + cHeight = getdisplay().height(); + cHeight = cHeight - top - bottom; + if (chrtDir == 0) { + // vertical chart + switch (chrtSze) { + case 0: + // default is already set + break; + case 1: + cWidth = cWidth; + cHeight = cHeight / 2 - gap; + cStart = { 30, cHeight + top }; + break; + case 2: + cWidth = cWidth; + cHeight = cHeight / 2 - gap; + cStart = { cWidth + gap, top }; + break; + default: + LOG_DEBUG(GwLog::DEBUG, "displayChart: wrong parameter"); + return; + } + } else if (chrtDir == 1) { + // horizontal chart + switch (chrtSze) { + case 0: + cStart = { 0, cHeight - bottom }; + break; + case 1: + cWidth = cWidth / 2 - gap; + cHeight = cHeight; + cStart = { 0, cHeight - bottom }; + break; + case 2: + cWidth = cWidth / 2 - gap; + cHeight = cHeight; + cStart = { cWidth + gap, cHeight - bottom }; + break; + default: + LOG_DEBUG(GwLog::DEBUG, "displayChart: wrong parameter"); + return; + } + } else { + LOG_DEBUG(GwLog::DEBUG, "displayChart: wrong parameter"); + return; + } + xCenter = cWidth / 2; + cLines = cHeight - 22; + + dataBuf->getMetaData(dbName, dbFormat); + dbMAX_VAL = dataBuf->getMaxVal(); + bufSize = dataBuf->getCapacity(); + bValue->setFormat(dataBuf->getFormat()); + }; + void drawChrtHdr(); + void drawChrtGrd(const int chrtRng); + bool drawChrt(int8_t chrtIntv, int dfltRng); +}; \ No newline at end of file diff --git a/lib/obp60task/PageWindPlot.cpp b/lib/obp60task/PageWindPlot.cpp index 4bc79f7..b3f55ea 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -1,10 +1,11 @@ #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 -#include "Pagedata.h" -#include "OBP60Extensions.h" -#include "OBPRingBuffer.h" -#include "OBPDataOperations.h" #include "BoatDataCalibration.h" +#include "OBP60Extensions.h" +#include "OBPDataOperations.h" +#include "OBPRingBuffer.h" +#include "OBPcharts.h" +#include "Pagedata.h" #include static const double radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees @@ -59,7 +60,7 @@ int getRng(const RingBuffer& windDirHstry, int center, size_t amount) value = windDirHstry.get(count - 1 - i); if (value == MAX_VAL) { - continue; // ignore invalid values + continue; // ignore invalid values } value = value / 1000.0 * radToDeg; @@ -99,13 +100,12 @@ public: // holdValues = common.config->getBool(common.config->holdvalues); flashLED = common.config->getString(common.config->flashLED); backlightMode = common.config->getString(common.config->backlight); - } virtual void setupKeys() { Page::setupKeys(); - // commonData->keydata[0].label = "MODE"; + commonData->keydata[0].label = "MODE"; #if defined BOARD_OBP60S3 commonData->keydata[1].label = "SRC"; commonData->keydata[4].label = "INTV"; @@ -161,17 +161,18 @@ public: return key; } - virtual void displayNew(PageData &pageData){ + virtual void displayNew(PageData& pageData) + { #ifdef BOARD_OBP40S3 String wndSrc; // Wind source true/apparant wind - preselection for OBP40 wndSrc = commonData->config->getString("page" + String(pageData.pageNumber) + "wndsrc"); - if (wndSrc =="True wind") { + if (wndSrc == "True wind") { showTruW = true; } else { showTruW = false; // Wind source is apparant wind } - commonData->logger->logDebug(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 } @@ -280,225 +281,234 @@ public: oldShowTruW = showTruW; } - // Identify buffer size and buffer start position for chart - count = wdHstry->getCurrentSize(); - currIdx = wdHstry->getLastIdx(); - numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display - if (dataIntv != oldDataIntv || count == 1) { - // new data interval selected by user - intvBufSize = cHeight * dataIntv; - numWndVals = min(count, (cHeight - 60) * dataIntv); - bufStart = max(0, count - numWndVals); - lastAddedIdx = currIdx; - oldDataIntv = dataIntv; - } else { - numWndVals = numWndVals + numAddedBufVals; - lastAddedIdx = currIdx; - if (count == bufSize) { - bufStart = max(0, bufStart - numAddedBufVals); + if (chrtMode == 'D') { + // Identify buffer size and buffer start position for chart + count = wdHstry->getCurrentSize(); + currIdx = wdHstry->getLastIdx(); + numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display + if (dataIntv != oldDataIntv || count == 1) { + // new data interval selected by user + intvBufSize = cHeight * dataIntv; + numWndVals = min(count, (cHeight - 60) * dataIntv); + bufStart = max(0, count - numWndVals); + lastAddedIdx = currIdx; + oldDataIntv = dataIntv; + } else { + numWndVals = numWndVals + numAddedBufVals; + lastAddedIdx = currIdx; + if (count == bufSize) { + bufStart = max(0, bufStart - numAddedBufVals); + } } - } - 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"); + 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_MAX || (wndCenter == 0 && count == 1)) { - wndCenter = getCntr(*wdHstry, numWndVals); - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, xWD: %.1f, 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); - } else { - // check and adjust range between left, center, and right chart limit - diffRng = getRng(*wdHstry, wndCenter, numWndVals); - diffRng = (diffRng == wdMAX_VAL ? 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); - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range adjust: wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", wndCenter, diffRng, chrtRng, - wdHstry->getMin(numWndVals) / 1000.0 * radToDeg, wdHstry->getMax(numWndVals) / 1000.0 * radToDeg); + // Set wndCenter from 1st real buffer value + if (wndCenter == INT_MAX || (wndCenter == 0 && count == 1)) { + wndCenter = getCntr(*wdHstry, numWndVals); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, xWD: %.1f, 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); + } else { + // check and adjust range between left, center, and right chart limit + diffRng = getRng(*wdHstry, wndCenter, numWndVals); + diffRng = (diffRng == wdMAX_VAL ? 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); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Range adjust: wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", wndCenter, diffRng, chrtRng, + wdHstry->getMin(numWndVals) / 1000.0 * radToDeg, wdHstry->getMax(numWndVals) / 1000.0 * radToDeg); + } } - } - chrtScl = float(width) / float(chrtRng) / 2.0; // Chart scale: pixels per degree - wndLeft = wndCenter - chrtRng; - if (wndLeft < 0) - wndLeft += 360; - wndRight = (chrtRng < 180 ? wndCenter + chrtRng : wndCenter + chrtRng - 1); - if (wndRight >= 360) - wndRight -= 360; + chrtScl = float(width) / float(chrtRng) / 2.0; // Chart scale: pixels per degree + wndLeft = wndCenter - chrtRng; + if (wndLeft < 0) + wndLeft += 360; + wndRight = (chrtRng < 180 ? wndCenter + chrtRng : wndCenter + chrtRng - 1); + if (wndRight >= 360) + wndRight -= 360; - // Draw page - //*********************************************************************** + // Draw page + //*********************************************************************** - // Set display in partial refresh mode - getdisplay().setPartialWindow(0, 0, width, height); // Set partial update - getdisplay().setTextColor(commonData->fgcolor); + // Set display in partial refresh mode + getdisplay().setPartialWindow(0, 0, width, height); // Set partial update + getdisplay().setTextColor(commonData->fgcolor); - // chart lines - getdisplay().fillRect(0, yOffset, width, 2, commonData->fgcolor); - getdisplay().fillRect(xCenter, yOffset, 1, cHeight, commonData->fgcolor); + // chart lines + getdisplay().fillRect(0, yOffset, width, 2, commonData->fgcolor); + getdisplay().fillRect(xCenter, yOffset, 1, cHeight, commonData->fgcolor); - // chart labels - char sWndLbl[4]; // char buffer for Wind angle label - getdisplay().setFont(&Ubuntu_Bold12pt8b); - getdisplay().setCursor(xCenter - 88, yOffset - 3); - getdisplay().print(wdName); // Wind data name - snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter); - drawTextCenter(xCenter, yOffset - 11, sWndLbl); - 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); - snprintf(sWndLbl, 4, "%03d", (wndLeft < 0) ? (wndLeft + 360) : wndLeft); - getdisplay().print(sWndLbl); // Wind left value - getdisplay().drawCircle(46, yOffset - 17, 2, commonData->fgcolor); // symbol - getdisplay().drawCircle(46, yOffset - 17, 3, commonData->fgcolor); // symbol - getdisplay().setCursor(width - 50, yOffset - 3); - snprintf(sWndLbl, 4, "%03d", (wndRight < 0) ? (wndRight + 360) : wndRight); - getdisplay().print(sWndLbl); // Wind right value - getdisplay().drawCircle(width - 5, yOffset - 17, 2, commonData->fgcolor); // symbol - getdisplay().drawCircle(width - 5, yOffset - 17, 3, commonData->fgcolor); // symbol + // chart labels + char sWndLbl[4]; // char buffer for Wind angle label + getdisplay().setFont(&Ubuntu_Bold12pt8b); + getdisplay().setCursor(xCenter - 88, yOffset - 3); + getdisplay().print(wdName); // Wind data name + snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter); + drawTextCenter(xCenter, yOffset - 11, sWndLbl); + 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); + snprintf(sWndLbl, 4, "%03d", (wndLeft < 0) ? (wndLeft + 360) : wndLeft); + getdisplay().print(sWndLbl); // Wind left value + getdisplay().drawCircle(46, yOffset - 17, 2, commonData->fgcolor); // symbol + getdisplay().drawCircle(46, yOffset - 17, 3, commonData->fgcolor); // symbol + getdisplay().setCursor(width - 50, yOffset - 3); + snprintf(sWndLbl, 4, "%03d", (wndRight < 0) ? (wndRight + 360) : wndRight); + getdisplay().print(sWndLbl); // Wind right value + getdisplay().drawCircle(width - 5, yOffset - 17, 2, commonData->fgcolor); // symbol + getdisplay().drawCircle(width - 5, yOffset - 17, 3, commonData->fgcolor); // symbol - if (wdHstry->getMax() == wdMAX_VAL) { - // only values in buffer -> no valid wind data available - wndDataValid = false; - } else if (!BDataValid[0] && !useSimuData) { - // currently no valid xWD data available and no simulation mode - numNoData++; - wndDataValid = true; - if (numNoData > 3) { - // If more than 4 invalid values in a row, send message + if (wdHstry->getMax() == wdMAX_VAL) { + // only values in buffer -> no valid wind data available wndDataValid = false; + } else if (!BDataValid[0] && !useSimuData) { + // currently no valid xWD data available and no simulation mode + numNoData++; + wndDataValid = true; + if (numNoData > 3) { + // If more than 4 invalid values in a row, send message + wndDataValid = false; + } + } else { + numNoData = 0; // reset data error counter + wndDataValid = true; // At least some wind data available } - } else { - numNoData = 0; // reset data error counter - wndDataValid = true; // At least some wind data available - } - // Draw wind values in chart - //*********************************************************************** - if (wndDataValid) { - for (int i = 0; i < (numWndVals / dataIntv); i++) { - chrtVal = static_cast(wdHstry->get(bufStart + (i * dataIntv))); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer - if (chrtVal == wdMAX_VAL) { - chrtPrevVal = wdMAX_VAL; - } else { - 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 + // Draw wind values in chart + //*********************************************************************** + if (wndDataValid) { + for (int i = 0; i < (numWndVals / dataIntv); i++) { + chrtVal = static_cast(wdHstry->get(bufStart + (i * dataIntv))); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer + if (chrtVal == wdMAX_VAL) { + chrtPrevVal = wdMAX_VAL; + } else { + 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) - 1) // log chart data of 1 line (adjust for test purposes) - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %d, bufStart: %d, count: %d, linesToShow: %d", i, chrtVal, bufStart, count, (numWndVals / dataIntv)); + if (i >= (numWndVals / dataIntv) - 1) // log chart data of 1 line (adjust for test purposes) + 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 == wdMAX_VAL)) { - // just a dot for 1st chart point or after some invalid values + if ((i == 0) || (chrtPrevVal == wdMAX_VAL)) { + // just a dot for 1st chart point or after some invalid values + prevX = x; + prevY = y; + } else { + // cross borders check; shift values to [-180..0..180]; when crossing borders, range is 2x 180 degrees + int wndLeftDlt = -180 - ((wndLeft >= 180) ? (wndLeft - 360) : wndLeft); + int chrtVal180 = ((chrtVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180; + int chrtPrevVal180 = ((chrtPrevVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180; + if (((chrtPrevVal180 >= -180) && (chrtPrevVal180 < -90) && (chrtVal180 > 90)) || ((chrtPrevVal180 <= 179) && (chrtPrevVal180 > 90) && chrtVal180 <= -90)) { + // If current value crosses chart borders compared to previous value, split line + int xSplit = (((chrtPrevVal180 > 0 ? wndRight : wndLeft) - wndLeft + 360) % 360) * chrtScl; + 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; + } + } + + // Draw line with 2 pixels width + make sure vertical line are drawn correctly + getdisplay().drawLine(prevX, prevY, x, y, commonData->fgcolor); + getdisplay().drawLine(prevX, prevY - 1, ((x != prevX) ? x : x - 1), ((x != prevX) ? y - 1 : y), commonData->fgcolor); + chrtPrevVal = chrtVal; prevX = x; prevY = y; - } else { - // cross borders check; shift values to [-180..0..180]; when crossing borders, range is 2x 180 degrees - int wndLeftDlt = -180 - ((wndLeft >= 180) ? (wndLeft - 360) : wndLeft); - int chrtVal180 = ((chrtVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180; - int chrtPrevVal180 = ((chrtPrevVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180; - if (((chrtPrevVal180 >= -180) && (chrtPrevVal180 < -90) && (chrtVal180 > 90)) || ((chrtPrevVal180 <= 179) && (chrtPrevVal180 > 90) && chrtVal180 <= -90)) { - // If current value crosses chart borders compared to previous value, split line - int xSplit = (((chrtPrevVal180 > 0 ? wndRight : wndLeft) - wndLeft + 360) % 360) * chrtScl; - 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; + } + // Reaching chart area top end + if (i >= (cHeight - 1)) { + oldDataIntv = 0; // force reset of buffer start and number of values to show in next display loop + + int minWndDir = wdHstry->getMin(numWndVals) / 1000.0 * radToDeg; + int maxWndDir = wdHstry->getMax(numWndVals) / 1000.0 * radToDeg; + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter); + // if (((minWndDir - wndCenter >= 0) && (minWndDir - wndCenter < 180)) || ((maxWndDir - wndCenter <= 0) && (maxWndDir - wndCenter >=180))) { + if ((wndRight > wndCenter && (minWndDir >= wndCenter && minWndDir <= wndRight)) || (wndRight <= wndCenter && (minWndDir >= wndCenter || minWndDir <= wndRight)) || (wndLeft < wndCenter && (maxWndDir <= wndCenter && maxWndDir >= wndLeft)) || (wndLeft >= wndCenter && (maxWndDir <= wndCenter || maxWndDir >= wndLeft))) { + // Check if all wind value are left or right of center value -> optimize chart center + wndCenter = getCntr(*wdHstry, numWndVals); } + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter); + break; } - - // Draw line with 2 pixels width + make sure vertical line are drawn correctly - getdisplay().drawLine(prevX, prevY, x, y, commonData->fgcolor); - getdisplay().drawLine(prevX, prevY - 1, ((x != prevX) ? x : x - 1), ((x != prevX) ? y - 1 : y), commonData->fgcolor); - chrtPrevVal = chrtVal; - prevX = x; - prevY = y; } - // Reaching chart area top end - if (i >= (cHeight - 1)) { - oldDataIntv = 0; // force reset of buffer start and number of values to show in next display loop - int minWndDir = wdHstry->getMin(numWndVals) / 1000.0 * radToDeg; - int maxWndDir = wdHstry->getMax(numWndVals) / 1000.0 * radToDeg; - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter); - // if (((minWndDir - wndCenter >= 0) && (minWndDir - wndCenter < 180)) || ((maxWndDir - wndCenter <= 0) && (maxWndDir - wndCenter >=180))) { - if ((wndRight > wndCenter && (minWndDir >= wndCenter && minWndDir <= wndRight)) || (wndRight <= wndCenter && (minWndDir >= wndCenter || minWndDir <= wndRight)) || (wndLeft < wndCenter && (maxWndDir <= wndCenter && maxWndDir >= wndLeft)) || (wndLeft >= wndCenter && (maxWndDir <= wndCenter || maxWndDir >= wndLeft))) { - // Check if all wind value are left or right of center value -> optimize chart center - wndCenter = getCntr(*wdHstry, numWndVals); + // Print wind speed value + int currentZone; + static int lastZone = 0; + static bool flipTws = false; + int xPosTws; + static const int yPosTws = yOffset + 40; + + xPosTws = flipTws ? 20 : width - 145; + currentZone = (y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146) ? 1 : 0; // Define current zone for TWS value + if (currentZone != lastZone) { + // Only flip when x moves to a different zone + if ((y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146)) { + flipTws = !flipTws; + xPosTws = flipTws ? 20 : width - 145; } - LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter); - break; } - } + lastZone = currentZone; - // Print wind speed value - int currentZone; - static int lastZone = 0; - static bool flipTws = false; - int xPosTws; - static const int yPosTws = yOffset + 40; + wsValue = wsHstry->getLast(); + 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); + getdisplay().print(swsValue); // Value + /* if (!wsBVal->valid) { + getdisplay().print("--.-"); + } else { + 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 + getdisplay().setFont(&Ubuntu_Bold8pt8b); + getdisplay().setCursor(xPosTws + 82, yPosTws + 1); + getdisplay().print(wsUnit); // Unit - xPosTws = flipTws ? 20 : width - 145; - currentZone = (y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146) ? 1 : 0; // Define current zone for TWS value - if (currentZone != lastZone) { - // Only flip when x moves to a different zone - if ((y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146)) { - flipTws = !flipTws; - xPosTws = flipTws ? 20 : width - 145; - } - } - lastZone = currentZone; - - wsValue = wsHstry->getLast(); - 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); - getdisplay().print(swsValue); // Value -/* if (!wsBVal->valid) { - getdisplay().print("--.-"); } else { - 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 + // No valid data available + LOG_DEBUG(GwLog::LOG, "PageWindPlot: No valid data available"); + getdisplay().setFont(&Ubuntu_Bold10pt8b); + getdisplay().fillRect(xCenter - 33, height / 2 - 20, 66, 24, commonData->bgcolor); // Clear area for message + drawTextCenter(xCenter, height / 2 - 10, "No data"); + } + + // chart Y axis labels; print at last to overwrite potential chart lines in label area + int yPos; + int chrtLbl; getdisplay().setFont(&Ubuntu_Bold8pt8b); - getdisplay().setCursor(xPosTws + 82, yPosTws + 1); - getdisplay().print(wsUnit); // Unit - - } else { - // No valid data available - LOG_DEBUG(GwLog::LOG, "PageWindPlot: No valid data available"); - getdisplay().setFont(&Ubuntu_Bold10pt8b); - getdisplay().fillRect(xCenter - 33, height / 2 - 20, 66, 24, commonData->bgcolor); // Clear area for message - drawTextCenter(xCenter, height / 2 - 10, "No data"); - } - - // chart Y axis labels; print at last to overwrite potential chart lines in label area - int yPos; - int chrtLbl; - getdisplay().setFont(&Ubuntu_Bold8pt8b); - for (int i = 1; i <= 3; i++) { - yPos = yOffset + (i * 60); - getdisplay().fillRect(0, yPos, width, 1, commonData->fgcolor); - 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 - chrtLbl = ((i - 1 + (prevY < yOffset + 30)) * dataIntv) * -1; // change label if last data point is more than 30 lines (= seconds) from chart line - } else { - int j = 3 - i; - chrtLbl = (int((((numWndVals / dataIntv) - 50) * dataIntv / 60) + 1) - (j * dataIntv)) * -1; // 50 lines left below last chart line + for (int i = 1; i <= 3; i++) { + yPos = yOffset + (i * 60); + getdisplay().fillRect(0, yPos, width, 1, commonData->fgcolor); + 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 + chrtLbl = ((i - 1 + (prevY < yOffset + 30)) * dataIntv) * -1; // change label if last data point is more than 30 lines (= seconds) from chart line + } else { + int j = 3 - i; + chrtLbl = (int((((numWndVals / dataIntv) - 50) * dataIntv / 60) + 1) - (j * dataIntv)) * -1; // 50 lines left below last chart line + } + getdisplay().printf("%3d", chrtLbl); // Wind value label } - getdisplay().printf("%3d", chrtLbl); // Wind value label + } else if (chrtMode == 'S') { + wsValue = wsHstry->getLast(); + Chart twsChart(wsHstry, wsBVal, 0, 0, dataIntv, dfltRng, logger); + twsChart.drawChrtHdr(); + twsChart.drawChrtGrd(40); + + } else if (chrtMode == 'B') { } LOG_DEBUG(GwLog::DEBUG, "PageWindPlot time: %ld", millis() - timer);