BeRTOS
|
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 */