1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-28 13:13:07 +01:00

10 Commits

Author SHA1 Message Date
Norbert Walter
f46a43d7fd Merge pull request #207 from thooge/configfix
Config file fixes and  generation script update
2025-10-06 10:44:58 +02:00
84e99365f7 Config file fixes and generation script update 2025-09-29 14:31:28 +02:00
Norbert Walter
d0076f336d Merge pull request #205 from TobiasE-github/master
use a smaller font on long names in WindRoseFlex
2025-09-25 23:59:28 +02:00
Tobias E
d94c4bbbdb optimize font size 2025-09-20 11:16:17 +00:00
TobiasE-github
6ef7681a40 use a smaller font on long names in WindRoseFlex 2025-09-14 21:00:02 +02:00
norbert-walter
34a289048f Fix HDOP and more delay for page refresh after new page 2025-09-10 18:48:24 +02:00
Norbert Walter
df1bd498ae Merge pull request #204 from Scorgan01/PSRAM
Data History Buffer: Moved buffers to PSRAM; extended wind buffer sizes to 1920 values
2025-09-10 18:17:00 +02:00
Scorgan01
de448974d9 Delete serial_output.txt 2025-08-27 23:21:21 +02:00
Scorgan01
6b91400cfc Merge branch 'norbert-walter:master' into PSRAM 2025-08-27 23:17:18 +02:00
Ulrich Meine
1abcb158ec Moved history buffers to PSRAM; extended buffer to 1920 values each (32 min.) 2025-08-26 23:21:36 +02:00
10 changed files with 2621 additions and 2739 deletions

View File

@@ -39,12 +39,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

@@ -169,8 +169,10 @@ public:
getdisplay().print("HDOP:"); getdisplay().print("HDOP:");
GwApi::BoatValue *bv_hdop = pageData.values[1]; // HDOP GwApi::BoatValue *bv_hdop = pageData.values[1]; // HDOP
String sval_hdop = formatValue(bv_hdop, *commonData).svalue; double hdop = formatValue(bv_hdop, *commonData).value * 4; // 4 is factor for UERE (translation in meter)
sval_hdop = sval_hdop + "m"; char sval_hdop[20];
dtostrf(hdop, 0, 1, sval_hdop); // Only one prefix
strcat(sval_hdop, "m");
getdisplay().setCursor(220, 269); getdisplay().setCursor(220, 269);
getdisplay().print(sval_hdop); getdisplay().print(sval_hdop);

View File

@@ -83,7 +83,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;
} }
@@ -204,7 +206,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
@@ -285,7 +287,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);
@@ -298,6 +300,7 @@ public:
bufStart = max(0, bufStart - numAddedBufVals); bufStart = max(0, bufStart - numAddedBufVals);
} }
} }
// 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", 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");

View File

@@ -58,6 +58,11 @@ public:
static String unit5old = ""; static String unit5old = "";
static String svalue6old = ""; static String svalue6old = "";
static String unit6old = ""; static String unit6old = "";
static GFXfont name3font;
static GFXfont name4font;
static GFXfont name5font;
static GFXfont name6font;
// Get config data // Get config data
String lengthformat = config->getString(config->lengthFormat); String lengthformat = config->getString(config->lengthFormat);
@@ -114,6 +119,12 @@ public:
GwApi::BoatValue *bvalue3 = pageData.values[0]; GwApi::BoatValue *bvalue3 = pageData.values[0];
String name3 = xdrDelete(bvalue3->getName()); // Value name String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
if (name3.length()>3){
name3font=Ubuntu_Bold8pt8b;
}
else{
name3font=Ubuntu_Bold12pt8b;
}
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
double value3 = bvalue3->value; // Value as double in SI unit double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
@@ -128,6 +139,12 @@ public:
GwApi::BoatValue *bvalue4 = pageData.values[1]; GwApi::BoatValue *bvalue4 = pageData.values[1];
String name4 = xdrDelete(bvalue4->getName()); // Value name String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name name4 = name4.substring(0, 6); // String length limit for value name
if (name4.length()>3){
name4font=Ubuntu_Bold8pt8b;
}
else{
name4font=Ubuntu_Bold12pt8b;
}
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
double value4 = bvalue4->value; // Value as double in SI unit double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information bool valid4 = bvalue4->valid; // Valid information
@@ -142,6 +159,12 @@ public:
GwApi::BoatValue *bvalue5 = pageData.values[2]; GwApi::BoatValue *bvalue5 = pageData.values[2];
String name5 = xdrDelete(bvalue5->getName()); // Value name String name5 = xdrDelete(bvalue5->getName()); // Value name
name5 = name5.substring(0, 6); // String length limit for value name name5 = name5.substring(0, 6); // String length limit for value name
if (name5.length()>3){
name5font=Ubuntu_Bold8pt8b;
}
else{
name5font=Ubuntu_Bold12pt8b;
}
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
double value5 = bvalue5->value; // Value as double in SI unit double value5 = bvalue5->value; // Value as double in SI unit
bool valid5 = bvalue5->valid; // Valid information bool valid5 = bvalue5->valid; // Valid information
@@ -152,10 +175,16 @@ public:
unit5old = unit5; // Save old unit unit5old = unit5; // Save old unit
} }
// Get boat value for center // Get boat value for center (name is not displayed)
GwApi::BoatValue *bvalue6 = pageData.values[3]; GwApi::BoatValue *bvalue6 = pageData.values[3];
String name6 = xdrDelete(bvalue6->getName()); // Value name String name6 = xdrDelete(bvalue6->getName()); // Value name
name6 = name6.substring(0, 6); // String length limit for value name name6 = name6.substring(0, 6); // String length limit for value name
if (name6.length()>3){
name6font=Ubuntu_Bold8pt8b;
}
else{
name6font=Ubuntu_Bold8pt8b;
}
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
double value6 = bvalue6->value; // Value as double in SI unit double value6 = bvalue6->value; // Value as double in SI unit
bool valid6 = bvalue6->valid; // Valid information bool valid6 = bvalue6->valid; // Valid information
@@ -209,7 +238,7 @@ public:
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 270); getdisplay().setCursor(10, 270);
getdisplay().print(svalue3); // Value getdisplay().print(svalue3); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setFont(&name3font);
getdisplay().setCursor(10, 220); getdisplay().setCursor(10, 220);
getdisplay().print(name3); // Name getdisplay().print(name3); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setFont(&Ubuntu_Bold8pt8b);
@@ -225,17 +254,12 @@ public:
// Show value 4 (=second user-configured parameter) at top right // Show value 4 (=second user-configured parameter) at top right
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 65); getdisplay().setCursor(295, 65);
if(valid3 == true){
getdisplay().print(svalue4); // Value getdisplay().print(svalue4); // Value
} getdisplay().setFont(&name4font);
else{ getdisplay().setCursor(325, 95);
getdisplay().print("---"); // Value
}
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(335, 95);
getdisplay().print(name4); // Name getdisplay().print(name4); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(335, 115); getdisplay().setCursor(325, 115);
getdisplay().print(" "); getdisplay().print(" ");
if(holdvalues == false){ if(holdvalues == false){
getdisplay().print(unit4); // Unit getdisplay().print(unit4); // Unit
@@ -251,11 +275,11 @@ public:
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 270); getdisplay().setCursor(295, 270);
getdisplay().print(svalue5); // Value getdisplay().print(svalue5); // Value
getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setFont(&name5font);
getdisplay().setCursor(335, 220); getdisplay().setCursor(325, 220);
getdisplay().print(name5); // Name getdisplay().print(name5); // Name
getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(335, 190); getdisplay().setCursor(325, 190);
getdisplay().print(" "); getdisplay().print(" ");
if(holdvalues == false){ if(holdvalues == false){
getdisplay().print(unit5); // Unit getdisplay().print(unit5); // Unit

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@ import getopt
import re import re
import json import json
__version__ = "0.2" __version__ = "0.3"
def detect_pages(filename): def detect_pages(filename):
# returns a dictionary with page name and the number of gui fields # returns a dictionary with page name and the number of gui fields
@@ -87,6 +87,11 @@ def create_json(device, no_of_pages, pagedata):
output = [] output = []
for page_no in range(1, no_of_pages + 1): for page_no in range(1, no_of_pages + 1):
category = f"{device.upper()} Page {page_no}"
capabilities = {device.lower(): "true"}
visiblepages = [str(vp) for vp in range(page_no, no_of_pages + 1)]
page_data = { page_data = {
"name": f"page{page_no}type", "name": f"page{page_no}type",
"label": "Type", "label": "Type",
@@ -94,9 +99,11 @@ def create_json(device, no_of_pages, pagedata):
"default": get_default_page(page_no), "default": get_default_page(page_no),
"description": f"Type of page for page {page_no}", "description": f"Type of page for page {page_no}",
"list": pages, "list": pages,
"category": f"{device.upper()} Page {page_no}", "category": category,
"capabilities": {device.lower(): "true"}, "capabilities": {device.lower(): "true"},
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)], "condition": {
"visiblePages": visiblepages
},
#"fields": [], #"fields": [],
} }
output.append(page_data) output.append(page_data)
@@ -108,17 +115,16 @@ def create_json(device, no_of_pages, pagedata):
"type": "boatData", "type": "boatData",
"default": "", "default": "",
"description": "The display for field {}".format(number_to_text(field_no)), "description": "The display for field {}".format(number_to_text(field_no)),
"category": f"{device.upper()} Page {page_no}", "category": category,
"capabilities": {device.lower(): "true"}, "capabilities": capabilities,
"condition": [ "condition": {
{f"page{page_no}type": page} f"page{page_no}type": [ p for p in pages if pagedata[p] >= field_no ]
for page in pages ,"visiblePages": visiblepages
if pagedata[page] >= field_no }
],
} }
output.append(field_data) output.append(field_data)
fluid_data ={ fluid_data = {
"name": f"page{page_no}fluid", "name": f"page{page_no}fluid",
"label": "Fluid type", "label": "Fluid type",
"type": "list", "type": "list",
@@ -133,14 +139,35 @@ def create_json(device, no_of_pages, pagedata):
{"l":"Fuel Gasoline (6)","v":"6"} {"l":"Fuel Gasoline (6)","v":"6"}
], ],
"description": "Fluid type in tank", "description": "Fluid type in tank",
"category": f"{device.upper()} Page {page_no}", "category": category,
"capabilities": { "capabilities": capabilities,
device.lower(): "true" "condition": {
}, f"page{page_no}type": "Fluid",
"condition":[{f"page{page_no}type":"Fluid"}] "visiblePages": visiblepages
}
} }
output.append(fluid_data) output.append(fluid_data)
if device.upper() == 'OBP40':
windsource = {
"name": f"page{page_no}wndsrc",
"label": "Wind source",
"type": "list",
"default": "True wind",
"description": f"Wind source for page {page_no}: [true|apparent]",
"list": [
"True wind",
"Apparant wind"
],
"category": category,
"capabilities": capabilities,
"condition": {
f"page{page_no}type": "WindPlot",
"visiblePages": visiblepages
}
}
output.append(windsource)
return json.dumps(output, indent=4) return json.dumps(output, indent=4)
def usage(): def usage():

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