Arduino_STM32/STM32F3/libraries/ringbuffer/ringbuffer.cpp

321 lines
7.1 KiB
C++

/******************************************************************************
* The MIT License
*
* Copyright (c) 2015 Frank-Michael Krause
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
#include "ringbuffer.h"
#ifdef WIN32
int tmcnt=10;
unsigned long millis() { return tmcnt++; }
#define NULL 0
#else
#include <wirish/wirish.h>
#endif
RingBuffer::RingBuffer(int _size, int *_values, unsigned long *_timeStamps)
{
size = _size; // muss ZweierPotenz sein
values = _values; // Pointer auf Speicher für Werte
timeStamps = _timeStamps; // optional Pointer auf Speicher für ms timestamps
mask = 0;
int t = size/2;
while (t)
{
mask = (mask<<1)|1;
t = t/2;
}
reset();
}
void RingBuffer::addValue(int value)
{
values[wrIdx] = value;
if (timeStamps != NULL)
timeStamps[wrIdx] = millis();
if (anz < size)
anz++;
wrIdx++;
wrIdx &= mask;
}
void RingBuffer::reset()
{
anz = 0;
wrIdx = 0;
rdIdx = 0;
for (int i=0; i<size; i++)
values[i] = 0;
}
/*
* setzt rdIdx auf distance Werte vor den aktuellen wrIdx
* Mit getValue können die letzten Werte bis zum letzten Wert abgefragt werden
*
* Fuer Vorwärtsauslesen:
* 0 bzw. Size setzen auf den ältesten vorhandenen Wert
*
* gibt 1 zurück, wenn genügend Werte im Puffer sind
* gibt 0 zurück, wenn noch nicht genügend Werte im Puffer sind oder distance
* größer als die Pufferlänge ist
*/
int RingBuffer::setReadIdx(int distance)
{
if (distance > anz)
return 0;
rdIdx = (wrIdx - distance) & mask;
lastRead = 0;
return 1;
}
/*
* Setzt rdIdx auf den ersten Wert, für den der zugehörige timeStamp mindestens <ms> zurückliegt,
* Es wird das Alter des betreffenden Wertes in ms zurückgegeben
* = wird zurückgegeben, wenn kein Wert mindestens so alt wie gefordert ist oder keine timestamps vorhanden sind
*/
int RingBuffer::setReadIdxDt(int ms)
{
if (timeStamps == NULL) // keine timeStamps vorhanden
return 0;
unsigned long aktTime = millis();
unsigned long dt=0;
int count = 0;
rdIdx = (wrIdx - 1)&mask; // auf letzten eingetragenen Wert setzen
lastRead = 0;
while (count<anz)
{
dt = aktTime - timeStamps[rdIdx];
if ((int)dt > ms)
return dt;
count++;
rdIdx = (rdIdx-1)&mask;
}
return 0;
}
/*
* gibt Wert für rdIdx zurück und incrementiert rdIdx, solange rdIdx < (wrIdx-1)
* ACHTUNG: wird wrPtr erreicht, so wird immer wieder der letzte Wert zurückgegeben!
*/
int RingBuffer::getValue()
{
int ret = values[rdIdx];
if (((rdIdx+1)&mask) == wrIdx)
lastRead = 1;
else
rdIdx = (rdIdx+1)&mask;
return ret;
}
/*
* gibt Wert für rdIdx zurück, trägt den zugehörigen timestamp
* in time ein und incrementiert rdIdx, solange rdIdx < wrIdx
* ACHTUNG: wird wrPtr erreicht, so wird immer wieder der letzte Wert zurückgegeben!
*/
int RingBuffer::getValue(unsigned long *time)
{
int ret = values[rdIdx];
if ((time != NULL) && (timeStamps!=NULL))
*time = timeStamps[rdIdx];
if (((rdIdx+1)&mask) == wrIdx)
lastRead = 1;
else
rdIdx = (rdIdx+1)&mask;
return ret;
}
/*
* gibt den Wert von rdIdx-1 zurück und decrementiert rdIdx wenn rdIdx-1 != wrIdx
*
*/
int RingBuffer::getPreviousValue()
{
int idx = (rdIdx-1)&mask;
int ret = values[idx];
if (idx != wrIdx) // rdIdx darf nicht kleiner als wrIdx werden
rdIdx = idx;
else
lastRead = 1;
return ret;
}
/*
`* decrementiert rdPtr und gibt den zugehörigen Wert zurück
*/
int RingBuffer::getPreviousValue(unsigned long *time)
{
int idx = (rdIdx-1)&mask;
int ret = values[idx];
rdIdx = (rdIdx-1)&mask;
if ((time != NULL) && (timeStamps!=NULL))
*time = timeStamps[idx];
if (idx != wrIdx) // rdIdx darf nicht kleiner als wrIdx werden
rdIdx = idx;
else
lastRead = 1;
return ret;
}
int RingBuffer::getPreviousValueDt(unsigned long *dt)
{
int idx = (rdIdx-1)&mask;
int ret = values[idx];
if ((dt != NULL) && (timeStamps!=NULL))
{
unsigned long aktTime = millis();
*dt = aktTime - timeStamps[idx];
}
if (idx != wrIdx) // rdIdx darf nicht kleiner als wrIdx werden
rdIdx = idx;
else
lastRead = 1;
return ret;
}
/*
* gibt eins zurück, sobald der älteste Wert mit einer PreviousValue-Funktion
* gelesen wurde
* wird durch jeden Aufruf einer SetReadIdx-Funktion zurückgesetzt
*/
int RingBuffer::lastValueRead()
{
return lastRead;
}
/*
* gibt 1 zurück, wenn rdPtr != wrPtr
* gibt 0 zurück, wenn rdPtr == wrPtr
*
* --> funktioniert nur, wenn zuvor SetReadIdx() aufgerufen wurde
*/
int RingBuffer::valueAvailable()
{
return !lastRead;
}
int RingBuffer::getValueAt(int idx)
{
return values[(wrIdx+idx)&mask];
}
int RingBuffer::getValueAt(int idx, unsigned long *time)
{
int valueIdx = (wrIdx+idx)&mask;
if ((time != NULL) && (timeStamps!=NULL))
*time = timeStamps[valueIdx];
return values[valueIdx];
}
int RingBuffer::getPreviousValueAt(int idx)
{
return values[(wrIdx-1-idx)&mask];
}
int RingBuffer::getPreviousValueAt(int idx, unsigned long *time)
{
int valueIdx = (wrIdx-1-idx)&mask;
if ((time != NULL) && (timeStamps!=NULL))
*time = timeStamps[valueIdx];
return values[valueIdx];
}
//*****************************************************************
RingBufferAverage::RingBufferAverage(int _size, int *_values, unsigned long *_timeStamps, int _averageSize):RingBuffer(_size, _values, _timeStamps)
{
averageSize = _averageSize;
averageSum = 0;
}
void RingBufferAverage::addValue(int val)
{
RingBuffer::addValue(val);
averageSum += val;
if (anz > averageSize)
averageSum -= getPreviousValueAt(averageSize);
}
void RingBufferAverage::reset()
{
RingBuffer::reset();
averageSum = 0;
}
void RingBufferAverage::setAverageLen(int len)
{
averageSize = len;
reset();
}
int RingBufferAverage::getAverage()
{
if (anz>averageSize)
return averageSum/averageSize;
return averageSum/anz;
}
int RingBufferAverage::getAverageSum()
{
return averageSum;
}