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