1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-29 05:33:05 +01:00

Merge branch 'PageWindPlot' of https://github.com/Scorgan01/esp32-nmea2000-obp60 into PageWindPlot

This commit is contained in:
Ulrich Meine
2025-09-12 18:58:53 +02:00
6 changed files with 90 additions and 28 deletions

View File

@@ -40,12 +40,13 @@ public:
HstryBuf(){ HstryBuf(){
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; // Generate history buffers of zero size hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; // Generate history buffers of zero size
}; };
HstryBuf(int size) { HstryBuf(int size) {
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry};
hstryBufList.twdHstry->resize(960); // store 960 TWD values for 16 minutes history hstryBufList.twdHstry->resize(size); // store <size> xWD values for <size>/60 minutes history
hstryBufList.twsHstry->resize(960); hstryBufList.twsHstry->resize(size);
hstryBufList.awdHstry->resize(960); hstryBufList.awdHstry->resize(size);
hstryBufList.awsHstry->resize(960); hstryBufList.awsHstry->resize(size);
}; };
void init(BoatValueList* boatValues, GwLog *log); void init(BoatValueList* boatValues, GwLog *log);
void handleHstryBuf(bool useSimuData); void handleHstryBuf(bool useSimuData);

View File

@@ -1,15 +1,48 @@
#pragma once #pragma once
#include "GwSynchronized.h" #include "GwSynchronized.h"
#include "WString.h"
#include "esp_heap_caps.h"
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include "WString.h"
template <typename T>
struct PSRAMAllocator {
using value_type = T;
PSRAMAllocator() = default;
template <class U>
constexpr PSRAMAllocator(const PSRAMAllocator<U>&) noexcept { }
T* allocate(std::size_t n)
{
void* ptr = heap_caps_malloc(n * sizeof(T), MALLOC_CAP_SPIRAM);
if (!ptr) {
return nullptr;
} else {
return static_cast<T*>(ptr);
}
}
void deallocate(T* p, std::size_t) noexcept
{
heap_caps_free(p);
}
};
template <class T, class U>
bool operator==(const PSRAMAllocator<T>&, const PSRAMAllocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const PSRAMAllocator<T>&, const PSRAMAllocator<U>&) { return false; }
template <typename T> template <typename T>
class RingBuffer { class RingBuffer {
private: private:
std::vector<T> buffer; // THE buffer vector // std::vector<T> buffer; // THE buffer vector
std::vector<T, PSRAMAllocator<T>> buffer; // THE buffer vector, allocated in PSRAM
size_t capacity; size_t capacity;
size_t head; // Points to the next insertion position size_t head; // Points to the next insertion position
size_t first; // Points to the first (oldest) valid element size_t first; // Points to the first (oldest) valid element

View File

@@ -35,6 +35,8 @@ RingBuffer<T>::RingBuffer(size_t size)
, is_Full(false) , is_Full(false)
{ {
initCommon(); initCommon();
buffer.reserve(size);
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values
} }
@@ -405,6 +407,7 @@ void RingBuffer<T>::resize(size_t newSize)
is_Full = false; is_Full = false;
buffer.clear(); buffer.clear();
buffer.reserve(newSize);
buffer.resize(newSize, MAX_VAL); buffer.resize(newSize, MAX_VAL);
} }

View File

@@ -80,12 +80,11 @@ public:
// sky view // sky view
Point c = {130, 148}; Point c = {130, 148};
uint16_t r = 125; uint16_t r = 120;
uint16_t r1 = r / 2; uint16_t r1 = r / 2;
getdisplay().fillCircle(c.x, c.y, r, commonData->bgcolor); getdisplay().fillCircle(c.x, c.y, r + 2, commonData->fgcolor);
getdisplay().drawCircle(c.x, c.y, r + 1, commonData->fgcolor); getdisplay().fillCircle(c.x, c.y, r - 1, commonData->bgcolor);
getdisplay().drawCircle(c.x, c.y, r + 2, commonData->fgcolor);
getdisplay().drawCircle(c.x, c.y, r1, commonData->fgcolor); getdisplay().drawCircle(c.x, c.y, r1, commonData->fgcolor);
// separation lines // separation lines
@@ -107,36 +106,36 @@ public:
getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().getTextBounds("N", 0, 150, &x1, &y1, &w, &h); getdisplay().getTextBounds("N", 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(c.x - w / 2, c.y - r + h + 2); getdisplay().setCursor(c.x - w / 2, c.y - r + h + 3);
getdisplay().print("N"); getdisplay().print("N");
getdisplay().getTextBounds("S", 0, 150, &x1, &y1, &w, &h); getdisplay().getTextBounds("S", 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(c.x - w / 2, c.y + r - 2); getdisplay().setCursor(c.x - w / 2, c.y + r - 3);
getdisplay().print("S"); getdisplay().print("S");
getdisplay().getTextBounds("E", 0, 150, &x1, &y1, &w, &h); getdisplay().getTextBounds("E", 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(c.x + r - w - 2, c.y + h / 2); getdisplay().setCursor(c.x + r - w - 3, c.y + h / 2);
getdisplay().print("E"); getdisplay().print("E");
getdisplay().getTextBounds("W", 0, 150, &x1, &y1, &w, &h); getdisplay().getTextBounds("W", 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(c.x - r + 2 , c.y + h / 2); getdisplay().setCursor(c.x - r + 3 , c.y + h / 2);
getdisplay().print("W"); getdisplay().print("W");
getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setFont(&Ubuntu_Bold8pt8b);
// show satellites in "map" // show satellites in "map"
for (int i = 0; i < nSat; i++) { for (int i = 0; i < nSat; i++) {
float arad = sats[i].Azimut * M_PI / 180.0; float arad = (sats[i].Azimut * M_PI / 180.0) + M_PI;
float erad = sats[i].Elevation * M_PI / 180.0; float erad = sats[i].Elevation * M_PI / 180.0;
uint16_t x = c.x + sin(arad) * erad * r; uint16_t x = c.x + sin(arad) * erad * r1;
uint16_t y = c.y + cos(arad) * erad * r; uint16_t y = c.y + cos(arad) * erad * r1;
getdisplay().drawRect(x-4, y-4, 8, 8, commonData->fgcolor); getdisplay().fillRect(x-4, y-4, 8, 8, commonData->fgcolor);
} }
// Signal / Noise bars // Signal / Noise bars
getdisplay().setCursor(325, 34); getdisplay().setCursor(325, 34);
getdisplay().print("SNR"); getdisplay().print("SNR");
getdisplay().drawRect(270, 20, 125, 257, commonData->fgcolor); // getdisplay().drawRect(270, 20, 125, 257, commonData->fgcolor);
int maxsat = std::min(nSat, 12); int maxsat = std::min(nSat, 12);
for (int i = 0; i < maxsat; i++) { for (int i = 0; i < maxsat; i++) {
uint16_t y = 29 + (i + 1) * 20; uint16_t y = 29 + (i + 1) * 20;
@@ -155,6 +154,28 @@ public:
} }
} }
// Show SatInfo and HDOP
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(220, 34);
getdisplay().print("Sat:");
GwApi::BoatValue *bv_satinfo = pageData.values[0]; // SatInfo
String sval_satinfo = formatValue(bv_satinfo, *commonData).svalue;
getdisplay().setCursor(220, 49);
getdisplay().print(sval_satinfo);
getdisplay().setCursor(220, 254);
getdisplay().print("HDOP:");
GwApi::BoatValue *bv_hdop = pageData.values[1]; // HDOP
double hdop = formatValue(bv_hdop, *commonData).value * 4; // 4 is factor for UERE (translation in meter)
char sval_hdop[20];
dtostrf(hdop, 0, 1, sval_hdop); // Only one prefix
strcat(sval_hdop, "m");
getdisplay().setCursor(220, 269);
getdisplay().print(sval_hdop);
return PAGE_UPDATE; return PAGE_UPDATE;
}; };
}; };
@@ -174,6 +195,7 @@ PageDescription registerPageSkyView(
"SkyView", // Page name "SkyView", // 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
{"SatInfo", "HDOP"}, // Bus values we need in the page
true // Show display header on/off true // Show display header on/off
); );

View File

@@ -84,7 +84,7 @@ class PageWindPlot : public Page {
bool oldShowTruW = false; // remember recent user selection of wind data type bool oldShowTruW = false; // remember recent user selection of wind data type
int dataIntv = 1; // Update interval for wind history chart: int dataIntv = 1; // Update interval for wind history chart:
// (1)|(2)|(3)|(4) seconds for approx. 4, 8, 12, 16 min. history chart // (1)|(2)|(3)|(4)|(8) x 240 seconds for 4, 8, 12, 16, 32 min. history chart
bool useSimuData; bool useSimuData;
String flashLED; String flashLED;
String backlightMode; String backlightMode;
@@ -147,6 +147,8 @@ public:
dataIntv = 3; dataIntv = 3;
} else if (dataIntv == 3) { } else if (dataIntv == 3) {
dataIntv = 4; dataIntv = 4;
} else if (dataIntv == 4) {
dataIntv = 8;
} else { } else {
dataIntv = 1; dataIntv = 1;
} }
@@ -205,7 +207,7 @@ public:
static int xCenter; // Center of screen in x direction static int xCenter; // Center of screen in x direction
static const int yOffset = 48; // Offset for y coordinates of chart area static const int yOffset = 48; // Offset for y coordinates of chart area
static int cHeight; // height 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 bufSize; // History buffer size: 1.920 values for 32 min. history chart
static int intvBufSize; // Buffer size used for currently selected time interval static int intvBufSize; // Buffer size used for currently selected time interval
int count; // current size of buffer int count; // current size of buffer
static int numWndVals; // number of wind values available for current interval selection static int numWndVals; // number of wind values available for current interval selection
@@ -287,7 +289,7 @@ public:
currIdx = wdHstry->getLastIdx(); currIdx = wdHstry->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 || count == 1) { if (dataIntv != oldDataIntv || count == 1) {
// new data interval selected by user // new data interval selected by user; this is only x * 230 values instead of 240 seconds (4 minutes) per interval step
intvBufSize = cHeight * dataIntv; intvBufSize = cHeight * dataIntv;
numWndVals = min(count, (cHeight - 60) * dataIntv); numWndVals = min(count, (cHeight - 60) * dataIntv);
bufStart = max(0, count - numWndVals); bufStart = max(0, count - numWndVals);
@@ -300,7 +302,8 @@ public:
bufStart = max(0, bufStart - numAddedBufVals); bufStart = max(0, bufStart - numAddedBufVals);
} }
} }
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Dataset: count: %d, xWD: %.1f, xWS: %.2f, xWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, wind source: %s", // LOG_DEBUG(GwLog::DEBUG,"PSRAM Size: %d kByte; free: %d Byte", ESP.getPsramSize()/1024, ESP.getFreePsram());
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Dataset: count: %d, xWD: %.1f, xWS: %.2f, xWD_valid? %d, intvBufSize: %d, numWndVals: %d, bufStart: %d, numAddedBufVals: %d, lastIdx: %d, wind source: %s",
count, wdHstry->getLast() / 1000.0 * radToDeg, wsHstry->getLast() / 1000.0 * 1.94384, BDataValid[0], intvBufSize, numWndVals, bufStart, numAddedBufVals, wdHstry->getLastIdx(), count, wdHstry->getLast() / 1000.0 * radToDeg, wsHstry->getLast() / 1000.0 * 1.94384, BDataValid[0], intvBufSize, numWndVals, bufStart, numAddedBufVals, wdHstry->getLastIdx(),
showTruW ? "True" : "App"); showTruW ? "True" : "App");
@@ -502,14 +505,14 @@ public:
} }
getdisplay().printf("%3d", chrtLbl); // Wind value label getdisplay().printf("%3d", chrtLbl); // Wind value label
} }
} else if (chrtMode == 'S') { /* } else if (chrtMode == 'S') {
wsValue = wsHstry->getLast(); wsValue = wsHstry->getLast();
Chart twsChart(wsHstry, wsBVal, 0, 0, dataIntv, dfltRng, logger); Chart twsChart(wsHstry, wsBVal, 0, 0, dataIntv, dfltRng, logger);
twsChart.drawChrtHdr(); twsChart.drawChrtHdr();
twsChart.drawChrtGrd(40); twsChart.drawChrtGrd(40);
} else if (chrtMode == 'B') { } else if (chrtMode == 'B') {
} } */
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot time: %ld", millis() - timer); LOG_DEBUG(GwLog::DEBUG, "PageWindPlot time: %ld", millis() - timer);
return PAGE_UPDATE; return PAGE_UPDATE;

View File

@@ -431,7 +431,7 @@ void OBP60Task(GwApi *api){
int lastPage=pageNumber; int lastPage=pageNumber;
BoatValueList boatValues; //all the boat values for the api query BoatValueList boatValues; //all the boat values for the api query
HstryBuf hstryBufList(960); // Create ring buffers for history storage of some boat data HstryBuf hstryBufList(1920); // Create ring buffers for history storage of some boat data (1920 seconds = 32 minutes)
WindUtils trueWind(&boatValues); // Create helper object for true wind calculation WindUtils trueWind(&boatValues); // Create helper object for true wind calculation
//commonData.distanceformat=config->getString(xxx); //commonData.distanceformat=config->getString(xxx);
//add all necessary data to common data //add all necessary data to common data
@@ -710,8 +710,8 @@ void OBP60Task(GwApi *api){
} }
} }
// Full display update afer a new selected page and 4s wait time // Full display update afer a new selected page and 8s wait time
if(millis() > starttime4 + 4000 && delayedDisplayUpdate == true){ if(millis() > starttime4 + 8000 && delayedDisplayUpdate == true){
starttime1 = millis(); starttime1 = millis();
starttime2 = millis(); starttime2 = millis();
getdisplay().setFullWindow(); // Set full update getdisplay().setFullWindow(); // Set full update