Implement OBPRingBuffer class and adjust PageWindPlot accordingly
This commit is contained in:
parent
9ada5be7cb
commit
1f90cefbd6
|
@ -1,3 +1,8 @@
|
||||||
{
|
{
|
||||||
"cmake.configureOnOpen": false
|
"cmake.configureOnOpen": false,
|
||||||
|
"files.associations": {
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"functional": "cpp"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
#pragma once
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class RingBuffer {
|
||||||
|
private:
|
||||||
|
std::vector<T> buffer;
|
||||||
|
size_t capacity;
|
||||||
|
size_t head; // Points to the next insertion position
|
||||||
|
size_t first; // Points to the first (oldest) valid element
|
||||||
|
size_t last; // Points to the last (newest) valid element
|
||||||
|
size_t count; // Number of valid elements currently in buffer
|
||||||
|
bool is_Full; // Indicates that all buffer elements are used and ringing is in use
|
||||||
|
T MIN_VAL; // lowest possible value of buffer
|
||||||
|
T MAX_VAL; // highest possible value of buffer of type <T>
|
||||||
|
|
||||||
|
// metadata for buffer
|
||||||
|
int updFreq; // Update frequency in milliseconds
|
||||||
|
int smallest; // Value range of buffer: smallest value
|
||||||
|
int biggest; // Value range of buffer: biggest value
|
||||||
|
|
||||||
|
public:
|
||||||
|
RingBuffer(size_t size);
|
||||||
|
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
|
||||||
|
T getLast() const; // Get the last (newest) value in buffer
|
||||||
|
T getMin() const; // Get the lowest value in buffer
|
||||||
|
T getMin(size_t amount) const; // Get minimum value of the last <amount> values of buffer
|
||||||
|
T getMax() const; // Get the highest value in buffer
|
||||||
|
T getMax(size_t amount) const; // Get maximum value of the last <amount> values of buffer
|
||||||
|
T getMid() const; // Get mid value between <min> and <max> value in buffer
|
||||||
|
T getMid(size_t amount) const; // Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||||
|
T getRng(T center, size_t amount) const; // Get maximum difference of last <amount> of buffer values to center value
|
||||||
|
T getMedian() const; // Get the median value in 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 getCurrentSize() const; // Get the current number of elements in 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
|
||||||
|
void clear(); // Clear buffer
|
||||||
|
T operator[](size_t index) const;
|
||||||
|
std::vector<T> getAllValues() const; // Operator[] for convenient access (same as get())
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "OBPRingBuffer.tpp"
|
|
@ -0,0 +1,356 @@
|
||||||
|
#include "OBPRingBuffer.h"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
RingBuffer<T>::RingBuffer(size_t size)
|
||||||
|
: capacity(size)
|
||||||
|
, head(0)
|
||||||
|
, first(0)
|
||||||
|
, last(0)
|
||||||
|
, count(0)
|
||||||
|
, is_Full(false)
|
||||||
|
{
|
||||||
|
if (size == 0) {
|
||||||
|
// return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MIN_VAL = std::numeric_limits<T>::lowest();
|
||||||
|
MAX_VAL = std::numeric_limits<T>::max();
|
||||||
|
buffer.resize(size, MIN_VAL);
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new value to the buffer
|
||||||
|
template <typename T>
|
||||||
|
void RingBuffer<T>::add(const T& value)
|
||||||
|
{
|
||||||
|
buffer[head] = value;
|
||||||
|
last = head;
|
||||||
|
|
||||||
|
if (is_Full) {
|
||||||
|
first = (first + 1) % capacity; // Move pointer to oldest element when overwriting
|
||||||
|
} else {
|
||||||
|
count++;
|
||||||
|
if (count == capacity) {
|
||||||
|
is_Full = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
head = (head + 1) % capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get value at specific position (0-based index from oldest to newest)
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::get(size_t index) const
|
||||||
|
{
|
||||||
|
if (isEmpty()) {
|
||||||
|
throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
if (index < 0 || index >= count) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::out_of_range("Index out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t realIndex = (first + index) % capacity;
|
||||||
|
return buffer[realIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operator[] for convenient access (same as get())
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::operator[](size_t index) const
|
||||||
|
{
|
||||||
|
return get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the first (oldest) value in the buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getFirst() const
|
||||||
|
{
|
||||||
|
if (isEmpty()) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
return buffer[first];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the last (newest) value in the buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getLast() const
|
||||||
|
{
|
||||||
|
if (isEmpty()) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
return buffer[last];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the lowest value in the buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMin() const
|
||||||
|
{
|
||||||
|
if (isEmpty()) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
T minVal = get(first);
|
||||||
|
T value;
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
value = get(i);
|
||||||
|
if (value < minVal) {
|
||||||
|
minVal = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get minimum value of the last <amount> values of buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMin(size_t amount) const
|
||||||
|
{
|
||||||
|
if (isEmpty() || amount <= 0) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
if (amount > count)
|
||||||
|
amount = count;
|
||||||
|
|
||||||
|
T minVal = get(last);
|
||||||
|
T value;
|
||||||
|
for (size_t i = 0; i < amount; i++) {
|
||||||
|
value = get((last + capacity - i) % capacity);
|
||||||
|
if (value < minVal && value != MIN_VAL) {
|
||||||
|
minVal = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the highest value in the buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMax() const
|
||||||
|
{
|
||||||
|
if (isEmpty()) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
T maxVal = get(first);
|
||||||
|
T value;
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
value = get(i);
|
||||||
|
if (value > maxVal) {
|
||||||
|
maxVal = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get maximum value of the last <amount> values of buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMax(size_t amount) const
|
||||||
|
{
|
||||||
|
if (isEmpty() || amount <= 0) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
if (amount > count)
|
||||||
|
amount = count;
|
||||||
|
|
||||||
|
T maxVal = get(last);
|
||||||
|
T value;
|
||||||
|
for (size_t i = 0; i < amount; i++) {
|
||||||
|
value = get((last + capacity - i) % capacity);
|
||||||
|
if (value > maxVal && value != MIN_VAL) {
|
||||||
|
maxVal = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mid value between <min> and <max> value in the buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMid() const
|
||||||
|
{
|
||||||
|
if (isEmpty()) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (getMin() + getMax()) / static_cast<T>(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMid(size_t amount) const
|
||||||
|
{
|
||||||
|
if (isEmpty() || amount <= 0) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount > count)
|
||||||
|
amount = count;
|
||||||
|
|
||||||
|
return (getMin(amount) + getMax(amount)) / static_cast<T>(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******************* works for wind direction only -> move out of here *******************************
|
||||||
|
// Get maximum difference of last <amount> of buffer values to center value
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getRng(T center, size_t amount) const
|
||||||
|
{
|
||||||
|
if (isEmpty() || amount <= 0) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
if (amount > count)
|
||||||
|
amount = count;
|
||||||
|
|
||||||
|
T value = 0;
|
||||||
|
T rng = 0;
|
||||||
|
T maxRng = MIN_VAL;
|
||||||
|
// Start from the newest value (last) and go backwards x times
|
||||||
|
for (size_t i = 0; i < amount; i++) {
|
||||||
|
value = get((last + capacity - i) % capacity);
|
||||||
|
if (value == MIN_VAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rng = abs(((value - center + 540) % 360) - 180);
|
||||||
|
if (rng > maxRng)
|
||||||
|
maxRng = rng;
|
||||||
|
}
|
||||||
|
if (maxRng > 180) {
|
||||||
|
maxRng = 180;
|
||||||
|
}
|
||||||
|
return maxRng;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the median value in the buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMedian() const
|
||||||
|
{
|
||||||
|
if (isEmpty()) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a temporary vector with current valid elements
|
||||||
|
std::vector<T> temp;
|
||||||
|
temp.reserve(count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
temp.push_back(get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort to find median
|
||||||
|
std::sort(temp.begin(), temp.end());
|
||||||
|
|
||||||
|
if (count % 2 == 1) {
|
||||||
|
// Odd number of elements
|
||||||
|
return temp[count / 2];
|
||||||
|
} else {
|
||||||
|
// Even number of elements - return average of middle two
|
||||||
|
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||||
|
return (temp[count / 2 - 1] + temp[count / 2]) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the median value of the last <amount> values of buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMedian(size_t amount) const
|
||||||
|
{
|
||||||
|
if (isEmpty() || amount <= 0) {
|
||||||
|
return MIN_VAL;
|
||||||
|
// throw std::runtime_error("Buffer is empty");
|
||||||
|
}
|
||||||
|
if (amount > count)
|
||||||
|
amount = count;
|
||||||
|
|
||||||
|
// Create a temporary vector with current valid elements
|
||||||
|
std::vector<T> temp;
|
||||||
|
temp.reserve(amount);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < amount; i++) {
|
||||||
|
temp.push_back(get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort to find median
|
||||||
|
std::sort(temp.begin(), temp.end());
|
||||||
|
|
||||||
|
if (amount % 2 == 1) {
|
||||||
|
// Odd number of elements
|
||||||
|
return temp[amount / 2];
|
||||||
|
} else {
|
||||||
|
// Even number of elements - return average of middle two
|
||||||
|
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||||
|
return (temp[amount / 2 - 1] + temp[amount / 2]) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the buffer capacity (maximum size)
|
||||||
|
template <typename T>
|
||||||
|
size_t RingBuffer<T>::getCapacity() const
|
||||||
|
{
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current number of elements in the buffer
|
||||||
|
template <typename T>
|
||||||
|
size_t RingBuffer<T>::getCurrentSize() const
|
||||||
|
{
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if buffer is empty
|
||||||
|
template <typename T>
|
||||||
|
bool RingBuffer<T>::isEmpty() const
|
||||||
|
{
|
||||||
|
return count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if buffer is full
|
||||||
|
template <typename T>
|
||||||
|
bool RingBuffer<T>::isFull() const
|
||||||
|
{
|
||||||
|
return is_Full;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get lowest possible value for buffer; used for initialized buffer data
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMinVal()
|
||||||
|
{
|
||||||
|
return MIN_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get highest possible value for buffer
|
||||||
|
template <typename T>
|
||||||
|
T RingBuffer<T>::getMaxVal()
|
||||||
|
{
|
||||||
|
return MAX_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear buffer
|
||||||
|
template <typename T>
|
||||||
|
void RingBuffer<T>::clear()
|
||||||
|
{
|
||||||
|
head = 0;
|
||||||
|
first = 0;
|
||||||
|
last = 0;
|
||||||
|
count = 0;
|
||||||
|
is_Full = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all current values as a vector
|
||||||
|
template <typename T>
|
||||||
|
std::vector<T> RingBuffer<T>::getAllValues() const
|
||||||
|
{
|
||||||
|
std::vector<T> result;
|
||||||
|
result.reserve(count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
result.push_back(get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
#include "ObpNmea0183.h" // Check NMEA0183 sentence for uncorrect content
|
#include "ObpNmea0183.h" // Check NMEA0183 sentence for uncorrect content
|
||||||
#include "OBP60Extensions.h" // Lib for hardware extensions
|
#include "OBP60Extensions.h" // Lib for hardware extensions
|
||||||
#include "movingAvg.h" // Lib for moving average building
|
#include "movingAvg.h" // Lib for moving average building
|
||||||
|
#include "OBPRingBuffer.h" // Lib with ring buffer for history storage of some boat data
|
||||||
#include "time.h" // For getting NTP time
|
#include "time.h" // For getting NTP time
|
||||||
#include <ESP32Time.h> // Internal ESP32 RTC clock
|
#include <ESP32Time.h> // Internal ESP32 RTC clock
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
#include "BoatDataCalibration.h"
|
#include "BoatDataCalibration.h"
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "Pagedata.h"
|
#include "Pagedata.h"
|
||||||
|
#include "OBPRingBuffer.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// ****************************************************************
|
// ****************************************************************
|
||||||
class wndHistory {
|
class OldwndHistory {
|
||||||
// provides a circular buffer to store wind history values
|
// provides a circular buffer to store wind history values
|
||||||
private:
|
private:
|
||||||
int SIZE;
|
int SIZE;
|
||||||
|
@ -273,9 +274,6 @@ public:
|
||||||
GwConfigHandler* config = commonData->config;
|
GwConfigHandler* config = commonData->config;
|
||||||
GwLog* logger = commonData->logger;
|
GwLog* logger = commonData->logger;
|
||||||
|
|
||||||
static wndHistory windDirHstry; // Circular buffer to store wind direction values
|
|
||||||
static wndHistory windSpdHstry; // Circular buffer to store wind speed values
|
|
||||||
|
|
||||||
GwApi::BoatValue* bvalue;
|
GwApi::BoatValue* bvalue;
|
||||||
const int numCfgValues = 9;
|
const int numCfgValues = 9;
|
||||||
String dataName[numCfgValues];
|
String dataName[numCfgValues];
|
||||||
|
@ -325,15 +323,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<int>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.getSize() == 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;
|
||||||
|
@ -363,7 +364,6 @@ public:
|
||||||
dataName[i] = dataName[i].substring(0, 6); // String length limit for value name
|
dataName[i] = dataName[i].substring(0, 6); // String length limit for value name
|
||||||
calibrationData.calibrateInstance(dataName[i], bvalue, logger); // Check if boat data value is to be calibrated
|
calibrationData.calibrateInstance(dataName[i], bvalue, logger); // Check if boat data value is to be calibrated
|
||||||
dataValue[i] = bvalue->value; // Value as double in SI unit
|
dataValue[i] = bvalue->value; // Value as double in SI unit
|
||||||
calibrationData.calibrateInstance(dataName[i], bvalue, logger); // Check if boat data value is to be calibrated
|
|
||||||
dataValid[i] = bvalue->valid;
|
dataValid[i] = bvalue->valid;
|
||||||
dataSValue[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
dataSValue[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||||
dataUnit[i] = formatValue(bvalue, *commonData).unit;
|
dataUnit[i] = formatValue(bvalue, *commonData).unit;
|
||||||
|
@ -396,7 +396,7 @@ public:
|
||||||
|
|
||||||
// Identify buffer sizes and buffer position to print on the chart
|
// Identify buffer sizes and buffer position to print on the chart
|
||||||
intvBufSize = cHeight * dataIntv;
|
intvBufSize = cHeight * dataIntv;
|
||||||
count = windDirHstry.getSize();
|
count = windDirHstry.getCurrentSize();
|
||||||
numWndValues = min(count, intvBufSize);
|
numWndValues = min(count, intvBufSize);
|
||||||
newDate++;
|
newDate++;
|
||||||
if (dataIntv != oldDataIntv) {
|
if (dataIntv != oldDataIntv) {
|
||||||
|
@ -522,7 +522,6 @@ public:
|
||||||
if (i == (cHeight - 1)) { // Reaching chart area top end ()
|
if (i == (cHeight - 1)) { // Reaching chart area top end ()
|
||||||
linesToShow -= min(40, cHeight); // free top 40 lines of chart for new values
|
linesToShow -= min(40, cHeight); // free top 40 lines of chart for new values
|
||||||
bufStart = max(0, count - (linesToShow * dataIntv)); // next start value in buffer to show
|
bufStart = max(0, count - (linesToShow * dataIntv)); // next start value in buffer to show
|
||||||
// windDirHstry.mvStart(); // virtually delete 40 values from buffer
|
|
||||||
if ((windDirHstry.getMin(numWndValues) > wndCenter) || (windDirHstry.getMax(numWndValues) < wndCenter)) {
|
if ((windDirHstry.getMin(numWndValues) > wndCenter) || (windDirHstry.getMax(numWndValues) < wndCenter)) {
|
||||||
// Check if all wind value are left or right of center value -> optimize chart range
|
// Check if all wind value are left or right of center value -> optimize chart range
|
||||||
int mid = windDirHstry.getMid(numWndValues);
|
int mid = windDirHstry.getMid(numWndValues);
|
||||||
|
|
Loading…
Reference in New Issue