mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-24 00:26:13 +01:00
remove unused circular buffer
This commit is contained in:
parent
800972a57c
commit
4896e6f040
|
@ -1,387 +0,0 @@
|
|||
/*
|
||||
* © 2023 Thierry Paris / Locoduino
|
||||
* All rights reserved.
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CircularBuffer.hpp"
|
||||
|
||||
CircularBuffer::CircularBuffer(int inSize)
|
||||
{
|
||||
this->head = 0;
|
||||
this->tail = 0;
|
||||
this->full = false;
|
||||
this->peakCount = 0;
|
||||
this->buffer = NULL;
|
||||
this->size = inSize;
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
this->xSemaphore = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CircularBuffer::begin(bool inMultiThread)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (inMultiThread)
|
||||
{
|
||||
this->xSemaphore = xSemaphoreCreateMutex();
|
||||
}
|
||||
#endif
|
||||
this->buffer = new byte[this->size];
|
||||
this->clear();
|
||||
}
|
||||
|
||||
bool CircularBuffer::CheckIfBeginDone()
|
||||
{
|
||||
if (this->buffer == NULL)
|
||||
{
|
||||
DIAG(F("Error : CircularBuffer missing begin !"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CircularBuffer::end()
|
||||
{
|
||||
START_SEMAPHORE()
|
||||
if (!this->CheckIfBeginDone()) return;
|
||||
|
||||
delete[] this->buffer;
|
||||
this->buffer = NULL; // to be sure to crash at any attemps to use it !
|
||||
END_SEMAPHORE()
|
||||
}
|
||||
|
||||
void CircularBuffer::clear()
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return;
|
||||
|
||||
START_SEMAPHORE()
|
||||
memset(this->buffer, 0, this->size);
|
||||
|
||||
this->full = false;
|
||||
this->head = this->tail = 0;
|
||||
this->peakCount = 0;
|
||||
END_SEMAPHORE()
|
||||
}
|
||||
|
||||
bool CircularBuffer::PushByte(byte inpData)
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return false;
|
||||
|
||||
bool ok = true;
|
||||
START_SEMAPHORE()
|
||||
|
||||
if (!this->full)
|
||||
{
|
||||
this->buffer[this->head] = inpData;
|
||||
this->head++;
|
||||
this->full = this->head == this->tail;
|
||||
|
||||
if (this->full)
|
||||
{
|
||||
ok = false;
|
||||
this->peakCount = this->size + 1; // maximum size !
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
DIAG(F("Error : the byte has been lost ! Buffer is full !"));
|
||||
}
|
||||
|
||||
END_SEMAPHORE()
|
||||
|
||||
this->GetCount(); // update peakCount...
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CircularBuffer::PushBytes(byte* inpData, int inDataLength)
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return false;
|
||||
|
||||
bool ok = true;
|
||||
START_SEMAPHORE()
|
||||
if (!this->full)
|
||||
{
|
||||
for (int i = 0; i < inDataLength; i++)
|
||||
{
|
||||
this->buffer[this->head] = inpData[i];
|
||||
this->head = (this->head + 1) % this->size;
|
||||
this->full = this->head == this->tail;
|
||||
|
||||
if (this->full)
|
||||
{
|
||||
ok = false;
|
||||
this->peakCount = this->size + (inDataLength - i); // maximum size !
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
DIAG(F("Error : bytes has been lost ! Buffer is full !"));
|
||||
}
|
||||
|
||||
END_SEMAPHORE()
|
||||
this->GetCount(); // update peakCount...
|
||||
return ok;
|
||||
}
|
||||
|
||||
byte CircularBuffer::GetByte()
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return 0;
|
||||
|
||||
byte value = 0;
|
||||
if (this->isEmpty())
|
||||
return 0;
|
||||
|
||||
START_SEMAPHORE()
|
||||
value = this->buffer[this->tail];
|
||||
this->tail = (this->tail + 1) % this->size;
|
||||
this->full = false;
|
||||
END_SEMAPHORE()
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int16_t CircularBuffer::GetInt16()
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return 0;
|
||||
|
||||
if (this->isEmpty() || this->GetCount() < 2)
|
||||
return 0;
|
||||
|
||||
byte value1 = this->GetByte();
|
||||
byte value2 = this->GetByte();
|
||||
|
||||
return int16_t((unsigned char)(value2) << 8 | (unsigned char)(value1));
|
||||
}
|
||||
|
||||
int32_t CircularBuffer::GetInt32()
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return 0;
|
||||
|
||||
if (this->isEmpty() || this->GetCount() < 4)
|
||||
return 0;
|
||||
|
||||
byte value1 = this->GetByte();
|
||||
byte value2 = this->GetByte();
|
||||
byte value3 = this->GetByte();
|
||||
byte value4 = this->GetByte();
|
||||
|
||||
return int32_t(value4 << 24 | value3 << 16 | value2 << 8 | value1);
|
||||
}
|
||||
|
||||
bool CircularBuffer::GetBytes(byte* inpData, int inDataLength)
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return false;
|
||||
|
||||
if (this->GetCount() < inDataLength)
|
||||
return false;
|
||||
|
||||
START_SEMAPHORE()
|
||||
for (int i = 0; i < inDataLength; i++)
|
||||
{
|
||||
inpData[i] = this->buffer[this->tail];
|
||||
this->tail = (this->tail + 1) % this->size;
|
||||
}
|
||||
this->full = false;
|
||||
END_SEMAPHORE()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int16_t CircularBuffer::GetInt16(byte* pBuffer, int inPos)
|
||||
{
|
||||
byte value1 = pBuffer[inPos];
|
||||
byte value2 = pBuffer[inPos+1];
|
||||
|
||||
return int16_t((unsigned char)(value2) << 8 | (unsigned char)(value1));
|
||||
}
|
||||
|
||||
int32_t CircularBuffer::GetInt32(byte* pBuffer, int inPos)
|
||||
{
|
||||
byte value1 = pBuffer[inPos];
|
||||
byte value2 = pBuffer[inPos + 1];
|
||||
byte value3 = pBuffer[inPos + 2];
|
||||
byte value4 = pBuffer[inPos + 3];
|
||||
|
||||
return int32_t(value4 << 24 | value3 << 16 | value2 << 8 | value1);
|
||||
}
|
||||
|
||||
void CircularBuffer::GetBytes(byte* pBuffer, int inPos, byte* inpData, int inDataLength)
|
||||
{
|
||||
memcpy(pBuffer + inPos, inpData, inDataLength);
|
||||
}
|
||||
|
||||
int CircularBuffer::GetCount()
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return 0;
|
||||
|
||||
int usedSize = 0;
|
||||
|
||||
usedSize = this->size;
|
||||
|
||||
if (!this->full)
|
||||
{
|
||||
if (this->head >= this->tail)
|
||||
{
|
||||
usedSize = this->head - this->tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
usedSize = this->size + this->head - this->tail;
|
||||
}
|
||||
}
|
||||
|
||||
if (usedSize > this->peakCount)
|
||||
this->peakCount = usedSize;
|
||||
|
||||
return usedSize;
|
||||
}
|
||||
|
||||
#ifdef DCCPP_DEBUG_MODE
|
||||
#ifdef VISUALSTUDIO
|
||||
const char textNum[] = "123456789";
|
||||
const char textChars[] = "ABCDEF";
|
||||
const char textSymb[] = "/*-+&$!:;,";
|
||||
void CircularBuffer::Test()
|
||||
{
|
||||
CircularBuffer test(20);
|
||||
|
||||
test.begin(false);
|
||||
|
||||
Serial.println("After all initialized");
|
||||
test.printCircularBuffer();
|
||||
|
||||
test.PushBytes((byte*)textNum, 9);
|
||||
Serial.println("After nums pushed");
|
||||
test.printCircularBuffer();
|
||||
|
||||
byte ret = test.GetByte();
|
||||
Serial.print("ret '1' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '2': ");
|
||||
Serial.println((int)ret);
|
||||
test.printCircularBuffer();
|
||||
|
||||
test.PushBytes((byte*)textChars, 6);
|
||||
Serial.println("After chars pushed");
|
||||
test.printCircularBuffer();
|
||||
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '3' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '4': ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '5': ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '6': ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '7': ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '8': ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '9': ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret 'A': ");
|
||||
Serial.println((int)ret);
|
||||
test.printCircularBuffer();
|
||||
|
||||
test.PushBytes((byte*)textSymb, 10);
|
||||
Serial.println("After chars pushed");
|
||||
test.printCircularBuffer();
|
||||
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret 'B' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret 'C' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret 'D' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret 'E' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret 'F' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '/' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '*' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '-' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '+' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '&' : ");
|
||||
Serial.println((int)ret);
|
||||
ret = test.GetByte();
|
||||
Serial.print("ret '$' : ");
|
||||
Serial.println((int)ret);
|
||||
test.printCircularBuffer();
|
||||
|
||||
Serial.print("Final size : ");
|
||||
Serial.println((int)test.GetCount());
|
||||
Serial.print("Max used : ");
|
||||
Serial.println((int)test.GetPeakCount());
|
||||
|
||||
// add too much data in the buffer...
|
||||
test.PushBytes((byte*)textSymb, 10);
|
||||
Serial.println("After chars pushed");
|
||||
test.PushBytes((byte*)textNum, 9);
|
||||
Serial.println("After chars pushed");
|
||||
test.printCircularBuffer();
|
||||
|
||||
Serial.print("Final size : ");
|
||||
Serial.println((int)test.GetCount());
|
||||
Serial.print("Max used : ");
|
||||
Serial.println((int)test.GetPeakCount());
|
||||
}
|
||||
#endif
|
||||
|
||||
void CircularBuffer::printCircularBuffer()
|
||||
{
|
||||
if (!this->CheckIfBeginDone()) return;
|
||||
|
||||
if (this->full)
|
||||
Serial.println("FULL !");
|
||||
for (int i = 0; i < this->size; i++)
|
||||
{
|
||||
if (i == this->tail)
|
||||
Serial.print("Tail ");
|
||||
if (i == this->head)
|
||||
Serial.print("Head ");
|
||||
if (i != this->tail && i != this->head)
|
||||
Serial.print(" ");
|
||||
Serial.println((int)this->buffer[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
* © 2023 Thierry Paris / Locoduino
|
||||
* All rights reserved.
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
#ifndef __CircularBuffer_Hpp__
|
||||
#define __CircularBuffer_Hpp__
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "DIAG.h"
|
||||
|
||||
/** This is a thread-safe buffer of bytes, binary or not. Bytes are pushed on the top (its head), and got from the bottom of the
|
||||
* buffer (its tail...).
|
||||
*/
|
||||
class CircularBuffer
|
||||
{
|
||||
private:
|
||||
byte *buffer; // buffer itself
|
||||
int size; // total size of this buffer
|
||||
int head; // index of the first free byte in the buffer
|
||||
int tail; // index of the next byte to get.
|
||||
bool full; // if true, no more space !
|
||||
int peakCount; // biggest occupancy size since the creation of the buffer.
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
SemaphoreHandle_t xSemaphore; // semaphore d'exclusion mutuelle
|
||||
#endif
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
@param inSize
|
||||
*/
|
||||
CircularBuffer(int inSize);
|
||||
|
||||
/** Initialize the list.
|
||||
@param inMultiThread If the buffer is used in multi-thread environnement, initialize the semaphore before calling this begin().
|
||||
*/
|
||||
void begin(bool inMultiThread = false);
|
||||
|
||||
/** Close the usage of this buffer and free the allocated memory.
|
||||
*/
|
||||
void end();
|
||||
|
||||
/** Remove the full content of the buffer, ready for the next push.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/** Add one byte in the buffer.
|
||||
@param inpData byte to add.
|
||||
@return true if the byte have been pushed. false if the byte are lost due to max size reached...
|
||||
*/
|
||||
bool PushByte(byte inpData);
|
||||
|
||||
/** Add some bytes in the buffer.
|
||||
@param inpData pointer to bytes to add.
|
||||
@param inDataLength number of bytes to add.
|
||||
@return true if all bytes have been pushed. false if one or more bytes are lost due to max size reached...
|
||||
*/
|
||||
bool PushBytes(byte* inpData, int inDataLength);
|
||||
|
||||
/** Get the next byte from the buffer.
|
||||
@return first available byte, or 0.
|
||||
*/
|
||||
byte GetByte();
|
||||
|
||||
/** Get the next two bytes from the buffer, to form an integer.
|
||||
@return integer created from two available bytes, or 0.
|
||||
*/
|
||||
int16_t GetInt16();
|
||||
|
||||
/** Get the next four bytes from the buffer, to form an integer.
|
||||
@return integer created from two available bytes, or 0.
|
||||
*/
|
||||
int32_t GetInt32();
|
||||
|
||||
/** Get some bytes.
|
||||
@param inpData buffer to fill.
|
||||
@param inDataLength number of bytes to get.
|
||||
@return true if all bytes have been get. false if there were not enough bytes in th buffer.
|
||||
*/
|
||||
bool GetBytes(byte* inpData, int inDataLength);
|
||||
|
||||
/** Get the next two bytes from the given buffer starting from the given position, to form an integer.
|
||||
@param pBuffer buffer to scan.
|
||||
@param inPos Position of the first useful byte.
|
||||
@return integer created from two available bytes, or 0.
|
||||
*/
|
||||
static int16_t GetInt16(byte* pBuffer, int inPos);
|
||||
|
||||
/** Get the next four bytes from the given buffer starting from the given position, to form a 32 bits integer.
|
||||
@param pBuffer buffer to scan.
|
||||
@param inPos Position of the first useful byte.
|
||||
@return integer created from four available bytes, or 0.
|
||||
*/
|
||||
static int32_t GetInt32(byte* pBuffer, int inPos);
|
||||
|
||||
/** Get some bytes from the given buffer starting from the given position.
|
||||
@param pBuffer buffer to scan.
|
||||
@param inPos Position of the first useful byte.
|
||||
@param inpData buffer to fill.
|
||||
@param inDataLength number of bytes to get.
|
||||
@return true if all bytes have been get. false if there were not enough bytes in th buffer.
|
||||
*/
|
||||
static void GetBytes(byte *pBuffer, int inPos, byte* inpData, int inDataLength);
|
||||
|
||||
/** Count the number of bytes in the buffer.
|
||||
@return number of bytes in the buffer.
|
||||
*/
|
||||
int GetCount();
|
||||
|
||||
/** Get the maximum size used by the buffer since the beggining of its usage.
|
||||
@return maximum number of bytes in the buffer.
|
||||
*/
|
||||
int GetPeakCount() { return this->peakCount; }
|
||||
|
||||
/** Check if the buffer is empty or not.
|
||||
*/
|
||||
bool isEmpty() const
|
||||
{
|
||||
//if head and tail are equal, we are empty
|
||||
return (!this->full && (this->head == this->tail));
|
||||
}
|
||||
|
||||
/** Check if the buffer is full or not.
|
||||
*/
|
||||
bool isFull() const
|
||||
{
|
||||
//If tail is ahead the head by 1, we are full
|
||||
return this->full;
|
||||
}
|
||||
|
||||
/** Check if the begin has been called. If not, the buffer is not allocated and any usage will crash the system !
|
||||
*/
|
||||
bool CheckIfBeginDone();
|
||||
|
||||
#ifdef DCCPP_DEBUG_MODE
|
||||
#ifdef VISUALSTUDIO
|
||||
/** Unit test function
|
||||
*/
|
||||
static void Test();
|
||||
#endif
|
||||
|
||||
/** Print the list of messages in the stack.
|
||||
@remark Only available if DCCPP_DEBUG_MODE is defined.
|
||||
*/
|
||||
void printCircularBuffer();
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define START_SEMAPHORE() \
|
||||
{ \
|
||||
byte semaphoreTaken = this->xSemaphore == NULL?1:0; \
|
||||
if (this->xSemaphore != NULL) \
|
||||
if (xSemaphoreTake(this->xSemaphore, (TickType_t)100) == pdTRUE) \
|
||||
semaphoreTaken = 1; \
|
||||
if (semaphoreTaken == 1)
|
||||
|
||||
#define END_SEMAPHORE() \
|
||||
xSemaphoreGive(this->xSemaphore); \
|
||||
}
|
||||
|
||||
#define ABORT_SEMAPHORE() \
|
||||
xSemaphoreGive(this->xSemaphore);
|
||||
#else
|
||||
#define START_SEMAPHORE()
|
||||
#define END_SEMAPHORE()
|
||||
#define ABORT_SEMAPHORE()
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user