Added Javadoc to fifo module and header file.

This commit is contained in:
skarg
2013-02-22 16:19:42 +00:00
parent 2eb8e84f41
commit 7084b9f036
2 changed files with 274 additions and 210 deletions
+35 -55
View File
@@ -1,92 +1,72 @@
/************************************************************************** /**
* * @file
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net> * @author Steve Karg
* * @date 2004
* 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 FIFO_H #ifndef FIFO_H
#define FIFO_H #define FIFO_H
/* Functional Description: Generic FIFO library for deeply
embedded system. See the unit tests for usage examples.
This library only uses a byte sized chunk.
This library is designed for use in Interrupt Service Routines
and so is declared as "static inline" */
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/**
* FIFO data structure
*
* @{
*/
struct fifo_buffer_t { struct fifo_buffer_t {
volatile unsigned head; /* first byte of data */ /** first byte of data */
volatile unsigned tail; /* last byte of data */ volatile unsigned head;
volatile uint8_t *buffer; /* block of memory or array of data */ /** last byte of data */
unsigned buffer_len; /* length of the data */ volatile unsigned tail;
/** block of memory or array of data */
volatile uint8_t *buffer;
/** length of the data */
unsigned buffer_len;
}; };
typedef struct fifo_buffer_t FIFO_BUFFER; typedef struct fifo_buffer_t FIFO_BUFFER;
/** @} */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
unsigned FIFO_Count( unsigned FIFO_Count(FIFO_BUFFER const *b);
FIFO_BUFFER const *b);
bool FIFO_Full( bool FIFO_Full(FIFO_BUFFER const *b);
FIFO_BUFFER const *b);
bool FIFO_Available( bool FIFO_Available(FIFO_BUFFER const *b,
FIFO_BUFFER const *b,
unsigned count); unsigned count);
bool FIFO_Empty( bool FIFO_Empty(FIFO_BUFFER const *b);
FIFO_BUFFER const *b);
uint8_t FIFO_Peek( uint8_t FIFO_Peek(FIFO_BUFFER const *b);
FIFO_BUFFER const *b);
uint8_t FIFO_Get( uint8_t FIFO_Get(FIFO_BUFFER * b);
FIFO_BUFFER * b);
unsigned FIFO_Pull( unsigned FIFO_Pull(FIFO_BUFFER * b,
FIFO_BUFFER * b,
uint8_t * data_bytes, uint8_t * data_bytes,
unsigned length); unsigned length);
bool FIFO_Put( bool FIFO_Put(FIFO_BUFFER * b,
FIFO_BUFFER * b,
uint8_t data_byte); uint8_t data_byte);
bool FIFO_Add( bool FIFO_Add(FIFO_BUFFER * b,
FIFO_BUFFER * b,
uint8_t * data_bytes, uint8_t * data_bytes,
unsigned count); unsigned count);
void FIFO_Flush( void FIFO_Flush(FIFO_BUFFER * b);
FIFO_BUFFER * b);
/* note: buffer_len must be a power of two */ /* note: buffer_len must be a power of two */
void FIFO_Init( void FIFO_Init(FIFO_BUFFER * b,
FIFO_BUFFER * b,
volatile uint8_t * buffer, volatile uint8_t * buffer,
unsigned buffer_len); unsigned buffer_len);
#ifdef TEST
#include "ctest.h"
void testFIFOBuffer(Test * pTest);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
+239 -155
View File
@@ -1,56 +1,107 @@
/*####COPYRIGHTBEGIN#### /**
------------------------------------------- * @file
Copyright (C) 2004 by Steve Karg * @author Steve Karg
* @date 2004
This program is free software; you can redistribute it and/or * @brief Generic interrupt safe FIFO 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
/** @file fifo.c Generic FIFO library for deeply embedded system */ * License.
*
/* Functional Description: Generic FIFO library for deeply * @section DESCRIPTION
embedded system. See the unit tests for usage examples. */ *
* Generic interrupt safe FIFO library for deeply embedded system
* This library only uses a byte sized chunk for a data element.
* 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.
*
* To use this library, first declare a data store, sized for a power of 2:
* {@code
* static volatile uint8_t data_store[64];
* }
*
* Then declare the FIFO tracking structure:
* {@code
* static FIFO_BUFFER queue;
* }
*
* Initialize the queue with the data store:
* {@code
* FIFO_Init(&queue, data_store, sizeof(data_store));
* }
*
* Then begin to use the FIFO queue by giving it data, retreiving data,
* and checking the FIFO queue to see if it is empty or full:
* {@code
* uint8_t in_data = 0;
* uint8_t out_data = 0;
* uint8_t add_data[5] = {0};
* uint8_t pull_data[5] = {0};
* unsigned count = 0;
* bool status = false;
*
* status = FIFO_Put(&queue, in_data);
* if (!FIFO_Empty(&queue)) {
* out_data = FIFO_Get(&queue);
* }
* if (FIFO_Available(&queue, sizeof(add_data))) {
* status = FIFO_Add(&queue, add_data, sizeof(add_data));
* }
* count = FIFO_Count(&queue);
* if (count == sizeof(add_data)) {
* count = FIFO_Pull(&queue, &pull_data[0], sizeof(pull_data));
* }
*
* }
*
* Normally the FIFO is used by a producer, such as in interrupt service
* routine, which places data into the queue using FIFO_Put(), and a consumer,
* such as a main loop handler, which pulls data from the queue by first
* checking the queue for data using FIFO_Empty(), and then pulling data from
* the queue using FIFO_Get().
*
*/
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "fifo.h" #include "fifo.h"
/**************************************************************************** /**
* DESCRIPTION: Returns the number of elements in the ring buffer * Returns the number of bytes in the FIFO
* RETURN: Number of elements in the ring buffer *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: none *
*****************************************************************************/ * @return Number of bytes in the FIFO
unsigned FIFO_Count( */
FIFO_BUFFER const *b) unsigned FIFO_Count(FIFO_BUFFER const *b)
{ {
unsigned head, tail; /* used to avoid volatile decision */ unsigned head, tail; /* used to avoid volatile decision */
@@ -63,91 +114,106 @@ unsigned FIFO_Count(
} }
} }
/**************************************************************************** /**
* DESCRIPTION: Returns the empty/full status of the ring buffer * Returns the full status of the FIFO
* RETURN: true if the ring buffer is full, false if it is not. *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: none *
*****************************************************************************/ * @return true if the FIFO is full, false if it is not.
bool FIFO_Full( */
FIFO_BUFFER const *b) bool FIFO_Full(FIFO_BUFFER const *b)
{ {
return (b ? (FIFO_Count(b) == b->buffer_len) : true); return (b ? (FIFO_Count(b) == b->buffer_len) : true);
} }
/**************************************************************************** /**
* DESCRIPTION: Tests to see if space is available * Tests to see if space is available in the FIFO
* RETURN: true if the number of bytes is available *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: none * @param count [in] - number of bytes tested for availability
*****************************************************************************/ *
bool FIFO_Available( * @return true if the number of bytes sought is available
FIFO_BUFFER const *b, */
bool FIFO_Available(FIFO_BUFFER const *b,
unsigned count) unsigned count)
{ {
return (b ? (count <= (b->buffer_len - FIFO_Count(b))) : false); return (b ? (count <= (b->buffer_len - FIFO_Count(b))) : false);
} }
/**************************************************************************** /**
* DESCRIPTION: Returns the empty/full status of the ring buffer * Returns the empty status of the FIFO
* RETURN: true if the ring buffer is empty, false if it is not. *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: none * @return true if the FIFO is empty, false if it is not.
*****************************************************************************/ */
bool FIFO_Empty( bool FIFO_Empty(FIFO_BUFFER const *b)
FIFO_BUFFER const *b)
{ {
return (b ? (FIFO_Count(b) == 0) : true); return (b ? (FIFO_Count(b) == 0) : true);
} }
/**************************************************************************** /**
* DESCRIPTION: Looks at the data from the head of the list without removing it * Peeks at the data from the front of the FIFO without removing it.
* RETURN: byte of data, or zero if nothing in the list * Use FIFO_Empty() or FIFO_Available() function to see if there is
* ALGORITHM: none * data to retrieve since this function doesn't return a flag indicating
* NOTES: Use Empty function to see if there is data to retrieve * success or failure.
*****************************************************************************/ *
uint8_t FIFO_Peek( * @param b - pointer to FIFO_BUFFER structure
FIFO_BUFFER const *b) *
* @return byte of data, or zero if nothing in the list
*/
uint8_t FIFO_Peek(FIFO_BUFFER const *b)
{ {
unsigned index;
if (b) { if (b) {
return (b->buffer[b->tail % b->buffer_len]); index = b->tail % b->buffer_len;
return (b->buffer[index]);
} }
return 0; return 0;
} }
/**************************************************************************** /**
* DESCRIPTION: Gets the data from the front of the list, and removes it * Gets a byte from the front of the FIFO, and removes it.
* RETURN: the data, or zero if nothing in the list * Use FIFO_Empty() or FIFO_Available() function to see if there is
* ALGORITHM: none * data to retrieve since this function doesn't return a flag indicating
* NOTES: Use Empty function to see if there is data to retrieve * success or failure.
*****************************************************************************/ *
uint8_t FIFO_Get( * @param b - pointer to FIFO_BUFFER structure
FIFO_BUFFER * b) *
* @return the data
*/
uint8_t FIFO_Get(FIFO_BUFFER * b)
{ {
uint8_t data_byte = 0; uint8_t data_byte = 0;
unsigned index;
if (!FIFO_Empty(b)) { if (!FIFO_Empty(b)) {
data_byte = b->buffer[b->tail % b->buffer_len]; index = b->tail % b->buffer_len;
data_byte = b->buffer[index];
b->tail++; b->tail++;
} }
return data_byte; return data_byte;
} }
/**************************************************************************** /**
* DESCRIPTION: Pulls the data from the front of the list, and removes it * Pulls one or more bytes from the front of the FIFO, and removes them
* RETURN: the data (in parameter) and the number of bytes pulled * from the FIFO. If less bytes are available, only the available bytes
* ALGORITHM: none * are retrieved.
* NOTES: none *
*****************************************************************************/ * @param b - pointer to FIFO_BUFFER structure
unsigned FIFO_Pull( * @param buffer [out] - buffer to hold the pulled bytes
FIFO_BUFFER * b, * @param length [in] - number of bytes to pull from the FIFO
uint8_t * data_bytes, *
* @return the number of bytes actually pulled from the FIFO
*/
unsigned FIFO_Pull(FIFO_BUFFER * b,
uint8_t * buffer,
unsigned length) unsigned length)
{ {
unsigned count; unsigned count;
uint8_t data_byte; uint8_t data_byte;
unsigned index;
count = FIFO_Count(b); count = FIFO_Count(b);
if (count > length) { if (count > length) {
@@ -159,32 +225,38 @@ unsigned FIFO_Pull(
length = count; length = count;
} }
while (count) { while (count) {
data_byte = b->buffer[b->tail % b->buffer_len]; index = b->tail % b->buffer_len;
data_byte = b->buffer[index];
b->tail++; b->tail++;
*data_bytes = data_byte; if (buffer) {
data_bytes++; *buffer = data_byte;
buffer++;
}
count--; count--;
} }
return length; return length;
} }
/**************************************************************************** /**
* DESCRIPTION: Adds an element of data to the FIFO * Adds a byte of data to the FIFO
* RETURN: true on successful add, false if not added *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: none * @param data_byte [in] - data to put into the FIFO
*****************************************************************************/ *
bool FIFO_Put( * @return true on successful add, false if not added
FIFO_BUFFER * b, */
bool FIFO_Put(FIFO_BUFFER * b,
uint8_t data_byte) uint8_t data_byte)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
unsigned index;
if (b) { if (b) {
/* limit the ring to prevent overwriting */ /* limit the buffer to prevent overwriting */
if (!FIFO_Full(b)) { if (!FIFO_Full(b)) {
b->buffer[b->head % b->buffer_len] = data_byte; index = b->head % b->buffer_len;
b->buffer[index] = data_byte;
b->head++; b->head++;
status = true; status = true;
} }
@@ -193,25 +265,29 @@ bool FIFO_Put(
return status; return status;
} }
/**************************************************************************** /**
* DESCRIPTION: Adds one or more elements of data to the FIFO * Adds one or more bytes of data to the FIFO
* RETURN: true if space available and added, false if not added *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: none * @param buffer [out] - data bytes to add to the FIFO
*****************************************************************************/ * @param count [in] - number of bytes to add to the FIFO
bool FIFO_Add( *
FIFO_BUFFER * b, * @return true if space available and added, false if not added
uint8_t * data_bytes, */
bool FIFO_Add(FIFO_BUFFER * b,
uint8_t * buffer,
unsigned count) unsigned count)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
unsigned index;
/* limit the ring to prevent overwriting */ /* limit the buffer to prevent overwriting */
if (FIFO_Available(b, count)) { if (FIFO_Available(b, count) && buffer) {
while (count) { while (count) {
b->buffer[b->head % b->buffer_len] = *data_bytes; index = b->head % b->buffer_len;
b->buffer[index] = *buffer;
b->head++; b->head++;
data_bytes++; buffer++;
count--; count--;
} }
status = true; status = true;
@@ -220,14 +296,14 @@ bool FIFO_Add(
return status; return status;
} }
/**************************************************************************** /**
* DESCRIPTION: Flushes any data in the buffer * Flushes any data in the FIFO buffer
* RETURN: none *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: none *
*****************************************************************************/ * @return none
void FIFO_Flush( */
FIFO_BUFFER * b) void FIFO_Flush(FIFO_BUFFER * b)
{ {
unsigned head; /* used to avoid volatile decision */ unsigned head; /* used to avoid volatile decision */
@@ -237,18 +313,20 @@ void FIFO_Flush(
} }
} }
/**************************************************************************** /**
* DESCRIPTION: Configures the ring buffer * Initializes the FIFO buffer with a data store
* RETURN: none *
* ALGORITHM: none * @param b - pointer to FIFO_BUFFER structure
* NOTES: buffer_len must be a power of two * @param buffer [in] - data bytes used to store bytes used by the FIFO
*****************************************************************************/ * @param buffer_len [in] - size of the buffer in bytes - must be power of 2.
void FIFO_Init( *
FIFO_BUFFER * b, * @return none
*/
void FIFO_Init(FIFO_BUFFER * b,
volatile uint8_t * buffer, volatile uint8_t * buffer,
unsigned buffer_len) unsigned buffer_len)
{ {
if (b) { if (b && buffer && buffer_len) {
b->head = 0; b->head = 0;
b->tail = 0; b->tail = 0;
b->buffer = buffer; b->buffer = buffer;
@@ -262,17 +340,19 @@ void FIFO_Init(
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "ctest.h" #include "ctest.h"
/* test the FIFO */ /**
/* note: must be a power of two! */ * Unit Test for the FIFO buffer
#define FIFO_BUFFER_SIZE 64 *
void testFIFOBuffer( * @param pTest - test tracking pointer
Test * pTest) */
void testFIFOBuffer(Test * pTest)
{ {
/* FIFO data structure */
FIFO_BUFFER test_buffer = { 0 }; FIFO_BUFFER test_buffer = { 0 };
volatile uint8_t data_store[FIFO_BUFFER_SIZE] = { 0 }; /* FIFO data store. Note: size must be a power of two! */
volatile uint8_t data_store[64] = { 0 };
uint8_t add_data[40] = { "RoseSteveLouPatRachelJessicaDaniAmyHerb" }; uint8_t add_data[40] = { "RoseSteveLouPatRachelJessicaDaniAmyHerb" };
uint8_t test_add_data[40] = { 0 }; uint8_t test_add_data[40] = { 0 };
uint8_t test_data = 0; uint8_t test_data = 0;
@@ -284,7 +364,7 @@ void testFIFOBuffer(
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
/* load the buffer */ /* load the buffer */
for (test_data = 0; test_data < FIFO_BUFFER_SIZE; test_data++) { for (test_data = 0; test_data < sizeof(data_store); test_data++) {
ct_test(pTest, !FIFO_Full(&test_buffer)); ct_test(pTest, !FIFO_Full(&test_buffer));
ct_test(pTest, FIFO_Available(&test_buffer, 1)); ct_test(pTest, FIFO_Available(&test_buffer, 1));
status = FIFO_Put(&test_buffer, test_data); status = FIFO_Put(&test_buffer, test_data);
@@ -297,7 +377,7 @@ void testFIFOBuffer(
status = FIFO_Put(&test_buffer, 42); status = FIFO_Put(&test_buffer, 42);
ct_test(pTest, status == false); ct_test(pTest, status == false);
/* unload the buffer */ /* unload the buffer */
for (index = 0; index < FIFO_BUFFER_SIZE; index++) { for (index = 0; index < sizeof(data_store); index++) {
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
test_data = FIFO_Peek(&test_buffer); test_data = FIFO_Peek(&test_buffer);
ct_test(pTest, test_data == index); ct_test(pTest, test_data == index);
@@ -313,7 +393,7 @@ void testFIFOBuffer(
ct_test(pTest, test_data == 0); ct_test(pTest, test_data == 0);
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
/* test the ring around the buffer */ /* test the ring around the buffer */
for (index = 0; index < FIFO_BUFFER_SIZE; index++) { for (index = 0; index < sizeof(data_store); index++) {
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
ct_test(pTest, FIFO_Available(&test_buffer, 4)); ct_test(pTest, FIFO_Available(&test_buffer, 4));
for (count = 1; count < 4; count++) { for (count = 1; count < 4; count++) {
@@ -381,8 +461,12 @@ void testFIFOBuffer(
} }
#ifdef TEST_FIFO_BUFFER #ifdef TEST_FIFO_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;