diff --git a/lib/obp60task/OBPcharts.cpp b/lib/obp60task/OBPcharts.cpp index 44c782e..907712b 100644 --- a/lib/obp60task/OBPcharts.cpp +++ b/lib/obp60task/OBPcharts.cpp @@ -1,75 +1,367 @@ // Function lib for display of boat data in various chart formats #include "OBPcharts.h" +#include "OBP60Extensions.h" +#include "OBPRingBuffer.h" // --- Class Chart --------------- -void Chart::drawChrtHdr() { - // chart header label + lines - int i; - getdisplay().fillRect(0, top, cWidth, 2, commonData->fgcolor); +template +Chart::Chart(RingBuffer& dataBuf, int8_t chrtDir, int8_t chrtSz, int dfltRng, CommonData& common, bool useSimuData) + : dataBuf(dataBuf) + , chrtDir(chrtDir) + , chrtSz(chrtSz) + , dfltRng(dfltRng) + , commonData(&common) + , useSimuData(useSimuData) +{ + logger = commonData->logger; + fgColor = commonData->fgcolor; + bgColor = commonData->bgcolor; - // horizontal chart labels - getdisplay().drawLine(cStart.x, cStart.y, cWidth, cStart.y); - getdisplay().fillRect(cStart.x, cStart.y, cWidth, 2, commonData->fgcolor); + LOG_DEBUG(GwLog::DEBUG, "Chart create: dataBuf: %p", (void*)&dataBuf); + dWidth = getdisplay().width(); + dHeight = getdisplay().height(); - getdisplay().setFont(&Ubuntu_Bold10pt8b); - getdisplay().setCursor(cStart.x, cStart.y + 12); - getdisplay().print(dbName); // Wind data name + if (chrtDir == 0) { + // horizontal chart timeline direction + timAxis = dWidth - xOffset; + switch (chrtSz) { + case 0: + valAxis = dHeight - top - bottom; + cStart = { xOffset, top }; + break; + case 1: + valAxis = (dHeight - top - bottom) / 2 - gap; + cStart = { xOffset, top }; + break; + case 2: + valAxis = (dHeight - top - bottom) / 2 - gap; + cStart = { xOffset, top + (valAxis + gap) + gap }; + break; + default: + LOG_DEBUG(GwLog::DEBUG, "displayChart: wrong parameter"); + return; + } + } else if (chrtDir == 1) { + // vertical chart timeline direction + timAxis = dHeight - top - bottom; + switch (chrtSz) { + case 0: + valAxis = dWidth - xOffset; + cStart = { xOffset, top }; + break; + case 1: + valAxis = dWidth / 2 - gap; + cStart = { 0, top }; + break; + case 2: + valAxis = dWidth / 2 - gap; + cStart = { dWidth / 2 + gap, top }; + break; + default: + LOG_DEBUG(GwLog::DEBUG, "displayChart: wrong parameter"); + return; + } + } else { + LOG_DEBUG(GwLog::DEBUG, "displayChart: wrong parameter"); + return; + } + // xCenter = timAxis / 2; - 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); - } + dataBuf.getMetaData(dbName, dbFormat); + dbMAX_VAL = dataBuf.getMaxVal(); + bufSize = dataBuf.getCapacity(); + LOG_DEBUG(GwLog::DEBUG, "Chart create: dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cStart {x,y}: %d, %d, dbname: %s", dWidth, dHeight, timAxis, valAxis, cStart.x, cStart.y, dbName); +}; + +template +Chart::~Chart() +{ } -void Chart::drawChrtGrd(const int chrtRng) { - // chart Y axis labels + lines - int i; +// chart time axis label + lines +template +void Chart::drawChrtTimeAxis(int8_t chrtIntv) +{ + int timeRng; + float slots, intv, i; + char sTime[6]; - 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); - } - } + getdisplay().setTextColor(fgColor); + if (chrtDir == 0) { // horizontal chart + getdisplay().fillRect(0, top, dWidth, 2, fgColor); + getdisplay().setFont(&Ubuntu_Bold8pt8b); + + timeRng = chrtIntv * 4; // Chart time interval: [1] 4 min., [2] 8 min., [3] 12 min., [4] 16 min., [8] 32 min. + slots = (timAxis - xOffset) / 75.0; // number of axis labels + intv = timeRng / slots; // minutes per chart axis interval + i = timeRng; // Chart axis label start at -32, -16, -12, ... minutes + + for (int j = 0; j < timAxis - 30; j += 75) { + LOG_DEBUG(GwLog::DEBUG, "ChartHdr: timAxis: %d, {x,y}: {%d,%d}, i: %.1f, j: %d, chrtIntv: %d, intv: %.1f, slots: %.1f", timAxis, cStart.x, cStart.y, i, j, chrtIntv, intv, slots); + if (chrtIntv < 3) { + snprintf(sTime, size_t(sTime), "-%.1f", i); + drawTextCenter(cStart.x + j - 8, cStart.y - 8, sTime); // time interval + } else { + snprintf(sTime, size_t(sTime), "-%.0f", std::round(i)); + drawTextCenter(cStart.x + j - 4, cStart.y - 8, sTime); // time interval + } + getdisplay().drawLine(cStart.x + j, cStart.y, cStart.x + j, cStart.y + 5, fgColor); + i -= intv; + } + /* getdisplay().setFont(&Ubuntu_Bold8pt8b); + getdisplay().setCursor(timAxis - 8, cStart.y - 2); + getdisplay().print("min"); */ + + } else { // chrtDir == 1; vertical chart + getdisplay().setFont(&Ubuntu_Bold8pt8b); + timeRng = chrtIntv * 4; // Chart time interval: [1] 4 min., [2] 8 min., [3] 12 min., [4] 16 min., [8] 32 min. + slots = timAxis / 75.0; // number of axis labels + intv = timeRng / slots; // minutes per chart axis interval + i = 0; // Chart axis label start at -32, -16, -12, ... minutes + + for (int j = 0; j < (timAxis - 75); j += 75) { // don't print time label at lower end + LOG_DEBUG(GwLog::DEBUG, "ChartHdr: timAxis: %d, {x,y}: {%d,%d}, i: %.1f, j: %d, chrtIntv: %d, intv: %.1f, slots: %.1f", timAxis, cStart.x, cStart.y, i, j, chrtIntv, intv, slots); + if (chrtIntv < 3) { // print 1 decimal if time range is single digit (4 or 8 minutes) + snprintf(sTime, size_t(sTime), "%.1f", i * -1); + } else { + snprintf(sTime, size_t(sTime), "%.0f", std::round(i) * -1); + } + drawTextCenter(dWidth / 2, cStart.y + j, sTime); // time value + getdisplay().drawLine(cStart.x, cStart.y + j, cStart.x + valAxis, cStart.y + j, fgColor); // Grid line + i += intv; + } + } } -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] +// chart value axis labels + lines +template +void Chart::drawChrtValAxis() +{ + float slots; + int i, intv; + char sVal[6]; + getdisplay().setFont(&Ubuntu_Bold10pt8b); + if (chrtDir == 0) { // horizontal chart + slots = valAxis / 60.0; // number of axis labels + intv = static_cast(round(chrtRng / slots)); + i = intv; + for (int j = 60; j < valAxis - 30; j += 60) { + LOG_DEBUG(GwLog::DEBUG, "ChartGrd: chrtRng: %d, intv: %d, slots: %.1f, valAxis: %d, i: %d, j: %d", chrtRng, intv, slots, valAxis, i, j); + getdisplay().fillRect(cStart.x - xOffset, cStart.y + j - 9, cStart.x - xOffset + 28, 12, bgColor); // Clear small area to remove potential chart lines + String sVal = String(static_cast(round(i))); + getdisplay().setCursor((3 - sVal.length()) * 9, cStart.y + j + 4); // value right-formated + getdisplay().printf("%s", sVal); // Range value + i += intv; + getdisplay().drawLine(cStart.x + 2, cStart.y + j, cStart.x + timAxis, cStart.y + j, fgColor); + } + getdisplay().setFont(&Ubuntu_Bold12pt8b); + drawTextRalign(cStart.x + timAxis, cStart.y - 3, dataBuf.getName()); // buffer data name + + } else { // chrtDir == 1; vertical chart + getdisplay().fillRect(cStart.x, top, valAxis, 2, fgColor); // top chart line + getdisplay().setCursor(cStart.x, cStart.y - 2); + snprintf(sVal, sizeof(sVal), "%d", dataBuf.getMin(numBufVals) / 1000); + getdisplay().printf("%s", sVal); // Range low end + snprintf(sVal, sizeof(sVal), "%.0f", round(chrtRng / 2)); + drawTextCenter(cStart.x + (valAxis / 2), cStart.y - 10, sVal); // Range mid end + snprintf(sVal, sizeof(sVal), "%.0f", round(chrtRng)); + drawTextRalign(cStart.x + valAxis - 1, cStart.y - 2, sVal); // Range high end + for (int j = 0; j <= valAxis; j += (valAxis / 2)) { + getdisplay().drawLine(cStart.x + j - 1, cStart.y, cStart.x + j - 1, cStart.y + timAxis, fgColor); + } + getdisplay().setFont(&Ubuntu_Bold12pt8b); + drawTextCenter(cStart.x + (valAxis / 4) + 4, cStart.y - 11, dataBuf.getName()); // buffer data name + LOG_DEBUG(GwLog::DEBUG, "ChartGrd: chrtRng: %d, intv: %d, slots: %.1f, valAxis: %d, i: %d, sVal.length: %d", chrtRng, intv, slots, valAxis, i, sizeof(sVal)); + } } + +// draw chart +template +void Chart::drawChrt(int8_t chrtIntv, GwApi::BoatValue currValue) +{ + float chrtScl; // Scale for data values in pixels per value + int chrtVal; // Current data value + static int chrtPrevVal; // Last data value in chart area + bool bufDataValid = false; // Flag to indicate if buffer data is valid + static int numNoData; // Counter for multiple invalid data values in a row + // GwApi::BoatValue currValue; // temporary boat value to display current data buffer value + + int x, y; // x and y coordinates for drawing + static int prevX, prevY; // Last x and y coordinates for drawing + + // Identify buffer size and buffer start position for chart + count = dataBuf.getCurrentSize(); + currIdx = dataBuf.getLastIdx(); + numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display + if (chrtIntv != oldChrtIntv || count == 1) { + // new data interval selected by user; this is only x * 230 values instead of 240 seconds (4 minutes) per interval step + intvBufSize = timAxis * chrtIntv; + numBufVals = min(count, (timAxis - 60) * chrtIntv); + bufStart = max(0, count - numBufVals); + lastAddedIdx = currIdx; + oldChrtIntv = chrtIntv; + } else { + numBufVals = numBufVals + numAddedBufVals; + lastAddedIdx = currIdx; + if (count == bufSize) { + bufStart = max(0, bufStart - numAddedBufVals); + } + } + + calcChrtRng(); + chrtScl = float(valAxis) / float(chrtRng); // Chart scale: pixels per value step + + // Do we have valid buffer data? + if (dataBuf.getMax() == dbMAX_VAL) { + // only values in buffer -> no valid wind data available + bufDataValid = false; + } else if (!currValue.valid && !useSimuData) { + // currently no valid boat data available and no simulation mode + numNoData++; + bufDataValid = true; + if (numNoData > 3) { + // If more than 4 invalid values in a row, send message + bufDataValid = false; + } + } else { + numNoData = 0; // reset data error counter + bufDataValid = true; // At least some wind data available + } + + // Draw wind values in chart + //*********************************************************************** + if (bufDataValid) { + for (int i = 0; i < (numBufVals / chrtIntv); i++) { + chrtVal = static_cast(dataBuf.get(bufStart + (i * chrtIntv))); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer + if (chrtVal == dbMAX_VAL) { + chrtPrevVal = dbMAX_VAL; + } else { + chrtVal = static_cast((chrtVal / 1000.0) + 0.5); // Convert to real value and round + if (chrtDir == 0) { // horizontal chart + x = cStart.x + i; // Position in chart area + y = cStart.y + (chrtVal * chrtScl); // value + } else { // vertical chart + x = cStart.x + (chrtVal * chrtScl); // value + y = cStart.y + timAxis - i; // Position in chart area + } + if (i >= (numBufVals / chrtIntv) - 10) // log chart data of 1 line (adjust for test purposes) + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %d, {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 + prevX = x; + prevY = y; + } + // Draw line with 2 pixels width + make sure vertical lines are drawn correctly + if (chrtDir == 0 || x == prevX) { // vertical line + getdisplay().drawLine(prevX, prevY, x, 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); + } + chrtPrevVal = chrtVal; + prevX = x; + prevY = y; + } + // Reaching chart area bottom end + if (i >= timAxis - 1) { + oldChrtIntv = 0; // force reset of buffer start and number of values to show in next display loop + break; + } + } + + // drawChrtValAxis(); + + // uses BoatValue temp variable to format latest buffer value + // doesn't work unfortunately when 'simulation data' is active, because OBP60Formatter generates own simulation value in that case + uint16_t lastVal = dataBuf.getLast(); + currValue.value = lastVal / 1000.0; + currValue.valid = (static_cast(lastVal) != dbMAX_VAL); + LOG_DEBUG(GwLog::DEBUG, "Chart drawChrt: lastVal: %d, currValue-value: %.1f, Valid: %d, Name: %s, Address: %p", lastVal, currValue.value, + currValue.valid, currValue.getName(), (void*)&currValue); + prntCurrValue(&currValue, { x, y }); + + } else { + // No valid data available + LOG_DEBUG(GwLog::LOG, "PageWindPlot: No valid data available"); + getdisplay().setFont(&Ubuntu_Bold10pt8b); + int pX, pY; + if (chrtDir == 0) { + pX = dWidth / 2; + pY = cStart.y + (valAxis / 2) - 10; + } else { + pX = valAxis / 2; + pY = cStart.y + (timAxis / 2) - 10; + } + getdisplay().fillRect(pX - 33, pY - 10, 66, 24, commonData->bgcolor); // Clear area for message + drawTextCenter(pX, pY, "No data"); + } + + drawChrtValAxis(); +} + +// Print current data value +template +void Chart::prntCurrValue(GwApi::BoatValue* currValue, const Pos chrtPos) +{ + int currentZone; + static int lastZone = 0; + static bool flipVal = false; + int xPosVal; + static const int yPosVal = (chrtDir == 0) ? cStart.y + valAxis - 5 : cStart.y + timAxis - 5; + + // flexible move of location for latest boat data value, in case chart data is printed at the current location + /* xPosVal = flipVal ? 8 : valAxis - 135; + currentZone = (chrtPos.y >= yPosVal - 32) && (chrtPos.y <= yPosVal + 6) && (chrtPos.x >= xPosVal - 4) && (chrtPos.x <= xPosVal + 146) ? 1 : 0; // Define current zone for data value + if (currentZone != lastZone) { + // Only flip when x moves to a different zone + if ((chrtPos.y >= yPosVal - 32) && (chrtPos.y <= yPosVal + 6) && (chrtPos.x >= xPosVal - 3) && (chrtPos.x <= xPosVal + 146)) { + flipVal = !flipVal; + xPosVal = flipVal ? 8 : valAxis - 135; + } + } + lastZone = currentZone; */ + + xPosVal = (chrtDir == 0) ? cStart.x + timAxis - 117 : cStart.x + valAxis - 117; + FormattedData frmtDbData = formatValue(currValue, *commonData); + double testdbValue = frmtDbData.value; + String sdbValue = frmtDbData.svalue; // value (string) + String dbUnit = frmtDbData.unit; // Unit of value + 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(), (void*)currValue); + getdisplay().fillRect(xPosVal - 3, yPosVal - 34, 118, 40, bgColor); // Clear area for TWS value + getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b); + getdisplay().setCursor(xPosVal, yPosVal); + if (useSimuData) + getdisplay().printf("%2.1f", currValue->value); // Value + else + getdisplay().print(sdbValue); // Value + // getdisplay().setFont(&Ubuntu_Bold12pt8b); + // getdisplay().setCursor(xPosVal + 76, yPosVal - 14); + // getdisplay().print(dbName); // Name + getdisplay().setFont(&Ubuntu_Bold8pt8b); + getdisplay().setCursor(xPosVal + 76, yPosVal + 1); + getdisplay().print(dbUnit); // Unit +} + +// check and adjust chart range +template +void Chart::calcChrtRng() +{ + int diffRng; + + diffRng = dataBuf.getMax(numBufVals) / 1000; + if (diffRng > chrtRng) { + chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 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, "Chart Range: diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", diffRng, chrtRng, dataBuf.getMin(numBufVals) / 1000, dataBuf.getMax(numBufVals) / 1000); +} + +// Explicitly instantiate class with required data types to avoid linker errors +template class Chart; +template class Chart; // --- Class Chart --------------- diff --git a/lib/obp60task/OBPcharts.h b/lib/obp60task/OBPcharts.h index 813c2da..2494213 100644 --- a/lib/obp60task/OBPcharts.h +++ b/lib/obp60task/OBPcharts.h @@ -1,103 +1,62 @@ // Function lib for display of boat data in various chart formats #pragma once -#include "OBP60Extensions.h" +#include +#include #include "Pagedata.h" -// #include "OBPDataOperations.h" -// #include "OBPRingBuffer.h" -struct Point { +struct Pos { int x; int y; }; +template class RingBuffer; +class GwLog; +template 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. + CommonData *commonData; + GwLog *logger; + + RingBuffer &dataBuf; // Buffer to display + int8_t chrtDir; // Chart timeline direction: [0] = horizontal, [1] = vertical + int8_t chrtSz; // Chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom int dfltRng; // Default range of chart, e.g. 30 = [0..30] + uint16_t fgColor; // color code for any screen writing + uint16_t bgColor; // color code for screen background + bool useSimuData; // flag to indicate if simulation data is active 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 + int gap = 20; // gap between 2 charts; actual gap is 2x + int xOffset = 33; // offset for horizontal axis (time/value), because of space for left vertical axis labeling + int yOffset = 10; // offset for vertical axis (time/value), because of space for top horizontal axis labeling + int dWidth; // Display width + int dHeight; // Display height + int timAxis, valAxis; // size of time and value chart axis + Pos cStart; // start point of chart area + int chrtRng; // Range of buffer values from min to max value - String dbName, dbFormat; - int16_t dbMAX_VAL; - size_t bufSize; - GwApi::BoatValue* bValue; + String dbName, dbFormat; // Name and format of data buffer + int16_t dbMAX_VAL; // Highest possible value of buffer of type -> indicates invalid value in buffer + size_t bufSize; // History buffer size: 1.920 values for 32 min. history chart + int intvBufSize; // Buffer size used for currently selected time interval + int count; // current size of buffer + int numBufVals; // number of wind values available for current interval selection + int bufStart; // 1st data value in buffer to show + int numAddedBufVals; // Number of values added to buffer since last display + size_t currIdx; // Current index in TWD history buffer + size_t lastIdx; // Last index of TWD history buffer + size_t lastAddedIdx = 0; // Last index of TWD history buffer when new data was added + int oldChrtIntv = 0; // remember recent user selection of data interval + + void calcChrtRng(); + void drawChrtValAxis(); 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; + Chart(RingBuffer& dataBuf, int8_t chrtDir, int8_t chrtSz, int dfltRng, CommonData& common, bool useSimuData); + ~Chart(); + void drawChrtTimeAxis(int8_t chrtIntv); + void drawChrt(int8_t chrtIntv, GwApi::BoatValue currValue); + void prntCurrValue(GwApi::BoatValue* currValue, Pos chrtPos); - 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 5a92554..eb2d079 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -1,11 +1,11 @@ #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 +#include "Pagedata.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 @@ -117,7 +117,7 @@ public: // Key functions virtual int handleKey(int key) { - // Set chart mode TWD | TWS -> to be implemented + // Set chart mode TWD | TWS if (key == 1) { if (chrtMode == 'D') { chrtMode = 'S'; @@ -189,6 +189,9 @@ public: static String wdName, wdFormat; // Wind direction name and format static String wsName, wsFormat; // Wind speed name and format static int16_t wdMAX_VAL; // Max. value of wd history buffer, indicating invalid values + static std::unique_ptr> twsFlChart; // chart object for wind speed chart + static std::unique_ptr> twdHfChart; // chart object for wind direction chart + static std::unique_ptr> twsHfChart; // chart object for wind speed chart float wsValue; // Wind speed value in chart area String wsUnit; // Wind speed unit in chart area static GwApi::BoatValue* wsBVal = new GwApi::BoatValue("TWS"); // temp BoatValue for wind speed unit identification; required by OBP60Formater @@ -253,7 +256,7 @@ public: isInitialized = true; // Set flag to indicate that page is now initialized } - // read boat data values; TWD only for validation test, TWS for display of current value + // read boat data values; TWD/AWS only for validation test for (int i = 0; i < numBoatData; i++) { bvalue = pageData.values[i]; BDataValid[i] = bvalue->valid; @@ -280,9 +283,18 @@ public: wsBVal->setFormat(wsHstry->getFormat()); lastAddedIdx = wdHstry->getLastIdx(); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot twsChart: *wsHstry: %p", wsHstry); + twsFlChart = std::unique_ptr>(new Chart(*wsHstry, 0, 0, 15, *commonData, useSimuData)); + twdHfChart = std::unique_ptr>(new Chart(*wdHstry, 1, 1, 15, *commonData, useSimuData)); + twsHfChart = std::unique_ptr>(new Chart(*wsHstry, 1, 2, 15, *commonData, useSimuData)); + oldShowTruW = showTruW; } + // Set display in partial refresh mode + getdisplay().setPartialWindow(0, 0, width, height); // Set partial update + getdisplay().setTextColor(commonData->fgcolor); + if (chrtMode == 'D') { // Identify buffer size and buffer start position for chart count = wdHstry->getCurrentSize(); @@ -302,8 +314,7 @@ public: bufStart = max(0, bufStart - numAddedBufVals); } } - // LOG_DEBUG(GwLog::DEBUG,"PSRAM Size: %d kByte; free: %d Byte", ESP.getPsramSize()/1024, ESP.getFreePsram()); - 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", + 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"); @@ -335,10 +346,6 @@ public: // Draw page //*********************************************************************** - // 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); @@ -348,17 +355,17 @@ public: 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); + snprintf(sWndLbl, size_t(sWndLbl), "%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); + snprintf(sWndLbl, size_t(sWndLbl), "%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); + snprintf(sWndLbl, size_t(sWndLbl), "%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 @@ -505,14 +512,20 @@ public: } 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 == 'S') { +// wsValue = wsHstry->getLast(); + twsFlChart->drawChrtTimeAxis(dataIntv); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot chart: wsBVal.name: %s, format: %s, wsBVal.value: %.1f, address: %p", wsBVal->getName(), wsBVal->getFormat(), wsBVal->value, wsBVal); + twsFlChart->drawChrt(dataIntv, *wsBVal); } else if (chrtMode == 'B') { - } */ +// wsValue = wsHstry->getLast(); + twdHfChart->drawChrtTimeAxis(dataIntv); + twsHfChart->drawChrtTimeAxis(dataIntv); + LOG_DEBUG(GwLog::DEBUG, "PageWindPlot chart: wsBVal.name: %s, format: %s, wsBVal.value: %.1f, address: %p", wsBVal->getName(), wsBVal->getFormat(), wsBVal->value, wsBVal); + twdHfChart->drawChrt(dataIntv, *wsBVal); + twsHfChart->drawChrt(dataIntv, *wsBVal); + } LOG_DEBUG(GwLog::DEBUG, "PageWindPlot time: %ld", millis() - timer); return PAGE_UPDATE;