mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
150 lines
3.5 KiB
C
150 lines
3.5 KiB
C
/**
|
|
* Ringbuffer implementation
|
|
*
|
|
* Copyright (C) 2013 Freie Universität Berlin
|
|
* Copyright (C) 2013 INRIA
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*
|
|
* @ingroup core_util
|
|
* @{
|
|
* @file
|
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
|
* @author René Kijewski <rene.kijewski@fu-berlin.de>
|
|
* @}
|
|
*/
|
|
|
|
#include "ringbuffer.h"
|
|
|
|
#include <string.h>
|
|
|
|
/**
|
|
* @brief Add an element to the end of the ringbuffer.
|
|
* @details This helper function does not check the pre-requirements for adding,
|
|
* i.e. the caller has to ensure that ringbuffer_full() is false.
|
|
* @param[in,out] rb Ringbuffer to operate on.
|
|
* @param[in] c Element to add.
|
|
*/
|
|
static void add_tail(ringbuffer_t *restrict rb, char c)
|
|
{
|
|
unsigned pos = rb->start + rb->avail++;
|
|
|
|
if (pos >= rb->size) {
|
|
pos -= rb->size;
|
|
}
|
|
rb->buf[pos] = c;
|
|
}
|
|
|
|
/**
|
|
* @brief Remove an element from the start of the ringbuffer.
|
|
* @details This helper function does not check the pre-requirements for reading,
|
|
* i.e. the caller has to ensure that ringbuffer_empty() is false.
|
|
* @param[in,out] rb Ringbuffer to operate on.
|
|
* @returns The removed element.
|
|
*/
|
|
static char get_head(ringbuffer_t *restrict rb)
|
|
{
|
|
char result = rb->buf[rb->start];
|
|
|
|
if ((--rb->avail == 0) || (++rb->start == rb->size)) {
|
|
rb->start = 0;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
unsigned ringbuffer_add(ringbuffer_t *restrict rb, const char *buf, unsigned n)
|
|
{
|
|
unsigned i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
if (ringbuffer_full(rb)) {
|
|
break;
|
|
}
|
|
add_tail(rb, buf[i]);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int ringbuffer_add_one(ringbuffer_t *restrict rb, char c)
|
|
{
|
|
int result = -1;
|
|
|
|
if (ringbuffer_full(rb)) {
|
|
result = (unsigned char)get_head(rb);
|
|
}
|
|
add_tail(rb, c);
|
|
return result;
|
|
}
|
|
|
|
int ringbuffer_get_one(ringbuffer_t *restrict rb)
|
|
{
|
|
if (!ringbuffer_empty(rb)) {
|
|
return (unsigned char)get_head(rb);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
unsigned ringbuffer_get(ringbuffer_t *restrict rb, char *buf, unsigned n)
|
|
{
|
|
if (n > rb->avail) {
|
|
n = rb->avail;
|
|
}
|
|
if (n > 0) {
|
|
unsigned bytes_till_end = rb->size - rb->start;
|
|
if (bytes_till_end >= n) {
|
|
memcpy(buf, rb->buf + rb->start, n);
|
|
if (bytes_till_end == n) {
|
|
rb->start = 0;
|
|
}
|
|
else {
|
|
rb->start += n;
|
|
}
|
|
}
|
|
else {
|
|
memcpy(buf, rb->buf + rb->start, bytes_till_end);
|
|
rb->start = n - bytes_till_end;
|
|
memcpy(buf + bytes_till_end, rb->buf, rb->start);
|
|
}
|
|
rb->avail -= n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
unsigned ringbuffer_remove(ringbuffer_t *restrict rb, unsigned n)
|
|
{
|
|
if (n > rb->avail) {
|
|
n = rb->avail;
|
|
rb->start = rb->avail = 0;
|
|
}
|
|
else {
|
|
rb->start += n;
|
|
rb->avail -= n;
|
|
|
|
/* compensate underflow */
|
|
if (rb->start >= rb->size) {
|
|
rb->start -= rb->size;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
int ringbuffer_peek_one(const ringbuffer_t *restrict rb_)
|
|
{
|
|
ringbuffer_t rb = *rb_;
|
|
|
|
return ringbuffer_get_one(&rb);
|
|
}
|
|
|
|
unsigned ringbuffer_peek(const ringbuffer_t *restrict rb_, char *buf,
|
|
unsigned n)
|
|
{
|
|
ringbuffer_t rb = *rb_;
|
|
|
|
return ringbuffer_get(&rb, buf, n);
|
|
}
|