fifobuf.h

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