Hey,
i just finished work on a Element based FiFo Buffer in C.
Layout of this question:
- Intro
- .h File
- .c File
- Usage Example
- Intended Use-cases
- Question
.h File
#ifndef Std_FiFo_LINEARBUFFER
#define Std_FiFo_LINEARBUFFER
#include <stdint.h> //Include for the UIntXX_t types
#ifdef __cplusplus
extern "C"
{
#endif
/// <summary>
/// Typedef used as handle to the Linear buffer entity used
/// </summary>
typedef volatile uint32_t t_Std_FiFo_LinearBuffer_BufferHandle;
/// <summary>
/// Typedef is used as a Handle for a single Element in the Buffer
/// </summary>
typedef volatile uint32_t t_Std_FiFo_LinearBuffer_ElementHandle;
/// <summary>
/// Used as nullpointer
/// </summary>
extern t_Std_FiFo_LinearBuffer_BufferHandle
c_Std_FiFo_LinearBuffer_NullBufferHandle;
/// <summary>
/// Used as nullpointer
/// </summary>
extern t_Std_FiFo_LinearBuffer_ElementHandle
c_Std_FiFo_LinearBuffer_NullElementHandle;
/// <summary>
/// Used as Nullpointer for Data elements or data fields in the buffer
/// </summary>
extern uint32_t* const c_Std_FiFo_LinearBuffer_NullDataPointer;
/// <summary>
/// Call to initiliaze the Buffer struct
///
/// Configures the initial state of the object handle and the
/// passed raw buffer. Must be called prior to any other calls.
/// </summary>
/// <param name="HandleForStruct">The pointer to the struct to
/// initialize</param> <returns>1 if possible, 0 if not</returns>
uint8_t Std_FiFo_LinearBuffer_Initiliaze(
t_Std_FiFo_LinearBuffer_BufferHandle* const HandleForStruct);
/// <summary>
/// Call to invalidate the Buffer struct
///
/// The pointer passed is invalidated aswell (0)
/// </summary>
/// <param name="HandleForStruct">The pointer to the struct to
/// initialize</param> <returns>1 if possible, 0 if not</returns>
uint8_t Std_FiFo_LinearBuffer_Invalidate(
t_Std_FiFo_LinearBuffer_BufferHandle* const HandleForStruct);
/// <summary>
/// Checks if a number of data can be put into the buffer
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="NumberOfU32s">The Number of U32s that should be put</param>
/// <returns>0x01 if can put, 0x00 if not</returns>
uint8_t Std_FiFo_LinearBuffer_CanPut(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t NumberOfU32s);
/// <summary>
/// Checks if one can remove data from the buffer
/// Does not allow to take locked head
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <returns>0x01 if can take, 0x00 if not</returns>
uint8_t Std_FiFo_LinearBuffer_CanTake(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct);
/// <summary>
/// Removes the first element from the buffer
/// without copying the data
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <returns>0x01 if possible, 0x00 if not</returns>
uint8_t Std_FiFo_LinearBuffer_Pop(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct);
/// <summary>
/// Takes data from the buffer and removes the first element
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="BufferToCopyTo">THe buffer to copy the data to</param>
/// <param name="NumberOfU32s">The Number of U32s that should be taken. If 0,
/// then entire buffer is copied</param> <returns>0x01 if possible, 0x00 if
/// not</returns>
uint8_t Std_FiFo_LinearBuffer_Take(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyTo, uint32_t NumberOfU32s);
/// <summary>
/// Checks if a number of data can be put into the buffer
/// and the puts them into the buffer
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="BufferToCopyFrom">THe buffer to copy the data from</param>
/// <param name="NumberOfU32s">The Number of U32s that should be put</param>
/// <returns>0x01 if possible, 0x00 if not</returns>
uint8_t Std_FiFo_LinearBuffer_Put(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyFrom, uint32_t NumberOfU32s);
/// <summary>
/// Checks if a number of data can be put into the buffer
/// and the puts them into the buffer
///
/// Puts the Item to the Top of the buffer
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="BufferToCopyFrom">THe buffer to copy the data from</param>
/// <param name="NumberOfU32s">The Number of U32s that should be put</param>
/// <returns>0x01 if possible, 0x00 if not</returns>
uint8_t Std_FiFo_LinearBuffer_PutTop(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyFrom, uint32_t NumberOfU32s);
/// <summary>
/// Takes data from the buffer, but does not remove the element
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="BufferToCopyTo">THe buffer to copy the data to</param>
/// <param name="NumberOfU32s">The Number of U32s that should be taken. If 0,
/// then entire buffer is copied</param> <returns>0x01 if possible, 0x00 if
/// not</returns>
uint8_t Std_FiFo_LinearBuffer_Peek(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyTo, uint32_t NumberOfU32s);
/// <summary>
/// Allocates a new element and returns a pointer to the raw data section
/// User is responsible for writing too much data
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="NumberOfU32s">The number of elements to feed. If to big or 0,
/// *(0) is returned</param> <returns>Handle to the Element or
/// c_Std_FiFo_LinearBuffer_NullElementHandle</returns>
uint8_t Std_FiFo_LinearBuffer_PutElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement,
uint32_t NumberOfU32s);
/// <summary>
/// Allocates a new element and returns a pointer to the raw data section
/// User is responsible for writing too much data
///
/// Puts the element to the top
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="NumberOfU32s">The number of elements to feed. If to big or 0,
/// *(0) is returned</param> <returns>Handle to the Element or
/// c_Std_FiFo_LinearBuffer_NullElementHandle</returns>
uint8_t Std_FiFo_LinearBuffer_PutTopElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement,
uint32_t NumberOfU32s);
/// <summary>
/// Returns a pointer to the raw data of the first element
/// Locks the element for take
/// Must call release before take or Pop
/// </summary>
/// <param name="HandleForStruct">The pointer to the fifo struct</param>
/// <param name="NumberOfU32s">THe number of U32s the user wants to use. If
/// not possible (= or too big), return is *(0)</param> <returns>Handle to the
/// Element or c_Std_FiFo_LinearBuffer_NullElementHandle</returns>
uint8_t Std_FiFo_LinearBuffer_PeekElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement,
uint32_t NumberOfU32s);
/// <summary>
/// Releases the Lock on the data
///
/// The passed handle to the element is destroyed in the process
/// </summary>
/// <param name="HandleForStruct">The pointer to the element struct</param>
/// <returns>1 if success, 0 if not</returns>
uint8_t Std_FiFo_LinearBuffer_ReleaseElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement);
#ifdef __cplusplus
}
#endif
#endif
.c File
#include "Std_FiFo_LinearBuffer.h"
#include <malloc.h>
#pragma region Static variables
/// <summary>
/// Variable used as internal NULLPTR
/// </summary>
static struct Std_FiFo_LinearBuffer
* const c_Std_FiFo_LinearBuffer_NullBufferHandlePointer
= (struct Std_FiFo_LinearBuffer* const)(0x00000000);
/// <summary>
/// Variable used as internal NULLPTR
/// </summary>
static struct Std_FiFo_LinearBuffer_Element
* const c_Std_FiFo_LinearBuffer_NullElementHandlePointer
= (struct Std_FiFo_LinearBuffer_Element* const)(0x00000000);
enum
{
/// <summary>
/// Configures the maximum number of elements in the buffer
/// Each element can be the maximum of the buffer size or just a single data
/// item However, no more than this number of elements are able to be managed
/// </summary>
c_Std_FiFo_LinearBuffer_MaxNumberOfElementsInBuffer = 16,
/// <summary>
/// Configures the number of U32s in the RAM Buffer
/// This is the entire raw ram buffer used to store the data
/// </summary>
c_Std_FiFo_LinearBuffer_RamBufferSizeInU32 = 1024
};
/// <summary>
/// Used as Internal True
/// </summary>
static const uint8_t c_Std_FiFo_LinearBuffer_True = (uint8_t)(0x01);
/// <summary>
/// Used as Internal False
/// </summary>
static const uint8_t c_Std_FiFo_LinearBuffer_False = (uint8_t)(0x00);
/// <summary>
/// Used as nullpointer
/// </summary>
static t_Std_FiFo_LinearBuffer_BufferHandle
c_Std_FiFo_LinearBuffer_NullBufferHandle
= (t_Std_FiFo_LinearBuffer_BufferHandle)(0x00000000);
/// <summary>
/// Used as nullpointer
/// </summary>
static t_Std_FiFo_LinearBuffer_ElementHandle
c_Std_FiFo_LinearBuffer_NullElementHandle
= (t_Std_FiFo_LinearBuffer_ElementHandle)(0x00000000);
/// <summary>
/// Used as Nullpointer for Data elements or data fields in the buffer
/// </summary>
static uint32_t* const c_Std_FiFo_LinearBuffer_NullDataPointer
= (uint32_t* const)(0x00000000);
#pragma endregion
#pragma region Struct definition
/// <summary>
/// Stores the status of the fifo
/// </summary>
struct Std_FiFo_LinearBuffer_Status
{
/// <summary>
/// Is configured Flag for the Struct
/// Is set in the initialization call.
/// Can not Put to/take from the buffer
/// unless the init call was performed
/// </summary>
uint32_t IsInitialized;
/// <summary>
/// The Current index in the circular Info struct allocation logic.
/// This is a rollover direct index into the
/// InfoElement Array. Everytime a new elemnt is allocated,
/// this index is incremented and if required rolled over
/// </summary>
uint32_t InfoStructAllocationIndex;
/// <summary>
/// The Current Number of elements in the Buffer
/// This indicates the number of elements currently in the buffer
/// User can not put to the fifo, if threshold is reached
/// </summary>
uint32_t NumberOfElements;
/// <summary>
/// Stores the current number of U32s stored in the buffer
/// This is the ammount of payload data currently residing in the buffer
/// </summary>
uint32_t NumberOfU32s;
/// <summary>
/// THe number of U32 slots left at the end of the buffer
/// This number indicates, how many free data slots are available at the end
/// of the buffer If all elements are taken from the buffer, this watermark is
/// reset to represent the full buffer size again
/// </summary>
uint32_t TailSizeU32s;
/// <summary>
/// Current buffer for allocation in the linear ram buffer
/// This pointer points to the first free slot at the end of the raw ram
/// buffer It is used to write to the data buffer and is incremented on write.
/// If all elements are taken, the pointer is reset to the buffer start
/// </summary>
uint32_t* CurrentAllocationPtr;
};
/// <summary>
/// Struct used to store information about the individual elements in the buffer
/// </summary>
struct Std_FiFo_LinearBuffer_Element
{
/// <summary>
/// POinter to the data start address of the data section occupied by the
/// element
/// </summary>
uint32_t* AbsStartAdr;
/// <summary>
/// Indicates if the current Element is locked (e.g. handle is available)
/// </summary>
uint32_t IsLocked;
/// <summary>
/// Number of U32s in the Buffer space for this element
/// </summary>
uint32_t NumElements;
};
/// <summary>
/// Struct represents the datatype used for an 4KB buffer with 16 Elements
/// </summary>
struct Std_FiFo_LinearBuffer
{
/// <summary>
/// Stores the status of the fifo
/// </summary>
struct Std_FiFo_LinearBuffer_Status Info;
/// <summary>
/// The Infos on the actual Elements
/// </summary>
struct Std_FiFo_LinearBuffer_Element
ElementInfos[c_Std_FiFo_LinearBuffer_MaxNumberOfElementsInBuffer];
/// <summary>
/// Stores the pointer mapping table for the elements
/// </summary>
struct Std_FiFo_LinearBuffer_Element
* ElementMapping[c_Std_FiFo_LinearBuffer_MaxNumberOfElementsInBuffer];
/// <summary>
/// The Actual RAM buffer used for the FIFO
/// </summary>
uint32_t RamBuffer[c_Std_FiFo_LinearBuffer_RamBufferSizeInU32];
};
#pragma endregion
#pragma region PrivateHelpers
/// <summary>
/// Creates a pointer to a struct for a given U32 Address
/// Checks if address is 0 or 0XF...F to make sure pointer is valid
/// </summary>
/// <param name="address">The absolute address to point to</param>
/// <returns>Returns (0) if not valid, otherwise the pointer to the
/// struct</returns>
static struct Std_FiFo_LinearBuffer* const
priv_GetBufferHandlePtrFromU32AddressAndValidate(
t_Std_FiFo_LinearBuffer_BufferHandle address)
{
if (address != 0 && address != 0xFFFFFFFF)
return (struct Std_FiFo_LinearBuffer* const)(address);
else
return c_Std_FiFo_LinearBuffer_NullBufferHandlePointer;
}
/// <summary>
/// Creates a pointer to a struct for a given U32 Address
/// Checks if address is 0 or 0XF...F to make sure pointer is valid
/// </summary>
/// <param name="address">The absolute address to point to</param>
/// <returns>Returns (0) if not valid, otherwise the pointer to the
/// struct</returns>
static uint8_t
priv_GetElementHandlePtrFromU32AddressAndValidate(
struct Std_FiFo_LinearBuffer* const ptr,
struct Std_FiFo_LinearBuffer_Element** ptrEle,
t_Std_FiFo_LinearBuffer_ElementHandle* HandleToElement)
{
// Loop all Elements and check if one with a fitting start address can be
// found If so, return Success - if not return error
for (uint32_t i = 0; i < ptr->Info.NumberOfElements; i++)
{
if ((uint32_t)ptr->ElementMapping[i]->AbsStartAdr == *HandleToElement)
{
// Set pointer and return success
*ptrEle = ptr->ElementMapping[i];
return c_Std_FiFo_LinearBuffer_True;
}
}
return c_Std_FiFo_LinearBuffer_False;
}
/// <summary>
/// Copies data from src to dest
/// Does not alter the pointers
/// </summary>
/// <param name="src">src pointer</param>
/// <param name="dst">dst pointer</param>
/// <param name="cnt">number of elements</param>
static void
priv_CopyDataFromTo(uint32_t* const src, uint32_t* const dst, uint32_t cnt)
{
// Make local copy, so the arguments are not altered
uint32_t* srcPtr = src;
uint32_t* destPtr = dst;
for (uint32_t i = 0; i < cnt; i++)
{
*destPtr = *srcPtr;
destPtr++;
srcPtr++;
}
}
/// <summary>
/// Trashes the first most info element and advances the mapping chain
///
/// First, the Number of ElementsIndex and the NumberOfU32s are decremented
/// Then, the Current Info struct is trashed (See buildflag)
/// Afterwards - if there are still elements in the buffer -
/// the buffer mapping chain is advanced
/// If there are no elements left, the internal logic is reset
/// (Head meets tail)
/// </summary>
/// <param name="ptr">The pointer to the fifo struct</param>
static void
priv_TrashInfoStructAndAdvanceMappingForHead(
struct Std_FiFo_LinearBuffer* const ptr)
{
// Update Info struct - always remove all data from data counter
ptr->Info.NumberOfElements--;
ptr->Info.NumberOfU32s -= ptr->ElementMapping[0]->NumElements;
// trash info struct
ptr->ElementMapping[0]->AbsStartAdr = c_Std_FiFo_LinearBuffer_NullDataPointer;
ptr->ElementMapping[0]->NumElements = 0;
ptr->ElementMapping[0]->IsLocked = c_Std_FiFo_LinearBuffer_False;
ptr->ElementMapping[0] = 0;
// Check if Head reached tail - if so, reset logic
if (ptr->Info.NumberOfElements == 0)
{
ptr->Info.NumberOfElements = 0;
ptr->Info.CurrentAllocationPtr = &ptr->RamBuffer[0];
ptr->Info.NumberOfU32s = 0;
ptr->Info.InfoStructAllocationIndex = 0;
ptr->Info.TailSizeU32s = c_Std_FiFo_LinearBuffer_RamBufferSizeInU32;
ptr->ElementMapping[0] = 0;
}
else
{
// Advance info mapping
for (uint32_t i = 0; i < ptr->Info.NumberOfElements; i++)
{
ptr->ElementMapping[i] = ptr->ElementMapping[i + 1];
}
ptr->ElementMapping[ptr->Info.NumberOfElements] = 0;
}
}
/// <summary>
/// Allocates a new element info item
///
/// First, the Element mapping is linked and initialized and the number of
/// elements is incremented Afterwards, the allocation index is incremented and
/// rolled over Then, the NumberOfU32s and the tail size are updated
/// </summary>
/// <param name="ptr">The pointer to the fifo struct</param>
/// <param name="NumberOfU32s">Number of data itmems to allocate for</param>
/// <param name="OnTop">If Flag is 1, the element gets allocated on top</param>
/// <param name="LockedFlag">If to lock element to prevent take. Default is
/// Unlocked</param> <returns>The Alllocation pointer to write the data
/// too</returns>
static uint32_t*
priv_AllocateNewInfoStructElement(struct Std_FiFo_LinearBuffer* const ptr,
uint32_t NumberOfU32s, uint8_t OnTop,
uint8_t LockedFlag)
{
// Check if to allocate on Top
// If not, then allocate the last element in chain
// Otherwise copy chain and then allocate top
if (OnTop == 0)
{
// Allocate current info element
// and put start values
ptr->ElementMapping[ptr->Info.NumberOfElements]
= &ptr->ElementInfos[ptr->Info.InfoStructAllocationIndex];
ptr->ElementMapping[ptr->Info.NumberOfElements]->NumElements
= NumberOfU32s;
ptr->ElementMapping[ptr->Info.NumberOfElements]->AbsStartAdr
= ptr->Info.CurrentAllocationPtr;
ptr->ElementMapping[ptr->Info.NumberOfElements]->IsLocked = LockedFlag;
}
else
{
// Map elements backwards
for (uint32_t i = ptr->Info.NumberOfElements; i > 0; i--)
{
ptr->ElementMapping[i] = ptr->ElementMapping[i - 1];
}
// Allocate current info element
// and put start values
ptr->ElementMapping[0]
= &ptr->ElementInfos[ptr->Info.InfoStructAllocationIndex];
ptr->ElementMapping[0]->NumElements = NumberOfU32s;
ptr->ElementMapping[0]->AbsStartAdr = ptr->Info.CurrentAllocationPtr;
ptr->ElementMapping[0]->IsLocked = LockedFlag;
}
// Always increment elements index
uint32_t* ret = ptr->Info.CurrentAllocationPtr;
ptr->Info.NumberOfElements++;
// Increment and rollover Allocation Index
ptr->Info.InfoStructAllocationIndex++;
if (ptr->Info.InfoStructAllocationIndex
>= c_Std_FiFo_LinearBuffer_MaxNumberOfElementsInBuffer)
{
ptr->Info.InfoStructAllocationIndex = 0;
}
// Update Info struct
ptr->Info.NumberOfU32s += NumberOfU32s;
ptr->Info.TailSizeU32s -= NumberOfU32s;
ptr->Info.CurrentAllocationPtr += NumberOfU32s;
return ret;
}
/// <summary>
/// Computes the maximum allowed number of elements to copy during take
/// </summary>
/// <param name="ptr">The pointer to the fifo struct</param>
/// <param name="NumberOfU32s">The proposed number of elements</param>
/// <returns>IF arg == 0, the maximum number pr info struct is returned
/// Otherwise, The bigger of the two is returned</returns>
static uint32_t
priv_GetMaxNumOfValidDataForCopyOnTake(struct Std_FiFo_LinearBuffer* const ptr,
uint32_t NumberOfU32s)
{
return (NumberOfU32s == 0)
? (ptr->ElementMapping[0]->NumElements)
: ((NumberOfU32s > ptr->ElementMapping[0]->NumElements)
? ptr->ElementMapping[0]->NumElements
: NumberOfU32s);
}
#pragma endregion
uint8_t
Std_FiFo_LinearBuffer_Initiliaze(
t_Std_FiFo_LinearBuffer_BufferHandle* const HandleForStruct)
{
// Check if valid pointer
// if so initialize
// Otherwise return error
struct Std_FiFo_LinearBuffer* const ptr
= (struct Std_FiFo_LinearBuffer* const)(malloc(
sizeof(struct Std_FiFo_LinearBuffer)));
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else
{
// Set Info struct as not-initialized
ptr->Info.IsInitialized = c_Std_FiFo_LinearBuffer_False;
ptr->Info.InfoStructAllocationIndex = 0;
ptr->Info.NumberOfElements = 0;
ptr->Info.NumberOfU32s = 0;
ptr->Info.TailSizeU32s = c_Std_FiFo_LinearBuffer_RamBufferSizeInU32;
ptr->Info.CurrentAllocationPtr = &ptr->RamBuffer[0];
// Rebuild mapping table
for (uint32_t i = 0;
i < c_Std_FiFo_LinearBuffer_MaxNumberOfElementsInBuffer; i++)
{
ptr->ElementInfos[i].AbsStartAdr
= c_Std_FiFo_LinearBuffer_NullDataPointer;
ptr->ElementInfos[i].NumElements = 0;
ptr->ElementInfos[i].IsLocked = c_Std_FiFo_LinearBuffer_False;
ptr->ElementMapping[i] = (struct Std_FiFo_LinearBuffer_Element*)
c_Std_FiFo_LinearBuffer_NullElementHandle;
}
// zerorize Buffer
for (uint32_t i = 0; i < c_Std_FiFo_LinearBuffer_RamBufferSizeInU32; i++)
{
ptr->RamBuffer[i] = 0;
}
// Set as initialized, set handle value and return
ptr->Info.IsInitialized = c_Std_FiFo_LinearBuffer_True;
*HandleForStruct = (t_Std_FiFo_LinearBuffer_BufferHandle)(ptr);
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_Invalidate(
t_Std_FiFo_LinearBuffer_BufferHandle* const HandleForStruct)
{
// Check if pointer exists
// if not return error
// If so, initialize to defaults and reset init flag
// Then invalidate the ptr
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(*HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else
{
ptr->Info.IsInitialized = c_Std_FiFo_LinearBuffer_False;
ptr->Info.InfoStructAllocationIndex = 0;
ptr->Info.NumberOfElements = 0;
ptr->Info.NumberOfU32s = 0;
ptr->Info.TailSizeU32s = 0;
ptr->Info.CurrentAllocationPtr = c_Std_FiFo_LinearBuffer_NullDataPointer;
// Rebuild mapping table
for (uint32_t i = 0;
i < c_Std_FiFo_LinearBuffer_MaxNumberOfElementsInBuffer; i++)
{
ptr->ElementInfos[i].AbsStartAdr
= c_Std_FiFo_LinearBuffer_NullDataPointer;
ptr->ElementInfos[i].NumElements = 0;
ptr->ElementInfos[i].IsLocked = c_Std_FiFo_LinearBuffer_False;
ptr->ElementMapping[i] = (struct Std_FiFo_LinearBuffer_Element*)
c_Std_FiFo_LinearBuffer_NullElementHandle;
}
// zerorize Buffer
for (uint32_t i = 0; i < c_Std_FiFo_LinearBuffer_RamBufferSizeInU32; i++)
{
ptr->RamBuffer[i] = 0;
}
// Invalidate Pointer and return success
*HandleForStruct
= (t_Std_FiFo_LinearBuffer_BufferHandle)(c_Std_FiFo_LinearBuffer_NullDataPointer);
free(ptr);
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_CanPut(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct, uint32_t NumberOfU32s)
{
// Check if struct is intialized and can take elements
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
return ((ptr != c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
&& (ptr->Info.IsInitialized == c_Std_FiFo_LinearBuffer_True)
&& (ptr->Info.NumberOfElements
< c_Std_FiFo_LinearBuffer_MaxNumberOfElementsInBuffer)
&& (ptr->Info.TailSizeU32s > NumberOfU32s))
? c_Std_FiFo_LinearBuffer_True
: c_Std_FiFo_LinearBuffer_False;
}
uint8_t
Std_FiFo_LinearBuffer_CanTake(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct)
{
// Check if struct is initialized and has elements
// Also check if Element is Locked
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
return ((ptr != c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
&& (ptr->Info.IsInitialized == c_Std_FiFo_LinearBuffer_True)
&& (ptr->Info.NumberOfElements > 0)
&& (ptr->ElementMapping[0]->IsLocked == c_Std_FiFo_LinearBuffer_False)
// Safe to access as Number of elements != 0
)
? c_Std_FiFo_LinearBuffer_True
: c_Std_FiFo_LinearBuffer_False;
}
uint8_t
Std_FiFo_LinearBuffer_Pop(t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data, then trash the Head and return success
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanTake(HandleForStruct))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Trash info struct
priv_TrashInfoStructAndAdvanceMappingForHead(ptr);
// Return success;
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_Take(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyTo, uint32_t NumberOfU32s)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data, determine number of U32s to Take and copy data
// Then Update metrics and trash the Head
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanTake(HandleForStruct))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Has data, so copy data from first element in buffer
// If Argument Len is 0, copy all data as per configuration
// otherwise copy the number given per parameter, but a maximum as per
// buffer info
priv_CopyDataFromTo(
ptr->ElementMapping[0]->AbsStartAdr, BufferToCopyTo,
priv_GetMaxNumOfValidDataForCopyOnTake(ptr, NumberOfU32s));
// Trash info struct
priv_TrashInfoStructAndAdvanceMappingForHead(ptr);
// return success
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_Put(t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyFrom,
uint32_t NumberOfU32s)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data, allocate new element and copy data
// Then increment allocation counter and Update metrics
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanPut(HandleForStruct, NumberOfU32s))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Copy data and increment pointer
priv_CopyDataFromTo(BufferToCopyFrom,
priv_AllocateNewInfoStructElement(
ptr, NumberOfU32s, c_Std_FiFo_LinearBuffer_False,
c_Std_FiFo_LinearBuffer_False),
NumberOfU32s);
// Return success
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_PutTop(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyFrom, uint32_t NumberOfU32s)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data, allocate new element and copy data
// Then increment allocation counter and Update metrics
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanPut(HandleForStruct, NumberOfU32s))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Copy data and increment pointer
priv_CopyDataFromTo(BufferToCopyFrom,
priv_AllocateNewInfoStructElement(
ptr, NumberOfU32s, c_Std_FiFo_LinearBuffer_True,
c_Std_FiFo_LinearBuffer_False),
NumberOfU32s);
// Return success
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_Peek(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
uint32_t* const BufferToCopyTo, uint32_t NumberOfU32s)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data, determine number of U32s to copy
// Then copy data and update metrics
// To not Trash head
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanTake(HandleForStruct))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Has data, so copy data from first element in buffer
// If Argument Len is 0, copy all data as per configuration
// otherwise copy the number given per parameter, but a maximum as per
// buffer info
priv_CopyDataFromTo(
ptr->ElementMapping[0]->AbsStartAdr, BufferToCopyTo,
priv_GetMaxNumOfValidDataForCopyOnTake(ptr, NumberOfU32s));
// return success
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_PutElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement,
uint32_t NumberOfU32s)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data allocate new info struct and return the handle
// advance the access pointer and update metrics
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanPut(HandleForStruct, NumberOfU32s))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Get new info struct
priv_AllocateNewInfoStructElement(ptr, NumberOfU32s,
c_Std_FiFo_LinearBuffer_False,
c_Std_FiFo_LinearBuffer_True);
// Return Handle.... -1 safe here, as element was created before hand
// is necessary as index was incremented
*HandleToElement
= (t_Std_FiFo_LinearBuffer_ElementHandle)(ptr->ElementMapping
[ptr->Info
.NumberOfElements
- 1]
->AbsStartAdr);
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_PutTopElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement,
uint32_t NumberOfU32s)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data allocate new info struct and return the handle
// advance the access pointer and update metrics
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanPut(HandleForStruct, NumberOfU32s))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Get new info struct
priv_AllocateNewInfoStructElement(ptr, NumberOfU32s,
c_Std_FiFo_LinearBuffer_True,
c_Std_FiFo_LinearBuffer_True);
// Return handle - Element was put to the Top sor eturn top element
*HandleToElement
= (t_Std_FiFo_LinearBuffer_ElementHandle)(ptr->ElementMapping[0]
->AbsStartAdr);
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_PeekElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement,
uint32_t NumberOfU32s)
{
// Get pointer to work with and check that is valid
// Then check if buffer has data. If not, just return error
// If has data return the data pointer
// Do not trash the head
// But lock the element
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!Std_FiFo_LinearBuffer_CanTake(HandleForStruct))
return c_Std_FiFo_LinearBuffer_False;
else if (ptr->ElementMapping[0]->NumElements >= NumberOfU32s)
return c_Std_FiFo_LinearBuffer_False;
else
{
// Lock head element
ptr->ElementMapping[0]->IsLocked = c_Std_FiFo_LinearBuffer_True;
// Return handle
*HandleToElement
= (t_Std_FiFo_LinearBuffer_ElementHandle)(ptr->ElementMapping[0]
->AbsStartAdr);
return c_Std_FiFo_LinearBuffer_True;
}
}
uint8_t
Std_FiFo_LinearBuffer_ReleaseElement(
t_Std_FiFo_LinearBuffer_BufferHandle HandleForStruct,
t_Std_FiFo_LinearBuffer_ElementHandle* const HandleToElement)
{
// Get the Pointer to the Element
// and check if exists. If not return error
// If exists, release the lock and invalidate the pointer
struct Std_FiFo_LinearBuffer* const ptr
= priv_GetBufferHandlePtrFromU32AddressAndValidate(HandleForStruct);
struct Std_FiFo_LinearBuffer_Element* ptrEle
= (struct Std_FiFo_LinearBuffer_Element*)(0);
if (ptr == c_Std_FiFo_LinearBuffer_NullBufferHandlePointer)
return c_Std_FiFo_LinearBuffer_False;
else if (!priv_GetElementHandlePtrFromU32AddressAndValidate(ptr, &ptrEle,
HandleToElement))
return c_Std_FiFo_LinearBuffer_False;
else
{
// Unlokc and invalidate the handle
ptrEle->IsLocked = c_Std_FiFo_LinearBuffer_False;
*HandleToElement
= (t_Std_FiFo_LinearBuffer_ElementHandle)(c_Std_FiFo_LinearBuffer_NullDataPointer);
return c_Std_FiFo_LinearBuffer_True;
}
}
Example
t_Std_FiFo_LinearBuffer_BufferHandle dsd;
if (Std_FiFo_LinearBuffer_Initiliaze(&dsd)) {
uint32_t buffer[32];
for (int i = 0; i < 8; i++) {
for (int d = 0; d < 32; d++) buffer[d] = d + i;
Std_FiFo_LinearBuffer_Put(dsd, buffer, 32);
}
for (int i = 0; i < 8; i++) {
t_Std_FiFo_LinearBuffer_ElementHandle h;
if (Std_FiFo_LinearBuffer_PutElement(dsd, &h, 32)) {
uint32_t* g = (uint32_t*)(h);
for (int d = 0; d < 32; d++) g[d] = d + i;
Std_FiFo_LinearBuffer_ReleaseElement(dsd,&h);
}
}
/* Do other Work */
}
Std_FiFo_LinearBuffer_Invalidate(&dsd);
Use-Cases
This library is itended to be used for embedded applications. My focus is one:
- Doucpling e.g. communication peripherals from the application code
- Buffering ADC/DAC samples
- Buffering data that is streamed through the system
- you get the idea...
Most of the times, one of these two scenarios will be present:
- ISR allocates element and fills is (e.g. receiving a frame via SPI). Once complete, it releases the element and the "main" grabs it via "take".
- The "main" both "puts" and "takes" - from different modules.
I do not require the code to be ISR/Thread-Safe/Reentrant. This will be done on the user-level.
Question
Now, i have multiple questions:
As Context: I'm currently working on improving the documentation. There still are "copy-paste residues" and incomplete explanations. So it is TBD.
At the top of the .c file i declare multiple constants for use throughout the code. I did this with e.g.
static const uint8_t c_Std_FiFo_LinearBuffer_False = (uint8_t)(0x00);
instead of#define c_Std_FiFo_LinearBuffer_False (uint8_t)(0)
to avoid polluting the codebase with defines. However, i think that this will place the constants into flash - which is not required. What would be a better approach for these constants only required in the .c file shown?In the
static struct Std_FiFo_LinearBuffer* const priv_GetBufferHandlePtrFromU32AddressAndValidate(t_Std_FiFo_LinearBuffer_BufferHandle address);
i try to check, if the absolute address provided to the call can be used as a valid pointer to the astruct Std_FiFo_LinearBuffer
- However, only checking if the address is not 0 or 0xF..F seems a little useless to me. I could of course adapt the ranges to reflect the memory ranges of the specific controller i'm using, but this would make the library non-reuseable. How would i make sure, that the address provided is indeed pointing to a struct in of said type in memory? Should i include a magic-number in the struct and check against it?I would like to hear your suggestions on how to further refactor the code, to make it more maintainable and re-useable.
Which additional features are a must to implement?
To "hide" the internal structs from the user, i choose to make the interface available only through a "handle". This handle is essentially a u32 storing the memory address of the memory instance to be used. I want to avoid the user to be able to access the inner workings of the data structure through the "user-space" reference. Is the way i choose practical or completly pointless? How could it be improved?