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 */
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)