/******************************************************************************* * @file rbuf_core.c * @author MEMS Application Team * @version V1.0 * @date 2020-10-15 * @brief ring buffer for interaction RAM *******************************************************************************/ /******************************************************************************/ //includes /******************************************************************************/ #include #include /******************************************************************************/ //constants /******************************************************************************/ /******************************************************************************/ //typedef /******************************************************************************/ /******************************************************************************/ //variables /******************************************************************************/ /******************************************************************************/ //functions /******************************************************************************/ static unsigned int wrap(unsigned int val, unsigned int max) { return val >= max ? (val - max) : val; } static unsigned int _get_space(unsigned int size, unsigned int head, unsigned int tail) { if (tail < head) { return head - tail - 1; } else { return (size - tail) + head - 1; } } static unsigned int _get_rbuf_space(rbuf_t *buf) { return _get_space(buf->size, buf->head, buf->tail); } static unsigned int _get_size(rbuf_t *buf, unsigned int size) { return buf->hlen ? ROUND_UP(size, 4) + buf->hlen : size; } rbuf_t *rbuf_init_buf(char *buf, unsigned int size, unsigned int mode) { rbuf_t *rbuf = (rbuf_t*)buf; rbuf->head = rbuf->tmp_head = 0; rbuf->tail = rbuf->tmp_tail = 0; rbuf->buf_off = RBUF_TO_OF(buf) + sizeof(rbuf_t); rbuf->size = size - sizeof(rbuf_t); if (mode == RBUF_MSG) { rbuf->hlen = sizeof(unsigned int); } else { rbuf->hlen = 0; } rbuf->next = 0; return rbuf; } unsigned int rbuf_get_space(rbuf_t *buf) { unsigned int space = _get_rbuf_space(buf); return (space < buf->hlen) ? 0 : (space - buf->hlen); } void* rbuf_put_claim(rbuf_t *buf, unsigned int size, unsigned int *psz) { unsigned int space, trail_size, allocated; unsigned int *pdata; /* Available size. */ size = _get_size(buf, size); space = _get_space(buf->size, buf->head, buf->tmp_tail); trail_size = buf->size - buf->tmp_tail; /* Data pointer */ pdata = (unsigned int*)RBUF_FR_OF(buf->buf_off + buf->tmp_tail); if (buf->hlen > 0) { /* Limit requested size to available size. */ if (space < size) { return NULL; } /* Limit requested size to be continued */ if (trail_size < size) { if ((space - trail_size) < size) { return NULL; } /* Put Null Msg and Reset tail */ *pdata = 0; buf->tail = buf->tmp_tail = 0; /* Next Msg */ pdata = (unsigned int*)RBUF_FR_OF(buf->buf_off); } /* Update data and size */ allocated = size - buf->hlen; *pdata = allocated; pdata ++; } else { /* Limit requested size to available size. */ size = MIN(size, space); /* Limit allocated size to trail size. */ allocated = MIN(trail_size, size); if (allocated == 0) { return NULL; } } if (psz) { *psz = allocated; } buf->tmp_tail = wrap(buf->tmp_tail + allocated + buf->hlen, buf->size); return pdata; } int rbuf_put_finish(rbuf_t *buf, unsigned int size) { size = _get_size(buf, size); if (size > _get_rbuf_space(buf)) { return -1; } buf->tail = wrap(buf->tail + size, buf->size); buf->tmp_tail = buf->tail; return 0; } void* rbuf_get_claim(rbuf_t *buf, unsigned int size, unsigned int *psz) { unsigned int space, granted_size, trail_size; unsigned int *pdata; /* Check space */ space = (buf->size - 1) - _get_space(buf->size, buf->tmp_head, buf->tail); if (space <= 0) { return NULL; } /* Data Pointer */ pdata = (unsigned int*)RBUF_FR_OF(buf->buf_off + buf->tmp_head); /* Msg process */ if (buf->hlen > 0) { /* Skip null data and reset head */ if (*pdata == 0) { buf->head = buf->tmp_head = 0; /* Check empty */ if (buf->head == buf->tail) { return NULL; } pdata = (unsigned int*)RBUF_FR_OF(buf->buf_off); } /* Update data and size */ granted_size = *pdata; pdata ++; } else { /* Limit requested size to available size. */ granted_size = MIN(size, space); /* Limit allocated size to trail size. */ trail_size = buf->size - buf->tmp_head; granted_size = MIN(trail_size, granted_size); } if (psz) { *psz = granted_size; } buf->tmp_head = wrap(buf->tmp_head + granted_size + buf->hlen, buf->size); return pdata; } int rbuf_get_finish(rbuf_t *buf, unsigned int size) { unsigned int allocated; size = _get_size(buf, size); allocated = (buf->size - 1) - _get_rbuf_space(buf); if (size > allocated) { return -1; } buf->head = wrap(buf->head + size, buf->size); buf->tmp_head = buf->head; return 0; } unsigned int rbuf_get_hdl(rbuf_t *buf, unsigned int size, rbuf_hdl hdl, void *ctx) { void *pdata; /* read data */ pdata = rbuf_get_claim(buf, size, &size); if (pdata != NULL) { /* handle data */ size = (*hdl)(ctx, pdata, size); } /* finish data */ rbuf_get_finish(buf, size); return size; } unsigned int rbuf_get_length(rbuf_t *buf) { if (buf->tail < buf->head) { return buf->size + buf->tail - buf->head; } else { return buf->tail - buf->head; } }