fifobuf.h

Go to the documentation of this file.
00001 
00069 #ifndef MWARE_FIFO_H
00070 #define MWARE_FIFO_H
00071 
00072 #include <cpu/types.h>
00073 #include <cpu/irq.h>
00074 #include <cfg/debug.h>
00075 
00076 typedef struct FIFOBuffer
00077 {
00078     unsigned char * volatile head;
00079     unsigned char * volatile tail;
00080     unsigned char *begin;
00081     unsigned char *end;
00082 } FIFOBuffer;
00083 
00084 
00085 #define ASSERT_VALID_FIFO(fifo) \
00086     ATOMIC( \
00087         ASSERT((fifo)->head >= (fifo)->begin); \
00088         ASSERT((fifo)->head <= (fifo)->end); \
00089         ASSERT((fifo)->tail >= (fifo)->begin); \
00090         ASSERT((fifo)->tail <= (fifo)->end); \
00091     )
00092 
00093 
00104 INLINE bool fifo_isempty(const FIFOBuffer *fb)
00105 {
00106     //ASSERT_VALID_FIFO(fb);
00107     return fb->head == fb->tail;
00108 }
00109 
00110 
00124 INLINE bool fifo_isfull(const FIFOBuffer *fb)
00125 {
00126     //ASSERT_VALID_FIFO(fb);
00127     return
00128         ((fb->head == fb->begin) && (fb->tail == fb->end))
00129         || (fb->tail == fb->head - 1);
00130 }
00131 
00132 
00147 INLINE void fifo_push(FIFOBuffer *fb, unsigned char c)
00148 {
00149 #ifdef __MWERKS__
00150 #pragma interrupt called
00151 #endif
00152     //ASSERT_VALID_FIFO(fb);
00153 
00154     /* Write at tail position */
00155     *(fb->tail) = c;
00156 
00157     if (UNLIKELY(fb->tail == fb->end))
00158         /* wrap tail around */
00159         fb->tail = fb->begin;
00160     else
00161         /* Move tail forward */
00162         fb->tail++;
00163 }
00164 
00165 
00176 INLINE unsigned char fifo_pop(FIFOBuffer *fb)
00177 {
00178 #ifdef __MWERKS__
00179 #pragma interrupt called
00180 #endif
00181     //ASSERT_VALID_FIFO(fb);
00182 
00183     if (UNLIKELY(fb->head == fb->end))
00184     {
00185         /* wrap head around */
00186         fb->head = fb->begin;
00187         return *(fb->end);
00188     }
00189     else
00190         /* move head forward */
00191         return *(fb->head++);
00192 }
00193 
00194 
00198 INLINE void fifo_flush(FIFOBuffer *fb)
00199 {
00200     //ASSERT_VALID_FIFO(fb);
00201     fb->head = fb->tail;
00202 }
00203 
00204 
00205 #if CPU_REG_BITS >= CPU_BITS_PER_PTR
00206 
00207     /*
00208      * 16/32bit CPUs that can update a pointer with a single write
00209      * operation, no need to disable interrupts.
00210      */
00211     #define fifo_isempty_locked(fb) fifo_isempty((fb))
00212     #define fifo_push_locked(fb, c) fifo_push((fb), (c))
00213     #define fifo_pop_locked(fb)     fifo_pop((fb))
00214     #define fifo_flush_locked(fb)   fifo_flush((fb))
00215 
00216 #else /* CPU_REG_BITS < CPU_BITS_PER_PTR */
00217 
00226     INLINE bool fifo_isempty_locked(const FIFOBuffer *fb)
00227     {
00228         bool result;
00229         ATOMIC(result = fifo_isempty(fb));
00230         return result;
00231     }
00232 
00233 
00242     INLINE void fifo_push_locked(FIFOBuffer *fb, unsigned char c)
00243     {
00244         ATOMIC(fifo_push(fb, c));
00245     }
00246 
00247     /* Probably not really needed, but hard to prove. */
00248     INLINE unsigned char fifo_pop_locked(FIFOBuffer *fb)
00249     {
00250         unsigned char c;
00251         ATOMIC(c = fifo_pop(fb));
00252         return c;
00253     }
00254 
00263     INLINE void fifo_flush_locked(FIFOBuffer *fb)
00264     {
00265         ATOMIC(fifo_flush(fb));
00266     }
00267 
00268 #endif /* CPU_REG_BITS < BITS_PER_PTR */
00269 
00270 
00274 INLINE bool fifo_isfull_locked(const FIFOBuffer *_fb)
00275 {
00276     bool result;
00277     ATOMIC(result = fifo_isfull(_fb));
00278     return result;
00279 }
00280 
00281 
00285 INLINE void fifo_init(FIFOBuffer *fb, unsigned char *buf, size_t size)
00286 {
00287     /* FIFO buffers have a known bug with 1-byte buffers. */
00288     ASSERT(size > 1);
00289 
00290     fb->head = fb->tail = fb->begin = buf;
00291     fb->end = buf + size - 1;
00292 }
00293 
00297 INLINE size_t fifo_len(FIFOBuffer *fb)
00298 {
00299     return fb->end - fb->begin;
00300 }
00301 
00302 
00303 #if 0
00304 
00305 /*
00306  * UNTESTED: if uncommented, to be moved in fifobuf.c
00307  */
00308 void fifo_pushblock(FIFOBuffer *fb, unsigned char *block, size_t len)
00309 {
00310     size_t freelen;
00311 
00312     /* Se c'e' spazio da tail alla fine del buffer */
00313     if (fb->tail >= fb->head)
00314     {
00315         freelen = fb->end - fb->tail + 1;
00316 
00317         /* C'e' abbastanza spazio per scrivere tutto il blocco? */
00318         if (freelen < len)
00319         {
00320             /* Scrivi quello che entra fino alla fine del buffer */
00321             memcpy(fb->tail, block, freelen);
00322             block += freelen;
00323             len -= freelen;
00324             fb->tail = fb->begin;
00325         }
00326         else
00327         {
00328             /* Scrivi tutto il blocco */
00329             memcpy(fb->tail, block, len);
00330             fb->tail += len;
00331             return;
00332         }
00333     }
00334 
00335     for(;;)
00336     {
00337         while (!(freelen = fb->head - fb->tail - 1))
00338             Delay(FIFO_POLLDELAY);
00339 
00340         /* C'e' abbastanza spazio per scrivere tutto il blocco? */
00341         if (freelen < len)
00342         {
00343             /* Scrivi quello che entra fino alla fine del buffer */
00344             memcpy(fb->tail, block, freelen);
00345             block += freelen;
00346             len -= freelen;
00347             fb->tail += freelen;
00348         }
00349         else
00350         {
00351             /* Scrivi tutto il blocco */
00352             memcpy(fb->tail, block, len);
00353             fb->tail += len;
00354             return;
00355         }
00356     }
00357 }
00358 #endif
00359 
00360 #endif /* MWARE_FIFO_H */
00361