fifobuf.h
Go to the documentation of this file.
00001
00070 #ifndef STRUCT_FIFO_H
00071 #define STRUCT_FIFO_H
00072 
00073 #include <cpu/types.h>
00074 #include <cpu/irq.h>
00075 #include <cfg/debug.h>
00076
00077 typedef struct FIFOBuffer
00078 {
00079     unsigned char * volatile head;
00080     unsigned char * volatile tail;
00081     unsigned char *begin;
00082     unsigned char *end;
00083 } FIFOBuffer;
00084
00085
00086 #define ASSERT_VALID_FIFO(fifo) \
00087     ATOMIC( \
00088         ASSERT((fifo)->head >= (fifo)->begin); \
00089         ASSERT((fifo)->head <= (fifo)->end); \
00090         ASSERT((fifo)->tail >= (fifo)->begin); \
00091         ASSERT((fifo)->tail <= (fifo)->end); \
00092     )
00093 
00094
00098 #define DEFINE_FIFO(_name, _ptr, _size)         \
00099     FIFOBuffer _name =                  \
00100     {                           \
00101         .head = (_ptr),                 \
00102         .tail = (_ptr),                 \
00103         .begin = (_ptr),                \
00104         .end = (_ptr) + (_size) - 1,            \
00105     };                          \
00106     STATIC_ASSERT((_size) > 1)
00107 
00118 INLINE bool fifo_isempty(const FIFOBuffer *fb)
00119 {
00120     //ASSERT_VALID_FIFO(fb);
00121     return fb->head == fb->tail;
00122 }
00123
00124
00138 INLINE bool fifo_isfull(const FIFOBuffer *fb)
00139 {
00140     //ASSERT_VALID_FIFO(fb);
00141     return
00142         ((fb->head == fb->begin) && (fb->tail == fb->end))
00143         || (fb->tail == fb->head - 1);
00144 }
00145
00146
00161 INLINE void fifo_push(FIFOBuffer *fb, unsigned char c)
00162 {
00163 #ifdef __MWERKS__
00164 #pragma interrupt called
00165 #endif
00166     //ASSERT_VALID_FIFO(fb);
00167
00168     /* Write at tail position */
00169     *(fb->tail) = c;
00170
00171     if (UNLIKELY(fb->tail == fb->end))
00172         /* wrap tail around */
00173         fb->tail = fb->begin;
00174     else
00175         /* Move tail forward */
00176         fb->tail++;
00177 }
00178
00179
00190 INLINE unsigned char fifo_pop(FIFOBuffer *fb)
00191 {
00192 #ifdef __MWERKS__
00193 #pragma interrupt called
00194 #endif
00195     //ASSERT_VALID_FIFO(fb);
00196
00197     if (UNLIKELY(fb->head == fb->end))
00198     {
00199         /* wrap head around */
00200         fb->head = fb->begin;
00201         return *(fb->end);
00202     }
00203     else
00204         /* move head forward */
00205         return *(fb->head++);
00206 }
00207
00208
00212 INLINE void fifo_flush(FIFOBuffer *fb)
00213 {
00214     //ASSERT_VALID_FIFO(fb);
00215     fb->head = fb->tail;
00216 }
00217
00218
00219 #if CPU_REG_BITS >= CPU_BITS_PER_PTR
00220 
00221     /*
00222      * 16/32bit CPUs that can update a pointer with a single write
00223      * operation, no need to disable interrupts.
00224      */
00225     #define fifo_isempty_locked(fb) fifo_isempty((fb))
00226     #define fifo_push_locked(fb, c) fifo_push((fb), (c))
00227     #define fifo_pop_locked(fb)     fifo_pop((fb))
00228     #define fifo_flush_locked(fb)   fifo_flush((fb))
00229 
00230 #else /* CPU_REG_BITS < CPU_BITS_PER_PTR */
00231
00240     INLINE bool fifo_isempty_locked(const FIFOBuffer *fb)
00241     {
00242         bool result;
00243         ATOMIC(result = fifo_isempty(fb));
00244         return result;
00245     }
00246
00247
00256     INLINE void fifo_push_locked(FIFOBuffer *fb, unsigned char c)
00257     {
00258         ATOMIC(fifo_push(fb, c));
00259     }
00260
00261     /* Probably not really needed, but hard to prove. */
00262     INLINE unsigned char fifo_pop_locked(FIFOBuffer *fb)
00263     {
00264         unsigned char c;
00265         ATOMIC(c = fifo_pop(fb));
00266         return c;
00267     }
00268
00277     INLINE void fifo_flush_locked(FIFOBuffer *fb)
00278     {
00279         ATOMIC(fifo_flush(fb));
00280     }
00281
00282 #endif /* CPU_REG_BITS < BITS_PER_PTR */
00283
00284
00288 INLINE bool fifo_isfull_locked(const FIFOBuffer *_fb)
00289 {
00290     bool result;
00291     ATOMIC(result = fifo_isfull(_fb));
00292     return result;
00293 }
00294
00295
00299 INLINE void fifo_init(FIFOBuffer *fb, unsigned char *buf, size_t size)
00300 {
00301     /* FIFO buffers have a known bug with 1-byte buffers. */
00302     ASSERT(size > 1);
00303
00304     fb->head = fb->tail = fb->begin = buf;
00305     fb->end = buf + size - 1;
00306 }
00307
00311 INLINE size_t fifo_len(FIFOBuffer *fb)
00312 {
00313     return fb->end - fb->begin;
00314 }
00315
00316
00317 #if 0
00318 
00319 /*
00320  * UNTESTED: if uncommented, to be moved in fifobuf.c
00321  */
00322 void fifo_pushblock(FIFOBuffer *fb, unsigned char *block, size_t len)
00323 {
00324     size_t freelen;
00325
00326     /* Se c'e' spazio da tail alla fine del buffer */
00327     if (fb->tail >= fb->head)
00328     {
00329         freelen = fb->end - fb->tail + 1;
00330
00331         /* C'e' abbastanza spazio per scrivere tutto il blocco? */
00332         if (freelen < len)
00333         {
00334             /* Scrivi quello che entra fino alla fine del buffer */
00335             memcpy(fb->tail, block, freelen);
00336             block += freelen;
00337             len -= freelen;
00338             fb->tail = fb->begin;
00339         }
00340         else
00341         {
00342             /* Scrivi tutto il blocco */
00343             memcpy(fb->tail, block, len);
00344             fb->tail += len;
00345             return;
00346         }
00347     }
00348
00349     for(;;)
00350     {
00351         while (!(freelen = fb->head - fb->tail - 1))
00352             Delay(FIFO_POLLDELAY);
00353
00354         /* C'e' abbastanza spazio per scrivere tutto il blocco? */
00355         if (freelen < len)
00356         {
00357             /* Scrivi quello che entra fino alla fine del buffer */
00358             memcpy(fb->tail, block, freelen);
00359             block += freelen;
00360             len -= freelen;
00361             fb->tail += freelen;
00362         }
00363         else
00364         {
00365             /* Scrivi tutto il blocco */
00366             memcpy(fb->tail, block, len);
00367             fb->tail += len;
00368             return;
00369         }
00370     }
00371 }
00372 #endif
00373  /* defgroup fifobuf */
00375
00376 #endif /* STRUCT_FIFO_H */