1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2026-01-26 08:13:05 +01:00

Code rework for OBPcharts, part 2

This commit is contained in:
Ulrich Meine
2026-01-06 22:57:07 +01:00
parent 559042da78
commit 2d4f49659d
4 changed files with 273 additions and 232 deletions

View File

@@ -4,6 +4,15 @@
#include "OBPDataOperations.h" #include "OBPDataOperations.h"
#include "OBPRingBuffer.h" #include "OBPRingBuffer.h"
std::map<String, ChartProps> Chart::dfltChrtDta = {
{ "formatWind", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
{ "formatCourse", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
//{ "formatKnots", { 7.71, 2.57 } }, // default speed range in m/s
{ "formatKnots", { 7.71, 2.56 } }, // default speed range in m/s
{ "formatDepth", { 15.0, 5.0 } }, // default depth range in m
{ "kelvinToC", { 30.0, 5.0 } } // default temp range in °C/K
};
// --- Class Chart --------------- // --- Class Chart ---------------
// Chart - object holding the actual chart, incl. data buffer and format definition // Chart - object holding the actual chart, incl. data buffer and format definition
@@ -12,11 +21,11 @@
// <dfltRng> default range of chart, e.g. 30 = [0..30]; // <dfltRng> default range of chart, e.g. 30 = [0..30];
// <common> common program data; required for logger and color data // <common> common program data; required for logger and color data
// <useSimuData> flag to indicate if simulation data is active // <useSimuData> flag to indicate if simulation data is active
template <typename T> // Chart::Chart(RingBuffer<uint16_t>& dataBuf, char chrtDir, int8_t chrtSz, double dfltRng, CommonData& common, bool useSimuData)
Chart<T>::Chart(RingBuffer<T>& dataBuf, char chrtDir, int8_t chrtSz, double dfltRng, CommonData& common, bool useSimuData) Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData)
: dataBuf(dataBuf) : dataBuf(dataBuf)
, chrtDir(chrtDir) //, chrtDir(chrtDir)
, chrtSz(chrtSz) //, chrtSz(chrtSz)
, dfltRng(dfltRng) , dfltRng(dfltRng)
, commonData(&common) , commonData(&common)
, useSimuData(useSimuData) , useSimuData(useSimuData)
@@ -28,51 +37,51 @@ Chart<T>::Chart(RingBuffer<T>& dataBuf, char chrtDir, int8_t chrtSz, double dflt
dWidth = getdisplay().width(); dWidth = getdisplay().width();
dHeight = getdisplay().height(); dHeight = getdisplay().height();
if (chrtDir == 'H') { /* if (chrtDir == 'H') {
// horizontal chart timeline direction // horizontal chart timeline direction
timAxis = dWidth - 1; timAxis = dWidth - 1;
switch (chrtSz) { switch (chrtSz) {
case 0: case 0:
valAxis = dHeight - top - bottom; valAxis = dHeight - top - bottom;
cRoot = { 0, top - 1 }; cRoot = { 0, top - 1 };
break; break;
case 1: case 1:
valAxis = (dHeight - top - bottom) / 2 - hGap; valAxis = (dHeight - top - bottom) / 2 - hGap;
cRoot = { 0, top - 1 }; cRoot = { 0, top - 1 };
break; break;
case 2: case 2:
valAxis = (dHeight - top - bottom) / 2 - hGap; valAxis = (dHeight - top - bottom) / 2 - hGap;
cRoot = { 0, top + (valAxis + hGap) + hGap - 1 }; cRoot = { 0, top + (valAxis + hGap) + hGap - 1 };
break; break;
default: default:
LOG_DEBUG(GwLog::ERROR, "obp60:Chart %s: wrong init parameter", dataBuf.getName()); LOG_DEBUG(GwLog::ERROR, "obp60:Chart %s: wrong init parameter", dataBuf.getName());
return; return;
} }
} else if (chrtDir == 'V') { } else if (chrtDir == 'V') {
// vertical chart timeline direction // vertical chart timeline direction
timAxis = dHeight - top - bottom; timAxis = dHeight - top - bottom;
switch (chrtSz) { switch (chrtSz) {
case 0: case 0:
valAxis = dWidth - 1; valAxis = dWidth - 1;
cRoot = { 0, top - 1 }; cRoot = { 0, top - 1 };
break; break;
case 1: case 1:
valAxis = dWidth / 2 - vGap; valAxis = dWidth / 2 - vGap;
cRoot = { 0, top - 1 }; cRoot = { 0, top - 1 };
break; break;
case 2: case 2:
valAxis = dWidth / 2 - vGap; valAxis = dWidth / 2 - vGap;
cRoot = { dWidth / 2 + vGap - 1, top - 1 }; cRoot = { dWidth / 2 + vGap - 1, top - 1 };
break; break;
default: default:
LOG_DEBUG(GwLog::ERROR, "obp60:Chart %s: wrong init parameter", dataBuf.getName());
return;
}
} else {
LOG_DEBUG(GwLog::ERROR, "obp60:Chart %s: wrong init parameter", dataBuf.getName()); LOG_DEBUG(GwLog::ERROR, "obp60:Chart %s: wrong init parameter", dataBuf.getName());
return; return;
} } */
} else {
LOG_DEBUG(GwLog::ERROR, "obp60:Chart %s: wrong init parameter", dataBuf.getName());
return;
}
dataBuf.getMetaData(dbName, dbFormat); dataBuf.getMetaData(dbName, dbFormat);
dbMIN_VAL = dataBuf.getMinVal(); dbMIN_VAL = dataBuf.getMinVal();
@@ -116,9 +125,6 @@ Chart<T>::Chart(RingBuffer<T>& dataBuf, char chrtDir, int8_t chrtSz, double dflt
rngStep = 5.0; rngStep = 5.0;
} }
//chrtMin = dbMIN_VAL;
//chrtMax = dbMAX_VAL;
//chrtMid = dbMAX_VAL;
// Initialize chart range values // Initialize chart range values
chrtMin = zeroValue; chrtMin = zeroValue;
chrtMax = chrtMin + dfltRng; chrtMax = chrtMin + dfltRng;
@@ -130,35 +136,93 @@ Chart<T>::Chart(RingBuffer<T>& dataBuf, char chrtDir, int8_t chrtSz, double dflt
dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, dbName, rngStep, chrtDataFmt); dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, dbName, rngStep, chrtDataFmt);
}; };
template <typename T> Chart::~Chart()
Chart<T>::~Chart()
{ {
} }
// Perform all actions to draw chart // Perform all actions to draw chart
// Parameters: <chrtIntv> chart time interval, <currValue> current boat data value to be printed, <showCurrValue> current boat data shall be shown yes/no // Parameters: <chrtDir>: chart timeline direction: 'H' = horizontal, 'V' = vertical
template <typename T> // <chrtSz>: chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom
void Chart<T>::showChrt(GwApi::BoatValue currValue, int8_t& chrtIntv, const bool showCurrValue) // <chrtIntv>: chart timeline interval
// <showCurrValue>: current boat data shall be shown [true/false]
// <currValue>: current boat data value to be printed
// void Chart::showChrt(GwApi::BoatValue currValue, int8_t& chrtIntv, const bool showCurrValue)
void Chart::showChrt(char chrtDir, int8_t chrtSz, int8_t& chrtIntv, bool showCurrValue, GwApi::BoatValue currValue)
{ {
drawChrt(chrtIntv, currValue); // this->chrtDir = chrtDir;
drawChrtTimeAxis(chrtIntv); // this->chrtSz = chrtSz;
drawChrtValAxis();
if (!setChartDimensions(chrtDir, chrtSz)) {
return; // wrong chart dimension parameters
}
drawChrt(chrtDir, chrtIntv, currValue);
drawChrtTimeAxis(chrtDir, chrtSz, chrtIntv);
drawChrtValAxis(chrtDir, chrtSz);
if (!bufDataValid) { // No valid data available if (!bufDataValid) { // No valid data available
prntNoValidData(); prntNoValidData(chrtDir);
return; return;
} }
if (showCurrValue) { // shows latest value from history buffer; usually this should be the most current one if (showCurrValue) { // show latest value from history buffer; usually this should be the most current one
currValue.value = dataBuf.getLast(); currValue.value = dataBuf.getLast();
currValue.valid = currValue.value != dbMAX_VAL; currValue.valid = currValue.value != dbMAX_VAL;
Chart<T>::prntCurrValue(currValue); prntCurrValue(chrtDir, currValue);
} }
} }
// define dimensions and start points for chart
bool Chart::setChartDimensions(const char direction, const int8_t size)
{
if ((direction != 'H' && direction != 'V') || (size < 0 || size > 2)) {
LOG_DEBUG(GwLog::ERROR, "obp60:setChartDimensions %s: wrong parameters", dataBuf.getName());
return false;
}
if (direction == 'H') {
// horizontal chart timeline direction
timAxis = dWidth - 1;
switch (size) {
case 0:
valAxis = dHeight - top - bottom;
cRoot = { 0, top - 1 };
break;
case 1:
valAxis = (dHeight - top - bottom) / 2 - hGap;
cRoot = { 0, top - 1 };
break;
case 2:
valAxis = (dHeight - top - bottom) / 2 - hGap;
cRoot = { 0, top + (valAxis + hGap) + hGap - 1 };
break;
}
} else if (direction == 'V') {
// vertical chart timeline direction
timAxis = dHeight - top - bottom;
switch (size) {
case 0:
valAxis = dWidth - 1;
cRoot = { 0, top - 1 };
break;
case 1:
valAxis = dWidth / 2 - vGap;
cRoot = { 0, top - 1 };
break;
case 2:
valAxis = dWidth / 2 - vGap;
cRoot = { dWidth / 2 + vGap - 1, top - 1 };
break;
}
}
LOG_DEBUG(GwLog::ERROR, "obp60:setChartDimensions %s: direction: %c, size: %d, dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot{%d, %d}, top: %d, bottom: %d, hGap: %d, vGap: %d",
dataBuf.getName(), direction, size, dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, top, bottom, hGap, vGap);
return true;
}
// draw chart // draw chart
template <typename T> void Chart::drawChrt(const char chrtDir, int8_t& chrtIntv, GwApi::BoatValue& currValue)
void Chart<T>::drawChrt(int8_t& chrtIntv, GwApi::BoatValue& currValue)
{ {
double chrtVal; // Current data value double chrtVal; // Current data value
double chrtScl; // Scale for data values in pixels per value double chrtScl; // Scale for data values in pixels per value
@@ -167,9 +231,9 @@ void Chart<T>::drawChrt(int8_t& chrtIntv, GwApi::BoatValue& currValue)
getBufStartNSize(chrtIntv); getBufStartNSize(chrtIntv);
// LOG_DEBUG(GwLog::DEBUG, "PageOneValue:drawChart: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng); // LOG_DEBUG(GwLog::DEBUG, "Chart:drawChart: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng);
calcChrtBorders(chrtMin, chrtMid, chrtMax, chrtRng); calcChrtBorders(chrtMin, chrtMid, chrtMax, chrtRng);
LOG_DEBUG(GwLog::DEBUG, "PageOneValue:drawChart2: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng); LOG_DEBUG(GwLog::DEBUG, "Chart:drawChart2: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng);
// Chart scale: pixels per value step // Chart scale: pixels per value step
chrtScl = double(valAxis) / chrtRng; chrtScl = double(valAxis) / chrtRng;
@@ -290,8 +354,7 @@ void Chart<T>::drawChrt(int8_t& chrtIntv, GwApi::BoatValue& currValue)
} }
// Identify buffer size and buffer start position for chart // Identify buffer size and buffer start position for chart
template <typename T> void Chart::getBufStartNSize(int8_t& chrtIntv)
void Chart<T>::getBufStartNSize(int8_t& chrtIntv)
{ {
count = dataBuf.getCurrentSize(); count = dataBuf.getCurrentSize();
currIdx = dataBuf.getLastIdx(); currIdx = dataBuf.getLastIdx();
@@ -314,8 +377,7 @@ void Chart<T>::getBufStartNSize(int8_t& chrtIntv)
} }
// check and adjust chart range and set range borders and range middle // check and adjust chart range and set range borders and range middle
template <typename T> void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, double& rng)
void Chart<T>::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, double& rng)
{ {
if (chrtDataFmt == 'W' || chrtDataFmt == 'R') { if (chrtDataFmt == 'W' || chrtDataFmt == 'R') {
// Chart data is of type 'course', 'wind' or 'rot' // Chart data is of type 'course', 'wind' or 'rot'
@@ -413,8 +475,7 @@ void Chart<T>::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, d
} }
// chart time axis label + lines // chart time axis label + lines
template <typename T> void Chart::drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, int8_t& chrtIntv)
void Chart<T>::drawChrtTimeAxis(int8_t& chrtIntv)
{ {
float axSlots, intv, i; float axSlots, intv, i;
char sTime[6]; char sTime[6];
@@ -461,8 +522,7 @@ void Chart<T>::drawChrtTimeAxis(int8_t& chrtIntv)
} }
// chart value axis labels + lines // chart value axis labels + lines
template <typename T> void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz)
void Chart<T>::drawChrtValAxis()
{ {
double axLabel; double axLabel;
double cVal; double cVal;
@@ -538,8 +598,7 @@ void Chart<T>::drawChrtValAxis()
} }
// Print current data value // Print current data value
template <typename T> void Chart::prntCurrValue(const char chrtDir, GwApi::BoatValue& currValue)
void Chart<T>::prntCurrValue(GwApi::BoatValue& currValue)
{ {
const int xPosVal = (chrtDir == 'H') ? cRoot.x + (timAxis / 2) - 56 : cRoot.x + 32; const int xPosVal = (chrtDir == 'H') ? cRoot.x + (timAxis / 2) - 56 : cRoot.x + 32;
const int yPosVal = (chrtDir == 'H') ? cRoot.y + valAxis - 7 : cRoot.y + timAxis - 7; const int yPosVal = (chrtDir == 'H') ? cRoot.y + valAxis - 7 : cRoot.y + timAxis - 7;
@@ -566,8 +625,7 @@ void Chart<T>::prntCurrValue(GwApi::BoatValue& currValue)
} }
// print message for no valid data availabletemplate <typename T> // print message for no valid data availabletemplate <typename T>
template <typename T> void Chart::prntNoValidData(const char chrtDir)
void Chart<T>::prntNoValidData()
{ {
int pX, pY; int pX, pY;
@@ -588,8 +646,7 @@ void Chart<T>::prntNoValidData()
} }
// Get maximum difference of last <amount> of dataBuf ringbuffer values to center chart; for angle data only // Get maximum difference of last <amount> of dataBuf ringbuffer values to center chart; for angle data only
template <typename T> double Chart::getAngleRng(double center, size_t amount)
double Chart<T>::getAngleRng(double center, size_t amount)
{ {
size_t count = dataBuf.getCurrentSize(); size_t count = dataBuf.getCurrentSize();
@@ -624,8 +681,7 @@ double Chart<T>::getAngleRng(double center, size_t amount)
} }
// print horizontal axis label with only three values: top, mid, and bottom // print horizontal axis label with only three values: top, mid, and bottom
template <typename T> void Chart::prntHorizThreeValueAxisLabel(const GFXfont* font)
void Chart<T>::prntHorizThreeValueAxisLabel(const GFXfont* font)
{ {
double axLabel; double axLabel;
double chrtMin, chrtMid, chrtMax; double chrtMin, chrtMid, chrtMax;
@@ -637,7 +693,7 @@ void Chart<T>::prntHorizThreeValueAxisLabel(const GFXfont* font)
yOffset = 15; yOffset = 15;
} else if (font == &Ubuntu_Bold12pt8b) { } else if (font == &Ubuntu_Bold12pt8b) {
xOffset = 51; xOffset = 51;
yOffset = 17; yOffset = 18;
} }
getdisplay().setFont(font); getdisplay().setFont(font);
@@ -658,8 +714,8 @@ void Chart<T>::prntHorizThreeValueAxisLabel(const GFXfont* font)
// print mid axis label // print mid axis label
axLabel = chrtMid; axLabel = chrtMid;
sVal = formatLabel(axLabel); sVal = formatLabel(axLabel);
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 9, xOffset + 4, 16, bgColor); // Clear small area to remove potential chart lines getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 4, 16, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + (valAxis / 2) + 5, sVal); // range value drawTextRalign(cRoot.x + xOffset, cRoot.y + (valAxis / 2) + 6, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 4, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor); getdisplay().drawLine(cRoot.x + xOffset + 4, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor);
// print bottom axis label // print bottom axis label
@@ -671,8 +727,7 @@ void Chart<T>::prntHorizThreeValueAxisLabel(const GFXfont* font)
} }
// print horizontal axis label with multiple axis lines // print horizontal axis label with multiple axis lines
template <typename T> void Chart::prntHorizMultiValueAxisLabel(const GFXfont* font)
void Chart<T>::prntHorizMultiValueAxisLabel(const GFXfont* font)
{ {
double chrtMin, chrtMax, chrtRng; double chrtMin, chrtMax, chrtRng;
double axSlots, axIntv, axLabel; double axSlots, axIntv, axLabel;
@@ -724,8 +779,7 @@ void Chart<T>::prntHorizMultiValueAxisLabel(const GFXfont* font)
} }
// Draw chart line with thickness of 2px // Draw chart line with thickness of 2px
template <typename T> void Chart::drawBoldLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
void Chart<T>::drawBoldLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
{ {
int16_t dx = std::abs(x2 - x1); int16_t dx = std::abs(x2 - x1);
@@ -741,8 +795,7 @@ void Chart<T>::drawBoldLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
} }
// Convert and format current axis label to user defined format; helper function for easier handling of OBP60Formatter // Convert and format current axis label to user defined format; helper function for easier handling of OBP60Formatter
template <typename T> String Chart::convNformatLabel(double label)
String Chart<T>::convNformatLabel(double label)
{ {
GwApi::BoatValue tmpBVal(dbName); // temporary boat value for string formatter GwApi::BoatValue tmpBVal(dbName); // temporary boat value for string formatter
String sVal; String sVal;
@@ -759,8 +812,7 @@ String Chart<T>::convNformatLabel(double label)
} }
// Format current axis label for printing w/o data format conversion (has been done earlier) // Format current axis label for printing w/o data format conversion (has been done earlier)
template <typename T> String Chart::formatLabel(const double& label)
String Chart<T>::formatLabel(const double& label)
{ {
char sVal[11]; char sVal[11];
@@ -786,7 +838,4 @@ String Chart<T>::formatLabel(const double& label)
return String(sVal); return String(sVal);
} }
// Explicitly instantiate class with required data types to avoid linker errors
template class Chart<uint16_t>;
// --- Class Chart --------------- // --- Class Chart ---------------

View File

@@ -17,15 +17,14 @@ template <typename T>
class RingBuffer; class RingBuffer;
class GwLog; class GwLog;
template <typename T>
class Chart { class Chart {
protected: protected:
CommonData* commonData; CommonData* commonData;
GwLog* logger; GwLog* logger;
RingBuffer<T>& dataBuf; // Buffer to display RingBuffer<uint16_t>& dataBuf; // Buffer to display
char chrtDir; // Chart timeline direction: 'H' = horizontal, 'V' = vertical //char chrtDir; // Chart timeline direction: 'H' = horizontal, 'V' = vertical
int8_t chrtSz; // Chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom //int8_t chrtSz; // Chart size: [0] = full size, [1] = half size left/top, [2] half size right/bottom
double dfltRng; // Default range of chart, e.g. 30 = [0..30] double dfltRng; // Default range of chart, e.g. 30 = [0..30]
uint16_t fgColor; // color code for any screen writing uint16_t fgColor; // color code for any screen writing
uint16_t bgColor; // color code for screen background uint16_t bgColor; // color code for screen background
@@ -72,13 +71,14 @@ protected:
static constexpr int8_t THRESHOLD_NO_DATA = 3; static constexpr int8_t THRESHOLD_NO_DATA = 3;
static constexpr int8_t VALAXIS_STEP = 60; static constexpr int8_t VALAXIS_STEP = 60;
void drawChrt(int8_t& chrtIntv, GwApi::BoatValue& currValue); // Draw chart line bool setChartDimensions(const char direction, const int8_t size); //define dimensions and start points for chart
void drawChrt(const char chrtDir, int8_t& chrtIntv, GwApi::BoatValue& currValue); // Draw chart line
void getBufStartNSize(int8_t& chrtIntv); // Identify buffer size and buffer start position for chart void getBufStartNSize(int8_t& chrtIntv); // Identify buffer size and buffer start position for chart
void calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, double& rng); // Calculate chart points for value axis and return range between <min> and <max> void calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, double& rng); // Calculate chart points for value axis and return range between <min> and <max>
void drawChrtTimeAxis(int8_t& chrtIntv); // Draw time axis of chart, value and lines void drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, int8_t& chrtIntv); // Draw time axis of chart, value and lines
void drawChrtValAxis(); // Draw value axis of chart, value and lines void drawChrtValAxis(const char chrtDir, const int8_t chrtSz); // Draw value axis of chart, value and lines
void prntCurrValue(GwApi::BoatValue& currValue); // Add current boat data value to chart void prntCurrValue(const char chrtDir, GwApi::BoatValue& currValue); // Add current boat data value to chart
void prntNoValidData(); // print message for no valid data available void prntNoValidData(const char chrtDir); // print message for no valid data available
double getAngleRng(double center, size_t amount); // Calculate range between chart center and edges double getAngleRng(double center, size_t amount); // Calculate range between chart center and edges
void prntHorizThreeValueAxisLabel(const GFXfont* font); // print horizontal axis label with only three values: top, mid, and bottom void prntHorizThreeValueAxisLabel(const GFXfont* font); // print horizontal axis label with only three values: top, mid, and bottom
void prntHorizMultiValueAxisLabel(const GFXfont* font); // print horizontal axis label with multiple axis lines void prntHorizMultiValueAxisLabel(const GFXfont* font); // print horizontal axis label with multiple axis lines
@@ -90,17 +90,9 @@ public:
// Define default chart range and range step for each boat data type // Define default chart range and range step for each boat data type
static std::map<String, ChartProps> dfltChrtDta; static std::map<String, ChartProps> dfltChrtDta;
Chart(RingBuffer<T>& dataBuf, char chrtDir, int8_t chrtSz, double dfltRng, CommonData& common, bool useSimuData); // Chart object of data chart // Chart(RingBuffer<uint16_t>& dataBuf, char chrtDir, int8_t chrtSz, double dfltRng, CommonData& common, bool useSimuData); // Chart object of data chart
Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData); // Chart object of data chart
~Chart(); ~Chart();
void showChrt(GwApi::BoatValue currValue, int8_t& chrtIntv, bool showCurrValue); // Perform all actions to draw chart // void showChrt(GwApi::BoatValue currValue, int8_t& chrtIntv, bool showCurrValue); // Perform all actions to draw chart
}; void showChrt(char chrtDir, int8_t chrtSz, int8_t& chrtIntv, bool showCurrValue, GwApi::BoatValue currValue); // Perform all actions to draw chart
template <typename T>
std::map<String, ChartProps> Chart<T>::dfltChrtDta = {
{ "formatWind", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
{ "formatCourse", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
//{ "formatKnots", { 7.71, 2.57 } }, // default speed range in m/s
{ "formatKnots", { 7.71, 2.56 } }, // default speed range in m/s
{ "formatDepth", { 15.0, 5.0 } }, // default depth range in m
{ "kelvinToC", { 30.0, 5.0 } } // default temp range in °C/K
}; };

View File

@@ -2,8 +2,8 @@
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
#include "OBPDataOperations.h"
#include "BoatDataCalibration.h" #include "BoatDataCalibration.h"
#include "OBPDataOperations.h"
#include "OBPcharts.h" #include "OBPcharts.h"
class PageOneValue : public Page { class PageOneValue : public Page {
@@ -18,7 +18,7 @@ private:
int8_t dataIntv = 1; // Update interval for wind history chart: int8_t dataIntv = 1; // Update interval for wind history chart:
// (1)|(2)|(3)|(4)|(8) x 240 seconds for 4, 8, 12, 16, 32 min. history chart // (1)|(2)|(3)|(4)|(8) x 240 seconds for 4, 8, 12, 16, 32 min. history chart
//String lengthformat; // String lengthformat;
bool useSimuData; bool useSimuData;
bool holdValues; bool holdValues;
String flashLED; String flashLED;
@@ -31,7 +31,7 @@ private:
// Data buffer pointer (owned by HstryBuffers) // Data buffer pointer (owned by HstryBuffers)
RingBuffer<uint16_t>* dataHstryBuf = nullptr; RingBuffer<uint16_t>* dataHstryBuf = nullptr;
std::unique_ptr<Chart<uint16_t>> dataFlChart, dataHfChart; // Chart object, full and half size std::unique_ptr<Chart> dataChart; // Chart object, full and half size
void showData(GwApi::BoatValue* bValue1, char size) void showData(GwApi::BoatValue* bValue1, char size)
{ {
@@ -124,7 +124,7 @@ public:
height = getdisplay().height(); // Screen height height = getdisplay().height(); // Screen height
// Get config data // Get config data
//lengthformat = commonData->config->getString(commonData->config->lengthFormat); // lengthformat = commonData->config->getString(commonData->config->lengthFormat);
useSimuData = commonData->config->getBool(commonData->config->useSimuData); useSimuData = commonData->config->getBool(commonData->config->useSimuData);
holdValues = commonData->config->getBool(commonData->config->holdvalues); holdValues = commonData->config->getBool(commonData->config->holdvalues);
flashLED = commonData->config->getString(commonData->config->flashLED); flashLED = commonData->config->getString(commonData->config->flashLED);
@@ -136,51 +136,57 @@ public:
{ {
Page::setupKeys(); Page::setupKeys();
#if defined BOARD_OBP60S3
constexpr int ZOOM_IDX = 4;
#elif defined BOARD_OBP40S3
constexpr int ZOOM_IDX = 1;
#endif
if (dataHstryBuf) { // show "Mode" key only if chart supported boat data type is available if (dataHstryBuf) { // show "Mode" key only if chart supported boat data type is available
commonData->keydata[0].label = "MODE"; commonData->keydata[0].label = "MODE";
commonData->keydata[ZOOM_IDX].label = "ZOOM";
} else { } else {
commonData->keydata[0].label = ""; commonData->keydata[0].label = "";
commonData->keydata[ZOOM_IDX].label = "";
} }
#if defined BOARD_OBP60S3
commonData->keydata[4].label = "ZOOM";
#elif defined BOARD_OBP40S3
commonData->keydata[1].label = "ZOOM";
#endif
} }
// Key functions // Key functions
virtual int handleKey(int key) virtual int handleKey(int key)
{ {
// Set page mode value | full chart | value/half chart if (dataHstryBuf) { // if boat data type supports charts
if (key == 1) {
if (pageMode == 'V') {
pageMode = 'C';
} else if (pageMode == 'C') {
pageMode = 'B';
} else {
pageMode = 'V';
}
return 0; // Commit the key
}
// Set interval for history chart update time (interval) // Set page mode value | full chart | value/half chart
#if defined BOARD_OBP60S3 if (key == 1) {
if (key == 5) { if (pageMode == 'V') {
#elif defined BOARD_OBP40S3 pageMode = 'C';
if (key == 2) { } else if (pageMode == 'C') {
#endif pageMode = 'B';
if (dataIntv == 1) { } else {
dataIntv = 2; pageMode = 'V';
} else if (dataIntv == 2) { }
dataIntv = 3; return 0; // Commit the key
} else if (dataIntv == 3) { }
dataIntv = 4;
} else if (dataIntv == 4) { // Set time frame to show for history chart
dataIntv = 8; #if defined BOARD_OBP60S3
} else { if (key == 5) {
dataIntv = 1; #elif defined BOARD_OBP40S3
if (key == 2) {
#endif
if (dataIntv == 1) {
dataIntv = 2;
} else if (dataIntv == 2) {
dataIntv = 3;
} else if (dataIntv == 3) {
dataIntv = 4;
} else if (dataIntv == 4) {
dataIntv = 8;
} else {
dataIntv = 1;
}
return 0; // Commit the key
} }
return 0; // Commit the key
} }
// Keylock function // Keylock function
@@ -201,7 +207,7 @@ public:
} }
#endif #endif
// buffer initialization will fail, if page is default page, because <displayNew> is not executed at system start for default page // buffer initialization will fail, if page is default page, because <displayNew> is not executed at system start for default page
if (!dataFlChart) { // Create chart objects if they don't exist if (!dataChart) { // Create chart objects if they don't exist
GwApi::BoatValue* bValue1 = pageData.values[0]; // Page boat data element GwApi::BoatValue* bValue1 = pageData.values[0]; // Page boat data element
String bValName1 = bValue1->getName(); // Value name String bValName1 = bValue1->getName(); // Value name
String bValFormat = bValue1->getFormat(); // Value format String bValFormat = bValue1->getFormat(); // Value format
@@ -209,8 +215,8 @@ public:
dataHstryBuf = pageData.hstryBuffers->getBuffer(bValName1); dataHstryBuf = pageData.hstryBuffers->getBuffer(bValName1);
if (dataHstryBuf) { if (dataHstryBuf) {
dataFlChart.reset(new Chart<uint16_t>(*dataHstryBuf, 'H', 0, Chart<uint16_t>::dfltChrtDta[bValFormat].range, *commonData, useSimuData)); dataChart.reset(new Chart(*dataHstryBuf, Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
dataHfChart.reset(new Chart<uint16_t>(*dataHstryBuf, 'H', 2, Chart<uint16_t>::dfltChrtDta[bValFormat].range, *commonData, useSimuData)); //dataHfChart.reset(new Chart(*dataHstryBuf, 'H', 2, Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: Created chart objects for %s", bValName1); LOG_DEBUG(GwLog::DEBUG, "PageOneValue: Created chart objects for %s", bValName1);
} else { } else {
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: No chart objects available for %s", bValName1); LOG_DEBUG(GwLog::DEBUG, "PageOneValue: No chart objects available for %s", bValName1);
@@ -249,14 +255,14 @@ public:
showData(bValue1, 'F'); showData(bValue1, 'F');
} else if (pageMode == 'C') { // show only data chart } else if (pageMode == 'C') { // show only data chart
if (dataFlChart) { if (dataChart) {
dataFlChart->showChrt(*bValue1, dataIntv, true); dataChart->showChrt('H', 0, dataIntv, true, *bValue1);
} }
} else if (pageMode == 'B') { // show data value and chart } else if (pageMode == 'B') { // show data value and chart
showData(bValue1, 'H'); showData(bValue1, 'H');
if (dataHfChart) { if (dataChart) {
dataHfChart->showChrt(*bValue1, dataIntv, false); dataChart->showChrt('H', 2, dataIntv, false, *bValue1);
} }
} }

View File

@@ -11,6 +11,15 @@ class PageWindPlot : public Page {
private: private:
GwLog* logger; GwLog* logger;
static constexpr char SHOW_WIND_DIR = 'D';
static constexpr char SHOW_WIND_SPEED = 'S';
static constexpr char SHOW_BOTH = 'B';
static constexpr char HORIZONTAL = 'H';
static constexpr char VERTICAL = 'V';
static constexpr int8_t FULL_SIZE = 0;
static constexpr int8_t HALF_SIZE_TOP = 1;
static constexpr int8_t HALF_SIZE_BOTTOM = 2;
int width; // Screen width int width; // Screen width
int height; // Screen height int height; // Screen height
@@ -37,16 +46,12 @@ private:
RingBuffer<uint16_t>* awsHstry = nullptr; RingBuffer<uint16_t>* awsHstry = nullptr;
// Chart objects // Chart objects
std::unique_ptr<Chart<uint16_t>> twdFlChart, awdFlChart; // Chart object for wind direction, full size std::unique_ptr<Chart> twdChart, awdChart; // Chart object for wind direction, full size
std::unique_ptr<Chart<uint16_t>> twsFlChart, awsFlChart; // Chart object for wind speed, full size std::unique_ptr<Chart> twsChart, awsChart; // Chart object for wind speed, full size
std::unique_ptr<Chart<uint16_t>> twdHfChart, awdHfChart; // Chart object for wind direction, half size
std::unique_ptr<Chart<uint16_t>> twsHfChart, awsHfChart; // Chart object for wind speed, half size
// Active charts and values // Active charts and values
Chart<uint16_t>* wdFlChart = nullptr; Chart* wdChart = nullptr;
Chart<uint16_t>* wsFlChart = nullptr; Chart* wsChart = nullptr;
Chart<uint16_t>* wdHfChart = nullptr;
Chart<uint16_t>* wsHfChart = nullptr;
GwApi::BoatValue* wdBVal = nullptr; GwApi::BoatValue* wdBVal = nullptr;
GwApi::BoatValue* wsBVal = nullptr; GwApi::BoatValue* wsBVal = nullptr;
@@ -86,12 +91,12 @@ public:
{ {
// Set chart mode TWD | TWS // Set chart mode TWD | TWS
if (key == 1) { if (key == 1) {
if (chrtMode == 'D') { if (chrtMode == SHOW_WIND_DIR) {
chrtMode = 'S'; chrtMode = SHOW_WIND_SPEED;
} else if (chrtMode == 'S') { } else if (chrtMode == SHOW_WIND_SPEED) {
chrtMode = 'B'; chrtMode = SHOW_BOTH;
} else { } else {
chrtMode = 'D'; chrtMode = SHOW_WIND_DIR;
} }
return 0; // Commit the key return 0; // Commit the key
} }
@@ -150,39 +155,36 @@ public:
oldShowTruW = !showTruW; // Force chart update in displayPage oldShowTruW = !showTruW; // Force chart update in displayPage
#endif #endif
// buffer initialization cannot be performed here, because <displayNew> is not executed at system start for default page // With chart object initialization being performed here, PageWindPlot won't properly work as default page,
/* if (!twdFlChart) { // Create true wind charts if they don't exist // because <displayNew> is not executed at system start for default page
if (!twdChart) { // Create true wind charts if they don't exist
twdHstry = pageData.hstryBuffers->getBuffer("TWD"); twdHstry = pageData.hstryBuffers->getBuffer("TWD");
twsHstry = pageData.hstryBuffers->getBuffer("TWS"); twsHstry = pageData.hstryBuffers->getBuffer("TWS");
if (twdHstry) { if (twdHstry) {
twdFlChart.reset(new Chart<uint16_t>(*twdHstry, 'V', 0, dfltRngWd, *commonData, useSimuData)); twdChart.reset(new Chart(*twdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
twdHfChart.reset(new Chart<uint16_t>(*twdHstry, 'V', 1, dfltRngWd, *commonData, useSimuData));
} }
if (twsHstry) { if (twsHstry) {
twsFlChart.reset(new Chart<uint16_t>(*twsHstry, 'H', 0, dfltRngWs, *commonData, useSimuData)); twsChart.reset(new Chart(*twsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
twsHfChart.reset(new Chart<uint16_t>(*twsHstry, 'V', 2, dfltRngWs, *commonData, useSimuData));
} }
} }
if (!awdFlChart) { // Create apparent wind charts if they don't exist if (!awdChart) { // Create apparent wind charts if they don't exist
awdHstry = pageData.hstryBuffers->getBuffer("AWD"); awdHstry = pageData.hstryBuffers->getBuffer("AWD");
awsHstry = pageData.hstryBuffers->getBuffer("AWS"); awsHstry = pageData.hstryBuffers->getBuffer("AWS");
if (awdHstry) { if (awdHstry) {
awdFlChart.reset(new Chart<uint16_t>(*awdHstry, 'V', 0, dfltRngWd, *commonData, useSimuData)); awdChart.reset(new Chart(*awdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
awdHfChart.reset(new Chart<uint16_t>(*awdHstry, 'V', 1, dfltRngWd, *commonData, useSimuData));
} }
if (awsHstry) { if (awsHstry) {
awsFlChart.reset(new Chart<uint16_t>(*awsHstry, 'H', 0, dfltRngWs, *commonData, useSimuData)); awsChart.reset(new Chart(*awsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
awsHfChart.reset(new Chart<uint16_t>(*awsHstry, 'V', 2, dfltRngWs, *commonData, useSimuData));
} }
if (twdHstry && twsHstry && awdHstry && awsHstry) { if (twdHstry && twsHstry && awdHstry && awsHstry) {
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Created wind charts"); LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Created wind charts");
} else { } else {
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Some/all chart objects for wind data missing"); LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Some/all chart objects for wind data missing");
} }
} */ }
} }
int displayPage(PageData& pageData) int displayPage(PageData& pageData)
@@ -190,54 +192,46 @@ public:
LOG_DEBUG(GwLog::LOG, "Display PageWindPlot"); LOG_DEBUG(GwLog::LOG, "Display PageWindPlot");
ulong pageTime = millis(); ulong pageTime = millis();
if (!twdFlChart) { // Create true wind charts if they don't exist /* if (!twdChart) { // Create true wind charts if they don't exist
twdHstry = pageData.hstryBuffers->getBuffer("TWD"); twdHstry = pageData.hstryBuffers->getBuffer("TWD");
twsHstry = pageData.hstryBuffers->getBuffer("TWS"); twsHstry = pageData.hstryBuffers->getBuffer("TWS");
if (twdHstry) { if (twdHstry) {
twdFlChart.reset(new Chart<uint16_t>(*twdHstry, 'V', 0, Chart<uint16_t>::dfltChrtDta["formatCourse"].range, *commonData, useSimuData)); twdChart.reset(new Chart(*twdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
twdHfChart.reset(new Chart<uint16_t>(*twdHstry, 'V', 1, Chart<uint16_t>::dfltChrtDta["formatCourse"].range, *commonData, useSimuData)); }
} if (twsHstry) {
if (twsHstry) { twsChart.reset(new Chart(*twsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
twsFlChart.reset(new Chart<uint16_t>(*twsHstry, 'H', 0, Chart<uint16_t>::dfltChrtDta["formatKnots"].range, *commonData, useSimuData)); }
twsHfChart.reset(new Chart<uint16_t>(*twsHstry, 'V', 2, Chart<uint16_t>::dfltChrtDta["formatKnots"].range, *commonData, useSimuData)); }
}
}
if (!awdFlChart) { // Create apparent wind charts if they don't exist if (!awdChart) { // Create apparent wind charts if they don't exist
awdHstry = pageData.hstryBuffers->getBuffer("AWD"); awdHstry = pageData.hstryBuffers->getBuffer("AWD");
awsHstry = pageData.hstryBuffers->getBuffer("AWS"); awsHstry = pageData.hstryBuffers->getBuffer("AWS");
if (awdHstry) { if (awdHstry) {
awdFlChart.reset(new Chart<uint16_t>(*awdHstry, 'V', 0, Chart<uint16_t>::dfltChrtDta["formatCourse"].range, *commonData, useSimuData)); awdChart.reset(new Chart(*awdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
awdHfChart.reset(new Chart<uint16_t>(*awdHstry, 'V', 1, Chart<uint16_t>::dfltChrtDta["formatCourse"].range, *commonData, useSimuData)); }
} if (awsHstry) {
if (awsHstry) { awsChart.reset(new Chart(*awsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
awsFlChart.reset(new Chart<uint16_t>(*awsHstry, 'H', 0, Chart<uint16_t>::dfltChrtDta["formatKnots"].range, *commonData, useSimuData)); }
awsHfChart.reset(new Chart<uint16_t>(*awsHstry, 'V', 2, Chart<uint16_t>::dfltChrtDta["formatKnots"].range, *commonData, useSimuData)); if (twdHstry && twsHstry && awdHstry && awsHstry) {
} LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Created wind charts");
if (twdHstry && twsHstry && awdHstry && awsHstry) { } else {
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Created wind charts"); LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Some/all chart objects for wind data missing");
} else { }
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Some/all chart objects for wind data missing"); } */
}
}
if (showTruW != oldShowTruW) { if (showTruW != oldShowTruW) {
// Switch active charts based on showTruW // Switch active charts based on showTruW
if (showTruW) { if (showTruW) {
wdFlChart = twdFlChart.get(); wdChart = twdChart.get();
wsFlChart = twsFlChart.get(); wsChart = twsChart.get();
wdHfChart = twdHfChart.get();
wsHfChart = twsHfChart.get();
wdBVal = pageData.values[0]; wdBVal = pageData.values[0];
wsBVal = pageData.values[1]; wsBVal = pageData.values[1];
} else { } else {
wdFlChart = awdFlChart.get(); wdChart = awdChart.get();
wsFlChart = awsFlChart.get(); wsChart = awsChart.get();
wdHfChart = awdHfChart.get();
wsHfChart = awsHfChart.get();
wdBVal = pageData.values[2]; wdBVal = pageData.values[2];
wsBVal = pageData.values[3]; wsBVal = pageData.values[3];
} }
@@ -253,22 +247,22 @@ public:
getdisplay().setPartialWindow(0, 0, width, height); // Set partial update getdisplay().setPartialWindow(0, 0, width, height); // Set partial update
getdisplay().setTextColor(commonData->fgcolor); getdisplay().setTextColor(commonData->fgcolor);
if (chrtMode == 'D') { if (chrtMode == SHOW_WIND_DIR) {
if (wdFlChart) { if (wdChart) {
wdFlChart->showChrt(*wdBVal, dataIntv, true); wdChart->showChrt(VERTICAL, FULL_SIZE, dataIntv, true, *wdBVal);
} }
} else if (chrtMode == 'S') { } else if (chrtMode == SHOW_WIND_SPEED) {
if (wsFlChart) { if (wsChart) {
wsFlChart->showChrt(*wsBVal, dataIntv, true); wsChart->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, true, *wsBVal);
} }
} else if (chrtMode == 'B') { } else if (chrtMode == SHOW_BOTH) {
if (wdHfChart) { if (wdChart) {
wdHfChart->showChrt(*wdBVal, dataIntv, true); wdChart->showChrt(VERTICAL, HALF_SIZE_TOP, dataIntv, true, *wdBVal);
} }
if (wsHfChart) { if (wsChart) {
wsHfChart->showChrt(*wsBVal, dataIntv, true); wsChart->showChrt(VERTICAL, HALF_SIZE_BOTTOM, dataIntv, true, *wsBVal);
} }
} }