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
					Steve Karg
				
			
				
					committed by
					
						 Patrick Grimm
						Patrick Grimm
					
				
			
			
				
	
			
			
			 Patrick Grimm
						Patrick Grimm
					
				
			
						parent
						
							25d6d06ad7
						
					
				
				
					commit
					7261d40214
				
			| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										484
									
								
								src/ringbuf.c
									
									
									
									
									
								
							
							
						
						
									
										484
									
								
								src/ringbuf.c
									
									
									
									
									
								
							| @@ -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); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user