+/*\r
+ LUFA Library\r
+ Copyright (C) Dean Camera, 2010.\r
+\r
+ dean [at] fourwalledcubicle [dot] com\r
+ www.lufa-lib.org\r
+*/\r
+\r
+/*\r
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+\r
+ Permission to use, copy, modify, distribute, and sell this\r
+ software and its documentation for any purpose is hereby granted\r
+ without fee, provided that the above copyright notice appear in\r
+ all copies and that both that the copyright notice and this\r
+ permission notice and warranty disclaimer appear in supporting\r
+ documentation, and that the name of the author not be used in\r
+ advertising or publicity pertaining to distribution of the\r
+ software without specific, written prior permission.\r
+\r
+ The author disclaim all warranties with regard to this\r
+ software, including all implied warranties of merchantability\r
+ and fitness. In no event shall the author be liable for any\r
+ special, indirect or consequential damages or any damages\r
+ whatsoever resulting from loss of use, data or profits, whether\r
+ in an action of contract, negligence or other tortious action,\r
+ arising out of or in connection with the use or performance of\r
+ this software.\r
+*/\r
+\r
+/** \file\r
+ * \brief Lightweight ring buffer, for fast insertion/deletion.\r
+ *\r
+ * Lightweight ring buffer, for fast insertion/deletion. Multiple buffers can be created of\r
+ * different sizes to suit different needs.\r
+ *\r
+ * Note that for each buffer, insertion and removal operations may occur at the same time (via\r
+ * a multithreaded ISR based system) however the same kind of operation (two or more insertions\r
+ * or deletions) must not overlap. If there is possibility of two or more of the same kind of\r
+ * operating occuring at the same point in time, atomic (mutex) locking should be used.\r
+ */\r
+ \r
+/** \ingroup Group_MiscDrivers\r
+ * @defgroup Group_RingBuff Generic Byte Ring Buffer - LUFA/Drivers/Misc/RingBuffer.h\r
+ *\r
+ * \section Sec_Dependencies Module Source Dependencies\r
+ * The following files must be built with any user project that uses this module:\r
+ * - None\r
+ *\r
+ * \section Module Description\r
+ * Lightweight ring buffer, for fast insertion/deletion. Multiple buffers can be created of\r
+ * different sizes to suit different needs.\r
+ *\r
+ * Note that for each buffer, insertion and removal operations may occur at the same time (via\r
+ * a multithreaded ISR based system) however the same kind of operation (two or more insertions\r
+ * or deletions) must not overlap. If there is possibility of two or more of the same kind of\r
+ * operating occuring at the same point in time, atomic (mutex) locking should be used.\r
+ *\r
+ * Example Usage:\r
+ * \code\r
+ * // Create the buffer structure and its underlying storage array\r
+ * RingBuff_t Buffer;\r
+ * uint8_t BufferData[128];\r
+ *\r
+ * // Initialise the buffer with the created storage array\r
+ * RingBuffer_InitBuffer(&Buffer, BufferData, sizeof(BufferData));\r
+ *\r
+ * // Insert some data into the buffer\r
+ * RingBuffer_Insert(Buffer, 'H');\r
+ * RingBuffer_Insert(Buffer, 'E');\r
+ * RingBuffer_Insert(Buffer, 'L');\r
+ * RingBuffer_Insert(Buffer, 'L');\r
+ * RingBuffer_Insert(Buffer, 'O');\r
+ *\r
+ * // Cache the number of stored bytes in the buffer\r
+ * uint16_t BufferCount = RingBuffer_GetCount(&Buffer);\r
+ *\r
+ * // Printer stored data length\r
+ * printf("Buffer Length: %d, Buffer Data:\r\n", BufferCount);\r
+ *\r
+ * // Print contents of the buffer one character at a time\r
+ * while (BufferCount--)\r
+ * putc(RingBuffer_Remove(&Buffer));\r
+ * \endcode\r
+ *\r
+ * @{\r
+ */\r
+\r
+#ifndef __RING_BUFF_H__\r
+#define __RING_BUFF_H__\r
+\r
+ /* Includes: */\r
+ #include <util/atomic.h>\r
+ #include <stdint.h>\r
+ #include <stdbool.h>\r
+\r
+ #include <LUFA/Common/Common.h>\r
+\r
+ /* Type Defines: */\r
+ /** Type define for a new ring buffer object. Buffers should be initialized via a call to\r
+ * \ref RingBuffer_InitBuffer() before use.\r
+ */\r
+ typedef struct\r
+ {\r
+ uint8_t* In; /**< Current storage location in the circular buffer */\r
+ uint8_t* Out; /**< Current retrieval location in the circular buffer */\r
+ uint8_t* Start; /** Pointer to the start of the buffer's underlying storage array */\r
+ uint8_t* End; /** Pointer to the end of the buffer's underlying storage array */\r
+ uint8_t Size; /** Size of the buffer's underlying storage array */\r
+ uint16_t Count; /** Number of bytes currently stored in the buffer */\r
+ } RingBuff_t;\r
+\r
+ /* Inline Functions: */\r
+ /** Initializes a ring buffer ready for use. Buffers must be initialized via this function\r
+ * before any operations are called upon them. Already initialized buffers may be reset\r
+ * by re-initializing them using this function.\r
+ *\r
+ * \param[out] Buffer Pointer to a ring buffer structure to initialize\r
+ * \param[out] DataPtr Pointer to a global array that will hold the data stored into the ring buffer\r
+ * \param[out] Size Maximum number of bytes that can be stored in the underlying data array\r
+ */\r
+ static inline void RingBuffer_InitBuffer(RingBuff_t* Buffer, uint8_t* const DataPtr, const uint16_t Size)\r
+ {\r
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE)\r
+ {\r
+ GCC_FORCE_POINTER_ACCESS(Buffer);\r
+ \r
+ Buffer->In = DataPtr;\r
+ Buffer->Out = DataPtr;\r
+ Buffer->Start = &DataPtr[0];\r
+ Buffer->End = &DataPtr[Size];\r
+ Buffer->Size = Size;\r
+ Buffer->Count = 0;\r
+ }\r
+ }\r
+\r
+ /** Retrieves the minimum number of bytes stored in a particular buffer. This value is computed\r
+ * by entering an atomic lock on the buffer while the IN and OUT locations are fetched, so that\r
+ * the buffer cannot be modified while the computation takes place. This value should be cached\r
+ * when reading out the contents of the buffer, so that as small a time as possible is spent\r
+ * in an atomic lock.\r
+ *\r
+ * \note The value returned by this function is guaranteed to only be the minimum number of bytes\r
+ * stored in the given buffer; this value may change as other threads write new data and so\r
+ * the returned number should be used only to determine how many successive reads may safely\r
+ * be performed on the buffer.\r
+ *\r
+ * \param[in] Buffer Pointer to a ring buffer structure whose count is to be computed\r
+ */\r
+ static inline uint16_t RingBuffer_GetCount(RingBuff_t* const Buffer)\r
+ {\r
+ uint16_t Count;\r
+\r
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE)\r
+ {\r
+ Count = Buffer->Count;\r
+ }\r
+\r
+ return Count;\r
+ }\r
+\r
+ /** Atomically determines if the specified ring buffer contains any free space. This should\r
+ * be tested before storing data to the buffer, to ensure that no data is lost due to a\r
+ * buffer overrun.\r
+ *\r
+ * \param[in,out] Buffer Pointer to a ring buffer structure to insert into\r
+ *\r
+ * \return Boolean true if the buffer contains no free space, false otherwise\r
+ */\r
+ static inline bool RingBuffer_IsFull(RingBuff_t* const Buffer)\r
+ {\r
+ return (RingBuffer_GetCount(Buffer) == Buffer->Size);\r
+ }\r
+\r
+ /** Atomically determines if the specified ring buffer contains any data. This should\r
+ * be tested before removing data from the buffer, to ensure that the buffer does not\r
+ * underflow.\r
+ *\r
+ * If the data is to be removed in a loop, store the total number of bytes stored in the\r
+ * buffer (via a call to the \ref RingBuffer_GetCount() function) in a temporary variable\r
+ * to reduce the time spent in atomicity locks.\r
+ *\r
+ * \param[in,out] Buffer Pointer to a ring buffer structure to insert into\r
+ *\r
+ * \return Boolean true if the buffer contains no free space, false otherwise\r
+ */\r
+ static inline bool RingBuffer_IsEmpty(RingBuff_t* const Buffer)\r
+ {\r
+ return (RingBuffer_GetCount(Buffer) == 0);\r
+ }\r
+\r
+ /** Inserts an element into the ring buffer.\r
+ *\r
+ * \note Only one execution thread (main program thread or an ISR) may insert into a single buffer\r
+ * otherwise data corruption may occur. Insertion and removal may occur from different execution\r
+ * threads.\r
+ *\r
+ * \param[in,out] Buffer Pointer to a ring buffer structure to insert into\r
+ * \param[in] Data Data element to insert into the buffer\r
+ */\r
+ static inline void RingBuffer_Insert(RingBuff_t* const Buffer,\r
+ const uint8_t Data)\r
+ {\r
+ *Buffer->In = Data;\r
+\r
+ if (++Buffer->In == Buffer->End)\r
+ Buffer->In = Buffer->Start;\r
+\r
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE)\r
+ {\r
+ Buffer->Count++;\r
+ }\r
+ }\r
+\r
+ /** Removes an element from the ring buffer.\r
+ *\r
+ * \note Only one execution thread (main program thread or an ISR) may remove from a single buffer\r
+ * otherwise data corruption may occur. Insertion and removal may occur from different execution\r
+ * threads.\r
+ *\r
+ * \param[in,out] Buffer Pointer to a ring buffer structure to retrieve from\r
+ *\r
+ * \return Next data element stored in the buffer\r
+ */\r
+ static inline uint8_t RingBuffer_Remove(RingBuff_t* const Buffer)\r
+ {\r
+ uint8_t Data = *Buffer->Out;\r
+\r
+ if (++Buffer->Out == Buffer->End)\r
+ Buffer->Out = Buffer->Start;\r
+\r
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE)\r
+ {\r
+ Buffer->Count--;\r
+ }\r
+\r
+ return Data;\r
+ }\r
+\r
+ /** Returns the next element stored in the ring buffer, without removing it.\r
+ *\r
+ * \param[in,out] Buffer Pointer to a ring buffer structure to retrieve from\r
+ *\r
+ * \return Next data element stored in the buffer\r
+ */\r
+ static inline uint8_t RingBuffer_Peek(RingBuff_t* const Buffer)\r
+ {\r
+ return *Buffer->Out;\r
+ }\r
+\r
+#endif\r
+\r
+/** @} */\r
+\r