1
0
mirror of https://github.com/stargieg/bacnet-stack synced 2025-10-26 23:35:52 +08:00

[r3089] Updated ringbuffer library to remove alloc and include data-peek and data-put.

This commit is contained in:
Steve Karg 2017-01-01 06:20:13 +01:00 committed by Patrick Grimm
parent 25d6d06ad7
commit 7261d40214
2 changed files with 396 additions and 210 deletions

View File

@ -1,82 +1,88 @@
/************************************************************************** /**
* @file
* @author Steve Karg
* @date 2004
* *
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net> * Generic ring buffer library for deeply embedded system.
* * See the unit tests for usage examples.
* 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.
*********************************************************************/
#ifndef RINGBUF_H #ifndef RINGBUF_H
#define RINGBUF_H #define RINGBUF_H
/* Functional Description: Generic ring buffer library for deeply
embedded system. See the unit tests for usage examples. */
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/**
* ring buffer power of two alignment macro
*
* @{
*/
#ifndef NEXT_POWER_OF_2
#define B2(x) ( (x) | ( (x) >> 1) )
#define B4(x) ( B2(x) | ( B2(x) >> 2) )
#define B8(x) ( B4(x) | ( B4(x) >> 4) )
#define B16(x) ( B8(x) | ( B8(x) >> 8) )
#define B32(x) (B16(x) | (B16(x) >>16) )
#define NEXT_POWER_OF_2(x) (B32((x)-1) + 1)
#endif
/** @} */
/**
* ring buffer data structure
*
* @{
*/
struct ring_buffer_t { struct ring_buffer_t {
volatile uint8_t *buffer; /* block of memory or array of data */ /** block of memory or array of data */
unsigned element_size; /* how many bytes for each chunk */ volatile uint8_t *buffer;
unsigned element_count; /* number of chunks of data */ /** how many bytes for each chunk */
volatile unsigned head; /* where the writes go */ unsigned element_size;
volatile unsigned tail; /* where the reads come from */ /** number of chunks of data */
unsigned element_count;
/** where the writes go */
volatile unsigned head;
/** where the reads come from */
volatile unsigned tail;
/* maximum depth reached */
volatile unsigned depth;
}; };
typedef struct ring_buffer_t RING_BUFFER; typedef struct ring_buffer_t RING_BUFFER;
/** @} */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
unsigned Ringbuf_Count( unsigned Ringbuf_Count(RING_BUFFER const *b);
RING_BUFFER const *b); unsigned Ringbuf_Depth(RING_BUFFER const *b);
bool Ringbuf_Full( unsigned Ringbuf_Depth_Reset(RING_BUFFER *b);
RING_BUFFER const *b); unsigned Ringbuf_Size(RING_BUFFER const *b);
bool Ringbuf_Empty( bool Ringbuf_Full(RING_BUFFER const *b);
RING_BUFFER const *b); bool Ringbuf_Empty(RING_BUFFER const *b);
volatile uint8_t *Ringbuf_Peek( /* tail */
RING_BUFFER const *b); volatile uint8_t *Ringbuf_Peek(RING_BUFFER const *b);
bool Ringbuf_Pop( bool Ringbuf_Pop(RING_BUFFER * b,
RING_BUFFER * b,
uint8_t * data_element); uint8_t * data_element);
bool Ringbuf_Put( bool Ringbuf_Put_Front(RING_BUFFER * b,
RING_BUFFER * b, /* ring buffer structure */
uint8_t * data_element); /* one element to add to the ring */
bool Ringbuf_Put_Front(
RING_BUFFER * b, /* ring buffer structure */
uint8_t * data_element); uint8_t * data_element);
volatile uint8_t *Ringbuf_Data_Peek( /* head */
RING_BUFFER * b); bool Ringbuf_Put(RING_BUFFER * b,
bool Ringbuf_Data_Put( uint8_t * data_element);
RING_BUFFER * b, volatile uint8_t *data_element); /* pair of functions to use head memory directly */
volatile uint8_t *Ringbuf_Data_Peek(RING_BUFFER * b);
bool Ringbuf_Data_Put(RING_BUFFER * b, volatile uint8_t *data_element);
/* Note: element_count must be a power of two */ /* Note: element_count must be a power of two */
void Ringbuf_Init( bool Ringbuf_Init(RING_BUFFER * b,
RING_BUFFER * b, /* ring buffer structure */ volatile uint8_t * buffer,
volatile uint8_t * buffer, /* data block or array of data */ unsigned element_size,
unsigned element_size, /* size of one element in the data block */ unsigned element_count);
unsigned element_count); /* number of elements in the data block */
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testRingBufSize16( void testRingBufPowerOfTwo(Test * pTest);
Test * pTest); void testRingBufSizeSmall(Test * pTest);
void testRingBufSize32( void testRingBufSizeLarge(Test * pTest);
Test * pTest); void testRingBufSizeInvalid(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -1,54 +1,64 @@
/*####COPYRIGHTBEGIN#### /**
------------------------------------------- * @file
Copyright (C) 2008 by Steve Karg * @author Steve Karg
* @date 2004
This program is free software; you can redistribute it and/or * @brief Generic ring buffer library for deeply embedded system.
modify it under the terms of the GNU General Public License *
as published by the Free Software Foundation; either version 2 * @section LICENSE
of the License, or (at your option) any later version. *
* This program is free software; you can redistribute it and/or
This program is distributed in the hope that it will be useful, * modify it under the terms of the GNU General Public License
but WITHOUT ANY WARRANTY; without even the implied warranty of * as published by the Free Software Foundation; either version 2
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * of the License, or (at your option) any later version.
GNU General Public License for more details. *
* This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License * but WITHOUT ANY WARRANTY; without even the implied warranty of
along with this program; if not, write to: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
The Free Software Foundation, Inc. * GNU General Public License for more details.
59 Temple Place - Suite 330 *
Boston, MA 02111-1307 * You should have received a copy of the GNU General Public License
USA. * along with this program; if not, write to:
* The Free Software Foundation, Inc.
As a special exception, if other files instantiate templates or * 59 Temple Place - Suite 330
use macros or inline functions from this file, or you compile * Boston, MA 02111-1307
this file and link it with other works to produce a work based * USA.
on this file, this file does not by itself cause the resulting *
work to be covered by the GNU General Public License. However * As a special exception, if other files instantiate templates or
the source code for this file must still be made available in * use macros or inline functions from this file, or you compile
accordance with section (3) of the GNU General Public License. * this file and link it with other works to produce a work based
* on this file, this file does not by itself cause the resulting
This exception does not invalidate any other reasons why a work * work to be covered by the GNU General Public License. However
based on this file might be covered by the GNU General Public * the source code for this file must still be made available in
License. * accordance with section (3) of the GNU General Public License.
------------------------------------------- *
####COPYRIGHTEND####*/ * This exception does not invalidate any other reasons why a work
* based on this file might be covered by the GNU General Public
/* Functional Description: Generic ring buffer library for deeply * License.
embedded system. See the unit tests for usage examples. */ *
* @section DESCRIPTION
*
* Generic ring buffer library for deeply embedded system.
* It uses a data store whose size is a power of 2 (8, 16, 32, 64, ...)
* and doesn't waste any data bytes. It has very low overhead, and
* utilizes modulo for indexing the data in the data store.
* It uses separate variables for consumer and producer so it can
* be used in multithreaded environment.
*
* See the unit tests for usage examples.
*
*/
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "ringbuf.h" #include "ringbuf.h"
/**************************************************************************** /**
* DESCRIPTION: Returns the number of elements in the ring buffer * Returns the number of elements in the ring buffer
* RETURN: Number of elements in the ring buffer *
* ALGORITHM: none * @param b - pointer to RING_BUFFER structure
* NOTES: none * @return Number of elements in the ring buffer
*****************************************************************************/ */
unsigned Ringbuf_Count( unsigned Ringbuf_Count(RING_BUFFER const *b)
RING_BUFFER const *b)
{ {
unsigned head, tail; /* used to avoid volatile decision */ unsigned head, tail; /* used to avoid volatile decision */
@ -61,38 +71,104 @@ unsigned Ringbuf_Count(
return 0; return 0;
} }
/**************************************************************************** /**
* DESCRIPTION: Returns the empty/full status of the ring buffer * Returns the empty/full status of the ring buffer
* RETURN: true if the ring buffer is full, false if it is not. *
* ALGORITHM: none * @param b - pointer to RING_BUFFER structure
* NOTES: none * @return true if the ring buffer is full, false if it is not.
*****************************************************************************/ */
bool Ringbuf_Full( bool Ringbuf_Full(RING_BUFFER const *b)
RING_BUFFER const *b)
{ {
return (b ? (Ringbuf_Count(b) == b->element_count) : true); return (b ? (Ringbuf_Count(b) == b->element_count) : true);
} }
/**************************************************************************** /**
* DESCRIPTION: Returns the empty/full status of the ring buffer * Returns the empty/full status of the ring buffer
* RETURN: true if the ring buffer is empty, false if it is not. *
* ALGORITHM: none * @param b - pointer to RING_BUFFER structure
* NOTES: none * @return true if the ring buffer is empty, false if it is not.
*****************************************************************************/ */
bool Ringbuf_Empty( bool Ringbuf_Empty(RING_BUFFER const *b)
RING_BUFFER const *b)
{ {
return (b ? (Ringbuf_Count(b) == 0) : true); return (b ? (Ringbuf_Count(b) == 0) : true);
} }
/**************************************************************************** /**
* DESCRIPTION: Looks at the data from the front of the list without removing it * Updates the depth tracking in the ring buffer
* RETURN: pointer to the data, or NULL if nothing in the list *
* ALGORITHM: none * @param b - pointer to RING_BUFFER structure
* NOTES: none */
*****************************************************************************/ static void Ringbuf_Depth_Update(RING_BUFFER *b)
volatile uint8_t *Ringbuf_Peek( {
RING_BUFFER const *b) unsigned count;
if (b) {
count = Ringbuf_Count(b);
if (count > b->depth) {
b->depth = count;
}
}
}
/**
* Updates the depth tracking in the ring buffer
*
* @param b - pointer to RING_BUFFER structure
* @return largest number of items that have been in the ring buffer
*/
unsigned Ringbuf_Depth(RING_BUFFER const *b)
{
unsigned depth = 0;
if (b) {
depth = b->depth;
}
return depth;
}
/**
* Resets the depth tracking in the ring buffer
*
* @param b - pointer to RING_BUFFER structure
* @return largest number of items that have been in the ring buffer
*/
unsigned Ringbuf_Depth_Reset(RING_BUFFER *b)
{
unsigned depth = 0;
if (b) {
depth = b->depth;
b->depth = 0;
}
return depth;
}
/**
* Gets the capacity of the ring buffer (number of possible elements)
*
* @param b - pointer to RING_BUFFER structure
* @return largest number of items that have been in the ring buffer
*/
unsigned Ringbuf_Size(RING_BUFFER const *b)
{
unsigned count = 0;
if (b) {
count = b->element_count;
}
return count;
}
/**
* Looks at the data from the head of the list without removing it
*
* @param b - pointer to RING_BUFFER structure
* @return pointer to the data, or NULL if nothing in the list
*/
volatile uint8_t *Ringbuf_Peek(RING_BUFFER const *b)
{ {
volatile uint8_t *data_element = NULL; /* return value */ volatile uint8_t *data_element = NULL; /* return value */
@ -104,14 +180,14 @@ volatile uint8_t *Ringbuf_Peek(
return data_element; return data_element;
} }
/**************************************************************************** /**
* DESCRIPTION: Copy the data from the front of the list, and removes it * Copy the data from the front of the list, and removes it
* RETURN: true if data was copied, false if list is empty *
* ALGORITHM: none * @param b - pointer to RING_BUFFER structure
* NOTES: none * @param data_element - element of data that is loaded with data from ring
*****************************************************************************/ * @return true if data was copied, false if list is empty
bool Ringbuf_Pop( */
RING_BUFFER * b, bool Ringbuf_Pop(RING_BUFFER * b,
uint8_t * data_element) uint8_t * data_element)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
@ -133,16 +209,16 @@ bool Ringbuf_Pop(
return status; return status;
} }
/**************************************************************************** /**
* DESCRIPTION: Adds an element of data to the end of the ring buffer * Adds an element of data to the ring buffer
* RETURN: true on succesful add, false if not added *
* ALGORITHM: none * @param b - pointer to RING_BUFFER structure
* NOTES: none * @param data_element - one element that is copied to the ring buffer
*****************************************************************************/ * @return true on succesful add, false if not added
bool Ringbuf_Put( */
RING_BUFFER * b, /* ring buffer structure */ bool Ringbuf_Put(RING_BUFFER * b,
uint8_t * data_element) uint8_t * data_element)
{ /* one element to add to the ring */ {
bool status = false; /* return value */ bool status = false; /* return value */
volatile uint8_t *ring_data = NULL; /* used to help point ring data */ volatile uint8_t *ring_data = NULL; /* used to help point ring data */
unsigned i; /* loop counter */ unsigned i; /* loop counter */
@ -156,6 +232,7 @@ bool Ringbuf_Put(
ring_data[i] = data_element[i]; ring_data[i] = data_element[i];
} }
b->head++; b->head++;
Ringbuf_Depth_Update(b);
status = true; status = true;
} }
} }
@ -163,18 +240,20 @@ bool Ringbuf_Put(
return status; return status;
} }
/**************************************************************************** /**
* DESCRIPTION: Adds an element of data to the front of the ring buffer * Adds an element of data to the front of the ring buffer
* RETURN: true on succesful add, false if not added *
* ALGORITHM: none * Note that this function moves the tail on add instead of head,
* NOTES: moves the tail on add instead of head, so this function * so this function cannot be used if you are keeping producer and
* can't be used if keeping producer and consumer * consumer as separate processes (i.e. interrupt handlers)
* as separate processes (i.e. interrupts) *
*****************************************************************************/ * @param b - pointer to RING_BUFFER structure
bool Ringbuf_Put_Front( * @param data_element - one element to copy to the front of the ring
RING_BUFFER * b, /* ring buffer structure */ * @return true on succesful add, false if not added
*/
bool Ringbuf_Put_Front(RING_BUFFER * b,
uint8_t * data_element) uint8_t * data_element)
{ /* one element to add to the front of the ring */ {
bool status = false; /* return value */ bool status = false; /* return value */
volatile uint8_t *ring_data = NULL; /* used to help point ring data */ volatile uint8_t *ring_data = NULL; /* used to help point ring data */
unsigned i = 0; /* loop counter */ unsigned i = 0; /* loop counter */
@ -189,6 +268,7 @@ bool Ringbuf_Put_Front(
for (i = 0; i < b->element_size; i++) { for (i = 0; i < b->element_size; i++) {
ring_data[i] = data_element[i]; ring_data[i] = data_element[i];
} }
Ringbuf_Depth_Update(b);
status = true; status = true;
} }
} }
@ -196,13 +276,13 @@ bool Ringbuf_Put_Front(
return status; return status;
} }
/**************************************************************************** /**
* DESCRIPTION: Gets a pointer to the next free data element of the buffer * Gets a pointer to the next free data element of the buffer
* without adding it to the ring. * without adding it to the ring.
* RETURN: pointer to the next data chunk, or NULL if ring buffer is full. *
* ALGORITHM: none * @param b - pointer to RING_BUFFER structure
* NOTES: Use Ringbuf_Data_Peek with Ringbuf_Data_Put * @return pointer to the next data element, or NULL if the list is full
*****************************************************************************/ */
volatile uint8_t *Ringbuf_Data_Peek(RING_BUFFER * b) volatile uint8_t *Ringbuf_Data_Peek(RING_BUFFER * b)
{ {
volatile uint8_t *ring_data = NULL; /* used to help point ring data */ volatile uint8_t *ring_data = NULL; /* used to help point ring data */
@ -218,14 +298,15 @@ volatile uint8_t *Ringbuf_Data_Peek(RING_BUFFER * b)
return ring_data; return ring_data;
} }
/**************************************************************************** /**
* DESCRIPTION: Adds the previously peeked element of data to the end of the * Adds the previously peeked element of data to the end of the
* ring buffer * ring buffer.
* RETURN: true if the buffer has space and the data element points to the *
* @param b - pointer to RING_BUFFER structure
* @param data_element - pointer to the peeked data element
* @return true if the buffer has space and the data element points to the
* same memory previously peeked. * same memory previously peeked.
* ALGORITHM: none */
* NOTES: Use Ringbuf_Data_Peek with Ringbuf_Data_Put
*****************************************************************************/
bool Ringbuf_Data_Put(RING_BUFFER * b, volatile uint8_t *data_element) bool Ringbuf_Data_Put(RING_BUFFER * b, volatile uint8_t *data_element)
{ {
bool status = false; bool status = false;
@ -239,6 +320,7 @@ bool Ringbuf_Data_Put(RING_BUFFER * b, volatile uint8_t *data_element)
if (ring_data == data_element) { if (ring_data == data_element) {
/* same chunk of memory - okay to signal the head */ /* same chunk of memory - okay to signal the head */
b->head++; b->head++;
Ringbuf_Depth_Update(b);
status = true; status = true;
} }
} }
@ -247,28 +329,49 @@ bool Ringbuf_Data_Put(RING_BUFFER * b, volatile uint8_t *data_element)
return status; return status;
} }
/**************************************************************************** /**
* DESCRIPTION: Configures the ring buffer * Test that the parameter is a power of two.
* RETURN: none *
* ALGORITHM: none * @param x unsigned integer value to be tested
* NOTES: *
* element_count must be a power of two * @return true if the parameter is a power of 2
*****************************************************************************/ */
void Ringbuf_Init( static bool isPowerOfTwo (unsigned int x)
RING_BUFFER * b, /* ring buffer structure */ {
volatile uint8_t * buffer, /* data block or array of data */ /* First x in the below expression is for the case when x is 0 */
unsigned element_size, /* size of one element in the data block */ return x && (!(x&(x-1)));
}
/**
* Configures the ring buffer data buffer. Note that the element_count
* parameter must be a power of two.
*
* @param b - pointer to RING_BUFFER structure
* @param buffer - pointer to a data buffer that is used to store the ring data
* @param element_size - size of one element in the data block
* @param element_count - number elements in the data block
*
* @return true if ring buffer was initialized
*/
bool Ringbuf_Init(RING_BUFFER * b,
volatile uint8_t * buffer,
unsigned element_size,
unsigned element_count) unsigned element_count)
{ /* number of elements in the data block */ {
if (b) { bool status = false;
if (b && isPowerOfTwo(element_count)) {
b->head = 0; b->head = 0;
b->tail = 0; b->tail = 0;
b->buffer = buffer; b->buffer = buffer;
b->element_size = element_size; b->element_size = element_size;
b->element_count = element_count; b->element_count = element_count;
/* tuning diagnostics */
b->depth = 0;
status = true;
} }
return; return status;
} }
#ifdef TEST #ifdef TEST
@ -277,9 +380,16 @@ void Ringbuf_Init(
#include <limits.h> #include <limits.h>
#include "ctest.h" #include "ctest.h"
/* test the ring buffer */ /**
static void testRingAroundBuffer( * Unit Test for the ring buffer
Test * pTest, *
* @param pTest - test tracking pointer
* @param test_buffer - pointer to RING_BUFFER structure
* @param data_element - one data element
* @param element_size - size of one data element
* @param element_count - number of data elements in the store
*/
static void testRingAroundBuffer(Test * pTest,
RING_BUFFER * test_buffer, RING_BUFFER * test_buffer,
uint8_t * data_element, uint8_t * data_element,
unsigned element_size, unsigned element_size,
@ -289,39 +399,47 @@ static void testRingAroundBuffer(
unsigned index; unsigned index;
unsigned data_index; unsigned data_index;
unsigned count; unsigned count;
unsigned dummy; uint8_t value;
bool status; bool status;
ct_test(pTest, Ringbuf_Empty(test_buffer)); ct_test(pTest, Ringbuf_Empty(test_buffer));
/* test the ring around the buffer */ /* test the ring around the buffer */
for (index = 0; index < element_count; index++) { for (index = 0; index < element_count; index++) {
for (count = 1; count < 4; count++) { for (count = 1; count < 4; count++) {
dummy = index * count; value = (index * count)%255;
for (data_index = 0; data_index < element_size; data_index++) { for (data_index = 0; data_index < element_size; data_index++) {
data_element[data_index] = dummy; data_element[data_index] = value;
} }
status = Ringbuf_Put(test_buffer, data_element); status = Ringbuf_Put(test_buffer, data_element);
ct_test(pTest, status == true); ct_test(pTest, status == true);
ct_test(pTest, Ringbuf_Count(test_buffer) == count);
} }
for (count = 1; count < 4; count++) { for (count = 1; count < 4; count++) {
dummy = index * count; value = (index * count)%255;
test_data = Ringbuf_Peek(test_buffer); test_data = Ringbuf_Peek(test_buffer);
ct_test(pTest, test_data); ct_test(pTest, test_data);
if (test_data) { if (test_data) {
for (data_index = 0; data_index < element_size; data_index++) { for (data_index = 0; data_index < element_size; data_index++) {
ct_test(pTest, test_data[data_index] == dummy); ct_test(pTest, test_data[data_index] == value);
} }
} }
(void) Ringbuf_Pop(test_buffer, NULL); status = Ringbuf_Pop(test_buffer, NULL);
ct_test(pTest, status == true);
} }
} }
ct_test(pTest, Ringbuf_Empty(test_buffer)); ct_test(pTest, Ringbuf_Empty(test_buffer));
} }
/* test the ring buffer */ /**
static void testRingBuf( * Unit Test for the ring buffer
Test * pTest, *
* @param pTest - test tracking pointer
* @param data_store - buffer to store elements
* @param data_element - one data element
* @param element_size - size of one data element
* @param element_count - number of data elements in the store
*/
static bool testRingBuf(Test * pTest,
uint8_t * data_store, uint8_t * data_store,
uint8_t * data_element, uint8_t * data_element,
unsigned element_size, unsigned element_size,
@ -333,8 +451,13 @@ static void testRingBuf(
unsigned data_index; unsigned data_index;
bool status; bool status;
Ringbuf_Init(&test_buffer, data_store, element_size, element_count); status = Ringbuf_Init(&test_buffer, data_store,
element_size, element_count);
if (!status) {
return false;
}
ct_test(pTest, Ringbuf_Empty(&test_buffer)); ct_test(pTest, Ringbuf_Empty(&test_buffer));
ct_test(pTest, Ringbuf_Depth(&test_buffer) == 0);
for (data_index = 0; data_index < element_size; data_index++) { for (data_index = 0; data_index < element_size; data_index++) {
data_element[data_index] = data_index; data_element[data_index] = data_index;
@ -342,6 +465,7 @@ static void testRingBuf(
status = Ringbuf_Put(&test_buffer, data_element); status = Ringbuf_Put(&test_buffer, data_element);
ct_test(pTest, status == true); ct_test(pTest, status == true);
ct_test(pTest, !Ringbuf_Empty(&test_buffer)); ct_test(pTest, !Ringbuf_Empty(&test_buffer));
ct_test(pTest, Ringbuf_Depth(&test_buffer) == 1);
test_data = Ringbuf_Peek(&test_buffer); test_data = Ringbuf_Peek(&test_buffer);
for (data_index = 0; data_index < element_size; data_index++) { for (data_index = 0; data_index < element_size; data_index++) {
@ -350,6 +474,7 @@ static void testRingBuf(
ct_test(pTest, !Ringbuf_Empty(&test_buffer)); ct_test(pTest, !Ringbuf_Empty(&test_buffer));
(void) Ringbuf_Pop(&test_buffer, NULL); (void) Ringbuf_Pop(&test_buffer, NULL);
ct_test(pTest, Ringbuf_Empty(&test_buffer)); ct_test(pTest, Ringbuf_Empty(&test_buffer));
ct_test(pTest, Ringbuf_Depth(&test_buffer) == 1);
/* fill to max */ /* fill to max */
for (index = 0; index < element_count; index++) { for (index = 0; index < element_count; index++) {
@ -359,7 +484,9 @@ static void testRingBuf(
status = Ringbuf_Put(&test_buffer, data_element); status = Ringbuf_Put(&test_buffer, data_element);
ct_test(pTest, status == true); ct_test(pTest, status == true);
ct_test(pTest, !Ringbuf_Empty(&test_buffer)); ct_test(pTest, !Ringbuf_Empty(&test_buffer));
ct_test(pTest, Ringbuf_Depth(&test_buffer) == (index+1));
} }
ct_test(pTest, Ringbuf_Depth(&test_buffer) == element_count);
/* verify actions on full buffer */ /* verify actions on full buffer */
for (index = 0; index < element_count; index++) { for (index = 0; index < element_count; index++) {
for (data_index = 0; data_index < element_size; data_index++) { for (data_index = 0; data_index < element_size; data_index++) {
@ -368,6 +495,7 @@ static void testRingBuf(
status = Ringbuf_Put(&test_buffer, data_element); status = Ringbuf_Put(&test_buffer, data_element);
ct_test(pTest, status == false); ct_test(pTest, status == false);
ct_test(pTest, !Ringbuf_Empty(&test_buffer)); ct_test(pTest, !Ringbuf_Empty(&test_buffer));
ct_test(pTest, Ringbuf_Depth(&test_buffer) == element_count);
} }
/* check buffer full */ /* check buffer full */
@ -382,6 +510,9 @@ static void testRingBuf(
(void) Ringbuf_Pop(&test_buffer, NULL); (void) Ringbuf_Pop(&test_buffer, NULL);
} }
ct_test(pTest, Ringbuf_Empty(&test_buffer)); ct_test(pTest, Ringbuf_Empty(&test_buffer));
ct_test(pTest, Ringbuf_Depth(&test_buffer) == element_count);
Ringbuf_Depth_Reset(&test_buffer);
ct_test(pTest, Ringbuf_Depth(&test_buffer) == 0);
testRingAroundBuffer(pTest, &test_buffer, data_element, element_size, testRingAroundBuffer(pTest, &test_buffer, data_element, element_size,
element_count); element_count);
@ -393,33 +524,78 @@ static void testRingBuf(
testRingAroundBuffer(pTest, &test_buffer, data_element, element_size, testRingAroundBuffer(pTest, &test_buffer, data_element, element_size,
element_count); element_count);
return; return true;
} }
void testRingBufSize16( /**
Test * pTest) * Unit Test for the ring buffer with 16 data elements
*
* @param pTest - test tracking pointer
*/
void testRingBufSizeSmall(Test * pTest)
{ {
bool status;
uint8_t data_element[5]; uint8_t data_element[5];
uint8_t data_store[sizeof(data_element) * 16]; uint8_t data_store[sizeof(data_element) * NEXT_POWER_OF_2(16)];
testRingBuf(pTest, data_store, data_element, sizeof(data_element), status = testRingBuf(pTest, data_store, data_element,
sizeof(data_element),
sizeof(data_store) / sizeof(data_element)); sizeof(data_store) / sizeof(data_element));
ct_test(pTest, status);
} }
void testRingBufSize32( /**
Test * pTest) * Unit Test for the ring buffer with 32 data elements
*
* @param pTest - test tracking pointer
*/
void testRingBufSizeLarge(Test * pTest)
{ {
bool status;
uint8_t data_element[16]; uint8_t data_element[16];
uint8_t data_store[sizeof(data_element) * 32]; uint8_t data_store[sizeof(data_element) * NEXT_POWER_OF_2(99)];
testRingBuf(pTest, data_store, data_element, sizeof(data_element), status = testRingBuf(pTest, data_store, data_element,
sizeof(data_element),
sizeof(data_store) / sizeof(data_element)); sizeof(data_store) / sizeof(data_element));
ct_test(pTest, status);
} }
/**
* Unit Test for the ring buffer with 32 data elements
*
* @param pTest - test tracking pointer
*/
void testRingBufSizeInvalid(Test * pTest)
{
bool status;
uint8_t data_element[16];
uint8_t data_store[sizeof(data_element) * 99];
status = testRingBuf(pTest, data_store, data_element,
sizeof(data_element),
sizeof(data_store) / sizeof(data_element));
ct_test(pTest, status==false);
}
void testRingBufPowerOfTwo(Test * pTest)
{
ct_test(pTest, NEXT_POWER_OF_2(3)==4);
ct_test(pTest, NEXT_POWER_OF_2(100)==128);
ct_test(pTest, NEXT_POWER_OF_2(127)==128);
ct_test(pTest, NEXT_POWER_OF_2(128)==128);
ct_test(pTest, NEXT_POWER_OF_2(129)==256);
ct_test(pTest, NEXT_POWER_OF_2(300)==512);
ct_test(pTest, NEXT_POWER_OF_2(500)==512);
}
#ifdef TEST_RING_BUFFER #ifdef TEST_RING_BUFFER
int main( /**
void) * Main program entry for Unit Test
*
* @return returns 0 on success, and non-zero on fail.
*/
int main(void)
{ {
Test *pTest; Test *pTest;
bool rc; bool rc;
@ -427,9 +603,13 @@ int main(
pTest = ct_create("Ring Buffer", NULL); pTest = ct_create("Ring Buffer", NULL);
/* individual tests */ /* individual tests */
rc = ct_addTestFunction(pTest, testRingBufSize16); rc = ct_addTestFunction(pTest, testRingBufPowerOfTwo);
assert(rc); assert(rc);
rc = ct_addTestFunction(pTest, testRingBufSize32); rc = ct_addTestFunction(pTest, testRingBufSizeSmall);
assert(rc);
rc = ct_addTestFunction(pTest, testRingBufSizeLarge);
assert(rc);
rc = ct_addTestFunction(pTest, testRingBufSizeInvalid);
assert(rc); assert(rc);
ct_setStream(pTest, stdout); ct_setStream(pTest, stdout);