From 9d0af750a5463f3a54c6fdd5932d82f7fc208ffc Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 20 Apr 2026 17:46:15 +0700 Subject: add test for net_lwip_webserver with iperf throughput validation --- examples/device/net_lwip_webserver/src/tusb_config.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'examples/device/net_lwip_webserver/src') diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h index 3285ea52c..db52e3b50 100644 --- a/examples/device/net_lwip_webserver/src/tusb_config.h +++ b/examples/device/net_lwip_webserver/src/tusb_config.h @@ -96,10 +96,13 @@ extern "C" { #define USE_ECM 1 #else #define USE_ECM 0 - #define INCLUDE_IPERF #endif #endif +#ifndef INCLUDE_IPERF + #define INCLUDE_IPERF +#endif + //-------------------------------------------------------------------- // NCM CLASS CONFIGURATION, SEE "ncm.h" FOR PERFORMANCE TUNING //-------------------------------------------------------------------- -- cgit v1.3.1 From f9e79844edd9757243c786c9e901cfba3f281b6b Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 21 Apr 2026 11:26:51 +0700 Subject: replace `TUD_ENDPOINT_ONE_DIRECTION_ONLY` with `CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY` for improved configuration consistency across examples and core sources --- .../device/cdc_dual_ports/src/usb_descriptors.c | 2 +- examples/device/cdc_msc/src/usb_descriptors.c | 2 +- examples/device/cdc_msc_freertos/src/main.c | 4 ++-- .../device/cdc_msc_freertos/src/usb_descriptors.c | 2 +- examples/device/cdc_uac2/src/usb_descriptors.c | 2 +- .../dynamic_configuration/src/usb_descriptors.c | 2 +- .../device/hid_generic_inout/src/usb_descriptors.c | 2 +- examples/device/midi_test/src/usb_descriptors.c | 2 +- .../midi_test_freertos/src/usb_descriptors.c | 2 +- examples/device/msc_dual_lun/src/usb_descriptors.c | 2 +- examples/device/mtp/src/usb_descriptors.c | 2 +- .../net_lwip_webserver/src/usb_descriptors.c | 2 +- .../device/printer_to_cdc/src/usb_descriptors.c | 2 +- examples/device/uac2_headset/src/usb_descriptors.c | 2 +- .../device/uac2_speaker_fb/src/usb_descriptors.c | 2 +- .../device/webusb_serial/src/usb_descriptors.c | 2 +- examples/dual/dynamic_switch/src/usb_descriptors.c | 2 +- src/common/tusb_mcu.h | 27 +++++++++++++++------- 18 files changed, 37 insertions(+), 26 deletions(-) (limited to 'examples/device/net_lwip_webserver/src') diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c index e6011c35a..2d899a7c6 100644 --- a/examples/device/cdc_dual_ports/src/usb_descriptors.c +++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c @@ -106,7 +106,7 @@ enum { #define EPNUM_CDC_1_OUT 0x05 #define EPNUM_CDC_1_IN 0x84 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_0_NOTIF 0x81 diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c index c668ea3a7..b738e7d12 100644 --- a/examples/device/cdc_msc/src/usb_descriptors.c +++ b/examples/device/cdc_msc/src/usb_descriptors.c @@ -102,7 +102,7 @@ enum { #define EPNUM_MSC_OUT 0x05 #define EPNUM_MSC_IN 0x84 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_NOTIF 0x81 diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c index 4fb209fd0..f2f71d089 100644 --- a/examples/device/cdc_msc_freertos/src/main.c +++ b/examples/device/cdc_msc_freertos/src/main.c @@ -34,10 +34,10 @@ #define USBD_STACK_SIZE 4096 #else // Increase stack size when debug log is enabled - #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) + #define USBD_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 4 : 2)) #endif -#define CDC_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) +#define CDC_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 3 : 2)) #define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE //--------------------------------------------------------------------+ diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c index 4950f02e0..26bc0de00 100644 --- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c +++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c @@ -102,7 +102,7 @@ enum { #define EPNUM_MSC_OUT 0x05 #define EPNUM_MSC_IN 0x84 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_NOTIF 0x81 diff --git a/examples/device/cdc_uac2/src/usb_descriptors.c b/examples/device/cdc_uac2/src/usb_descriptors.c index e6caaa971..7ef738de9 100644 --- a/examples/device/cdc_uac2/src/usb_descriptors.c +++ b/examples/device/cdc_uac2/src/usb_descriptors.c @@ -97,7 +97,7 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_CDC_OUT 0x02 #define EPNUM_CDC_IN 0x82 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_AUDIO_IN 0x01 diff --git a/examples/device/dynamic_configuration/src/usb_descriptors.c b/examples/device/dynamic_configuration/src/usb_descriptors.c index 458b7c2a5..c4049414f 100644 --- a/examples/device/dynamic_configuration/src/usb_descriptors.c +++ b/examples/device/dynamic_configuration/src/usb_descriptors.c @@ -132,7 +132,7 @@ enum #define EPNUM_1_MSC_OUT 0x02 #define EPNUM_1_MSC_IN 0x82 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_0_CDC_NOTIF 0x81 diff --git a/examples/device/hid_generic_inout/src/usb_descriptors.c b/examples/device/hid_generic_inout/src/usb_descriptors.c index 929b2fd3a..93e718461 100644 --- a/examples/device/hid_generic_inout/src/usb_descriptors.c +++ b/examples/device/hid_generic_inout/src/usb_descriptors.c @@ -97,7 +97,7 @@ enum #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) -#if defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#if CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_HID_OUT 0x01 diff --git a/examples/device/midi_test/src/usb_descriptors.c b/examples/device/midi_test/src/usb_descriptors.c index e969f33a3..99c798ce1 100644 --- a/examples/device/midi_test/src/usb_descriptors.c +++ b/examples/device/midi_test/src/usb_descriptors.c @@ -87,7 +87,7 @@ enum { #define EPNUM_MIDI_OUT 0x02 #define EPNUM_MIDI_IN 0x81 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_MIDI_OUT 0x01 diff --git a/examples/device/midi_test_freertos/src/usb_descriptors.c b/examples/device/midi_test_freertos/src/usb_descriptors.c index e969f33a3..99c798ce1 100644 --- a/examples/device/midi_test_freertos/src/usb_descriptors.c +++ b/examples/device/midi_test_freertos/src/usb_descriptors.c @@ -87,7 +87,7 @@ enum { #define EPNUM_MIDI_OUT 0x02 #define EPNUM_MIDI_IN 0x81 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_MIDI_OUT 0x01 diff --git a/examples/device/msc_dual_lun/src/usb_descriptors.c b/examples/device/msc_dual_lun/src/usb_descriptors.c index f73935ee0..c2eb22a4c 100644 --- a/examples/device/msc_dual_lun/src/usb_descriptors.c +++ b/examples/device/msc_dual_lun/src/usb_descriptors.c @@ -91,7 +91,7 @@ enum #define EPNUM_MSC_OUT 0x02 #define EPNUM_MSC_IN 0x81 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_MSC_OUT 0x01 diff --git a/examples/device/mtp/src/usb_descriptors.c b/examples/device/mtp/src/usb_descriptors.c index f0aa3de6b..4c840560e 100644 --- a/examples/device/mtp/src/usb_descriptors.c +++ b/examples/device/mtp/src/usb_descriptors.c @@ -94,7 +94,7 @@ enum #define EPNUM_MTP_OUT 0x02 #define EPNUM_MTP_IN 0x81 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_MTP_EVT 0x81 diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c index c976cb62b..8cfef41a6 100644 --- a/examples/device/net_lwip_webserver/src/usb_descriptors.c +++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c @@ -121,7 +121,7 @@ const uint8_t *tud_descriptor_device_cb(void) { #define EPNUM_NET_OUT 0x02 #define EPNUM_NET_IN 0x81 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_NET_NOTIF 0x81 diff --git a/examples/device/printer_to_cdc/src/usb_descriptors.c b/examples/device/printer_to_cdc/src/usb_descriptors.c index 30d309ed4..2e6b3f6c3 100644 --- a/examples/device/printer_to_cdc/src/usb_descriptors.c +++ b/examples/device/printer_to_cdc/src/usb_descriptors.c @@ -67,7 +67,7 @@ uint8_t const *tud_descriptor_device_cb(void) { //--------------------------------------------------------------------+ // Endpoint numbers -#if defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#if CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY #define EPNUM_CDC_NOTIF 0x81 #define EPNUM_CDC_OUT 0x02 #define EPNUM_CDC_IN 0x83 diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index e4fbbf8a5..e9ac8b817 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -97,7 +97,7 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_AUDIO_OUT 0x08 #define EPNUM_AUDIO_INT 0x01 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_AUDIO_IN 0x01 diff --git a/examples/device/uac2_speaker_fb/src/usb_descriptors.c b/examples/device/uac2_speaker_fb/src/usb_descriptors.c index c5a161a1e..2e21e54e3 100644 --- a/examples/device/uac2_speaker_fb/src/usb_descriptors.c +++ b/examples/device/uac2_speaker_fb/src/usb_descriptors.c @@ -115,7 +115,7 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) { #define EPNUM_AUDIO_FB 0x08 #define EPNUM_DEBUG 0x01 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_AUDIO 0x02 diff --git a/examples/device/webusb_serial/src/usb_descriptors.c b/examples/device/webusb_serial/src/usb_descriptors.c index 0ef41a68e..415d2b66a 100644 --- a/examples/device/webusb_serial/src/usb_descriptors.c +++ b/examples/device/webusb_serial/src/usb_descriptors.c @@ -104,7 +104,7 @@ enum #define EPNUM_VENDOR_OUT 0x05 #define EPNUM_VENDOR_IN 0x84 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_NOTIF 0x81 diff --git a/examples/dual/dynamic_switch/src/usb_descriptors.c b/examples/dual/dynamic_switch/src/usb_descriptors.c index 54ffc2c18..ef6d795b7 100644 --- a/examples/dual/dynamic_switch/src/usb_descriptors.c +++ b/examples/dual/dynamic_switch/src/usb_descriptors.c @@ -86,7 +86,7 @@ enum { #define EPNUM_CDC_OUT 0x02 #define EPNUM_CDC_IN 0x82 -#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_CDC_NOTIF 0x81 diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 77a0bbf1d..651bb149d 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -177,12 +177,12 @@ #elif TU_CHECK_MCU(OPT_MCU_SAMG) #define TUP_DCD_ENDPOINT_MAX 6 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 #elif TU_CHECK_MCU(OPT_MCU_SAMX7X) #define TUP_DCD_ENDPOINT_MAX 10 #define TUP_RHPORT_HIGHSPEED 1 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 // Enable dcache if DMA is enabled #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_SAMX7X_DMA_ENABLE @@ -190,11 +190,11 @@ #elif TU_CHECK_MCU(OPT_MCU_PIC32MZ) #define TUP_DCD_ENDPOINT_MAX 8 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 #elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33) #define TUP_DCD_ENDPOINT_MAX 16 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 #define TUP_DCD_EDPT_CLOSE_API //--------------------------------------------------------------------+ @@ -411,7 +411,7 @@ #elif TU_CHECK_MCU(OPT_MCU_CXD56) #define TUP_DCD_ENDPOINT_MAX 7 #define TUP_RHPORT_HIGHSPEED 1 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 //--------------------------------------------------------------------+ // TI @@ -547,12 +547,12 @@ #elif TU_CHECK_MCU(OPT_MCU_FT90X) #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 #elif TU_CHECK_MCU(OPT_MCU_FT93X) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_RHPORT_HIGHSPEED 1 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 //--------------------------------------------------------------------+ // Allwinner @@ -643,7 +643,7 @@ #define TUP_USBIP_MUSB_ADI #define TUP_DCD_ENDPOINT_MAX 12 #define TUP_RHPORT_HIGHSPEED 1 - #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1 //--------------------------------------------------------------------+ // ArteryTek @@ -727,3 +727,14 @@ #ifndef TUP_DCD_EDPT_CLOSE_API #define TUP_DCD_EDPT_ISO_ALLOC #endif + +// Some USBIPs (SAMG, SAMX7X, PIC32, MAX3266x/MAX78002) cannot assign the same endpoint +// number to both IN and OUT. Default to 0 (same endpoint number may be used for IN and OUT). +#ifndef CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 0 +#endif + +// Backward-compatible alias: legacy code only tests defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) +#if CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY && !defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY +#endif -- cgit v1.3.1 From 8513c50231e1935657737b42a739e96c6d0dd154 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 22 Apr 2026 11:53:02 +0700 Subject: musb implement double buffer for tx --- examples/device/cdc_msc/src/usb_descriptors.c | 22 +++++++--- examples/device/dfu/skip.txt | 1 - .../net_lwip_webserver/src/usb_descriptors.c | 10 ++++- src/portable/mentor/musb/dcd_musb.c | 49 +++++++++++++--------- src/portable/mentor/musb/musb_type.h | 10 +++++ 5 files changed, 64 insertions(+), 28 deletions(-) (limited to 'examples/device/net_lwip_webserver/src') diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c index b738e7d12..5dc80dee3 100644 --- a/examples/device/cdc_msc/src/usb_descriptors.c +++ b/examples/device/cdc_msc/src/usb_descriptors.c @@ -105,12 +105,22 @@ enum { #elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together - #define EPNUM_CDC_NOTIF 0x81 - #define EPNUM_CDC_OUT 0x02 - #define EPNUM_CDC_IN 0x83 - - #define EPNUM_MSC_OUT 0x04 - #define EPNUM_MSC_IN 0x85 + #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_CDC_NOTIF 0x81 + #define EPNUM_CDC_OUT 0x08 + #define EPNUM_CDC_IN 0x89 + + #define EPNUM_MSC_OUT 0x0A + #define EPNUM_MSC_IN 0x8B + #else + #define EPNUM_CDC_NOTIF 0x81 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x83 + + #define EPNUM_MSC_OUT 0x04 + #define EPNUM_MSC_IN 0x85 + #endif #else #define EPNUM_CDC_NOTIF 0x81 diff --git a/examples/device/dfu/skip.txt b/examples/device/dfu/skip.txt index 79d3da9d2..ccff857ac 100644 --- a/examples/device/dfu/skip.txt +++ b/examples/device/dfu/skip.txt @@ -1,3 +1,2 @@ -mcu:TM4C mcu:BCM2835 family:espressif diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c index 8cfef41a6..e97b103f9 100644 --- a/examples/device/net_lwip_webserver/src/usb_descriptors.c +++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c @@ -122,11 +122,19 @@ const uint8_t *tud_descriptor_device_cb(void) { #define EPNUM_NET_IN 0x81 #elif CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY -// MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h +// MCUs that don't support the same endpoint number with different direction IN and OUT defined in tusb_mcu.h // 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) +// endpoint 8,9 has FIFO of 2048 bytes +#define EPNUM_NET_NOTIF 0x81 +#define EPNUM_NET_OUT 0x08 +#define EPNUM_NET_IN 0x89 +#else #define EPNUM_NET_NOTIF 0x81 #define EPNUM_NET_OUT 0x02 #define EPNUM_NET_IN 0x83 +#endif #else #define EPNUM_NET_NOTIF 0x81 diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index 02d9c2f66..667102bc5 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -172,9 +172,15 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_reset(musb_regs_t* musb, unsigne TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsigned epnum, unsigned is_rx, unsigned mps, bool double_packet) { - (void) epnum; (void) mps; + (void) mps; #if defined(TUP_USBIP_MUSB_ADI) + // AnalogDevice FIFO sizes: EP1..7 = 512 B, EP8..9 = 2048 B, EP10..11 = 4096 B. + // DPB requires FIFO >= 2 * MPS. For HS bulk (MPS=512) only EP >= 8 qualifies. + // Force single-buffered on EP < 8 even if the caller requested DPB. + if (epnum < 8 && (musb->power & MUSB_POWER_HSMODE)) { + double_packet = false; + } volatile uint8_t* csrh = &musb->indexed_csr.maxp_csr[is_rx].csrh; if (double_packet) { *csrh &= ~MUSB_CSRH_DISABLE_DOUBLE_PACKET; @@ -234,7 +240,7 @@ static void process_setup_packet(uint8_t rhport) { // write to txfifo using pipe_state_t info static void pipe_write(musb_regs_t* musb_regs, pipe_state_t* pipe, uint8_t epnum) { musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); - const unsigned mps = ep_csr->tx_maxp; + const unsigned mps = ep_csr->tx_maxp & MUSB_TXMAXP_PACKET_SIZE_MASK; const unsigned rem = pipe->remaining; const unsigned len = TU_MIN(mps, rem); volatile void *fifo_ptr = &musb_regs->fifo[epnum]; @@ -260,7 +266,9 @@ static void process_epin(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum) } pipe_state_t* pipe = pipe_get(epnum, TUSB_DIR_IN); - if (pipe->remaining == 0) { + if (pipe->remaining > 0) { + pipe_write(musb_regs, pipe, epnum); + } else { // All bytes have been loaded into the FIFO. With double-packet buffering a // second packet may still be waiting in the FIFO when this IRQ fires (the // hardware signals TXRDY clear as soon as a slot frees, not when the wire @@ -273,12 +281,10 @@ static void process_epin(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum) pipe->buf = NULL; pipe->armed = false; dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, TUSB_DIR_IN), xferred_len, XFER_RESULT_SUCCESS, true); - return; } - pipe_write(musb_regs, pipe, epnum); } -static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum) { +static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum, bool is_isr) { musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); if (ep_csr->rx_csrl & MUSB_RXCSRL1_STALLED) { ep_csr->rx_csrl &= ~(MUSB_RXCSRL1_STALLED | MUSB_RXCSRL1_OVER); @@ -302,7 +308,7 @@ static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum) return; } - const unsigned mps = ep_csr->rx_maxp; + const unsigned mps = ep_csr->rx_maxp & MUSB_RXMAXP_PACKET_SIZE_MASK; const unsigned rem = pipe->remaining; const unsigned vld = ep_csr->rx_count; const unsigned len = TU_MIN(TU_MIN(rem, mps), vld); @@ -323,11 +329,11 @@ static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum) pipe->buf = NULL; pipe->armed = false; - dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, TUSB_DIR_OUT), xferred_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, TUSB_DIR_OUT), xferred_len, XFER_RESULT_SUCCESS, is_isr); } } -static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, void *buffer, uint16_t total_bytes, bool use_fifo) { +static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, void *buffer, uint16_t total_bytes, bool use_fifo, bool is_isr) { const uint8_t epnum = tu_edpt_number(ep_addr); const unsigned dir_in = tu_edpt_dir(ep_addr); @@ -354,13 +360,13 @@ static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, void *buffer, uint16_t // Drain any packet staged in the Rx FIFO from a prior no-buffer interrupt. // process_epout() fires dcd_event_xfer_complete() itself if the drain completes. if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) { - process_epout(rhport, musb_regs, epnum); + process_epout(rhport, musb_regs, epnum, is_isr); } } return true; } -static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) +static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { (void)rhport; TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */ @@ -380,7 +386,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ // TU_LOG1(" STATUS OUT ep_csr->csr0l = %x\r\n", ep_csr->csr0l); _dcd.status_out = 0; if (req == REQUEST_TYPE_INVALID) { - dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); + dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, is_isr); } else { /* The next setup packet has already been received, it aborts * invoking callback function to avoid confusing TUSB stack. */ @@ -755,18 +761,16 @@ void dcd_edpt_close_all(uint8_t rhport) // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; (void)rhport; bool ret; - // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); unsigned const ie = musb_dcd_get_int_enable(rhport); musb_dcd_int_disable(rhport); if (epnum) { - ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes, false); + ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes, false, is_isr); } else { - ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes); + ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes, is_isr); } if (ie) { @@ -779,15 +783,13 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t // - optional, however, must be listed in usbd.c bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { - (void) is_isr; (void)rhport; bool ret; - // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); TU_ASSERT(epnum); unsigned const ie = musb_dcd_get_int_enable(rhport); musb_dcd_int_disable(rhport); - ret = edpt_n_xfer(rhport, ep_addr, ff, total_bytes, true); + ret = edpt_n_xfer(rhport, ep_addr, ff, total_bytes, true, is_isr); if (ie) musb_dcd_int_enable(rhport); return ret; } @@ -871,16 +873,23 @@ void dcd_int_handler(uint8_t rhport) { process_ep0(rhport); intr_tx &= ~TU_BIT(0); } + while (intr_tx) { const unsigned epnum = __builtin_ctz(intr_tx); process_epin(rhport, musb_regs, epnum); intr_tx &= ~TU_BIT(epnum); + + // for Double-buffered endpoint: TxPktRdy is cleared and interrupt is generated when we write the first packet + uint_fast8_t new_intr_tx = musb_regs->intr_tx; + new_intr_tx &= musb_regs->intr_txen; + + intr_tx |= new_intr_tx; } intr_rx &= musb_regs->intr_rxen; /* Clear disabled interrupts */ while (intr_rx) { unsigned const epnum = __builtin_ctz(intr_rx); - process_epout(rhport, musb_regs, epnum); + process_epout(rhport, musb_regs, epnum, true); intr_rx &= ~TU_BIT(epnum); } diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h index 6a85d2ca8..dd1cd6ded 100644 --- a/src/portable/mentor/musb/musb_type.h +++ b/src/portable/mentor/musb/musb_type.h @@ -566,6 +566,16 @@ TU_ATTR_ALWAYS_INLINE static inline musb_ep_csr_t* get_ep_csr(musb_regs_t* musb_ #define MUSB_NAKLMT_NAKLMT_M 0x001F // EP0 NAK Limit #define MUSB_NAKLMT_NAKLMT_S 0 +//***************************************************************************** +// +// The following are defines for the bit fields in the MUSB_O_TXMAXP / MUSB_O_RXMAXP +// registers. Bits [10:0] carry the maximum packet size; bits [15:11] carry +// numpackminus1 (HB-iso / HS-bulk multiplier - 1). +// +//***************************************************************************** +#define MUSB_TXMAXP_PACKET_SIZE_MASK 0x07FFu +#define MUSB_RXMAXP_PACKET_SIZE_MASK 0x07FFu + //***************************************************************************** // // The following are defines for the bit fields in the MUSB_O_TXCSRL1 register. -- cgit v1.3.1 From f9ffb94f3d392140cc350cdb532f0576552bbeb8 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 23 Apr 2026 15:27:05 +0700 Subject: tweak lwip config to get better iperf throughput --- examples/device/net_lwip_webserver/src/lwipopts.h | 8 +++++--- examples/device/net_lwip_webserver/src/tusb_config.h | 11 ++++------- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'examples/device/net_lwip_webserver/src') diff --git a/examples/device/net_lwip_webserver/src/lwipopts.h b/examples/device/net_lwip_webserver/src/lwipopts.h index 11686ce2a..4fdef6b4e 100644 --- a/examples/device/net_lwip_webserver/src/lwipopts.h +++ b/examples/device/net_lwip_webserver/src/lwipopts.h @@ -48,8 +48,8 @@ #define LWIP_IP_ACCEPT_UDP_PORT(p) ((p) == PP_NTOHS(67)) #define TCP_MSS (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/) -#define TCP_SND_BUF (4 * TCP_MSS) -#define TCP_WND (4 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_WND (8 * TCP_MSS) #define ETHARP_SUPPORT_STATIC_ENTRIES 1 @@ -60,7 +60,9 @@ #define LWIP_SINGLE_NETIF 1 #define LWIP_NETIF_LINK_CALLBACK 1 -#define PBUF_POOL_SIZE 4 +#define PBUF_POOL_SIZE 8 +// Must grow in step with TCP_SND_BUF (default MEMP_NUM_TCP_SEG=16 caps TCP_SND_BUF at 4*MSS). +#define MEMP_NUM_TCP_SEG 32 #define HTTPD_USE_CUSTOM_FSDATA 0 diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h index db52e3b50..ae7d00a74 100644 --- a/examples/device/net_lwip_webserver/src/tusb_config.h +++ b/examples/device/net_lwip_webserver/src/tusb_config.h @@ -92,8 +92,6 @@ extern "C" { #define USE_ECM 1 #elif TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F1) #define USE_ECM 1 -#elif TU_CHECK_MCU(OPT_MCU_MAX32690, OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX78002) - #define USE_ECM 1 #else #define USE_ECM 0 #endif @@ -109,20 +107,19 @@ extern "C" { // Must be >> MTU // Can be set to 2048 without impact -#define CFG_TUD_NCM_IN_NTB_MAX_SIZE (2 * TCP_MSS + 100) +#define CFG_TUD_NCM_IN_NTB_MAX_SIZE (3 * TCP_MSS + 100) // Must be >> MTU // Can be set to smaller values if wNtbOutMaxDatagrams==1 -#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (2 * TCP_MSS + 100) +#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (3 * TCP_MSS + 100) // Number of NCM transfer blocks for reception side #ifndef CFG_TUD_NCM_OUT_NTB_N - #define CFG_TUD_NCM_OUT_NTB_N 1 + #define CFG_TUD_NCM_OUT_NTB_N 2 #endif -// Number of NCM transfer blocks for transmission side #ifndef CFG_TUD_NCM_IN_NTB_N - #define CFG_TUD_NCM_IN_NTB_N 1 + #define CFG_TUD_NCM_IN_NTB_N 2 #endif //-------------------------------------------------------------------- -- cgit v1.3.1 From d3b6a252b142592a3bacae5e44ab8770421812b7 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 23 Apr 2026 15:57:47 +0700 Subject: reduce memory, focus on keep iperf speed --- examples/device/net_lwip_webserver/src/lwipopts.h | 4 ++-- examples/device/net_lwip_webserver/src/tusb_config.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'examples/device/net_lwip_webserver/src') diff --git a/examples/device/net_lwip_webserver/src/lwipopts.h b/examples/device/net_lwip_webserver/src/lwipopts.h index 4fdef6b4e..6682d2903 100644 --- a/examples/device/net_lwip_webserver/src/lwipopts.h +++ b/examples/device/net_lwip_webserver/src/lwipopts.h @@ -48,7 +48,7 @@ #define LWIP_IP_ACCEPT_UDP_PORT(p) ((p) == PP_NTOHS(67)) #define TCP_MSS (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/) -#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_SND_BUF (4 * TCP_MSS) #define TCP_WND (8 * TCP_MSS) #define ETHARP_SUPPORT_STATIC_ENTRIES 1 @@ -62,7 +62,7 @@ #define PBUF_POOL_SIZE 8 // Must grow in step with TCP_SND_BUF (default MEMP_NUM_TCP_SEG=16 caps TCP_SND_BUF at 4*MSS). -#define MEMP_NUM_TCP_SEG 32 +#define MEMP_NUM_TCP_SEG 16 #define HTTPD_USE_CUSTOM_FSDATA 0 diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h index ae7d00a74..6809a3fae 100644 --- a/examples/device/net_lwip_webserver/src/tusb_config.h +++ b/examples/device/net_lwip_webserver/src/tusb_config.h @@ -107,7 +107,7 @@ extern "C" { // Must be >> MTU // Can be set to 2048 without impact -#define CFG_TUD_NCM_IN_NTB_MAX_SIZE (3 * TCP_MSS + 100) +#define CFG_TUD_NCM_IN_NTB_MAX_SIZE (1 * TCP_MSS + 100) // Must be >> MTU // Can be set to smaller values if wNtbOutMaxDatagrams==1 @@ -115,11 +115,11 @@ extern "C" { // Number of NCM transfer blocks for reception side #ifndef CFG_TUD_NCM_OUT_NTB_N - #define CFG_TUD_NCM_OUT_NTB_N 2 + #define CFG_TUD_NCM_OUT_NTB_N 1 #endif #ifndef CFG_TUD_NCM_IN_NTB_N - #define CFG_TUD_NCM_IN_NTB_N 2 + #define CFG_TUD_NCM_IN_NTB_N 1 #endif //-------------------------------------------------------------------- -- cgit v1.3.1 From bafce337f76551cc60e15e4072fc563380b8e908 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 26 Apr 2026 09:43:58 +0700 Subject: gate lwIP throughput tuning + iperf on MCU SRAM tier The bigger TCP_WND/PBUF_POOL/MEMP_NUM_TCP_SEG and the always-on iperf overflowed SRAM on stm32c0/f1/wb, lpc11/13, samd11. Add LWIP_HIGH_THROUGHPUT gate (defined in tusb_config.h, consumed by lwipopts.h) so RAM-tight MCUs keep the original modest buffers and skip iperf, while RAM-rich targets (max32*/stm32f2/f4/f7/h5/h7/h7rs/u5/n6, rp2040, mimxrt1xxx, nrf5x) keep the throughput tuning needed for the iperf HIL test. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/device/net_lwip_webserver/src/lwipopts.h | 22 ++++++++++++++----- .../device/net_lwip_webserver/src/tusb_config.h | 25 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 7 deletions(-) (limited to 'examples/device/net_lwip_webserver/src') diff --git a/examples/device/net_lwip_webserver/src/lwipopts.h b/examples/device/net_lwip_webserver/src/lwipopts.h index 6682d2903..350120423 100644 --- a/examples/device/net_lwip_webserver/src/lwipopts.h +++ b/examples/device/net_lwip_webserver/src/lwipopts.h @@ -32,6 +32,14 @@ #ifndef LWIPOPTS_H__ #define LWIPOPTS_H__ +// Pulls in tusb_option.h → tusb_config.h, which defines LWIP_HIGH_THROUGHPUT +// based on the target MCU's SRAM tier. +#include "tusb_option.h" + +#ifndef LWIP_HIGH_THROUGHPUT + #define LWIP_HIGH_THROUGHPUT 0 +#endif + /* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ #define NO_SYS 1 #define MEM_ALIGNMENT 4 @@ -49,7 +57,15 @@ #define TCP_MSS (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/) #define TCP_SND_BUF (4 * TCP_MSS) -#define TCP_WND (8 * TCP_MSS) +#if LWIP_HIGH_THROUGHPUT + #define TCP_WND (8 * TCP_MSS) + #define PBUF_POOL_SIZE 8 + // Must grow in step with TCP_SND_BUF (default MEMP_NUM_TCP_SEG=16 caps TCP_SND_BUF at 4*MSS). + #define MEMP_NUM_TCP_SEG 16 +#else + #define TCP_WND (4 * TCP_MSS) + #define PBUF_POOL_SIZE 4 +#endif #define ETHARP_SUPPORT_STATIC_ENTRIES 1 @@ -60,10 +76,6 @@ #define LWIP_SINGLE_NETIF 1 #define LWIP_NETIF_LINK_CALLBACK 1 -#define PBUF_POOL_SIZE 8 -// Must grow in step with TCP_SND_BUF (default MEMP_NUM_TCP_SEG=16 caps TCP_SND_BUF at 4*MSS). -#define MEMP_NUM_TCP_SEG 16 - #define HTTPD_USE_CUSTOM_FSDATA 0 #define LWIP_MULTICAST_PING 1 diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h index 6809a3fae..24082fe25 100644 --- a/examples/device/net_lwip_webserver/src/tusb_config.h +++ b/examples/device/net_lwip_webserver/src/tusb_config.h @@ -97,7 +97,24 @@ extern "C" { #endif #endif -#ifndef INCLUDE_IPERF +// MCU SRAM tier — drives the bigger lwIP buffers in lwipopts.h, the larger +// NCM OUT NTB size below, and whether iperf is built. Small-RAM MCUs +// (stm32c0/f1/wb, lpc11/13, samd11) keep modest defaults to fit. +#ifndef LWIP_HIGH_THROUGHPUT + #if TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) || \ + TU_CHECK_MCU(OPT_MCU_STM32F2, OPT_MCU_STM32F4, OPT_MCU_STM32F7) || \ + TU_CHECK_MCU(OPT_MCU_STM32H5, OPT_MCU_STM32H7, OPT_MCU_STM32H7RS) || \ + TU_CHECK_MCU(OPT_MCU_STM32U5, OPT_MCU_STM32N6) || \ + TU_CHECK_MCU(OPT_MCU_RP2040) || \ + TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX) || \ + TU_CHECK_MCU(OPT_MCU_NRF5X) + #define LWIP_HIGH_THROUGHPUT 1 + #else + #define LWIP_HIGH_THROUGHPUT 0 + #endif +#endif + +#if LWIP_HIGH_THROUGHPUT && !defined(INCLUDE_IPERF) #define INCLUDE_IPERF #endif @@ -111,7 +128,11 @@ extern "C" { // Must be >> MTU // Can be set to smaller values if wNtbOutMaxDatagrams==1 -#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (3 * TCP_MSS + 100) +#if LWIP_HIGH_THROUGHPUT + #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (3 * TCP_MSS + 100) +#else + #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (2 * TCP_MSS + 100) +#endif // Number of NCM transfer blocks for reception side #ifndef CFG_TUD_NCM_OUT_NTB_N -- cgit v1.3.1