Implement v1 history data storage at OBPSensorTask
This commit is contained in:
parent
1f90cefbd6
commit
2729ef9cb6
|
@ -4,5 +4,6 @@
|
||||||
"stdexcept": "cpp",
|
"stdexcept": "cpp",
|
||||||
"limits": "cpp",
|
"limits": "cpp",
|
||||||
"functional": "cpp"
|
"functional": "cpp"
|
||||||
}
|
},
|
||||||
|
"github.copilot.nextEditSuggestions.enabled": false
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "WString.h"
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class RingBuffer {
|
class RingBuffer {
|
||||||
|
@ -18,12 +19,16 @@ private:
|
||||||
T MAX_VAL; // highest possible value of buffer of type <T>
|
T MAX_VAL; // highest possible value of buffer of type <T>
|
||||||
|
|
||||||
// metadata for buffer
|
// 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
|
int updFreq; // Update frequency in milliseconds
|
||||||
int smallest; // Value range of buffer: smallest value
|
int smallest; // Value range of buffer: smallest value
|
||||||
int biggest; // Value range of buffer: biggest value
|
int largest; // Value range of buffer: biggest value
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RingBuffer(size_t size);
|
RingBuffer(size_t size);
|
||||||
|
void setMetaData(String name, String format, int updateFrequency, int minValue, int maxValue); // Set meta data for buffer
|
||||||
|
bool getMetaData(String& name, String& format, int& updateFrequency, int& minValue, int& maxValue); // Get meta data of buffer
|
||||||
void add(const T& value); // Add a new value to buffer
|
void add(const T& value); // Add a new value to buffer
|
||||||
T get(size_t index) const; // Get value at specific position (0-based index from oldest to newest)
|
T get(size_t index) const; // Get value at specific position (0-based index from oldest to newest)
|
||||||
T getFirst() const; // Get the first (oldest) value in buffer
|
T getFirst() const; // Get the first (oldest) value in buffer
|
||||||
|
@ -39,12 +44,13 @@ public:
|
||||||
T getMedian(size_t amount) const; // Get the median value of the last <amount> values of 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 getCapacity() const; // Get the buffer capacity (maximum size)
|
||||||
size_t getCurrentSize() const; // Get the current number of elements in buffer
|
size_t getCurrentSize() const; // Get the current number of elements in buffer
|
||||||
|
size_t getLastIdx() const; // Get the last index of buffer
|
||||||
bool isEmpty() const; // Check if buffer is empty
|
bool isEmpty() const; // Check if buffer is empty
|
||||||
bool isFull() const; // Check if buffer is full
|
bool isFull() const; // Check if buffer is full
|
||||||
T getMinVal(); // Get lowest possible value for buffer; used for initialized buffer data
|
T getMinVal() const; // Get lowest possible value for buffer; used for initialized buffer data
|
||||||
T getMaxVal(); // Get highest possible value for buffer
|
T getMaxVal() const; // Get highest possible value for buffer
|
||||||
void clear(); // Clear buffer
|
void clear(); // Clear buffer
|
||||||
T operator[](size_t index) const;
|
T operator[](size_t index);
|
||||||
std::vector<T> getAllValues() const; // Operator[] for convenient access (same as get())
|
std::vector<T> getAllValues() const; // Operator[] for convenient access (same as get())
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,15 +15,50 @@ RingBuffer<T>::RingBuffer(size_t size)
|
||||||
|
|
||||||
MIN_VAL = std::numeric_limits<T>::lowest();
|
MIN_VAL = std::numeric_limits<T>::lowest();
|
||||||
MAX_VAL = std::numeric_limits<T>::max();
|
MAX_VAL = std::numeric_limits<T>::max();
|
||||||
|
dataName = "";
|
||||||
|
dataFmt = "";
|
||||||
|
updFreq = MIN_VAL;
|
||||||
|
smallest = MIN_VAL;
|
||||||
|
largest = MAX_VAL;
|
||||||
buffer.resize(size, MIN_VAL);
|
buffer.resize(size, MIN_VAL);
|
||||||
|
|
||||||
// return true;
|
// return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new value to the buffer
|
// Specify meta data of buffer content
|
||||||
|
template <typename T>
|
||||||
|
void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency, int minValue, int maxValue)
|
||||||
|
{
|
||||||
|
dataName = name;
|
||||||
|
dataFmt = format;
|
||||||
|
updFreq = updateFrequency;
|
||||||
|
smallest = minValue;
|
||||||
|
largest = maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get meta data of buffer content
|
||||||
|
template <typename T>
|
||||||
|
bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequency, int& minValue, int& maxValue)
|
||||||
|
{
|
||||||
|
if (updFreq == MIN_VAL || smallest == MIN_VAL || largest == MAX_VAL) {
|
||||||
|
return false; // Meta data not set
|
||||||
|
}
|
||||||
|
|
||||||
|
name = dataName;
|
||||||
|
format = dataFmt;
|
||||||
|
updFreq = updFreq;
|
||||||
|
smallest = smallest;
|
||||||
|
largest = largest;
|
||||||
|
return true; // Meta data successfully retrieved
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new value to buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void RingBuffer<T>::add(const T& value)
|
void RingBuffer<T>::add(const T& value)
|
||||||
{
|
{
|
||||||
|
if (value < smallest || value > largest) {
|
||||||
|
buffer[head] = MIN_VAL; // Store MIN_VAL if value is out of range
|
||||||
|
}
|
||||||
buffer[head] = value;
|
buffer[head] = value;
|
||||||
last = head;
|
last = head;
|
||||||
|
|
||||||
|
@ -48,7 +83,7 @@ T RingBuffer<T>::get(size_t index) const
|
||||||
}
|
}
|
||||||
if (index < 0 || index >= count) {
|
if (index < 0 || index >= count) {
|
||||||
return MIN_VAL;
|
return MIN_VAL;
|
||||||
// throw std::out_of_range("Index out of range");
|
// throw std::out_of_range("Index out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t realIndex = (first + index) % capacity;
|
size_t realIndex = (first + index) % capacity;
|
||||||
|
@ -57,7 +92,7 @@ T RingBuffer<T>::get(size_t index) const
|
||||||
|
|
||||||
// Operator[] for convenient access (same as get())
|
// Operator[] for convenient access (same as get())
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::operator[](size_t index) const
|
T RingBuffer<T>::operator[](size_t index)
|
||||||
{
|
{
|
||||||
return get(index);
|
return get(index);
|
||||||
}
|
}
|
||||||
|
@ -302,6 +337,13 @@ size_t RingBuffer<T>::getCurrentSize() const
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the last index of buffer
|
||||||
|
template <typename T>
|
||||||
|
size_t RingBuffer<T>::getLastIdx() const
|
||||||
|
{
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if buffer is empty
|
// Check if buffer is empty
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool RingBuffer<T>::isEmpty() const
|
bool RingBuffer<T>::isEmpty() const
|
||||||
|
@ -318,14 +360,14 @@ bool RingBuffer<T>::isFull() const
|
||||||
|
|
||||||
// Get lowest possible value for buffer; used for initialized buffer data
|
// Get lowest possible value for buffer; used for initialized buffer data
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMinVal()
|
T RingBuffer<T>::getMinVal() const
|
||||||
{
|
{
|
||||||
return MIN_VAL;
|
return MIN_VAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get highest possible value for buffer
|
// Get highest possible value for buffer
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T RingBuffer<T>::getMaxVal()
|
T RingBuffer<T>::getMaxVal() const
|
||||||
{
|
{
|
||||||
return MAX_VAL;
|
return MAX_VAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,12 @@ void sensorTask(void *param){
|
||||||
batV.begin();
|
batV.begin();
|
||||||
batC.begin();
|
batC.begin();
|
||||||
|
|
||||||
|
// Create ring buffers for history storage of some boat data
|
||||||
|
// later read data types from config and specify buffers accordingly
|
||||||
|
RingBuffer<int16_t> twdHstry(960); // Circular buffer to store wind direction values; store 960 TWD values for 16 minutes history
|
||||||
|
RingBuffer<int16_t> twsHstry(960); // Circular buffer to store wind speed values (TWS)
|
||||||
|
RingBuffer<int16_t> dbtHstry(960); // Circular buffer to store water depth values (DBT)
|
||||||
|
|
||||||
// Start timer
|
// Start timer
|
||||||
Timer1.start(); // Start Timer1 for blinking LED
|
Timer1.start(); // Start Timer1 for blinking LED
|
||||||
|
|
||||||
|
@ -361,6 +367,7 @@ void sensorTask(void *param){
|
||||||
long starttime11 = millis(); // Copy GPS data to RTC all 5min
|
long starttime11 = millis(); // Copy GPS data to RTC all 5min
|
||||||
long starttime12 = millis(); // Get RTC data all 500ms
|
long starttime12 = millis(); // Get RTC data all 500ms
|
||||||
long starttime13 = millis(); // Get 1Wire sensor data all 2s
|
long starttime13 = millis(); // Get 1Wire sensor data all 2s
|
||||||
|
unsigned long starttime20 = millis(); // Get TWD and TWS data every 1000ms
|
||||||
|
|
||||||
tN2kMsg N2kMsg;
|
tN2kMsg N2kMsg;
|
||||||
shared->setSensorData(sensors); //set initially read values
|
shared->setSensorData(sensors); //set initially read values
|
||||||
|
@ -370,6 +377,21 @@ void sensorTask(void *param){
|
||||||
GwApi::BoatValue *hdop=new GwApi::BoatValue(GwBoatData::_HDOP);
|
GwApi::BoatValue *hdop=new GwApi::BoatValue(GwBoatData::_HDOP);
|
||||||
GwApi::BoatValue *valueList[]={gpsdays, gpsseconds, hdop};
|
GwApi::BoatValue *valueList[]={gpsdays, gpsseconds, hdop};
|
||||||
|
|
||||||
|
// Prepare boat data values for history storage
|
||||||
|
// later read data types from config and specify hstryvalList accordingly
|
||||||
|
GwApi::BoatValue *twdBVal=new GwApi::BoatValue(GwBoatData::_TWD);
|
||||||
|
GwApi::BoatValue *twsBVal=new GwApi::BoatValue(GwBoatData::_TWS);
|
||||||
|
GwApi::BoatValue *dbtBVal=new GwApi::BoatValue(GwBoatData::_DBT);
|
||||||
|
GwApi::BoatValue *hstryValList[]={twdBVal, twsBVal, dbtBVal}; // List of boat values for history storage
|
||||||
|
int twdHstryMin = 0;
|
||||||
|
int twsHstryMin = 0;
|
||||||
|
int dbtHstryMin = 0;
|
||||||
|
// Initialize history buffers with meta data
|
||||||
|
api->getBoatDataValues(3,hstryValList);
|
||||||
|
twdHstry.setMetaData(twdBVal->getName(), twdBVal->getFormat(), 1000, twdHstryMin, 360); // Set meta data for TWD buffer: update frequency 1000ms, min value 0, max value 360
|
||||||
|
twsHstry.setMetaData(twsBVal->getName(), twsBVal->getFormat(), 1000, twsHstryMin, 100); // Set meta data for TWS buffer: update frequency 1000ms, min value 0, max value 100
|
||||||
|
dbtHstry.setMetaData(dbtBVal->getName(), dbtBVal->getFormat(), 1000, dbtHstryMin, 10928); // Set meta data for TWS buffer: update frequency 1000ms, min value 0, max value 10,928
|
||||||
|
|
||||||
// Internal RTC with NTP init
|
// Internal RTC with NTP init
|
||||||
ESP32Time rtc(0);
|
ESP32Time rtc(0);
|
||||||
if (api->getConfig()->getString(api->getConfig()->timeSource) == "iRTC") {
|
if (api->getConfig()->getString(api->getConfig()->timeSource) == "iRTC") {
|
||||||
|
@ -775,6 +797,39 @@ void sensorTask(void *param){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read TWD, TWS, DBT data from boatData every 1000ms for history and windplot display
|
||||||
|
if(millis() > starttime20 + 1000){
|
||||||
|
starttime20 = millis();
|
||||||
|
api->getBoatDataValues(3,hstryValList);
|
||||||
|
int16_t bValue;
|
||||||
|
if (twdBVal->valid) {
|
||||||
|
bValue = int16_t(RadToDeg(twdBVal->value));
|
||||||
|
twdHstry.add(bValue);
|
||||||
|
} else {
|
||||||
|
twdHstry.add(INT16_MIN); // Add invalid value
|
||||||
|
}
|
||||||
|
if (twsBVal->valid) {
|
||||||
|
bValue = int16_t(twsBVal->value);
|
||||||
|
twsHstry.add(bValue);
|
||||||
|
} else {
|
||||||
|
twsHstry.add(INT16_MIN); // Add invalid value
|
||||||
|
}
|
||||||
|
if (dbtBVal->valid) {
|
||||||
|
bValue = int16_t(dbtBVal->value);
|
||||||
|
dbtHstry.add(bValue);
|
||||||
|
} else {
|
||||||
|
dbtHstry.add(INT16_MIN); // Add invalid value
|
||||||
|
}
|
||||||
|
String TmpName;
|
||||||
|
String TmpFormat;
|
||||||
|
int TmpUpdFreq;
|
||||||
|
int TmpSmallest;
|
||||||
|
int TmpBiggest;
|
||||||
|
twdHstry.getMetaData(TmpName, TmpFormat, TmpUpdFreq, TmpSmallest, TmpBiggest);
|
||||||
|
api->getLogger()->logDebug(GwLog::ERROR,"History buffer TWD: name:%s format:%s Freq:%d, Min: %d, Max: %d", TmpName.c_str(), TmpFormat.c_str(), TmpUpdFreq, TmpSmallest, TmpBiggest);
|
||||||
|
api->getLogger()->logDebug(GwLog::ERROR,"History buffers: TWD:%d TWS:%d DBT:%d", twdHstry.getLast(), twsHstry.getLast(), dbtHstry.getLast());
|
||||||
|
}
|
||||||
|
|
||||||
shared->setSensorData(sensors);
|
shared->setSensorData(sensors);
|
||||||
}
|
}
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
#include "BoatDataCalibration.h"
|
#include "BoatDataCalibration.h"
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "Pagedata.h"
|
|
||||||
#include "OBPRingBuffer.h"
|
#include "OBPRingBuffer.h"
|
||||||
|
#include "Pagedata.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -201,12 +201,44 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 + capacity - i) % capacity);
|
||||||
|
if (value == minVal) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rng = abs(((value - center + 540) % 360) - 180);
|
||||||
|
if (rng > maxRng)
|
||||||
|
maxRng = rng;
|
||||||
|
}
|
||||||
|
if (maxRng > 180) {
|
||||||
|
maxRng = 180;
|
||||||
|
}
|
||||||
|
return maxRng;
|
||||||
|
}
|
||||||
|
|
||||||
// ****************************************************************
|
// ****************************************************************
|
||||||
class PageWindPlot : public Page {
|
class PageWindPlot : public Page {
|
||||||
|
|
||||||
bool keylock = false; // Keylock
|
bool keylock = false; // Keylock
|
||||||
// int16_t lp = 80; // Pointer length
|
char chrtMode = 'D'; // Chart mode: 'D' for TWD, 'S' for TWS, 'B' for both
|
||||||
char chrtMode = 'D'; // Chart mode: 'D' for TWD, 'S' for TWS, 'B' for both06121990
|
|
||||||
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) seconds for approx. 4, 8, 12, 16 min. history chart
|
||||||
bool showTWS = true; // Show TWS value in chart area
|
bool showTWS = true; // Show TWS value in chart area
|
||||||
|
@ -323,18 +355,18 @@ public:
|
||||||
int distVals; // helper to check wndCenter crossing
|
int distVals; // helper to check wndCenter crossing
|
||||||
int distMid; // helper to check wndCenter crossing
|
int distMid; // helper to check wndCenter crossing
|
||||||
|
|
||||||
static RingBuffer<int> windDirHstry(bufSize); // Circular buffer to store wind direction values
|
static RingBuffer<int16_t> windDirHstry(bufSize); // Circular buffer to store wind direction values
|
||||||
static RingBuffer<int>windSpdHstry(bufSize); // Circular buffer to store wind speed values
|
static RingBuffer<int16_t> windSpdHstry(bufSize); // Circular buffer to store wind speed values
|
||||||
|
|
||||||
LOG_DEBUG(GwLog::LOG, "Display page WindPlot");
|
LOG_DEBUG(GwLog::LOG, "Display page WindPlot");
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
|
|
||||||
// Data initialization
|
// Data initialization
|
||||||
if (windDirHstry.getCurrentSize() == 0) {
|
if (windDirHstry.getCurrentSize() == 0) {
|
||||||
/* if (!windDirHstry.begin(bufSize)) {
|
/* if (!windDirHstry.begin(bufSize)) {
|
||||||
logger->logDebug(GwLog::ERROR, "Failed to initialize wind direction history buffer");
|
logger->logDebug(GwLog::ERROR, "Failed to initialize wind direction history buffer");
|
||||||
return;
|
return;
|
||||||
} */
|
} */
|
||||||
simWnd = 0;
|
simWnd = 0;
|
||||||
simTWS = 0;
|
simTWS = 0;
|
||||||
twdValue = 0;
|
twdValue = 0;
|
||||||
|
@ -420,13 +452,13 @@ public:
|
||||||
|
|
||||||
// initialize chart range values
|
// initialize chart range values
|
||||||
if (wndCenter == INT_MIN) {
|
if (wndCenter == INT_MIN) {
|
||||||
wndCenter = max(0, windDirHstry.get(numWndValues - intvBufSize)); // get 1st value of current data interval
|
wndCenter = max(0, int(windDirHstry.get(numWndValues - intvBufSize))); // get 1st value of current data interval
|
||||||
wndCenter = (int((wndCenter + (wndCenter >= 0 ? 5 : -5)) / 10) * 10) % 360; // Set new center value; round to nearest 10 degree value; 360° -> 0°
|
wndCenter = (int((wndCenter + (wndCenter >= 0 ? 5 : -5)) / 10) * 10) % 360; // Set new center value; round to nearest 10 degree value; 360° -> 0°
|
||||||
diffRng = dfltRng;
|
diffRng = dfltRng;
|
||||||
chrtRng = dfltRng;
|
chrtRng = dfltRng;
|
||||||
} else {
|
} else {
|
||||||
// check and adjust range between left, center, and right chart limit
|
// check and adjust range between left, center, and right chart limit
|
||||||
diffRng = windDirHstry.getRng(wndCenter, numWndValues);
|
diffRng = getRng(windDirHstry, wndCenter, numWndValues);
|
||||||
diffRng = (diffRng == INT_MIN ? 0 : diffRng);
|
diffRng = (diffRng == INT_MIN ? 0 : diffRng);
|
||||||
if (diffRng > chrtRng) {
|
if (diffRng > chrtRng) {
|
||||||
chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 degree value
|
chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 degree value
|
||||||
|
|
Loading…
Reference in New Issue