ringbuf cleanup

This commit is contained in:
Dan Halbert 2022-09-16 18:46:02 -04:00
parent 32d8dd425f
commit ea15a9118a
15 changed files with 136 additions and 161 deletions

View File

@ -93,6 +93,7 @@ bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer
void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) {
if (!common_hal_bleio_characteristic_buffer_deinited(self)) { if (!common_hal_bleio_characteristic_buffer_deinited(self)) {
bleio_characteristic_clear_observer(self->characteristic); bleio_characteristic_clear_observer(self->characteristic);
ringbuf_deinit(&self->ringbuf);
} }
} }

View File

@ -37,13 +37,13 @@
#include "supervisor/shared/tick.h" #include "supervisor/shared/tick.h"
STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) { STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) {
if (len + sizeof(uint16_t) > ringbuf_capacity(&self->ringbuf)) { if (len + sizeof(uint16_t) > ringbuf_size(&self->ringbuf)) {
// This shouldn't happen. // This shouldn't happen.
return; return;
} }
// Push all the data onto the ring buffer. // Push all the data onto the ring buffer.
// Make room for the new value by dropping the oldest packets first. // Make room for the new value by dropping the oldest packets first.
while (ringbuf_capacity(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) { while (ringbuf_size(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) {
uint16_t packet_length; uint16_t packet_length;
ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t));
for (uint16_t i = 0; i < packet_length; i++) { for (uint16_t i = 0; i < packet_length; i++) {
@ -264,5 +264,6 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) {
void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) {
if (!common_hal_bleio_packet_buffer_deinited(self)) { if (!common_hal_bleio_packet_buffer_deinited(self)) {
bleio_characteristic_clear_observer(self->characteristic); bleio_characteristic_clear_observer(self->characteristic);
ringbuf_deinit(&self->ringbuf);
} }
} }

View File

@ -208,7 +208,9 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
self->sigint_enabled = sigint_enabled; self->sigint_enabled = sigint_enabled;
if (rx != NULL) { if (rx != NULL) {
// Use the provided buffer when given.
if (receiver_buffer != NULL) { if (receiver_buffer != NULL) {
ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size);
self->ringbuf = (ringbuf_t) { receiver_buffer, receiver_buffer_size }; self->ringbuf = (ringbuf_t) { receiver_buffer, receiver_buffer_size };
} else { } else {
// Initially allocate the UART's buffer in the long-lived part of the // Initially allocate the UART's buffer in the long-lived part of the
@ -217,7 +219,6 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
// self->buffer, so do it manually. (However, as long as internal // self->buffer, so do it manually. (However, as long as internal
// pointers like this are NOT moved, allocating the buffer // pointers like this are NOT moved, allocating the buffer
// in the long-lived pool is not strictly necessary) // in the long-lived pool is not strictly necessary)
// (This is a macro.)
if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) { if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) {
m_malloc_fail(receiver_buffer_size); m_malloc_fail(receiver_buffer_size);
} }
@ -337,7 +338,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
pl011->CR = 0; pl011->CR = 0;
} }
active_uart[self->uart_id] = NULL; active_uart[self->uart_id] = NULL;
ringbuf_free(&self->ringbuf); ringbuf_deinit(&self->ringbuf);
uart_status[self->uart_id] = STATUS_FREE; uart_status[self->uart_id] = STATUS_FREE;
common_hal_reset_pin(self->tx_pin); common_hal_reset_pin(self->tx_pin);
common_hal_reset_pin(self->rx_pin); common_hal_reset_pin(self->rx_pin);

View File

@ -36,11 +36,11 @@ typedef struct {
const mcu_pin_obj_t *rx_pin; const mcu_pin_obj_t *rx_pin;
const mcu_pin_obj_t *cts_pin; const mcu_pin_obj_t *cts_pin;
const mcu_pin_obj_t *rts_pin; const mcu_pin_obj_t *rts_pin;
uint8_t uart_id;
uint32_t baudrate; uint32_t baudrate;
uint32_t timeout_ms; uint32_t timeout_ms;
bool sigint_enabled;
ringbuf_t ringbuf; ringbuf_t ringbuf;
bool sigint_enabled;
uint8_t uart_id;
} busio_uart_obj_t; } busio_uart_obj_t;
extern void reset_uart(void); extern void reset_uart(void);

View File

@ -72,11 +72,7 @@ void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buff
void *static_handler_entry) { void *static_handler_entry) {
self->characteristic = characteristic; self->characteristic = characteristic;
self->timeout_ms = timeout * 1000; self->timeout_ms = timeout * 1000;
ringbuf_init(&self->ringbuf, buffer, buffer_size);
self->ringbuf.buf = (uint8_t *)buffer;
self->ringbuf.size = buffer_size;
self->ringbuf.iget = 0;
self->ringbuf.iput = 0;
if (static_handler_entry != NULL) { if (static_handler_entry != NULL) {
ble_event_add_handler_entry((ble_event_handler_entry_t *)static_handler_entry, characteristic_buffer_on_ble_evt, self); ble_event_add_handler_entry((ble_event_handler_entry_t *)static_handler_entry, characteristic_buffer_on_ble_evt, self);
@ -131,6 +127,7 @@ void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_o
if (!common_hal_bleio_characteristic_buffer_deinited(self)) { if (!common_hal_bleio_characteristic_buffer_deinited(self)) {
ble_event_remove_handler(characteristic_buffer_on_ble_evt, self); ble_event_remove_handler(characteristic_buffer_on_ble_evt, self);
self->characteristic = NULL; self->characteristic = NULL;
ringbuf_deinit(&self->ringbuf);
} }
} }

View File

@ -42,13 +42,13 @@
STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, const struct os_mbuf *mbuf) { STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, const struct os_mbuf *mbuf) {
size_t len = OS_MBUF_PKTLEN(mbuf); size_t len = OS_MBUF_PKTLEN(mbuf);
if (len + sizeof(uint16_t) > ringbuf_capacity(&self->ringbuf)) { if (len + sizeof(uint16_t) > ringbuf_size(&self->ringbuf)) {
// This shouldn't happen but can if our buffer size was much smaller than // This shouldn't happen but can if our buffer size was much smaller than
// the writes the client actually makes. // the writes the client actually makes.
return; return;
} }
// Make room for the new value by dropping the oldest packets first. // Make room for the new value by dropping the oldest packets first.
while (ringbuf_capacity(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) { while (ringbuf_size(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) {
uint16_t packet_length; uint16_t packet_length;
ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t));
for (uint16_t i = 0; i < packet_length; i++) { for (uint16_t i = 0; i < packet_length; i++) {
@ -164,10 +164,7 @@ void _common_hal_bleio_packet_buffer_construct(
} }
if (incoming) { if (incoming) {
self->ringbuf.buf = (uint8_t *)incoming_buffer; ringbuf_init(&self->ringbuf, (uint8_t *)incoming_buffer, incoming_buffer_size);
self->ringbuf.size = incoming_buffer_size;
self->ringbuf.iget = 0;
self->ringbuf.iput = 0;
} }
self->packet_queued = false; self->packet_queued = false;
@ -219,8 +216,7 @@ void common_hal_bleio_packet_buffer_construct(
size_t incoming_buffer_size = 0; size_t incoming_buffer_size = 0;
uint32_t *incoming_buffer = NULL; uint32_t *incoming_buffer = NULL;
if (incoming) { if (incoming) {
incoming_buffer_size = buffer_size * (sizeof(uint16_t) + max_packet_size); ringbuf_init(&self->ringbuf, (uint8_t *)incoming_buffer, incoming_buffer_size);
incoming_buffer = m_malloc(incoming_buffer_size, false);
} }
uint32_t *outgoing1 = NULL; uint32_t *outgoing1 = NULL;
@ -414,5 +410,6 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) {
void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) {
if (!common_hal_bleio_packet_buffer_deinited(self)) { if (!common_hal_bleio_packet_buffer_deinited(self)) {
ble_event_remove_handler(packet_buffer_on_ble_client_evt, self); ble_event_remove_handler(packet_buffer_on_ble_client_evt, self);
ringbuf_deinit(&self->ringbuf);
} }
} }

View File

@ -90,10 +90,7 @@ void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buff
self->characteristic = characteristic; self->characteristic = characteristic;
self->timeout_ms = timeout * 1000; self->timeout_ms = timeout * 1000;
self->ringbuf.buf = (uint8_t *)buffer; ringbuf_init(&self->ringbuf, buffer, buffer_size);
self->ringbuf.size = buffer_size;
self->ringbuf.iget = 0;
self->ringbuf.iput = 0;
if (static_handler_entry != NULL) { if (static_handler_entry != NULL) {
ble_drv_add_event_handler_entry((ble_drv_evt_handler_entry_t *)static_handler_entry, characteristic_buffer_on_ble_evt, self); ble_drv_add_event_handler_entry((ble_drv_evt_handler_entry_t *)static_handler_entry, characteristic_buffer_on_ble_evt, self);
@ -159,6 +156,7 @@ void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_o
if (!common_hal_bleio_characteristic_buffer_deinited(self)) { if (!common_hal_bleio_characteristic_buffer_deinited(self)) {
ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self); ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self);
self->characteristic = NULL; self->characteristic = NULL;
ringbuf_deinit(&self->ringbuf);
} }
} }

View File

@ -43,7 +43,7 @@
#include "supervisor/shared/bluetooth/serial.h" #include "supervisor/shared/bluetooth/serial.h"
STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) { STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) {
if (len + sizeof(uint16_t) > ringbuf_capacity(&self->ringbuf)) { if (len + sizeof(uint16_t) > ringbuf_size(&self->ringbuf)) {
// This shouldn't happen but can if our buffer size was much smaller than // This shouldn't happen but can if our buffer size was much smaller than
// the writes the client actually makes. // the writes the client actually makes.
return; return;
@ -52,7 +52,7 @@ STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uin
uint8_t is_nested_critical_region; uint8_t is_nested_critical_region;
sd_nvic_critical_region_enter(&is_nested_critical_region); sd_nvic_critical_region_enter(&is_nested_critical_region);
// Make room for the new value by dropping the oldest packets first. // Make room for the new value by dropping the oldest packets first.
while (ringbuf_capacity(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) { while (ringbuf_size(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) {
uint16_t packet_length; uint16_t packet_length;
ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t));
for (uint16_t i = 0; i < packet_length; i++) { for (uint16_t i = 0; i < packet_length; i++) {
@ -233,10 +233,7 @@ void _common_hal_bleio_packet_buffer_construct(
} }
if (incoming) { if (incoming) {
self->ringbuf.buf = (uint8_t *)incoming_buffer; ringbuf_init(&self->ringbuf, (uint8_t *)incoming_buffer, incoming_buffer_size);
self->ringbuf.size = incoming_buffer_size;
self->ringbuf.iget = 0;
self->ringbuf.iput = 0;
} }
self->packet_queued = false; self->packet_queued = false;
@ -502,7 +499,9 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) {
} }
void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) {
if (!common_hal_bleio_packet_buffer_deinited(self)) { if (!common_hal_bleio_packet_buffer_deinited(self)) {
ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self);
ringbuf_deinit(&self->ringbuf);
} }
} }

View File

@ -213,24 +213,20 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
// Init buffer for rx // Init buffer for rx
if (rx != NULL) { if (rx != NULL) {
self->allocated_ringbuf = true;
// Use the provided buffer when given. // Use the provided buffer when given.
if (receiver_buffer != NULL) { if (receiver_buffer != NULL) {
self->ringbuf.buf = receiver_buffer; ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size);
self->ringbuf.size = receiver_buffer_size - 1; } else {
self->ringbuf.iput = 0;
self->ringbuf.iget = 0;
self->allocated_ringbuf = false;
// Initially allocate the UART's buffer in the long-lived part of the // Initially allocate the UART's buffer in the long-lived part of the
// heap. UARTs are generally long-lived objects, but the "make long- // heap. UARTs are generally long-lived objects, but the "make long-
// lived" machinery is incapable of moving internal pointers like // lived" machinery is incapable of moving internal pointers like
// self->buffer, so do it manually. (However, as long as internal // self->buffer, so do it manually. (However, as long as internal
// pointers like this are NOT moved, allocating the buffer // pointers like this are NOT moved, allocating the buffer
// in the long-lived pool is not strictly necessary) // in the long-lived pool is not strictly necessary)
// (This is a macro.) if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) {
} else if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) { nrfx_uarte_uninit(self->uarte);
nrfx_uarte_uninit(self->uarte); m_malloc_fail(receiver_buffer_size);
m_malloc_fail(receiver_buffer_size); }
} }
self->rx_pin_number = rx->number; self->rx_pin_number = rx->number;
@ -282,9 +278,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
self->rx_pin_number = NO_PIN; self->rx_pin_number = NO_PIN;
self->rts_pin_number = NO_PIN; self->rts_pin_number = NO_PIN;
self->cts_pin_number = NO_PIN; self->cts_pin_number = NO_PIN;
if (self->allocated_ringbuf) { ringbuf_deinit(&self->ringbuf);
ringbuf_free(&self->ringbuf);
}
for (size_t i = 0; i < MP_ARRAY_SIZE(nrfx_uartes); i++) { for (size_t i = 0; i < MP_ARRAY_SIZE(nrfx_uartes); i++) {
if (self->uarte == &nrfx_uartes[i]) { if (self->uarte == &nrfx_uartes[i]) {
@ -305,7 +299,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t
// check removed to reduce code size // check removed to reduce code size
/* /*
if (len > ringbuf_capacity(&self->ringbuf)) { if (len > ringbuf_size(&self->ringbuf)) {
mp_raise_ValueError(translate("Reading >receiver_buffer_size bytes is not supported")); mp_raise_ValueError(translate("Reading >receiver_buffer_size bytes is not supported"));
} }
*/ */

View File

@ -44,7 +44,6 @@ typedef struct {
ringbuf_t ringbuf; ringbuf_t ringbuf;
uint8_t rx_char; // EasyDMA buf uint8_t rx_char; // EasyDMA buf
bool rx_paused; // set by irq if no space in rbuf bool rx_paused; // set by irq if no space in rbuf
bool allocated_ringbuf;
uint8_t tx_pin_number; uint8_t tx_pin_number;
uint8_t rx_pin_number; uint8_t rx_pin_number;

View File

@ -155,27 +155,33 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
uart_set_hw_flow(self->uart, (cts != NULL), (rts != NULL)); uart_set_hw_flow(self->uart, (cts != NULL), (rts != NULL));
if (rx != NULL) { if (rx != NULL) {
// Initially allocate the UART's buffer in the long-lived part of the // Use the provided buffer when given.
// heap. UARTs are generally long-lived objects, but the "make long- if (receiver_buffer != NULL) {
// lived" machinery is incapable of moving internal pointers like ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size);
// self->buffer, so do it manually. (However, as long as internal
// pointers like this are NOT moved, allocating the buffer
// in the long-lived pool is not strictly necessary)
// (This is a macro.)
if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) {
m_malloc_fail(receiver_buffer_size);
}
active_uarts[uart_id] = self;
if (uart_id == 1) {
self->uart_irq_id = UART1_IRQ;
irq_set_exclusive_handler(self->uart_irq_id, uart1_callback);
} else { } else {
self->uart_irq_id = UART0_IRQ; // Initially allocate the UART's buffer in the long-lived part of the
irq_set_exclusive_handler(self->uart_irq_id, uart0_callback); // heap. UARTs are generally long-lived objects, but the "make long-
// lived" machinery is incapable of moving internal pointers like
// self->buffer, so do it manually. (However, as long as internal
// pointers like this are NOT moved, allocating the buffer
// in the long-lived pool is not strictly necessary)
if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) {
uart_deinit(self->uart);
m_malloc_fail(receiver_buffer_size);
}
} }
irq_set_enabled(self->uart_irq_id, true);
uart_set_irq_enables(self->uart, true /* rx has data */, false /* tx needs data */);
} }
active_uarts[uart_id] = self;
if (uart_id == 1) {
self->uart_irq_id = UART1_IRQ;
irq_set_exclusive_handler(self->uart_irq_id, uart1_callback);
} else {
self->uart_irq_id = UART0_IRQ;
irq_set_exclusive_handler(self->uart_irq_id, uart0_callback);
}
irq_set_enabled(self->uart_irq_id, true);
uart_set_irq_enables(self->uart, true /* rx has data */, false /* tx needs data */);
} }
bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) {
@ -187,7 +193,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
return; return;
} }
uart_deinit(self->uart); uart_deinit(self->uart);
ringbuf_free(&self->ringbuf); ringbuf_deinit(&self->ringbuf);
active_uarts[self->uart_id] = NULL; active_uarts[self->uart_id] = NULL;
uart_status[self->uart_id] = STATUS_FREE; uart_status[self->uart_id] = STATUS_FREE;
reset_pin_number(self->tx_pin); reset_pin_number(self->tx_pin);

View File

@ -214,9 +214,16 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
// Init buffer for rx and claim pins // Init buffer for rx and claim pins
if (self->rx != NULL) { if (self->rx != NULL) {
// Use the provided buffer when given.
if (receiver_buffer != NULL) { if (receiver_buffer != NULL) {
self->ringbuf = (ringbuf_t) { receiver_buffer, receiver_buffer_size }; ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size);
} else { } else {
// Initially allocate the UART's buffer in the long-lived part of the
// heap. UARTs are generally long-lived objects, but the "make long-
// lived" machinery is incapable of moving internal pointers like
// self->buffer, so do it manually. (However, as long as internal
// pointers like this are NOT moved, allocating the buffer
// in the long-lived pool is not strictly necessary)
if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) { if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) {
m_malloc_fail(receiver_buffer_size); m_malloc_fail(receiver_buffer_size);
} }
@ -281,7 +288,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
self->rx = NULL; self->rx = NULL;
} }
ringbuf_free(&self->ringbuf); ringbuf_deinit(&self->ringbuf);
} }
size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) {

View File

@ -526,7 +526,9 @@ STATIC mp_obj_t extra_coverage(void) {
// ringbuf // ringbuf
{ {
byte buf[100]; #define RINGBUF_SIZE 99
byte buf[RINGBUF_SIZE];
ringbuf_t ringbuf; ringbuf_t ringbuf;
ringbuf_init(&ringbuf, &buf[0], sizeof(buf)); ringbuf_init(&ringbuf, &buf[0], sizeof(buf));
@ -546,7 +548,7 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf));
// Two-byte put with full ringbuf. // Two-byte put with full ringbuf.
for (int i = 0; i < 99; ++i) { for (int i = 0; i < RINGBUF_SIZE; ++i) {
ringbuf_put(&ringbuf, i); ringbuf_put(&ringbuf, i);
} }
mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf));
@ -558,16 +560,15 @@ STATIC mp_obj_t extra_coverage(void) {
ringbuf_get(&ringbuf); ringbuf_get(&ringbuf);
mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf));
mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0xcc99)); mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0xcc99));
for (int i = 0; i < 97; ++i) { for (int i = 0; i < RINGBUF_SIZE - 2; ++i) {
ringbuf_get(&ringbuf); ringbuf_get(&ringbuf);
} }
mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf));
mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf));
// Two-byte put with wrap around on first byte: // Two-byte put with wrap around on first byte:
ringbuf.iput = 0; ringbuf_clear(&ringbuf);
ringbuf.iget = 0; for (int i = 0; i < RINGBUF_SIZE; ++i) {
for (int i = 0; i < 99; ++i) {
ringbuf_put(&ringbuf, i); ringbuf_put(&ringbuf, i);
ringbuf_get(&ringbuf); ringbuf_get(&ringbuf);
} }
@ -575,9 +576,8 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf));
// Two-byte put with wrap around on second byte: // Two-byte put with wrap around on second byte:
ringbuf.iput = 0; ringbuf_clear(&ringbuf);
ringbuf.iget = 0; for (int i = 0; i < RINGBUF_SIZE - 1; ++i) {
for (int i = 0; i < 98; ++i) {
ringbuf_put(&ringbuf, i); ringbuf_put(&ringbuf, i);
ringbuf_get(&ringbuf); ringbuf_get(&ringbuf);
} }
@ -585,13 +585,11 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf));
// Two-byte get from empty ringbuf. // Two-byte get from empty ringbuf.
ringbuf.iput = 0; ringbuf_clear(&ringbuf);
ringbuf.iget = 0;
mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf));
// Two-byte get from ringbuf with one byte available. // Two-byte get from ringbuf with one byte available.
ringbuf.iput = 0; ringbuf_clear(&ringbuf);
ringbuf.iget = 0;
ringbuf_put(&ringbuf, 0xaa); ringbuf_put(&ringbuf, 0xaa);
mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf));
} }

View File

@ -27,86 +27,85 @@
#include "ringbuf.h" #include "ringbuf.h"
bool ringbuf_init(ringbuf_t *r, uint8_t *buf, size_t capacity) { bool ringbuf_init(ringbuf_t *r, uint8_t *buf, size_t size) {
r->buf = buf; r->buf = buf;
r->size = capacity; r->size = size;
r->iget = r->iput = 0; r->used = 0;
r->next_read = 0;
r->next_write = 0;
return r->buf != NULL; return r->buf != NULL;
} }
// Dynamic initialization. This should be accessible from a root pointer. // Dynamic initialization. This should be accessible from a root pointer..
// capacity is the number of bytes the ring buffer can hold. The actual bool ringbuf_alloc(ringbuf_t *r, size_t size, bool long_lived) {
// size of the buffer is one greater than that, due to how the buffer bool result = ringbuf_init(r, gc_alloc(size, false, long_lived), size);
// handles empty and full statuses. return result;
bool ringbuf_alloc(ringbuf_t *r, size_t capacity, bool long_lived) {
r->buf = gc_alloc(capacity + 1, false, long_lived);
r->size = capacity + 1;
r->iget = r->iput = 0;
return r->buf != NULL;
} }
void ringbuf_free(ringbuf_t *r) { void ringbuf_deinit(ringbuf_t *r) {
// Free buf by letting gc take care of it. If the VM has finished already, // Free buf by doing nothing and letting gc take care of it. If the VM has finished already,
// this will be safe. // this will be safe.
r->buf = (uint8_t *)NULL; r->buf = (uint8_t *)NULL;
r->size = 0; r->size = 0;
ringbuf_clear(r); ringbuf_clear(r);
} }
size_t ringbuf_capacity(ringbuf_t *r) { size_t ringbuf_size(ringbuf_t *r) {
return r->size - 1; return r->size;
} }
// Returns -1 if buffer is empty, else returns byte fetched. // Return -1 if buffer is empty, else return byte fetched.
int ringbuf_get(ringbuf_t *r) { int ringbuf_get(ringbuf_t *r) {
if (r->iget == r->iput) { if (r->used < 1) {
return -1; return -1;
} }
uint8_t v = r->buf[r->iget++]; uint8_t v = r->buf[r->next_read];
if (r->iget >= r->size) { r->next_read++;
r->iget = 0; if (r->next_read >= r->size) {
r->next_read = 0;
} }
r->used--;
return v; return v;
} }
int ringbuf_get16(ringbuf_t *r) { int ringbuf_get16(ringbuf_t *r) {
int v = ringbuf_peek16(r); if (r->used < 2) {
if (v == -1) {
return v;
}
r->iget += 2;
if (r->iget >= r->size) {
r->iget -= r->size;
}
return v;
}
// Returns -1 if no room in buffer, else returns 0.
int ringbuf_put(ringbuf_t *r, uint8_t v) {
uint32_t iput_new = r->iput + 1;
if (iput_new >= r->size) {
iput_new = 0;
}
if (iput_new == r->iget) {
return -1; return -1;
} }
r->buf[r->iput] = v;
r->iput = iput_new; int high_byte = ringbuf_get(r);
int low_byte = ringbuf_get(r);
return (high_byte << 8) | low_byte;
}
// Return -1 if no room in buffer, else return 0.
int ringbuf_put(ringbuf_t *r, uint8_t v) {
if (r->used >= r->size) {
return -1;
}
r->buf[r->next_write] = v;
r->next_write++;
if (r->next_write >= r->size) {
r->next_write = 0;
}
r->used++;
return 0; return 0;
} }
void ringbuf_clear(ringbuf_t *r) { void ringbuf_clear(ringbuf_t *r) {
r->iput = r->iget = 0; r->next_write = 0;
r->next_read = 0;
r->used = 0;
} }
// Number of free slots that can be written. // Number of free slots that can be written.
size_t ringbuf_num_empty(ringbuf_t *r) { size_t ringbuf_num_empty(ringbuf_t *r) {
return (r->size + r->iget - r->iput - 1) % r->size; return r->size - r->used;
} }
// Number of bytes available to read. // Number of bytes available to read.
size_t ringbuf_num_filled(ringbuf_t *r) { size_t ringbuf_num_filled(ringbuf_t *r) {
return (r->size + r->iput - r->iget) % r->size; return r->used;
} }
// If the ring buffer fills up, not all bytes will be written. // If the ring buffer fills up, not all bytes will be written.
@ -134,37 +133,12 @@ size_t ringbuf_get_n(ringbuf_t *r, uint8_t *buf, size_t bufsize) {
return bufsize; return bufsize;
} }
int ringbuf_peek16(ringbuf_t *r) {
if (r->iget == r->iput) {
return -1;
}
uint32_t iget_a = r->iget + 1;
if (iget_a == r->size) {
iget_a = 0;
}
if (iget_a == r->iput) {
return -1;
}
return (r->buf[r->iget] << 8) | (r->buf[iget_a]);
}
int ringbuf_put16(ringbuf_t *r, uint16_t v) { int ringbuf_put16(ringbuf_t *r, uint16_t v) {
uint32_t iput_a = r->iput + 1; if (r->size - r->used < 2) {
if (iput_a == r->size) {
iput_a = 0;
}
if (iput_a == r->iget) {
return -1; return -1;
} }
uint32_t iput_b = iput_a + 1;
if (iput_b == r->size) { ringbuf_put(r, (v >> 8) & 0xff);
iput_b = 0; ringbuf_put(r, v & 0xff);
}
if (iput_b == r->iget) {
return -1;
}
r->buf[r->iput] = (v >> 8) & 0xff;
r->buf[iput_a] = v & 0xff;
r->iput = iput_b;
return 0; return 0;
} }

View File

@ -33,19 +33,23 @@
typedef struct _ringbuf_t { typedef struct _ringbuf_t {
uint8_t *buf; uint8_t *buf;
// Allocated size; capacity is one less. Don't reference this directly.
uint32_t size; uint32_t size;
uint32_t iget; uint32_t used;
uint32_t iput; uint32_t next_read;
uint32_t next_write;
} ringbuf_t; } ringbuf_t;
// Note that the capacity of the buffer is N-1! // For static initialization with an existing buffer, use ringbuf_init().
// For static initialization use ringbuf_init()
bool ringbuf_init(ringbuf_t *r, uint8_t *buf, size_t capacity); bool ringbuf_init(ringbuf_t *r, uint8_t *buf, size_t capacity);
// For allocation of a buffer on the heap, use ringbuf_alloc().
bool ringbuf_alloc(ringbuf_t *r, size_t capacity, bool long_lived); bool ringbuf_alloc(ringbuf_t *r, size_t capacity, bool long_lived);
void ringbuf_free(ringbuf_t *r);
size_t ringbuf_capacity(ringbuf_t *r); // Mark ringbuf as no longer in use, and allow any heap storage to be freed by gc.
void ringbuf_deinit(ringbuf_t *r);
// Note: Ringbuf operations are not atomic.
size_t ringbuf_size(ringbuf_t *r);
int ringbuf_get(ringbuf_t *r); int ringbuf_get(ringbuf_t *r);
int ringbuf_put(ringbuf_t *r, uint8_t v); int ringbuf_put(ringbuf_t *r, uint8_t v);
void ringbuf_clear(ringbuf_t *r); void ringbuf_clear(ringbuf_t *r);
@ -54,9 +58,8 @@ size_t ringbuf_num_filled(ringbuf_t *r);
size_t ringbuf_put_n(ringbuf_t *r, const uint8_t *buf, size_t bufsize); size_t ringbuf_put_n(ringbuf_t *r, const uint8_t *buf, size_t bufsize);
size_t ringbuf_get_n(ringbuf_t *r, uint8_t *buf, size_t bufsize); size_t ringbuf_get_n(ringbuf_t *r, uint8_t *buf, size_t bufsize);
// Note: big-endian. No-op if not enough room available for both bytes. // Note: big-endian. Return -1 if can't read or write two bytes.
int ringbuf_get16(ringbuf_t *r); int ringbuf_get16(ringbuf_t *r);
int ringbuf_peek16(ringbuf_t *r);
int ringbuf_put16(ringbuf_t *r, uint16_t v); int ringbuf_put16(ringbuf_t *r, uint16_t v);
#endif // MICROPY_INCLUDED_PY_RINGBUF_H #endif // MICROPY_INCLUDED_PY_RINGBUF_H