diff options
| author | Ha Thach <[email protected]> | 2026-03-13 01:29:37 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-13 01:29:37 +0700 |
| commit | f98f7e003fc8c4bcdf503e8c9bff29122b70cc9e (patch) | |
| tree | ad99f53db0e5da76d8eee987b30fdbba8776942e | |
| parent | 1fcb49fc638635337dc3d757767428bc3cb8c4b7 (diff) | |
| parent | 5bca175ea1f19309bc3f53a9435cb289561e1aa2 (diff) | |
Merge pull request #3438 from hathach/ncm_restart
Fix NCM state on restart
| -rw-r--r-- | examples/device/net_lwip_webserver/src/main.c | 51 | ||||
| -rw-r--r-- | hw/bsp/stm32h7/boards/stm32h747disco/board.h | 2 | ||||
| -rw-r--r-- | src/class/net/ncm_device.c | 89 |
3 files changed, 116 insertions, 26 deletions
diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c index 8bd8a8c21..b78fd7c00 100644 --- a/examples/device/net_lwip_webserver/src/main.c +++ b/examples/device/net_lwip_webserver/src/main.c @@ -67,6 +67,19 @@ try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00 #define INIT_IP4(a, b, c, d) \ { PP_HTONL(LWIP_MAKEU32(a, b, c, d)) } +/* Blink pattern + * - 250 ms : device not mounted + * - 1000 ms : device mounted + * - 2500 ms : device is suspended + */ +enum { + BLINK_NOT_MOUNTED = 250, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, +}; + +static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; + /* lwip context */ static struct netif netif_data; @@ -218,6 +231,20 @@ uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) { return pbuf_copy_partial(p, dst, p->tot_len, 0); } +static void led_blinking_task(void) { + static uint32_t start_ms = 0; + static bool led_state = false; + + // Blink every interval ms + if (tusb_time_millis_api() - start_ms < blink_interval_ms) { + return; // not enough time + } + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} + static void handle_link_state_switch(void) { /* Check for button press to toggle link state */ static bool last_link_state = true; @@ -275,9 +302,33 @@ int main(void) { tud_task(); sys_check_timeouts(); // service lwip handle_link_state_switch(); + led_blinking_task(); } } +// Invoked when device is mounted +void tud_mount_cb(void) { + blink_interval_ms = BLINK_MOUNTED; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) { + blink_interval_ms = BLINK_NOT_MOUNTED; +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) { + (void) remote_wakeup_en; + blink_interval_ms = BLINK_SUSPENDED; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) { + blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; +} + /* lwip has provision for using a mutex, when applicable */ /* This implementation is for single-threaded use only */ sys_prot_t sys_arch_protect(void) { diff --git a/hw/bsp/stm32h7/boards/stm32h747disco/board.h b/hw/bsp/stm32h7/boards/stm32h747disco/board.h index 458aa48b6..0a25c89dc 100644 --- a/hw/bsp/stm32h7/boards/stm32h747disco/board.h +++ b/hw/bsp/stm32h7/boards/stm32h747disco/board.h @@ -63,7 +63,7 @@ static board_pindef_t board_pindef[] = { }, { // Button .port = GPIOC, - .pin_init = { .Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_HIGH, .Alternate = 0 }, + .pin_init = { .Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_HIGH, .Alternate = 0 }, .active_state = 1 }, { // UART TX diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 3e19b5f3a..405e4467b 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -86,14 +86,24 @@ typedef struct { // recv handling recv_ntb_t *recv_free_ntb[RECV_NTB_N]; // free list of recv NTBs - recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; // NTBs waiting for transmission to glue logic + recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; // NTBs waiting for transmission to glue logic (circular buffer) + #if RECV_NTB_N > 1 + uint8_t recv_ready_head; // head index for recv_ready_ntb circular buffer + uint8_t recv_ready_tail; // tail index for recv_ready_ntb circular buffer + uint8_t recv_ready_count; // number of elements in recv_ready_ntb circular buffer + #endif recv_ntb_t *recv_tinyusb_ntb; // buffer for the running transfer TinyUSB -> driver recv_ntb_t *recv_glue_ntb; // buffer for the running transfer driver -> glue logic uint16_t recv_glue_ntb_datagram_ndx; // index into \a recv_glue_ntb_datagram // xmit handling xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; // free list of xmit NTBs - xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; // NTBs waiting for transmission to TinyUSB + xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; // NTBs waiting for transmission to TinyUSB (circular buffer) + #if XMIT_NTB_N > 1 + uint8_t xmit_ready_head; // head index for xmit_ready_ntb circular buffer + uint8_t xmit_ready_tail; // tail index for xmit_ready_ntb circular buffer + uint8_t xmit_ready_count; // number of elements in xmit_ready_ntb circular buffer + #endif xmit_ntb_t *xmit_tinyusb_ntb; // buffer for the running transfer driver -> TinyUSB xmit_ntb_t *xmit_glue_ntb; // buffer for the running transfer glue logic -> driver uint16_t xmit_sequence; // NTB sequence counter @@ -279,13 +289,17 @@ static xmit_ntb_t *xmit_get_free_ntb(void) { static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) { TU_LOG_DRV("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); - for (int i = 0; i < XMIT_NTB_N; ++i) { - if (ncm_interface.xmit_ready_ntb[i] == NULL) { - ncm_interface.xmit_ready_ntb[i] = ready_ntb; - return; - } +#if XMIT_NTB_N == 1 + ncm_interface.xmit_ready_ntb[0] = ready_ntb; +#else + if (ncm_interface.xmit_ready_count >= XMIT_NTB_N) { + TU_LOG_DRV("(EE) xmit_put_ntb_into_ready_list: ready list full\n");// this should not happen + return; } - TU_LOG_DRV("(EE) xmit_put_ntb_into_ready_list: ready list full\n");// this should not happen + ncm_interface.xmit_ready_ntb[ncm_interface.xmit_ready_head] = ready_ntb; + ncm_interface.xmit_ready_head = (ncm_interface.xmit_ready_head + 1) % XMIT_NTB_N; + ncm_interface.xmit_ready_count++; +#endif } // xmit_put_ntb_into_ready_list /** @@ -293,14 +307,23 @@ static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) { * If the ready list is empty, return NULL. */ static xmit_ntb_t *xmit_get_next_ready_ntb(void) { - xmit_ntb_t *r = NULL; +#if XMIT_NTB_N == 1 + xmit_ntb_t *r = ncm_interface.xmit_ready_ntb[0]; + ncm_interface.xmit_ready_ntb[0] = NULL; + TU_LOG_DRV("xmit_get_next_ready_ntb: %p\n", r); + return r; +#else + if (ncm_interface.xmit_ready_count == 0) { + return NULL; // empty + } - r = ncm_interface.xmit_ready_ntb[0]; - memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0])); - ncm_interface.xmit_ready_ntb[XMIT_NTB_N - 1] = NULL; + xmit_ntb_t *r = ncm_interface.xmit_ready_ntb[ncm_interface.xmit_ready_tail]; + ncm_interface.xmit_ready_tail = (ncm_interface.xmit_ready_tail + 1) % XMIT_NTB_N; + ncm_interface.xmit_ready_count--; - TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r); + TU_LOG_DRV("xmit_get_next_ready_ntb: %p\n", r); return r; +#endif } // xmit_get_next_ready_ntb /** @@ -458,14 +481,23 @@ static recv_ntb_t *recv_get_free_ntb(void) { * If the ready list is empty, return NULL. */ static recv_ntb_t *recv_get_next_ready_ntb(void) { - recv_ntb_t *r = NULL; +#if RECV_NTB_N == 1 + recv_ntb_t *r = ncm_interface.recv_ready_ntb[0]; + ncm_interface.recv_ready_ntb[0] = NULL; + TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r); + return r; +#else + if (ncm_interface.recv_ready_count == 0) { + return NULL; // empty + } - r = ncm_interface.recv_ready_ntb[0]; - memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0])); - ncm_interface.recv_ready_ntb[RECV_NTB_N - 1] = NULL; + recv_ntb_t *r = ncm_interface.recv_ready_ntb[ncm_interface.recv_ready_tail]; + ncm_interface.recv_ready_tail = (ncm_interface.recv_ready_tail + 1) % RECV_NTB_N; + ncm_interface.recv_ready_count--; TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r); return r; +#endif } // recv_get_next_ready_ntb /** @@ -490,13 +522,17 @@ static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) { static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) { TU_LOG_DRV("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); - for (int i = 0; i < RECV_NTB_N; ++i) { - if (ncm_interface.recv_ready_ntb[i] == NULL) { - ncm_interface.recv_ready_ntb[i] = ready_ntb; - return; - } +#if RECV_NTB_N == 1 + ncm_interface.recv_ready_ntb[0] = ready_ntb; +#else + if (ncm_interface.recv_ready_count >= RECV_NTB_N) { + TU_LOG_DRV("(EE) recv_put_ntb_into_ready_list: ready list full\n");// this should not happen + return; } - TU_LOG_DRV("(EE) recv_put_ntb_into_ready_list: ready list full\n");// this should not happen + ncm_interface.recv_ready_ntb[ncm_interface.recv_ready_head] = ready_ntb; + ncm_interface.recv_ready_head = (ncm_interface.recv_ready_head + 1) % RECV_NTB_N; + ncm_interface.recv_ready_count++; +#endif } // recv_put_ntb_into_ready_list /** @@ -772,8 +808,8 @@ void tud_network_link_state(uint8_t rhport, bool is_up) { return; } - // Reset notification state to send link state update - ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED; + // Reset notification state to send speed change notification first, then link state notification + ncm_interface.notification_xmit_state = NOTIFICATION_SPEED; // Trigger notification transmission notification_xmit(rhport, false); @@ -940,6 +976,9 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t if (ncm_interface.itf_data_alt == 1) { tud_network_recv_renew_r(rhport); notification_xmit(rhport, false); + } else { + // Reset notification state to send link state update when interface is re-activated + ncm_interface.notification_xmit_state = NOTIFICATION_SPEED; } tud_control_status(rhport, request); } break; |
