mirror of
https://github.com/hathach/tinyusb.git
synced 2026-02-04 09:05:35 +00:00
Merge pull request #3461 from hathach/edpt_stream-remove-nofifo-mode
remove no-fifo mode in edpt stream API
This commit is contained in:
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -315,7 +315,7 @@ jobs:
|
||||
run: python3 tools/get_deps.py $BUILD_ARGS
|
||||
|
||||
- name: Build
|
||||
run: python3 tools/build.py -j 4 --toolchain iar $BUILD_ARGS
|
||||
run: python3 tools/build.py --toolchain iar $BUILD_ARGS
|
||||
|
||||
- name: Test on actual hardware (hardware in the loop)
|
||||
run: python3 test/hil/hil_test.py hfp.json
|
||||
|
||||
266
src/class/vendor/vendor_device.c
vendored
266
src/class/vendor/vendor_device.c
vendored
@ -40,36 +40,33 @@ typedef struct {
|
||||
uint8_t rhport;
|
||||
uint8_t itf_num;
|
||||
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
struct {
|
||||
tu_edpt_stream_t tx;
|
||||
tu_edpt_stream_t rx;
|
||||
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
|
||||
tu_edpt_stream_t tx_stream;
|
||||
tu_edpt_stream_t rx_stream;
|
||||
uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
|
||||
uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
|
||||
#else
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
uint16_t ep_in_mps;
|
||||
uint16_t ep_out_mps;
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
||||
uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
|
||||
#endif
|
||||
} stream;
|
||||
} vendord_interface_t;
|
||||
|
||||
#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + sizeof(((vendord_interface_t *)0)->itf_num))
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + TU_FIELD_SIZE(vendord_interface_t, itf_num))
|
||||
#else
|
||||
#define ITF_MEM_RESET_SIZE sizeof(vendord_interface_t)
|
||||
#endif
|
||||
|
||||
static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
|
||||
|
||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
|
||||
// Skip local EP buffer if dedicated hw FIFO is supported or no fifo mode
|
||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || !CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
typedef struct {
|
||||
// Skip local EP buffer if dedicated hw FIFO is supported
|
||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
|
||||
TUD_EPBUF_DEF(epout, CFG_TUD_VENDOR_EPSIZE);
|
||||
#endif
|
||||
|
||||
// Skip local EP buffer if dedicated hw FIFO is supported
|
||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0
|
||||
TUD_EPBUF_DEF(epin, CFG_TUD_VENDOR_EPSIZE);
|
||||
#endif
|
||||
} vendord_epbuf_t;
|
||||
|
||||
CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
|
||||
@ -78,7 +75,6 @@ CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
|
||||
//--------------------------------------------------------------------+
|
||||
// Weak stubs: invoked if no strong implementation is available
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) {
|
||||
(void)idx;
|
||||
(void)buffer;
|
||||
@ -93,40 +89,44 @@ TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes) {
|
||||
//--------------------------------------------------------------------
|
||||
// Application API
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
bool tud_vendor_n_mounted(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return p_itf->stream.rx.ep_addr || p_itf->stream.tx.ep_addr;
|
||||
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
return (p_itf->rx_stream.ep_addr != 0) || (p_itf->tx_stream.ep_addr != 0);
|
||||
#else
|
||||
return (p_itf->ep_out != 0) || (p_itf->ep_in != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Read API
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
uint32_t tud_vendor_n_available(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_read_available(&p_itf->stream.rx);
|
||||
return tu_edpt_stream_read_available(&p_itf->rx_stream);
|
||||
}
|
||||
|
||||
bool tud_vendor_n_peek(uint8_t idx, uint8_t *u8) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_peek(&p_itf->stream.rx, u8);
|
||||
return tu_edpt_stream_peek(&p_itf->rx_stream, u8);
|
||||
}
|
||||
|
||||
uint32_t tud_vendor_n_read(uint8_t idx, void *buffer, uint32_t bufsize) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_read(&p_itf->stream.rx, buffer, bufsize);
|
||||
return tu_edpt_stream_read(&p_itf->rx_stream, buffer, bufsize);
|
||||
}
|
||||
|
||||
void tud_vendor_n_read_flush(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, );
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
tu_edpt_stream_clear(&p_itf->stream.rx);
|
||||
tu_edpt_stream_read_xfer(&p_itf->stream.rx);
|
||||
tu_edpt_stream_clear(&p_itf->rx_stream);
|
||||
tu_edpt_stream_read_xfer(&p_itf->rx_stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -134,9 +134,17 @@ void tud_vendor_n_read_flush(uint8_t idx) {
|
||||
bool tud_vendor_n_read_xfer(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_read_xfer(&p_itf->stream.rx);
|
||||
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
return tu_edpt_stream_read_xfer(&p_itf->rx_stream);
|
||||
|
||||
#else
|
||||
// Non-FIFO mode
|
||||
TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_out));
|
||||
return usbd_edpt_xfer(p_itf->rhport, p_itf->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -145,26 +153,45 @@ bool tud_vendor_n_read_xfer(uint8_t idx) {
|
||||
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_write(&p_itf->stream.tx, buffer, (uint16_t)bufsize);
|
||||
}
|
||||
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
uint32_t tud_vendor_n_write_flush(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_write_xfer(&p_itf->stream.tx);
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
return tu_edpt_stream_write(&p_itf->tx_stream, buffer, (uint16_t)bufsize);
|
||||
|
||||
#else
|
||||
// non-fifo mode: direct transfer
|
||||
TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_in), 0);
|
||||
const uint32_t xact_len = tu_min32(bufsize, CFG_TUD_VENDOR_EPSIZE);
|
||||
memcpy(_vendord_epbuf[idx].epin, buffer, xact_len);
|
||||
TU_ASSERT(usbd_edpt_xfer(p_itf->rhport, p_itf->ep_in, _vendord_epbuf[idx].epin, (uint16_t)xact_len, false), 0);
|
||||
return xact_len;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t tud_vendor_n_write_available(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_write_available(&p_itf->stream.tx);
|
||||
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
return tu_edpt_stream_write_available(&p_itf->tx_stream);
|
||||
|
||||
#else
|
||||
// Non-FIFO mode
|
||||
TU_VERIFY(p_itf->ep_in > 0, 0); // must be opened
|
||||
return usbd_edpt_busy(p_itf->rhport, p_itf->ep_in) ? 0 : CFG_TUD_VENDOR_EPSIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
uint32_t tud_vendor_n_write_flush(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
return tu_edpt_stream_write_xfer(&p_itf->tx_stream);
|
||||
}
|
||||
|
||||
bool tud_vendor_n_write_clear(uint8_t idx) {
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||
tu_edpt_stream_clear(&p_itf->stream.tx);
|
||||
tu_edpt_stream_clear(&p_itf->tx_stream);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -175,48 +202,37 @@ bool tud_vendor_n_write_clear(uint8_t idx) {
|
||||
void vendord_init(void) {
|
||||
tu_memclr(_vendord_itf, sizeof(_vendord_itf));
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
|
||||
vendord_interface_t* p_itf = &_vendord_itf[i];
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
for (uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
|
||||
vendord_interface_t *p_itf = &_vendord_itf[i];
|
||||
|
||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE == 0 // non-fifo rx still need ep buffer
|
||||
uint8_t *epout_buf = _vendord_epbuf[i].epout;
|
||||
#else
|
||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
|
||||
uint8_t *epout_buf = NULL;
|
||||
#endif
|
||||
|
||||
uint8_t *epin_buf = NULL;
|
||||
#else
|
||||
uint8_t *epin_buf = NULL;
|
||||
#else
|
||||
uint8_t *epout_buf = _vendord_epbuf[i].epout;
|
||||
uint8_t *epin_buf = _vendord_epbuf[i].epin;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
||||
uint8_t *rx_ff_buf = p_itf->stream.rx_ff_buf;
|
||||
#else
|
||||
uint8_t *rx_ff_buf = NULL;
|
||||
#endif
|
||||
|
||||
tu_edpt_stream_init(&p_itf->stream.rx, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
|
||||
uint8_t *rx_ff_buf = p_itf->rx_ff_buf;
|
||||
tu_edpt_stream_init(&p_itf->rx_stream, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
|
||||
CFG_TUD_VENDOR_EPSIZE);
|
||||
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
uint8_t *tx_ff_buf = p_itf->stream.tx_ff_buf;
|
||||
#else
|
||||
uint8_t *tx_ff_buf = NULL;
|
||||
#endif
|
||||
|
||||
tu_edpt_stream_init(&p_itf->stream.tx, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
|
||||
uint8_t *tx_ff_buf = p_itf->tx_ff_buf;
|
||||
tu_edpt_stream_init(&p_itf->tx_stream, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
|
||||
CFG_TUD_VENDOR_EPSIZE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool vendord_deinit(void) {
|
||||
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
|
||||
vendord_interface_t* p_itf = &_vendord_itf[i];
|
||||
tu_edpt_stream_deinit(&p_itf->stream.rx);
|
||||
tu_edpt_stream_deinit(&p_itf->stream.tx);
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
for (uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
|
||||
vendord_interface_t *p_itf = &_vendord_itf[i];
|
||||
tu_edpt_stream_deinit(&p_itf->rx_stream);
|
||||
tu_edpt_stream_deinit(&p_itf->tx_stream);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -227,11 +243,12 @@ void vendord_reset(uint8_t rhport) {
|
||||
vendord_interface_t* p_itf = &_vendord_itf[i];
|
||||
tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
|
||||
|
||||
tu_edpt_stream_clear(&p_itf->stream.rx);
|
||||
tu_edpt_stream_close(&p_itf->stream.rx);
|
||||
|
||||
tu_edpt_stream_clear(&p_itf->stream.tx);
|
||||
tu_edpt_stream_close(&p_itf->stream.tx);
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
tu_edpt_stream_clear(&p_itf->rx_stream);
|
||||
tu_edpt_stream_close(&p_itf->rx_stream);
|
||||
tu_edpt_stream_clear(&p_itf->tx_stream);
|
||||
tu_edpt_stream_close(&p_itf->tx_stream);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,13 +258,25 @@ static uint8_t find_vendor_itf(uint8_t ep_addr) {
|
||||
const vendord_interface_t *p_vendor = &_vendord_itf[idx];
|
||||
if (ep_addr == 0) {
|
||||
// find unused: require both ep == 0
|
||||
if (p_vendor->stream.rx.ep_addr == 0 && p_vendor->stream.tx.ep_addr == 0) {
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
if (p_vendor->rx_stream.ep_addr == 0 && p_vendor->tx_stream.ep_addr == 0) {
|
||||
return idx;
|
||||
}
|
||||
} else if (ep_addr == p_vendor->stream.rx.ep_addr || ep_addr == p_vendor->stream.tx.ep_addr) {
|
||||
return idx;
|
||||
#else
|
||||
if (p_vendor->ep_out == 0 && p_vendor->ep_in == 0) {
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// nothing to do
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
if (ep_addr == p_vendor->rx_stream.ep_addr || ep_addr == p_vendor->tx_stream.ep_addr) {
|
||||
return idx;
|
||||
}
|
||||
#else
|
||||
if (ep_addr == p_vendor->ep_out || ep_addr == p_vendor->ep_in) {
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0xff;
|
||||
@ -273,28 +302,39 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uin
|
||||
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
|
||||
TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
|
||||
|
||||
// open endpoint stream, skip if already opened (multiple IN/OUT endpoints)
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
// open endpoint stream
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
|
||||
tu_edpt_stream_t *stream_tx = &p_vendor->stream.tx;
|
||||
if (stream_tx->ep_addr == 0) {
|
||||
tu_edpt_stream_open(stream_tx, rhport, desc_ep);
|
||||
tu_edpt_stream_write_xfer(stream_tx); // flush pending data
|
||||
}
|
||||
tu_edpt_stream_t *tx_stream = &p_vendor->tx_stream;
|
||||
tu_edpt_stream_open(tx_stream, rhport, desc_ep);
|
||||
tu_edpt_stream_write_xfer(tx_stream); // flush pending data
|
||||
} else {
|
||||
tu_edpt_stream_t *stream_rx = &p_vendor->stream.rx;
|
||||
if (stream_rx->ep_addr == 0) {
|
||||
tu_edpt_stream_open(stream_rx, rhport, desc_ep);
|
||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||
TU_ASSERT(tu_edpt_stream_read_xfer(stream_rx) > 0, 0); // prepare for incoming data
|
||||
#endif
|
||||
}
|
||||
tu_edpt_stream_t *rx_stream = &p_vendor->rx_stream;
|
||||
tu_edpt_stream_open(rx_stream, rhport, desc_ep);
|
||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||
TU_ASSERT(tu_edpt_stream_read_xfer(rx_stream) > 0, 0); // prepare for incoming data
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
// Non-FIFO mode: store endpoint info
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
|
||||
p_vendor->ep_in = desc_ep->bEndpointAddress;
|
||||
p_vendor->ep_in_mps = tu_edpt_packet_size(desc_ep);
|
||||
} else {
|
||||
p_vendor->ep_out = desc_ep->bEndpointAddress;
|
||||
p_vendor->ep_out_mps = tu_edpt_packet_size(desc_ep);
|
||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||
// Prepare for incoming data
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false), 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf);
|
||||
return (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_itf);
|
||||
}
|
||||
|
||||
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
@ -304,34 +344,36 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||
vendord_interface_t *p_vendor = &_vendord_itf[idx];
|
||||
|
||||
if (ep_addr == p_vendor->stream.rx.ep_addr) {
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE
|
||||
// Received new data: put into stream's fifo
|
||||
tu_edpt_stream_read_xfer_complete(&p_vendor->stream.rx, xferred_bytes);
|
||||
#endif
|
||||
|
||||
// invoke callback
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE == 0
|
||||
tud_vendor_rx_cb(idx, p_vendor->stream.rx.ep_buf, xferred_bytes);
|
||||
#else
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
if (ep_addr == p_vendor->rx_stream.ep_addr) {
|
||||
// Put received data to FIFO
|
||||
tu_edpt_stream_read_xfer_complete(&p_vendor->rx_stream, xferred_bytes);
|
||||
tud_vendor_rx_cb(idx, NULL, 0);
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||
tu_edpt_stream_read_xfer(&p_vendor->stream.rx); // prepare next data
|
||||
#endif
|
||||
} else if (ep_addr == p_vendor->stream.tx.ep_addr) {
|
||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||
tu_edpt_stream_read_xfer(&p_vendor->rx_stream); // prepare next data
|
||||
#endif
|
||||
} else if (ep_addr == p_vendor->tx_stream.ep_addr) {
|
||||
// Send complete
|
||||
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
|
||||
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
// try to send more if possible
|
||||
if (0 == tu_edpt_stream_write_xfer(&p_vendor->stream.tx)) {
|
||||
if (0 == tu_edpt_stream_write_xfer(&p_vendor->tx_stream)) {
|
||||
// If there is no data left, a ZLP should be sent if xferred_bytes is multiple of EP Packet size and not zero
|
||||
tu_edpt_stream_write_zlp_if_needed(&p_vendor->stream.tx, xferred_bytes);
|
||||
tu_edpt_stream_write_zlp_if_needed(&p_vendor->tx_stream, xferred_bytes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (ep_addr == p_vendor->ep_out) {
|
||||
// Non-FIFO mode: invoke callback with buffer
|
||||
tud_vendor_rx_cb(idx, _vendord_epbuf[idx].epout, xferred_bytes);
|
||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||
usbd_edpt_xfer(rhport, p_vendor->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false);
|
||||
#endif
|
||||
} else if (ep_addr == p_vendor->ep_in) {
|
||||
// Send complete
|
||||
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
44
src/class/vendor/vendor_device.h
vendored
44
src/class/vendor/vendor_device.h
vendored
@ -50,8 +50,14 @@ extern "C" {
|
||||
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
|
||||
#endif
|
||||
|
||||
// Vendor is buffered (FIFO mode) if both TX and RX buffers are configured
|
||||
// If either is 0, vendor operates in non-buffered (direct transfer) mode
|
||||
#ifndef CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
#define CFG_TUD_VENDOR_TXRX_BUFFERED ((CFG_TUD_VENDOR_RX_BUFSIZE > 0) && (CFG_TUD_VENDOR_TX_BUFSIZE > 0))
|
||||
#endif
|
||||
|
||||
// Application will manually schedule RX transfer. This can be useful when using with non-fifo (buffered) mode
|
||||
// i.e. CFG_TUD_VENDOR_RX_BUFSIZE = 0
|
||||
// i.e. CFG_TUD_VENDOR_TXRX_BUFFERED = 0
|
||||
#ifndef CFG_TUD_VENDOR_RX_MANUAL_XFER
|
||||
#define CFG_TUD_VENDOR_RX_MANUAL_XFER 0
|
||||
#endif
|
||||
@ -63,7 +69,8 @@ extern "C" {
|
||||
// Return whether the vendor interface is mounted
|
||||
bool tud_vendor_n_mounted(uint8_t idx);
|
||||
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
||||
//------------- RX -------------//
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
// Return number of available bytes for reading
|
||||
uint32_t tud_vendor_n_available(uint8_t idx);
|
||||
|
||||
@ -82,16 +89,17 @@ void tud_vendor_n_read_flush(uint8_t idx);
|
||||
bool tud_vendor_n_read_xfer(uint8_t idx);
|
||||
#endif
|
||||
|
||||
//------------- TX -------------//
|
||||
// Write to TX FIFO. This can be buffered and not sent immediately unless buffered bytes >= USB endpoint size
|
||||
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize);
|
||||
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
// Return number of bytes available for writing in TX FIFO (or endpoint if non-buffered)
|
||||
uint32_t tud_vendor_n_write_available(uint8_t idx);
|
||||
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
// Force sending buffered data, return number of bytes sent
|
||||
uint32_t tud_vendor_n_write_flush(uint8_t idx);
|
||||
|
||||
// Return number of bytes available for writing in TX FIFO
|
||||
uint32_t tud_vendor_n_write_available(uint8_t idx);
|
||||
|
||||
// Clear the transmit FIFO
|
||||
bool tud_vendor_n_write_clear(uint8_t idx);
|
||||
#endif
|
||||
@ -111,7 +119,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_mounted(void) {
|
||||
return tud_vendor_n_mounted(0);
|
||||
}
|
||||
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
||||
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_available(void) {
|
||||
return tud_vendor_n_available(0);
|
||||
}
|
||||
@ -127,6 +135,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_read(void *buffer, uint3
|
||||
TU_ATTR_ALWAYS_INLINE static inline void tud_vendor_read_flush(void) {
|
||||
tud_vendor_n_read_flush(0);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
|
||||
return tud_vendor_n_write_flush(0);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
|
||||
return tud_vendor_n_write_clear(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER
|
||||
@ -143,20 +159,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_str(const char *st
|
||||
return tud_vendor_n_write_str(0, str);
|
||||
}
|
||||
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
|
||||
return tud_vendor_n_write_flush(0);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
|
||||
return tud_vendor_n_write_available(0);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
|
||||
return tud_vendor_n_write_clear(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// backward compatible
|
||||
#define tud_vendor_flush() tud_vendor_write_flush()
|
||||
|
||||
@ -165,8 +171,8 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received new data.
|
||||
// - CFG_TUD_VENDOR_RX_BUFSIZE > 0; buffer and bufsize must not be used (both NULL,0) since data is in RX FIFO
|
||||
// - CFG_TUD_VENDOR_RX_BUFSIZE = 0: Buffer and bufsize are valid
|
||||
// - CFG_TUD_VENDOR_TXRX_BUFFERED = 1: buffer and bufsize must not be used (both NULL,0) since data is in RX FIFO
|
||||
// - CFG_TUD_VENDOR_TXRX_BUFFERED = 0: Buffer and bufsize are valid
|
||||
void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize);
|
||||
|
||||
// Invoked when tx transfer is finished
|
||||
|
||||
@ -37,14 +37,6 @@
|
||||
// Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if CFG_TUD_ENABLED && CFG_TUD_VENDOR && (CFG_TUD_VENDOR_TX_BUFSIZE == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0)
|
||||
#define CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED 1
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
||||
#define CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED 0
|
||||
#endif
|
||||
|
||||
#define TUP_USBIP_CONTROLLER_NUM 2
|
||||
extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
|
||||
|
||||
|
||||
97
src/tusb.c
97
src/tusb.c
@ -309,11 +309,9 @@ bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool ove
|
||||
uint16_t ff_bufsize, uint8_t *ep_buf, uint16_t ep_bufsize) {
|
||||
(void) is_tx;
|
||||
|
||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED == 0 // FIFO is required
|
||||
if (ff_buf == NULL || ff_bufsize == 0) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
s->is_host = is_host;
|
||||
tu_fifo_config(&s->ff, ff_buf, ff_bufsize, overwritable);
|
||||
@ -411,88 +409,45 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t *s) {
|
||||
}
|
||||
|
||||
uint32_t tu_edpt_stream_write(tu_edpt_stream_t *s, const void *buffer, uint32_t bufsize) {
|
||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
||||
if (0 == tu_fifo_depth(&s->ff)) {
|
||||
// non-fifo mode: TX need ep buffer
|
||||
TU_VERIFY(s->ep_buf != NULL, 0);
|
||||
TU_VERIFY(stream_claim(s), 0);
|
||||
uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize);
|
||||
memcpy(s->ep_buf, buffer, xact_len);
|
||||
TU_ASSERT(stream_xfer(s, (uint16_t) xact_len), 0);
|
||||
return xact_len;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
TU_VERIFY(bufsize > 0);
|
||||
const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
|
||||
TU_VERIFY(bufsize > 0);
|
||||
const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
|
||||
|
||||
// flush if fifo has more than packet size or
|
||||
// in rare case: fifo depth is configured too small (which never reach packet size)
|
||||
if ((tu_fifo_count(&s->ff) >= s->mps) || (tu_fifo_depth(&s->ff) < s->mps)) {
|
||||
tu_edpt_stream_write_xfer(s);
|
||||
}
|
||||
return ret;
|
||||
// flush if fifo has more than packet size or
|
||||
// in rare case: fifo depth is configured too small (which never reach packet size)
|
||||
if ((tu_fifo_count(&s->ff) >= s->mps) || (tu_fifo_depth(&s->ff) < s->mps)) {
|
||||
tu_edpt_stream_write_xfer(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t *s) {
|
||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
||||
if (0 == tu_fifo_depth(&s->ff)) {
|
||||
// non-fifo mode
|
||||
TU_VERIFY(s->ep_addr > 0); // must be opened
|
||||
bool is_busy = true;
|
||||
if (s->is_host) {
|
||||
#if CFG_TUH_ENABLED
|
||||
is_busy = usbh_edpt_busy(s->hwid, s->ep_addr);
|
||||
#endif
|
||||
} else {
|
||||
#if CFG_TUD_ENABLED
|
||||
is_busy = usbd_edpt_busy(s->hwid, s->ep_addr);
|
||||
#endif
|
||||
}
|
||||
return is_busy ? 0 : s->ep_bufsize;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return (uint32_t)tu_fifo_remaining(&s->ff);
|
||||
}
|
||||
return (uint32_t)tu_fifo_remaining(&s->ff);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Stream Read
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t *s) {
|
||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
||||
if (0 == tu_fifo_depth(&s->ff)) {
|
||||
// non-fifo mode: RX need ep buffer
|
||||
TU_VERIFY(s->ep_buf != NULL, 0);
|
||||
TU_VERIFY(stream_claim(s), 0);
|
||||
TU_ASSERT(stream_xfer(s, s->ep_bufsize), 0);
|
||||
return s->ep_bufsize;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint16_t available = tu_fifo_remaining(&s->ff);
|
||||
uint16_t available = tu_fifo_remaining(&s->ff);
|
||||
|
||||
// Prepare for incoming data but only allow what we can store in the ring buffer.
|
||||
// TODO Actually we can still carry out the transfer, keeping count of received bytes
|
||||
// and slowly move it to the FIFO when read().
|
||||
// This pre-check reduces endpoint claiming
|
||||
TU_VERIFY(available >= s->mps);
|
||||
TU_VERIFY(stream_claim(s), 0);
|
||||
available = tu_fifo_remaining(&s->ff); // re-get available since fifo can be changed
|
||||
// Prepare for incoming data but only allow what we can store in the ring buffer.
|
||||
// TODO Actually we can still carry out the transfer, keeping count of received bytes
|
||||
// and slowly move it to the FIFO when read().
|
||||
// This pre-check reduces endpoint claiming
|
||||
TU_VERIFY(available >= s->mps);
|
||||
TU_VERIFY(stream_claim(s), 0);
|
||||
available = tu_fifo_remaining(&s->ff); // re-get available since fifo can be changed
|
||||
|
||||
if (available >= s->mps) {
|
||||
// multiple of packet size limit by ep bufsize
|
||||
uint16_t count = (uint16_t) (available & ~(s->mps - 1));
|
||||
count = tu_min16(count, s->ep_bufsize);
|
||||
TU_ASSERT(stream_xfer(s, count), 0);
|
||||
return count;
|
||||
} else {
|
||||
// Release endpoint since we don't make any transfer
|
||||
stream_release(s);
|
||||
return 0;
|
||||
}
|
||||
if (available >= s->mps) {
|
||||
// multiple of packet size limit by ep bufsize
|
||||
uint16_t count = (uint16_t) (available & ~(s->mps - 1));
|
||||
count = tu_min16(count, s->ep_bufsize);
|
||||
TU_ASSERT(stream_xfer(s, count), 0);
|
||||
return count;
|
||||
} else {
|
||||
// Release endpoint since we don't make any transfer
|
||||
stream_release(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -410,22 +410,22 @@ def test_device_cdc_dual_ports(board):
|
||||
sizes = [32, 64, 128, 256, 512, random.randint(2000, 5000)]
|
||||
|
||||
def write_and_check(writer, payload):
|
||||
size = len(payload)
|
||||
payload_len = len(payload)
|
||||
for s in ser:
|
||||
s.reset_input_buffer()
|
||||
rd0 = b''
|
||||
rd1 = b''
|
||||
offset = 0
|
||||
# Write in chunks of random 1-64 bytes (device has 64-byte buffer)
|
||||
while offset < size:
|
||||
chunk_size = min(random.randint(1, 64), size - offset)
|
||||
while offset < payload_len:
|
||||
chunk_size = min(random.randint(1, 64), payload_len - offset)
|
||||
ser[writer].write(payload[offset:offset + chunk_size])
|
||||
ser[writer].flush()
|
||||
rd0 += ser[0].read(chunk_size)
|
||||
rd1 += ser[1].read(chunk_size)
|
||||
offset += chunk_size
|
||||
assert rd0 == payload.lower(), f'Port0 wrong data ({size}): expected {payload.lower()[:16]}... was {rd0[:16]}'
|
||||
assert rd1 == payload.upper(), f'Port1 wrong data ({size}): expected {payload.upper()[:16]}... was {rd1[:16]}'
|
||||
assert rd0 == payload.lower(), f'Port0 wrong data ({payload_len}): expected {payload.lower()}... was {rd0}'
|
||||
assert rd1 == payload.upper(), f'Port1 wrong data ({payload_len}): expected {payload.upper()}... was {rd1}'
|
||||
|
||||
for size in sizes:
|
||||
payload0 = rand_ascii(size)
|
||||
|
||||
Reference in New Issue
Block a user