added calibration to buffer; separated buffer and wind code in opb60task; prepared simulation; getMin/Max fix for ringbuffer for invalid data; fix for chart center; cleanup code
This commit is contained in:
parent
c48c6a2e48
commit
fe2223839f
|
@ -1,45 +1,51 @@
|
||||||
#include "OBPDataOperations.h"
|
#include "OBPDataOperations.h"
|
||||||
|
|
||||||
void WindUtils::to2PI(double* a)
|
double WindUtils::to2PI(double a)
|
||||||
{
|
{
|
||||||
while (*a < 0) {
|
a = fmod(a, 2 * M_PI);
|
||||||
*a += 2 * M_PI;
|
if (a < 0.0) {
|
||||||
|
a += 2 * M_PI;
|
||||||
}
|
}
|
||||||
*a = fmod(*a, 2 * M_PI);
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindUtils::toPI(double* a)
|
double WindUtils::toPI(double a)
|
||||||
{
|
{
|
||||||
*a += M_PI;
|
a += M_PI;
|
||||||
to2PI(a);
|
a = to2PI(a);
|
||||||
*a -= M_PI;
|
a -= M_PI;
|
||||||
|
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindUtils::to360(double* a)
|
double WindUtils::to360(double a)
|
||||||
{
|
{
|
||||||
while (*a < 0) {
|
a = fmod(a, 360);
|
||||||
*a += 360;
|
if (a < 0.0) {
|
||||||
|
a += 360;
|
||||||
}
|
}
|
||||||
*a = fmod(*a, 360);
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindUtils::to180(double* a)
|
double WindUtils::to180(double a)
|
||||||
{
|
{
|
||||||
*a += 180;
|
a += 180;
|
||||||
to360(a);
|
a = to360(a);
|
||||||
*a -= 180;
|
a -= 180;
|
||||||
|
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindUtils::toCart(const double* phi, const double* r, double* x, double* y)
|
void WindUtils::toCart(const double* phi, const double* r, double* x, double* y)
|
||||||
{
|
{
|
||||||
*x = *r * sin(radians(*phi));
|
*x = *r * sin(*phi);
|
||||||
*y = *r * cos(radians(*phi));
|
*y = *r * cos(*phi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindUtils::toPol(const double* x, const double* y, double* phi, double* r)
|
void WindUtils::toPol(const double* x, const double* y, double* phi, double* r)
|
||||||
{
|
{
|
||||||
*phi = 90 - degrees(atan2(*y, *x));
|
*phi = (M_PI / 2) - atan2(*y, *x);
|
||||||
to360(phi);
|
*phi = to2PI(*phi);
|
||||||
*r = sqrt(*x * *x + *y * *y);
|
*r = sqrt(*x * *x + *y * *y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,80 +63,96 @@ void WindUtils::addPolar(const double* phi1, const double* r1,
|
||||||
|
|
||||||
void WindUtils::calcTwdSA(const double* AWA, const double* AWS,
|
void WindUtils::calcTwdSA(const double* AWA, const double* AWS,
|
||||||
const double* CTW, const double* STW, const double* HDT,
|
const double* CTW, const double* STW, const double* HDT,
|
||||||
double* TWD, double* TWS)
|
double* TWD, double* TWS, double* TWA)
|
||||||
{
|
{
|
||||||
double AWD = *AWA + *HDT;
|
double awd = *AWA + *HDT;
|
||||||
|
awd = to2PI(awd);
|
||||||
double stw = -*STW;
|
double stw = -*STW;
|
||||||
Serial.println("calcTwdSA: AWA: " + String(*AWA) + ", AWS: " + String(*AWS) + ", CTW: " + String(*CTW) + ", STW: " + String(*STW) + ", HDT: " + String(*HDT));
|
// Serial.println("\ncalcTwdSA: AWA: " + String(*AWA) + ", AWS: " + String(*AWS) + ", CTW: " + String(*CTW) + ", STW: " + String(*STW) + ", HDT: " + String(*HDT));
|
||||||
addPolar(&AWD, AWS, CTW, &stw, TWD, TWS);
|
addPolar(&awd, AWS, CTW, &stw, TWD, TWS);
|
||||||
|
|
||||||
// Normalize TWD to 0-360°
|
// Normalize TWD and TWA to 0-360°
|
||||||
while (*TWD < 0)
|
*TWD = to2PI(*TWD);
|
||||||
*TWD += 360;
|
*TWA = toPI(*TWD - *HDT);
|
||||||
while (*TWD >= 360)
|
// Serial.println("calcTwdSA: TWD: " + String(*TWD) + ", TWS: " + String(*TWS));
|
||||||
*TWD -= 360;
|
|
||||||
|
|
||||||
Serial.println("calcTwdSA: TWD: " + String(*TWD) + ", TWS: " + String(*TWS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
bool WindUtils::calcTrueWind(const double* awaVal, const double* awsVal,
|
||||||
const double* cogVal, const double* stwVal, const double* hdtVal,
|
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||||
const double* hdmVal, double* twdVal, double* twsVal)
|
const double* hdmVal, const double* varVal, double* twdVal, double* twsVal, double* twaVal)
|
||||||
{
|
{
|
||||||
double hdt, ctw;
|
double stw, hdt, ctw;
|
||||||
double hdmVar = 3.0; // Magnetic declination, can be set from config if needed
|
double twd, tws, twa;
|
||||||
double twd, tws;
|
static const double DBL_MIN = std::numeric_limits<double>::lowest();
|
||||||
|
|
||||||
if (*hdtVal == __DBL_MIN__) {
|
if (*hdtVal != DBL_MIN) {
|
||||||
if (*hdmVal != __DBL_MIN__) {
|
hdt = *hdtVal; // Use HDT if available
|
||||||
hdt = *hdmVal + hdmVar; // Use corrected HDM if HDT is not available
|
} else {
|
||||||
|
if (*hdmVal != DBL_MIN && *varVal != DBL_MIN) {
|
||||||
|
hdt = *hdmVal + *varVal; // Use corrected HDM if HDT 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 {
|
} else {
|
||||||
return false; // Cannot calculate without valid HDT or HDM
|
return false; // Cannot calculate without valid HDT or HDM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctw = *hdtVal + ((*cogVal - *hdtVal) / 2); // Estimate CTW from COG
|
|
||||||
|
|
||||||
if ((*awaVal == __DBL_MIN__) || (*awsVal == __DBL_MIN__) || (*cogVal == __DBL_MIN__) || (*stwVal == __DBL_MIN__)) {
|
if (*cogVal != DBL_MIN) {
|
||||||
|
ctw = *cogVal; // Use COG as CTW if available
|
||||||
|
// ctw = *cogVal + ((*cogVal - hdt) / 2); // Estimate CTW from COG
|
||||||
|
} else {
|
||||||
|
ctw = hdt; // 2nd approximation for CTW;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*stwVal != DBL_MIN) {
|
||||||
|
stw = *stwVal; // Use STW if available
|
||||||
|
} else if (*sogVal != DBL_MIN) {
|
||||||
|
stw = *sogVal;
|
||||||
|
} else {
|
||||||
|
// If STW and SOG are not available, we cannot calculate true wind
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*awaVal == DBL_MIN) || (*awsVal == DBL_MIN) || (*cogVal == DBL_MIN) || (*stwVal == DBL_MIN)) {
|
||||||
// Cannot calculate true wind without valid AWA, AWS, COG, or STW
|
// Cannot calculate true wind without valid AWA, AWS, COG, or STW
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
calcTwdSA(awaVal, awsVal, cogVal, stwVal, hdtVal, &twd, &tws);
|
calcTwdSA(awaVal, awsVal, &ctw, stwVal, &hdt, &twd, &tws, &twa);
|
||||||
*twdVal = twd;
|
*twdVal = twd;
|
||||||
*twsVal = tws;
|
*twsVal = tws;
|
||||||
|
*twaVal = twa;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void HstryBuf::fillWndBufSimData(tBoatHstryData& hstryBufs)
|
||||||
// make function available in Python for testing
|
// Fill most part of TWD and TWS history buffer with simulated data
|
||||||
static PyObject* true_wind(PyObject* self, PyObject* args) {
|
{
|
||||||
double AWA,AWS,CTW,STW,HDT,TWS,TWD;
|
double value = 20.0;
|
||||||
if (!PyArg_ParseTuple(args, "ddddd", &AWA, &AWS, &CTW, &STW, &HDT)) {
|
int16_t value2 = 0;
|
||||||
return NULL;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
calc_true_wind(&AWA, &AWS, &CTW, &STW, &HDT, &TWD, &TWS);
|
|
||||||
|
|
||||||
PyObject* twd = PyFloat_FromDouble(TWD);
|
|
||||||
PyObject* tws = PyFloat_FromDouble(TWS);
|
|
||||||
PyObject* tw = PyTuple_Pack(2,twd,tws);
|
|
||||||
return tw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef methods[] = {
|
/* double genTwdSimDat()
|
||||||
{"true_wind", true_wind, METH_VARARGS, NULL},
|
{
|
||||||
{NULL, NULL, 0, NULL}
|
simTwd += random(-20, 20);
|
||||||
};
|
if (simTwd < 0.0)
|
||||||
|
simTwd += 360.0;
|
||||||
|
if (simTwd >= 360.0)
|
||||||
|
simTwd -= 360.0;
|
||||||
|
|
||||||
static struct PyModuleDef module = {
|
int16_t z = static_cast<int16_t>(DegToRad(simTwd) * 1000.0);
|
||||||
PyModuleDef_HEAD_INIT,
|
pageData.boatHstry.twdHstry->add(z); // Fill the buffer with some test data
|
||||||
"truewind", // Module name
|
|
||||||
NULL, // Optional docstring
|
|
||||||
-1,
|
|
||||||
methods
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMODINIT_FUNC PyInit_truewind(void) {
|
simTws += random(-200, 150) / 10.0; // TWS value in knots
|
||||||
return PyModule_Create(&module);
|
simTws = constrain(simTws, 0.0f, 50.0f); // Ensure TWS is between 0 and 50 knots
|
||||||
}*/
|
twsValue = simTws;
|
||||||
|
}*/
|
||||||
|
|
|
@ -1,48 +1,36 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
// #include <Python.h>
|
|
||||||
#include "GwApi.h"
|
#include "GwApi.h"
|
||||||
|
#include "OBPRingBuffer.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
// #define radians(a) (a*0.017453292519943295)
|
typedef struct {
|
||||||
// #define degrees(a) (a*57.29577951308232)
|
RingBuffer<int16_t>* twdHstry;
|
||||||
|
RingBuffer<int16_t>* twsHstry;
|
||||||
|
} 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 {
|
class WindUtils {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void to360(double* a);
|
static double to2PI(double a);
|
||||||
static void to180(double* a);
|
static double toPI(double a);
|
||||||
static void to2PI(double* a);
|
static double to360(double a);
|
||||||
static void toPI(double* a);
|
static double to180(double a);
|
||||||
static void toCart(const double* phi, const double* r, double* x, double* y);
|
static void toCart(const double* phi, const double* r, double* x, double* y);
|
||||||
static void toPol(const double* x, const double* y, double* phi, double* r);
|
static void toPol(const double* x, const double* y, double* phi, double* r);
|
||||||
static void addPolar(const double* phi1, const double* r1,
|
static void addPolar(const double* phi1, const double* r1,
|
||||||
const double* phi2, const double* r2,
|
const double* phi2, const double* r2,
|
||||||
double* phi, double* r);
|
double* phi, double* r);
|
||||||
static bool calcTrueWind(const double* awaVal, const double* awsVal,
|
|
||||||
const double* cogVal, const double* stwVal, const double* hdtVal,
|
|
||||||
const double* hdmVal, double* twdVal, double* twsVal);
|
|
||||||
static void calcTwdSA(const double* AWA, const double* AWS,
|
static void calcTwdSA(const double* AWA, const double* AWS,
|
||||||
const double* CTW, const double* STW, const double* HDT,
|
const double* CTW, const double* STW, const double* HDT,
|
||||||
double* TWD, double* TWS);
|
double* TWD, double* TWS, double* TWA);
|
||||||
};
|
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);
|
||||||
// make function available in Python for testing
|
};
|
||||||
static PyObject* true_wind(PyObject* self, PyObject* args);
|
|
||||||
static PyMethodDef methods[] = {
|
|
||||||
{"true_wind", true_wind, METH_VARARGS, NULL},
|
|
||||||
{NULL, NULL, 0, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct PyModuleDef module = {
|
|
||||||
PyModuleDef_HEAD_INIT,
|
|
||||||
"truewind", // Module name
|
|
||||||
NULL, // Optional docstring
|
|
||||||
-1,
|
|
||||||
methods
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMODINIT_FUNC PyInit_truewind(void) {
|
|
||||||
return PyModule_Create(&module);
|
|
||||||
} */
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
RingBuffer(size_t size);
|
RingBuffer(size_t size);
|
||||||
void setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue); // Set meta data for buffer
|
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
|
bool getMetaData(String& name, String& format, int& updateFrequency, T& minValue, T& maxValue); // Get meta data of buffer
|
||||||
|
String getName() const; // Get buffer name
|
||||||
void add(const T& value); // Add a new value to buffer
|
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 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
|
T getFirst() const; // Get the first (oldest) value in buffer
|
||||||
|
|
|
@ -57,6 +57,13 @@ bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequen
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get buffer name
|
||||||
|
template <typename T>
|
||||||
|
String RingBuffer<T>::getName() const
|
||||||
|
{
|
||||||
|
return dataName;
|
||||||
|
}
|
||||||
|
|
||||||
// Add a new value to buffer
|
// Add a new value to buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void RingBuffer<T>::add(const T& value)
|
void RingBuffer<T>::add(const T& value)
|
||||||
|
@ -129,9 +136,9 @@ T RingBuffer<T>::getMin() const
|
||||||
return MIN_VAL;
|
return MIN_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
T minVal = getFirst();
|
T minVal = MAX_VAL;
|
||||||
T value;
|
T value;
|
||||||
for (size_t i = 1; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
value = get(i);
|
value = get(i);
|
||||||
if (value < minVal && value != MIN_VAL) {
|
if (value < minVal && value != MIN_VAL) {
|
||||||
minVal = value;
|
minVal = value;
|
||||||
|
@ -150,7 +157,7 @@ T RingBuffer<T>::getMin(size_t amount) const
|
||||||
if (amount > count)
|
if (amount > count)
|
||||||
amount = count;
|
amount = count;
|
||||||
|
|
||||||
T minVal = getLast();
|
T minVal = MAX_VAL;
|
||||||
T value;
|
T value;
|
||||||
for (size_t i = 0; i < amount; i++) {
|
for (size_t i = 0; i < amount; i++) {
|
||||||
value = get(count - 1 - i);
|
value = get(count - 1 - i);
|
||||||
|
@ -169,9 +176,9 @@ T RingBuffer<T>::getMax() const
|
||||||
return MIN_VAL;
|
return MIN_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
T maxVal = getFirst();
|
T maxVal = MIN_VAL;
|
||||||
T value;
|
T value;
|
||||||
for (size_t i = 1; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
value = get(i);
|
value = get(i);
|
||||||
if (value > maxVal && value != MIN_VAL) {
|
if (value > maxVal && value != MIN_VAL) {
|
||||||
maxVal = value;
|
maxVal = value;
|
||||||
|
@ -190,7 +197,7 @@ T RingBuffer<T>::getMax(size_t amount) const
|
||||||
if (amount > count)
|
if (amount > count)
|
||||||
amount = count;
|
amount = count;
|
||||||
|
|
||||||
T maxVal = getLast();
|
T maxVal = MIN_VAL;
|
||||||
T value;
|
T value;
|
||||||
for (size_t i = 0; i < amount; i++) {
|
for (size_t i = 0; i < amount; i++) {
|
||||||
value = get(count - 1 - i);
|
value = get(count - 1 - i);
|
||||||
|
@ -328,7 +335,7 @@ bool RingBuffer<T>::isFull() const
|
||||||
return is_Full;
|
return is_Full;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get lowest possible value for buffer; used for initialized buffer data
|
// Get lowest possible value for buffer; used for non-set buffer data
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMinVal() const
|
T RingBuffer<T>::getMinVal() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,20 +4,17 @@
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "OBPRingBuffer.h"
|
#include "OBPRingBuffer.h"
|
||||||
#include "Pagedata.h"
|
#include "Pagedata.h"
|
||||||
#include <N2kMessages.h> // just for RadToDeg function
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
static const double radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees
|
static const double radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees
|
||||||
// #define radians(a) (a * 0.017453292519943295)
|
|
||||||
// #define degrees(a) (a * 57.29577951308232)
|
|
||||||
|
|
||||||
// Get maximum difference of last <amount> of TWD ringbuffer values to center chart
|
// 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 getRng(const RingBuffer<int16_t>& windDirHstry, int center, size_t amount)
|
||||||
{
|
{
|
||||||
int minVal = windDirHstry.getMinVal();
|
int minVal = windDirHstry.getMinVal();
|
||||||
size_t count = windDirHstry.getCurrentSize();
|
size_t count = windDirHstry.getCurrentSize();
|
||||||
// size_t capacity = windDirHstry.getCapacity();
|
// size_t capacity = windDirHstry.getCapacity();
|
||||||
// size_t last = windDirHstry.getLastIdx();
|
// size_t last = windDirHstry.getLastIdx();
|
||||||
|
|
||||||
if (windDirHstry.isEmpty() || amount <= 0) {
|
if (windDirHstry.isEmpty() || amount <= 0) {
|
||||||
return minVal;
|
return minVal;
|
||||||
|
@ -30,7 +27,7 @@ int getRng(const RingBuffer<int16_t>& windDirHstry, int center, size_t amount)
|
||||||
int maxRng = minVal;
|
int maxRng = minVal;
|
||||||
// Start from the newest value (last) and go backwards x times
|
// Start from the newest value (last) and go backwards x times
|
||||||
for (size_t i = 0; i < amount; i++) {
|
for (size_t i = 0; i < amount; i++) {
|
||||||
// value = windDirHstry.get(((last - i) % capacity + capacity) % capacity);
|
// value = windDirHstry.get(((last - i) % capacity + capacity) % capacity);
|
||||||
value = windDirHstry.get(count - 1 - i);
|
value = windDirHstry.get(count - 1 - i);
|
||||||
|
|
||||||
if (value == minVal) {
|
if (value == minVal) {
|
||||||
|
@ -49,43 +46,6 @@ int getRng(const RingBuffer<int16_t>& windDirHstry, int center, size_t amount)
|
||||||
return maxRng;
|
return maxRng;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fillSimData(PageData& pageData)
|
|
||||||
// Fill part of the TWD history buffer with simulated data
|
|
||||||
{
|
|
||||||
int value = 20;
|
|
||||||
int16_t value2 = 0;
|
|
||||||
for (int i = 0; i < 900; i++) {
|
|
||||||
value += random(-20, 20);
|
|
||||||
if (value < 0)
|
|
||||||
value += 360;
|
|
||||||
if (value >= 360)
|
|
||||||
value -= 360;
|
|
||||||
value2 = static_cast<int16_t>(DegToRad(value) * 1000.0);
|
|
||||||
pageData.boatHstry.twdHstry->add(value2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fillTstBuffer(PageData& pageData)
|
|
||||||
{
|
|
||||||
float value = 0;
|
|
||||||
int value2 = 0;
|
|
||||||
for (int i = 0; i < 60; i++) {
|
|
||||||
pageData.boatHstry.twdHstry->add(-10); // -> irregular data
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 20; i++) {
|
|
||||||
for (int j = 0; j < 20; j++) {
|
|
||||||
value += 10;
|
|
||||||
value2 = static_cast<int>(DegToRad(value) * 1000.0);
|
|
||||||
pageData.boatHstry.twdHstry->add(value2);
|
|
||||||
}
|
|
||||||
for (int j = 0; j < 20; j++) {
|
|
||||||
value -= 10;
|
|
||||||
value2 = static_cast<int>(DegToRad(value) * 1000.0);
|
|
||||||
pageData.boatHstry.twdHstry->add(value2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ****************************************************************
|
// ****************************************************************
|
||||||
class PageWindPlot : public Page {
|
class PageWindPlot : public Page {
|
||||||
|
|
||||||
|
@ -105,7 +65,7 @@ public:
|
||||||
virtual void setupKeys()
|
virtual void setupKeys()
|
||||||
{
|
{
|
||||||
Page::setupKeys();
|
Page::setupKeys();
|
||||||
commonData->keydata[0].label = "MODE";
|
// commonData->keydata[0].label = "MODE";
|
||||||
commonData->keydata[1].label = "INTV";
|
commonData->keydata[1].label = "INTV";
|
||||||
commonData->keydata[4].label = "TWS";
|
commonData->keydata[4].label = "TWS";
|
||||||
}
|
}
|
||||||
|
@ -113,7 +73,7 @@ public:
|
||||||
// Key functions
|
// Key functions
|
||||||
virtual int handleKey(int key)
|
virtual int handleKey(int key)
|
||||||
{
|
{
|
||||||
// Set chart mode TWD | TWS
|
// Set chart mode TWD | TWS -> to be implemented
|
||||||
if (key == 1) {
|
if (key == 1) {
|
||||||
if (chrtMode == 'D') {
|
if (chrtMode == 'D') {
|
||||||
chrtMode = 'S';
|
chrtMode = 'S';
|
||||||
|
@ -159,9 +119,10 @@ public:
|
||||||
GwLog* logger = commonData->logger;
|
GwLog* logger = commonData->logger;
|
||||||
|
|
||||||
float twsValue; // TWS value in chart area
|
float twsValue; // TWS value in chart area
|
||||||
String twdName, twdUnit; // TWD name and unit
|
static String twdName, twdUnit; // TWD name and unit
|
||||||
int updFreq; // Update frequency for TWD
|
static int updFreq; // Update frequency for TWD
|
||||||
int16_t twdLowest, twdHighest; // TWD range
|
static int16_t twdLowest, twdHighest; // TWD range
|
||||||
|
// static int16_t twdBufMinVal; // lowest possible twd buffer value; used for non-set data
|
||||||
|
|
||||||
static bool isInitialized = false; // Flag to indicate that page is initialized
|
static bool isInitialized = false; // Flag to indicate that page is initialized
|
||||||
static bool wndDataValid = false; // Flag to indicate if wind data is valid
|
static bool wndDataValid = false; // Flag to indicate if wind data is valid
|
||||||
|
@ -191,6 +152,7 @@ public:
|
||||||
static int chrtRng; // Range of wind values from mid wind value to min/max wind value in degrees
|
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
|
int diffRng; // Difference between mid and current wind value
|
||||||
static const int dfltRng = 40; // Default range for chart
|
static const int dfltRng = 40; // Default range for chart
|
||||||
|
int midWndDir; // New value for wndCenter after chart start / shift
|
||||||
static int simTwd; // Simulation value for TWD
|
static int simTwd; // Simulation value for TWD
|
||||||
static float simTws; // Simulation value for TWS
|
static float simTws; // Simulation value for TWS
|
||||||
|
|
||||||
|
@ -201,7 +163,7 @@ public:
|
||||||
static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line
|
static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line
|
||||||
|
|
||||||
LOG_DEBUG(GwLog::LOG, "Display page WindPlot");
|
LOG_DEBUG(GwLog::LOG, "Display page WindPlot");
|
||||||
unsigned long start = millis();
|
unsigned long WndPlotStart = millis();
|
||||||
|
|
||||||
// Get config data
|
// Get config data
|
||||||
simulation = config->getBool(config->useSimuData);
|
simulation = config->getBool(config->useSimuData);
|
||||||
|
@ -210,11 +172,6 @@ public:
|
||||||
String backlightMode = config->getString(config->backlight);
|
String backlightMode = config->getString(config->backlight);
|
||||||
|
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
|
|
||||||
if (simulation) {
|
|
||||||
fillSimData(pageData); // Fill the buffer with some test data
|
|
||||||
}
|
|
||||||
|
|
||||||
width = getdisplay().width();
|
width = getdisplay().width();
|
||||||
height = getdisplay().height();
|
height = getdisplay().height();
|
||||||
xCenter = width / 2;
|
xCenter = width / 2;
|
||||||
|
@ -230,8 +187,33 @@ public:
|
||||||
lastAddedIdx = pageData.boatHstry.twdHstry->getLastIdx();
|
lastAddedIdx = pageData.boatHstry.twdHstry->getLastIdx();
|
||||||
pageData.boatHstry.twdHstry->getMetaData(twdName, twdUnit, updFreq, twdLowest, twdHighest);
|
pageData.boatHstry.twdHstry->getMetaData(twdName, twdUnit, updFreq, twdLowest, twdHighest);
|
||||||
wndCenter = INT_MIN;
|
wndCenter = INT_MIN;
|
||||||
|
midWndDir = 0;
|
||||||
|
diffRng = dfltRng;
|
||||||
|
chrtRng = dfltRng;
|
||||||
|
|
||||||
isInitialized = true; // Set flag to indicate that page is now initialized
|
isInitialized = true; // Set flag to indicate that page is now initialized
|
||||||
LOG_DEBUG(GwLog::ERROR, "PageWindPlot Start1: lastAddedIdx: %d, simTwd: %.1f, isInitialized: %d, SimData: %d", lastAddedIdx, simTwd / 1000 + radToDeg, isInitialized, simulation);
|
}
|
||||||
|
|
||||||
|
const int numBoatData = 2;
|
||||||
|
GwApi::BoatValue* bvalue;
|
||||||
|
String DataName[numBoatData];
|
||||||
|
double DataValue[numBoatData];
|
||||||
|
bool DataValid[numBoatData];
|
||||||
|
String DataText[numBoatData];
|
||||||
|
String DataUnit[numBoatData];
|
||||||
|
String DataFormat[numBoatData];
|
||||||
|
|
||||||
|
// read boat data values; TWD only for validation test, TWS for display of current value
|
||||||
|
for (int i = 0; i < numBoatData; i++) {
|
||||||
|
bvalue = pageData.values[i];
|
||||||
|
DataName[i] = xdrDelete(bvalue->getName());
|
||||||
|
DataName[i] = DataName[i].substring(0, 6); // String length limit for value name
|
||||||
|
calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated
|
||||||
|
DataValue[i] = bvalue->value; // Value as double in SI unit
|
||||||
|
DataValid[i] = bvalue->valid;
|
||||||
|
DataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||||
|
DataUnit[i] = formatValue(bvalue, *commonData).unit;
|
||||||
|
DataFormat[i] = bvalue->getFormat(); // Unit of value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optical warning by limit violation (unused)
|
// Optical warning by limit violation (unused)
|
||||||
|
@ -240,30 +222,11 @@ public:
|
||||||
setFlashLED(false);
|
setFlashLED(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simulation) {
|
|
||||||
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);
|
|
||||||
LOG_DEBUG(GwLog::ERROR, "PageWindPlot Simulation: getLast TWD: %.0f, lastIdx: %d", pageData.boatHstry.twdHstry->getLast() / 1000.0 * RAD_TO_DEG, pageData.boatHstry.twdHstry->getLastIdx());
|
|
||||||
pageData.boatHstry.twdHstry->add(z); // Fill the buffer with some test data
|
|
||||||
LOG_DEBUG(GwLog::ERROR, "PageWindPlot Simulation: getAdded TWD: %.0f, lastIdx: %d", pageData.boatHstry.twdHstry->getLast() / 1000.0 * RAD_TO_DEG, pageData.boatHstry.twdHstry->getLastIdx());
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
twsValue = pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384; // TWS value in knots
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identify buffer size and buffer start position for chart
|
// Identify buffer size and buffer start position for chart
|
||||||
count = pageData.boatHstry.twdHstry->getCurrentSize();
|
count = pageData.boatHstry.twdHstry->getCurrentSize();
|
||||||
currIdx = pageData.boatHstry.twdHstry->getLastIdx();
|
currIdx = pageData.boatHstry.twdHstry->getLastIdx();
|
||||||
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
|
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
|
||||||
if (dataIntv != oldDataIntv) {
|
if (dataIntv != oldDataIntv || count == 1) {
|
||||||
// new data interval selected by user
|
// new data interval selected by user
|
||||||
intvBufSize = cHeight * dataIntv;
|
intvBufSize = cHeight * dataIntv;
|
||||||
numWndVals = min(count, (cHeight - 60) * dataIntv);
|
numWndVals = min(count, (cHeight - 60) * dataIntv);
|
||||||
|
@ -277,16 +240,21 @@ public:
|
||||||
bufStart = max(0, bufStart - numAddedBufVals);
|
bufStart = max(0, bufStart - numAddedBufVals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_DEBUG(GwLog::ERROR, "PageWindPlot Dataset: TWD: %.0f, TWS: %.1f, DBT: %.1f, count: %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d",
|
LOG_DEBUG(GwLog::ERROR, "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",
|
||||||
pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384, pageData.boatHstry.dbtHstry->getLast() / 10.0,
|
count, pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, pageData.boatHstry.twsHstry->getLast() / 10.0 * 1.94384, DataValid[0],
|
||||||
count, intvBufSize, numWndVals, bufStart, numAddedBufVals, pageData.boatHstry.twdHstry->getLastIdx());
|
intvBufSize, numWndVals, bufStart, numAddedBufVals, pageData.boatHstry.twdHstry->getLastIdx(), oldDataIntv, dataIntv);
|
||||||
|
|
||||||
// initialize chart range values
|
// Set wndCenter from 1st real buffer value
|
||||||
if (wndCenter == INT_MIN) {
|
if (wndCenter == INT_MIN || (wndCenter == 0 && count == 1)) {
|
||||||
wndCenter = max(0, int(pageData.boatHstry.twdHstry->get(numWndVals - intvBufSize) / 1000.0 * radToDeg)); // get 1st value of current data interval
|
midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals);
|
||||||
wndCenter = (int((wndCenter + (wndCenter >= 0 ? 5 : -5)) / 10) * 10) % 360; // Set new center value; round to nearest 10 degree value; 360° -> 0°
|
if (midWndDir != INT16_MIN) {
|
||||||
diffRng = dfltRng;
|
midWndDir = midWndDir / 1000.0 * radToDeg;
|
||||||
chrtRng = dfltRng;
|
wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value
|
||||||
|
} else {
|
||||||
|
wndCenter = 0;
|
||||||
|
}
|
||||||
|
LOG_DEBUG(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);
|
||||||
} else {
|
} else {
|
||||||
// check and adjust range between left, center, and right chart limit
|
// check and adjust range between left, center, and right chart limit
|
||||||
diffRng = getRng(*pageData.boatHstry.twdHstry, wndCenter, numWndVals);
|
diffRng = getRng(*pageData.boatHstry.twdHstry, wndCenter, numWndVals);
|
||||||
|
@ -304,8 +272,6 @@ public:
|
||||||
wndRight = (chrtRng < 180 ? wndCenter + chrtRng : wndCenter + chrtRng - 1);
|
wndRight = (chrtRng < 180 ? wndCenter + chrtRng : wndCenter + chrtRng - 1);
|
||||||
if (wndRight >= 360)
|
if (wndRight >= 360)
|
||||||
wndRight -= 360;
|
wndRight -= 360;
|
||||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FirstVal: %f, LastVal: %d, count: %d, diffRng: %d, chartRng: %d, Center: %d, scale: %f", pageData.boatHstry.twdHstry->getFirst() / 1000.0 * radToDeg,
|
|
||||||
pageData.boatHstry.twdHstry->getLast() / 1000.0 * radToDeg, count, diffRng, chrtRng, wndCenter, chrtScl);
|
|
||||||
|
|
||||||
// Draw page
|
// Draw page
|
||||||
//***********************************************************************
|
//***********************************************************************
|
||||||
|
@ -322,11 +288,9 @@ public:
|
||||||
char sWndLbl[4]; // char buffer for Wind angle label
|
char sWndLbl[4]; // char buffer for Wind angle label
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||||
getdisplay().setCursor(xCenter - 88, yOffset - 3);
|
getdisplay().setCursor(xCenter - 88, yOffset - 3);
|
||||||
getdisplay().print("TWD"); // Wind name
|
getdisplay().print("TWD"); // Wind data name
|
||||||
// getdisplay().setCursor(xCenter - 20, yOffset - 3);
|
|
||||||
snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter);
|
snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter);
|
||||||
drawTextCenter(xCenter, yOffset - 11, sWndLbl);
|
drawTextCenter(xCenter, yOffset - 11, sWndLbl);
|
||||||
// getdisplay().print(sWndLbl); // Wind center value
|
|
||||||
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
|
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
|
||||||
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
|
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
|
||||||
getdisplay().setCursor(1, yOffset - 3);
|
getdisplay().setCursor(1, yOffset - 3);
|
||||||
|
@ -343,7 +307,19 @@ public:
|
||||||
if (pageData.boatHstry.twdHstry->getMax() == pageData.boatHstry.twdHstry->getMinVal()) {
|
if (pageData.boatHstry.twdHstry->getMax() == pageData.boatHstry.twdHstry->getMinVal()) {
|
||||||
// only <INT16_MIN> values in buffer -> no valid wind data available
|
// only <INT16_MIN> values in buffer -> no valid wind data available
|
||||||
wndDataValid = false;
|
wndDataValid = false;
|
||||||
|
} else if (!DataValid[0]) {
|
||||||
|
// currently no valid TWD data available
|
||||||
|
numNoData++;
|
||||||
|
wndDataValid = true;
|
||||||
|
if (numNoData > 3) {
|
||||||
|
// If more than 4 invalid values in a row, send message
|
||||||
|
wndDataValid = false;
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||||
|
getdisplay().fillRect(xCenter - 66, height / 2 - 20, 146, 24, commonData->bgcolor); // Clear area for TWS value
|
||||||
|
drawTextCenter(xCenter, height / 2 - 10, "No sensor data");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
numNoData = 0; // reset data error counter
|
||||||
wndDataValid = true; // At least some wind data available
|
wndDataValid = true; // At least some wind data available
|
||||||
}
|
}
|
||||||
// Draw wind values in chart
|
// Draw wind values in chart
|
||||||
|
@ -361,17 +337,17 @@ public:
|
||||||
}
|
}
|
||||||
if (numNoData > 4) {
|
if (numNoData > 4) {
|
||||||
// If more than 4 invalid values in a row, send message
|
// If more than 4 invalid values in a row, send message
|
||||||
getdisplay().setFont(&Ubuntu_Bold10pt7b);
|
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||||
getdisplay().fillRect(xCenter - 66, height / 2 - 20, 146, 24, commonData->bgcolor); // Clear area for TWS value
|
getdisplay().fillRect(xCenter - 66, height / 2 - 20, 146, 24, commonData->bgcolor); // Clear area for TWS value
|
||||||
drawTextCenter(xCenter, height / 2 - 10, "No sensor data");
|
drawTextCenter(xCenter, height / 2 - 10, "No sensor data");
|
||||||
} */
|
} */
|
||||||
} else {
|
} else {
|
||||||
chrtVal = (chrtVal / 1000.0 * radToDeg) + 0.5; // Convert to degrees and round
|
chrtVal = static_cast<int>((chrtVal / 1000.0 * radToDeg) + 0.5); // Convert to degrees and round
|
||||||
x = ((chrtVal - wndLeft + 360) % 360) * chrtScl;
|
x = ((chrtVal - wndLeft + 360) % 360) * chrtScl;
|
||||||
y = yOffset + cHeight - i; // Position in chart area
|
y = yOffset + cHeight - i; // Position in chart area
|
||||||
|
|
||||||
if (i >= (numWndVals / dataIntv) - 10)
|
if (i >= (numWndVals / dataIntv) - 10)
|
||||||
LOG_DEBUG(GwLog::ERROR, "PageWindPlot Chart: i: %d, chrtVal: %d, bufStart: %d count: %d, linesToShow: %d", i, chrtVal, bufStart, count, (numWndVals / dataIntv));
|
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %d, bufStart: %d, count: %d, linesToShow: %d", i, chrtVal, bufStart, count, (numWndVals / dataIntv));
|
||||||
|
|
||||||
if ((i == 0) || (chrtPrevVal == INT16_MIN)) {
|
if ((i == 0) || (chrtPrevVal == INT16_MIN)) {
|
||||||
// just a dot for 1st chart point or after some invalid values
|
// just a dot for 1st chart point or after some invalid values
|
||||||
|
@ -404,15 +380,15 @@ public:
|
||||||
|
|
||||||
int minWndDir = pageData.boatHstry.twdHstry->getMin(numWndVals) / 1000.0 * radToDeg;
|
int minWndDir = pageData.boatHstry.twdHstry->getMin(numWndVals) / 1000.0 * radToDeg;
|
||||||
int maxWndDir = pageData.boatHstry.twdHstry->getMax(numWndVals) / 1000.0 * radToDeg;
|
int maxWndDir = pageData.boatHstry.twdHstry->getMax(numWndVals) / 1000.0 * radToDeg;
|
||||||
LOG_DEBUG(GwLog::ERROR, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter);
|
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, maxWndDir, wndCenter);
|
||||||
if ((minWndDir > wndCenter) || (maxWndDir < wndCenter)) {
|
if ((minWndDir + 540 >= wndCenter + 540) || (maxWndDir + 540 <= wndCenter + 540)) {
|
||||||
// Check if all wind value are left or right of center value -> optimize chart range
|
// Check if all wind value are left or right of center value -> optimize chart range
|
||||||
int midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals) / 1000.0 * radToDeg;
|
midWndDir = pageData.boatHstry.twdHstry->getMid(numWndVals) / 1000.0 * radToDeg;
|
||||||
if (midWndDir != INT16_MIN) {
|
if (midWndDir != INT16_MIN) {
|
||||||
wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value
|
wndCenter = int((midWndDir + (midWndDir >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_DEBUG(GwLog::ERROR, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter);
|
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,6 +409,8 @@ public:
|
||||||
int xPosTws;
|
int xPosTws;
|
||||||
static const int yPosTws = yOffset + 40;
|
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 - 138;
|
||||||
currentZone = (y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146) ? 1 : 0; // Define current zone for TWS value
|
currentZone = (y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146) ? 1 : 0; // Define current zone for TWS value
|
||||||
if (currentZone != lastZone) {
|
if (currentZone != lastZone) {
|
||||||
|
@ -447,21 +425,24 @@ public:
|
||||||
getdisplay().fillRect(xPosTws - 4, yPosTws - 38, 142, 44, commonData->bgcolor); // Clear area for TWS value
|
getdisplay().fillRect(xPosTws - 4, yPosTws - 38, 142, 44, commonData->bgcolor); // Clear area for TWS value
|
||||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||||
getdisplay().setCursor(xPosTws, yPosTws);
|
getdisplay().setCursor(xPosTws, yPosTws);
|
||||||
if (twsValue < 0 || twsValue >= 100) {
|
if (!DataValid[1]) {
|
||||||
getdisplay().print("--.-");
|
getdisplay().print("--.-");
|
||||||
} else {
|
} else {
|
||||||
if (twsValue < 10.0) {
|
if (DataValue[1] < 9.95) {
|
||||||
getdisplay().printf("!%3.1f", twsValue); // Value
|
getdisplay().printf("!%3.1f", DataValue[1] + 0.05); // Value, round to 1 decimal
|
||||||
} else {
|
} else {
|
||||||
getdisplay().printf("%4.1f", twsValue); // Value}
|
getdisplay().printf("%4.1f", DataValue[1] + 0.05); // Value, round to 1 decimal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||||
getdisplay().setCursor(xPosTws + 82, yPosTws - 14);
|
getdisplay().setCursor(xPosTws + 82, yPosTws - 14);
|
||||||
getdisplay().print("TWS"); // Name
|
// getdisplay().print("TWS"); // Name
|
||||||
|
getdisplay().print(DataName[1]); // Name
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
getdisplay().setCursor(xPosTws + 78, yPosTws + 1);
|
// getdisplay().setCursor(xPosTws + 78, yPosTws + 1);
|
||||||
getdisplay().printf(" kn"); // Unit
|
getdisplay().setCursor(xPosTws + 82, yPosTws + 1);
|
||||||
|
// getdisplay().printf(" kn"); // Unit
|
||||||
|
getdisplay().print(DataUnit[1]); // Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
// chart Y axis labels; print at last to overwrite potential chart lines in label area
|
// chart Y axis labels; print at last to overwrite potential chart lines in label area
|
||||||
|
@ -471,7 +452,7 @@ public:
|
||||||
for (int i = 1; i <= 3; i++) {
|
for (int i = 1; i <= 3; i++) {
|
||||||
yPos = yOffset + (i * 60);
|
yPos = yOffset + (i * 60);
|
||||||
getdisplay().fillRect(0, yPos, width, 1, commonData->fgcolor);
|
getdisplay().fillRect(0, yPos, width, 1, commonData->fgcolor);
|
||||||
getdisplay().fillRect(0, yPos - 8, 26, 16, commonData->bgcolor); // Clear small area to remove potential chart lines
|
getdisplay().fillRect(0, yPos - 8, 24, 16, commonData->bgcolor); // Clear small area to remove potential chart lines
|
||||||
getdisplay().setCursor(1, yPos + 4);
|
getdisplay().setCursor(1, yPos + 4);
|
||||||
if (count >= intvBufSize) {
|
if (count >= intvBufSize) {
|
||||||
// Calculate minute value for label
|
// Calculate minute value for label
|
||||||
|
@ -483,8 +464,8 @@ public:
|
||||||
getdisplay().printf("%3d", chrtLbl); // Wind value label
|
getdisplay().printf("%3d", chrtLbl); // Wind value label
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long finish = millis() - start;
|
unsigned long finish = millis() - WndPlotStart;
|
||||||
// LOG_DEBUG(GwLog::ERROR, "PageWindPlot Time: %lu", finish);
|
LOG_DEBUG(GwLog::ERROR, "PageWindPlot Time: %lu", finish);
|
||||||
// Update display
|
// Update display
|
||||||
getdisplay().nextPage(); // Partial update (fast)
|
getdisplay().nextPage(); // Partial update (fast)
|
||||||
};
|
};
|
||||||
|
@ -505,9 +486,9 @@ PageDescription registerPageWindPlot(
|
||||||
"WindPlot", // Page name
|
"WindPlot", // Page name
|
||||||
createPage, // Action
|
createPage, // Action
|
||||||
0, // Number of bus values depends on selection in Web configuration
|
0, // Number of bus values depends on selection in Web configuration
|
||||||
// { "TWD", "TWA", "TWS", "HDM", "AWA", "AWS", "STW", "COG", "SOG" }, // Bus values we need in the page
|
{ "TWD", "TWS" }, // Bus values we need in the page
|
||||||
{ }, // Bus values we need in the page
|
// {}, // Bus values we need in the page
|
||||||
true // Show display header on/off
|
true // Show display header on/off
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -5,15 +5,10 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "LedSpiTask.h"
|
#include "LedSpiTask.h"
|
||||||
#include "OBPRingBuffer.h"
|
#include "OBPRingBuffer.h"
|
||||||
|
#include "OBPDataOperations.h"
|
||||||
|
|
||||||
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
|
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
|
||||||
|
|
||||||
typedef struct{
|
|
||||||
RingBuffer<int16_t>* twdHstry;
|
|
||||||
RingBuffer<int16_t>* twsHstry;
|
|
||||||
RingBuffer<int16_t>* dbtHstry;
|
|
||||||
} tBoatHstryData;
|
|
||||||
|
|
||||||
typedef std::vector<GwApi::BoatValue *> ValueList;
|
typedef std::vector<GwApi::BoatValue *> ValueList;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
|
|
|
@ -219,6 +219,17 @@
|
||||||
"obp60":"true"
|
"obp60":"true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "calcTrueWnds",
|
||||||
|
"label": "Calculate True Wind",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "false",
|
||||||
|
"description": "If not available, calculate true wind data from appearant wind and other boat data",
|
||||||
|
"category": "OBP60 Settings",
|
||||||
|
"capabilities": {
|
||||||
|
"obp60": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "lengthFormat",
|
"name": "lengthFormat",
|
||||||
"label": "Length Format",
|
"label": "Length Format",
|
||||||
|
|
|
@ -219,6 +219,17 @@
|
||||||
"obp40": "true"
|
"obp40": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "calcTrueWnds",
|
||||||
|
"label": "Calculate True Wind",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "false",
|
||||||
|
"description": "If not available, calculate true wind data from appearant wind and other boat data",
|
||||||
|
"category": "OBP40 Settings",
|
||||||
|
"capabilities": {
|
||||||
|
"obp40": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "lengthFormat",
|
"name": "lengthFormat",
|
||||||
"label": "Length Format",
|
"label": "Length Format",
|
||||||
|
|
|
@ -376,6 +376,112 @@ void underVoltageDetection(GwApi *api, CommonData &common){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//bool addTrueWind(GwApi* api, BoatValueList* boatValues, double *twd, double *tws, double *twa) {
|
||||||
|
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;
|
||||||
|
bool isCalculated = false;
|
||||||
|
const double DBL_MIN = std::numeric_limits<double>::lowest();
|
||||||
|
|
||||||
|
GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate("TWD");
|
||||||
|
GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate("TWS");
|
||||||
|
GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA");
|
||||||
|
GwApi::BoatValue *awaBVal = boatValues->findValueOrCreate("AWA");
|
||||||
|
GwApi::BoatValue *awsBVal = boatValues->findValueOrCreate("AWS");
|
||||||
|
GwApi::BoatValue *cogBVal = boatValues->findValueOrCreate("COG");
|
||||||
|
GwApi::BoatValue *stwBVal = boatValues->findValueOrCreate("STW");
|
||||||
|
GwApi::BoatValue *sogBVal = boatValues->findValueOrCreate("SOG");
|
||||||
|
GwApi::BoatValue *hdtBVal = boatValues->findValueOrCreate("HDT");
|
||||||
|
GwApi::BoatValue *hdmBVal = boatValues->findValueOrCreate("HDM");
|
||||||
|
GwApi::BoatValue *varBVal = boatValues->findValueOrCreate("VAR");
|
||||||
|
awaVal = awaBVal->valid ? awaBVal->value : DBL_MIN;
|
||||||
|
awsVal = awsBVal->valid ? awsBVal->value : DBL_MIN;
|
||||||
|
cogVal = cogBVal->valid ? cogBVal->value : DBL_MIN;
|
||||||
|
stwVal = stwBVal->valid ? stwBVal->value : DBL_MIN;
|
||||||
|
sogVal = sogBVal->valid ? sogBVal->value : DBL_MIN;
|
||||||
|
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::ERROR,"obp60task addTrueWind: AWA: %.1f, AWS: %.1f, COG: %.1f, STW: %.1f, 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, 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, &twdBVal->value, &twsBVal->value, &twaBVal->value);
|
||||||
|
twdBVal->valid = isCalculated;
|
||||||
|
twsBVal->valid = isCalculated;
|
||||||
|
twaBVal->valid = isCalculated;
|
||||||
|
|
||||||
|
api->getLogger()->logDebug(GwLog::ERROR,"obp60task calcTrueWind: TWD_Valid? %d, TWD=%.1f, TWS=%.1f, TWA=%.1f, isCalculated? %d", twdBVal->valid, twdBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852,
|
||||||
|
twaBVal->value * RAD_TO_DEG, isCalculated);
|
||||||
|
|
||||||
|
return isCalculated;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
// Initialize history buffers with meta data
|
||||||
|
hstryBufList.twdHstry->setMetaData("TWD", "formatCourse", hstryUpdFreq, hstryMinVal, twdHstryMax);
|
||||||
|
hstryBufList.twsHstry->setMetaData("TWS", "formatKnots", hstryUpdFreq, hstryMinVal, twsHstryMax);
|
||||||
|
|
||||||
|
GwApi::BoatValue *twdBVal = boatValues->findValueOrCreate(hstryBufList.twdHstry->getName());
|
||||||
|
GwApi::BoatValue *twsBVal = boatValues->findValueOrCreate(hstryBufList.twsHstry->getName());
|
||||||
|
GwApi::BoatValue *twaBVal = boatValues->findValueOrCreate("TWA");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleHstryBuf(GwApi* api, BoatValueList* boatValues, tBoatHstryData hstryBufList) {
|
||||||
|
// Handle history buffers for TWD, TWS
|
||||||
|
|
||||||
|
GwLog *logger = api->getLogger();
|
||||||
|
|
||||||
|
int16_t twdHstryMin = hstryBufList.twdHstry->getMinVal();
|
||||||
|
int16_t twdHstryMax = hstryBufList.twdHstry->getMaxVal();
|
||||||
|
int16_t twsHstryMin = hstryBufList.twsHstry->getMinVal();
|
||||||
|
int16_t twsHstryMax = hstryBufList.twsHstry->getMaxVal();
|
||||||
|
int16_t twdBuf, twsBuf;
|
||||||
|
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");
|
||||||
|
|
||||||
|
api->getLogger()->logDebug(GwLog::ERROR,"obp60task handleHstryBuf: twdBVal: %f, twsBVal: %f, twaBVal: %f, TWD_isValid? %d", twdBVal->value * RAD_TO_DEG,
|
||||||
|
twsBVal->value * 3.6 / 1.852, twaBVal->value * RAD_TO_DEG, twdBVal->valid);
|
||||||
|
calBVal = new GwApi::BoatValue("TWD"); // temporary solution for calibration of history buffer values
|
||||||
|
calBVal->setFormat(twdBVal->getFormat());
|
||||||
|
if (twdBVal->valid) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete calBVal;
|
||||||
|
calBVal = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// OBP60 Task
|
// OBP60 Task
|
||||||
//####################################################################################
|
//####################################################################################
|
||||||
void OBP60Task(GwApi *api){
|
void OBP60Task(GwApi *api){
|
||||||
|
@ -392,11 +498,6 @@ void OBP60Task(GwApi *api){
|
||||||
commonData.logger=logger;
|
commonData.logger=logger;
|
||||||
commonData.config=config;
|
commonData.config=config;
|
||||||
|
|
||||||
// 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)
|
|
||||||
RingBuffer<int16_t> dbtHstry(960); // Circular buffer to store water depth values (DBT)
|
|
||||||
|
|
||||||
#ifdef HARDWARE_V21
|
#ifdef HARDWARE_V21
|
||||||
// Keyboard coordinates for page footer
|
// Keyboard coordinates for page footer
|
||||||
initKeys(commonData);
|
initKeys(commonData);
|
||||||
|
@ -494,6 +595,11 @@ void OBP60Task(GwApi *api){
|
||||||
//commonData.distanceformat=config->getString(xxx);
|
//commonData.distanceformat=config->getString(xxx);
|
||||||
//add all necessary data to common data
|
//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};
|
||||||
|
|
||||||
//fill the page data from config
|
//fill the page data from config
|
||||||
numPages=config->getInt(config->visiblePages,1);
|
numPages=config->getInt(config->visiblePages,1);
|
||||||
if (numPages < 1) numPages=1;
|
if (numPages < 1) numPages=1;
|
||||||
|
@ -532,8 +638,10 @@ void OBP60Task(GwApi *api){
|
||||||
LOG_DEBUG(GwLog::DEBUG,"added fixed value %s to page %d",value->getName().c_str(),i);
|
LOG_DEBUG(GwLog::DEBUG,"added fixed value %s to page %d",value->getName().c_str(),i);
|
||||||
pages[i].parameters.values.push_back(value);
|
pages[i].parameters.values.push_back(value);
|
||||||
}
|
}
|
||||||
// Add boat history data to page parameters
|
if (pages[i].description->pageName == "WindPlot") {
|
||||||
pages[i].parameters.boatHstry = {&twdHstry, &twsHstry, &dbtHstry};
|
// Add boat history data to page parameters
|
||||||
|
pages[i].parameters.boatHstry = hstryBufList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// add out of band system page (always available)
|
// add out of band system page (always available)
|
||||||
Page *syspage = allPages.pages[0]->creator(commonData);
|
Page *syspage = allPages.pages[0]->creator(commonData);
|
||||||
|
@ -541,32 +649,12 @@ void OBP60Task(GwApi *api){
|
||||||
// Read all calibration data settings from config
|
// Read all calibration data settings from config
|
||||||
calibrationData.readConfig(config, logger);
|
calibrationData.readConfig(config, logger);
|
||||||
|
|
||||||
// List of boat values for history storage
|
// Check user setting for true wind calculation
|
||||||
GwApi::BoatValue *twdBVal=new GwApi::BoatValue(GwBoatData::_TWD);
|
bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false);
|
||||||
GwApi::BoatValue *twsBVal=new GwApi::BoatValue(GwBoatData::_TWS);
|
// bool simulation = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
||||||
GwApi::BoatValue *dbtBVal=new GwApi::BoatValue(GwBoatData::_DBT);
|
|
||||||
GwApi::BoatValue *hstryValList[]={twdBVal, twsBVal, dbtBVal};
|
|
||||||
api->getBoatDataValues(3, hstryValList);
|
|
||||||
// Boat data history buffer initialization
|
|
||||||
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 dbtHstryMax = 3276; // Max value for depth in m (=327), shifted by 10 for 1 decimal
|
|
||||||
// Initialize history buffers with meta data
|
|
||||||
twdHstry.setMetaData(twdBVal->getName(), twdBVal->getFormat(), hstryUpdFreq, hstryMinVal, twdHstryMax);
|
|
||||||
twsHstry.setMetaData(twsBVal->getName(), twsBVal->getFormat(), hstryUpdFreq, hstryMinVal, twsHstryMax);
|
|
||||||
dbtHstry.setMetaData(dbtBVal->getName(), dbtBVal->getFormat(), hstryUpdFreq, hstryMinVal, dbtHstryMax);
|
|
||||||
bool simulation = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
|
||||||
|
|
||||||
// List of boat values for true winds calculation
|
// Initialize history buffer for certain boat data
|
||||||
GwApi::BoatValue *awaBVal=new GwApi::BoatValue(GwBoatData::_AWA);
|
initHstryBuf(api, &boatValues, hstryBufList);
|
||||||
GwApi::BoatValue *awsBVal=new GwApi::BoatValue(GwBoatData::_AWS);
|
|
||||||
GwApi::BoatValue *cogBVal=new GwApi::BoatValue(GwBoatData::_COG);
|
|
||||||
GwApi::BoatValue *stwBVal=new GwApi::BoatValue(GwBoatData::_STW);
|
|
||||||
GwApi::BoatValue *hdtBVal=new GwApi::BoatValue(GwBoatData::_HDT);
|
|
||||||
GwApi::BoatValue *hdmBVal=new GwApi::BoatValue(GwBoatData::_HDM);
|
|
||||||
GwApi::BoatValue *WndCalcValList[]={awaBVal, awsBVal, cogBVal, stwBVal, hdtBVal, hdmBVal};
|
|
||||||
|
|
||||||
// Display screenshot handler for HTTP request
|
// Display screenshot handler for HTTP request
|
||||||
// http://192.168.15.1/api/user/OBP60Task/screenshot
|
// http://192.168.15.1/api/user/OBP60Task/screenshot
|
||||||
|
@ -623,18 +711,6 @@ void OBP60Task(GwApi *api){
|
||||||
GwApi::BoatValue *lon = boatValues.findValueOrCreate("LON"); // Load GpsLongitude
|
GwApi::BoatValue *lon = boatValues.findValueOrCreate("LON"); // Load GpsLongitude
|
||||||
GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP
|
GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP
|
||||||
|
|
||||||
/* // Boat values for wind conversion for main loop; will be calculated in case values are not available by sensors
|
|
||||||
GwApi::BoatValue *twd = boatValues.findValueOrCreate("TWD"); // True Wind Direction
|
|
||||||
GwApi::BoatValue *tws = boatValues.findValueOrCreate("TWS"); // True Wind Speed
|
|
||||||
GwApi::BoatValue *twa = boatValues.findValueOrCreate("TWA"); // True Wind Angle
|
|
||||||
GwApi::BoatValue *awaBVal = boatValues.findValueOrCreate("AWA"); // Apparent Wind Angle
|
|
||||||
GwApi::BoatValue *awsBVal = boatValues.findValueOrCreate("AWS"); // Apparent Wind Speed
|
|
||||||
GwApi::BoatValue *cogBVal = boatValues.findValueOrCreate("COG"); // Course Over Ground
|
|
||||||
GwApi::BoatValue *stwBVal = boatValues.findValueOrCreate("STW"); // Speed Through Water
|
|
||||||
GwApi::BoatValue *hdtBVal = boatValues.findValueOrCreate("HDT"); // Heading True
|
|
||||||
GwApi::BoatValue *ctwBVal = boatValues.findValueOrCreate("CTW"); // Course Through Water
|
|
||||||
GwApi::BoatValue *hdmBVal = boatValues.findValueOrCreate("HDM"); // Heading Magnetic
|
|
||||||
*/
|
|
||||||
LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop");
|
LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop");
|
||||||
|
|
||||||
commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime
|
commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime
|
||||||
|
@ -648,7 +724,6 @@ void OBP60Task(GwApi *api){
|
||||||
long starttime3 = millis(); // Display update all 1s
|
long starttime3 = millis(); // Display update all 1s
|
||||||
long starttime4 = millis(); // Delayed display update after 4s when select a new page
|
long starttime4 = millis(); // Delayed display update after 4s when select a new page
|
||||||
long starttime5 = millis(); // Calculate sunrise and sunset all 1s
|
long starttime5 = millis(); // Calculate sunrise and sunset all 1s
|
||||||
unsigned long starttime10 = millis(); // Get history TWD, TWS, DBT data and calculate true winds each 1s
|
|
||||||
|
|
||||||
pages[pageNumber].page->setupKeys(); // Initialize keys for first page
|
pages[pageNumber].page->setupKeys(); // Initialize keys for first page
|
||||||
|
|
||||||
|
@ -836,62 +911,8 @@ void OBP60Task(GwApi *api){
|
||||||
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
||||||
getdisplay().nextPage(); // Full update
|
getdisplay().nextPage(); // Full update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read TWD, TWS, DBT data from boatData each 1000ms for history and windplot display
|
|
||||||
if((millis() > starttime10 + 1000) && !simulation) {
|
|
||||||
double twdVal, twsVal, dbtVal;
|
|
||||||
double awaVal, awsVal, cogVal, stwVal, hdtVal, hdmVal;
|
|
||||||
double DBL_MIN = std::numeric_limits<double>::lowest();
|
|
||||||
|
|
||||||
starttime10 = millis();
|
|
||||||
LOG_DEBUG(GwLog::DEBUG,"History buffer write cycle");
|
|
||||||
api->getBoatDataValues(3, hstryValList);
|
|
||||||
|
|
||||||
if (!twdBVal->valid || !twsBVal->valid) {
|
|
||||||
api->getBoatDataValues(6, WndCalcValList); // Get all values for true wind calculation
|
|
||||||
awaVal = awaBVal->valid ? awaBVal->value * RAD_TO_DEG : __DBL_MIN__;
|
|
||||||
awsVal = awsBVal->valid ? awsBVal->value : __DBL_MIN__;
|
|
||||||
cogVal = cogBVal->valid ? cogBVal->value * RAD_TO_DEG : __DBL_MIN__;
|
|
||||||
stwVal = stwBVal->valid ? stwBVal->value : __DBL_MIN__;
|
|
||||||
hdtVal = hdtBVal->valid ? hdtBVal->value * RAD_TO_DEG : __DBL_MIN__;
|
|
||||||
hdmVal = hdmBVal->valid ? hdmBVal->value * RAD_TO_DEG : __DBL_MIN__;
|
|
||||||
LOG_DEBUG(GwLog::ERROR,"obp60task - Read data: AWA: %f, AWS: %f, COG: %f, STW: %f, HDT: %f, TWD=%f, TWS=%f", awaBVal->value, awsBVal->value,
|
|
||||||
cogBVal->value, stwBVal->value, hdtBVal->value, twdBVal->value, twsBVal->value);
|
|
||||||
|
|
||||||
bool isCalculated = WindUtils::calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &cogVal, &hdmVal, &twdVal, &twsVal); // Calculate true wind if TWD not available
|
|
||||||
// bool isCalculated = WindUtils::calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &hdtVal, &hdmVal, &twdVal, &twsVal); // Calculate true wind if TWD not available
|
|
||||||
LOG_DEBUG(GwLog::ERROR,"obp60task - calc Wind: AWA: %f, AWS: %f, COG: %f, STW: %f, HDT: %f, TWD=%f, TWS=%f, converted? %d", awaBVal->value * RAD_TO_DEG, awsBVal->value * 3.6 / 1.852,
|
|
||||||
cogBVal->value * RAD_TO_DEG, stwBVal->value * 3.6 / 1.852, hdtBVal->value * RAD_TO_DEG, twdVal, twsVal, isCalculated);
|
|
||||||
}
|
|
||||||
if (twdBVal->valid) {
|
|
||||||
twdVal = std::round(twdBVal->value * 1000); // Shift value to store decimals in int16_t);
|
|
||||||
if (twdVal < hstryMinVal || twdVal > twdHstryMax) {
|
|
||||||
twdVal = INT16_MIN; // Add invalid value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
twdHstry.add(static_cast<int16_t>(twdVal));
|
|
||||||
|
|
||||||
if (twsBVal->valid) {
|
|
||||||
twsVal = static_cast<int16_t>(twsBVal->value * 10); // Shift value to store decimals in int16_t
|
|
||||||
if (twsVal < hstryMinVal || twsVal > twsHstryMax) {
|
|
||||||
twsVal = INT16_MIN; // Add invalid value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
twsHstry.add(twsVal);
|
|
||||||
|
|
||||||
if (dbtBVal->valid) {
|
|
||||||
dbtVal = dbtBVal->value * 10; // Shift value to store decimals in int16_t
|
|
||||||
if (dbtVal < hstryMinVal || dbtVal > dbtHstryMax) {
|
|
||||||
dbtVal = INT16_MIN; // Add invalid value
|
|
||||||
}
|
|
||||||
dbtHstry.add(dbtVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
int counttime = millis() - starttime10;
|
|
||||||
LOG_DEBUG(GwLog::ERROR,"obp60task: History buffer write time: %d", counttime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh display data, default all 1s
|
// Refresh display data, default all 1s
|
||||||
currentPage = pages[pageNumber].page;
|
currentPage = pages[pageNumber].page;
|
||||||
int pagetime = 1000;
|
int pagetime = 1000;
|
||||||
|
@ -907,6 +928,12 @@ void OBP60Task(GwApi *api){
|
||||||
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
|
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
|
||||||
api->getStatus(commonData.status);
|
api->getStatus(commonData.status);
|
||||||
|
|
||||||
|
if (calcTrueWnds) {
|
||||||
|
addTrueWind(api, &boatValues);
|
||||||
|
}
|
||||||
|
// Handle history buffers for TWD, TWS for wind plot page and other usage
|
||||||
|
handleHstryBuf(api, &boatValues, hstryBufList);
|
||||||
|
|
||||||
// Clear display
|
// Clear display
|
||||||
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
|
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
|
||||||
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
||||||
|
|
Loading…
Reference in New Issue