Integrate changes from master
This commit is contained in:
parent
c6df6eac56
commit
318a218470
|
@ -173,7 +173,7 @@ void CalibrationDataList::smoothInstance(GwApi::BoatValue* boatDataValue, GwLog*
|
|||
if (!boatDataValue->valid) { // no valid boat data value, so we don't want to smoothen value
|
||||
return;
|
||||
} else if (calibMap.find(instance) == calibMap.end()) {
|
||||
logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: smooth factor for %s not found in calibration data list", instance.c_str());
|
||||
logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: smooth factor for %s not found in calibration list", instance.c_str());
|
||||
return;
|
||||
} else {
|
||||
smoothFactor = calibMap[instance].smooth;
|
||||
|
@ -184,8 +184,6 @@ void CalibrationDataList::smoothInstance(GwApi::BoatValue* boatDataValue, GwLog*
|
|||
}
|
||||
lastValue[instance] = dataValue; // store the new value for next cycle; first time, store only the current value and return
|
||||
boatDataValue->value = dataValue; // set the smoothed value to the boat data value
|
||||
|
||||
logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: %s: Smoothing factor: %f, Smoothed value: %f", instance.c_str(), smoothFactor, dataValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -439,21 +439,30 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
|
|||
//########################################################
|
||||
else if (value->getFormat() == "formatXte"){
|
||||
double xte = 0;
|
||||
if (!usesimudata) {
|
||||
xte = abs(value->value);
|
||||
if (usesimudata == false) {
|
||||
xte = value->value;
|
||||
rawvalue = value->value;
|
||||
} else {
|
||||
rawvalue = 6.0 + float(random(0, 4));
|
||||
xte = rawvalue;
|
||||
}
|
||||
if (xte >= 100) {
|
||||
snprintf(buffer, bsize, fmt_dec_100, value->value);
|
||||
} else if (xte >= 10) {
|
||||
snprintf(buffer, bsize, fmt_dec_10, value->value);
|
||||
if (distanceFormat == "km") {
|
||||
xte = xte * 0.001;
|
||||
result.unit = "km";
|
||||
} else if (distanceFormat == "nm") {
|
||||
xte = xte * 0.000539957;
|
||||
result.unit = "nm";
|
||||
} else {
|
||||
snprintf(buffer, bsize, fmt_dec_1, value->value);
|
||||
result.unit = "m";
|
||||
}
|
||||
if (xte < 10) {
|
||||
snprintf(buffer, bsize, "%3.2f", xte);
|
||||
} else if (xte < 100) {
|
||||
snprintf(buffer,bsize,"%3.1f",xte);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, bsize, "%3.0f", xte);
|
||||
}
|
||||
result.unit = "nm";
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "kelvinToC"){
|
||||
|
|
|
@ -77,30 +77,56 @@ void WindUtils::calcTwdSA(const double* AWA, const double* AWS,
|
|||
// Serial.println("calcTwdSA: TWD: " + String(*TWD) + ", TWS: " + String(*TWS));
|
||||
}
|
||||
|
||||
double WindUtils::calcHDT(const double* hdmVal, const double* varVal, const double* cogVal, const double* sogVal)
|
||||
{
|
||||
double hdt;
|
||||
double minSogVal = 0.1; // SOG below this value (m/s) is assumed to be data noise from GPS sensor
|
||||
static const double DBL_MIN = std::numeric_limits<double>::lowest();
|
||||
|
||||
// Serial.println("\ncalcTrueWind: HDT: " + String(*hdtVal) + ", HDM: " + String(*hdmVal) + ", VAR: " + String(*varVal) + ", SOG: " + String(*sogVal) + ", COG: " + String(*cogVal));
|
||||
if (*hdmVal != DBL_MIN) {
|
||||
hdt = *hdmVal + (*varVal != DBL_MIN ? *varVal : 0.0); // Use corrected HDM if HDT is not available (or just HDM if VAR is not available)
|
||||
hdt = to2PI(hdt);
|
||||
} else if (*cogVal != DBL_MIN && *sogVal >= minSogVal) {
|
||||
hdt = *cogVal; // Use COG as fallback if HDT and HDM are not available, and SOG is not data noise
|
||||
} else {
|
||||
hdt = DBL_MIN; // Cannot calculate HDT without valid HDM or HDM+VAR or COG
|
||||
}
|
||||
|
||||
return hdt;
|
||||
}
|
||||
|
||||
bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
||||
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal)
|
||||
{
|
||||
double stw, hdt, ctw;
|
||||
double twd, tws, twa;
|
||||
double minSogVal = 0.1; // SOG below this value (m/s) is assumed to be data noise from GPS sensor
|
||||
static const double DBL_MIN = std::numeric_limits<double>::lowest();
|
||||
|
||||
if (*hdtVal != DBL_MIN) {
|
||||
// Serial.println("\ncalcTrueWind: HDT: " + String(*hdtVal) + ", HDM: " + String(*hdmVal) + ", VAR: " + String(*varVal) + ", SOG: " + String(*sogVal) + ", COG: " + String(*cogVal));
|
||||
/* if (*hdtVal != DBL_MIN) {
|
||||
hdt = *hdtVal; // Use HDT if available
|
||||
} else {
|
||||
if (*hdmVal != DBL_MIN && *varVal != DBL_MIN) {
|
||||
hdt = *hdmVal + *varVal; // Use corrected HDM if HDT is not available
|
||||
if (*hdmVal != DBL_MIN) {
|
||||
hdt = *hdmVal + (*varVal != DBL_MIN ? *varVal : 0.0); // Use corrected HDM if HDT is not available (or just HDM if VAR is not available)
|
||||
hdt = to2PI(hdt);
|
||||
} else if (*cogVal != DBL_MIN) {
|
||||
hdt = *cogVal; // Use COG as fallback if HDT and HDM are not available
|
||||
} else if (*cogVal != DBL_MIN && *sogVal >= minSogVal) {
|
||||
hdt = *cogVal; // Use COG as fallback if HDT and HDM are not available, and SOG is not data noise
|
||||
} else {
|
||||
return false; // Cannot calculate without valid HDT or HDM+VAR or COG
|
||||
}
|
||||
} */
|
||||
if (*hdtVal != DBL_MIN) {
|
||||
hdt = *hdtVal; // Use HDT if available
|
||||
} else {
|
||||
hdt = calcHDT(hdmVal, varVal, cogVal, sogVal);
|
||||
}
|
||||
|
||||
if (*cogVal != DBL_MIN) {
|
||||
ctw = *cogVal; // Use COG as CTW if available
|
||||
// ctw = *cogVal + ((*cogVal - hdt) / 2); // Estimate CTW from COG
|
||||
if (*cogVal != DBL_MIN && *sogVal >= minSogVal) { // if SOG is data noise, we don't trust COG
|
||||
|
||||
ctw = *cogVal; // Use COG for CTW if available
|
||||
} else {
|
||||
ctw = hdt; // 2nd approximation for CTW; hdt must exist if we reach this part of the code
|
||||
}
|
||||
|
@ -113,6 +139,7 @@ bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
|||
// If STW and SOG are not available, we cannot calculate true wind
|
||||
return false;
|
||||
}
|
||||
// Serial.println("\ncalcTrueWind: HDT: " + String(hdt) + ", CTW: " + String(ctw) + ", STW: " + String(stw));
|
||||
|
||||
if ((*awaVal == DBL_MIN) || (*awsVal == DBL_MIN)) {
|
||||
// Cannot calculate true wind without valid AWA, AWS; other checks are done earlier
|
||||
|
@ -126,32 +153,3 @@ bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void HstryBuf::fillWndBufSimData(tBoatHstryData& hstryBufs)
|
||||
// Fill most part of TWD and TWS history buffer with simulated data
|
||||
{
|
||||
double value = 20.0;
|
||||
int16_t value2 = 0;
|
||||
for (int i = 0; i < 900; i++) {
|
||||
value += random(-20, 20);
|
||||
value = WindUtils::to360(value);
|
||||
value2 = static_cast<int16_t>(value * DEG_TO_RAD * 1000);
|
||||
hstryBufs.twdHstry->add(value2);
|
||||
}
|
||||
}
|
||||
|
||||
/* double genTwdSimDat()
|
||||
{
|
||||
simTwd += random(-20, 20);
|
||||
if (simTwd < 0.0)
|
||||
simTwd += 360.0;
|
||||
if (simTwd >= 360.0)
|
||||
simTwd -= 360.0;
|
||||
|
||||
int16_t z = static_cast<int16_t>(DegToRad(simTwd) * 1000.0);
|
||||
pageData.boatHstry.twdHstry->add(z); // Fill the buffer with some test data
|
||||
|
||||
simTws += random(-200, 150) / 10.0; // TWS value in knots
|
||||
simTws = constrain(simTws, 0.0f, 50.0f); // Ensure TWS is between 0 and 50 knots
|
||||
twsValue = simTws;
|
||||
}*/
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
#pragma once
|
||||
#include "GwApi.h"
|
||||
#include "OBPRingBuffer.h"
|
||||
#include <Arduino.h>
|
||||
// #include <Arduino.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
RingBuffer<int16_t>* twdHstry;
|
||||
RingBuffer<int16_t>* twsHstry;
|
||||
RingBuffer<int16_t>* awdHstry;
|
||||
RingBuffer<int16_t>* awsHstry;
|
||||
} tBoatHstryData; // Holds pointers to all history buffers for boat data
|
||||
|
||||
class HstryBuf {
|
||||
|
||||
public:
|
||||
void fillWndBufSimData(tBoatHstryData& hstryBufs); // Fill most part of the TWD and TWS history buffer with simulated data
|
||||
|
||||
};
|
||||
|
||||
class WindUtils {
|
||||
|
@ -30,7 +32,8 @@ public:
|
|||
static void calcTwdSA(const double* AWA, const double* AWS,
|
||||
const double* CTW, const double* STW, const double* HDT,
|
||||
double* TWD, double* TWS, double* TWA);
|
||||
static double calcHDT(const double* hdmVal, const double* varVal, const double* cogVal, const double* sogVal);
|
||||
static bool calcTrueWind(const double* awaVal, const double* awsVal,
|
||||
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
void setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue); // Set meta data for buffer
|
||||
bool getMetaData(String& name, String& format, int& updateFrequency, T& minValue, T& maxValue); // Get meta data of buffer
|
||||
String getName() const; // Get buffer name
|
||||
String getFormat() const; // Get buffer data format
|
||||
void add(const T& value); // Add a new value to buffer
|
||||
T get(size_t index) const; // Get value at specific position (0-based index from oldest to newest)
|
||||
T getFirst() const; // Get the first (oldest) value in buffer
|
||||
|
@ -57,4 +58,4 @@ public:
|
|||
std::vector<T> getAllValues() const; // Get all current values as a vector
|
||||
};
|
||||
|
||||
#include "OBPRingBuffer.tpp"
|
||||
#include "OBPRingBuffer.tpp"
|
||||
|
|
|
@ -64,6 +64,13 @@ String RingBuffer<T>::getName() const
|
|||
return dataName;
|
||||
}
|
||||
|
||||
// Get buffer data format
|
||||
template <typename T>
|
||||
String RingBuffer<T>::getFormat() const
|
||||
{
|
||||
return dataFmt;
|
||||
}
|
||||
|
||||
// Add a new value to buffer
|
||||
template <typename T>
|
||||
void RingBuffer<T>::add(const T& value)
|
||||
|
@ -373,4 +380,4 @@ std::vector<T> RingBuffer<T>::getAllValues() const
|
|||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,40 @@
|
|||
|
||||
static const double radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees
|
||||
|
||||
// Get maximum difference of last <amount> of TWD ringbuffer values to center chart; returns "0" if data is not valid
|
||||
int getCntr(const RingBuffer<int16_t>& windDirHstry, size_t amount)
|
||||
{
|
||||
int minVal = windDirHstry.getMinVal();
|
||||
size_t count = windDirHstry.getCurrentSize();
|
||||
|
||||
if (windDirHstry.isEmpty() || amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
int16_t midWndDir, minWndDir, maxWndDir = 0;
|
||||
int wndCenter = 0;
|
||||
|
||||
midWndDir = windDirHstry.getMid(amount);
|
||||
if (midWndDir != INT16_MIN) {
|
||||
midWndDir = midWndDir / 1000.0 * radToDeg;
|
||||
wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value
|
||||
minWndDir = windDirHstry.getMin(amount) / 1000.0 * radToDeg;
|
||||
maxWndDir = windDirHstry.getMax(amount) / 1000.0 * radToDeg;
|
||||
if ((maxWndDir - minWndDir) > 180 && !(minWndDir > maxWndDir)) { // if wind range is > 180 and no 0° crossover, adjust wndCenter to smaller wind range end
|
||||
wndCenter = WindUtils::to360(wndCenter + 180);
|
||||
}
|
||||
}
|
||||
|
||||
return wndCenter;
|
||||
}
|
||||
|
||||
// Get maximum difference of last <amount> of TWD ringbuffer values to center chart
|
||||
int getRng(const RingBuffer<int16_t>& windDirHstry, int center, size_t amount)
|
||||
{
|
||||
int minVal = windDirHstry.getMinVal();
|
||||
size_t count = windDirHstry.getCurrentSize();
|
||||
// size_t capacity = windDirHstry.getCapacity();
|
||||
// size_t last = windDirHstry.getLastIdx();
|
||||
|
||||
if (windDirHstry.isEmpty() || amount <= 0) {
|
||||
return minVal;
|
||||
|
@ -28,7 +55,6 @@ int getRng(const RingBuffer<int16_t>& windDirHstry, int center, size_t amount)
|
|||
int maxRng = minVal;
|
||||
// Start from the newest value (last) and go backwards x times
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
// value = windDirHstry.get(((last - i) % capacity + capacity) % capacity);
|
||||
value = windDirHstry.get(count - 1 - i);
|
||||
|
||||
if (value == minVal) {
|
||||
|
@ -52,9 +78,9 @@ class PageWindPlot : public Page {
|
|||
private:
|
||||
bool keylock = false; // Keylock
|
||||
char chrtMode = 'D'; // Chart mode: 'D' for TWD, 'S' for TWS, 'B' for both
|
||||
bool showTruW = true; // Show true wind or apparant wind in chart area
|
||||
int dataIntv = 1; // Update interval for wind history chart:
|
||||
// (1)|(2)|(3)|(4) seconds for approx. 4, 8, 12, 16 min. history chart
|
||||
bool showTWS = true; // Show TWS value in chart area
|
||||
|
||||
public:
|
||||
PageWindPlot(CommonData& common) : Page(common)
|
||||
|
@ -65,8 +91,12 @@ public:
|
|||
void setupKeys() {
|
||||
Page::setupKeys();
|
||||
// commonData->keydata[0].label = "MODE";
|
||||
#if defined BOARD_OBP60S3
|
||||
commonData->keydata[1].label = "SRC";
|
||||
commonData->keydata[4].label = "INTV";
|
||||
#elif defined BOARD_OBP40S3
|
||||
commonData->keydata[1].label = "INTV";
|
||||
commonData->keydata[4].label = "TWS";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Key functions
|
||||
|
@ -83,8 +113,18 @@ public:
|
|||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Set interval for wind history chart update time
|
||||
#if defined BOARD_OBP60S3
|
||||
// Set data source TRUE | APP
|
||||
if (key == 2) {
|
||||
showTruW = !showTruW;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Set interval for wind history chart update time (interval)
|
||||
if (key == 5) {
|
||||
#elif defined BOARD_OBP40S3
|
||||
if (key == 2) {
|
||||
#endif
|
||||
if (dataIntv == 1) {
|
||||
dataIntv = 2;
|
||||
} else if (dataIntv == 2) {
|
||||
|
@ -97,12 +137,6 @@ public:
|
|||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Switch TWS on/off
|
||||
if (key == 5) {
|
||||
showTWS = !showTWS;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Keylock function
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
|
@ -118,19 +152,35 @@ public:
|
|||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
String wndSrc; // Wind source true/apparant wind - preselection for OBP40
|
||||
|
||||
wndSrc = commonData->config->getString("page" + String(pageData.pageNumber) + "wndsrc");
|
||||
if (wndSrc =="True wind") {
|
||||
showTruW = true;
|
||||
} else {
|
||||
showTruW = false; // Wind source is apparant wind
|
||||
}
|
||||
commonData->logger->logDebug(GwLog::LOG,"New PageWindPlot: wind source=%s", wndSrc);
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
int displayPage(PageData& pageData) {
|
||||
|
||||
float twsValue; // TWS value in chart area
|
||||
static String twdName, twdUnit; // TWD name and unit
|
||||
static int updFreq; // Update frequency for TWD
|
||||
static int16_t twdLowest, twdHighest; // TWD range
|
||||
// static int16_t twdBufMinVal; // lowest possible twd buffer value; used for non-set data
|
||||
static RingBuffer<int16_t>* wdHstry; // Wind direction data buffer
|
||||
static RingBuffer<int16_t>* wsHstry; // Wind speed data buffer
|
||||
static String wdName, wdFormat; // Wind direction name and format
|
||||
static String wsName, wsFormat; // Wind speed name and format
|
||||
static int updFreq; // Update frequency for wind direction
|
||||
static int16_t wdLowest, wdHighest; // Wind direction range
|
||||
float wsValue; // Wind speed value in chart area
|
||||
String wsUnit; // Wind speed unit in chart area
|
||||
static GwApi::BoatValue* wsBVal = new GwApi::BoatValue("TWS"); // temp BoatValue for wind speed unit identification; required by OBP60Formater
|
||||
|
||||
// current boat data values; TWD only for validation test, TWS for display of current value
|
||||
const int numBoatData = 2;
|
||||
// current boat data values; TWD/AWD only for validation test, TWS/AWS for display of current value
|
||||
const int numBoatData = 4;
|
||||
GwApi::BoatValue* bvalue;
|
||||
String BDataName[numBoatData];
|
||||
double BDataValue[numBoatData];
|
||||
|
@ -158,16 +208,15 @@ public:
|
|||
static size_t lastIdx; // Last index of TWD history buffer
|
||||
static size_t lastAddedIdx = 0; // Last index of TWD history buffer when new data was added
|
||||
static int oldDataIntv; // remember recent user selection of data interval
|
||||
static bool oldShowTruW; // remember recent user selection of wind data type
|
||||
|
||||
static int wndCenter; // chart wind center value position
|
||||
static int wndLeft; // chart wind left value position
|
||||
static int wndRight; // chart wind right value position
|
||||
static int chrtRng; // Range of wind values from mid wind value to min/max wind value in degrees
|
||||
int diffRng; // Difference between mid and current wind value
|
||||
static const int dfltRng = 40; // Default range for chart
|
||||
static const int dfltRng = 60; // Default range for chart
|
||||
int midWndDir; // New value for wndCenter after chart start / shift
|
||||
static int simTwd; // Simulation value for TWD
|
||||
static float simTws; // Simulation value for TWS
|
||||
|
||||
int x, y; // x and y coordinates for drawing
|
||||
static int prevX, prevY; // Last x and y coordinates for drawing
|
||||
|
@ -175,23 +224,27 @@ public:
|
|||
int chrtVal; // Current wind value
|
||||
static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line
|
||||
|
||||
logger->logDebug(GwLog::LOG, "Display page WindPlot");
|
||||
logger->logDebug(GwLog::LOG, "Display PageWindPlot");
|
||||
|
||||
if (!isInitialized) {
|
||||
width = epd->width();
|
||||
height = epd->height();
|
||||
xCenter = width / 2;
|
||||
cHeight = height - yOffset - 22;
|
||||
bufSize = pageData.boatHstry.twdHstry->getCapacity();
|
||||
numNoData = 0;
|
||||
simTwd = pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg;
|
||||
simTws = 0;
|
||||
twsValue = 0;
|
||||
bufStart = 0;
|
||||
oldDataIntv = 0;
|
||||
oldShowTruW = false; // we want to initialize wind buffers at 1st time routine runs
|
||||
wdHstry = pageData.boatHstry.twdHstry;
|
||||
bufSize = wdHstry->getCapacity();
|
||||
wsHstry = pageData.boatHstry.twsHstry;
|
||||
bufSize = wsHstry->getCapacity();
|
||||
wdHstry->getMetaData(wdName, wdFormat, updFreq, wdLowest, wdHighest);
|
||||
wsHstry->getMetaData(wsName, wsFormat, updFreq, wdLowest, wdHighest);
|
||||
wsValue = 0;
|
||||
wsBVal->setFormat(wsHstry->getFormat());
|
||||
numAddedBufVals, currIdx, lastIdx = 0;
|
||||
lastAddedIdx = pageData.boatHstry.twdHstry->getLastIdx();
|
||||
pageData.boatHstry.twdHstry->getMetaData(twdName, twdUnit, updFreq, twdLowest, twdHighest);
|
||||
lastAddedIdx = wdHstry->getLastIdx();
|
||||
wndCenter = INT_MIN;
|
||||
midWndDir = 0;
|
||||
diffRng = dfltRng;
|
||||
|
@ -219,9 +272,25 @@ public:
|
|||
setFlashLED(false);
|
||||
}
|
||||
|
||||
if (showTruW != oldShowTruW) {
|
||||
if (showTruW) {
|
||||
wdHstry = pageData.boatHstry.twdHstry;
|
||||
wsHstry = pageData.boatHstry.twsHstry;
|
||||
} else {
|
||||
wdHstry = pageData.boatHstry.awdHstry;
|
||||
wsHstry = pageData.boatHstry.awsHstry;
|
||||
}
|
||||
wdHstry->getMetaData(wdName, wdFormat, updFreq, wdLowest, wdHighest);
|
||||
wsHstry->getMetaData(wsName, wsFormat, updFreq, wdLowest, wdHighest);
|
||||
bufSize = wdHstry->getCapacity();
|
||||
wsBVal->setFormat(wsHstry->getFormat());
|
||||
|
||||
oldShowTruW = showTruW;
|
||||
}
|
||||
|
||||
// Identify buffer size and buffer start position for chart
|
||||
count = pageData.boatHstry.twdHstry->getCurrentSize();
|
||||
currIdx = pageData.boatHstry.twdHstry->getLastIdx();
|
||||
count = wdHstry->getCurrentSize();
|
||||
currIdx = wdHstry->getLastIdx();
|
||||
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
|
||||
if (dataIntv != oldDataIntv || count == 1) {
|
||||
// new data interval selected by user
|
||||
|
@ -237,29 +306,25 @@ public:
|
|||
bufStart = max(0, bufStart - numAddedBufVals);
|
||||
}
|
||||
}
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot Dataset: count: %d, TWD: %.0f, TWS: %.1f, TWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, old: %d, act: %d",
|
||||
count, pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384, BDataValid[0],
|
||||
intvBufSize, numWndVals, bufStart, numAddedBufVals, pageData.boatHstry.twdHstry->getLastIdx(), oldDataIntv, dataIntv);
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot Dataset: count: %d, xWD: %.0f, xWS: %.1f, xWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, wind source: %s",
|
||||
count, wdHstry->getLast() / 1000.0 * radToDeg, wsHstry->getLast() / 10.0 * 1.94384, BDataValid[0], intvBufSize, numWndVals, bufStart, numAddedBufVals, wdHstry->getLastIdx(),
|
||||
showTruW ? "True" : "App");
|
||||
|
||||
// Set wndCenter from 1st real buffer value
|
||||
if (wndCenter == INT_MIN || (wndCenter == 0 && count == 1)) {
|
||||
midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals);
|
||||
if (midWndDir != INT16_MIN) {
|
||||
midWndDir = midWndDir / 1000.0 * radToDeg;
|
||||
wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value
|
||||
} else {
|
||||
wndCenter = 0;
|
||||
}
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, TWD: %.0f, wndCenter: %d, diffRng: %d, chrtRng: %d", count, pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg,
|
||||
wndCenter, diffRng, chrtRng);
|
||||
wndCenter = getCntr(*wdHstry, numWndVals);
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot Range Init: count: %d, xWD: %.0f, wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", count, wdHstry->getLast() / 1000.0 * radToDeg,
|
||||
wndCenter, diffRng, chrtRng, wdHstry->getMin(numWndVals) / 1000.0 * radToDeg, wdHstry->getMax(numWndVals) / 1000.0 * radToDeg);
|
||||
} else {
|
||||
// check and adjust range between left, center, and right chart limit
|
||||
diffRng = getRng(*pageData.boatHstry.twdHstry, wndCenter, numWndVals);
|
||||
diffRng = getRng(*wdHstry, wndCenter, numWndVals);
|
||||
diffRng = (diffRng == INT16_MIN ? 0 : diffRng);
|
||||
if (diffRng > chrtRng) {
|
||||
chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 degree value
|
||||
} else if (diffRng + 10 < chrtRng) { // Reduce chart range for higher resolution if possible
|
||||
chrtRng = max(dfltRng, int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10);
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot Range adjust: wndCenter: %d, diffRng: %d, chrtRng: %d, Min: %.0f, Max: %.0f", wndCenter, diffRng, chrtRng,
|
||||
wdHstry->getMin(numWndVals) / 1000.0 * radToDeg, wdHstry->getMax(numWndVals) / 1000.0 * radToDeg);
|
||||
}
|
||||
}
|
||||
chrtScl = float(width) / float(chrtRng) / 2.0; // Chart scale: pixels per degree
|
||||
|
@ -285,7 +350,7 @@ public:
|
|||
char sWndLbl[4]; // char buffer for Wind angle label
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(xCenter - 88, yOffset - 3);
|
||||
epd->print("TWD"); // Wind data name
|
||||
epd->print(wdName); // Wind data name
|
||||
snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter);
|
||||
drawTextCenter(xCenter, yOffset - 11, sWndLbl);
|
||||
epd->drawCircle(xCenter + 25, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
|
||||
|
@ -301,11 +366,11 @@ public:
|
|||
epd->drawCircle(width - 5, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
|
||||
epd->drawCircle(width - 5, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
|
||||
|
||||
if (pageData.boatHstry.twdHstry->getMax() == pageData.boatHstry.twdHstry->getMinVal()) {
|
||||
if (wdHstry->getMax() == wdHstry->getMinVal()) {
|
||||
// only <INT16_MIN> values in buffer -> no valid wind data available
|
||||
wndDataValid = false;
|
||||
} else if (!BDataValid[0]) {
|
||||
// currently no valid TWD data available
|
||||
} else if (!BDataValid[0] && !simulation) {
|
||||
// currently no valid TWD data available and no simulation mode
|
||||
numNoData++;
|
||||
wndDataValid = true;
|
||||
if (numNoData > 3) {
|
||||
|
@ -320,7 +385,7 @@ public:
|
|||
//***********************************************************************
|
||||
if (wndDataValid) {
|
||||
for (int i = 0; i < (numWndVals / dataIntv); i++) {
|
||||
chrtVal = static_cast<int>(pageData.boatHstry.twdHstry->get(bufStart + (i * dataIntv))); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer
|
||||
chrtVal = static_cast<int>(wdHstry->get(bufStart + (i * dataIntv))); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer
|
||||
if (chrtVal == INT16_MIN) {
|
||||
chrtPrevVal = INT16_MIN;
|
||||
} else {
|
||||
|
@ -328,8 +393,7 @@ public:
|
|||
x = ((chrtVal - wndLeft + 360) % 360) * chrtScl;
|
||||
y = yOffset + cHeight - i; // Position in chart area
|
||||
|
||||
// if (i >= (numWndVals / dataIntv) - 10)
|
||||
if (i >= (numWndVals / dataIntv) - 1)
|
||||
if (i >= (numWndVals / dataIntv) - 1) // log chart data of 1 line (adjust for test purposes)
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %d, bufStart: %d, count: %d, linesToShow: %d", i, chrtVal, bufStart, count, (numWndVals / dataIntv));
|
||||
|
||||
if ((i == 0) || (chrtPrevVal == INT16_MIN)) {
|
||||
|
@ -361,41 +425,27 @@ public:
|
|||
if (i >= (cHeight - 1)) {
|
||||
oldDataIntv = 0; // force reset of buffer start and number of values to show in next display loop
|
||||
|
||||
int minWndDir = pageData.boatHstry.twdHstry->getMin(numWndVals) / 1000.0 * radToDeg;
|
||||
int maxWndDir = pageData.boatHstry.twdHstry->getMax(numWndVals) / 1000.0 * radToDeg;
|
||||
int minWndDir = wdHstry->getMin(numWndVals) / 1000.0 * radToDeg;
|
||||
int maxWndDir = wdHstry->getMax(numWndVals) / 1000.0 * radToDeg;
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter);
|
||||
// if ((minWndDir + 540 >= wndCenter + 540) || (maxWndDir + 540 <= wndCenter + 540)) {
|
||||
if (((minWndDir - wndCenter >= 0) && (minWndDir - wndCenter < 180)) || ((maxWndDir - wndCenter <= 0) && (maxWndDir - wndCenter >=180))) {
|
||||
// Check if all wind value are left or right of center value -> optimize chart range
|
||||
midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals) / 1000.0 * radToDeg;
|
||||
if (midWndDir != INT16_MIN) {
|
||||
wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value
|
||||
}
|
||||
// if (((minWndDir - wndCenter >= 0) && (minWndDir - wndCenter < 180)) || ((maxWndDir - wndCenter <= 0) && (maxWndDir - wndCenter >=180))) {
|
||||
if ((wndRight > wndCenter && (minWndDir >= wndCenter && minWndDir <= wndRight)) || (wndRight <= wndCenter && (minWndDir >= wndCenter || minWndDir <= wndRight)) || (wndLeft < wndCenter && (maxWndDir <= wndCenter && maxWndDir >= wndLeft)) || (wndLeft >= wndCenter && (maxWndDir <= wndCenter || maxWndDir >= wndLeft))) {
|
||||
// Check if all wind value are left or right of center value -> optimize chart center
|
||||
wndCenter = getCntr(*wdHstry, numWndVals);
|
||||
}
|
||||
logger->logDebug(GwLog::DEBUG, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// No valid data available
|
||||
logger->logDebug(GwLog::LOG, "PageWindPlot: No valid data available");
|
||||
epd->setFont(&Ubuntu_Bold10pt8b);
|
||||
epd->fillRect(xCenter - 33, height / 2 - 20, 66, 24, commonData->bgcolor); // Clear area for message
|
||||
drawTextCenter(xCenter, height / 2 - 10, "No data");
|
||||
}
|
||||
|
||||
// Print TWS value
|
||||
if (showTWS) {
|
||||
// Print wind speed value
|
||||
int currentZone;
|
||||
static int lastZone = 0;
|
||||
static bool flipTws = false;
|
||||
int xPosTws;
|
||||
static const int yPosTws = yOffset + 40;
|
||||
|
||||
twsValue = pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384; // TWS value in knots
|
||||
|
||||
xPosTws = flipTws ? 20 : width - 138;
|
||||
xPosTws = flipTws ? 20 : width - 145;
|
||||
currentZone = (y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146) ? 1 : 0; // Define current zone for TWS value
|
||||
if (currentZone != lastZone) {
|
||||
// Only flip when x moves to a different zone
|
||||
|
@ -406,28 +456,36 @@ public:
|
|||
}
|
||||
lastZone = currentZone;
|
||||
|
||||
wsValue = wsHstry->getLast();
|
||||
wsBVal->value = wsValue; // temp variable to retreive data unit from OBP60Formater
|
||||
wsBVal->valid = (static_cast<int16_t>(wsValue) != wsHstry->getMinVal());
|
||||
wsUnit = formatValue(wsBVal, *commonData).unit; // Unit of value
|
||||
epd->fillRect(xPosTws - 4, yPosTws - 38, 142, 44, commonData->bgcolor); // Clear area for TWS value
|
||||
epd->setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
epd->setCursor(xPosTws, yPosTws);
|
||||
if (!BDataValid[1]) {
|
||||
if (!wsBVal->valid) {
|
||||
epd->print("--.-");
|
||||
} else {
|
||||
double dbl = BDataValue[1] * 3.6 / 1.852;
|
||||
if (dbl < 10.0) {
|
||||
epd->printf("!%3.1f", dbl); // Value, round to 1 decimal
|
||||
wsValue = wsValue / 10.0 * 1.94384; // Wind speed value in knots
|
||||
if (wsValue < 10.0) {
|
||||
epd->printf("!%3.1f", wsValue); // Value, round to 1 decimal
|
||||
} else {
|
||||
epd->printf("%4.1f", dbl); // Value, round to 1 decimal
|
||||
epd->printf("%4.1f", wsValue); // Value, round to 1 decimal
|
||||
}
|
||||
}
|
||||
epd->setFont(&Ubuntu_Bold12pt8b);
|
||||
epd->setCursor(xPosTws + 82, yPosTws - 14);
|
||||
// epd->print("TWS"); // Name
|
||||
epd->print(BDataName[1]); // Name
|
||||
epd->print(wsName); // Name
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
// epd->setCursor(xPosTws + 78, yPosTws + 1);
|
||||
epd->setCursor(xPosTws + 82, yPosTws + 1);
|
||||
// epd->printf(" kn"); // Unit
|
||||
epd->print(BDataUnit[1]); // Unit
|
||||
epd->print(wsUnit); // Unit
|
||||
|
||||
} else {
|
||||
// No valid data available
|
||||
LOG_DEBUG(GwLog::LOG, "PageWindPlot: No valid data available");
|
||||
epd->setFont(&Ubuntu_Bold10pt8b);
|
||||
epd->fillRect(xCenter - 33, height / 2 - 20, 66, 24, commonData->bgcolor); // Clear area for message
|
||||
drawTextCenter(xCenter, height / 2 - 10, "No data");
|
||||
}
|
||||
|
||||
// chart Y axis labels; print at last to overwrite potential chart lines in label area
|
||||
|
@ -457,19 +515,17 @@ static Page* createPage(CommonData& common)
|
|||
{
|
||||
return new PageWindPlot(common);
|
||||
}
|
||||
/**
|
||||
* with the code below we make this page known to the PageTask
|
||||
|
||||
/* 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 (0 here)
|
||||
* and will will provide the names of the fixed values we need
|
||||
*/
|
||||
* and will will provide the names of the fixed values we need */
|
||||
PageDescription registerPageWindPlot(
|
||||
"WindPlot", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{ "TWD", "TWS" }, // Bus values we need in the page
|
||||
// {}, // Bus values we need in the page
|
||||
{ "TWD", "TWS", "AWD", "AWS" }, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ class PageWindRoseFlex : public Page
|
|||
{
|
||||
private:
|
||||
String lengthformat;
|
||||
int16_t lp = 80; // Pointer length
|
||||
int16_t lp = 80; // Pointer length
|
||||
char source = 'A'; // data source (A)pparent | (T)rue
|
||||
String ssource="App."; // String for Data Source
|
||||
|
||||
public:
|
||||
PageWindRoseFlex(CommonData &common) : Page(common)
|
||||
|
@ -20,6 +22,11 @@ public:
|
|||
lengthformat = config->getString(config->lengthFormat);
|
||||
}
|
||||
|
||||
void setupKeys() {
|
||||
Page::setupKeys();
|
||||
commonData->keydata[1].label = "SRC";
|
||||
}
|
||||
|
||||
// Key functions
|
||||
int handleKey(int key) {
|
||||
// Code for keylock
|
||||
|
@ -55,37 +62,50 @@ public:
|
|||
static String svalue6old = "";
|
||||
static String unit6old = "";
|
||||
|
||||
// Get boat values #1
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
GwApi::BoatValue *bvalue1; // Value 1 for angle
|
||||
GwApi::BoatValue *bvalue2; // Value 2 for speed
|
||||
|
||||
// Get boat value for wind angle (AWA/TWA), shown by pointer
|
||||
if (source == 'A') {
|
||||
bvalue1 = pageData.values[4];
|
||||
} else {
|
||||
bvalue1 = pageData.values[6];
|
||||
}
|
||||
String name1 = bvalue1->getName().c_str(); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
|
||||
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
|
||||
if(valid1 == true){
|
||||
if (valid1 == true) {
|
||||
svalue1old = svalue1; // Save old value
|
||||
unit1old = unit1; // Save old unit
|
||||
}
|
||||
|
||||
// Get boat values #2
|
||||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
// Get boat value for wind speed (AWS/TWS), shown in top left corner
|
||||
if (source == 'A') {
|
||||
bvalue2 =pageData.values[5];
|
||||
} else {
|
||||
bvalue2 = pageData.values[7];
|
||||
}
|
||||
String name2 = bvalue2->getName().c_str(); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
if (simulation) {
|
||||
value2 = 0.62731; // some random value
|
||||
}
|
||||
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
|
||||
if(valid2 == true){
|
||||
if (valid2 == true) {
|
||||
svalue2old = svalue2; // Save old value
|
||||
unit2old = unit2; // Save old unit
|
||||
}
|
||||
|
||||
// Get boat values #3
|
||||
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Third element in list
|
||||
// Get boat value for bottom left corner
|
||||
GwApi::BoatValue *bvalue3 = pageData.values[0];
|
||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||
name3 = name3.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
|
@ -98,8 +118,8 @@ public:
|
|||
unit3old = unit3; // Save old unit
|
||||
}
|
||||
|
||||
// Get boat values #4
|
||||
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Fourth element in list
|
||||
// Get boat value for top right corner
|
||||
GwApi::BoatValue *bvalue4 = pageData.values[1];
|
||||
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
||||
name4 = name4.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
|
@ -112,8 +132,8 @@ public:
|
|||
unit4old = unit4; // Save old unit
|
||||
}
|
||||
|
||||
// Get boat values #5
|
||||
GwApi::BoatValue *bvalue5 = pageData.values[4]; // Fifth element in list
|
||||
// Get boat value for bottom right corner
|
||||
GwApi::BoatValue *bvalue5 = pageData.values[2];
|
||||
String name5 = xdrDelete(bvalue5->getName()); // Value name
|
||||
name5 = name5.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
|
||||
|
@ -126,8 +146,8 @@ public:
|
|||
unit5old = unit5; // Save old unit
|
||||
}
|
||||
|
||||
// Get boat values #5
|
||||
GwApi::BoatValue *bvalue6 = pageData.values[5]; // Sixth element in list
|
||||
// Get boat value for center
|
||||
GwApi::BoatValue *bvalue6 = pageData.values[3];
|
||||
String name6 = xdrDelete(bvalue6->getName()); // Value name
|
||||
name6 = name6.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
|
||||
|
@ -152,7 +172,7 @@ public:
|
|||
|
||||
epd->setTextColor(commonData->fgcolor);
|
||||
|
||||
// Show value 2 at position of value 1 (top left)
|
||||
// Show AWS or TWS top left
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 65);
|
||||
epd->print(svalue2); // Value
|
||||
|
@ -167,7 +187,7 @@ public:
|
|||
// Horizintal separator left
|
||||
epd->fillRect(0, 149, 60, 3, commonData->fgcolor);
|
||||
|
||||
// Show value 3 at bottom left
|
||||
// Show value 3 (=first user-configured parameter) at bottom left
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(10, 270);
|
||||
epd->print(svalue3); // Value
|
||||
|
@ -180,11 +200,10 @@ public:
|
|||
epd->print(holdvalues ? unit3old : unit3);
|
||||
|
||||
|
||||
// Show value 4 at top right
|
||||
// Show value 4 (=second user-configured parameter) at top right
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(295, 65);
|
||||
if(valid3 == true){
|
||||
// epd->print(abs(value3 * 180 / M_PI), 0); // Value
|
||||
epd->print(svalue4); // Value
|
||||
}
|
||||
else{
|
||||
|
@ -202,7 +221,7 @@ public:
|
|||
// Horizintal separator right
|
||||
epd->fillRect(340, 149, 80, 3, commonData->fgcolor);
|
||||
|
||||
// Show value 5 at bottom right
|
||||
// Show value 5 (=third user-configured parameter) at bottom right
|
||||
epd->setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
epd->setCursor(295, 270);
|
||||
epd->print(svalue5); // Value
|
||||
|
@ -311,21 +330,37 @@ public:
|
|||
|
||||
//*******************************************************************************************
|
||||
|
||||
// Show value6, so that it does not collide with the wind pointer
|
||||
// Show value6 (=fourth user-configured parameter) and ssource, so that they do not collide with the wind pointer
|
||||
if (cos(value1) > 0) {
|
||||
epd->setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
if (cos(value1) > 0){
|
||||
epd->setCursor(160, 200);
|
||||
epd->print(svalue6); // Value
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(190, 215);
|
||||
} else{
|
||||
epd->setCursor(160, 130);
|
||||
epd->print(svalue6); // Value
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(190, 90);
|
||||
}
|
||||
epd->setCursor(160, 200);
|
||||
epd->print(svalue6); // Value
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(190, 215);
|
||||
epd->print(" ");
|
||||
epd->print(holdvalues ? unit6old : unit6);
|
||||
if (sin(value1) > 0) {
|
||||
epd->setCursor(160, 130);
|
||||
} else {
|
||||
epd->setCursor(220, 130);
|
||||
}
|
||||
epd->print(ssource); // true or app.
|
||||
}
|
||||
else {
|
||||
epd->setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
epd->setCursor(160, 130);
|
||||
epd->print(svalue6);
|
||||
epd->setFont(&Ubuntu_Bold8pt8b);
|
||||
epd->setCursor(190, 90);
|
||||
epd->print(" ");
|
||||
epd->print(holdvalues ? unit6old : unit6);
|
||||
if (sin(value1) > 0) {
|
||||
epd->setCursor(160, 130);
|
||||
} else {
|
||||
epd->setCursor(220, 130);
|
||||
}
|
||||
epd->print(ssource); //true or app.
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
@ -338,13 +373,14 @@ static Page *createPage(CommonData &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 (0 here)
|
||||
* and we provide the number of user parameters we expect (4 here)
|
||||
* and will will provide the names of the fixed values we need
|
||||
*/
|
||||
PageDescription registerPageWindRoseFlex(
|
||||
"WindRoseFlex", // Page name
|
||||
createPage, // Action
|
||||
6, // Number of bus values depends on selection in Web configuration; was zero
|
||||
4, // Number of bus values depends on selection in Web configuration
|
||||
{"AWA", "AWS", "TWA", "TWS"}, // fixed values we need in the page. They are inserted AFTER the web-configured values.
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
|
|
|
@ -1674,6 +1674,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page1wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 1: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 1",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page1type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page2type",
|
||||
"label": "Type",
|
||||
|
@ -1976,6 +1996,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page2wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 2: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 2",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page2type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page3type",
|
||||
"label": "Type",
|
||||
|
@ -2269,6 +2309,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page3wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 3: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 3",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page3type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page4type",
|
||||
"label": "Type",
|
||||
|
@ -2553,6 +2613,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page4wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 4: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 4",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page4type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page5type",
|
||||
"label": "Type",
|
||||
|
@ -2828,6 +2908,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page5wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 5: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 5",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page5type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page6type",
|
||||
"label": "Type",
|
||||
|
@ -3094,6 +3194,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page6wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 6: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 6",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page6type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page7type",
|
||||
"label": "Type",
|
||||
|
@ -3351,6 +3471,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page7wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 7: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 7",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page7type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page8type",
|
||||
"label": "Type",
|
||||
|
@ -3599,6 +3739,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page8wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 8: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 8",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page8type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page9type",
|
||||
"label": "Type",
|
||||
|
@ -3838,6 +3998,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page9wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 9: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 9",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page9type": "WindPlot"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page10type",
|
||||
"label": "Type",
|
||||
|
@ -4067,5 +4247,25 @@
|
|||
"page10type": "Fluid"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "page10wndsrc",
|
||||
"label": "Wind source",
|
||||
"type": "list",
|
||||
"default": "True wind",
|
||||
"description": "Wind source for page 10: [true|apparant]",
|
||||
"list": [
|
||||
"True wind",
|
||||
"Apparant wind"
|
||||
],
|
||||
"category": "OBP40 Page 10",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
},
|
||||
"condition": [
|
||||
{
|
||||
"page10type": "WindPlot"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
(function(){
|
||||
const api=window.esp32nmea2k;
|
||||
if (! api) return;
|
||||
const tabName="OBP60";
|
||||
api.registerListener((id, data) => {
|
||||
// if (!data.testboard) return; //do nothing if we are not active
|
||||
let page = api.addTabPage(tabName, "OBP60");
|
||||
api.addEl('button', '', page, 'Screenshot').addEventListener('click', function (ev) {
|
||||
window.open('/api/user/OBP60Task/screenshot', 'screenshot');
|
||||
})
|
||||
}, api.EVENTS.init);
|
||||
})();
|
|
@ -339,9 +339,8 @@ void underVoltageDetection(GwApi *api, CommonData &common){
|
|||
}
|
||||
}
|
||||
|
||||
//bool addTrueWind(GwApi* api, BoatValueList* boatValues, double *twd, double *tws, double *twa) {
|
||||
// Calculate true wind data and add to obp60task boat data list
|
||||
bool addTrueWind(GwApi* api, BoatValueList* boatValues) {
|
||||
// Calculate true wind data and add to obp60task boat data list
|
||||
|
||||
double awaVal, awsVal, cogVal, stwVal, sogVal, hdtVal, hdmVal, varVal;
|
||||
double twd, tws, twa;
|
||||
|
@ -367,7 +366,7 @@ bool addTrueWind(GwApi* api, BoatValueList* boatValues) {
|
|||
hdtVal = hdtBVal->valid ? hdtBVal->value : DBL_MIN;
|
||||
hdmVal = hdmBVal->valid ? hdmBVal->value : DBL_MIN;
|
||||
varVal = varBVal->valid ? varBVal->value : DBL_MIN;
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"obp60task addTrueWind: AWA %.1f, AWS %.1f, COG %.1f, STW %.1f, SOG %.1f, HDT %.1f, HDM %.1f, VAR %.1f", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852,
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"obp60task addTrueWind: AWA %.1f, AWS %.1f, COG %.1f, STW %.1f, SOG %.2f, HDT %.1f, HDM %.1f, VAR %.1f", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852,
|
||||
cogBVal->value * RAD_TO_DEG, stwBVal->value * 3.6 / 1.852, sogBVal->value * 3.6 / 1.852, hdtBVal->value * RAD_TO_DEG, hdmBVal->value * RAD_TO_DEG, varBVal->value * RAD_TO_DEG);
|
||||
|
||||
isCalculated = WindUtils::calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &sogVal, &hdtVal, &hdmVal, &varVal, &twd, &tws, &twa);
|
||||
|
@ -386,31 +385,42 @@ bool addTrueWind(GwApi* api, BoatValueList* boatValues) {
|
|||
twaBVal->valid = true;
|
||||
}
|
||||
}
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"obp60task addTrueWind: TWD_Valid %d, isCalculated %d, TWD %.1f, TWA %.1f, TWS %.1f", twdBVal->valid, isCalculated, twdBVal->value * RAD_TO_DEG,
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"obp60task addTrueWind: isCalculated %d, TWD %.1f, TWA %.1f, TWS %.1f", isCalculated, twdBVal->value * RAD_TO_DEG,
|
||||
twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852);
|
||||
|
||||
return isCalculated;
|
||||
}
|
||||
|
||||
// Init history buffers for selected boat data
|
||||
void initHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList) {
|
||||
// Init history buffers for TWD, TWS
|
||||
|
||||
GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here
|
||||
const double DBL_MIN = std::numeric_limits<double>::lowest();
|
||||
|
||||
int hstryUpdFreq = 1000; // Update frequency for history buffers in ms
|
||||
int hstryMinVal = 0; // Minimum value for these history buffers
|
||||
int twdHstryMax = 6283; // Max value for wind direction (TWD) in rad (0...2*PI), shifted by 1000 for 3 decimals
|
||||
int twsHstryMax = 1000; // Max value for wind speed (TWS) in m/s, shifted by 10 for 1 decimal
|
||||
int twdHstryMax = 6283; // Max value for wind direction (TWD, AWD) in rad (0...2*PI), shifted by 1000 for 3 decimals
|
||||
int twsHstryMax = 1000; // Max value for wind speed (TWS, AWS) in m/s, shifted by 10 for 1 decimal
|
||||
// Initialize history buffers with meta data
|
||||
hstryBufList.twdHstry->setMetaData("TWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax);
|
||||
hstryBufList.twsHstry->setMetaData("TWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax);
|
||||
hstryBufList.awdHstry->setMetaData("AWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax);
|
||||
hstryBufList.awsHstry->setMetaData("AWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax);
|
||||
|
||||
// create boat values for history data types, if they don't exist yet
|
||||
GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName());
|
||||
GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName());
|
||||
GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA");
|
||||
GwApi::BoatValue *awdBVal = boatValues->findValueOrCreate(hstryBufList.awdHstry->getName());
|
||||
GwApi::BoatValue *awsBVal = boatValues->findValueOrCreate(hstryBufList.awsHstry->getName());
|
||||
|
||||
if (!awdBVal->valid) { // AWD usually does not exist
|
||||
awdBVal->setFormat(hstryBufList.awdHstry->getFormat());
|
||||
awdBVal->value = DBL_MIN;
|
||||
}
|
||||
}
|
||||
|
||||
void handleHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList) {
|
||||
void handleHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList, bool useSimuData) {
|
||||
// Handle history buffers for TWD, TWS
|
||||
|
||||
GwLog *logger = api->getLogger();
|
||||
|
@ -419,42 +429,110 @@ void handleHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryB
|
|||
int16_t twdHstryMax = hstryBufList.twdHstry->getMaxVal();
|
||||
int16_t twsHstryMin = hstryBufList.twsHstry->getMinVal();
|
||||
int16_t twsHstryMax = hstryBufList.twsHstry->getMaxVal();
|
||||
int16_t twdBuf, twsBuf;
|
||||
int16_t awdHstryMin = hstryBufList.awdHstry->getMinVal();
|
||||
int16_t awdHstryMax = hstryBufList.awdHstry->getMaxVal();
|
||||
int16_t awsHstryMin = hstryBufList.awsHstry->getMinVal();
|
||||
int16_t awsHstryMax = hstryBufList.awsHstry->getMaxVal();
|
||||
static int16_t twd, tws = 20; //initial value only relevant if we use simulation data
|
||||
static double awd, aws, hdt = 20; //initial value only relevant if we use simulation data
|
||||
GwApi::BoatValue *calBVal; // temp variable just for data calibration -> we don't want to calibrate the original data here
|
||||
|
||||
GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName());
|
||||
GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName());
|
||||
GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA");
|
||||
GwApi::BoatValue *awdBVal = boatValues->findValueOrCreate(hstryBufList.awdHstry->getName());
|
||||
GwApi::BoatValue *awsBVal = boatValues->findValueOrCreate(hstryBufList.awsHstry->getName());
|
||||
GwApi::BoatValue *awaBVal = boatValues->findValueOrCreate("AWA");
|
||||
GwApi::BoatValue *hdtBVal = boatValues->findValueOrCreate("HDT");
|
||||
GwApi::BoatValue *hdmBVal = boatValues->findValueOrCreate("HDM");
|
||||
GwApi::BoatValue *varBVal = boatValues->findValueOrCreate("VAR");
|
||||
GwApi::BoatValue *cogBVal = boatValues->findValueOrCreate("COG");
|
||||
GwApi::BoatValue *sogBVal = boatValues->findValueOrCreate("SOG");
|
||||
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"obp60task handleHstryBuf: TWD_isValid? %d, twdBVal: %.1f, twaBVal: %.1f, twsBVal: %.1f", twdBVal->valid, twdBVal->value * RAD_TO_DEG,
|
||||
twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852);
|
||||
|
||||
api->getLogger()->logDebug(GwLog::DEBUG,"obp60task handleHstryBuf: twdBVal: %.1f, twaBVal: %.1f, twsBVal: %.1f, TWD_isValid? %d", twdBVal->value * RAD_TO_DEG,
|
||||
twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852, twdBVal->valid);
|
||||
calBVal = new GwApi::BoatValue("TWD"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(twdBVal->getFormat());
|
||||
if (twdBVal->valid) {
|
||||
calBVal = new GwApi::BoatValue("TWD"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(twdBVal->getFormat());
|
||||
calBVal->value = twdBVal->value;
|
||||
calBVal->valid = twdBVal->valid;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
twdBuf = static_cast<int16_t>(std::round(calBVal->value * 1000));
|
||||
if (twdBuf >= twdHstryMin && twdBuf <= twdHstryMax) {
|
||||
hstryBufList.twdHstry->add(twdBuf);
|
||||
twd = static_cast<int16_t>(std::round(calBVal->value * 1000));
|
||||
if (twd >= twdHstryMin && twd <= twdHstryMax) {
|
||||
hstryBufList.twdHstry->add(twd);
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
twd += random(-20, 20);
|
||||
twd = WindUtils::to360(twd);
|
||||
hstryBufList.twdHstry->add(static_cast<int16_t>(DegToRad(twd) * 1000.0));
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
|
||||
calBVal = new GwApi::BoatValue("TWS"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(twsBVal->getFormat());
|
||||
if (twsBVal->valid) {
|
||||
calBVal = new GwApi::BoatValue("TWS"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(twsBVal->getFormat());
|
||||
calBVal->value = twsBVal->value;
|
||||
calBVal->valid = twsBVal->valid;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
twsBuf = static_cast<int16_t>(std::round(calBVal->value * 10));
|
||||
if (twsBuf >= twsHstryMin && twsBuf <= twsHstryMax) {
|
||||
hstryBufList.twsHstry->add(twsBuf);
|
||||
tws = static_cast<int16_t>(std::round(calBVal->value * 10));
|
||||
if (tws >= twsHstryMin && tws <= twsHstryMax) {
|
||||
hstryBufList.twsHstry->add(tws);
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
tws += random(-50, 50); // TWS value in m/s; expands to 1 decimal
|
||||
tws = constrain(tws, 0, 250); // Limit TWS to [0..25] m/s
|
||||
hstryBufList.twsHstry->add(tws);
|
||||
}
|
||||
|
||||
if (awaBVal->valid) {
|
||||
if (hdtBVal->valid) {
|
||||
hdt = hdtBVal->value; // Use HDT if available
|
||||
} else {
|
||||
hdt = WindUtils::calcHDT(&hdmBVal->value, &varBVal->value, &cogBVal->value, &sogBVal->value);
|
||||
}
|
||||
|
||||
awd = awaBVal->value + hdt;
|
||||
awd = WindUtils::to2PI(awd);
|
||||
calBVal = new GwApi::BoatValue("AWD"); // temporary solution for calibration of history buffer values
|
||||
calBVal->value = awd;
|
||||
calBVal->setFormat(awdBVal->getFormat());
|
||||
calBVal->valid = true;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
awdBVal->value = calBVal->value;
|
||||
awdBVal->valid = true;
|
||||
awd = std::round(calBVal->value * 1000);
|
||||
if (awd >= awdHstryMin && awd <= awdHstryMax) {
|
||||
hstryBufList.awdHstry->add(static_cast<int16_t>(awd));
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
awd += random(-20, 20);
|
||||
awd = WindUtils::to360(awd);
|
||||
hstryBufList.awdHstry->add(static_cast<int16_t>(DegToRad(awd) * 1000.0));
|
||||
}
|
||||
|
||||
if (awsBVal->valid) {
|
||||
calBVal = new GwApi::BoatValue("AWS"); // temporary solution for calibration of history buffer values
|
||||
calBVal->setFormat(awsBVal->getFormat());
|
||||
calBVal->value = awsBVal->value;
|
||||
calBVal->valid = awsBVal->valid;
|
||||
calibrationData.calibrateInstance(calBVal, logger); // Check if boat data value is to be calibrated
|
||||
aws = std::round(calBVal->value * 10);
|
||||
if (aws >= awsHstryMin && aws <= awsHstryMax) {
|
||||
hstryBufList.awsHstry->add(static_cast<int16_t>(aws));
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
} else if (useSimuData) {
|
||||
aws += random(-50, 50); // TWS value in m/s; expands to 1 decimal
|
||||
aws = constrain(aws, 0, 250); // Limit TWS to [0..25] m/s
|
||||
hstryBufList.awsHstry->add(aws);
|
||||
}
|
||||
delete calBVal;
|
||||
calBVal = nullptr;
|
||||
}
|
||||
|
||||
// OBP60 Task
|
||||
|
@ -572,9 +650,11 @@ void OBP60Task(GwApi *api){
|
|||
//add all necessary data to common data
|
||||
|
||||
// Create ring buffers for history storage of some boat data
|
||||
RingBuffer<int16_t> twdHstry(960); // Circular buffer to store wind direction values; store 960 TWD values for 16 minutes history
|
||||
RingBuffer<int16_t> twsHstry(960); // Circular buffer to store wind speed values (TWS)
|
||||
tBoatHstryData hstryBufList = {&twdHstry, &twsHstry};
|
||||
RingBuffer<int16_t> twdHstry(960); // Circular buffer to store true wind direction values; store 960 TWD values for 16 minutes history
|
||||
RingBuffer<int16_t> twsHstry(960); // Circular buffer to store true wind speed values (TWS)
|
||||
RingBuffer<int16_t> awdHstry(960); // Circular buffer to store appearant wind direction values; store 960 AWD values for 16 minutes history
|
||||
RingBuffer<int16_t> awsHstry(960); // Circular buffer to store appearant xwind speed values (AWS)
|
||||
tBoatHstryData hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry};
|
||||
|
||||
//fill the page data from config
|
||||
numPages=config->getInt(config->visiblePages,1);
|
||||
|
@ -627,7 +707,7 @@ void OBP60Task(GwApi *api){
|
|||
|
||||
// Check user setting for true wind calculation
|
||||
bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false);
|
||||
// bool simulation = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
||||
bool simulation = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
||||
|
||||
// Initialize history buffer for certain boat data
|
||||
initHstryBuf(api, &boatValues, hstryBufList);
|
||||
|
@ -940,7 +1020,7 @@ void OBP60Task(GwApi *api){
|
|||
addTrueWind(api, &boatValues);
|
||||
}
|
||||
// Handle history buffers for TWD, TWS for wind plot page and other usage
|
||||
handleHstryBuf(api, &boatValues, hstryBufList);
|
||||
handleHstryBuf(api, &boatValues, hstryBufList, simulation);
|
||||
|
||||
// Clear display
|
||||
// epd->fillRect(0, 0, epd->width(), epd->height(), commonData.bgcolor);
|
||||
|
|
Loading…
Reference in New Issue