Skip to content

Commit a6cfc3f

Browse files
authored
Merge pull request #21788 from kfessel/p-usb-turb
sys/usb/cdc_acm, sys/tsrb: speedup usb_cdc ringbuffer handling
2 parents d450db4 + d893fc9 commit a6cfc3f

File tree

4 files changed

+261
-69
lines changed

4 files changed

+261
-69
lines changed

sys/include/tsrb.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ extern "C" {
3333
#endif
3434

3535
/**
36-
* @brief thread-safe ringbuffer struct
36+
* @brief thread-safe ringbuffer struct
3737
*/
3838
typedef struct tsrb {
3939
uint8_t *buf; /**< Buffer to operate on. */
@@ -43,22 +43,22 @@ typedef struct tsrb {
4343
} tsrb_t;
4444

4545
/**
46-
* @brief Static initializer
46+
* @brief Static initializer
4747
*
4848
* @note The size of the buffer (`sizeof(@p BUF)`) must be a power of two.
4949
*
50-
* @param[in] BUF Buffer to use by tsrb.
50+
* @param[in] BUF Buffer to use by tsrb.
5151
*/
5252
#define TSRB_INIT(BUF) { (BUF), sizeof (BUF), 0, 0 }
5353

5454
/**
55-
* @brief Initialize a tsrb.
55+
* @brief Initialize a tsrb.
5656
*
5757
* @note The size of the buffer (@p bufsize) must be a power of two.
5858
*
59-
* @param[out] rb Datum to initialize.
60-
* @param[in] buffer Buffer to use by tsrb.
61-
* @param[in] bufsize Size of @p buffer.
59+
* @param[out] rb Datum to initialize.
60+
* @param[in] buffer Buffer to use by tsrb.
61+
* @param[in] bufsize Size of @p buffer.
6262
*/
6363
static inline void tsrb_init(tsrb_t *rb, uint8_t *buffer, unsigned bufsize)
6464
{
@@ -74,8 +74,8 @@ static inline void tsrb_init(tsrb_t *rb, uint8_t *buffer, unsigned bufsize)
7474
}
7575

7676
/**
77-
* @brief Clear a tsrb.
78-
* @param[out] rb Ringbuffer to operate on
77+
* @brief Clear a tsrb.
78+
* @param[out] rb Ringbuffer to operate on
7979
*/
8080
static inline void tsrb_clear(tsrb_t *rb)
8181
{
@@ -106,7 +106,7 @@ static inline int tsrb_empty(const tsrb_t *rb)
106106
static inline unsigned int tsrb_avail(const tsrb_t *rb)
107107
{
108108
unsigned irq_state = irq_disable();
109-
int retval = (rb->writes - rb->reads);
109+
unsigned int retval = (rb->writes - rb->reads);
110110
irq_restore(irq_state);
111111
return retval;
112112
}
@@ -133,7 +133,7 @@ static inline int tsrb_full(const tsrb_t *rb)
133133
static inline unsigned int tsrb_free(const tsrb_t *rb)
134134
{
135135
unsigned irq_state = irq_disable();
136-
int retval = (rb->size - rb->writes + rb->reads);
136+
unsigned int retval = (rb->size - rb->writes + rb->reads);
137137
irq_restore(irq_state);
138138
return retval;
139139
}

sys/include/turb.h

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2015 Kaspar Schleiser <[email protected]>
3+
* SPDX-FileCopyrightText: 2025 Karl Fessel <[email protected]> ML!PA Consulting GmbH
4+
* SPDX-License-Identifier: LGPL-2.1-only
5+
*/
6+
7+
#pragma once
8+
9+
/**
10+
* @ingroup sys_tsrb
11+
* @brief Thread Unsafe access to Thread-safe ringbuffer
12+
* @{
13+
*
14+
* @attention use only if you ensurred thread safety otherwise
15+
* e.g.: by an irq guard
16+
* @file
17+
* @brief Thread-unsafe ringbuffer interface definition
18+
*
19+
* @author Kaspar Schleiser <[email protected]>
20+
* @author Karl Fessel <[email protected]>
21+
*/
22+
23+
#include "tsrb.h"
24+
25+
#ifdef __cplusplus
26+
extern "C" {
27+
#endif
28+
29+
/**
30+
* @brief Clear a tsrb.
31+
* @attention use only if you ensurred thread safety otherwise
32+
* @param[out] rb Ringbuffer to operate on
33+
*/
34+
static inline void turb_clear(tsrb_t *rb)
35+
{
36+
rb->reads = rb->writes;
37+
}
38+
39+
/**
40+
* @brief Test if the tsrb is empty.
41+
* @attention use only if you ensurred thread safety otherwise
42+
* @param[in] rb Ringbuffer to operate on
43+
* @return 0 if not empty
44+
* @return 1 otherwise
45+
*/
46+
static inline int turb_empty(const tsrb_t *rb)
47+
{
48+
int retval = (rb->reads == rb->writes);
49+
return retval;
50+
}
51+
52+
/**
53+
* @brief Get number of bytes available for reading
54+
* @attention use only if you ensurred thread safety otherwise
55+
* @param[in] rb Ringbuffer to operate on
56+
* @return nr of available bytes
57+
*/
58+
static inline unsigned int turb_avail(const tsrb_t *rb)
59+
{
60+
unsigned retval = (rb->writes - rb->reads);
61+
return retval;
62+
}
63+
64+
/**
65+
* @brief Test if the tsrb is full
66+
* @attention use only if you ensurred thread safety otherwise
67+
* @param[in] rb Ringbuffer to operate on
68+
* @return 0 if not full
69+
* @return 1 otherwise
70+
*/
71+
static inline int turb_full(const tsrb_t *rb)
72+
{
73+
int retval = (rb->writes - rb->reads) == rb->size;
74+
return retval;
75+
}
76+
77+
/**
78+
* @brief Get free space in ringbuffer
79+
* @attention use only if you ensurred thread safety otherwise
80+
* @param[in] rb Ringbuffer to operate on
81+
* @return nr of available bytes
82+
*/
83+
static inline unsigned int turb_free(const tsrb_t *rb)
84+
{
85+
unsigned int retval = (rb->size - rb->writes + rb->reads);
86+
return retval;
87+
}
88+
89+
#ifndef DOXYGEN
90+
/* these are internal function */
91+
static inline void _turb_push(tsrb_t *rb, uint8_t c)
92+
{
93+
rb->buf[rb->writes++ & (rb->size - 1)] = c;
94+
}
95+
96+
static inline uint8_t _turb_pop(tsrb_t *rb)
97+
{
98+
return rb->buf[rb->reads++ & (rb->size - 1)];
99+
}
100+
101+
static inline uint8_t _turb_peek(tsrb_t *rb, unsigned int idx)
102+
{
103+
return rb->buf[(rb->reads + idx) & (rb->size - 1)];
104+
}
105+
#endif
106+
107+
/**
108+
* @brief Get a byte from ringbuffer
109+
* @attention use only if you ensurred thread safety otherwise
110+
* @param[in] rb Ringbuffer to operate on
111+
* @return >=0 byte that has been read
112+
* @return -1 if no byte available
113+
*/
114+
static inline int turb_get_one(tsrb_t *rb)
115+
{
116+
int retval = -1;
117+
if (!turb_empty(rb)) {
118+
retval = _turb_pop(rb);
119+
}
120+
return retval;
121+
}
122+
123+
/**
124+
* @brief Get a byte from ringbuffer, without removing it
125+
* @attention use only if you ensurred thread safety otherwise
126+
* @param[in] rb Ringbuffer to operate on
127+
* @return >=0 byte that has been read
128+
* @return -1 if no byte available
129+
*/
130+
static inline int turb_peek_one(tsrb_t *rb)
131+
{
132+
int retval = -1;
133+
if (!turb_empty(rb)) {
134+
retval = _turb_peek(rb, 0);
135+
}
136+
return retval;
137+
}
138+
139+
/**
140+
* @brief Get bytes from ringbuffer
141+
* @attention use only if you ensurred thread safety otherwise
142+
* @param[in] rb Ringbuffer to operate on
143+
* @param[out] dst buffer to write to
144+
* @param[in] n max number of bytes to write to @p dst
145+
* @return nr of bytes written to @p dst
146+
*/
147+
static inline int turb_get(tsrb_t *rb, uint8_t *dst, size_t n)
148+
{
149+
size_t cnt = 0;
150+
while (n-- && !turb_empty(rb)) {
151+
*dst++ = _turb_pop(rb);
152+
cnt++;
153+
}
154+
return (int) cnt;
155+
}
156+
157+
/**
158+
* @brief Get bytes from ringbuffer, without removing them
159+
* @attention use only if you ensurred thread safety otherwise
160+
* @param[in] rb Ringbuffer to operate on
161+
* @param[out] dst buffer to write to
162+
* @param[in] n max number of bytes to write to @p dst
163+
* @return nr of bytes written to @p dst
164+
*/
165+
static inline int turb_peek(tsrb_t *rb, uint8_t *dst, size_t n)
166+
{
167+
size_t idx = 0;
168+
unsigned int avail = turb_avail(rb);
169+
while (idx < n && idx != avail) {
170+
*dst++ = _turb_peek(rb, idx++);
171+
}
172+
return (int) idx;
173+
}
174+
175+
/**
176+
* @brief Drop bytes from ringbuffer
177+
* @attention use only if you ensurred thread safety otherwise
178+
* @param[in] rb Ringbuffer to operate on
179+
* @param[in] n max number of bytes to drop
180+
* @return nr of bytes dropped
181+
*/
182+
static inline int turb_drop(tsrb_t *rb, size_t n)
183+
{
184+
size_t cnt = 0;
185+
while (n-- && !turb_empty(rb)) {
186+
_turb_pop(rb);
187+
cnt++;
188+
}
189+
return (int) cnt;
190+
}
191+
192+
/**
193+
* @brief Add a byte to ringbuffer
194+
* @attention use only if you ensurred thread safety otherwise
195+
* @param[in] rb Ringbuffer to operate on
196+
* @param[in] c Character to add to ringbuffer
197+
* @return 0 on success
198+
* @return -1 if no space available
199+
*/
200+
static inline int turb_add_one(tsrb_t *rb, uint8_t c)
201+
{
202+
int retval = -1;
203+
if (!turb_full(rb)) {
204+
_turb_push(rb, c);
205+
retval = 0;
206+
}
207+
return retval;
208+
}
209+
210+
/**
211+
* @brief Add bytes to ringbuffer
212+
* @attention use only if you ensurred thread safety otherwise
213+
* @param[in] rb Ringbuffer to operate on
214+
* @param[in] src buffer to read from
215+
* @param[in] n max number of bytes to read from @p src
216+
* @return nr of bytes read from @p src
217+
*/
218+
static inline int turb_add(tsrb_t *rb, const uint8_t *src, size_t n)
219+
{
220+
size_t ret = 0;
221+
while (n-- && !turb_full(rb)) {
222+
_turb_push(rb, *src++);
223+
ret++;
224+
}
225+
return (int) ret;
226+
}
227+
228+
#ifdef __cplusplus
229+
}
230+
#endif
231+
232+
/** @} */

0 commit comments

Comments
 (0)