Compare commits

..

1 Commits

Author SHA1 Message Date
Thomas Hooge 6793bcb8e1 Preparation for new page "Anchor" 2025-07-26 09:31:38 +02:00
15 changed files with 41 additions and 1531 deletions

View File

@ -1,158 +0,0 @@
#include "OBPDataOperations.h"
double WindUtils::to2PI(double a)
{
a = fmod(a, 2 * M_PI);
if (a < 0.0) {
a += 2 * M_PI;
}
return a;
}
double WindUtils::toPI(double a)
{
a += M_PI;
a = to2PI(a);
a -= M_PI;
return a;
}
double WindUtils::to360(double a)
{
a = fmod(a, 360);
if (a < 0.0) {
a += 360;
}
return a;
}
double WindUtils::to180(double a)
{
a += 180;
a = to360(a);
a -= 180;
return a;
}
void WindUtils::toCart(const double* phi, const double* r, double* x, double* y)
{
*x = *r * sin(*phi);
*y = *r * cos(*phi);
}
void WindUtils::toPol(const double* x, const double* y, double* phi, double* r)
{
*phi = (M_PI / 2) - atan2(*y, *x);
*phi = to2PI(*phi);
*r = sqrt(*x * *x + *y * *y);
}
void WindUtils::addPolar(const double* phi1, const double* r1,
const double* phi2, const double* r2,
double* phi, double* r)
{
double x1, y1, x2, y2;
toCart(phi1, r1, &x1, &y1);
toCart(phi2, r2, &x2, &y2);
x1 += x2;
y1 += y2;
toPol(&x1, &y1, phi, r);
}
void WindUtils::calcTwdSA(const double* AWA, const double* AWS,
const double* CTW, const double* STW, const double* HDT,
double* TWD, double* TWS, double* TWA)
{
double awd = *AWA + *HDT;
awd = to2PI(awd);
double stw = -*STW;
// 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);
// Normalize TWD and TWA to 0-360°
*TWD = to2PI(*TWD);
*TWA = toPI(*TWD - *HDT);
// Serial.println("calcTwdSA: TWD: " + String(*TWD) + ", TWS: " + String(*TWS));
}
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;
static const double DBL_MIN = std::numeric_limits<double>::lowest();
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
hdt = to2PI(hdt);
} else if (*cogVal != DBL_MIN) {
hdt = *cogVal; // Use COG as fallback if HDT and HDM are not available
} else {
return false; // Cannot calculate without valid HDT or HDM
}
}
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
return false;
} else {
calcTwdSA(awaVal, awsVal, &ctw, stwVal, &hdt, &twd, &tws, &twa);
*twdVal = twd;
*twsVal = tws;
*twaVal = twa;
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;
}*/

View File

@ -1,36 +0,0 @@
#pragma once
#include "GwApi.h"
#include "OBPRingBuffer.h"
#include <Arduino.h>
#include <math.h>
typedef struct {
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 {
public:
static double to2PI(double a);
static double toPI(double a);
static double to360(double a);
static double to180(double a);
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 addPolar(const double* phi1, const double* r1,
const double* phi2, const double* r2,
double* phi, double* r);
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 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);
};

View File

@ -1,60 +0,0 @@
#pragma once
#include "GwSynchronized.h"
#include <algorithm>
#include <limits>
#include <stdexcept>
#include <vector>
#include "WString.h"
template <typename T>
class RingBuffer {
private:
mutable SemaphoreHandle_t bufLocker;
std::vector<T> buffer;
size_t capacity;
size_t head; // Points to the next insertion position
size_t first; // Points to the first (oldest) valid element
size_t last; // Points to the last (newest) valid element
size_t count; // Number of valid elements currently in buffer
bool is_Full; // Indicates that all buffer elements are used and ringing is in use
T MIN_VAL; // lowest possible value of buffer
T MAX_VAL; // highest possible value of buffer of type <T>
// metadata for buffer
String dataName; // Name of boat data in buffer
String dataFmt; // Format of boat data in buffer
int updFreq; // Update frequency in milliseconds
T smallest; // Value range of buffer: smallest value
T largest; // Value range of buffer: biggest value
public:
RingBuffer(size_t size);
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
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
T getLast() const; // Get the last (newest) value in buffer
T getMin() const; // Get the lowest value in buffer
T getMin(size_t amount) const; // Get minimum value of the last <amount> values of buffer
T getMax() const; // Get the highest value in buffer
T getMax(size_t amount) const; // Get maximum value of the last <amount> values of buffer
T getMid() const; // Get mid value between <min> and <max> value in buffer
T getMid(size_t amount) const; // Get mid value between <min> and <max> value of the last <amount> values of buffer
T getMedian() const; // Get the median value in buffer
T getMedian(size_t amount) const; // Get the median value of the last <amount> values of buffer
size_t getCapacity() const; // Get the buffer capacity (maximum size)
size_t getCurrentSize() const; // Get the current number of elements in buffer
size_t getFirstIdx() const; // Get the index of oldest value in buffer
size_t getLastIdx() const; // Get the index of newest value in buffer
bool isEmpty() const; // Check if buffer is empty
bool isFull() const; // Check if buffer is full
T getMinVal() const; // Get lowest possible value for buffer; used for initialized buffer data
T getMaxVal() const; // Get highest possible value for buffer
void clear(); // Clear buffer
T operator[](size_t index) const; // Operator[] for convenient access (same as get())
std::vector<T> getAllValues() const; // Get all current values as a vector
};
#include "OBPRingBuffer.tpp"

View File

@ -1,376 +0,0 @@
#include "OBPRingBuffer.h"
template <typename T>
RingBuffer<T>::RingBuffer(size_t size)
: capacity(size)
, head(0)
, first(0)
, last(0)
, count(0)
, is_Full(false)
{
bufLocker = xSemaphoreCreateMutex();
if (size == 0) {
// return false;
}
MIN_VAL = std::numeric_limits<T>::lowest();
MAX_VAL = std::numeric_limits<T>::max();
dataName = "";
dataFmt = "";
updFreq = -1;
smallest = MIN_VAL;
largest = MAX_VAL;
buffer.resize(size, MIN_VAL);
// return true;
}
// Specify meta data of buffer content
template <typename T>
void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency, T minValue, T maxValue)
{
GWSYNCHRONIZED(&bufLocker);
dataName = name;
dataFmt = format;
updFreq = updateFrequency;
smallest = std::max(MIN_VAL, minValue);
largest = std::min(MAX_VAL, maxValue);
}
// Get meta data of buffer content
template <typename T>
bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequency, T& minValue, T& maxValue)
{
if (dataName == "" || dataFmt == "" || updFreq == -1) {
return false; // Meta data not set
}
GWSYNCHRONIZED(&bufLocker);
name = dataName;
format = dataFmt;
updateFrequency = updFreq;
minValue = smallest;
maxValue = largest;
return true;
}
// Get buffer name
template <typename T>
String RingBuffer<T>::getName() const
{
return dataName;
}
// Add a new value to buffer
template <typename T>
void RingBuffer<T>::add(const T& value)
{
GWSYNCHRONIZED(&bufLocker);
if (value < smallest || value > largest) {
buffer[head] = MIN_VAL; // Store MIN_VAL if value is out of range
} else {
buffer[head] = value;
}
last = head;
if (is_Full) {
first = (first + 1) % capacity; // Move pointer to oldest element when overwriting
} else {
count++;
if (count == capacity) {
is_Full = true;
}
}
head = (head + 1) % capacity;
}
// Get value at specific position (0-based index from oldest to newest)
template <typename T>
T RingBuffer<T>::get(size_t index) const
{
GWSYNCHRONIZED(&bufLocker);
if (isEmpty() || index < 0 || index >= count) {
return MIN_VAL;
}
size_t realIndex = (first + index) % capacity;
return buffer[realIndex];
}
// Operator[] for convenient access (same as get())
template <typename T>
T RingBuffer<T>::operator[](size_t index) const
{
return get(index);
}
// Get the first (oldest) value in the buffer
template <typename T>
T RingBuffer<T>::getFirst() const
{
if (isEmpty()) {
return MIN_VAL;
}
return get(0);
}
// Get the last (newest) value in the buffer
template <typename T>
T RingBuffer<T>::getLast() const
{
if (isEmpty()) {
return MIN_VAL;
}
return get(count - 1);
}
// Get the lowest value in the buffer
template <typename T>
T RingBuffer<T>::getMin() const
{
if (isEmpty()) {
return MIN_VAL;
}
T minVal = MAX_VAL;
T value;
for (size_t i = 0; i < count; i++) {
value = get(i);
if (value < minVal && value != MIN_VAL) {
minVal = value;
}
}
return minVal;
}
// Get minimum value of the last <amount> values of buffer
template <typename T>
T RingBuffer<T>::getMin(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return MIN_VAL;
}
if (amount > count)
amount = count;
T minVal = MAX_VAL;
T value;
for (size_t i = 0; i < amount; i++) {
value = get(count - 1 - i);
if (value < minVal && value != MIN_VAL) {
minVal = value;
}
}
return minVal;
}
// Get the highest value in the buffer
template <typename T>
T RingBuffer<T>::getMax() const
{
if (isEmpty()) {
return MIN_VAL;
}
T maxVal = MIN_VAL;
T value;
for (size_t i = 0; i < count; i++) {
value = get(i);
if (value > maxVal && value != MIN_VAL) {
maxVal = value;
}
}
return maxVal;
}
// Get maximum value of the last <amount> values of buffer
template <typename T>
T RingBuffer<T>::getMax(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return MIN_VAL;
}
if (amount > count)
amount = count;
T maxVal = MIN_VAL;
T value;
for (size_t i = 0; i < amount; i++) {
value = get(count - 1 - i);
if (value > maxVal && value != MIN_VAL) {
maxVal = value;
}
}
return maxVal;
}
// Get mid value between <min> and <max> value in the buffer
template <typename T>
T RingBuffer<T>::getMid() const
{
if (isEmpty()) {
return MIN_VAL;
}
return (getMin() + getMax()) / static_cast<T>(2);
}
// Get mid value between <min> and <max> value of the last <amount> values of buffer
template <typename T>
T RingBuffer<T>::getMid(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return MIN_VAL;
}
if (amount > count)
amount = count;
return (getMin(amount) + getMax(amount)) / static_cast<T>(2);
}
// Get the median value in the buffer
template <typename T>
T RingBuffer<T>::getMedian() const
{
if (isEmpty()) {
return MIN_VAL;
}
// Create a temporary vector with current valid elements
std::vector<T> temp;
temp.reserve(count);
for (size_t i = 0; i < count; i++) {
temp.push_back(get(i));
}
// Sort to find median
std::sort(temp.begin(), temp.end());
if (count % 2 == 1) {
// Odd number of elements
return temp[count / 2];
} else {
// Even number of elements - return average of middle two
// Note: For integer types, this truncates. For floating point, it's exact.
return (temp[count / 2 - 1] + temp[count / 2]) / 2;
}
}
// Get the median value of the last <amount> values of buffer
template <typename T>
T RingBuffer<T>::getMedian(size_t amount) const
{
if (isEmpty() || amount <= 0) {
return MIN_VAL;
}
if (amount > count)
amount = count;
// Create a temporary vector with current valid elements
std::vector<T> temp;
temp.reserve(amount);
for (size_t i = 0; i < amount; i++) {
temp.push_back(get(i));
}
// Sort to find median
std::sort(temp.begin(), temp.end());
if (amount % 2 == 1) {
// Odd number of elements
return temp[amount / 2];
} else {
// Even number of elements - return average of middle two
// Note: For integer types, this truncates. For floating point, it's exact.
return (temp[amount / 2 - 1] + temp[amount / 2]) / 2;
}
}
// Get the buffer capacity (maximum size)
template <typename T>
size_t RingBuffer<T>::getCapacity() const
{
return capacity;
}
// Get the current number of elements in the buffer
template <typename T>
size_t RingBuffer<T>::getCurrentSize() const
{
return count;
}
// Get the first index of buffer
template <typename T>
size_t RingBuffer<T>::getFirstIdx() const
{
return first;
}
// Get the last index of buffer
template <typename T>
size_t RingBuffer<T>::getLastIdx() const
{
return last;
}
// Check if buffer is empty
template <typename T>
bool RingBuffer<T>::isEmpty() const
{
return count == 0;
}
// Check if buffer is full
template <typename T>
bool RingBuffer<T>::isFull() const
{
return is_Full;
}
// Get lowest possible value for buffer; used for non-set buffer data
template <typename T>
T RingBuffer<T>::getMinVal() const
{
return MIN_VAL;
}
// Get highest possible value for buffer
template <typename T>
T RingBuffer<T>::getMaxVal() const
{
return MAX_VAL;
}
// Clear buffer
template <typename T>
void RingBuffer<T>::clear()
{
GWSYNCHRONIZED(&bufLocker);
head = 0;
first = 0;
last = 0;
count = 0;
is_Full = false;
}
// Get all current values as a vector
template <typename T>
std::vector<T> RingBuffer<T>::getAllValues() const
{
std::vector<T> result;
result.reserve(count);
for (size_t i = 0; i < count; i++) {
result.push_back(get(i));
}
return result;
}

View File

@ -6,37 +6,16 @@
/* /*
Anchor overview with additional associated data Anchor overview with additional associated data
This page is in experimental stage so be warned! This page is in experimental stage so be warned!
North is up.
Boatdata used
DBS - Water depth DBS - Water depth
HDT - Boat heading HDT - Boat heading
AWS - Wind strength; Boat not moving so we assume AWS=TWS and AWD=TWD TWS - Wind strength
AWD - Wind direction TWD - Wind direction
LAT/LON - Boat position, current
HDOP - Position error
This is the fist page to contain a configuration page with This is the fist page to contain a configuration page with
data entry option. data entry option.
Also it will make use of the new alarm function. Also it will make use of the new alarm function.
Data
Anchor position lat/lon
Depth at anchor position
Chain length used
Boat position current
Depth at boat position
Boat heading
Wind direction
Wind strength
Alarm j/n
Alarm radius
GPS position error
Timestamp while dropping anchor
Drop / raise function in device OBP40 has to be done inside
config mode because of limited number of buttons.
*/ */
#define anchor_width 16 #define anchor_width 16
@ -48,180 +27,54 @@ static unsigned char anchor_bits[] = {
class PageAnchor : public Page class PageAnchor : public Page
{ {
private:
GwConfigHandler *config;
GwLog *logger;
bool simulation = false; bool simulation = false;
bool holdvalues = false; bool holdvalues = false;
String flashLED; String flashLED;
String backlightMode; String backlightMode;
bool alarm = false;
bool alarm_enabled = false;
uint8_t alarm_range;
uint8_t chain_length;
uint8_t chain;
bool anchor_set = false;
double anchor_lat;
double anchor_lon;
double anchor_depth;
int anchor_ts; // time stamp anchor dropped
char mode = 'N'; // (N)ormal, (C)onfig
void displayModeNormal(PageData &pageData) {
// Boatvalues: DBS, HDT, AWS, AWD, LAT, LON, HDOP
GwApi::BoatValue *bv_dbs = pageData.values[0]; // DBS
String sval_dbs = formatValue(bv_dbs, *commonData).svalue;
GwApi::BoatValue *bv_hdt = pageData.values[1]; // HDT
String sval_hdt = formatValue(bv_hdt, *commonData).svalue;
GwApi::BoatValue *bv_aws = pageData.values[2]; // AWS
String sval_aws = formatValue(bv_aws, *commonData).svalue;
GwApi::BoatValue *bv_awd = pageData.values[3]; // AWD
String sval_awd = formatValue(bv_awd, *commonData).svalue;
GwApi::BoatValue *bv_lat = pageData.values[4]; // LAT
String sval_lat = formatValue(bv_lat, *commonData).svalue;
GwApi::BoatValue *bv_lon = pageData.values[5]; // LON
String sval_lon = formatValue(bv_lon, *commonData).svalue;
GwApi::BoatValue *bv_hdop = pageData.values[6]; // HDOP
String sval_hdop = formatValue(bv_hdop, *commonData).svalue;
Point c = {200, 150}; // center = anchor position
uint16_t r = 125;
Point b = {200, 180}; // boat position while dropping anchor
std::vector<Point> pts_boat = { // polygon lines
{b.x - 5, b.y},
{b.x - 5, b.y - 10},
{b.x, b.y - 16},
{b.x + 5, b.y - 10}
};
//rotatePoints und dann Linien zeichnen
// TODO rotate boat according to current heading
//fillPoly4(rotatePoints(c, pts, RadToDeg(value2)), commonData->fgcolor);
// Draw wind arrow
/*
if self._bd.awa.value:
p = ((cx, cy - r + 25), (cx - 12, cy - r - 4), (cx, cy - r + 6), (cx + 12, cy - r - 4), (cx, cy - r + 25))
wind = self.rotate((cx, cy), p, self._bd.awa.value)
ctx.move_to(*wind[0])
for point in wind[1:]:
ctx.line_to(*point)
ctx.fill()
*/
// Title and corner value headings
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold10pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("Anchor");
getdisplay().setCursor(8, 200);
getdisplay().print("Depth");
drawTextRalign(392, 50, "Chain");
drawTextRalign(392, 200, "Wind");
// Corner values
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(2, 70);
getdisplay().print("Alarm: ");
getdisplay().print(alarm_enabled ? "On" : "Off");
// Units
// Values
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
// Depth
getdisplay().setCursor(8, 250);
//getdisplay().print(sval_dbs);
getdisplay().print("6.4");
// Wind
getdisplay().setCursor(320, 250);
//getdisplay().print(sval_aws);
getdisplay().print("12");
getdisplay().drawCircle(c.x, c.y, r, commonData->fgcolor);
// draw anchor symbol (as bitmap)
getdisplay().drawXBitmap(c.x - anchor_width / 2, c.y - anchor_height / 2,
anchor_bits, anchor_width, anchor_height, commonData->fgcolor);
}
void displayModeConfig() {
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("Anchor configuration");
}
public: public:
PageAnchor(CommonData &common){ PageAnchor(CommonData &common){
commonData = &common; commonData = &common;
config = commonData->config; common.logger->logDebug(GwLog::LOG,"Instantiate PageAnchor");
logger = commonData->logger;
logger->logDebug(GwLog::LOG,"Instantiate PageAnchor");
// preload configuration data // preload configuration data
simulation = config->getBool(config->useSimuData); simulation = common.config->getBool(common.config->useSimuData);
holdvalues = config->getBool(config->holdvalues); holdvalues = common.config->getBool(common.config->holdvalues);
flashLED = config->getString(config->flashLED); flashLED = common.config->getString(common.config->flashLED);
backlightMode = config->getString(config->backlight); backlightMode = common.config->getString(common.config->backlight);
chainLength = config->getInt(config->chainLength);
chain = 0;
anchor_set = false;
}
void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "MODE";
commonData->keydata[1].label = "ALARM";
} }
int handleKey(int key){ virtual int handleKey(int key){
if (key == 1) { // Switch between normal and config mode // Code for keylock
if (mode == 'N') { if (key == 11) {
mode = 'C';
} else {
mode = 'N';
}
return 0;
}
if (key == 2) { // Toggle alarm
alarm_enabled = !alarm_enabled;
return 0;
}
if (key == 11) { // Code for keylock
commonData->keylock = !commonData->keylock; commonData->keylock = !commonData->keylock;
return 0; return 0; // Commit the key
} }
return key; return key;
} }
void displayNew(PageData &pageData){ void displayNew(PageData &pageData){
}; }
int displayPage(PageData &pageData){ int displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Logging boat values // Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor"); LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor");
LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor; Mode=%c", mode);
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
if (mode == 'N') { uint16_t cx = 200; // center = anchor position
displayModeNormal(pageData); uint16_t cy = 150;
} else if (mode == 'C') {
displayModeConfig(); // draw anchor symbol (as bitmap)
} getdisplay().drawXBitmap(cx - anchor_width / 2, cy - anchor_height / 2,
anchor_bits, anchor_width, anchor_height, commonData->fgcolor);
getdisplay().setTextColor(commonData->fgcolor);
return PAGE_UPDATE; return PAGE_UPDATE;
}; };
@ -229,9 +82,7 @@ class PageAnchor : public Page
static Page *createPage(CommonData &common){ static Page *createPage(CommonData &common){
return new PageAnchor(common); return new PageAnchor(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 give it a type (name) that can be selected in the config
* we define which function is to be called * we define which function is to be called
@ -239,11 +90,11 @@ static Page *createPage(CommonData &common){
* this will be number of BoatValue pointers in pageData.values * this will be number of BoatValue pointers in pageData.values
*/ */
PageDescription registerPageAnchor( PageDescription registerPageAnchor(
"Anchor", // Page name "Anchor", // 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
{"DBS", "HDT", "AWS", "AWD", "LAT", "LON", "HDOP"}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h) {"DBS", "HDT", "TWS", "TWD"}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off true // Show display header on/off
); );
#endif #endif

View File

@ -1,489 +0,0 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "BoatDataCalibration.h"
#include "OBP60Extensions.h"
#include "OBPRingBuffer.h"
#include "Pagedata.h"
#include <vector>
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
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;
}
if (amount > count)
amount = count;
int value = 0;
int rng = 0;
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) {
continue;
}
value = value / 1000.0 * radToDeg;
rng = abs(((value - center + 540) % 360) - 180);
if (rng > maxRng)
maxRng = rng;
}
if (maxRng > 180) {
maxRng = 180;
}
return maxRng;
}
// ****************************************************************
class PageWindPlot : public Page {
bool keylock = false; // Keylock
char chrtMode = 'D'; // Chart mode: 'D' for TWD, 'S' for TWS, 'B' for both
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)
{
commonData = &common;
common.logger->logDebug(GwLog::LOG, "Instantiate PageWindPlot");
}
virtual void setupKeys()
{
Page::setupKeys();
// commonData->keydata[0].label = "MODE";
commonData->keydata[1].label = "INTV";
commonData->keydata[4].label = "TWS";
}
// Key functions
virtual int handleKey(int key)
{
// Set chart mode TWD | TWS -> to be implemented
if (key == 1) {
if (chrtMode == 'D') {
chrtMode = 'S';
} else if (chrtMode == 'S') {
chrtMode = 'B';
} else {
chrtMode = 'D';
}
return 0; // Commit the key
}
// Set interval for wind history chart update time
if (key == 2) {
if (dataIntv == 1) {
dataIntv = 2;
} else if (dataIntv == 2) {
dataIntv = 3;
} else if (dataIntv == 3) {
dataIntv = 4;
} else {
dataIntv = 1;
}
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;
return 0; // Commit the key
}
return key;
}
int displayPage(PageData& pageData)
{
GwConfigHandler* config = commonData->config;
GwLog* logger = commonData->logger;
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
// current boat data values; TWD only for validation test, TWS for display of current value
const int numBoatData = 2;
GwApi::BoatValue* bvalue;
String BDataName[numBoatData];
double BDataValue[numBoatData];
bool BDataValid[numBoatData];
String BDataText[numBoatData];
String BDataUnit[numBoatData];
String BDataFormat[numBoatData];
static bool isInitialized = false; // Flag to indicate that page is initialized
static bool wndDataValid = false; // Flag to indicate if wind data is valid
static int numNoData; // Counter for multiple invalid data values in a row
static bool simulation = false;
static bool holdValues = false;
static int width; // Screen width
static int height; // Screen height
static int xCenter; // Center of screen in x direction
static const int yOffset = 48; // Offset for y coordinates of chart area
static int cHeight; // height of chart area
static int bufSize; // History buffer size: 960 values for appox. 16 min. history chart
static int intvBufSize; // Buffer size used for currently selected time interval
int count; // current size of buffer
static int numWndVals; // number of wind values available for current interval selection
static int bufStart; // 1st data value in buffer to show
int numAddedBufVals; // Number of values added to buffer since last display
size_t currIdx; // Current index in TWD history buffer
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 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
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
static float chrtScl; // Scale for wind values in pixels per degree
int chrtVal; // Current wind value
static int chrtPrevVal; // Last wind value in chart area for check if value crosses 180 degree line
LOG_DEBUG(GwLog::LOG, "Display page WindPlot");
// Get config data
simulation = config->getBool(config->useSimuData);
holdValues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
if (!isInitialized) {
width = getdisplay().width();
height = getdisplay().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;
numAddedBufVals, currIdx, lastIdx = 0;
lastAddedIdx = pageData.boatHstry.twdHstry->getLastIdx();
pageData.boatHstry.twdHstry->getMetaData(twdName, twdUnit, updFreq, twdLowest, twdHighest);
wndCenter = INT_MIN;
midWndDir = 0;
diffRng = dfltRng;
chrtRng = dfltRng;
isInitialized = true; // Set flag to indicate that page is now initialized
}
// read boat data values; TWD only for validation test, TWS for display of current value
for (int i = 0; i < numBoatData; i++) {
bvalue = pageData.values[i];
// BDataName[i] = xdrDelete(bvalue->getName());
BDataName[i] = BDataName[i].substring(0, 6); // String length limit for value name
calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated
BDataValue[i] = bvalue->value; // Value as double in SI unit
BDataValid[i] = bvalue->valid;
BDataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
BDataUnit[i] = formatValue(bvalue, *commonData).unit;
BDataFormat[i] = bvalue->getFormat(); // Unit of value
}
// Optical warning by limit violation (unused)
if (String(flashLED) == "Limit Violation") {
setBlinkingLED(false);
setFlashLED(false);
}
// Identify buffer size and buffer start position for chart
count = pageData.boatHstry.twdHstry->getCurrentSize();
currIdx = pageData.boatHstry.twdHstry->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
intvBufSize = cHeight * dataIntv;
numWndVals = min(count, (cHeight - 60) * dataIntv);
bufStart = max(0, count - numWndVals);
lastAddedIdx = currIdx;
oldDataIntv = dataIntv;
} else {
numWndVals = numWndVals + numAddedBufVals;
lastAddedIdx = currIdx;
if (count == bufSize) {
bufStart = max(0, bufStart - numAddedBufVals);
}
}
LOG_DEBUG(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);
// 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;
}
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 {
// check and adjust range between left, center, and right chart limit
diffRng = getRng(*pageData.boatHstry.twdHstry, 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);
}
}
chrtScl = float(width) / float(chrtRng) / 2.0; // Chart scale: pixels per degree
wndLeft = wndCenter - chrtRng;
if (wndLeft < 0)
wndLeft += 360;
wndRight = (chrtRng < 180 ? wndCenter + chrtRng : wndCenter + chrtRng - 1);
if (wndRight >= 360)
wndRight -= 360;
// Draw page
//***********************************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, width, height); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
// chart lines
getdisplay().fillRect(0, yOffset, width, 2, commonData->fgcolor);
getdisplay().fillRect(xCenter, yOffset, 1, cHeight, commonData->fgcolor);
// chart labels
char sWndLbl[4]; // char buffer for Wind angle label
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(xCenter - 88, yOffset - 3);
getdisplay().print("TWD"); // Wind data name
snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter);
drawTextCenter(xCenter, yOffset - 11, sWndLbl);
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
getdisplay().drawCircle(xCenter + 25, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
getdisplay().setCursor(1, yOffset - 3);
snprintf(sWndLbl, 4, "%03d", (wndLeft < 0) ? (wndLeft + 360) : wndLeft);
getdisplay().print(sWndLbl); // Wind left value
getdisplay().drawCircle(46, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
getdisplay().drawCircle(46, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
getdisplay().setCursor(width - 50, yOffset - 3);
snprintf(sWndLbl, 4, "%03d", (wndRight < 0) ? (wndRight + 360) : wndRight);
getdisplay().print(sWndLbl); // Wind right value
getdisplay().drawCircle(width - 5, yOffset - 17, 2, commonData->fgcolor); // <degree> symbol
getdisplay().drawCircle(width - 5, yOffset - 17, 3, commonData->fgcolor); // <degree> symbol
if (pageData.boatHstry.twdHstry->getMax() == pageData.boatHstry.twdHstry->getMinVal()) {
// only <INT16_MIN> values in buffer -> no valid wind data available
wndDataValid = false;
} else if (!BDataValid[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;
}
} else {
numNoData = 0; // reset data error counter
wndDataValid = true; // At least some wind data available
}
// Draw wind values in chart
//***********************************************************************
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
if (chrtVal == INT16_MIN) {
chrtPrevVal = INT16_MIN;
/* if (i == linesToShow - 1) {
numNoData++;
// If more than 4 invalid values in a row, reset chart
} else {
numNoData = 0; // Reset invalid value counter
}
if (numNoData > 4) {
// If more than 4 invalid values in a row, send message
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 {
chrtVal = static_cast<int>((chrtVal / 1000.0 * radToDeg) + 0.5); // Convert to degrees and round
x = ((chrtVal - wndLeft + 360) % 360) * chrtScl;
y = yOffset + cHeight - i; // Position in chart area
if (i >= (numWndVals / dataIntv) - 10)
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)) {
// just a dot for 1st chart point or after some invalid values
prevX = x;
prevY = y;
} else {
// cross borders check; shift values to [-180..0..180]; when crossing borders, range is 2x 180 degrees
int wndLeftDlt = -180 - ((wndLeft >= 180) ? (wndLeft - 360) : wndLeft);
int chrtVal180 = ((chrtVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180;
int chrtPrevVal180 = ((chrtPrevVal + wndLeftDlt + 180) % 360 + 360) % 360 - 180;
if (((chrtPrevVal180 >= -180) && (chrtPrevVal180 < -90) && (chrtVal180 > 90)) || ((chrtPrevVal180 <= 179) && (chrtPrevVal180 > 90) && chrtVal180 <= -90)) {
// If current value crosses chart borders compared to previous value, split line
int xSplit = (((chrtPrevVal180 > 0 ? wndRight : wndLeft) - wndLeft + 360) % 360) * chrtScl;
getdisplay().drawLine(prevX, prevY, xSplit, y, commonData->fgcolor);
getdisplay().drawLine(prevX, prevY - 1, ((xSplit != prevX) ? xSplit : xSplit - 1), ((xSplit != prevX) ? y - 1 : y), commonData->fgcolor);
prevX = (((chrtVal180 > 0 ? wndRight : wndLeft) - wndLeft + 360) % 360) * chrtScl;
}
}
// Draw line with 2 pixels width + make sure vertical line are drawn correctly
getdisplay().drawLine(prevX, prevY, x, y, commonData->fgcolor);
getdisplay().drawLine(prevX, prevY - 1, ((x != prevX) ? x : x - 1), ((x != prevX) ? y - 1 : y), commonData->fgcolor);
chrtPrevVal = chrtVal;
prevX = x;
prevY = y;
}
// Reaching chart area top end
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;
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: Minimum: %d, Maximum: %d, OldwndCenter: %d", minWndDir, 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
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
}
}
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot FreeTop: cHeight: %d, bufStart: %d, numWndVals: %d, wndCenter: %d", cHeight, bufStart, numWndVals, wndCenter);
break;
}
}
} else {
// No valid data available
LOG_DEBUG(GwLog::LOG, "PageWindPlot: No valid data available");
getdisplay().setFont(&Ubuntu_Bold10pt8b);
getdisplay().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) {
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;
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
if ((y >= yPosTws - 38) && (y <= yPosTws + 6) && (x >= xPosTws - 4) && (x <= xPosTws + 146)) {
flipTws = !flipTws;
xPosTws = flipTws ? 20 : width - 145;
}
}
lastZone = currentZone;
getdisplay().fillRect(xPosTws - 4, yPosTws - 38, 142, 44, commonData->bgcolor); // Clear area for TWS value
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(xPosTws, yPosTws);
if (!BDataValid[1]) {
getdisplay().print("--.-");
} else {
double dbl = BDataValue[1] * 3.6 / 1.852;
if (dbl < 10.0) {
getdisplay().printf("!%3.1f", dbl); // Value, round to 1 decimal
} else {
getdisplay().printf("%4.1f", dbl); // Value, round to 1 decimal
}
}
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(xPosTws + 82, yPosTws - 14);
// getdisplay().print("TWS"); // Name
getdisplay().print(BDataName[1]); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b);
// getdisplay().setCursor(xPosTws + 78, yPosTws + 1);
getdisplay().setCursor(xPosTws + 82, yPosTws + 1);
// getdisplay().printf(" kn"); // Unit
getdisplay().print(BDataUnit[1]); // Unit
}
// chart Y axis labels; print at last to overwrite potential chart lines in label area
int yPos;
int chrtLbl;
getdisplay().setFont(&Ubuntu_Bold8pt8b);
for (int i = 1; i <= 3; i++) {
yPos = yOffset + (i * 60);
getdisplay().fillRect(0, yPos, width, 1, commonData->fgcolor);
getdisplay().fillRect(0, yPos - 8, 24, 16, commonData->bgcolor); // Clear small area to remove potential chart lines
getdisplay().setCursor(1, yPos + 4);
if (count >= intvBufSize) {
// Calculate minute value for label
chrtLbl = ((i - 1 + (prevY < yOffset + 30)) * dataIntv) * -1; // change label if last data point is more than 30 lines (= seconds) from chart line
} else {
int j = 3 - i;
chrtLbl = (int((((numWndVals / dataIntv) - 50) * dataIntv / 60) + 1) - (j * dataIntv)) * -1; // 50 lines left below last chart line
}
getdisplay().printf("%3d", chrtLbl); // Wind value label
}
return PAGE_UPDATE;
};
};
static Page* createPage(CommonData& common)
{
return new PageWindPlot(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 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
true // Show display header on/off
);
#endif

View File

@ -4,19 +4,15 @@
#include <functional> #include <functional>
#include <vector> #include <vector>
#include "LedSpiTask.h" #include "LedSpiTask.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 std::vector<GwApi::BoatValue *> ValueList; typedef std::vector<GwApi::BoatValue *> ValueList;
typedef struct{ typedef struct{
String pageName; String pageName;
uint8_t pageNumber; // page number in sequence of visible pages uint8_t pageNumber; // page number in sequence of visible pages
//the values will always contain the user defined values first //the values will always contain the user defined values first
ValueList values; ValueList values;
tBoatHstryData boatHstry;
} PageData; } PageData;
// Sensor data structure (only for extended sensors, not for NMEA bus sensors) // Sensor data structure (only for extended sensors, not for NMEA bus sensors)

View File

@ -75,20 +75,6 @@
"obp60":"true" "obp60":"true"
} }
}, },
{
"name": "chainLength",
"label": "Anchor Chain Length [m]",
"type": "number",
"default": 0,
"check": "checkMinMax",
"min": 0,
"max": 255,
"description": "The length of the anchor chain [0...255m]",
"category": "OBP60 Settings",
"capabilities": {
"obp60":"true"
}
},
{ {
"name": "fuelTank", "name": "fuelTank",
"label": "Fuel Tank [l]", "label": "Fuel Tank [l]",
@ -233,17 +219,6 @@
"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",
@ -1339,7 +1314,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -1621,7 +1595,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -1900,7 +1873,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -2176,7 +2148,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -2449,7 +2420,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -2719,7 +2689,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -2986,7 +2955,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -3250,7 +3218,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -3511,7 +3478,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -3769,7 +3735,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"

View File

@ -75,20 +75,6 @@
"obp40": "true" "obp40": "true"
} }
}, },
{
"name": "chainLength",
"label": "Anchor Chain Length [m]",
"type": "number",
"default": "0",
"check": "checkMinMax",
"min": 0,
"max": 255,
"description": "The length of the anchor chain [0...255m]",
"category": "OBP40 Settings",
"capabilities": {
"obp40":"true"
}
},
{ {
"name": "fuelTank", "name": "fuelTank",
"label": "Fuel Tank [l]", "label": "Fuel Tank [l]",
@ -233,17 +219,6 @@
"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",
@ -1362,7 +1337,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -1644,7 +1618,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -1923,7 +1896,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -2199,7 +2171,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -2472,7 +2443,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -2742,7 +2712,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -3009,7 +2978,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -3273,7 +3241,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -3534,7 +3501,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"
@ -3792,7 +3758,6 @@
"Voltage", "Voltage",
"WhitePage", "WhitePage",
"Wind", "Wind",
"WindPlot",
"WindRose", "WindRose",
"WindRoseFlex", "WindRoseFlex",
"XTETrack" "XTETrack"

View File

@ -31,7 +31,6 @@ no_of_fields_per_page = {
"TwoValues": 2, "TwoValues": 2,
"Voltage": 0, "Voltage": 0,
"WhitePage": 0, "WhitePage": 0,
"WindPlot": 0,
"WindRose": 0, "WindRose": 0,
"WindRoseFlex": 6, "WindRoseFlex": 6,
"Anchor", 0 "Anchor", 0

View File

@ -1,6 +1,6 @@
#define OBP40_400x300_width 400 #define OBP40_400x300_width 400
#define OBP40_400x300_height 300 #define OBP40_400x300_height 300
const unsigned char OBP40_400x300_bits[15000] PROGMEM = { static unsigned char OBP40_400x300_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View File

@ -1,6 +1,6 @@
#define OBP60_400x300_width 400 #define OBP60_400x300_width 400
#define OBP60_400x300_height 300 #define OBP60_400x300_height 300
const unsigned char OBP60_400x300_bits[15000] PROGMEM = { static unsigned char OBP60_400x300_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View File

@ -1,6 +1,6 @@
#define OBP_400x300_width 400 #define OBP_400x300_width 400
#define OBP_400x300_height 300 #define OBP_400x300_height 300
const unsigned char OBP_400x300_bits[15000] PROGMEM = { static unsigned char OBP_400x300_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View File

@ -13,11 +13,9 @@
#include "OBP60Extensions.h" // Functions lib for extension board #include "OBP60Extensions.h" // Functions lib for extension board
#include "OBP60Keypad.h" // Functions for keypad #include "OBP60Keypad.h" // Functions for keypad
#include "BoatDataCalibration.h" // Functions lib for data instance calibration #include "BoatDataCalibration.h" // Functions lib for data instance calibration
#include "OBPRingBuffer.h" // Functions lib with ring buffer for history storage of some boat data
#include "OBPDataOperations.h" // Functions lib for data operations such as true wind calculation
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
#include "driver/rtc_io.h" // Needs for wakeup from deep sleep #include "driver/rtc_io.h" // Needs for weakup from deep sleep
#include <FS.h> // SD-Card access #include <FS.h> // SD-Card access
#include <SD.h> #include <SD.h>
#include <SPI.h> #include <SPI.h>
@ -277,8 +275,6 @@ void registerAllPages(PageList &list){
list.add(&registerPageFourValues2); list.add(&registerPageFourValues2);
extern PageDescription registerPageWind; extern PageDescription registerPageWind;
list.add(&registerPageWind); list.add(&registerPageWind);
extern PageDescription registerPageWindPlot;
list.add(&registerPageWindPlot);
extern PageDescription registerPageWindRose; extern PageDescription registerPageWindRose;
list.add(&registerPageWindRose); list.add(&registerPageWindRose);
extern PageDescription registerPageWindRoseFlex; extern PageDescription registerPageWindRoseFlex;
@ -378,125 +374,6 @@ 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;
double twd, tws, twa;
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::DEBUG,"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);
isCalculated = WindUtils::calcTrueWind(&awaVal, &awsVal, &cogVal, &stwVal, &sogVal, &hdtVal, &hdmVal, &varVal, &twd, &tws, &twa);
if (isCalculated) { // Replace values only, if successfully calculated and not already available
if (!twdBVal->valid) {
twdBVal->value = twd;
twdBVal->valid = true;
}
if (!twsBVal->valid) {
twsBVal->value = tws;
twsBVal->valid = true;
}
if (!twaBVal->valid) {
twaBVal->value = twa;
twaBVal->valid = true;
}
}
api->getLogger()->logDebug(GwLog::DEBUG,"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::DEBUG,"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){
@ -610,11 +487,6 @@ 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;
@ -653,10 +525,6 @@ 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);
} }
if (pages[i].description->pageName == "WindPlot") {
// 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);
@ -664,13 +532,6 @@ 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);
// 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);
// Initialize history buffer for certain boat data
initHstryBuf(api, &boatValues, hstryBufList);
// 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
api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) { api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) {
@ -956,8 +817,8 @@ void OBP60Task(GwApi *api){
// getdisplay().nextPage(); // Partial update // getdisplay().nextPage(); // Partial update
// getdisplay().nextPage(); // Partial update // getdisplay().nextPage(); // Partial update
} }
} }
// 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;
@ -973,12 +834,6 @@ 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

View File

@ -43,17 +43,16 @@ lib_deps =
adafruit/Adafruit FRAM I2C@2.0.3 adafruit/Adafruit FRAM I2C@2.0.3
build_flags= build_flags=
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (serial device) # -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (seral device)
# -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC) # -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC)
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib -D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
-D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3 -D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3
# -D HARDWARE_V20 #OBP60 hardware revision V2.0 # -D HARDWARE_V20 #OBP60 hardware revision V2.0
-D HARDWARE_V21 #OBP60 hardware revision V2.1 -D HARDWARE_V21 #OBP60 hardware revision V2.1
# -D DISPLAY_GDEW042T2 #old E-Ink display from GoodDisplay (Waveshare), R10 0.47 ohm - very good # -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm
-D DISPLAY_GDEY042T81 #new E-Ink display from GoodDisplay (Waveshare), R10 2.2 ohm - good (contast lost by shunshine) -D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
# -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm - medium # -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
# -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm - bad (burn in effects) # -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm
# -D DISPLAY_ZJY400300-042CAAMFGN #alternativ E-Ink display from ZZE Technology, R10 2.2 ohm - very good
${env.build_flags} ${env.build_flags}
#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default #CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
upload_port = /dev/ttyACM0 #OBP60 download via USB-C direct upload_port = /dev/ttyACM0 #OBP60 download via USB-C direct
@ -97,8 +96,7 @@ build_flags=
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib -D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
-D BOARD_OBP40S3 #Board OBP40 with ESP32S3 -D BOARD_OBP40S3 #Board OBP40 with ESP32S3
-D HARDWARE_V10 #OBP40 hardware revision V1.0 SKU:DIE07300S V1.1 (CrowPanel 4.2) -D HARDWARE_V10 #OBP40 hardware revision V1.0 SKU:DIE07300S V1.1 (CrowPanel 4.2)
-D DISPLAY_GDEY042T81 #new E-Ink display from Good Display (Waveshare), R10 2.2 ohm - good (contast lost by shunshine) -D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
#-D DISPLAY_ZJY400300-042CAAMFGN #alternativ E-Ink display from ZZE Technology, R10 2.2 ohm - very good
#-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh #-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh
#-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors #-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors
${env.build_flags} ${env.build_flags}