Skip to content

Commit

Permalink
Merge pull request #142 from mryndzionek/bipbuffer
Browse files Browse the repository at this point in the history
Use a bip buffer instead of a ring buffer
  • Loading branch information
dawsonjon authored Oct 30, 2024
2 parents e90e9fe + 8d4103f commit 47503cf
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 497 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if(PICO_BOARD STREQUAL "pico")
event.c
usb_descriptors.c
usb_audio_device.c
ring_buffer_lib.c
bipbuffer.c
squelch.c
)

Expand Down
188 changes: 188 additions & 0 deletions bipbuffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/**
* Copyright (c) 2011, Willem-Hendrik Thiart
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* @file
* @author Willem Thiart [email protected]
*/

#include "stdio.h"
#include <stdlib.h>

/* for memcpy */
#include <string.h>

#include "bipbuffer.h"

static size_t bipbuf_sizeof(const unsigned int size)
{
return sizeof(bipbuf_t) + size;
}

int bipbuf_unused(bipbuf_t *me)
{
critical_section_enter_blocking(&me->crit);
int ret;
if (1 == me->b_inuse)
/* distance between region B and region A */
ret = me->a_start - me->b_end;
else
ret = me->size - me->a_end;
critical_section_exit(&me->crit);
return ret;
}

static inline int _unused(const bipbuf_t *me)
{
if (1 == me->b_inuse)
/* distance between region B and region A */
return me->a_start - me->b_end;
else
return me->size - me->a_end;
}

int bipbuf_size(bipbuf_t *me)
{
critical_section_enter_blocking(&me->crit);
int ret = me->size;
critical_section_exit(&me->crit);
return ret;
}

int bipbuf_used(bipbuf_t *me)
{
critical_section_enter_blocking(&me->crit);
int ret = (me->a_end - me->a_start) + me->b_end;
critical_section_exit(&me->crit);
return ret;
}

static void bipbuf_init(bipbuf_t *me, const unsigned int size)
{
me->a_start = me->a_end = me->b_end = 0;
me->size = size;
me->b_inuse = 0;
}

bipbuf_t *bipbuf_new(const unsigned int size)
{
bipbuf_t *me = calloc(1, bipbuf_sizeof(size));
if (!me)
return NULL;
bipbuf_init(me, size);
critical_section_init(&me->crit);
return me;
}

void bipbuf_free(bipbuf_t *me)
{
critical_section_deinit(&me->crit);
free(me);
}

int bipbuf_is_empty(bipbuf_t *me)
{
critical_section_enter_blocking(&me->crit);
int ret = me->a_start == me->a_end;
critical_section_exit(&me->crit);
return ret;
}

static inline int _is_empty(const bipbuf_t *me)
{
return me->a_start == me->a_end;
}

/* find out if we should turn on region B
* ie. is the distance from A to buffer's end less than B to A? */
static void __check_for_switch_to_b(bipbuf_t *me)
{
if (me->size - me->a_end < me->a_start - me->b_end)
me->b_inuse = 1;
}

int bipbuf_offer(bipbuf_t *me, const unsigned char *data, const int size)
{
critical_section_enter_blocking(&me->crit);
/* not enough space */
if (_unused(me) < size)
{
critical_section_exit(&me->crit);
return 0;
}

if (1 == me->b_inuse)
{
memcpy(me->data + me->b_end, data, size);
me->b_end += size;
}
else
{
memcpy(me->data + me->a_end, data, size);
me->a_end += size;
}

__check_for_switch_to_b(me);
critical_section_exit(&me->crit);
return size;
}

unsigned char *bipbuf_peek(bipbuf_t *me, const unsigned int size)
{
critical_section_enter_blocking(&me->crit);
/* make sure we can actually peek at this data */
if (me->size < me->a_start + size)
{
critical_section_exit(&me->crit);
return NULL;
}

if (_is_empty(me))
{
critical_section_exit(&me->crit);
return NULL;
}

critical_section_exit(&me->crit);
return (unsigned char *)me->data + me->a_start;
}

unsigned char *bipbuf_poll(bipbuf_t *me, const unsigned int size)
{
critical_section_enter_blocking(&me->crit);
if (_is_empty(me))
{
critical_section_exit(&me->crit);
return NULL;
}

/* make sure we can actually poll this data */
if (me->size < me->a_start + size)
{
critical_section_exit(&me->crit);
return NULL;
}

void *end = me->data + me->a_start;
me->a_start += size;

/* we seem to be empty.. */
if (me->a_start == me->a_end)
{
/* replace a with region b */
if (1 == me->b_inuse)
{
me->a_start = 0;
me->a_end = me->b_end;
me->b_end = me->b_inuse = 0;
}
else
/* safely move cursor back to the start because we are empty */
me->a_start = me->a_end = 0;
}

__check_for_switch_to_b(me);
critical_section_exit(&me->crit);
return end;
}
76 changes: 76 additions & 0 deletions bipbuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#pragma once

#include "pico/critical_section.h"

#ifdef __cplusplus
extern "C"
{
#endif

typedef struct
{
unsigned long int size;

/* region A */
unsigned int a_start, a_end;

/* region B */
unsigned int b_end;

/* is B inuse? */
int b_inuse;
critical_section_t crit;
unsigned char data[];
} bipbuf_t;

/**
* Create a new bip buffer.
*
* malloc()s space
*
* @param[in] size The size of the buffer */
bipbuf_t *bipbuf_new(const unsigned int size);

/**
* Free the bip buffer */
void bipbuf_free(bipbuf_t *me);

/**
* @param[in] data The data to be offered to the buffer
* @param[in] size The size of the data to be offered
* @return number of bytes offered */
int bipbuf_offer(bipbuf_t *me, const unsigned char *data, const int size);

/**
* Look at data. Don't move cursor
*
* @param[in] len The length of the data to be peeked
* @return data on success, NULL if we can't peek at this much data */
unsigned char *bipbuf_peek(bipbuf_t* me, const unsigned int len);

/**
* Get pointer to data to read. Move the cursor on.
*
* @param[in] len The length of the data to be polled
* @return pointer to data, NULL if we can't poll this much data */
unsigned char *bipbuf_poll(bipbuf_t* me, const unsigned int size);

/**
* @return the size of the bipbuffer */
int bipbuf_size(bipbuf_t* me);

/**
* @return 1 if buffer is empty; 0 otherwise */
int bipbuf_is_empty(bipbuf_t* me);

/**
* @return how much space we have assigned */
int bipbuf_used(bipbuf_t* cb);

/**
* @return bytes of unused space */
int bipbuf_unused(bipbuf_t* me);

#ifdef __cplusplus
}
#endif
Loading

0 comments on commit 47503cf

Please sign in to comment.