summaryrefslogtreecommitdiff
path: root/examples/device/usbtest/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-07-02 22:06:24 +0700
committerhathach <[email protected]>2026-07-02 22:06:24 +0700
commitbda8f9cf9a0a2c8d7e0972c4f130fa839a1b891d (patch)
tree36967366af56795aff92eb210835516031d30046 /examples/device/usbtest/src
parent73b42f80992f9da5d27eed061dc7c25358bf3259 (diff)
example(usbtest): tier 3 - interrupt source/sink (cases 25/26)
The host usbtest driver collects interrupt pipes from the same altsetting as the bulk pair, so the interface grows to 4 endpoints (hand-rolled descriptor: bulk IN/OUT + interrupt IN/OUT, FS 64B interval 1 / HS 512B interval 4) using the vendor class with CFG_TUD_VENDOR_EP_INT_OUT/IN. The interrupt pumps mirror the bulk ones: poll + re-arm from callbacks, self-healing across the halt tests. Full tier-3 battery (26 cases, now incl. 25/26 interrupt write/read) passes on stm32f407disco, stm32f723disco, stm32h743nucleo and stm32l476disco. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
Diffstat (limited to 'examples/device/usbtest/src')
-rw-r--r--examples/device/usbtest/src/main.c44
-rw-r--r--examples/device/usbtest/src/tusb_config.h6
-rw-r--r--examples/device/usbtest/src/usb_descriptors.c55
-rw-r--r--examples/device/usbtest/src/usb_descriptors.h5
4 files changed, 79 insertions, 31 deletions
diff --git a/examples/device/usbtest/src/main.c b/examples/device/usbtest/src/main.c
index 56b0128d8..ee5b53073 100644
--- a/examples/device/usbtest/src/main.c
+++ b/examples/device/usbtest/src/main.c
@@ -26,8 +26,8 @@
/* Device-side peer of the Linux kernel host test driver drivers/usb/misc/usbtest.c
* (driven from userspace by tools/usb/testusb.c). Implements the Gadget-Zero
* style source/sink protocol on a vendor interface:
- * - bulk IN = infinite source (pattern 0: all zeros)
- * - bulk OUT = infinite sink (data discarded)
+ * - bulk/interrupt IN = infinite source (pattern 0: all zeros)
+ * - bulk/interrupt OUT = infinite sink (data discarded)
* - EP0 0x5b/0x5c = control write then read-back (ctrl_out tests)
* See examples/device/usbtest/README.md and test/hil/usbtest.py for usage.
*/
@@ -57,9 +57,11 @@ enum {
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
-// Source data, all zeros = usbtest pattern 0. Size is a multiple of bulk MPS at
-// both speeds: transfers are always whole packets, never an unintended short/ZLP.
+// Source data, all zeros = usbtest pattern 0. Sizes are a multiple of the
+// endpoint max packet size: transfers are always whole packets, never an
+// unintended short packet or ZLP.
static uint8_t const tx_chunk[CFG_TUD_VENDOR_TX_EPSIZE];
+static uint8_t const int_tx_chunk[USBTEST_INT_EP_MPS];
//------------- prototypes -------------//
void led_blinking_task(void);
@@ -89,19 +91,23 @@ int main(void) {
// Source/sink pumps
//--------------------------------------------------------------------+
-// Polling keeps both directions armed and self-heals after endpoint halt
-// (set/clear feature tests): stall marks the endpoint busy so both calls fail
+// Polling keeps all four endpoints armed and self-heals after endpoint halt
+// (set/clear feature tests): stall marks the endpoint busy so the calls fail
// quietly until the host clears the halt, then the next tick re-arms.
static void usbtest_task(void) {
if (!tud_vendor_mounted()) {
return;
}
- tud_vendor_read_xfer(); // sink: arm/re-arm OUT, quiet fail if already armed or halted
-
- if (tud_vendor_write_available()) { // 0 while IN is busy or halted
+ tud_vendor_read_xfer(); // bulk sink: arm/re-arm, quiet fail if armed or halted
+ if (tud_vendor_write_available()) { // 0 while bulk IN is busy or halted
tud_vendor_write(tx_chunk, sizeof(tx_chunk));
}
+
+ tud_vendor_int_read_xfer(); // interrupt sink
+ if (tud_vendor_int_write_available()) {
+ tud_vendor_int_write(int_tx_chunk, sizeof(int_tx_chunk));
+ }
}
// Invoked when received data from host: discard and immediately re-arm
@@ -112,13 +118,31 @@ void tud_vendor_rx_cb(uint8_t idx, const uint8_t* buffer, uint32_t bufsize) {
tud_vendor_read_xfer();
}
-// Invoked when last tx transfer finished: keep the source saturated
+// Invoked when last bulk tx transfer finished: keep the source saturated
void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes) {
(void) idx;
(void) sent_bytes;
tud_vendor_write(tx_chunk, sizeof(tx_chunk));
}
+// Interrupt pair: same discard/refill pumps as bulk
+void tud_vendor_int_rx_cb(uint8_t idx, const uint8_t* buffer, uint32_t bufsize) {
+ (void) idx;
+ (void) buffer;
+ (void) bufsize;
+ tud_vendor_int_read_xfer();
+}
+
+void tud_vendor_int_tx_cb(uint8_t idx, uint32_t sent_bytes) {
+ (void) idx;
+ (void) sent_bytes;
+ tud_vendor_int_write(int_tx_chunk, sizeof(int_tx_chunk));
+}
+
+//--------------------------------------------------------------------+
+// Vendor control requests (EP0)
+//--------------------------------------------------------------------+
+
// Control write/read-back for the ctrl_out tests (14/21), same protocol as
// Gadget Zero: 0x5b stores the host's wLength bytes, 0x5c returns them.
static uint8_t ctrl_buf[1024];
diff --git a/examples/device/usbtest/src/tusb_config.h b/examples/device/usbtest/src/tusb_config.h
index 058e2362c..19729f0ca 100644
--- a/examples/device/usbtest/src/tusb_config.h
+++ b/examples/device/usbtest/src/tusb_config.h
@@ -110,6 +110,12 @@
// Multi-packet IN transfers; must be a multiple of bulk MPS at both speeds (64/512)
#define CFG_TUD_VENDOR_TX_EPSIZE 2048
+// Interrupt IN/OUT source/sink pair (usbtest cases 25/26)
+#define CFG_TUD_VENDOR_EP_INT_OUT 1
+#define CFG_TUD_VENDOR_EP_INT_IN 1
+#define CFG_TUD_VENDOR_EP_INT_OUT_BUFSIZE 512
+#define CFG_TUD_VENDOR_EP_INT_IN_BUFSIZE 512
+
#ifdef __cplusplus
}
#endif
diff --git a/examples/device/usbtest/src/usb_descriptors.c b/examples/device/usbtest/src/usb_descriptors.c
index 7ef1c2ff2..e73cd7df5 100644
--- a/examples/device/usbtest/src/usb_descriptors.c
+++ b/examples/device/usbtest/src/usb_descriptors.c
@@ -65,43 +65,57 @@ enum {
ITF_NUM_TOTAL
};
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VENDOR_DESC_LEN)
+// Vendor interface with bulk IN/OUT source/sink plus interrupt IN/OUT: the host
+// usbtest driver collects all pipe types from one altsetting. No TUD_ macro
+// covers this layout, hand-rolled: interface + 2 bulk + 2 interrupt endpoints.
+#define USBTEST_DESC_LEN (9 + 4*7)
+#define USBTEST_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _bulk_mps, _intout, _intin, _int_mps, _int_interval) \
+ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 4, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\
+ 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_mps), 0,\
+ 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_mps), 0,\
+ 7, TUSB_DESC_ENDPOINT, _intout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_int_mps), _int_interval,\
+ 7, TUSB_DESC_ENDPOINT, _intin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_int_mps), _int_interval
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + USBTEST_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
- // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
- #define EPNUM_VENDOR_OUT 0x02
- #define EPNUM_VENDOR_IN 0x82
-
-#elif CFG_TUSB_MCU == OPT_MCU_CXD56
- // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
- // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
- #define EPNUM_VENDOR_OUT 0x02
- #define EPNUM_VENDOR_IN 0x81
+ // 0 control, 1 Interrupt, 2 Bulk, 3 Iso, 4 Interrupt etc ...
+ #define EPNUM_BULK_OUT 0x02
+ #define EPNUM_BULK_IN 0x85
+ #define EPNUM_INT_OUT 0x01
+ #define EPNUM_INT_IN 0x84
#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY
// MCUs that don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#if TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002)
// Put bulk on EP>=8 so the 2048/4096-byte FIFOs can back double packet buffering
- #define EPNUM_VENDOR_OUT 0x08
- #define EPNUM_VENDOR_IN 0x89
+ #define EPNUM_BULK_OUT 0x08
+ #define EPNUM_BULK_IN 0x89
+ #define EPNUM_INT_OUT 0x02
+ #define EPNUM_INT_IN 0x83
#else
- #define EPNUM_VENDOR_OUT 0x01
- #define EPNUM_VENDOR_IN 0x82
+ #define EPNUM_BULK_OUT 0x01
+ #define EPNUM_BULK_IN 0x82
+ #define EPNUM_INT_OUT 0x03
+ #define EPNUM_INT_IN 0x84
#endif
#else
- #define EPNUM_VENDOR_OUT 0x01
- #define EPNUM_VENDOR_IN 0x81
+ #define EPNUM_BULK_OUT 0x01
+ #define EPNUM_BULK_IN 0x81
+ #define EPNUM_INT_OUT 0x02
+ #define EPNUM_INT_IN 0x82
#endif
static uint8_t const desc_fs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
- // Interface number, string index, EP Out & IN address, EP size
- TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR, 4, EPNUM_VENDOR_OUT, 0x80 | EPNUM_VENDOR_IN, 64)
+ // Interface number, string index, bulk EP out/in + mps, interrupt EP out/in + mps + interval
+ USBTEST_DESCRIPTOR(ITF_NUM_VENDOR, 4, EPNUM_BULK_OUT, 0x80 | EPNUM_BULK_IN, 64,
+ EPNUM_INT_OUT, 0x80 | EPNUM_INT_IN, 64, 1)
};
#if TUD_OPT_HIGH_SPEED
@@ -111,8 +125,9 @@ static uint8_t const desc_hs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
- // Interface number, string index, EP Out & IN address, EP size
- TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR, 4, EPNUM_VENDOR_OUT, 0x80 | EPNUM_VENDOR_IN, 512)
+ // Interface number, string index, bulk EP out/in + mps, interrupt EP out/in + mps + interval (1 ms)
+ USBTEST_DESCRIPTOR(ITF_NUM_VENDOR, 4, EPNUM_BULK_OUT, 0x80 | EPNUM_BULK_IN, 512,
+ EPNUM_INT_OUT, 0x80 | EPNUM_INT_IN, 512, 4)
};
// other speed configuration
diff --git a/examples/device/usbtest/src/usb_descriptors.h b/examples/device/usbtest/src/usb_descriptors.h
index 6b703ed8f..02ea9ccbd 100644
--- a/examples/device/usbtest/src/usb_descriptors.h
+++ b/examples/device/usbtest/src/usb_descriptors.h
@@ -32,6 +32,9 @@
// 2: + vendor control 0x5b/0x5c (ctrl_out)
// 3: + interrupt source/sink
// 4: + isochronous source/sink
-#define USBTEST_TIER 2
+#define USBTEST_TIER 3
+
+// Interrupt endpoint max packet size, must match the configuration descriptor
+#define USBTEST_INT_EP_MPS (TUD_OPT_HIGH_SPEED ? 512 : 64)
#endif /* USB_DESCRIPTORS_H_ */