Skip to content

Commit 0e57b19

Browse files
committed
virtio_buffer: manage buffer rollover
1 parent 6dbfc1b commit 0e57b19

File tree

3 files changed

+70
-55
lines changed

3 files changed

+70
-55
lines changed

cores/arduino/VirtIOSerial.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,15 @@ int VirtIOSerial::read(void)
113113

114114
size_t VirtIOSerial::readBytes(char *buffer, size_t length)
115115
{
116-
const size_t size = length;
117-
_startMillis = millis();
118-
while (length > 0 && (millis() - _startMillis < _timeout)) {
119-
uint16_t prev_write_available = virtio_buffer_write_available(&ring);
120-
length -= virtio_buffer_read(&ring, reinterpret_cast<uint8_t *>(buffer), length);
121-
if (prev_write_available < RPMSG_BUFFER_SIZE
122-
&& virtio_buffer_write_available(&ring) >= RPMSG_BUFFER_SIZE) {
123-
MAILBOX_Notify_Rx_Buf_Free();
124-
}
116+
uint16_t prev_write_available = virtio_buffer_write_available(&_VirtIOSerialObj.ring);
117+
const size_t size = virtio_buffer_read(&_VirtIOSerialObj.ring, reinterpret_cast<uint8_t *>(buffer), length);
118+
119+
if (prev_write_available < RPMSG_BUFFER_SIZE
120+
&& virtio_buffer_write_available(&_VirtIOSerialObj.ring) >= RPMSG_BUFFER_SIZE) {
121+
MAILBOX_Notify_Rx_Buf_Free();
125122
}
126-
return size - length;
123+
124+
return size;
127125
}
128126

129127
size_t VirtIOSerial::write(uint8_t ch)

cores/arduino/stm32/virtio/virtio_buffer.c

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -27,85 +27,102 @@
2727
#include <string.h>
2828
#include "wiring.h"
2929

30-
#define BUFFER_END (VIRTIO_BUFFER_SIZE - 1)
31-
3230
void virtio_buffer_init(virtio_buffer_t *ring)
3331
{
34-
ring->write = 0;
35-
ring->read = 0;
32+
ring->write_index = 0;
33+
ring->read_index = 0;
3634
}
3735

3836
uint16_t virtio_buffer_read_available(virtio_buffer_t *ring)
3937
{
40-
// This will make the function safe when write operations are done in interrupts
41-
volatile uint16_t write = ring->write;
38+
int32_t delta = ring->write_index - ring->read_index;
4239

43-
if (write < ring->read) {
44-
return (BUFFER_END - ring->read) + (write + 1);
40+
if (delta < 0) {
41+
return (VIRTIO_BUFFER_SIZE + delta);
4542
}
46-
return write - ring->read;
43+
return delta;
4744
}
4845

46+
/* WARNING no protection against race codition (on ring->read_index) when used in interruption */
4947
static uint16_t read(virtio_buffer_t *ring, uint8_t *dst, uint16_t size, bool peek)
5048
{
51-
// This will make the function safe when write operations are done in interrupts
52-
volatile uint16_t write = ring->write;
53-
uint16_t end = (write >= ring->read) ? write : BUFFER_END + 1;
49+
uint16_t read_index = ring->read_index;
50+
int32_t delta = ring->write_index - read_index;
51+
if (delta < 0) {
52+
delta += VIRTIO_BUFFER_SIZE;
53+
}
54+
55+
size = min(size, delta);
56+
57+
if ((size + read_index) > VIRTIO_BUFFER_SIZE) {
58+
// Manage ring buffer rollover
59+
// First, copy ring buffer from read index to end of buffer
60+
memcpy(dst, ring->buffer + read_index, VIRTIO_BUFFER_SIZE - read_index);
61+
// then, copy ring buffer from begining of buffer to end of read
62+
memcpy(dst + VIRTIO_BUFFER_SIZE - read_index, ring->buffer, size - (VIRTIO_BUFFER_SIZE - read_index));
63+
} else {
64+
memcpy(dst, ring->buffer + read_index, size);
65+
}
5466

55-
size = min(end - ring->read, size);
56-
memcpy(dst, ring->buffer + ring->read, size);
67+
// Update read index if not peeked
5768
if (!peek) {
58-
ring->read += size;
69+
ring->read_index += size;
5970

60-
if (ring->read > BUFFER_END) {
61-
ring->read = 0;
71+
// Manage ring buffer rollover
72+
if (ring->read_index >= VIRTIO_BUFFER_SIZE) {
73+
ring->read_index -= VIRTIO_BUFFER_SIZE;
6274
}
6375
}
6476
return size;
6577
}
6678

6779
uint16_t virtio_buffer_read(virtio_buffer_t *ring, uint8_t *dst, uint16_t size)
6880
{
69-
uint16_t recv_size = read(ring, dst, size, false);
70-
return recv_size;
81+
return read(ring, dst, size, false);
7182
}
7283

73-
/**
74-
* WARNING: The size of read cannot be larger than virtio_buffer_read_available().
75-
*/
84+
7685
uint16_t virtio_buffer_peek(virtio_buffer_t *ring, uint8_t *dst, uint16_t size)
7786
{
78-
size = min(size, virtio_buffer_read_available(ring));
79-
uint16_t recv_size = 0;
80-
while (recv_size < size) {
81-
recv_size += read(ring, dst + recv_size, size - recv_size, true);
82-
}
83-
return recv_size;
87+
return read(ring, dst, size, true);
8488
}
8589

90+
91+
8692
uint16_t virtio_buffer_write_available(virtio_buffer_t *ring)
8793
{
88-
// This will make the function safe when read operations are done in interrupts
89-
volatile uint16_t read = ring->read;
94+
int32_t delta = ring->read_index - ring->write_index - 1;
9095

91-
if (ring->write < read) {
92-
return (read - 1) - ring->write;
96+
if (delta < 0) {
97+
return (VIRTIO_BUFFER_SIZE + delta);
9398
}
94-
return read + (BUFFER_END - ring->write);
99+
return delta;
95100
}
96101

102+
/* WARNING no protection against race codition (on ring->write_index) when used in interruption */
97103
uint16_t virtio_buffer_write(virtio_buffer_t *ring, uint8_t *src, uint16_t size)
98104
{
99-
// This will make the function safe when read operations are done in a interrupt
100-
volatile uint16_t read = ring->read;
101-
uint16_t end = (ring->write < read) ? read - 1
102-
: (read == 0) ? BUFFER_END : BUFFER_END + 1;
103-
104-
size = min(end - ring->write, size);
105-
memcpy(ring->buffer + ring->write, src, size);
106-
ring->write += size;
107-
if (ring->write > BUFFER_END) {
108-
ring->write = 0;
105+
uint16_t write_index = ring->write_index;
106+
int32_t delta = ring->read_index - write_index - 1;
107+
if (delta < 0) {
108+
delta += VIRTIO_BUFFER_SIZE;
109+
}
110+
111+
size = min(size, delta);
112+
113+
if ((size + write_index) > VIRTIO_BUFFER_SIZE) {
114+
// Manage ring buffer rollover
115+
// First, write ring buffer from write index to end of buffer
116+
memcpy(ring->buffer + write_index, src, VIRTIO_BUFFER_SIZE - write_index);
117+
// then, write ring buffer from beginning of buffer to end of read
118+
memcpy(ring->buffer, src + VIRTIO_BUFFER_SIZE - write_index, size - (VIRTIO_BUFFER_SIZE - write_index));
119+
} else {
120+
memcpy(ring->buffer + write_index, src, size);
121+
}
122+
123+
ring->write_index += size;
124+
if (ring->write_index >= VIRTIO_BUFFER_SIZE) {
125+
ring->write_index -= VIRTIO_BUFFER_SIZE;
109126
}
110127
return size;
111128
}

cores/arduino/stm32/virtio/virtio_buffer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ extern "C" {
3434

3535
typedef struct {
3636
uint8_t buffer[VIRTIO_BUFFER_SIZE];
37-
volatile uint16_t write;
38-
volatile uint16_t read;
37+
volatile uint16_t write_index;
38+
volatile uint16_t read_index;
3939
} virtio_buffer_t;
4040

4141
void virtio_buffer_init(virtio_buffer_t *ring);

0 commit comments

Comments
 (0)