/** @file fifo_buffered.c @brief fifo implementation for buffered access @date 2016-02-04 the module implements fifo using circular buffer in this module we provide a buffered area for deferred reading this is the case for DMA access where during the operation the buffer has to be blocked the application writes to the buffer synchonously. the driver blocks written buffer in order to proceed the DMA transfer operation to the IO device (deferred operation) when the deferred operation exits, then the blocked buffer is released and can be reused */ #include "fifo_buffered.h" /** initialize the structure check and adapt buffer top value @param ctx pointer to structure @param data pointer to buffer area @param top the topmax value of any index (thus not exceeding the value range) */ void fifo_init(fifo_t *ctx, uint8_t *data, fifo_size_t top) { ctx->in = 0; ctx->out = 0; ctx->top = top; ctx->data = data; ctx->locked_size = 0; } /** check data size @param ctx pointer to structure @return 1 if fifo does not contain data otherwise 0 */ bool fifo_isempty(fifo_t *ctx) { if(ctx->in == ctx->out) { return true; } return false; } /** check locked data size @param ctx pointer to structure @return 1 if fifo does not contain data otherwise 0 */ bool fifo_islocked(fifo_t *ctx) { if(ctx->locked_size != 0) { return true; } return false; } /** write one byte into fifo @param ctx pointer to structure @param data data to write @return number of bytes written, is 1 if fifo is not full */ fifo_size_t fifo_write(fifo_t *ctx, uint8_t data) { // cache pointer fifo_size_t in = ctx->in; ctx->data[in] = data; in++; if(in > ctx->top) { in = 0; } if (in != ctx->out) { //flush ctx->in = in; return 1; } return 0; } /** write several byte into fifo @param ctx pointer to structure @param data data to write @param len number of bytes to write @return number of bytes written */ fifo_size_t fifo_write_buf(fifo_t *ctx, const uint8_t *data, fifo_size_t len) { // cache pointer fifo_size_t in = ctx->in; fifo_size_t out = ctx->out; fifo_size_t s = 0; /* if(in == out) { // reallign the buffer for longer sequencial memory in = 0; ctx->out = 0; ctx->locked_size = 0; } */ while(len > 0) { ctx->data[in] = *data++; in++; // skipping check if(in > ctx->top) { in = 0; } // overflow check if (in == out) { if(in == 0) { in = ctx->top; } else { in--; } break; } s++; len--; } //flush ctx->in = in; return s; } /** read single byte from fifo @param ctx pointer to structure @param data pointer to data for outgoing bytes @return number of bytes read out */ fifo_size_t fifo_read(fifo_t *ctx, uint8_t *data) { // cache pointer fifo_size_t out = ctx->out; if (ctx->in != out) { *data = ctx->data[out]; out++; if(out > ctx->top) { out = 0; } // flush ctx->out = out; return 1; } return 0; } void fifo_clear(fifo_t *ctx) { ctx->in = 0; ctx->out = 0; ctx->locked_size = 0; } /** aquire a buffer for reading from fifo once the deferred read operation completes fifo_read_unlock will release the lock @param ctx pointer to structure @param data pointer to data pointer that contains the start of the buffer @return number of bytes in the buffer, 0 if no data available */ fifo_size_t fifo_read_locked(fifo_t *ctx, uint8_t **data) { // cache pointer fifo_size_t out = ctx->out; fifo_size_t in = ctx->in; fifo_size_t locked_size = ctx->locked_size; // abort if no data in buffer or deferred operation in progress if((in == out) || (locked_size != 0)) { return 0; } // aquire data pointer *data = &ctx->data[out]; // get length of continous buffer if(in > out) { // aquire all locked_size = in - out; } else { locked_size = ctx->top - out + 1; } ctx->locked_size = locked_size; return locked_size; } /** release locked buffer area @return 0-if fifo becomes empty, 1-if still some data in buffer */ fifo_size_t fifo_read_unlock(fifo_t *ctx) { // cache pointer fifo_size_t out = ctx->out + ctx->locked_size; if(out > ctx->top) { out = 0; } ctx->out = out; ctx->locked_size = 0; return (out != ctx->in) ? 1 : 0; } /// return the current occupied size fifo_size_t fifo_size(fifo_t *ctx) { // cache the volatile members fifo_size_t in = ctx->in; fifo_size_t out = ctx->out; if(in >= out) { return in - out; } else { return (ctx->top - out) + in + 1; } } fifo_size_t fifo_capacity(fifo_t *ctx) { return ctx->top; }