Merge pull request #241 from Scorgan01/Barograph

Add PageWeather
This commit is contained in:
Norbert Walter
2026-07-03 10:50:42 +02:00
committed by GitHub
15 changed files with 883 additions and 289 deletions
+12 -4
View File
@@ -519,11 +519,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
}
if (String(tempFormat) == "C") {
temp = temp - 273.15;
result.unit = "C";
result.unit = "Deg C";
}
else if (String(tempFormat) == "F") {
temp = (temp - 273.15) * 9 / 5 + 32;
result.unit = "F";
result.unit = "Deg F";
}
else{
result.unit = "K";
@@ -587,7 +587,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
rawvalue = 968 + float(random(0, 10));
pressure = rawvalue;
}
snprintf(buffer, bsize, "%4.0f", pressure);
if (pressure < 999.5) {
snprintf(buffer, bsize, "!%3.0f", pressure);
} else {
snprintf(buffer, bsize, "%4.0f", pressure);
}
result.unit = "hPa";
result.cvalue = pressure;
}
@@ -603,7 +607,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
rawvalue = value->value;
pressure = 968 + float(random(0, 10));
}
snprintf(buffer, bsize, "%4.0f", pressure);
if (pressure < 999.5) {
snprintf(buffer, bsize, "!%3.0f", pressure);
} else {
snprintf(buffer, bsize, "%4.0f", pressure);
}
result.unit = "mBar";
result.cvalue = pressure;
}
+72 -29
View File
@@ -223,13 +223,13 @@ HstryBuf::HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLo
boatValue = boatValues->findValueOrCreate(name);
}
void HstryBuf::init(const String& format, int updFreq, int mltplr, double minVal, double maxVal)
void HstryBuf::init(const String& format, int updFreq, double mltplr, double minVal, double maxVal)
{
hstryBuf.setMetaData(boatDataName, format, updFreq, mltplr, minVal, maxVal);
hstryMin = minVal;
hstryMax = maxVal;
bufUpdateTime = 0;
if (!boatValue->valid) {
boatValue->setFormat(format);
boatValue->value = std::numeric_limits<double>::max(); // mark current value invalid
}
}
@@ -238,25 +238,32 @@ void HstryBuf::add(double value)
{
if (value >= hstryMin && value <= hstryMax) {
hstryBuf.add(value);
// LOG_DEBUG(GwLog::DEBUG, "HstryBuf::add: name: %s, value: %.3f", hstryBuf.getName(), value);
// LOG_DEBUG(GwLog::DEBUG, "HstryBuf::add: name: %s, value: %.3f, value buffer: %.3f", hstryBuf.getName(), value, hstryBuf.getLast());
}
}
void HstryBuf::handle(bool useSimuData, CommonData& common)
{
std::unique_ptr<GwApi::BoatValue> tmpBVal; // Temp variable to get formatted and converted data value from OBP60Formatter
if ((millis() - bufUpdateTime) >= hstryBuf.getUpdFreq()) {
if (boatValue->valid) {
add(boatValue->value);
} else if (useSimuData) { // add simulated value to history buffer
tmpBVal = std::unique_ptr<GwApi::BoatValue>(new GwApi::BoatValue(boatDataName)); // create temporary boat value for retrieval of simulation value
tmpBVal->setFormat(boatValue->getFormat());
tmpBVal->value = boatValue->value;
tmpBVal->valid = boatValue->valid;
double simSIValue = formatValue(tmpBVal.get(), common).value; // simulated value is generated at <formatValue>; here: retreive SI value
add(simSIValue);
} else {
// here we will add invalid (DBL_MAX) value; this will mark periods of missing data in buffer together with a timestamp
bufUpdateTime = millis();
// LOG_DEBUG(GwLog::DEBUG, "HstryBuf::handle: name: %s, frequency: %d, format: %s, value: %.3f", hstryBuf.getName(), hstryBuf.getUpdFreq(),
// boatValue->getFormat().c_str(), boatValue->value);
if (boatValue->valid) {
add(boatValue->value);
} else if (useSimuData) { // add simulated value to history buffer
std::unique_ptr<GwApi::BoatValue> tmpBVal; // Temp variable to get formatted and converted data value from OBP60Formatter
tmpBVal = std::unique_ptr<GwApi::BoatValue>(new GwApi::BoatValue(boatDataName)); // create temporary boat value for retrieval of simulation value
tmpBVal->setFormat(boatValue->getFormat());
tmpBVal->value = boatValue->value;
tmpBVal->valid = boatValue->valid;
double simSIValue = formatValue(tmpBVal.get(), common).value; // simulated value is generated at <formatValue>; here: retreive SI value
add(simSIValue);
} else {
// here we will add invalid (DBL_MAX) value; this will mark periods of missing data in buffer together with a timestamp
}
}
}
// --- End Class HstryBuf ---------------
@@ -273,21 +280,16 @@ void HstryBuffers::addBuffer(const String& name)
if (HstryBuffers::getBuffer(name) != nullptr) { // buffer for this data type already exists
return;
}
if (bufferParams.find(name) == bufferParams.end()) { // requested boat data type is not supported in list of <bufferParams>
auto it = bufferParams.find(name);
if (it == bufferParams.end() && !name.startsWith("xdr")) { // requested boat data type is not supported in list of <bufferParams>
// we take any "XDR" type, though
return;
}
// Initialize metadata for buffer
String valueFormat = bufferParams[name].format; // Data format of boat data type
// String valueFormat = boatValueList->findValueOrCreate(name)->getFormat().c_str(); // Unfortunately, format is not yet available during system initialization
int hstryUpdFreq = bufferParams[name].hstryUpdFreq; // Update frequency for history buffers in ms
int mltplr = bufferParams[name].mltplr; // default multiplier which transforms original <double> value into buffer type format
double bufferMinVal = bufferParams[name].bufferMinVal; // Min value for this history buffer
double bufferMaxVal = bufferParams[name].bufferMaxVal; // Max value for this history buffer
// create buffer only; initialization with metadata can only be done later after boat data have been updated first time
hstryBuffers[name] = std::unique_ptr<HstryBuf>(new HstryBuf(name, size, boatValueList, logger));
hstryBuffers[name]->init(valueFormat, hstryUpdFreq, mltplr, bufferMinVal, bufferMaxVal);
LOG_DEBUG(GwLog::DEBUG, "HstryBuffers: new buffer added: name: %s, format: %s, multiplier: %d, min value: %.2f, max value: %.2f", name, valueFormat, mltplr, bufferMinVal, bufferMaxVal);
LOG_DEBUG(GwLog::DEBUG, "HstryBuffers: new buffer added: name: %s", name);
}
// Handle all registered history buffers
@@ -295,6 +297,35 @@ void HstryBuffers::handleHstryBufs(bool useSimuData, CommonData& common)
{
for (auto& bufMap : hstryBuffers) {
auto& buf = bufMap.second;
if (!buf->hasMetaData()) { // meta data initialization for buffer has not been done before
String valueFormat = boatValueList->findValueOrCreate(buf->boatDataName)->getFormat().c_str();
LOG_DEBUG(GwLog::DEBUG, "HstryBuffers: value name: %s, format: %s", boatValueList->findValueOrCreate(buf->boatDataName)->getName().c_str(), valueFormat);
if (!valueFormat.isEmpty()) {
String lookupKey = buf->boatDataName;
if (buf->boatDataName.startsWith("xdr")) { // current boat data is of type "XDR"
lookupKey = valueFormat;
}
auto it = bufferParams.find(lookupKey);
if (it == bufferParams.end()) { // requested boat data type is not supported in list of <bufferParams>
return;
}
HistoryParams params = it->second; // this is the metadata for the new buffer
int hstryUpdFreq = params.hstryUpdFreq; // Update frequency for history buffers in ms
double mltplr = params.mltplr; // default multiplier which transforms original <double> value into buffer type format
double bufferMinVal = params.bufferMinVal; // Min value for this history buffer
double bufferMaxVal = params.bufferMaxVal; // Max value for this history buffer
hstryBuffers[buf->boatDataName]->init(valueFormat, hstryUpdFreq, mltplr, bufferMinVal, bufferMaxVal);
buf->metaDataDefined = true;
LOG_DEBUG(GwLog::DEBUG, "HstryBuffers::handleBufs: metadata added: name: %s, format: %s, frequency: %d, multiplier: %f, min value: %.2f, max value: %.2f", buf->boatDataName, valueFormat, hstryUpdFreq,
mltplr, bufferMinVal, bufferMaxVal);
}
}
buf->handle(useSimuData, common);
}
}
@@ -461,10 +492,24 @@ bool WindUtils::calcTrueWinds(const double* awaVal, const double* awsVal, const
return true;
}
// Set max wind speed
void WindUtils::setMaxWs(GwApi::BoatValue* wsMaxValue, const double* wsVal)
{
static double maxWs = 0.0; // maintain own maxTWS value in obp user task; core gateway would reset MaxTWS obp boat value if true wind data is not available
if (*wsVal != DBL_MAX && *wsVal > maxWs) {
maxWs = *wsVal;
}
if ( maxWs > 0.0 && maxWs >= wsMaxValue->value) {
wsMaxValue->value = maxWs; // overwrite core gateway value each second again with own user task value if that value is larger
wsMaxValue->valid = true;
}
};
// Calculate true wind data and add to obp60task boat data list
bool WindUtils::handleWinds(bool calcWinds)
{
double twd, tws, twa, awd;
bool twCalculated = false;
double awaVal = awaBVal->valid ? awaBVal->value : DBL_MAX;
@@ -477,8 +522,6 @@ bool WindUtils::handleWinds(bool calcWinds)
double varVal = varBVal->valid ? varBVal->value : DBL_MAX;
double twaVal = twaBVal->valid ? twaBVal->value : DBL_MAX;
double twsVal = twsBVal->valid ? twsBVal->value : DBL_MAX;
// LOG_DEBUG(GwLog::DEBUG, "WindUtils:handleWinds: AWA %.1f, AWS %.1f, AWD %.1f, COG %.1f, STW %.1f, SOG %.2f, HDT %.1f, HDM %.1f, VAR %.1f", awaVal * RAD_TO_DEG, awsVal * 3.6 / 1.852,
// awd * RAD_TO_DEG, cogVal * RAD_TO_DEG, stwVal * 3.6 / 1.852, sogVal * 3.6 / 1.852, hdtVal * RAD_TO_DEG, hdmVal * RAD_TO_DEG, varVal * RAD_TO_DEG);
if (calcHDT(&hdmVal, &varVal, &cogVal, &sogVal, &hdtVal)) {
hdtBVal->value = hdtVal;
+37 -22
View File
@@ -39,6 +39,8 @@ private:
String boatDataName;
double hstryMin;
double hstryMax;
bool metaDataDefined = false;
unsigned long bufUpdateTime;
GwApi::BoatValue* boatValue;
GwLog* logger;
@@ -46,7 +48,8 @@ private:
public:
HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLog* log);
void init(const String& format, int updFreq, int mltplr, double minVal, double maxVal);
bool hasMetaData() const { return metaDataDefined; };
void init(const String& format, int updFreq, double mltplr, double minVal, double maxVal);
void add(double value);
void handle(bool useSimuData, CommonData& common);
};
@@ -61,31 +64,39 @@ private:
struct HistoryParams {
int hstryUpdFreq; // update frequency of history buffer (documentation only)
int mltplr; // specifies actual value precision being storable:
// [10000: 0 - 6.5535 | 1000: 0 - 65.535 | 100: 0 - 650.35 | 10: 0 - 6503.5
double mltplr; // specifies actual value precision being storable:
// [10000: 0 - 6.5535 | 1000: 0 - 65.535 | 100: 0 - 655.35 | 10: 0 - 6553.5 | 1: 0 - 65535 | 0.1: 0 - 655350]
double bufferMinVal; // minimum valid data value
double bufferMaxVal; // maximum valid data value
String format; // format of data type
};
// Define buffer parameters for supported boat data type
std::map<String, HistoryParams> bufferParams = {
{ "AWA", { 1000, 10000, 0.0, M_TWOPI, "formatWind" } },
{ "AWD", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
{ "AWS", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
{ "COG", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
{ "DBS", { 1000, 100, 0.0, 650.0, "formatDepth" } },
{ "DBT", { 1000, 100, 0.0, 650.0, "formatDepth" } },
{ "DPT", { 1000, 100, 0.0, 650.0, "formatDepth" } },
{ "HDM", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
{ "HDT", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
{ "ROT", { 1000, 10000, -M_PI / 180.0 * 99.0, M_PI / 180.0 * 99.0, "formatRot" } }, // min/max is -/+ 99 degrees for "rate of turn"
{ "SOG", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
{ "STW", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
{ "TWA", { 1000, 10000, 0.0, M_TWOPI, "formatWind" } },
{ "TWD", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
{ "TWS", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
{ "WTemp", { 1000, 100, 233.0, 650.0, "kelvinToC" } } // [-50..376] °C
{ "AWA", { 1000, 10000, 0.0, M_TWOPI } },
{ "AWD", { 1000, 10000, 0.0, M_TWOPI } },
{ "AWS", { 1000, 1000, 0.0, 65.0 } },
{ "COG", { 1000, 10000, 0.0, M_TWOPI } },
{ "DBK", { 1000, 100, 0.0, 650.0 } },
{ "DBS", { 1000, 100, 0.0, 650.0 } },
{ "DBT", { 1000, 100, 0.0, 650.0 } },
{ "DPT", { 1000, 100, 0.0, 650.0 } },
{ "HDM", { 1000, 10000, 0.0, M_TWOPI } },
{ "HDT", { 1000, 10000, 0.0, M_TWOPI } },
{ "ROT", { 1000, 10000, -M_PI / 180.0 * 99.0, M_PI / 180.0 * 99.0 } }, // min/max is -/+ 99 degrees for "rate of turn"
{ "SOG", { 1000, 1000, 0.0, 65.0 } },
{ "STW", { 1000, 1000, 0.0, 65.0 } },
{ "TWA", { 1000, 10000, 0.0, M_TWOPI } },
{ "TWD", { 1000, 10000, 0.0, M_TWOPI } },
{ "TWS", { 1000, 1000, 0.0, 65.0 } },
{ "WTemp", { 1000, 100, 263.15, 403.15 } }, // water temp [-10..130] °C
{ "formatXdr:C:K", { 1000, 100, 223.15, 423.15 } }, // temperature [-50..150] deg celsius
{ "formatXdr:P:B", { 60000, 1000, 0, 65.0 } }, // pressure [0..65] bar
{ "formatXdr:P:P", { 60000, 0.1, 0, 650000 } }, // pressure [0..6500] hPa
{ "formatXdr:H:P", { 1000, 100, 0, 100 } }, // humidity [0..100] percent
{ "formatXdr:I:A", { 1000, 100, 0, 650.0 } }, // current [0..650] amperes
{ "formatXdr:U:V", { 1000, 1000, 0, 65.0 } }, // voltage [0..65] volts
{ "formatXdr:T:R", { 1000, 1, 0, 30000 } }, // tachometer [0..30000] rpm
{ "formatXdr:V:L", { 10000, 100, 0, 650 } }, // volume [0..650] litres
{ "formatXdr:V:M", { 10000, 10000, 0, 6.50 } }, // volume [0..6.5] m^3
};
public:
@@ -97,9 +108,10 @@ public:
class WindUtils {
private:
GwApi::BoatValue *twaBVal, *twsBVal, *twdBVal;
GwApi::BoatValue *twaBVal, *twsBVal, *twdBVal, *maxtwsBVal;
GwApi::BoatValue *awaBVal, *awsBVal, *awdBVal;
GwApi::BoatValue *cogBVal, *stwBVal, *sogBVal, *hdtBVal, *hdmBVal, *varBVal;
double twd, tws, twa, awd;
static constexpr double DBL_MAX = std::numeric_limits<double>::max();
GwLog* logger;
@@ -109,6 +121,7 @@ public:
{
twaBVal = boatValues->findValueOrCreate("TWA");
twsBVal = boatValues->findValueOrCreate("TWS");
maxtwsBVal = boatValues->findValueOrCreate("MaxTws");
twdBVal = boatValues->findValueOrCreate("TWD");
awaBVal = boatValues->findValueOrCreate("AWA");
awsBVal = boatValues->findValueOrCreate("AWS");
@@ -137,5 +150,7 @@ public:
bool calcTrueWinds(const double* awaVal, const double* awsVal, const double* awd,
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
double* twdVal, double* twsVal, double* twaVal);
void setMaxWs(GwApi::BoatValue *wsMaxValue, const double * wsVal);
void setMaxWs() { setMaxWs(maxtwsBVal, &tws); };
bool handleWinds(bool calcWinds);
};
+7 -5
View File
@@ -45,9 +45,9 @@ private:
size_t last; // Points to the last (newest) valid element
size_t count; // Number of valid elements currently in buffer
bool is_Full; // Indicates that all buffer elements are used and ringing is in use
T MIN_VAL; // lowest possible value of buffer of type <T>
T MAX_VAL; // highest possible value of buffer of type <T> -> indicates invalid value in buffer
double dblMIN_VAL, dblMAX_VAL; // MIN_VAL, MAX_VAL in double format
T NUMLIMIT_LOW; // internally lowest possible value of buffer of type <T>
T NUMLIMIT_HIGH; // internally highest possible value of buffer of type <T>
double BUFMIN_VAL, BUFMAX_VAL; // lowest/highest possible buffer value considering multiplier -> externally used
mutable SemaphoreHandle_t bufLocker;
// metadata for buffer
@@ -55,8 +55,8 @@ private:
String dataFmt; // Format of boat data in buffer
int updFreq; // Update frequency in milliseconds
double mltplr; // Multiplier which transforms original <double> value into buffer type format
double smallest; // Value range of buffer: smallest value; needs to be => MIN_VAL
double largest; // Value range of buffer: biggest value; needs to be < MAX_VAL, since MAX_VAL indicates invalid entries
double lowest; // low value range for boat data in this buffer; needs to be => BUFMIN_VAL
double highest; // high value range for boat data in this buffer; needs to be < BUFMAX_VAL, since BUFMAX_VAL indicates invalid entries
void initCommon();
@@ -64,10 +64,12 @@ public:
RingBuffer();
RingBuffer(size_t size);
void setMetaData(String name, String format, int updateFrequency, double multiplier, double minValue, double maxValue); // Set meta data for buffer
void setFormat(String format); // Specify format of buffer
bool getMetaData(String& name, String& format, int& updateFrequency, double& multiplier, double& minValue, double& maxValue); // Get meta data of buffer
bool getMetaData(String& name, String& format);
String getName() const; // Get buffer name
String getFormat() const; // Get buffer data format
int getUpdFreq() const; // Get buffer update frequency
void add(const double& value); // Add a new value to buffer
double get(size_t index) const; // Get value at specific position (0-based index from oldest to newest)
double getFirst() const; // Get the first (oldest) value in buffer
+52 -95
View File
@@ -6,16 +6,16 @@
template <typename T>
void RingBuffer<T>::initCommon()
{
MIN_VAL = std::numeric_limits<T>::lowest();
MAX_VAL = std::numeric_limits<T>::max();
dblMIN_VAL = static_cast<double>(MIN_VAL);
dblMAX_VAL = static_cast<double>(MAX_VAL);
NUMLIMIT_LOW = std::numeric_limits<T>::lowest();
NUMLIMIT_HIGH = std::numeric_limits<T>::max();
dataName = "";
dataFmt = "";
updFreq = -1;
mltplr = 1;
smallest = dblMIN_VAL;
largest = dblMAX_VAL;
BUFMIN_VAL = static_cast<double>(NUMLIMIT_LOW);
BUFMAX_VAL = static_cast<double>(NUMLIMIT_HIGH);
lowest = BUFMIN_VAL;
highest = BUFMAX_VAL;
bufLocker = xSemaphoreCreateMutex();
}
@@ -44,7 +44,7 @@ RingBuffer<T>::RingBuffer(size_t size)
initCommon();
buffer.reserve(size);
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values
buffer.resize(size, NUMLIMIT_HIGH); // NUMLIMIT_HIGH indicate invalid values
}
// Specify meta data of buffer content
@@ -56,8 +56,18 @@ void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency,
dataFmt = format;
updFreq = updateFrequency;
mltplr = multiplier;
smallest = std::max(dblMIN_VAL, minValue);
largest = std::min(dblMAX_VAL, maxValue);
BUFMIN_VAL = static_cast<double>(NUMLIMIT_LOW) / mltplr; // lowest possible buffer value; converted to external view
BUFMAX_VAL = static_cast<double>(NUMLIMIT_HIGH) / mltplr; // highest possible buffer value; converted to external view
lowest = std::max(BUFMIN_VAL, minValue); // low value range, set by user
highest = std::min(std::nextafter(BUFMAX_VAL, -std::numeric_limits<double>::infinity()), maxValue); // high value range, set by user; max. is 1 tick smaller than BUFMAX_VAL
}
// Specify format of buffer content
template <typename T>
void RingBuffer<T>::setFormat(String format)
{
GWSYNCHRONIZED(&bufLocker);
dataFmt = format;
}
// Get meta data of buffer content
@@ -73,8 +83,8 @@ bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequen
format = dataFmt;
updateFrequency = updFreq;
multiplier = mltplr;
minValue = smallest;
maxValue = largest;
minValue = lowest;
maxValue = highest;
return true;
}
@@ -106,13 +116,20 @@ String RingBuffer<T>::getFormat() const
return dataFmt;
}
// Get buffer update frequency
template <typename T>
int RingBuffer<T>::getUpdFreq() const
{
return updFreq;
}
// Add a new value to buffer
template <typename T>
void RingBuffer<T>::add(const double& value)
{
GWSYNCHRONIZED(&bufLocker);
if (value < smallest || value > largest) {
buffer[head] = MAX_VAL; // Store MAX_VAL if value is out of range
if (value < lowest || value > highest) {
buffer[head] = NUMLIMIT_HIGH; // Store maximum buffer value if data value is out of range
} else {
buffer[head] = static_cast<T>(std::round(value * mltplr));
}
@@ -136,11 +153,11 @@ double RingBuffer<T>::get(size_t index) const
{
GWSYNCHRONIZED(&bufLocker);
if (isEmpty() || index < 0 || index >= count) {
return dblMAX_VAL;
return BUFMAX_VAL;
}
size_t realIndex = (first + index) % capacity;
return static_cast<double>(buffer[realIndex] / mltplr);
return static_cast<double>(buffer[realIndex] / mltplr); // is BUFMAX_VAL if value is invalid
}
// Operator[] for convenient access (same as get())
@@ -155,7 +172,7 @@ template <typename T>
double RingBuffer<T>::getFirst() const
{
if (isEmpty()) {
return dblMAX_VAL;
return BUFMAX_VAL;
}
return get(0);
}
@@ -165,7 +182,7 @@ template <typename T>
double RingBuffer<T>::getLast() const
{
if (isEmpty()) {
return dblMAX_VAL;
return BUFMAX_VAL;
}
return get(count - 1);
}
@@ -174,19 +191,7 @@ double RingBuffer<T>::getLast() const
template <typename T>
double RingBuffer<T>::getMin() const
{
if (isEmpty()) {
return dblMAX_VAL;
}
double minVal = dblMAX_VAL;
double value;
for (size_t i = 0; i < count; i++) {
value = get(i);
if (value < minVal && value != dblMAX_VAL) {
minVal = value;
}
}
return minVal;
return getMin(getCurrentSize());
}
// Get minimum value of the last <amount> values of buffer
@@ -194,16 +199,16 @@ template <typename T>
double RingBuffer<T>::getMin(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return dblMAX_VAL;
return BUFMAX_VAL;
}
if (amount > count)
amount = count;
double minVal = dblMAX_VAL;
double minVal = BUFMAX_VAL;
double value;
for (size_t i = 0; i < amount; i++) {
value = get(count - 1 - i);
if (value < minVal && value != dblMAX_VAL) {
if (value < minVal && value != BUFMAX_VAL) {
minVal = value;
}
}
@@ -214,22 +219,7 @@ double RingBuffer<T>::getMin(size_t amount) const
template <typename T>
double RingBuffer<T>::getMax() const
{
if (isEmpty()) {
return dblMAX_VAL;
}
double maxVal = dblMIN_VAL;
double value;
for (size_t i = 0; i < count; i++) {
value = get(i);
if (value > maxVal && value != dblMAX_VAL) {
maxVal = value;
}
}
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
maxVal = dblMAX_VAL;
}
return maxVal;
return getMax(getCurrentSize());
}
// Get maximum value of the last <amount> values of buffer
@@ -237,21 +227,21 @@ template <typename T>
double RingBuffer<T>::getMax(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return dblMAX_VAL;
return BUFMAX_VAL;
}
if (amount > count)
amount = count;
double maxVal = dblMIN_VAL;
double maxVal = BUFMIN_VAL;
double value;
for (size_t i = 0; i < amount; i++) {
value = get(count - 1 - i);
if (value > maxVal && value != dblMAX_VAL) {
if (value > maxVal && value != BUFMAX_VAL) {
maxVal = value;
}
}
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
maxVal = dblMAX_VAL;
if (maxVal == BUFMIN_VAL) { // no change of initial value -> buffer has only invalid values (BUFMAX_VAL)
maxVal = BUFMAX_VAL;
}
return maxVal;
}
@@ -260,11 +250,7 @@ double RingBuffer<T>::getMax(size_t amount) const
template <typename T>
double RingBuffer<T>::getMid() const
{
if (isEmpty()) {
return dblMAX_VAL;
}
return (getMin() + getMax()) / 2;
return getMid(getCurrentSize());
}
// Get mid value between <min> and <max> value of the last <amount> values of buffer
@@ -272,7 +258,7 @@ template <typename T>
double RingBuffer<T>::getMid(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return dblMAX_VAL;
return BUFMAX_VAL;
}
if (amount > count)
@@ -285,29 +271,7 @@ double RingBuffer<T>::getMid(size_t amount) const
template <typename T>
double RingBuffer<T>::getMedian() const
{
if (isEmpty()) {
return dblMAX_VAL;
}
// Create a temporary vector with current valid elements
std::vector<T> temp;
temp.reserve(count);
for (size_t i = 0; i < count; i++) {
temp.push_back(get(i));
}
// Sort to find median
std::sort(temp.begin(), temp.end());
if (count % 2 == 1) {
// Odd number of elements
return static_cast<double>(temp[count / 2]);
} else {
// Even number of elements - return average of middle two
// Note: For integer types, this truncates. For floating point, it's exact.
return static_cast<double>((temp[count / 2 - 1] + temp[count / 2]) / 2);
}
return getMedian(getCurrentSize());
}
// Get the median value of the last <amount> values of buffer
@@ -315,7 +279,7 @@ template <typename T>
double RingBuffer<T>::getMedian(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return dblMAX_VAL;
return BUFMAX_VAL;
}
if (amount > count)
amount = count;
@@ -387,14 +351,14 @@ bool RingBuffer<T>::isFull() const
template <typename T>
double RingBuffer<T>::getMinVal() const
{
return dblMIN_VAL;
return BUFMIN_VAL;
}
// Get highest possible value for buffer; used for unset/invalid buffer data
template <typename T>
double RingBuffer<T>::getMaxVal() const
{
return dblMAX_VAL;
return BUFMAX_VAL;
}
// Clear buffer
@@ -423,21 +387,14 @@ void RingBuffer<T>::resize(size_t newSize)
buffer.clear();
buffer.reserve(newSize);
buffer.resize(newSize, MAX_VAL);
buffer.resize(newSize, NUMLIMIT_HIGH);
}
// Get all current values in native buffer format as a vector
template <typename T>
std::vector<double> RingBuffer<T>::getAllValues() const
{
std::vector<double> result;
result.reserve(count);
for (size_t i = 0; i < count; i++) {
result.push_back(get(i));
}
return result;
return getAllValues(getCurrentSize());
}
// Get last <amount> values in native buffer format as a vector
+177 -107
View File
@@ -3,16 +3,6 @@
#include "OBPDataOperations.h"
#include "OBPRingBuffer.h"
// Default ranges for various boat data types: 1st value default range, 2nd value step for range adjustment
// should be multiple of 4 for full integer chart labels w/o decimals
std::map<String, ChartProps> Chart::dfltChrtDta = {
{ "formatWind", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default wind range 60 degrees
{ "formatCourse", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
{ "formatKnots", { 2.572, 2.572 } }, // default speed range in m/s
{ "formatDepth", { 10.0, 5.0 } }, // default depth range in m
{ "kelvinToC", { 20.0, 5.0 } } // default temp range in °C/K
};
// --- Class Chart ---------------
// Chart - object holding the actual chart, incl. data buffer and format definition
@@ -20,9 +10,8 @@ std::map<String, ChartProps> Chart::dfltChrtDta = {
// <dfltRng> default range of chart, e.g. 30 = [0..30]
// <common> common program data; required for logger and color data
// <useSimuData> flag to indicate if simulation data is active
Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData)
Chart::Chart(RingBuffer<uint16_t>& dataBuf, CommonData& common, bool useSimuData)
: dataBuf(dataBuf)
, dfltRng(dfltRng)
, commonData(&common)
, useSimuData(useSimuData)
{
@@ -30,41 +19,60 @@ Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common,
fgColor = commonData->fgcolor;
bgColor = commonData->bgcolor;
// display dimensions (avoid calling width()/height() on incomplete LGFX type)
#ifdef TFT_DISPLAY
dWidth = 480;
dHeight = 320;
#else
dWidth = getdisplay().width();
dHeight = getdisplay().height();
#endif
// display dimensions (avoid calling width()/height() on incomplete LGFX type)
#ifdef TFT_DISPLAY
dWidth = 480;
dHeight = 320;
#else
dWidth = getdisplay().width();
dHeight = getdisplay().height();
#endif
smoothCharts = commonData->config->getBool(commonData->config->smoothCharts);
if (smoothCharts) {
chrtAvg.begin();
}
init();
};
Chart::~Chart()
{
}
bool Chart::init()
{
chrtMin = 0.0;
chrtMax = 0.0;
chrtMid = 0.0;
chrtRng = 0.0;
dataBuf.getMetaData(dbName, dbFormat);
dbMIN_VAL = dataBuf.getMinVal();
dbMAX_VAL = dataBuf.getMaxVal();
bufSize = dataBuf.getCapacity();
smoothCharts = common.config->getBool(common.config->smoothCharts);
if (smoothCharts) {
chrtAvg.begin();
}
LOG_DEBUG(GwLog::DEBUG, "Chart Init: dbMIN_VAL: %.2f, dbMAX_VAL: %.2fd, bufSize: %d", dbMIN_VAL, dbMAX_VAL, bufSize);
// Initialize chart data format; shorter version of standard format indicator
if (dbFormat == "formatCourse" || dbFormat == "formatWind" || dbFormat == "formatRot") {
if (dbFormat == "formatCourse" || dbFormat == "formatWind") {
chrtDataFmt = WIND; // Chart is showing data of course / wind <degree> format
} else if (dbFormat == "formatRot") {
chrtDataFmt = ROTATION; // Chart is showing data of rotational <degree> format
} else if (dbFormat == "formatKnots") {
chrtDataFmt = SPEED; // Chart is showing data of speed or windspeed format
} else if (dbFormat == "formatDepth") {
chrtDataFmt = DEPTH; // Chart ist showing data of <depth> format
chrtDataFmt = DEPTH;
} else if (dbFormat == "kelvinToC") {
chrtDataFmt = TEMPERATURE; // Chart ist showing data of <temp> format
chrtDataFmt = TEMPERATURE;
} else if (dbFormat.startsWith("formatXdr:P")) {
chrtDataFmt = PRESSURE;
} else if (dbFormat.startsWith("formatXdr:H")) {
chrtDataFmt = HUMIDITY;
} else {
chrtDataFmt = OTHER; // Chart is showing any other data format
}
// "0" value is the same for any data format but for user defined temperature format
// "0" value is the same for any data format but for user defined temperature and pressure format
zeroValue = 0.0;
if (chrtDataFmt == TEMPERATURE) {
tempFormat = commonData->config->getString(commonData->config->tempFormat); // [K|°C|°F]
@@ -75,6 +83,8 @@ Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common,
} else if (tempFormat == "F") {
zeroValue = 255.37;
}
} else if (chrtDataFmt == PRESSURE) {
zeroValue = 98000.0; // typical low pressure area value
}
// Read default range and range step for this chart type
@@ -91,14 +101,18 @@ Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common,
chrtMax = chrtMin + dfltRng;
chrtMid = (chrtMin + chrtMax) / 2;
chrtRng = dfltRng;
recalcRngMid = true; // initialize <chrtMid> and chart borders on first screen call
recalcRngMid = true; // initialize <chrtMid> and chart borders on first chart display call
LOG_DEBUG(GwLog::DEBUG, "Chart Init: dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot {x,y}: %d, %d, dbname: %s, rngStep: %.4f, chrtDataFmt: %d",
dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, dbName, rngStep, chrtDataFmt);
};
if (dbFormat.isEmpty()) {
// data buffer may not exist yet, because boat data object is not available yet
initValid = false; // chart object will get invalid data during initialization
} else {
initValid = true;
}
LOG_DEBUG(GwLog::DEBUG, "Chart Init: dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot {x,y}: %d, %d, dbname: %s, rngStep: %.4f, chrtDataFmt: %d, initValid: %d",
dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, dbName, rngStep, chrtDataFmt, initValid);
Chart::~Chart()
{
return isValid();
}
// Perform all actions to draw chart
@@ -108,7 +122,8 @@ Chart::~Chart()
// <prntName>; print data name on horizontal half chart [true|false]
// <showCurrValue>: print current boat data value [true|false]
// <currValue>: current boat data value; used only for test on valid data
void Chart::showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue)
// void Chart::showChrt(ChrtDirection chrtDire, ChrtSize chrtSze, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue)
void Chart::showChrt(const char chrtDir, const int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue)
{
if (!setChartDimensions(chrtDir, chrtSz)) {
return; // wrong chart dimension parameters
@@ -123,17 +138,18 @@ void Chart::showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool pr
return;
}
if (showCurrValue) { // show latest value from history buffer; this should be the most current one
currValue.value = dataBuf.getLast();
if (showCurrValue) {
currValue.value = dataBuf.getLast(); // show latest value from history buffer; this should be the most current one
currValue.valid = currValue.value != dbMAX_VAL;
prntCurrValue(chrtDir, currValue);
}
}
// define dimensions and start points for chart
// bool Chart::setChartDimensions(const ChrtDirection direction, const ChrtSize size)
bool Chart::setChartDimensions(const char direction, const int8_t size)
{
if ((direction != HORIZONTAL && direction != VERTICAL) || (size < 0 || size > 2)) {
if ((direction != HORIZONTAL && direction != VERTICAL) || (size < 0 || size > 3)) {
LOG_DEBUG(GwLog::ERROR, "obp60:setChartDimensions %s: wrong parameters", dataBuf.getName());
return false;
}
@@ -154,6 +170,13 @@ bool Chart::setChartDimensions(const char direction, const int8_t size)
valAxis = (dHeight - top - bottom) / 2 - hGap;
cRoot = { 0, top + (valAxis + hGap) + hGap - 1 };
break;
case 3:
valAxis = (dHeight - top - bottom) * 0.667 - hGap;
cRoot = { 0, top - 1 };
break;
default: // same as case 0; should never happen
valAxis = dHeight - top - bottom;
cRoot = { 0, top - 1 };
}
} else if (direction == VERTICAL) {
@@ -172,10 +195,13 @@ bool Chart::setChartDimensions(const char direction, const int8_t size)
valAxis = dWidth / 2 - vGap;
cRoot = { dWidth / 2 + vGap - 1, top - 1 };
break;
default: // same as case 0; should never happen
valAxis = dWidth - 1;
cRoot = { 0, top - 1 };
}
}
//LOG_DEBUG(GwLog::DEBUG, "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);
// LOG_DEBUG(GwLog::DEBUG, "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;
}
@@ -186,10 +212,10 @@ void Chart::drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue
getBufferStartNSize(chrtIntv);
// LOG_DEBUG(GwLog::DEBUG, "Chart: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);
chrtScale = double(valAxis) / chrtRng; // Chart scale: pixels per value step
// LOG_DEBUG(GwLog::DEBUG, "Chart: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, data valid: %d", chrtMin, chrtMid, chrtMax, chrtRng, currValue.valid);
// Do we have valid buffer data?
if (dataBuf.getMax() == dbMAX_VAL) { // only <MAX_VAL> values in buffer -> no valid wind data available
@@ -204,7 +230,8 @@ void Chart::drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue
numNoData++;
bufDataValid = true;
if (numNoData > THRESHOLD_NO_DATA) { // If more than 4 invalid values in a row, flag for invalid data
// if (numNoData > THRESHOLD_NO_DATA) { // If more than 4 invalid values in a row, flag for invalid data
if (numNoData > THRESHOLD_NO_DATA * (dataBuf.getUpdFreq() / 1000)) { // If more than <THRESHOLD> invalid values in a row, flag for invalid data
bufDataValid = false;
return;
}
@@ -219,17 +246,15 @@ void Chart::getBufferStartNSize(const int8_t chrtIntv)
count = dataBuf.getCurrentSize();
currIdx = dataBuf.getLastIdx();
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
lastAddedIdx = currIdx;
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
if (chrtIntv != oldChrtIntv || count == 1) { // new data interval selected by user
numBufVals = min(count, (timAxis - MIN_FREE_VALUES) * chrtIntv); // keep free or release MIN_FREE_VALUES on chart for plotting of new values
bufStart = max(0, count - numBufVals);
lastAddedIdx = currIdx;
oldChrtIntv = chrtIntv;
} else {
numBufVals = numBufVals + numAddedBufVals;
lastAddedIdx = currIdx;
if (count == bufSize) {
bufStart = max(0, bufStart - numAddedBufVals);
}
@@ -308,8 +333,15 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
double currMinVal = dataBuf.getMin(numBufVals);
double currMaxVal = dataBuf.getMax(numBufVals);
if (currMinVal == dbMAX_VAL || currMaxVal == dbMAX_VAL) {
return; // no valid data
if (currMinVal == dbMAX_VAL || currMaxVal == dbMAX_VAL) { // no valid data
auto chkIsNaN = [](double& val) { if (std::isnan(val)) val = 0.0; }; // define inline function
// range values can be undefined if boat data type has not been created at time of chart printing (e.g. XDR data types)
// we set them to "0.0" then
chkIsNaN(rngMin);
chkIsNaN(rngMid);
chkIsNaN(rngMax);
chkIsNaN(rng);
return;
}
// check if current chart border have to be adjusted
@@ -333,8 +365,8 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
rngMid = (rngMin + rngMax) / 2.0;
rng = rngMax - rngMin;
// LOG_DEBUG(GwLog::DEBUG, "calcChrtRange-end: currMinVal: %.1f, currMaxVal: %.1f, rngMin: %.1f, rngMid: %.1f, rngMax: %.1f, rng: %.1f, rngStep: %.1f, zeroValue: %.1f, dbMIN_VAL: %.1f",
// currMinVal, currMaxVal, rngMin, rngMid, rngMax, rng, rngStep, zeroValue, dbMIN_VAL);
LOG_DEBUG(GwLog::DEBUG, "calcChrtRange-end: currMinVal: %.1f, currMaxVal: %.1f, rngMin: %.1f, rngMid: %.1f, rngMax: %.1f, rng: %.1f, rngStep: %.1f, zeroValue: %.1f, dbMIN_VAL: %.1f",
currMinVal, currMaxVal, rngMin, rngMid, rngMax, rng, rngStep, zeroValue, dbMIN_VAL);
}
}
@@ -354,7 +386,7 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do
// Calculate index with wrapping: (start - offset + size) % size
int primeIdx = (bufStart - (p * chrtIntv));
double primeVal = dataBuf.get(primeIdx);
if (primeVal != dbMAX_VAL) {
chrtAvg.reading(primeVal);
}
@@ -376,8 +408,8 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do
point = setCurrentChartPoint(i, direction, chrtVal, chrtScale);
// if (i >= (numBufVals / chrtIntv) - 5) // log chart data of 1 line (adjust for test purposes)
// LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %.2f, chrtMin: %.2f, {x,y} {%d,%d}", i, chrtVal, chrtMin, x, y);
if (i >= (numBufVals / chrtIntv) - 5) // log chart data of 1 line (adjust for test purposes)
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %.2f, chrtMin: %.2f, {x,y} {%d,%d}", i, chrtVal, chrtMin, x, y);
if ((i == 0) || (chrtPrevVal == dbMAX_VAL)) {
// just a dot for 1st chart point or after some invalid values
@@ -447,10 +479,10 @@ Pos Chart::setCurrentChartPoint(const int i, const char direction, const double
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) { // degree type value
currentPoint.y = cRoot.y + static_cast<int>((WindUtils::to2PI(chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
} else if (chrtDataFmt == SPEED or chrtDataFmt == TEMPERATURE) { // speed or temperature data format -> print low values at bottom
currentPoint.y = cRoot.y + valAxis - static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
} else { // any other data format
} else if (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) { // print low values at bottom
currentPoint.y = cRoot.y + static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
} else { // any other data format
currentPoint.y = cRoot.y + valAxis - static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
}
} else { // vertical chart
@@ -532,7 +564,8 @@ void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntNa
font = &Ubuntu_Bold12pt8b;
getdisplay().setFont(font);
getdisplay().fillRect(cRoot.x + timAxis - 57, cRoot.y + 2, 58, 20, bgColor); // clear small area to remove potential chart lines
drawTextRalign(cRoot.x + timAxis, cRoot.y + 19, dbName.substring(0, 5));
String name = xdrDelete(dbName); // Value name
drawTextRalign(cRoot.x + timAxis - 1, cRoot.y + 19, name.substring(0, 5));
if (chrtDataFmt == WIND) {
prntHorizChartThreeValueAxisLabel(font);
@@ -548,10 +581,11 @@ void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntNa
font = &Ubuntu_Bold10pt8b;
if (prntName) {
// print buffer data name on right hand side of time axis (max. size 5 characters)
// print buffer data name on right hand side of time axis (max. size 6 characters)
getdisplay().setFont(font);
getdisplay().fillRect(cRoot.x + timAxis - 57, cRoot.y + 2, 58, 20, bgColor); // clear small area to remove potential chart lines
drawTextRalign(cRoot.x + timAxis, cRoot.y + 16, dbName.substring(0, 5));
getdisplay().fillRect(cRoot.x + timAxis - 57, cRoot.y + 2, 58, 16, bgColor); // clear small area to remove potential chart lines
String name = xdrDelete(dbName); // Value name
drawTextRalign(cRoot.x + timAxis - 1, cRoot.y + 16, name.substring(0, 6));
}
prntHorizChartThreeValueAxisLabel(font);
@@ -563,7 +597,8 @@ void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntNa
if (chrtSz == FULL_SIZE) {
font = &Ubuntu_Bold12pt8b;
getdisplay().setFont(font); // use larger font
drawTextRalign(cRoot.x + (valAxis * 0.42), cRoot.y - 2, dbName.substring(0, 6)); // print buffer data name (max. size 5 characters)
String name = xdrDelete(dbName); // Value name
drawTextRalign(cRoot.x + (valAxis * 0.42), cRoot.y - 2, name.substring(0, 6)); // print buffer data name (max. size 6 characters)
}
font = &Ubuntu_Bold10pt8b;
@@ -574,26 +609,32 @@ void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntNa
// Print current data value
void Chart::prntCurrValue(const char direction, GwApi::BoatValue& currValue)
{
const int xPosVal = (direction == HORIZONTAL) ? cRoot.x + (timAxis / 2) - 56 : cRoot.x + 32;
const int yPosVal = (direction == HORIZONTAL) ? cRoot.y + valAxis - 7 : cRoot.y + timAxis - 7;
const int xPosVal = (direction == HORIZONTAL) ? cRoot.x + (timAxis / 2) - 74 : cRoot.x + 31;
const int yPosVal = (direction == HORIZONTAL) ? cRoot.y + valAxis : cRoot.y + timAxis;
FormattedData frmtDbData = formatValue(&currValue, *commonData, NO_SIMUDATA);
String sdbValue = frmtDbData.svalue; // value as formatted string
String dbUnit = frmtDbData.unit; // Unit of value; limit length to 3 characters
getdisplay().fillRect(xPosVal - 1, yPosVal - 35, 128, 41, bgColor); // Clear area for TWS value
getdisplay().drawRect(xPosVal, yPosVal - 34, 126, 40, fgColor); // Draw box for TWS value
// box
getdisplay().fillRect(xPosVal - 1, yPosVal - 40, 148, 39, bgColor); // Clear area for value
getdisplay().drawRect(xPosVal, yPosVal - 39, 146, 37, fgColor); // Draw box for value
// value
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(xPosVal + 1, yPosVal);
getdisplay().print(sdbValue); // value
getdisplay().setCursor(xPosVal + 1, yPosVal - 6);
getdisplay().print(sdbValue);
// name
getdisplay().setFont(&Ubuntu_Bold10pt8b);
getdisplay().setCursor(xPosVal + 76, yPosVal - 17);
getdisplay().print(dbName.substring(0, 3)); // Name, limited to 3 characters
getdisplay().setCursor(xPosVal + 100, yPosVal - 23);
String name = xdrDelete(dbName);
getdisplay().print(name.substring(0, 3)); // Name, limited to 3 characters
// unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(xPosVal + 76, yPosVal + 0);
getdisplay().print(dbUnit); // Unit
getdisplay().setCursor(xPosVal + 101, yPosVal - 8);
getdisplay().print(dbUnit);
}
// print message for no valid data availabletemplate <typename T>
@@ -652,8 +693,8 @@ double Chart::getAngleRng(const double center, size_t amount)
return (maxRng != dbMIN_VAL ? maxRng : dbMAX_VAL); // Return range from <mid> to <max>
}
// print value axis label with only three values: top, mid, and bottom for vertical chart
void Chart::prntVerticChartThreeValueAxisLabel(const GFXfont* font)
// print value axis label with only three values: top, mid, and bottom for vertical chart
void Chart::prntVerticChartThreeValueAxisLabel(const GFXfont* font)
{
double cVal;
char sVal[7];
@@ -689,7 +730,7 @@ void Chart::prntHorizChartThreeValueAxisLabel(const GFXfont* font)
double axLabel;
double chrtMin, chrtMid, chrtMax;
int xOffset, yOffset; // offset for text position of x axis label for different font sizes
char sVal[11];
char sVal[11]; // data value have max. 6 digits + decimal point + 2 decimals + sign
if (font == &Ubuntu_Bold10pt8b) {
xOffset = 32;
@@ -706,33 +747,54 @@ void Chart::prntHorizChartThreeValueAxisLabel(const GFXfont* font)
chrtMax = convertValue(this->chrtMax, dbName, dbFormat, *commonData);
// print top axis label
axLabel = (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE) ? chrtMax : chrtMin;
snprintf(sVal, sizeof(sVal), "%3.0f", axLabel);
getdisplay().fillRect(cRoot.x, cRoot.y + 2, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + yOffset, sVal); // range value
axLabel = (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) ? chrtMin : chrtMax;
formatLabel(axLabel).toCharArray(sVal, 11);
if (chrtDataFmt == PRESSURE) {
snprintf(sVal, sizeof(sVal), "%4.0f", axLabel);
getdisplay().fillRect(cRoot.x, cRoot.y + 2, xOffset + 12, yOffset, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + yOffset, sVal); // range value
} else {
if (char* dot = strchr(sVal, '.'))
*dot = '\0'; // no decimal for top axis label
getdisplay().fillRect(cRoot.x, cRoot.y + 2, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + yOffset, sVal); // range value
}
// print mid axis label
axLabel = chrtMid;
formatLabel(axLabel).toCharArray(sVal, 11); // print mid label with 1 decimal for small numbers, if required
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 3, 16, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + (valAxis / 2) + 6, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor);
formatLabel(axLabel).toCharArray(sVal, 11);
if (chrtDataFmt == PRESSURE) { // print 4-digit value
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 12, yOffset, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + (valAxis / 2) + 6, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 14, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor);
} else { // print 3-digit value
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + (valAxis / 2) + 6, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor);
}
// print bottom axis label
axLabel = (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE) ? chrtMin : chrtMax;
snprintf(sVal, sizeof(sVal), "%3.0f", axLabel);
getdisplay().fillRect(cRoot.x, cRoot.y + valAxis - 14, xOffset + 3, 15, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + valAxis, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + valAxis, cRoot.x + timAxis, cRoot.y + valAxis, fgColor);
axLabel = (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) ? chrtMax : chrtMin;
formatLabel(axLabel).toCharArray(sVal, 11);
if (chrtDataFmt == PRESSURE) {
getdisplay().fillRect(cRoot.x, cRoot.y + valAxis - 14, xOffset + 12, yOffset, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + valAxis, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 14, cRoot.y + valAxis, cRoot.x + timAxis, cRoot.y + valAxis, fgColor);
} else {
if (char* dot = strchr(sVal, '.'))
*dot = '\0'; // no decimal for bottom axis label
getdisplay().fillRect(cRoot.x, cRoot.y + valAxis - 14, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + valAxis, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + valAxis, cRoot.x + timAxis, cRoot.y + valAxis, fgColor);
}
}
// print value axis label with multiple axis lines for horizontal chart
void Chart::prntHorizChartMultiValueAxisLabel(const GFXfont* font)
{
double chrtMin, chrtMax, chrtRng;
// int axSlots = 5; // no. of axis labels
int xOffset; // offset for text position of x axis label for different font sizes
char sVal[11];
char sVal[11]; // data value have max. 6 digits + decimal point + 2 decimals + sign
if (font == &Ubuntu_Bold10pt8b) {
xOffset = 32;
@@ -753,23 +815,29 @@ void Chart::prntHorizChartMultiValueAxisLabel(const GFXfont* font)
// LOG_DEBUG(GwLog::DEBUG, "Chart::printHorizMultiValueAxisLabel: chrtRng: %.2f, th-chrtRng: %.2f, axSlots: %.2f, axIntv: %.2f, axLabel: %.2f, chrtMin: %.2f, chrtMid: %.2f, chrtMax: %.2f", chrtRng, this->chrtRng, VALAXIS_SLOTS, axIntv, axLabel, this->chrtMin, chrtMid, chrtMax);
int loopStrt, loopEnd, loopStp;
if (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE || chrtDataFmt == OTHER) {
loopStrt = valAxis - valAxisStep;
loopEnd = valAxisStep / 2;
loopStp = valAxisStep * -1;
} else {
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) {
// Low value at top
loopStrt = valAxisStep;
loopEnd = valAxis - (valAxisStep / 2);
loopStp = valAxisStep;
} else {
// high value at top
loopStrt = valAxis - valAxisStep;
loopEnd = valAxisStep / 2;
loopStp = valAxisStep * -1;
}
for (int j = loopStrt; (loopStp > 0) ? (j < loopEnd) : (j > loopEnd); j += loopStp) {
// sVal = formatLabel(axLabel);
snprintf(sVal, sizeof(sVal), "%3.0f", axLabel);
getdisplay().fillRect(cRoot.x, cRoot.y + j - 11, xOffset + 3, 21, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + j + 7, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + j, cRoot.x + timAxis, cRoot.y + j, fgColor);
formatLabel(axLabel).toCharArray(sVal, 11);
if (chrtDataFmt == PRESSURE) { // print 4-digit value
getdisplay().fillRect(cRoot.x, cRoot.y + j - 11, xOffset + 12, 21, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + j + 7, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 14, cRoot.y + j, cRoot.x + timAxis, cRoot.y + j, fgColor);
} else { // print 3-digit value
getdisplay().fillRect(cRoot.x, cRoot.y + j - 11, xOffset + 3, 21, bgColor); // Clear small area to remove potential chart lines
drawTextRalign(cRoot.x + xOffset, cRoot.y + j + 7, sVal); // range value
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + j, cRoot.x + timAxis, cRoot.y + j, fgColor);
}
axLabel += axIntv;
}
@@ -812,16 +880,18 @@ String Chart::formatLabel(const double& label)
{
char sVal[11];
if (dbFormat == "formatCourse" || dbFormat == "formatWind") {
// Format 3 numbers with prefix zero
snprintf(sVal, sizeof(sVal), "%03.0f", label);
if (chrtDataFmt == WIND) {
snprintf(sVal, sizeof(sVal), "%03.0f", label); // Format 3 numbers with prefix zero
/* } else if (dbFormat == "formatRot") {
if (label > -10 && label < 10) {
} else if (chrtDataFmt == ROTATION) {
if (label > -9.995 && label < 9.995) {
snprintf(sVal, sizeof(sVal), "%3.2f", label);
} else {
snprintf(sVal, sizeof(sVal), "%3.0f", label);
} */
}
} else if (chrtDataFmt == PRESSURE) {
snprintf(sVal, sizeof(sVal), "%4.0f", label);
} else {
if (label < 9.95) {
+41 -13
View File
@@ -19,6 +19,26 @@ class RingBuffer;
class GwLog;
class Chart {
public:
/* enum class ChrtDirection {
HORIZONTALE,
VERTICALE
};
enum class ChrtSize {
FULL_SIZEE,
HALF_SIZE_LEFTE,
HALF_SIZE_RIGHTE,
TWO_THIRD_TOPE
}; */
Chart(RingBuffer<uint16_t>& dataBuf, CommonData& common, bool useSimuData); // Chart object of data chart
~Chart();
bool init(); // initialize chart object parameters
bool isValid() { return initValid; }; // Checks if chart object has been fully initialized
void showChrt(const char chrtDir, const int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue); // Perform all actions to draw chart
// void showChrt(ChrtDirection chrtDir, ChrtSize chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue); // Perform all actions to draw chart
protected:
CommonData* commonData;
GwLog* logger;
@@ -29,6 +49,8 @@ protected:
SPEED,
DEPTH,
TEMPERATURE,
PRESSURE,
HUMIDITY,
OTHER
};
@@ -37,6 +59,7 @@ protected:
static constexpr int8_t FULL_SIZE = 0;
static constexpr int8_t HALF_SIZE_LEFT = 1;
static constexpr int8_t HALF_SIZE_RIGHT = 2;
static constexpr int8_t TWO_THIRD_TOP = 3;
static constexpr int8_t MIN_FREE_VALUES = 60; // free 60 values when chart line reaches chart end
static constexpr int8_t THRESHOLD_NO_DATA = 3; // max. seconds of invalid values in a row
@@ -45,6 +68,7 @@ protected:
static constexpr bool NO_SIMUDATA = true; // switch off simulation feature of <formatValue> function
RingBuffer<uint16_t>& dataBuf; // Buffer to display
bool initValid = false; // indicates whether object holds valid initialization data or not
double 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
@@ -77,19 +101,31 @@ protected:
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
size_t currIdx; // Current index in history buffer
size_t lastIdx; // Last index of history buffer
size_t lastAddedIdx = 0; // Last index of history buffer when new data was added
int numNoData; // Counter for multiple invalid data values in a row
bool bufDataValid = false; // Flag to indicate if buffer data is valid
int oldChrtIntv = 0; // remember recent user selection of data interval
movingAvg<double> chrtAvg{7}; // Store average of the last 7 chart values if chart gradient shall be smoothed
movingAvg<double> chrtAvg { 7 }; // Store average of the last 7 chart values if chart gradient shall be smoothed
double chrtPrevVal; // Last data value in chart area
int x, y; // x and y coordinates for drawing
int prevX, prevY; // Last x and y coordinates for drawing
bool setChartDimensions(const char direction, const int8_t size); //define dimensions and start points for chart
// Default ranges for various boat data types
// Parameters: <1st value> default range, <2nd value> step for range adjustment
std::map<String, ChartProps> dfltChrtDta = {
{ "formatWind", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default wind range 60 degrees
{ "formatCourse", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
{ "formatKnots", { 2.572, 2.572 } }, // default speed range in m/s
{ "formatDepth", { 10.0, 5.0 } }, // default depth range in m
{ "kelvinToC", { 20.0, 5.0 } }, // default temp range in °C/K
{ "formatXdr:P:P", { 4000.0, 1000.0 } } // default pressure range in Pascal (hPa * 100); XDR <B> (bar) format is represented in gateway in the same way
};
bool setChartDimensions(const char direction, const int8_t size); // define dimensions and start points for chart
// bool setChartDimensions(const ChrtDirection direction, const ChrtSize size); // define dimensions and start points for chart
void drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue& currValue); // Draw chart line
void getBufferStartNSize(const 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>
@@ -106,12 +142,4 @@ protected:
void drawBoldLine(const int16_t x1, const int16_t y1, const int16_t x2, const int16_t y2); // Draw chart line with thickness of 2px
String convNformatLabel(const double& label); // Convert and format current axis label to user defined format; helper function for easier handling of OBP60Formatter
String formatLabel(const double& label); // Format current axis label for printing w/o data format conversion (has been done earlier)
public:
// Define default chart range and range step for each boat data type
static std::map<String, ChartProps> dfltChrtDta;
Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData); // Chart object of data chart
~Chart();
void showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue); // Perform all actions to draw chart
};
+8 -4
View File
@@ -76,10 +76,10 @@ private:
nameYoff = -34;
nameFnt = &Ubuntu_Bold20pt8b;
unitXoff = -295;
unitYoff = -119;
unitYoff = 21;
unitFnt = &Ubuntu_Bold12pt8b;
valueFnt1 = &Ubuntu_Bold12pt8b;
value1Xoff = 153;
value1Xoff = 111;
value1Yoff = -119;
valueFnt2 = &Ubuntu_Bold20pt8b;
valueFnt3 = &DSEG7Classic_BoldItalic42pt7b;
@@ -100,7 +100,7 @@ private:
// Show unit
getdisplay().setFont(unitFnt);
getdisplay().setCursor(305 + unitXoff, 240 + unitYoff);
getdisplay().setCursor(305 + unitXoff, 100 + unitYoff);
if (holdValues) {
getdisplay().print(unit1Old); // name
@@ -243,7 +243,7 @@ public:
dataHstryBuf = pageData.hstryBuffers->getBuffer(bValName1);
if (dataHstryBuf) {
dataChart.reset(new Chart(*dataHstryBuf, Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
dataChart.reset(new Chart(*dataHstryBuf, *commonData, useSimuData));
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: Created chart objects for %s", bValName1);
} else {
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: No chart objects available for %s", bValName1);
@@ -276,6 +276,10 @@ public:
displaySetPartialWindow(0, 0, width, height); // Set partial update
if (!dataChart->isValid()) {
dataChart->init(); // try late initialization if chart object could not be properly initialized earlier due to missing boat data
}
if (pageMode == VALUE || dataHstryBuf == nullptr) {
// show only data value; ignore other pageMode options if no chart supported boat data history buffer is available
showData(bValue1, FULL);
+9 -3
View File
@@ -203,7 +203,7 @@ public:
#if defined BOARD_OBP60S3
if (key == 5 && pageMode != VALUES) {
#elif defined BOARD_OBP40S3
if (key == 2 && pageMode != VALUES) {
if (key == 2 && pageMode != VALUES) {
#endif
if (dataIntv == 1) {
dataIntv = 2;
@@ -246,8 +246,8 @@ public:
dataHstryBuf[i] = pageData.hstryBuffers->getBuffer(bValName);
if (dataHstryBuf[i]) {
dataChart[i].reset(new Chart(*dataHstryBuf[i], Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: Created chart object%d for %s", i, bValName.c_str());
dataChart[i].reset(new Chart(*dataHstryBuf[i], *commonData, useSimuData));
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: Created chart object %d for %s", i, bValName.c_str());
} else {
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: No chart object available for %s", bValName.c_str());
}
@@ -283,6 +283,12 @@ public:
displaySetPartialWindow(0, 0, width, height); // Set partial update
for (int i = 0; i < NUMVALUES; i++) {
if (!dataChart[i]->isValid()) {
dataChart[i]->init(); // try late initialization if chart object could not be properly initialized earlier due to missing boat data
}
}
if (pageMode == VALUES || (dataHstryBuf[0] == nullptr && dataHstryBuf[1] == nullptr)) {
// show only data value; ignore other pageMode options if no chart supported boat data history buffer is available
showData(bValue, FULL);
+307
View File
@@ -0,0 +1,307 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "OBPDataOperations.h"
#include "OBPcharts.h"
class PageWeather : public Page {
private:
GwLog* logger;
enum PageMode {
VAL_CHART,
CHART
};
/* enum DisplayMode {
FULL,
HALF
}; */
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;
static constexpr int8_t TWO_THIRD_TOP = 3;
static constexpr bool PRNT_NAME = true;
static constexpr bool NO_PRNT_NAME = false;
static constexpr bool PRNT_VALUE = true;
static constexpr bool NO_PRNT_VALUE = false;
static constexpr int XOFFSET = 133; // x offset for display of boat values
int width; // Screen width
int height; // Screen height
bool keylock = false; // Keylock
PageMode pageMode = VAL_CHART; // Page display mode
int8_t dataIntv = 1; // Update interval for barograph history chart:
// (1)|(3)|(6)|(12)|(24) x 60 min. for 1, 3, 6, 12, 24 hours history chart
// String lengthformat;
bool useSimuData;
bool holdValues;
String flashLED;
String backlightMode;
String tempFormat;
static constexpr int NUMVALUES = 4; // number of boat values used on this page
static constexpr int NUMCHARTS = 1; // one data buffer used on this page
// Data buffer pointer (owned by HstryBuffers)
RingBuffer<uint16_t>* dataHstryBuf[NUMCHARTS] = { nullptr };
std::unique_ptr<Chart> dataChart[NUMCHARTS]; // Chart object
// Old values for hold function
String sValueOld[NUMVALUES] = { "", "", "", "" };
String unitOld[NUMVALUES] = { "", "", "", "" };
// display data values in display mode <HALF>
void showData(const std::vector<GwApi::BoatValue*>& bValue)
{
getdisplay().setTextColor(commonData->fgcolor);
int numValues = bValue.size(); // How many values do we have to handle? We will ignore value no. 1
for (int i = 1; i < numValues; i++) {
String name = xdrDelete(bValue[i]->getName()); // Value name
name = name.substring(0, 7); // String length limit for value name
double value = bValue[i]->value; // Value as double in SI unit
bool valid = bValue[i]->valid; // Valid information
String sValue = formatValue(bValue[i], *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit = formatValue(bValue[i], *commonData).unit; // Unit of value
int xOffset = XOFFSET * (i - 1);
// Print name
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(5 + xOffset, 213);
getdisplay().print(name); // name
// Print unit
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(5 + xOffset, 229);
if (holdValues) {
getdisplay().print(unitOld[i]); // name
} else {
getdisplay().print(unit); // name
}
// Print value
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
if (bValue[i]->getFormat() == "formatXdr:P:P" || bValue[i]->getFormat() == "formatXdr:P:B") {
getdisplay().setCursor(6 + xOffset, 275); // pressure format is always 4 digits when all other boat data has 3 digit format
} else {
getdisplay().setCursor(37 + xOffset, 275);
}
if (!holdValues || useSimuData) {
getdisplay().print(sValue); // Real value as formated string
} else {
getdisplay().print(sValueOld[i]); // Old value as formated string
}
if (valid) { // Save value for hold function
sValueOld[i] = sValue;
unitOld[i] = unit;
}
}
// print lines for data separation of bottom data values
getdisplay().fillRect(0, 191, 400, 2, commonData->fgcolor); // horizontal line
getdisplay().fillRect(133, 192, 2, 84, commonData->fgcolor); // vertical lines
getdisplay().fillRect(266, 192, 2, 84, commonData->fgcolor);
}
public:
PageWeather(CommonData& common)
{
commonData = &common;
logger = commonData->logger;
LOG_DEBUG(GwLog::LOG, "Instantiate PageWeather");
width = getdisplay().width(); // Screen width
height = getdisplay().height(); // Screen height
// Get config data
// lengthformat = commonData->config->getString(commonData->config->lengthFormat);
useSimuData = commonData->config->getBool(commonData->config->useSimuData);
holdValues = commonData->config->getBool(commonData->config->holdvalues);
flashLED = commonData->config->getString(commonData->config->flashLED);
backlightMode = commonData->config->getString(commonData->config->backlight);
tempFormat = commonData->config->getString(commonData->config->tempFormat); // [K|°C|°F]
}
virtual void setupKeys()
{
Page::setupKeys();
#if defined BOARD_OBP60S3
constexpr int ZOOM_KEY = 4;
#elif defined BOARD_OBP40S3
constexpr int ZOOM_KEY = 1;
#endif
if (dataHstryBuf) { // show "Mode" key only if chart-supported boat data type is available
commonData->keydata[0].label = "MODE";
commonData->keydata[ZOOM_KEY].label = "ZOOM";
} else {
commonData->keydata[0].label = "";
commonData->keydata[ZOOM_KEY].label = "";
}
}
// Key functions
virtual int handleKey(int key)
{
if (dataHstryBuf) { // if boat data type supports charts
// Set page mode: value/half chart | full chart
if (key == 1) {
switch (pageMode) {
case VAL_CHART:
pageMode = CHART;
break;
case CHART:
pageMode = VAL_CHART;
break;
}
setupKeys(); // Adjust key definition depending on <pageMode> and chart-supported boat data type
return 0; // Commit the key
}
// Set time frame to show for chart
#if defined BOARD_OBP60S3
if (key == 5) {
#elif defined BOARD_OBP40S3
if (key == 2) {
#endif
if (dataIntv == 1) {
dataIntv = 2;
} else if (dataIntv == 2) {
dataIntv = 4;
} else if (dataIntv == 4) {
dataIntv = 8;
} else if (dataIntv == 8) {
dataIntv = 12;
} else {
dataIntv = 1;
}
return 0; // Commit the key
}
}
// Keylock function
if (key == 11) { // Code for keylock
commonData->keylock = !commonData->keylock;
return 0; // Commit the key
}
return key;
}
virtual void displayNew(PageData& pageData)
{
#ifdef BOARD_OBP60S3
// Clear optical warning
if (flashLED == "Limit Violation") {
setBlinkingLED(false);
setFlashLED(false);
}
#endif
for (int i = 0; i < NUMCHARTS; i++) {
if (!dataChart[i]) { // Create chart objects if they don't exist
GwApi::BoatValue* bValue = pageData.values[i]; // Page boat data element
String bValName = bValue->getName(); // Value name
String bValFormat = bValue->getFormat(); // Value format
dataHstryBuf[i] = pageData.hstryBuffers->getBuffer(bValName);
// if (dataHstryBuf[i]->getFormat() == "") { // data format might have been unknown at time of buffer creation
// dataHstryBuf[i]->setFormat(bValFormat); // in that case, we specify it here, because we need it for printing of buffer data
// }
if (dataHstryBuf[i]) {
dataChart[i].reset(new Chart(*dataHstryBuf[i], *commonData, useSimuData));
LOG_DEBUG(GwLog::DEBUG, "PageWeather: Created chart object %d for %s, format: %s", i, bValName.c_str(), dataHstryBuf[i]->getFormat().c_str());
} else {
LOG_DEBUG(GwLog::DEBUG, "PageWeather: No chart object available for %s", bValName.c_str());
}
}
}
}
int displayPage(PageData& pageData)
{
// using CD = Chart::ChrtDirection;
LOG_DEBUG(GwLog::LOG, "Display PageWeather");
// Get latest boat values for page
std::vector<GwApi::BoatValue*> bValue;
for (int i = 0; i < NUMVALUES; i++) {
bValue.push_back(pageData.values[i]);
}
// Optical warning by limit violation (unused)
if (String(flashLED) == "Limit Violation") {
setBlinkingLED(false);
setFlashLED(false);
}
if (bValue[0] == NULL && bValue[1] == NULL && bValue[2] == NULL && bValue[3] == NULL)
return PAGE_OK; // no data, no page to display
LOG_DEBUG(GwLog::DEBUG, "PageWeather: printing #1: %s, %.3f, %s, #2: %s, %.3f, %s, #3: %s, %.3f, %s, #4: %s, %.3f, %s",
bValue[0]->getName().c_str(), bValue[0]->value, bValue[0]->getFormat().c_str(), bValue[1]->getName().c_str(), bValue[1]->value, bValue[1]->getFormat().c_str(),
bValue[2]->getName().c_str(), bValue[2]->value, bValue[2]->getFormat().c_str(), bValue[3]->getName().c_str(), bValue[3]->value, bValue[3]->getFormat().c_str());
// Draw page
//***********************************************************
displaySetPartialWindow(0, 0, width, height); // Set partial update
if (dataHstryBuf == nullptr) { // no buffer for main boat data item, no page display
return PAGE_UPDATE;
}
if (!dataChart[0]->isValid()) {
dataChart[0]->init(); // try late initialization if chart object could not be properly initialized earlier due to missing boat data
}
if (pageMode == VAL_CHART) {
if (dataChart[0]) {
dataChart[0]->showChrt(HORIZONTAL, TWO_THIRD_TOP, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[0]);
}
showData(bValue);
} else if (pageMode == CHART && dataChart[0]) { // show only data chart, but that has to exist
dataChart[0]->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[0]);
}
return PAGE_UPDATE;
};
};
static Page* createPage(CommonData& common)
{
return new PageWeather(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageWeather(
"Weather", // Page name
createPage, // Action
4, // Number of bus values depends on selection in Web configuration (air baro pressure, air temperature, humidity, true wind speed)
{ }, // Bus values we need in the page
true // Show display header on/off
);
#endif
+4 -4
View File
@@ -168,10 +168,10 @@ public:
twsHstry = pageData.hstryBuffers->getBuffer("TWS");
if (twdHstry) {
twdChart.reset(new Chart(*twdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
twdChart.reset(new Chart(*twdHstry, *commonData, useSimuData));
}
if (twsHstry) {
twsChart.reset(new Chart(*twsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
twsChart.reset(new Chart(*twsHstry, *commonData, useSimuData));
}
}
@@ -180,10 +180,10 @@ public:
awsHstry = pageData.hstryBuffers->getBuffer("AWS");
if (awdHstry) {
awdChart.reset(new Chart(*awdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
awdChart.reset(new Chart(*awdHstry, *commonData, useSimuData));
}
if (awsHstry) {
awsChart.reset(new Chart(*awsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
awsChart.reset(new Chart(*awsHstry, *commonData, useSimuData));
}
if (twdHstry && twsHstry && awdHstry && awsHstry) {
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Created wind charts");
+49
View File
@@ -1590,6 +1590,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -1637,6 +1638,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1671,6 +1673,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1703,6 +1706,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1734,6 +1738,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1923,6 +1928,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -1969,6 +1975,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2002,6 +2009,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2033,6 +2041,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2063,6 +2072,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2247,6 +2257,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2292,6 +2303,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2324,6 +2336,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2354,6 +2367,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2383,6 +2397,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2562,6 +2577,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2606,6 +2622,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2637,6 +2654,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2666,6 +2684,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2694,6 +2713,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2868,6 +2888,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2911,6 +2932,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2941,6 +2963,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2996,6 +3019,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3165,6 +3189,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3207,6 +3232,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3236,6 +3262,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3263,6 +3290,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3289,6 +3317,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3453,6 +3482,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3494,6 +3524,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3522,6 +3553,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3548,6 +3580,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3573,6 +3606,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3732,6 +3766,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3772,6 +3807,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3799,6 +3835,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3824,6 +3861,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3848,6 +3886,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4002,6 +4041,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -4041,6 +4081,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4067,6 +4108,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4091,6 +4133,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4114,6 +4157,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4263,6 +4307,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -4301,6 +4346,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4326,6 +4372,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4349,6 +4396,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4371,6 +4419,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
+50
View File
@@ -1568,6 +1568,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -1615,6 +1616,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1649,6 +1651,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1681,6 +1684,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1712,6 +1716,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1871,6 +1876,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -1917,6 +1923,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1950,6 +1957,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1981,6 +1989,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2011,6 +2020,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2166,6 +2176,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2211,6 +2222,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2243,6 +2255,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2273,6 +2286,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2302,6 +2316,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2453,6 +2468,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2497,6 +2513,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2528,6 +2545,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2557,6 +2575,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2585,6 +2604,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2732,6 +2752,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2775,6 +2796,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2805,6 +2827,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2833,6 +2856,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2860,6 +2884,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3003,6 +3028,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3045,6 +3071,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3074,6 +3101,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3101,6 +3129,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3127,6 +3156,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3266,6 +3296,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3307,6 +3338,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3335,6 +3367,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3361,6 +3394,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3386,6 +3420,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3521,6 +3556,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3561,6 +3597,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3588,6 +3625,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3613,6 +3651,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3637,6 +3676,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3768,6 +3808,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3807,6 +3848,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3833,6 +3875,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3857,6 +3900,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3880,6 +3924,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4007,6 +4052,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -4045,6 +4091,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4070,6 +4117,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4093,6 +4141,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4115,6 +4164,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
+50
View File
@@ -1522,6 +1522,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -1568,6 +1569,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1602,6 +1604,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1634,6 +1637,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1665,6 +1669,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1824,6 +1829,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -1869,6 +1875,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1902,6 +1909,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1933,6 +1941,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -1963,6 +1972,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2118,6 +2128,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2162,6 +2173,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2194,6 +2206,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2224,6 +2237,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2253,6 +2267,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2404,6 +2419,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2447,6 +2463,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2478,6 +2495,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2507,6 +2525,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2535,6 +2554,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2682,6 +2702,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2724,6 +2745,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2754,6 +2776,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2782,6 +2805,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2809,6 +2833,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -2952,6 +2977,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -2993,6 +3019,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3022,6 +3049,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3049,6 +3077,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3075,6 +3104,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3214,6 +3244,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3254,6 +3285,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3282,6 +3314,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3308,6 +3341,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3333,6 +3367,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3468,6 +3503,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3507,6 +3543,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3534,6 +3571,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3559,6 +3597,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3583,6 +3622,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3714,6 +3754,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3752,6 +3793,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3778,6 +3820,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3802,6 +3845,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3825,6 +3869,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -3952,6 +3997,7 @@
"ThreeValues",
"TwoValues",
"Voltage",
"Weather",
"WhitePage",
"Wind",
"WindPlot",
@@ -3989,6 +4035,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4014,6 +4061,7 @@
"SixValues",
"ThreeValues",
"TwoValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4037,6 +4085,7 @@
"FourValues2",
"SixValues",
"ThreeValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
@@ -4059,6 +4108,7 @@
"FourValues",
"FourValues2",
"SixValues",
"Weather",
"WindRoseFlex"
],
"visiblePages": [
+8 -3
View File
@@ -265,6 +265,8 @@ void registerAllPages(PageList &list){
list.add(&registerPageDigitalOut);
extern PageDescription registerPageAutopilot;
list.add(&registerPageAutopilot);
extern PageDescription registerPageWeather;
list.add(&registerPageWeather);
}
// Undervoltage detection for shutdown display
@@ -501,15 +503,15 @@ void OBP60Task(GwApi *api){
}
// Read the specified boat data types of relevant pages and create a history buffer for each type for later use in charts
// applies only for pages that uses charts
if (pages[i].parameters.pageName == "OneValue" || pages[i].parameters.pageName == "TwoValues" || pages[i].parameters.pageName == "WindPlot") {
// applies only to pages that uses charts
if (pages[i].parameters.pageName == "OneValue" || pages[i].parameters.pageName == "TwoValues"
|| pages[i].parameters.pageName == "WindPlot" || pages[i].parameters.pageName == "Weather") {
for (auto pVal : pages[i].parameters.values) {
hstryBufferList.addBuffer(pVal->getName());
}
}
// Add list of history buffers to page parameters
pages[i].parameters.hstryBuffers = &hstryBufferList;
}
// add out of band system page (always available)
@@ -846,9 +848,12 @@ void OBP60Task(GwApi *api){
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
api->getStatus(commonData.status);
// ulong startHndl = millis();
trueWind.handleWinds(calcTrueWnds); // calculate true wind data from apparent wind values
trueWind.setMaxWs(); // maintain MaxTWS value in any case; invalid TWS value is considered automatically
calibrationDataList.handleCalibration(&boatValues); // Process calibration for all boat data in <calibrationDataList>
hstryBufferList.handleHstryBufs(useSimuData, commonData); // Handle history buffers for certain boat data for charts and other usage
// LOG_DEBUG(GwLog::DEBUG, "obp60task: data handling: %d ms", millis() - startHndl);
// Clear display
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);