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