| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- //*****************************************************************************
- //
- // usbringbuf.c - USB library ring buffer management utilities.
- //
- // Copyright (c) 2008-2010 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 AM1808 Sitaraware USB Library and reused from revision 6288
- // of the Stellaris USB Library.
- //
- //*****************************************************************************
- #include "hw_types.h"
- #include "debug.h"
- #include "interrupt.h"
- #include "usblib.h"
- //*****************************************************************************
- //
- //! \addtogroup usblib_buffer_api
- //! @{
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- // Define NULL, if not already defined.
- //
- //*****************************************************************************
- #ifndef NULL
- #define NULL ((void *)0)
- #endif
- //*****************************************************************************
- //
- // Change the value of a variable atomically.
- //
- // \param pulVal points to the index whose value is to be modified.
- // \param ulDelta is the number of bytes to increment the index by.
- // \param ulSize 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.
- //
- //*****************************************************************************
- #ifdef _TMS320C6X
- static void
- UpdateIndexAtomic(volatile unsigned int *pulVal, unsigned int ulDelta,
- unsigned int ulSize)
- {
- unsigned int IntStatus;
- //
- // Turn interrupts off temporarily.
- //
- IntStatus = IntGlobalDisable();
- //
- // Update the variable value.
- //
- *pulVal += ulDelta;
- //
- // 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 ulDelta is greater than ulSize (which is extremely unlikely but...)
- //
- while(*pulVal >= ulSize)
- {
- *pulVal -= ulSize;
- }
- //
- // Restore the interrupt state
- //
- IntGlobalRestore(IntStatus);
- }
- #else
- static void
- UpdateIndexAtomic(volatile unsigned int *pulVal, unsigned int ulDelta,
- unsigned int ulSize)
- {
- unsigned char IntStatus;
- //
- // Turn interrupts off temporarily.
- //
- IntStatus = IntDisable();
- //
- // Update the variable value.
- //
- *pulVal += ulDelta;
- //
- // 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 ulDelta is greater than ulSize (which is extremely unlikely but...)
- //
- while(*pulVal >= ulSize)
- {
- *pulVal -= ulSize;
- }
- //
- // Restore the interrupt state
- //
- IntEnable(IntStatus);
- }
- #endif
- //*****************************************************************************
- //
- //! Determines whether a ring buffer is full or not.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- tBoolean
- USBRingBufFull(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned int ulWrite;
- unsigned int ulRead;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Copy the Read/Write indices for calculation.
- //
- ulWrite = ptUSBRingBuf->ulWriteIndex;
- ulRead = ptUSBRingBuf->ulReadIndex;
- //
- // Return the full status of the buffer.
- //
- return((((ulWrite + 1) % ptUSBRingBuf->ulSize) == ulRead) ? true : false);
- }
- //*****************************************************************************
- //
- //! Determines whether a ring buffer is empty or not.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- tBoolean
- USBRingBufEmpty(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned int ulWrite;
- unsigned int ulRead;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Copy the Read/Write indices for calculation.
- //
- ulWrite = ptUSBRingBuf->ulWriteIndex;
- ulRead = ptUSBRingBuf->ulReadIndex;
- //
- // Return the empty status of the buffer.
- //
- return((ulWrite == ulRead) ? true : false);
- }
- //*****************************************************************************
- //
- //! Empties the ring buffer.
- //!
- //! \param ptUSBRingBuf is the ring buffer object to empty.
- //!
- //! Discards all data from the ring buffer.
- //!
- //! \return None.
- //
- //*****************************************************************************
- #ifdef _TMS320C6X
- void
- USBRingBufFlush(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned int bIntsOff;
-
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != 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 = IntGlobalDisable();
- ptUSBRingBuf->ulReadIndex = ptUSBRingBuf->ulWriteIndex;
- IntGlobalRestore(bIntsOff);
- }
- #else
- void
- USBRingBufFlush(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned char bIntsOff;
-
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != 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 =IntDisable();
- ptUSBRingBuf->ulReadIndex = ptUSBRingBuf->ulWriteIndex;
- IntEnable(bIntsOff);
- }
- #endif
- //*****************************************************************************
- //
- //! Returns number of bytes stored in ring buffer.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- unsigned int
- USBRingBufUsed(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned int ulWrite;
- unsigned int ulRead;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Copy the Read/Write indices for calculation.
- //
- ulWrite = ptUSBRingBuf->ulWriteIndex;
- ulRead = ptUSBRingBuf->ulReadIndex;
- //
- // Return the number of bytes contained in the ring buffer.
- //
- return((ulWrite >= ulRead) ? (ulWrite - ulRead) :
- (ptUSBRingBuf->ulSize - (ulRead - ulWrite)));
- }
- //*****************************************************************************
- //
- //! Returns number of bytes available in a ring buffer.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- unsigned int
- USBRingBufFree(tUSBRingBufObject *ptUSBRingBuf)
- {
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Return the number of bytes available in the ring buffer.
- //
- return((ptUSBRingBuf->ulSize - 1) - USBRingBufUsed(ptUSBRingBuf));
- }
- //*****************************************************************************
- //
- //! Returns number of contiguous bytes of data stored in ring buffer ahead of
- //! the current read pointer.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- unsigned int
- USBRingBufContigUsed(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned int ulWrite;
- unsigned int ulRead;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Copy the Read/Write indices for calculation.
- //
- ulWrite = ptUSBRingBuf->ulWriteIndex;
- ulRead = ptUSBRingBuf->ulReadIndex;
- //
- // Return the number of contiguous bytes available.
- //
- return((ulWrite >= ulRead) ? (ulWrite - ulRead) :
- (ptUSBRingBuf->ulSize - ulRead));
- }
- //*****************************************************************************
- //
- //! Returns number of contiguous free bytes available in a ring buffer.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- unsigned int
- USBRingBufContigFree(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned int ulWrite;
- unsigned int ulRead;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Copy the Read/Write indices for calculation.
- //
- ulWrite = ptUSBRingBuf->ulWriteIndex;
- ulRead = ptUSBRingBuf->ulReadIndex;
- //
- // Return the number of contiguous bytes available.
- //
- if(ulRead > ulWrite)
- {
- //
- // 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((ulRead - ulWrite) - 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(ptUSBRingBuf->ulSize - ulWrite - ((ulRead == 0) ? 1 : 0));
- }
- }
- //*****************************************************************************
- //
- //! Returns the size in bytes of a ring buffer.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- unsigned int
- USBRingBufSize(tUSBRingBufObject *ptUSBRingBuf)
- {
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Return the number of bytes available in the ring buffer.
- //
- return(ptUSBRingBuf->ulSize);
- }
- //*****************************************************************************
- //
- //! Reads a single byte of data from a ring buffer.
- //!
- //! \param ptUSBRingBuf 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.
- //
- //*****************************************************************************
- unsigned char
- USBRingBufReadOne(tUSBRingBufObject *ptUSBRingBuf)
- {
- unsigned char ucTemp;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Verify that space is available in the buffer.
- //
- ASSERT(USBRingBufUsed(ptUSBRingBuf) != 0);
- //
- // Write the data byte.
- //
- ucTemp = ptUSBRingBuf->pucBuf[ptUSBRingBuf->ulReadIndex];
- //
- // Increment the read index.
- //
- UpdateIndexAtomic(&ptUSBRingBuf->ulReadIndex, 1, ptUSBRingBuf->ulSize);
- //
- // Return the character read.
- //
- return(ucTemp);
- }
- //*****************************************************************************
- //
- //! Reads data from a ring buffer.
- //!
- //! \param ptUSBRingBuf points to the ring buffer to be read from.
- //! \param pucData points to where the data should be stored.
- //! \param ulLength is the number of bytes to be read.
- //!
- //! This function reads a sequence of bytes from a ring buffer.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBRingBufRead(tUSBRingBufObject *ptUSBRingBuf, unsigned char *pucData,
- unsigned int ulLength)
- {
- unsigned int ulTemp;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- ASSERT(pucData != NULL);
- ASSERT(ulLength != 0);
- //
- // Verify that data is available in the buffer.
- //
- ASSERT(ulLength <= USBRingBufUsed(ptUSBRingBuf));
- //
- // Read the data from the ring buffer.
- //
- for(ulTemp = 0; ulTemp < ulLength; ulTemp++)
- {
- pucData[ulTemp] = USBRingBufReadOne(ptUSBRingBuf);
- }
- }
- //*****************************************************************************
- //
- //! Removes bytes from the ring buffer by advancing the read index.
- //!
- //! \param ptUSBRingBuf points to the ring buffer from which bytes are to be
- //! removed.
- //! \param ulNumBytes 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
- //! ulNumBytes is larger than the number of bytes currently in the buffer, the
- //! buffer is emptied.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBRingBufAdvanceRead(tUSBRingBufObject *ptUSBRingBuf,
- unsigned int ulNumBytes)
- {
- unsigned int ulCount;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Make sure that we are not being asked to remove more data than is
- // there to be removed.
- //
- ulCount = USBRingBufUsed(ptUSBRingBuf);
- ulCount = (ulCount < ulNumBytes) ? ulCount : ulNumBytes;
- //
- // Advance the buffer read index by the required number of bytes.
- //
- UpdateIndexAtomic(&ptUSBRingBuf->ulReadIndex, ulCount,
- ptUSBRingBuf->ulSize);
- }
- //*****************************************************************************
- //
- //! Adds bytes to the ring buffer by advancing the write index.
- //!
- //! \param ptUSBRingBuf points to the ring buffer to which bytes have been
- //! added.
- //! \param ulNumBytes 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 USBRingBufWrite() or
- //! USBRingBufWriteOne(). It advances the write index by a given number of
- //! bytes.
- //!
- //! \note It is considered an error if the \e ulNumBytes parameter is larger
- //! than the amount of free space in the buffer and a debug build of this
- //! function will fail (ASSERT) if this condition is detected. In a release
- //! build, the buffer read pointer will be advanced if too much data is written
- //! but this will, of course, result in some of the oldest data in the buffer
- //! being discarded and also, depending upon how data is being read from
- //! the buffer, may result in a race condition which could corrupt the read
- //! pointer.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBRingBufAdvanceWrite(tUSBRingBufObject *ptUSBRingBuf,
- unsigned int ulNumBytes)
- {
- unsigned int ulCount;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Make sure we were not asked to add a silly number of bytes.
- //
- ASSERT(ulNumBytes <= ptUSBRingBuf->ulSize);
- //
- // Determine how much free space we currently think the buffer has.
- //
- ulCount = USBRingBufFree(ptUSBRingBuf);
- //
- // Check that the client has not added more data to the buffer than there
- // is space for. In this case, corruption may have occurred since the
- // buffer may have been read under interrupt context while the writer was
- // busy trashing the area around the read pointer.
- //
- ASSERT(ulCount >= ulNumBytes);
- //
- // Update the write pointer.
- //
- ptUSBRingBuf->ulWriteIndex += ulNumBytes;
- //
- // Check and correct for wrap.
- //
- if(ptUSBRingBuf->ulWriteIndex >= ptUSBRingBuf->ulSize)
- {
- ptUSBRingBuf->ulWriteIndex -= ptUSBRingBuf->ulSize;
- }
- //
- // Did the client add more bytes than the buffer had free space for? This
- // should be considered a bug since, unless this function is called in
- // the same context as the code which is reading from the buffer, writing
- // over the earliest data can cause corrupted data to be read. The
- // ASSERT above catches this in debug builds but, in release builds, we
- // go ahead and try to fix up the read pointer appropriately.
- //
- if(ulCount < ulNumBytes)
- {
- //
- // Yes - we need to advance the read pointer to ahead of the write
- // pointer to discard some of the oldest data.
- //
- ptUSBRingBuf->ulReadIndex = ptUSBRingBuf->ulWriteIndex + 1;
- //
- // Correct for buffer wrap if necessary.
- //
- if(ptUSBRingBuf->ulReadIndex >= ptUSBRingBuf->ulSize)
- {
- ptUSBRingBuf->ulReadIndex -= ptUSBRingBuf->ulSize;
- }
- }
- }
- //*****************************************************************************
- //
- //! Writes a single byte of data to a ring buffer.
- //!
- //! \param ptUSBRingBuf points to the ring buffer to be written to.
- //! \param ucData is the byte to be written.
- //!
- //! This function writes a single byte of data into a ring buffer.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBRingBufWriteOne(tUSBRingBufObject *ptUSBRingBuf, unsigned char ucData)
- {
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- //
- // Verify that space is available in the buffer.
- //
- ASSERT(USBRingBufFree(ptUSBRingBuf) != 0);
- //
- // Write the data byte.
- //
- ptUSBRingBuf->pucBuf[ptUSBRingBuf->ulWriteIndex] = ucData;
- //
- // Increment the write index.
- //
- UpdateIndexAtomic(&ptUSBRingBuf->ulWriteIndex, 1, ptUSBRingBuf->ulSize);
- }
- //*****************************************************************************
- //
- //! Writes data to a ring buffer.
- //!
- //! \param ptUSBRingBuf points to the ring buffer to be written to.
- //! \param pucData points to the data to be written.
- //! \param ulLength is the number of bytes to be written.
- //!
- //! This function write a sequence of bytes into a ring buffer.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBRingBufWrite(tUSBRingBufObject *ptUSBRingBuf, const unsigned char *pucData,
- unsigned int ulLength)
- {
- unsigned int ulTemp;
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- ASSERT(pucData != NULL);
- ASSERT(ulLength != 0);
- //
- // Verify that space is available in the buffer.
- //
- ASSERT(ulLength <= USBRingBufFree(ptUSBRingBuf));
- //
- // Write the data into the ring buffer.
- //
- for(ulTemp = 0; ulTemp < ulLength; ulTemp++)
- {
- USBRingBufWriteOne(ptUSBRingBuf, pucData[ulTemp]);
- }
- }
- //*****************************************************************************
- //
- //! Initializes a ring buffer object.
- //!
- //! \param ptUSBRingBuf points to the ring buffer to be initialized.
- //! \param pucBuf points to the data buffer to be used for the ring buffer.
- //! \param ulSize is the size of the buffer in bytes.
- //!
- //! This function initializes a ring buffer object, preparing it to store data.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBRingBufInit(tUSBRingBufObject *ptUSBRingBuf, unsigned char *pucBuf,
- unsigned int ulSize)
- {
- //
- // Check the arguments.
- //
- ASSERT(ptUSBRingBuf != NULL);
- ASSERT(pucBuf != NULL);
- ASSERT(ulSize != 0);
- //
- // Initialize the ring buffer object.
- //
- ptUSBRingBuf->ulSize = ulSize;
- ptUSBRingBuf->pucBuf = pucBuf;
- ptUSBRingBuf->ulWriteIndex = ptUSBRingBuf->ulReadIndex = 0;
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|