Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
//*****************************************************************************
//
// ringbuf.c - Ring buffer management utilities.
//
// Copyright (c) 2008-2013 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 1.1 of the Tiva Utility Library.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "utils/ringbuf.h"
//*****************************************************************************
//
//! \addtogroup ringbuf_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Define NULL, if not already defined.
//
//*****************************************************************************
#ifndef NULL
#define NULL ((void *)0)
#endif
//*****************************************************************************
//
// Change the value of a variable atomically.
//
// \param pui32Val points to the index whose value is to be modified.
// \param ui32Delta is the number of bytes to increment the index by.
// \param ui32Size is the size of the buffer the index refers to.
//
// This function is used to increment a read or write buffer index that may be
// written in various different contexts. It ensures that the
// read/modify/write sequence is not interrupted and, hence, guards against
// corruption of the variable. The new value is adjusted for buffer wrap.
//
// \return None.
//
//*****************************************************************************
static void
UpdateIndexAtomic(volatile uint32_t *pui32Val, uint32_t ui32Delta,
uint32_t ui32Size)
{
bool bIntsOff;
//
// Turn interrupts off temporarily.
//
bIntsOff = IntMasterDisable();
//
// Update the variable value.
//
*pui32Val += ui32Delta;
//
// Correct for wrap. We use a loop here since we don't want to use a
// modulus operation with interrupts off but we don't want to fail in
// case ui32Delta is greater than ui32Size (which is extremely unlikely
// but...)
//
while(*pui32Val >= ui32Size)
{
*pui32Val -= ui32Size;
}
//
// Restore the interrupt state
//
if(!bIntsOff)
{
IntMasterEnable();
}
}
//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is full or not.
//!
//! \param psRingBuf is the ring buffer object to empty.
//!
//! This function is used to determine whether or not a given ring buffer is
//! full. The structure is specifically to ensure that we do not see
//! warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is full or \b false otherwise.
//
//*****************************************************************************
bool
RingBufFull(tRingBufObject *psRingBuf)
{
uint32_t ui32Write;
uint32_t ui32Read;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Copy the Read/Write indices for calculation.
//
ui32Write = psRingBuf->ui32WriteIndex;
ui32Read = psRingBuf->ui32ReadIndex;
//
// Return the full status of the buffer.
//
return((((ui32Write + 1) % psRingBuf->ui32Size) == ui32Read) ? true :
false);
}
//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is empty or not.
//!
//! \param psRingBuf is the ring buffer object to empty.
//!
//! This function is used to determine whether or not a given ring buffer is
//! empty. The structure is specifically to ensure that we do not see
//! warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is empty or \b false otherwise.
//
//*****************************************************************************
bool
RingBufEmpty(tRingBufObject *psRingBuf)
{
uint32_t ui32Write;
uint32_t ui32Read;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Copy the Read/Write indices for calculation.
//
ui32Write = psRingBuf->ui32WriteIndex;
ui32Read = psRingBuf->ui32ReadIndex;
//
// Return the empty status of the buffer.
//
return((ui32Write == ui32Read) ? true : false);
}
//*****************************************************************************
//
//! Empties the ring buffer.
//!
//! \param psRingBuf is the ring buffer object to empty.
//!
//! Discards all data from the ring buffer.
//!
//! \return None.
//
//*****************************************************************************
void
RingBufFlush(tRingBufObject *psRingBuf)
{
bool bIntsOff;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Set the Read/Write pointers to be the same. Do this with interrupts
// disabled to prevent the possibility of corruption of the read index.
//
bIntsOff = IntMasterDisable();
psRingBuf->ui32ReadIndex = psRingBuf->ui32WriteIndex;
if(!bIntsOff)
{
IntMasterEnable();
}
}
//*****************************************************************************
//
//! Returns number of bytes stored in ring buffer.
//!
//! \param psRingBuf is the ring buffer object to check.
//!
//! This function returns the number of bytes stored in the ring buffer.
//!
//! \return Returns the number of bytes stored in the ring buffer.
//
//*****************************************************************************
uint32_t
RingBufUsed(tRingBufObject *psRingBuf)
{
uint32_t ui32Write;
uint32_t ui32Read;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Copy the Read/Write indices for calculation.
//
ui32Write = psRingBuf->ui32WriteIndex;
ui32Read = psRingBuf->ui32ReadIndex;
//
// Return the number of bytes contained in the ring buffer.
//
return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
(psRingBuf->ui32Size - (ui32Read - ui32Write)));
}
//*****************************************************************************
//
//! Returns number of bytes available in a ring buffer.
//!
//! \param psRingBuf is the ring buffer object to check.
//!
//! This function returns the number of bytes available in the ring buffer.
//!
//! \return Returns the number of bytes available in the ring buffer.
//
//*****************************************************************************
uint32_t
RingBufFree(tRingBufObject *psRingBuf)
{
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Return the number of bytes available in the ring buffer.
//
return((psRingBuf->ui32Size - 1) - RingBufUsed(psRingBuf));
}
//*****************************************************************************
//
//! Returns number of contiguous bytes of data stored in ring buffer ahead of
//! the current read pointer.
//!
//! \param psRingBuf is the ring buffer object to check.
//!
//! This function returns the number of contiguous bytes of data available in
//! the ring buffer ahead of the current read pointer. This represents the
//! largest block of data which does not straddle the buffer wrap.
//!
//! \return Returns the number of contiguous bytes available.
//
//*****************************************************************************
uint32_t
RingBufContigUsed(tRingBufObject *psRingBuf)
{
uint32_t ui32Write;
uint32_t ui32Read;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Copy the Read/Write indices for calculation.
//
ui32Write = psRingBuf->ui32WriteIndex;
ui32Read = psRingBuf->ui32ReadIndex;
//
// Return the number of contiguous bytes available.
//
return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
(psRingBuf->ui32Size - ui32Read));
}
//*****************************************************************************
//
//! Returns number of contiguous free bytes available in a ring buffer.
//!
//! \param psRingBuf is the ring buffer object to check.
//!
//! This function returns the number of contiguous free bytes ahead of the
//! current write pointer in the ring buffer.
//!
//! \return Returns the number of contiguous bytes available in the ring
//! buffer.
//
//*****************************************************************************
uint32_t
RingBufContigFree(tRingBufObject *psRingBuf)
{
uint32_t ui32Write;
uint32_t ui32Read;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Copy the Read/Write indices for calculation.
//
ui32Write = psRingBuf->ui32WriteIndex;
ui32Read = psRingBuf->ui32ReadIndex;
//
// Return the number of contiguous bytes available.
//
if(ui32Read > ui32Write)
{
//
// The read pointer is above the write pointer so the amount of free
// space is the difference between the two indices minus 1 to account
// for the buffer full condition (write index one behind read index).
//
return((ui32Read - ui32Write) - 1);
}
else
{
//
// If the write pointer is above the read pointer, the amount of free
// space is the size of the buffer minus the write index. We need to
// add a special-case adjustment if the read index is 0 since we need
// to leave 1 byte empty to ensure we can tell the difference between
// the buffer being full and empty.
//
return(psRingBuf->ui32Size - ui32Write - ((ui32Read == 0) ? 1 : 0));
}
}
//*****************************************************************************
//
//! Return size in bytes of a ring buffer.
//!
//! \param psRingBuf is the ring buffer object to check.
//!
//! This function returns the size of the ring buffer.
//!
//! \return Returns the size in bytes of the ring buffer.
//
//*****************************************************************************
uint32_t
RingBufSize(tRingBufObject *psRingBuf)
{
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Return the number of bytes available in the ring buffer.
//
return(psRingBuf->ui32Size);
}
//*****************************************************************************
//
//! Reads a single byte of data from a ring buffer.
//!
//! \param psRingBuf points to the ring buffer to be written to.
//!
//! This function reads a single byte of data from a ring buffer.
//!
//! \return The byte read from the ring buffer.
//
//*****************************************************************************
uint8_t
RingBufReadOne(tRingBufObject *psRingBuf)
{
uint8_t ui8Temp;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Verify that space is available in the buffer.
//
ASSERT(RingBufUsed(psRingBuf) != 0);
//
// Write the data byte.
//
ui8Temp = psRingBuf->pui8Buf[psRingBuf->ui32ReadIndex];
//
// Increment the read index.
//
UpdateIndexAtomic(&psRingBuf->ui32ReadIndex, 1, psRingBuf->ui32Size);
//
// Return the character read.
//
return(ui8Temp);
}
//*****************************************************************************
//
//! Reads data from a ring buffer.
//!
//! \param psRingBuf points to the ring buffer to be read from.
//! \param pui8Data points to where the data should be stored.
//! \param ui32Length is the number of bytes to be read.
//!
//! This function reads a sequence of bytes from a ring buffer.
//!
//! \return None.
//
//*****************************************************************************
void
RingBufRead(tRingBufObject *psRingBuf, uint8_t *pui8Data, uint32_t ui32Length)
{
uint32_t ui32Temp;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
ASSERT(pui8Data != NULL);
ASSERT(ui32Length != 0);
//
// Verify that data is available in the buffer.
//
ASSERT(ui32Length <= RingBufUsed(psRingBuf));
//
// Read the data from the ring buffer.
//
for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
{
pui8Data[ui32Temp] = RingBufReadOne(psRingBuf);
}
}
//*****************************************************************************
//
//! Remove bytes from the ring buffer by advancing the read index.
//!
//! \param psRingBuf points to the ring buffer from which bytes are to be
//! removed.
//! \param ui32NumBytes is the number of bytes to be removed from the buffer.
//!
//! This function advances the ring buffer read index by a given number of
//! bytes, removing that number of bytes of data from the buffer. If
//! \e ui32NumBytes is larger than the number of bytes currently in the buffer,
//! the buffer is emptied.
//!
//! \return None.
//
//*****************************************************************************
void
RingBufAdvanceRead(tRingBufObject *psRingBuf, uint32_t ui32NumBytes)
{
uint32_t ui32Count;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Make sure that we are not being asked to remove more data than is
// there to be removed.
//
ui32Count = RingBufUsed(psRingBuf);
ui32Count = (ui32Count < ui32NumBytes) ? ui32Count : ui32NumBytes;
//
// Advance the buffer read index by the required number of bytes.
//
UpdateIndexAtomic(&psRingBuf->ui32ReadIndex, ui32Count,
psRingBuf->ui32Size);
}
//*****************************************************************************
//
//! Add bytes to the ring buffer by advancing the write index.
//!
//! \param psRingBuf points to the ring buffer to which bytes have been added.
//! \param ui32NumBytes is the number of bytes added to the buffer.
//!
//! This function should be used by clients who wish to add data to the buffer
//! directly rather than via calls to RingBufWrite() or RingBufWriteOne(). It
//! advances the write index by a given number of bytes. If the
//! \e ui32NumBytes parameter is larger than the amount of free space in the
//! buffer, the read pointer will be advanced to cater for the addition. Note
//! that this will result in some of the oldest data in the buffer being
//! discarded.
//!
//! \return None.
//
//*****************************************************************************
void
RingBufAdvanceWrite(tRingBufObject *psRingBuf,
uint32_t ui32NumBytes)
{
uint32_t ui32Count;
bool bIntsOff;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Make sure we were not asked to add a silly number of bytes.
//
ASSERT(ui32NumBytes <= psRingBuf->ui32Size);
//
// Determine how much free space we currently think the buffer has.
//
ui32Count = RingBufFree(psRingBuf);
//
// Advance the buffer write index by the required number of bytes and
// check that we have not run past the read index. Note that we must do
// this within a critical section (interrupts disabled) to prevent
// race conditions that could corrupt one or other of the indices.
//
bIntsOff = IntMasterDisable();
//
// Update the write pointer.
//
psRingBuf->ui32WriteIndex += ui32NumBytes;
//
// Check and correct for wrap.
//
if(psRingBuf->ui32WriteIndex >= psRingBuf->ui32Size)
{
psRingBuf->ui32WriteIndex -= psRingBuf->ui32Size;
}
//
// Did the client add more bytes than the buffer had free space for?
//
if(ui32Count < ui32NumBytes)
{
//
// Yes - we need to advance the read pointer to ahead of the write
// pointer to discard some of the oldest data.
//
psRingBuf->ui32ReadIndex = psRingBuf->ui32WriteIndex + 1;
//
// Correct for buffer wrap if necessary.
//
if(psRingBuf->ui32ReadIndex >= psRingBuf->ui32Size)
{
psRingBuf->ui32ReadIndex -= psRingBuf->ui32Size;
}
}
//
// Restore interrupts if we turned them off earlier.
//
if(!bIntsOff)
{
IntMasterEnable();
}
}
//*****************************************************************************
//
//! Writes a single byte of data to a ring buffer.
//!
//! \param psRingBuf points to the ring buffer to be written to.
//! \param ui8Data is the byte to be written.
//!
//! This function writes a single byte of data into a ring buffer.
//!
//! \return None.
//
//*****************************************************************************
void
RingBufWriteOne(tRingBufObject *psRingBuf, uint8_t ui8Data)
{
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
//
// Verify that space is available in the buffer.
//
ASSERT(RingBufFree(psRingBuf) != 0);
//
// Write the data byte.
//
psRingBuf->pui8Buf[psRingBuf->ui32WriteIndex] = ui8Data;
//
// Increment the write index.
//
UpdateIndexAtomic(&psRingBuf->ui32WriteIndex, 1, psRingBuf->ui32Size);
}
//*****************************************************************************
//
//! Writes data to a ring buffer.
//!
//! \param psRingBuf points to the ring buffer to be written to.
//! \param pui8Data points to the data to be written.
//! \param ui32Length is the number of bytes to be written.
//!
//! This function write a sequence of bytes into a ring buffer.
//!
//! \return None.
//
//*****************************************************************************
void
RingBufWrite(tRingBufObject *psRingBuf, uint8_t *pui8Data,
uint32_t ui32Length)
{
uint32_t ui32Temp;
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
ASSERT(pui8Data != NULL);
ASSERT(ui32Length != 0);
//
// Verify that space is available in the buffer.
//
ASSERT(ui32Length <= RingBufFree(psRingBuf));
//
// Write the data into the ring buffer.
//
for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
{
RingBufWriteOne(psRingBuf, pui8Data[ui32Temp]);
}
}
//*****************************************************************************
//
//! Initialize a ring buffer object.
//!
//! \param psRingBuf points to the ring buffer to be initialized.
//! \param pui8Buf points to the data buffer to be used for the ring buffer.
//! \param ui32Size is the size of the buffer in bytes.
//!
//! This function initializes a ring buffer object, preparing it to store data.
//!
//! \return None.
//
//*****************************************************************************
void
RingBufInit(tRingBufObject *psRingBuf, uint8_t *pui8Buf,
uint32_t ui32Size)
{
//
// Check the arguments.
//
ASSERT(psRingBuf != NULL);
ASSERT(pui8Buf != NULL);
ASSERT(ui32Size != 0);
//
// Initialize the ring buffer object.
//
psRingBuf->ui32Size = ui32Size;
psRingBuf->pui8Buf = pui8Buf;
psRingBuf->ui32WriteIndex = psRingBuf->ui32ReadIndex = 0;
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
33ba1246aThis file is pinned to the selected release. Download the original to open it in your design tool.