X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=mware%2Ffifobuf.h;h=cb634ee32ffe14e004c97a6645260380d333ba81;hb=faf2f6bfd5933ff75e6cc01e3d48f9277f731d8f;hp=43ea6f1d6dc6a767de3d4618d51136ca96361338;hpb=4d1df24838aae04c82ffc93ebb1d6437b25a057d;p=bertos.git diff --git a/mware/fifobuf.h b/mware/fifobuf.h old mode 100755 new mode 100644 index 43ea6f1d..cb634ee3 --- a/mware/fifobuf.h +++ b/mware/fifobuf.h @@ -1,9 +1,34 @@ -/*! +/** * \file * * * \version $Id$ @@ -12,83 +37,41 @@ * * \brief General pourpose FIFO buffer implemented with a ring buffer * - * \li \c begin punta al primo elemento del buffer, - * \li \c end punta all'ultimo elemento, - * \li \c head punta al prossimo elemento che verra' estratto, - * \li \c tail punta alla posizione successiva all'ultimo elemento inserito. - * \li quando uno dei due puntatori raggiunge @c end, viene resettato a @c begin. + * \li \c begin points to the first buffer element; + * \li \c end points to the last buffer element (unlike the STL convention); + * \li \c head points to the element to be extracted next; + * \li \c tail points to the location following the last insertion; + * \li when any of the pointers advances beyond \c end, it is reset + * back to \c begin. * * \code * * +-----------------------------------+ - * | vuoto | dati validi | vuoto | + * | empty | valid data | empty | * +-----------------------------------+ * ^ ^ ^ ^ * begin head tail end * * \endcode * - * Il buffer e' VUOTO quando head e tail coincidono: + * The buffer is EMPTY when \c head and \c tail point to the same location: * \code head == tail \endcode * - * Il buffer e' PIENO quando tail si trova immediatamente dietro a head: + * The buffer is FULL when \c tail points to the location immediately + * after \c head: * \code tail == head - 1 \endcode * - * Il buffer e' PIENO anche quando tail e' posizionato - * sull'ultima posizione del buffer e head sulla prima: + * The buffer is also FULL when \c tail points to the last buffer + * location and head points to the first one: * \code head == begin && tail == end \endcode */ -/* - * $Log$ - * Revision 1.5 2004/06/06 16:50:35 bernie - * Import fixes for race conditions from project_ks. - * - * Revision 1.4 2004/06/06 16:11:17 bernie - * Protect MetroWerks specific pragmas with #ifdef's - * - * Revision 1.3 2004/06/03 15:04:10 aleph - * Merge improvements from project_ks (mainly inlining) - * - * Revision 1.2 2004/06/03 11:27:09 bernie - * Add dual-license information. - * - * Revision 1.1 2004/05/23 15:43:16 bernie - * Import mware modules. - * - * Revision 1.3 2004/05/22 17:55:58 rasky - * \samp non esiste in doxygen - * - * Revision 1.2 2004/04/27 11:13:29 rasky - * Spostate tutte le definizioni CPU-specific da compiler.h nel nuovo file cpu.h - * - * Revision 1.1 2004/04/21 17:38:25 rasky - * New application - * - * Revision 1.4 2004/03/24 15:37:03 bernie - * Remove Copyright messages from Doxygen output - * - * Revision 1.3 2004/03/18 18:11:07 bernie - * Add thread-safe FIFO handling macros - * - * Revision 1.2 2004/03/01 08:00:36 bernie - * Fixes for Doxygen - * - * Revision 1.1 2003/12/07 04:04:20 bernie - * Initial project_ks framework. - * - * Revision 1.1 2003/11/21 16:36:17 aleph - * Rename from fifo to fifobuf to avoid conflict with BSP fifo.h header - * - * Revision 1.1 2003/11/20 22:17:41 aleph - * Add fifo buffer used by serial - * - */ - #ifndef MWARE_FIFO_H #define MWARE_FIFO_H -#include "cpu.h" +#include +#include +#include typedef struct FIFOBuffer { @@ -99,24 +82,16 @@ typedef struct FIFOBuffer } FIFOBuffer; -/* Public function prototypes */ -INLINE bool fifo_isempty(const FIFOBuffer *fb); -INLINE bool fifo_isempty_locked(const FIFOBuffer *fb); -INLINE bool fifo_isfull(const FIFOBuffer *fb); -INLINE bool fifo_isfull_locked(const FIFOBuffer *fb); -#ifdef __MWERKS__ -#pragma interrupt called -#endif -INLINE void fifo_push(FIFOBuffer *fb, unsigned char c); -#ifdef __MWERKS__ -#pragma interrupt called -#endif -INLINE unsigned char fifo_pop(FIFOBuffer *fb); -INLINE void fifo_flush(FIFOBuffer *fb); -INLINE void fifo_init(FIFOBuffer *fb, unsigned char *buf, size_t size); +#define ASSERT_VALID_FIFO(fifo) \ + ATOMIC( \ + ASSERT((fifo)->head >= (fifo)->begin); \ + ASSERT((fifo)->head <= (fifo)->end); \ + ASSERT((fifo)->tail >= (fifo)->begin); \ + ASSERT((fifo)->tail <= (fifo)->end); \ + ) -/*! +/** * Check whether the fifo is empty * * \note Calling fifo_isempty() is safe while a concurrent @@ -128,11 +103,12 @@ INLINE void fifo_init(FIFOBuffer *fb, unsigned char *buf, size_t size); */ INLINE bool fifo_isempty(const FIFOBuffer *fb) { + //ASSERT_VALID_FIFO(fb); return fb->head == fb->tail; } -/*! +/** * Check whether the fifo is full * * \note Calling fifo_isfull() is safe while a concurrent @@ -147,14 +123,15 @@ INLINE bool fifo_isempty(const FIFOBuffer *fb) */ INLINE bool fifo_isfull(const FIFOBuffer *fb) { + //ASSERT_VALID_FIFO(fb); return ((fb->head == fb->begin) && (fb->tail == fb->end)) || (fb->tail == fb->head - 1); } -/*! - * Pop a character from the fifo buffer. +/** + * Push a character on the fifo buffer. * * \note Calling \c fifo_push() on a full buffer is undefined. * The caller must make sure the buffer has at least @@ -169,10 +146,15 @@ INLINE bool fifo_isfull(const FIFOBuffer *fb) */ INLINE void fifo_push(FIFOBuffer *fb, unsigned char c) { +#ifdef __MWERKS__ +#pragma interrupt called +#endif + //ASSERT_VALID_FIFO(fb); + /* Write at tail position */ *(fb->tail) = c; - if (fb->tail == fb->end) + if (UNLIKELY(fb->tail == fb->end)) /* wrap tail around */ fb->tail = fb->begin; else @@ -181,7 +163,7 @@ INLINE void fifo_push(FIFOBuffer *fb, unsigned char c) } -/*! +/** * Pop a character from the fifo buffer. * * \note Calling \c fifo_pop() on an empty buffer is undefined. @@ -193,7 +175,12 @@ INLINE void fifo_push(FIFOBuffer *fb, unsigned char c) */ INLINE unsigned char fifo_pop(FIFOBuffer *fb) { - if (fb->head == fb->end) +#ifdef __MWERKS__ +#pragma interrupt called +#endif + //ASSERT_VALID_FIFO(fb); + + if (UNLIKELY(fb->head == fb->end)) { /* wrap head around */ fb->head = fb->begin; @@ -205,90 +192,106 @@ INLINE unsigned char fifo_pop(FIFOBuffer *fb) } -/*! +/** * Make the fifo empty, discarding all its current contents. */ INLINE void fifo_flush(FIFOBuffer *fb) { + //ASSERT_VALID_FIFO(fb); fb->head = fb->tail; } -#if !defined(__AVR__) +#if CPU_REG_BITS >= CPU_BITS_PER_PTR - /* No tricks needed on 16/32bit CPUs */ -# define fifo_isempty_locked(fb) fifo_isempty((fb)) -# define fifo_push_locked(fb, c) fifo_push((fb), (c)) + /* + * 16/32bit CPUs that can update a pointer with a single write + * operation, no need to disable interrupts. + */ + #define fifo_isempty_locked(fb) fifo_isempty((fb)) + #define fifo_push_locked(fb, c) fifo_push((fb), (c)) + #define fifo_pop_locked(fb) fifo_pop((fb)) + #define fifo_flush_locked(fb) fifo_flush((fb)) -#else /* !__AVR__ */ +#else /* CPU_REG_BITS < CPU_BITS_PER_PTR */ - /*! + /** * Similar to fifo_isempty(), but with stronger guarantees for * concurrent access between user and interrupt code. - * This is actually only needed for 8-bit processors. + * + * \note This is actually only needed for 8-bit processors. * * \sa fifo_isempty() */ - INLINE bool fifo_isempty_locked(const FIFOBuffer *fb); INLINE bool fifo_isempty_locked(const FIFOBuffer *fb) { bool result; - cpuflags_t flags; - - DISABLE_IRQSAVE(flags); - result = fifo_isempty(fb); - ENABLE_IRQRESTORE(flags); - + ATOMIC(result = fifo_isempty(fb)); return result; } - /*! + + /** * Similar to fifo_push(), but with stronger guarantees for * concurrent access between user and interrupt code. - * This is actually only needed for 8-bit processors. + * + * \note This is actually only needed for 8-bit processors. * * \sa fifo_push() */ - INLINE void fifo_push_locked(FIFOBuffer *fb, unsigned char c); INLINE void fifo_push_locked(FIFOBuffer *fb, unsigned char c) { - cpuflags_t flags; - DISABLE_IRQSAVE(flags); - fifo_push(fb, c); - ENABLE_IRQRESTORE(flags); + ATOMIC(fifo_push(fb, c)); } -#endif /* !__AVR__ */ + /* Probably not really needed, but hard to prove. */ + INLINE unsigned char fifo_pop_locked(FIFOBuffer *fb) + { + unsigned char c; + ATOMIC(c = fifo_pop(fb)); + return c; + } + /** + * Similar to fifo_flush(), but with stronger guarantees for + * concurrent access between user and interrupt code. + * + * \note This is actually only needed for 8-bit processors. + * + * \sa fifo_flush() + */ + INLINE void fifo_flush_locked(FIFOBuffer *fb) + { + ATOMIC(fifo_flush(fb)); + } + +#endif /* CPU_REG_BITS < BITS_PER_PTR */ -/*! + +/** * Thread safe version of fifo_isfull() */ INLINE bool fifo_isfull_locked(const FIFOBuffer *_fb) { - bool _result; - cpuflags_t _flags; - - DISABLE_IRQSAVE(_flags); - _result = fifo_isfull(_fb); - ENABLE_IRQRESTORE(_flags); - - return _result; + bool result; + ATOMIC(result = fifo_isfull(_fb)); + return result; } - -/*! +/** * FIFO Initialization. */ INLINE void fifo_init(FIFOBuffer *fb, unsigned char *buf, size_t size) { + /* FIFO buffers have a known bug with 1-byte buffers. */ + ASSERT(size > 1); + fb->head = fb->tail = fb->begin = buf; fb->end = buf + size - 1; } - #if 0 /*