2018-07-12 16:29:32 +02:00
|
|
|
#ifndef FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_
|
|
|
|
#define FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_
|
|
|
|
|
|
|
|
#include <framework/container/ArrayList.h>
|
|
|
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
|
|
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
|
|
|
#include <framework/serialize/SerialArrayListAdapter.h>
|
|
|
|
#include <framework/globalfunctions/crc_ccitt.h>
|
|
|
|
#include <cmath>
|
|
|
|
|
2020-03-19 12:38:11 +01:00
|
|
|
/**
|
|
|
|
* Index is the Type used for the list of indices.
|
|
|
|
*
|
|
|
|
* @tparam T Type which destribes the index. Needs to be a child of SerializeIF
|
|
|
|
* to be able to make it persistent
|
|
|
|
*/
|
2018-07-12 16:29:32 +02:00
|
|
|
template<typename T>
|
|
|
|
class Index: public SerializeIF{
|
|
|
|
/**
|
2020-03-19 12:38:11 +01:00
|
|
|
*
|
2018-07-12 16:29:32 +02:00
|
|
|
*/
|
2020-03-19 12:38:11 +01:00
|
|
|
static_assert(std::is_base_of<SerializeIF,T>::value,
|
|
|
|
"Wrong Type for Index, Type must implement SerializeIF");
|
2018-07-12 16:29:32 +02:00
|
|
|
public:
|
|
|
|
Index():blockStartAddress(0),size(0),storedPackets(0){}
|
|
|
|
|
2020-03-19 12:38:11 +01:00
|
|
|
Index(uint32_t startAddress):blockStartAddress(startAddress),
|
|
|
|
size(0),storedPackets(0) {
|
2018-07-12 16:29:32 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 12:38:11 +01:00
|
|
|
void setBlockStartAddress(uint32_t newAddress) {
|
2018-07-12 16:29:32 +02:00
|
|
|
this->blockStartAddress = newAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getBlockStartAddress() const {
|
|
|
|
return blockStartAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
const T* getIndexType() const {
|
|
|
|
return &indexType;
|
|
|
|
}
|
|
|
|
|
2020-03-19 12:38:11 +01:00
|
|
|
T* modifyIndexType() {
|
2018-07-12 16:29:32 +02:00
|
|
|
return &indexType;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Updates the index Type. Uses = operator
|
|
|
|
* @param indexType Type to copy from
|
|
|
|
*/
|
|
|
|
void setIndexType(T* indexType) {
|
|
|
|
this->indexType = *indexType;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getSize() const {
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setSize(uint32_t size) {
|
|
|
|
this->size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void addSize(uint32_t size){
|
|
|
|
this->size += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setStoredPackets(uint32_t newStoredPackets){
|
|
|
|
this->storedPackets = newStoredPackets;
|
|
|
|
}
|
|
|
|
|
|
|
|
void addStoredPackets(uint32_t packets){
|
|
|
|
this->storedPackets += packets;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getStoredPackets() const{
|
|
|
|
return this->storedPackets;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
|
|
|
const uint32_t max_size, bool bigEndian) const {
|
|
|
|
ReturnValue_t result = AutoSerializeAdapter::serialize(&blockStartAddress,buffer,size,max_size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
result = indexType.serialize(buffer,size,max_size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
result = AutoSerializeAdapter::serialize(&this->size,buffer,size,max_size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
result = AutoSerializeAdapter::serialize(&this->storedPackets,buffer,size,max_size,bigEndian);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
|
|
|
bool bigEndian){
|
|
|
|
ReturnValue_t result = AutoSerializeAdapter::deSerialize(&blockStartAddress,buffer,size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
result = indexType.deSerialize(buffer,size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
result = AutoSerializeAdapter::deSerialize(&this->size,buffer,size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
result = AutoSerializeAdapter::deSerialize(&this->storedPackets,buffer,size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getSerializedSize() const {
|
|
|
|
uint32_t size = AutoSerializeAdapter::getSerializedSize(&blockStartAddress);
|
|
|
|
size += indexType.getSerializedSize();
|
|
|
|
size += AutoSerializeAdapter::getSerializedSize(&this->size);
|
|
|
|
size += AutoSerializeAdapter::getSerializedSize(&this->storedPackets);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool operator==(const Index<T>& other){
|
|
|
|
return ((blockStartAddress == other.getBlockStartAddress()) && (size==other.getSize())) && (indexType == *(other.getIndexType()));
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint32_t blockStartAddress;
|
|
|
|
uint32_t size;
|
|
|
|
uint32_t storedPackets;
|
|
|
|
T indexType;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2020-03-19 12:38:11 +01:00
|
|
|
/**
|
|
|
|
* @brief Indexed Ring Memory Array is a class for a ring memory with indices.
|
|
|
|
* @details
|
|
|
|
* It assumes that the newest data comes in last
|
|
|
|
* It uses the currentWriteBlock as pointer to the current writing position
|
|
|
|
* The currentReadBlock must be set manually
|
|
|
|
* @tparam T
|
|
|
|
*/
|
2018-07-12 16:29:32 +02:00
|
|
|
template<typename T>
|
|
|
|
class IndexedRingMemoryArray: public SerializeIF, public ArrayList<Index<T>, uint32_t>{
|
|
|
|
/**
|
2020-03-19 12:38:11 +01:00
|
|
|
*
|
2018-07-12 16:29:32 +02:00
|
|
|
*/
|
|
|
|
public:
|
2020-03-19 12:38:11 +01:00
|
|
|
IndexedRingMemoryArray(uint32_t startAddress, uint32_t size, uint32_t bytesPerBlock,
|
|
|
|
SerializeIF* additionalInfo, bool overwriteOld):
|
|
|
|
ArrayList<Index<T>,uint32_t>(NULL,(uint32_t)10,(uint32_t)0),totalSize(size),
|
|
|
|
indexAddress(startAddress),currentReadSize(0),currentReadBlockSizeCached(0),
|
|
|
|
lastBlockToReadSize(0), additionalInfo(additionalInfo),overwriteOld(overwriteOld)
|
|
|
|
{
|
2018-07-12 16:29:32 +02:00
|
|
|
//Calculate the maximum number of indices needed for this blocksize
|
|
|
|
uint32_t maxNrOfIndices = floor(static_cast<double>(size)/static_cast<double>(bytesPerBlock));
|
|
|
|
|
|
|
|
//Calculate the Size needeed for the index itself
|
2020-04-05 21:54:11 +02:00
|
|
|
size_t serializedSize = 0;
|
2020-03-19 12:38:11 +01:00
|
|
|
if(additionalInfo!=NULL) {
|
2018-07-12 16:29:32 +02:00
|
|
|
serializedSize += additionalInfo->getSerializedSize();
|
|
|
|
}
|
2020-03-19 12:38:11 +01:00
|
|
|
|
2018-07-12 16:29:32 +02:00
|
|
|
//Size of current iterator type
|
|
|
|
Index<T> tempIndex;
|
|
|
|
serializedSize += tempIndex.getSerializedSize();
|
|
|
|
|
|
|
|
//Add Size of Array
|
|
|
|
serializedSize += sizeof(uint32_t); //size of array
|
|
|
|
serializedSize += (tempIndex.getSerializedSize() * maxNrOfIndices); //size of elements
|
|
|
|
serializedSize += sizeof(uint16_t); //size of crc
|
|
|
|
|
|
|
|
//Calculate new size after index
|
|
|
|
if(serializedSize > totalSize){
|
|
|
|
error << "IndexedRingMemory: Store is too small for index" << std::endl;
|
|
|
|
}
|
|
|
|
uint32_t useableSize = totalSize - serializedSize;
|
2020-03-19 12:38:11 +01:00
|
|
|
|
2018-07-12 16:29:32 +02:00
|
|
|
//Update the totalSize for calculations
|
|
|
|
totalSize = useableSize;
|
|
|
|
|
|
|
|
//True StartAddress
|
|
|
|
uint32_t trueStartAddress = indexAddress + serializedSize;
|
|
|
|
|
|
|
|
//Calculate True number of Blocks and reset size of true Number of Blocks
|
|
|
|
uint32_t trueNumberOfBlocks = floor(static_cast<double>(totalSize) / static_cast<double>(bytesPerBlock));
|
|
|
|
|
|
|
|
//allocate memory now
|
|
|
|
this->entries = new Index<T>[trueNumberOfBlocks];
|
|
|
|
this->size = trueNumberOfBlocks;
|
|
|
|
this->maxSize_ = trueNumberOfBlocks;
|
|
|
|
this->allocated = true;
|
|
|
|
|
|
|
|
//Check trueNumberOfBlocks
|
2020-03-19 12:38:11 +01:00
|
|
|
if(trueNumberOfBlocks<1) {
|
2018-07-12 16:29:32 +02:00
|
|
|
error << "IndexedRingMemory: Invalid Number of Blocks: " << trueNumberOfBlocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Fill address into index
|
|
|
|
uint32_t address = trueStartAddress;
|
|
|
|
for (typename IndexedRingMemoryArray<T>::Iterator it = this->begin();it!=this->end();++it) {
|
|
|
|
it->setBlockStartAddress(address);
|
|
|
|
it->setSize(0);
|
|
|
|
it->setStoredPackets(0);
|
|
|
|
address += bytesPerBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Initialize iterators
|
|
|
|
currentWriteBlock = this->begin();
|
|
|
|
currentReadBlock = this->begin();
|
|
|
|
lastBlockToRead = this->begin();
|
|
|
|
|
|
|
|
//Check last blockSize
|
|
|
|
uint32_t lastBlockSize = (trueStartAddress + useableSize) - (this->back()->getBlockStartAddress());
|
|
|
|
if((lastBlockSize<bytesPerBlock) && (this->size > 1)){
|
|
|
|
//remove the last Block so the second last block has more size
|
|
|
|
this->size -= 1;
|
|
|
|
debug << "IndexedRingMemory: Last Block is smaller than bytesPerBlock, removed last block" << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resets the whole index, the iterators and executes the given reset function on every index type
|
|
|
|
* @param typeResetFnc static reset function which accepts a pointer to the index Type
|
|
|
|
*/
|
|
|
|
void reset(void (*typeResetFnc)(T*)){
|
|
|
|
currentReadBlock = this->begin();
|
|
|
|
currentWriteBlock = this->begin();
|
|
|
|
lastBlockToRead = this->begin();
|
|
|
|
currentReadSize = 0;
|
|
|
|
currentReadBlockSizeCached = 0;
|
|
|
|
lastBlockToReadSize = 0;
|
|
|
|
for(typename IndexedRingMemoryArray<T>::Iterator it = this->begin();it!=this->end();++it){
|
|
|
|
it->setSize(0);
|
|
|
|
it->setStoredPackets(0);
|
|
|
|
(*typeResetFnc)(it->modifyIndexType());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void resetBlock(typename IndexedRingMemoryArray<T>::Iterator it,void (*typeResetFnc)(T*)){
|
|
|
|
it->setSize(0);
|
|
|
|
it->setStoredPackets(0);
|
|
|
|
(*typeResetFnc)(it->modifyIndexType());
|
|
|
|
}
|
|
|
|
|
2020-03-19 12:38:11 +01:00
|
|
|
/**
|
2018-07-12 16:29:32 +02:00
|
|
|
* Reading
|
2020-03-19 12:38:11 +01:00
|
|
|
* @param it
|
2018-07-12 16:29:32 +02:00
|
|
|
*/
|
|
|
|
void setCurrentReadBlock(typename IndexedRingMemoryArray<T>::Iterator it){
|
|
|
|
currentReadBlock = it;
|
|
|
|
currentReadBlockSizeCached = it->getSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void resetRead(){
|
|
|
|
currentReadBlock = this->begin();
|
|
|
|
currentReadSize = 0;
|
|
|
|
currentReadBlockSizeCached = this->begin()->getSize();
|
|
|
|
lastBlockToRead = currentWriteBlock;
|
|
|
|
lastBlockToReadSize = currentWriteBlock->getSize();
|
|
|
|
}
|
2020-03-19 12:38:11 +01:00
|
|
|
|
2018-07-12 16:29:32 +02:00
|
|
|
/**
|
|
|
|
* Sets the last block to read to this iterator.
|
|
|
|
* Can be used to dump until block x
|
|
|
|
* @param it The iterator for the last read block
|
|
|
|
*/
|
|
|
|
void setLastBlockToRead(typename IndexedRingMemoryArray<T>::Iterator it){
|
|
|
|
lastBlockToRead = it;
|
|
|
|
lastBlockToReadSize = it->getSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the read pointer to the first written Block, which is the first non empty block in front of the write block
|
|
|
|
* Can be the currentWriteBlock as well
|
|
|
|
*/
|
|
|
|
void readOldest(){
|
|
|
|
resetRead();
|
|
|
|
currentReadBlock = getNextNonEmptyBlock();
|
|
|
|
currentReadBlockSizeCached = currentReadBlock->getSize();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the current read iterator to the next Block and resets the current read size
|
|
|
|
* The current size of the block will be cached to avoid race condition between write and read
|
|
|
|
* If the end of the ring is reached the read pointer will be set to the begin
|
|
|
|
*/
|
|
|
|
void readNext(){
|
|
|
|
currentReadSize = 0;
|
|
|
|
if((this->size != 0) && (currentReadBlock.value ==this->back())){
|
|
|
|
currentReadBlock = this->begin();
|
|
|
|
}else{
|
|
|
|
currentReadBlock++;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentReadBlockSizeCached = currentReadBlock->getSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the address which is currently read from
|
|
|
|
* @return Address to read from
|
|
|
|
*/
|
|
|
|
uint32_t getCurrentReadAddress() const {
|
|
|
|
return getAddressOfCurrentReadBlock() + currentReadSize;
|
|
|
|
}
|
2020-03-19 12:38:11 +01:00
|
|
|
|
2018-07-12 16:29:32 +02:00
|
|
|
/**
|
2020-03-19 12:38:11 +01:00
|
|
|
* Adds readSize to the current size and checks if the read has no more data
|
|
|
|
* left and advances the read block.
|
2018-07-12 16:29:32 +02:00
|
|
|
* @param readSize The size that was read
|
|
|
|
* @return Returns true if the read can go on
|
|
|
|
*/
|
|
|
|
bool addReadSize(uint32_t readSize) {
|
2020-03-19 12:38:11 +01:00
|
|
|
if(currentReadBlock == lastBlockToRead) {
|
2018-07-12 16:29:32 +02:00
|
|
|
//The current read block is the last to read
|
2020-03-19 12:38:11 +01:00
|
|
|
if((currentReadSize+readSize)<lastBlockToReadSize) {
|
2018-07-12 16:29:32 +02:00
|
|
|
//the block has more data -> return true
|
|
|
|
currentReadSize += readSize;
|
|
|
|
return true;
|
2020-03-19 12:38:11 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-07-12 16:29:32 +02:00
|
|
|
//Reached end of read -> return false
|
|
|
|
currentReadSize = lastBlockToReadSize;
|
|
|
|
return false;
|
|
|
|
}
|
2020-03-19 12:38:11 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-07-12 16:29:32 +02:00
|
|
|
//We are not in the last Block
|
2020-03-19 12:38:11 +01:00
|
|
|
if((currentReadSize + readSize)<currentReadBlockSizeCached) {
|
2018-07-12 16:29:32 +02:00
|
|
|
//The current Block has more data
|
|
|
|
currentReadSize += readSize;
|
|
|
|
return true;
|
2020-03-19 12:38:11 +01:00
|
|
|
}
|
|
|
|
// TODO: Maybe some logic blocks should be extracted
|
|
|
|
else {
|
2018-07-12 16:29:32 +02:00
|
|
|
//The current block is written completely
|
|
|
|
readNext();
|
2020-03-19 12:38:11 +01:00
|
|
|
if(currentReadBlockSizeCached==0) {
|
2018-07-12 16:29:32 +02:00
|
|
|
//Next block is empty
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator it(currentReadBlock);
|
|
|
|
//Search if any block between this and the last block is not empty
|
|
|
|
for(;it!=lastBlockToRead;++it){
|
|
|
|
if(it == this->end()){
|
|
|
|
//This is the end, next block is the begin
|
|
|
|
it = this->begin();
|
|
|
|
if(it == lastBlockToRead){
|
|
|
|
//Break if the begin is the lastBlockToRead
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(it->getSize()!=0){
|
|
|
|
//This is a non empty block. Go on reading with this block
|
|
|
|
currentReadBlock = it;
|
|
|
|
currentReadBlockSizeCached = it->getSize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//reached lastBlockToRead and every block was empty, check if the last block is also empty
|
|
|
|
if(lastBlockToReadSize!=0){
|
|
|
|
//go on with last Block
|
|
|
|
currentReadBlock = lastBlockToRead;
|
|
|
|
currentReadBlockSizeCached = lastBlockToReadSize;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
//There is no non empty block left
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
//Size is larger than 0
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
uint32_t getRemainigSizeOfCurrentReadBlock() const{
|
|
|
|
if(currentReadBlock == lastBlockToRead){
|
|
|
|
return (lastBlockToReadSize - currentReadSize);
|
|
|
|
}else{
|
|
|
|
return (currentReadBlockSizeCached - currentReadSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getAddressOfCurrentReadBlock() const {
|
|
|
|
return currentReadBlock->getBlockStartAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the next non empty Block after the current write block,
|
|
|
|
* @return Returns the iterator to the block. If there is non, the current write block is returned
|
|
|
|
*/
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator getNextNonEmptyBlock() const {
|
|
|
|
for(typename IndexedRingMemoryArray<T>::Iterator it = getNextWrite();it!=currentWriteBlock;++it){
|
|
|
|
if(it == this->end()){
|
|
|
|
it = this->begin();
|
|
|
|
if(it == currentWriteBlock){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(it->getSize()!=0){
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return currentWriteBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a copy of the oldest Index type
|
|
|
|
* @return Type of Index
|
|
|
|
*/
|
|
|
|
T* getOldest(){
|
|
|
|
return (getNextNonEmptyBlock()->modifyIndexType());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Writing
|
|
|
|
*/
|
|
|
|
uint32_t getAddressOfCurrentWriteBlock() const{
|
|
|
|
return currentWriteBlock->getBlockStartAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getSizeOfCurrentWriteBlock() const{
|
|
|
|
return currentWriteBlock->getSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getCurrentWriteAddress() const{
|
|
|
|
return getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void clearCurrentWriteBlock(){
|
|
|
|
currentWriteBlock->setSize(0);
|
|
|
|
currentWriteBlock->setStoredPackets(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void addCurrentWriteBlock(uint32_t size, uint32_t storedPackets){
|
|
|
|
currentWriteBlock->addSize(size);
|
|
|
|
currentWriteBlock->addStoredPackets(storedPackets);
|
|
|
|
}
|
|
|
|
|
|
|
|
T* modifyCurrentWriteBlockIndexType(){
|
|
|
|
return currentWriteBlock->modifyIndexType();
|
|
|
|
}
|
2020-03-19 12:38:11 +01:00
|
|
|
|
2018-07-12 16:29:32 +02:00
|
|
|
void updatePreviousWriteSize(uint32_t size, uint32_t storedPackets){
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator it = getPreviousBlock(currentWriteBlock);
|
|
|
|
it->addSize(size);
|
|
|
|
it->addStoredPackets(storedPackets);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the block has enough space for sizeToWrite
|
|
|
|
* @param sizeToWrite The data to be written in the Block
|
|
|
|
* @return Returns true if size to write is smaller the remaining size of the block
|
|
|
|
*/
|
|
|
|
bool hasCurrentWriteBlockEnoughSpace(uint32_t sizeToWrite){
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator next = getNextWrite();
|
|
|
|
uint32_t addressOfNextBlock = next->getBlockStartAddress();
|
2020-03-19 12:38:11 +01:00
|
|
|
uint32_t availableSize =
|
|
|
|
( ( addressOfNextBlock + totalSize ) -
|
|
|
|
(getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock()))
|
|
|
|
% totalSize;
|
2018-07-12 16:29:32 +02:00
|
|
|
return (sizeToWrite < availableSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the store is full if overwrite old is false
|
|
|
|
* @return Returns true if it is writeable and false if not
|
|
|
|
*/
|
|
|
|
bool isNextBlockWritable(){
|
|
|
|
//First check if this is the end of the list
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator next;
|
|
|
|
next = getNextWrite();
|
|
|
|
if((next->getSize()!=0) && (!overwriteOld)){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates current write Block Index Type
|
|
|
|
* @param infoOfNewBlock
|
|
|
|
*/
|
|
|
|
void updateCurrentBlock(T* infoOfNewBlock){
|
|
|
|
currentWriteBlock->setIndexType(infoOfNewBlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Succeed to next block, returns FAILED if overwrite is false and the store is full
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
ReturnValue_t writeNext(){
|
|
|
|
//Check Next Block
|
|
|
|
if(!isNextBlockWritable()){
|
|
|
|
//The Index is full and does not overwrite old
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
//Next block can be written, update Metadata
|
|
|
|
currentWriteBlock = getNextWrite();
|
|
|
|
currentWriteBlock->setSize(0);
|
|
|
|
currentWriteBlock->setStoredPackets(0);
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serializes the Index and calculates the CRC.
|
|
|
|
* Parameters according to HasSerializeIF
|
|
|
|
* @param buffer
|
|
|
|
* @param size
|
|
|
|
* @param max_size
|
|
|
|
* @param bigEndian
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
|
|
|
const uint32_t max_size, bool bigEndian) const{
|
|
|
|
uint8_t* crcBuffer = *buffer;
|
|
|
|
uint32_t oldSize = *size;
|
|
|
|
if(additionalInfo!=NULL){
|
|
|
|
additionalInfo->serialize(buffer,size,max_size,bigEndian);
|
|
|
|
}
|
|
|
|
ReturnValue_t result = currentWriteBlock->serialize(buffer,size,max_size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
result = AutoSerializeAdapter::serialize(&this->size,buffer,size,max_size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t i = 0;
|
|
|
|
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) {
|
|
|
|
result = SerializeAdapter<Index<T> >::serialize(&this->entries[i], buffer, size,
|
|
|
|
max_size, bigEndian);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
uint16_t crc = Calculate_CRC(crcBuffer,(*size-oldSize));
|
|
|
|
result = AutoSerializeAdapter::serialize(&crc,buffer,size,max_size,bigEndian);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the serialized Size of the index
|
|
|
|
* @return The serialized size of the index
|
|
|
|
*/
|
2020-04-05 21:54:11 +02:00
|
|
|
size_t getSerializedSize() const {
|
2018-07-12 16:29:32 +02:00
|
|
|
|
2020-04-05 21:54:11 +02:00
|
|
|
size_t size = 0;
|
2018-07-12 16:29:32 +02:00
|
|
|
if(additionalInfo!=NULL){
|
|
|
|
size += additionalInfo->getSerializedSize();
|
|
|
|
}
|
|
|
|
size += currentWriteBlock->getSerializedSize();
|
|
|
|
size += AutoSerializeAdapter::getSerializedSize(&this->size);
|
|
|
|
size += (this->entries[0].getSerializedSize()) * this->size;
|
|
|
|
uint16_t crc = 0;
|
|
|
|
size += AutoSerializeAdapter::getSerializedSize(&crc);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* DeSerialize the Indexed Ring from a buffer, deSerializes the current write iterator
|
|
|
|
* CRC Has to be checked before!
|
|
|
|
* @param buffer
|
|
|
|
* @param size
|
|
|
|
* @param bigEndian
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
|
|
|
|
ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
|
|
|
bool bigEndian){
|
|
|
|
|
|
|
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
|
|
if(additionalInfo!=NULL){
|
|
|
|
result = additionalInfo->deSerialize(buffer,size,bigEndian);
|
|
|
|
}
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Index<T> tempIndex;
|
|
|
|
result = tempIndex.deSerialize(buffer,size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
uint32_t tempSize = 0;
|
|
|
|
result = AutoSerializeAdapter::deSerialize(&tempSize,buffer,size,bigEndian);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
if(this->size != tempSize){
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
uint32_t i = 0;
|
|
|
|
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) {
|
|
|
|
result = SerializeAdapter<Index<T> >::deSerialize(
|
|
|
|
&this->entries[i], buffer, size,
|
|
|
|
bigEndian);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator cmp(&tempIndex);
|
|
|
|
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
|
|
if(*(cmp.value) == *(it.value)){
|
|
|
|
currentWriteBlock = it;
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Reached if current write block iterator is not found
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getIndexAddress() const {
|
|
|
|
return indexAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Statistics
|
|
|
|
*/
|
|
|
|
uint32_t getStoredPackets() const {
|
|
|
|
uint32_t size = 0;
|
|
|
|
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
|
|
size += it->getStoredPackets();
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getTotalSize() const {
|
|
|
|
return totalSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getCurrentSize() const{
|
|
|
|
uint32_t size = 0;
|
|
|
|
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
|
|
size += it->getSize();
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isEmpty() const{
|
|
|
|
return getCurrentSize()==0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double getPercentageFilled() const{
|
|
|
|
uint32_t filledSize = 0;
|
|
|
|
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
|
|
filledSize += it->getSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
return (double)filledSize/(double)this->totalSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator getCurrentWriteBlock() const{
|
|
|
|
return currentWriteBlock;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get the next block of the currentWriteBlock.
|
|
|
|
* Returns the first one if currentWriteBlock is the last one
|
|
|
|
* @return Iterator pointing to the next block after currentWriteBlock
|
|
|
|
*/
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator getNextWrite() const{
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator next(currentWriteBlock);
|
|
|
|
if((this->size != 0) && (currentWriteBlock.value == this->back())){
|
|
|
|
next = this->begin();
|
|
|
|
}else{
|
|
|
|
++next;
|
|
|
|
}
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get the block in front of the Iterator
|
|
|
|
* Returns the last block if it is the first block
|
|
|
|
* @param it iterator which you want the previous block from
|
|
|
|
* @return pointing to the block before it
|
|
|
|
*/
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator getPreviousBlock(typename IndexedRingMemoryArray<T>::Iterator it) {
|
|
|
|
if(this->begin() == it){
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator next((this->back()));
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator next(it);
|
|
|
|
--next;
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
//The total size used by the blocks (without index)
|
|
|
|
uint32_t totalSize;
|
|
|
|
|
|
|
|
//The address of the index
|
|
|
|
const uint32_t indexAddress;
|
|
|
|
|
|
|
|
//The iterators for writing and reading
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator currentWriteBlock;
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator currentReadBlock;
|
|
|
|
|
|
|
|
//How much of the current read block is read already
|
|
|
|
uint32_t currentReadSize;
|
|
|
|
|
|
|
|
//Cached Size of current read block
|
|
|
|
uint32_t currentReadBlockSizeCached;
|
|
|
|
|
|
|
|
//Last block of current write (should be write block)
|
|
|
|
typename IndexedRingMemoryArray<T>::Iterator lastBlockToRead;
|
|
|
|
//current size of last Block to read
|
|
|
|
uint32_t lastBlockToReadSize;
|
|
|
|
|
|
|
|
//Additional Info to be serialized with the index
|
|
|
|
SerializeIF* additionalInfo;
|
|
|
|
|
|
|
|
//Does it overwrite old blocks?
|
|
|
|
const bool overwriteOld;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ */
|