mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2025-12-28 13:13:07 +01:00
Compare commits
10 Commits
tracker
...
f46a43d7fd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f46a43d7fd | ||
| 84e99365f7 | |||
|
|
d0076f336d | ||
|
|
d94c4bbbdb | ||
|
|
6ef7681a40 | ||
|
|
34a289048f | ||
|
|
df1bd498ae | ||
|
|
de448974d9 | ||
|
|
6b91400cfc | ||
|
|
1abcb158ec |
@@ -39,12 +39,13 @@ public:
|
||||
HstryBuf(){
|
||||
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry}; // Generate history buffers of zero size
|
||||
};
|
||||
|
||||
HstryBuf(int size) {
|
||||
hstryBufList = {&twdHstry, &twsHstry, &awdHstry, &awsHstry};
|
||||
hstryBufList.twdHstry->resize(960); // store 960 TWD values for 16 minutes history
|
||||
hstryBufList.twsHstry->resize(960);
|
||||
hstryBufList.awdHstry->resize(960);
|
||||
hstryBufList.awsHstry->resize(960);
|
||||
hstryBufList.twdHstry->resize(size); // store <size> xWD values for <size>/60 minutes history
|
||||
hstryBufList.twsHstry->resize(size);
|
||||
hstryBufList.awdHstry->resize(size);
|
||||
hstryBufList.awsHstry->resize(size);
|
||||
};
|
||||
void init(BoatValueList* boatValues, GwLog *log);
|
||||
void handleHstryBuf(bool useSimuData);
|
||||
|
||||
@@ -1,15 +1,48 @@
|
||||
#pragma once
|
||||
#include "GwSynchronized.h"
|
||||
#include "WString.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#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>
|
||||
class RingBuffer {
|
||||
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 head; // Points to the next insertion position
|
||||
size_t first; // Points to the first (oldest) valid element
|
||||
|
||||
@@ -35,6 +35,8 @@ RingBuffer<T>::RingBuffer(size_t size)
|
||||
, is_Full(false)
|
||||
{
|
||||
initCommon();
|
||||
|
||||
buffer.reserve(size);
|
||||
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values
|
||||
}
|
||||
|
||||
@@ -405,6 +407,7 @@ void RingBuffer<T>::resize(size_t newSize)
|
||||
is_Full = false;
|
||||
|
||||
buffer.clear();
|
||||
buffer.reserve(newSize);
|
||||
buffer.resize(newSize, MAX_VAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -169,8 +169,10 @@ public:
|
||||
getdisplay().print("HDOP:");
|
||||
|
||||
GwApi::BoatValue *bv_hdop = pageData.values[1]; // HDOP
|
||||
String sval_hdop = formatValue(bv_hdop, *commonData).svalue;
|
||||
sval_hdop = sval_hdop + "m";
|
||||
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);
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class PageWindPlot : public Page {
|
||||
bool oldShowTruW = false; // remember recent user selection of wind data type
|
||||
|
||||
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;
|
||||
String flashLED;
|
||||
String backlightMode;
|
||||
@@ -147,6 +147,8 @@ public:
|
||||
dataIntv = 3;
|
||||
} else if (dataIntv == 3) {
|
||||
dataIntv = 4;
|
||||
} else if (dataIntv == 4) {
|
||||
dataIntv = 8;
|
||||
} else {
|
||||
dataIntv = 1;
|
||||
}
|
||||
@@ -204,7 +206,7 @@ public:
|
||||
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 bufSize; // History buffer size: 1.920 values for 32 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
|
||||
@@ -285,7 +287,7 @@ public:
|
||||
currIdx = wdHstry->getLastIdx();
|
||||
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
|
||||
if (dataIntv != oldDataIntv || count == 1) {
|
||||
// new data interval selected by user
|
||||
// new data interval selected by user; this is only x * 230 values instead of 240 seconds (4 minutes) per interval step
|
||||
intvBufSize = cHeight * dataIntv;
|
||||
numWndVals = min(count, (cHeight - 60) * dataIntv);
|
||||
bufStart = max(0, count - numWndVals);
|
||||
@@ -298,6 +300,7 @@ public:
|
||||
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",
|
||||
count, wdHstry->getLast() / 1000.0 * radToDeg, wsHstry->getLast() / 1000.0 * 1.94384, BDataValid[0], intvBufSize, numWndVals, bufStart, numAddedBufVals, wdHstry->getLastIdx(),
|
||||
showTruW ? "True" : "App");
|
||||
|
||||
@@ -58,6 +58,11 @@ public:
|
||||
static String unit5old = "";
|
||||
static String svalue6old = "";
|
||||
static String unit6old = "";
|
||||
static GFXfont name3font;
|
||||
static GFXfont name4font;
|
||||
static GFXfont name5font;
|
||||
static GFXfont name6font;
|
||||
|
||||
|
||||
// Get config data
|
||||
String lengthformat = config->getString(config->lengthFormat);
|
||||
@@ -114,6 +119,12 @@ public:
|
||||
GwApi::BoatValue *bvalue3 = pageData.values[0];
|
||||
String name3 = xdrDelete(bvalue3->getName()); // 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
|
||||
double value3 = bvalue3->value; // Value as double in SI unit
|
||||
bool valid3 = bvalue3->valid; // Valid information
|
||||
@@ -128,6 +139,12 @@ public:
|
||||
GwApi::BoatValue *bvalue4 = pageData.values[1];
|
||||
String name4 = xdrDelete(bvalue4->getName()); // 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
|
||||
double value4 = bvalue4->value; // Value as double in SI unit
|
||||
bool valid4 = bvalue4->valid; // Valid information
|
||||
@@ -142,6 +159,12 @@ public:
|
||||
GwApi::BoatValue *bvalue5 = pageData.values[2];
|
||||
String name5 = xdrDelete(bvalue5->getName()); // 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
|
||||
double value5 = bvalue5->value; // Value as double in SI unit
|
||||
bool valid5 = bvalue5->valid; // Valid information
|
||||
@@ -152,10 +175,16 @@ public:
|
||||
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];
|
||||
String name6 = xdrDelete(bvalue6->getName()); // 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
|
||||
double value6 = bvalue6->value; // Value as double in SI unit
|
||||
bool valid6 = bvalue6->valid; // Valid information
|
||||
@@ -209,7 +238,7 @@ public:
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 270);
|
||||
getdisplay().print(svalue3); // Value
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setFont(&name3font);
|
||||
getdisplay().setCursor(10, 220);
|
||||
getdisplay().print(name3); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
@@ -225,17 +254,12 @@ public:
|
||||
// Show value 4 (=second user-configured parameter) at top right
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 65);
|
||||
if(valid3 == true){
|
||||
getdisplay().print(svalue4); // Value
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Value
|
||||
}
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(335, 95);
|
||||
getdisplay().print(svalue4); // Value
|
||||
getdisplay().setFont(&name4font);
|
||||
getdisplay().setCursor(325, 95);
|
||||
getdisplay().print(name4); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(335, 115);
|
||||
getdisplay().setCursor(325, 115);
|
||||
getdisplay().print(" ");
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit4); // Unit
|
||||
@@ -251,11 +275,11 @@ public:
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 270);
|
||||
getdisplay().print(svalue5); // Value
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(335, 220);
|
||||
getdisplay().setFont(&name5font);
|
||||
getdisplay().setCursor(325, 220);
|
||||
getdisplay().print(name5); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(335, 190);
|
||||
getdisplay().setCursor(325, 190);
|
||||
getdisplay().print(" ");
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit5); // Unit
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,7 @@ import getopt
|
||||
import re
|
||||
import json
|
||||
|
||||
__version__ = "0.2"
|
||||
__version__ = "0.3"
|
||||
|
||||
def detect_pages(filename):
|
||||
# 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 = []
|
||||
|
||||
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 = {
|
||||
"name": f"page{page_no}type",
|
||||
"label": "Type",
|
||||
@@ -94,9 +99,11 @@ def create_json(device, no_of_pages, pagedata):
|
||||
"default": get_default_page(page_no),
|
||||
"description": f"Type of page for page {page_no}",
|
||||
"list": pages,
|
||||
"category": f"{device.upper()} Page {page_no}",
|
||||
"category": category,
|
||||
"capabilities": {device.lower(): "true"},
|
||||
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
|
||||
"condition": {
|
||||
"visiblePages": visiblepages
|
||||
},
|
||||
#"fields": [],
|
||||
}
|
||||
output.append(page_data)
|
||||
@@ -108,39 +115,59 @@ def create_json(device, no_of_pages, pagedata):
|
||||
"type": "boatData",
|
||||
"default": "",
|
||||
"description": "The display for field {}".format(number_to_text(field_no)),
|
||||
"category": f"{device.upper()} Page {page_no}",
|
||||
"capabilities": {device.lower(): "true"},
|
||||
"condition": [
|
||||
{f"page{page_no}type": page}
|
||||
for page in pages
|
||||
if pagedata[page] >= field_no
|
||||
],
|
||||
"category": category,
|
||||
"capabilities": capabilities,
|
||||
"condition": {
|
||||
f"page{page_no}type": [ p for p in pages if pagedata[p] >= field_no ]
|
||||
,"visiblePages": visiblepages
|
||||
}
|
||||
}
|
||||
output.append(field_data)
|
||||
|
||||
fluid_data ={
|
||||
fluid_data = {
|
||||
"name": f"page{page_no}fluid",
|
||||
"label": "Fluid type",
|
||||
"type": "list",
|
||||
"default": "0",
|
||||
"list": [
|
||||
{"l":"Fuel (0)","v":"0"},
|
||||
{"l":"Water (1)","v":"1"},
|
||||
{"l":"Gray Water (2)","v":"2"},
|
||||
{"l":"Live Well (3)","v":"3"},
|
||||
{"l":"Oil (4)","v":"4"},
|
||||
{"l":"Black Water (5)","v":"5"},
|
||||
{"l":"Fuel Gasoline (6)","v":"6"}
|
||||
{"l":"Fuel (0)","v":"0"},
|
||||
{"l":"Water (1)","v":"1"},
|
||||
{"l":"Gray Water (2)","v":"2"},
|
||||
{"l":"Live Well (3)","v":"3"},
|
||||
{"l":"Oil (4)","v":"4"},
|
||||
{"l":"Black Water (5)","v":"5"},
|
||||
{"l":"Fuel Gasoline (6)","v":"6"}
|
||||
],
|
||||
"description": "Fluid type in tank",
|
||||
"category": f"{device.upper()} Page {page_no}",
|
||||
"capabilities": {
|
||||
device.lower(): "true"
|
||||
},
|
||||
"condition":[{f"page{page_no}type":"Fluid"}]
|
||||
"category": category,
|
||||
"capabilities": capabilities,
|
||||
"condition": {
|
||||
f"page{page_no}type": "Fluid",
|
||||
"visiblePages": visiblepages
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
||||
def usage():
|
||||
|
||||
@@ -431,7 +431,7 @@ void OBP60Task(GwApi *api){
|
||||
int lastPage=pageNumber;
|
||||
|
||||
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
|
||||
//commonData.distanceformat=config->getString(xxx);
|
||||
//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
|
||||
if(millis() > starttime4 + 4000 && delayedDisplayUpdate == true){
|
||||
// Full display update afer a new selected page and 8s wait time
|
||||
if(millis() > starttime4 + 8000 && delayedDisplayUpdate == true){
|
||||
starttime1 = millis();
|
||||
starttime2 = millis();
|
||||
getdisplay().setFullWindow(); // Set full update
|
||||
|
||||
Reference in New Issue
Block a user