Skip to content

Commit 5ef55bf

Browse files
authored
Merge pull request #3359 from hathach/xfer-fifo
remove ep buffer for port with dedicated hw fifo
2 parents 3884249 + 8cf2c3b commit 5ef55bf

File tree

31 files changed

+1197
-885
lines changed

31 files changed

+1197
-885
lines changed

.clang-format

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ MaxEmptyLinesToKeep: 2
8484
NamespaceIndentation: All
8585
PenaltyBreakBeforeFirstCallParameter: 1000000
8686
PenaltyBreakOpenParenthesis: 1000000
87+
PPIndentWidth: 2
8788
QualifierAlignment: Custom
8889
QualifierOrder: ['static', 'const', 'volatile', 'restrict', 'type']
89-
ReflowComments: false
9090
SpaceAfterTemplateKeyword: false
9191
SpaceBeforeRangeBasedForLoopColon: false
9292
SpaceInEmptyParentheses: false

AGENTS.md

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,39 @@ information that does not match the info here.
1818

1919
- Install ARM GCC toolchain: `sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi`
2020
- Fetch core dependencies: `python3 tools/get_deps.py` -- takes <1 second. NEVER CANCEL.
21-
- For specific board families: `python3 tools/get_deps.py FAMILY_NAME` (e.g., rp2040, stm32f4)
21+
- For specific board families: `python3 tools/get_deps.py FAMILY_NAME` (e.g., rp2040, stm32f4), or
22+
`python3 tools/get_deps.py -b BOARD_NAME`
2223
- Dependencies are cached in `lib/` and `hw/mcu/` directories
2324

2425
## Build Examples
2526

2627
Choose ONE of these approaches:
2728

28-
**Option 1: Individual Example with CMake (RECOMMENDED)**
29+
**Option 1: Individual Example with CMake and Ninja (RECOMMENDED)**
2930

3031
```bash
3132
cd examples/device/cdc_msc
3233
mkdir -p build && cd build
33-
cmake -DBOARD=raspberry_pi_pico -DCMAKE_BUILD_TYPE=MinSizeRel ..
34-
cmake --build . -j4
34+
cmake -DBOARD=raspberry_pi_pico -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel ..
35+
cmake --build .
3536
```
3637

3738
-- takes 1-2 seconds. NEVER CANCEL. Set timeout to 5+ minutes.
3839

39-
**CMake with Ninja (Alternative)**
40+
**Option 2: All Examples for a Board**
41+
42+
different folder than Option 1
4043

4144
```bash
42-
cd examples/device/cdc_msc
43-
mkdir build && cd build
44-
cmake -G Ninja -DBOARD=raspberry_pi_pico ..
45-
ninja
45+
cd examples/
46+
mkdir -p build && cd build
47+
cmake -DBOARD=raspberry_pi_pico -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel ..
48+
cmake --build .
4649
```
4750

48-
**Option 2: Individual Example with Make**
51+
-- takes 15-20 seconds, may have some objcopy failures that are non-critical. NEVER CANCEL. Set timeout to 30+ minutes.
52+
53+
**Option 3: Individual Example with Make**
4954

5055
```bash
5156
cd examples/device/cdc_msc
@@ -54,13 +59,6 @@ make BOARD=raspberry_pi_pico all
5459

5560
-- takes 2-3 seconds. NEVER CANCEL. Set timeout to 5+ minutes.
5661

57-
**Option 3: All Examples for a Board**
58-
59-
```bash
60-
python3 tools/build.py -b BOARD_NAME
61-
```
62-
63-
-- takes 15-20 seconds, may have some objcopy failures that are non-critical. NEVER CANCEL. Set timeout to 30+ minutes.
6462

6563
## Build Options
6664

@@ -101,6 +99,17 @@ python3 tools/build.py -b BOARD_NAME
10199
- Run specific test: `cd test/unit-test && ceedling test:test_fifo`
102100
- Tests use Unity framework with CMock for mocking
103101

102+
## Hardware-in-the-Loop (HIL) Testing
103+
104+
- Run tests on actual hardware, one of following ways:
105+
- test a specific board `python test/hil/hil_test.py -b BOARD_NAME -B examples local.json`
106+
- test all boards in config `python test/hil/hil_test.py -B examples local.json`
107+
- In case of error, enabled verbose mode with `-v` flag for detailed logs. Also try to observe script output, and try to
108+
modify hil_test.py (temporarily) to add more debug prints to pinpoint the issue.
109+
- Requires pre-built (all) examples for target boards (see Build Examples section 2)
110+
111+
take 2-5 minutes. NEVER CANCEL. Set timeout to 20+ minutes.
112+
104113
## Documentation
105114

106115
- Install requirements: `pip install -r docs/requirements.txt`
@@ -145,11 +154,8 @@ python3 tools/build.py -b BOARD_NAME
145154
- Install pre-commit: `pip install pre-commit && pre-commit install`
146155
- Runs all quality checks, unit tests, spell checking, and formatting
147156
- Takes 10-15 seconds. NEVER CANCEL. Set timeout to 15+ minutes.
148-
2. **Build validation**: Build at least one example that exercises your changes
149-
```bash
150-
cd examples/device/cdc_msc
151-
make BOARD=raspberry_pi_pico all
152-
```
157+
2. **Build validation**: Build at least one board with all example that exercises your changes, see Build Examples
158+
section (option 2)
153159
3. Run unit tests relevant to touched modules; add fuzz/HIL coverage when modifying parsers or protocol state machines.
154160

155161
### Manual Testing Scenarios

CLAUDE.md

Lines changed: 0 additions & 78 deletions
This file was deleted.

docs/info/changelog.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Changelog
55
0.20.0
66
======
77

8-
*November 19, 2024*
8+
*November 19, 2025*
99

1010
General
1111
-------

src/class/cdc/cdc_device.c

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ typedef struct {
6666

6767
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, line_coding)
6868

69+
// Skip local EP buffer if dedicated hw FIFO is supported
70+
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0
6971
typedef struct {
7072
TUD_EPBUF_DEF(epout, CFG_TUD_CDC_EP_BUFSIZE);
7173
TUD_EPBUF_DEF(epin, CFG_TUD_CDC_EP_BUFSIZE);
@@ -75,6 +77,9 @@ typedef struct {
7577
#endif
7678
} cdcd_epbuf_t;
7779

80+
CFG_TUD_MEM_SECTION static cdcd_epbuf_t _cdcd_epbuf[CFG_TUD_CDC];
81+
#endif
82+
7883
//--------------------------------------------------------------------+
7984
// Weak stubs: invoked if no strong implementation is available
8085
//--------------------------------------------------------------------+
@@ -115,7 +120,6 @@ TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) {
115120
// INTERNAL OBJECT & FUNCTION DECLARATION
116121
//--------------------------------------------------------------------+
117122
static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
118-
CFG_TUD_MEM_SECTION static cdcd_epbuf_t _cdcd_epbuf[CFG_TUD_CDC];
119123
static tud_cdc_configure_t _cdcd_cfg = TUD_CDC_CONFIGURE_DEFAULT();
120124

121125
TU_ATTR_ALWAYS_INLINE static inline uint8_t find_cdc_itf(uint8_t ep_addr) {
@@ -166,40 +170,22 @@ void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t *coding) {
166170
}
167171

168172
#if CFG_TUD_CDC_NOTIFY
169-
bool tud_cdc_n_notify_uart_state (uint8_t itf, const cdc_notify_uart_state_t *state) {
173+
bool tud_cdc_n_notify_msg(uint8_t itf, cdc_notify_msg_t *msg) {
170174
TU_VERIFY(itf < CFG_TUD_CDC);
171-
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
172-
cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[itf];
175+
const cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
173176
TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0);
174177
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify));
175178

176-
cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify;
177-
notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF;
178-
notify_msg->request.bRequest = CDC_NOTIF_SERIAL_STATE;
179-
notify_msg->request.wValue = 0;
180-
notify_msg->request.wIndex = p_cdc->itf_num;
181-
notify_msg->request.wLength = sizeof(cdc_notify_uart_state_t);
182-
notify_msg->serial_state = *state;
183-
184-
return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_uart_state_t), false);
185-
}
186-
187-
bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change) {
188-
TU_VERIFY(itf < CFG_TUD_CDC);
189-
cdcd_interface_t *p_cdc = &_cdcd_itf[itf];
190-
cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[itf];
191-
TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0);
192-
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify));
179+
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
180+
cdc_notify_msg_t *msg_epbuf = msg;
181+
#else
182+
cdc_notify_msg_t *msg_epbuf = &_cdcd_epbuf[itf].epnotify;
183+
*msg_epbuf = *msg;
184+
#endif
193185

194-
cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify;
195-
notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF;
196-
notify_msg->request.bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE;
197-
notify_msg->request.wValue = 0;
198-
notify_msg->request.wIndex = p_cdc->itf_num;
199-
notify_msg->request.wLength = sizeof(cdc_notify_conn_speed_change_t);
200-
notify_msg->conn_speed_change = *conn_speed_change;
186+
msg_epbuf->request.wIndex = p_cdc->itf_num;
201187

202-
return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_conn_speed_change_t), false);
188+
return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)msg_epbuf, 8 + msg_epbuf->request.wLength, false);
203189
}
204190
#endif
205191

@@ -268,8 +254,6 @@ void cdcd_init(void) {
268254
tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
269255
for (uint8_t i = 0; i < CFG_TUD_CDC; i++) {
270256
cdcd_interface_t *p_cdc = &_cdcd_itf[i];
271-
cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[i];
272-
273257
p_cdc->wanted_char = (char) -1;
274258

275259
// default line coding is : stop bit = 1, parity = none, data bits = 8
@@ -278,14 +262,23 @@ void cdcd_init(void) {
278262
p_cdc->line_coding.parity = 0;
279263
p_cdc->line_coding.data_bits = 8;
280264

265+
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
266+
uint8_t *epout_buf = NULL;
267+
uint8_t *epin_buf = NULL;
268+
#else
269+
cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[i];
270+
uint8_t *epout_buf = p_epbuf->epout;
271+
uint8_t *epin_buf = p_epbuf->epin;
272+
#endif
273+
281274
tu_edpt_stream_init(&p_cdc->stream.rx, false, false, false, p_cdc->stream.rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE,
282-
p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE);
275+
epout_buf, CFG_TUD_CDC_EP_BUFSIZE);
283276

284277
// TX fifo can be configured to change to overwritable if not connected (DTR bit not set). Without DTR we do not
285278
// know if data is actually polled by terminal. This way the most current data is prioritized.
286279
// Default: is overwritable
287280
tu_edpt_stream_init(&p_cdc->stream.tx, false, true, _cdcd_cfg.tx_overwritabe_if_not_connected,
288-
p_cdc->stream.tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE);
281+
p_cdc->stream.tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, epin_buf, CFG_TUD_CDC_EP_BUFSIZE);
289282
}
290283
}
291284

@@ -481,11 +474,35 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
481474
if (ep_addr == stream_rx->ep_addr) {
482475
tu_edpt_stream_read_xfer_complete(stream_rx, xferred_bytes);
483476

484-
// Check for wanted char and invoke wanted callback (multiple times if multiple wanted received)
477+
// Check for wanted char and invoke wanted callback
485478
if (((signed char)p_cdc->wanted_char) != -1) {
486-
for (uint32_t i = 0; i < xferred_bytes; i++) {
487-
if ((p_cdc->wanted_char == (char)stream_rx->ep_buf[i]) && !tu_edpt_stream_empty(stream_rx)) {
488-
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
479+
tu_fifo_buffer_info_t buf_info;
480+
tu_fifo_get_read_info(&stream_rx->ff, &buf_info);
481+
482+
// find backward
483+
uint8_t *ptr;
484+
if (buf_info.wrapped.len > 0) {
485+
ptr = buf_info.wrapped.ptr + buf_info.wrapped.len - 1; // last byte of wrap buffer
486+
} else if (buf_info.linear.len > 0) {
487+
ptr = buf_info.linear.ptr + buf_info.linear.len - 1; // last byte of linear buffer
488+
} else {
489+
ptr = NULL; // no data
490+
}
491+
492+
if (ptr != NULL) {
493+
for (uint32_t i = 0; i < xferred_bytes; i++) {
494+
if (p_cdc->wanted_char == (char)*ptr) {
495+
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
496+
break; // only invoke once per transfer, even if multiple wanted chars are present
497+
}
498+
499+
if (ptr == buf_info.wrapped.ptr) {
500+
ptr = buf_info.linear.ptr + buf_info.linear.len - 1; // last byte of linear buffer
501+
} else if (ptr == buf_info.linear.ptr) {
502+
break; // reached the beginning
503+
} else {
504+
ptr--;
505+
}
489506
}
490507
}
491508
}

0 commit comments

Comments
 (0)