-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #142 from mryndzionek/bipbuffer
Use a bip buffer instead of a ring buffer
- Loading branch information
Showing
6 changed files
with
277 additions
and
497 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.