Implement v1 history data storage at OBPSensorTask
This commit is contained in:
parent
1f90cefbd6
commit
2729ef9cb6
|
@ -4,5 +4,6 @@
|
|||
"stdexcept": "cpp",
|
||||
"limits": "cpp",
|
||||
"functional": "cpp"
|
||||
}
|
||||
},
|
||||
"github.copilot.nextEditSuggestions.enabled": false
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include "WString.h"
|
||||
|
||||
template <typename T>
|
||||
class RingBuffer {
|
||||
|
@ -18,12 +19,16 @@ private:
|
|||
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
|
||||
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:
|
||||
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
|
||||
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
|
||||
|
@ -39,12 +44,13 @@ public:
|
|||
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 getLastIdx() const; // Get the last index of buffer
|
||||
bool isEmpty() const; // Check if buffer is empty
|
||||
bool isFull() const; // Check if buffer is full
|
||||
T getMinVal(); // Get lowest possible value for buffer; used for initialized buffer data
|
||||
T getMaxVal(); // Get highest possible value for buffer
|
||||
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;
|
||||
T operator[](size_t index);
|
||||
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();
|
||||
MAX_VAL = std::numeric_limits<T>::max();
|
||||
dataName = "";
|
||||
dataFmt = "";
|
||||
updFreq = MIN_VAL;
|
||||
smallest = MIN_VAL;
|
||||
largest = MAX_VAL;
|
||||
buffer.resize(size, MIN_VAL);
|
||||
|
||||
// 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>
|
||||
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;
|
||||
last = head;
|
||||
|
||||
|
@ -57,7 +92,7 @@ T RingBuffer<T>::get(size_t index) const
|
|||
|
||||
// Operator[] for convenient access (same as get())
|
||||
template <typename T>
|
||||
T RingBuffer<T>::operator[](size_t index) const
|
||||
T RingBuffer<T>::operator[](size_t index)
|
||||
{
|
||||
return get(index);
|
||||
}
|
||||
|
@ -302,6 +337,13 @@ size_t RingBuffer<T>::getCurrentSize() const
|
|||
return count;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -318,14 +360,14 @@ bool RingBuffer<T>::isFull() const
|
|||
|
||||
// Get lowest possible value for buffer; used for initialized buffer data
|
||||
template <typename T>
|
||||
T RingBuffer<T>::getMinVal()
|
||||
T RingBuffer<T>::getMinVal() const
|
||||
{
|
||||
return MIN_VAL;
|
||||
}
|
||||
|
||||
// Get highest possible value for buffer
|
||||
template <typename T>
|
||||
T RingBuffer<T>::getMaxVal()
|
||||
T RingBuffer<T>::getMaxVal() const
|
||||
{
|
||||
return MAX_VAL;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,12 @@ void sensorTask(void *param){
|
|||
batV.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
|
||||
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 starttime12 = millis(); // Get RTC data all 500ms
|
||||
long starttime13 = millis(); // Get 1Wire sensor data all 2s
|
||||
unsigned long starttime20 = millis(); // Get TWD and TWS data every 1000ms
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
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 *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
|
||||
ESP32Time rtc(0);
|
||||
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);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include "BoatDataCalibration.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "Pagedata.h"
|
||||
#include "OBPRingBuffer.h"
|
||||
#include "Pagedata.h"
|
||||
|
||||
#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 {
|
||||
|
||||
bool keylock = false; // Keylock
|
||||
// int16_t lp = 80; // Pointer length
|
||||
char chrtMode = 'D'; // Chart mode: 'D' for TWD, 'S' for TWS, 'B' for both06121990
|
||||
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
|
||||
|
@ -323,8 +355,8 @@ public:
|
|||
int distVals; // 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<int>windSpdHstry(bufSize); // Circular buffer to store wind speed values
|
||||
static RingBuffer<int16_t> windDirHstry(bufSize); // Circular buffer to store wind direction values
|
||||
static RingBuffer<int16_t> windSpdHstry(bufSize); // Circular buffer to store wind speed values
|
||||
|
||||
LOG_DEBUG(GwLog::LOG, "Display page WindPlot");
|
||||
unsigned long start = millis();
|
||||
|
@ -420,13 +452,13 @@ public:
|
|||
|
||||
// initialize chart range values
|
||||
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°
|
||||
diffRng = dfltRng;
|
||||
chrtRng = dfltRng;
|
||||
} else {
|
||||
// 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);
|
||||
if (diffRng > chrtRng) {
|
||||
chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 degree value
|
||||
|
|
Loading…
Reference in New Issue