X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=mware%2Ffifobuf.h;h=2b749d8fe1c748b275b4ef64d21d7817d2ceb4a1;hb=4309f8e147e1a4741beb0a0b1933e63218bd89ca;hp=1cbd89d4a96336f58c1405856b9742cfce8737e1;hpb=37d3acaa622b7f695ce57578e56311d031a22d22;p=bertos.git diff --git a/mware/fifobuf.h b/mware/fifobuf.h index 1cbd89d4..2b749d8f 100755 --- a/mware/fifobuf.h +++ b/mware/fifobuf.h @@ -1,9 +1,9 @@ -/*! +/** * \file * * * \version $Id$ @@ -12,103 +12,138 @@ * * \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.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 - * - */ +/*#* + *#* $Log$ + *#* Revision 1.22 2006/07/19 12:56:27 bernie + *#* Convert to new Doxygen style. + *#* + *#* Revision 1.21 2005/11/04 16:20:02 bernie + *#* Fix reference to README.devlib in header. + *#* + *#* Revision 1.20 2005/04/11 19:10:28 bernie + *#* Include top-level headers from cfg/ subdir. + *#* + *#* Revision 1.19 2004/12/08 08:30:12 bernie + *#* Add missing header. + *#* + *#* Revision 1.18 2004/11/16 21:55:12 bernie + *#* Workaround for a known fifobuf bug. + *#* + *#* Revision 1.17 2004/09/14 20:57:00 bernie + *#* Use debug.h instead of kdebug.h. + *#* + *#* Revision 1.16 2004/09/06 21:39:08 bernie + *#* Simplify code using ATOMIC(). + *#* + *#* Revision 1.15 2004/08/29 22:05:16 bernie + *#* Rename BITS_PER_PTR to CPU_BITS_PER_PTR. + *#* + *#* Revision 1.14 2004/08/25 14:12:09 rasky + *#* Aggiornato il comment block dei log RCS + *#* + *#* Revision 1.13 2004/08/24 13:16:11 bernie + *#* Add type-size definitions for preprocessor. + *#* + *#* Revision 1.12 2004/08/02 20:20:29 aleph + *#* Merge from project_ks + *#* + *#* Revision 1.11 2004/07/30 14:15:53 rasky + *#* Nuovo supporto unificato per detect della CPU + *#* + *#* Revision 1.10 2004/07/29 22:57:09 bernie + *#* Doxygen fix. + *#* + *#* Revision 1.9 2004/07/20 23:54:27 bernie + *#* fifo_flush_locked(): New function; + *#* Revamp documentation. + *#* + *#* Revision 1.8 2004/07/20 23:47:39 bernie + *#* Finally remove redundant protos. + *#* + *#* Revision 1.7 2004/07/20 23:46:29 bernie + *#* Finally remove redundant protos. + *#* + *#* Revision 1.6 2004/06/06 17:18:04 bernie + *#* Remove redundant declaration of fifo_isempty_locked(). + *#* + *#* 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 + *#*/ #ifndef MWARE_FIFO_H #define MWARE_FIFO_H -#include "cpu.h" -#ifndef COMPILER_H -#include "compiler.h" -#endif +#include +#include typedef struct FIFOBuffer { - unsigned char *head; - unsigned char *tail; + unsigned char * volatile head; + unsigned char * volatile tail; unsigned char *begin; unsigned char *end; } FIFOBuffer; -/* Public function prototypes */ -void fifo_init(volatile FIFOBuffer *fb, unsigned char *buf, size_t size); - -#pragma interrupt called -void fifo_push(volatile FIFOBuffer *fb, unsigned char c); -#pragma interrupt called -unsigned char fifo_pop(volatile FIFOBuffer *fb); +#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 * execution context is calling fifo_push() or fifo_pop() - * only if the CPU can atomically update a pointer. + * only if the CPU can atomically update a pointer + * (which the AVR and other 8-bit processors can't do). + * + * \sa fifo_isempty_locked */ -#define fifo_isempty(fb) ((fb)->head == (fb)->tail) +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 @@ -121,52 +156,233 @@ unsigned char fifo_pop(volatile FIFOBuffer *fb); * fifo_isfull() and fifo_push() are usually called * in the producer context. */ -#define fifo_isfull(fb) \ - ((((fb)->head == (fb)->begin) && ((fb)->tail == (fb)->end)) \ - || ((fb)->tail == (fb)->head - 1)) +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. + * + * \note Calling \c fifo_push() on a full buffer is undefined. + * The caller must make sure the buffer has at least + * one free slot before calling this function. + * + * \note It is safe to call fifo_pop() and fifo_push() from + * concurrent contexts, unless the CPU can't update + * a pointer atomically (which the AVR and other 8-bit + * processors can't do). + * + * \sa fifo_push_locked + */ +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 (UNLIKELY(fb->tail == fb->end)) + /* wrap tail around */ + fb->tail = fb->begin; + else + /* Move tail forward */ + fb->tail++; +} + -/*! +/** + * Pop a character from the fifo buffer. + * + * \note Calling \c fifo_pop() on an empty buffer is undefined. + * The caller must make sure the buffer contains at least + * one character before calling this function. + * + * \note It is safe to call fifo_pop() and fifo_push() from + * concurrent contexts. + */ +INLINE unsigned char fifo_pop(FIFOBuffer *fb) +{ +#ifdef __MWERKS__ +#pragma interrupt called +#endif + //ASSERT_VALID_FIFO(fb); + + if (UNLIKELY(fb->head == fb->end)) + { + /* wrap head around */ + fb->head = fb->begin; + return *(fb->end); + } + else + /* move head forward */ + return *(fb->head++); +} + + +/** * Make the fifo empty, discarding all its current contents. */ -#define fifo_flush(fb) ((fb)->head = (fb)->tail) +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)) + /* + * 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 */ - INLINE bool fifo_isempty_locked(const volatile FIFOBuffer *_fb); - INLINE bool fifo_isempty_locked(const volatile FIFOBuffer *_fb) + /** + * Similar to fifo_isempty(), but with stronger guarantees for + * concurrent access between user and interrupt code. + * + * \note This is actually only needed for 8-bit processors. + * + * \sa fifo_isempty() + */ + INLINE bool fifo_isempty_locked(const FIFOBuffer *fb) { - bool _result; - cpuflags_t _flags; + bool result; + ATOMIC(result = fifo_isempty(fb)); + return result; + } + + + /** + * Similar to fifo_push(), but with stronger guarantees for + * concurrent access between user and interrupt code. + * + * \note This is actually only needed for 8-bit processors. + * + * \sa fifo_push() + */ + INLINE void fifo_push_locked(FIFOBuffer *fb, unsigned char c) + { + ATOMIC(fifo_push(fb, c)); + } - DISABLE_IRQSAVE(_flags); - _result = fifo_isempty(_fb); - ENABLE_IRQRESTORE(_flags); + /* 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; + } - return _result; + /** + * 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 /* !__AVR__ */ +#endif /* CPU_REG_BITS < BITS_PER_PTR */ -/*! + +/** * Thread safe version of fifo_isfull() */ -INLINE bool fifo_isfull_locked(const volatile FIFOBuffer *_fb); -INLINE bool fifo_isfull_locked(const volatile FIFOBuffer *_fb) +INLINE bool fifo_isfull_locked(const FIFOBuffer *_fb) { - bool _result; - cpuflags_t _flags; + bool result; + ATOMIC(result = fifo_isfull(_fb)); + return result; +} - DISABLE_IRQSAVE(_flags); - _result = fifo_isfull(_fb); - ENABLE_IRQRESTORE(_flags); - 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; } -#endif /* MWARE_FIFOBUF_H */ + +#if 0 + +/* + * UNTESTED: if uncommented, to be moved in fifobuf.c + */ +void fifo_pushblock(FIFOBuffer *fb, unsigned char *block, size_t len) +{ + size_t freelen; + + /* Se c'e' spazio da tail alla fine del buffer */ + if (fb->tail >= fb->head) + { + freelen = fb->end - fb->tail + 1; + + /* C'e' abbastanza spazio per scrivere tutto il blocco? */ + if (freelen < len) + { + /* Scrivi quello che entra fino alla fine del buffer */ + memcpy(fb->tail, block, freelen); + block += freelen; + len -= freelen; + fb->tail = fb->begin; + } + else + { + /* Scrivi tutto il blocco */ + memcpy(fb->tail, block, len); + fb->tail += len; + return; + } + } + + for(;;) + { + while (!(freelen = fb->head - fb->tail - 1)) + Delay(FIFO_POLLDELAY); + + /* C'e' abbastanza spazio per scrivere tutto il blocco? */ + if (freelen < len) + { + /* Scrivi quello che entra fino alla fine del buffer */ + memcpy(fb->tail, block, freelen); + block += freelen; + len -= freelen; + fb->tail += freelen; + } + else + { + /* Scrivi tutto il blocco */ + memcpy(fb->tail, block, len); + fb->tail += len; + return; + } + } +} +#endif + +#endif /* MWARE_FIFO_H */