// // Created by Administrator on 2025/12/31. // #include "usb_cdc_char_device.h" #include // 例如在 board init / main 里 int usb_init(void) { return rt_hw_usbd_cdc_char_init("cdc0", 0, USB_OTG_FS_PERIPH_BASE); } // INIT_APP_EXPORT(usb_init); #include "usb_cdc_char_device.h" /* 为了 CDC_CTRL_GET_CONFIGURED */ /* 线程参数 */ #define CDC_ECHO_THREAD_NAME "cdc_echo" #define CDC_ECHO_THREAD_STACK 4096 #define CDC_ECHO_THREAD_PRIO 20 #define CDC_ECHO_THREAD_TICK 10 /* 等待策略 */ #define CDC_WAIT_SEM_TIMEOUT_MS 500 /* 不要 FOREVER,支持先启动后插线/断开重连 */ #define CDC_NOT_CFG_DELAY_MS 50 /* RX 等待信号量 */ static rt_sem_t s_cdc_rx_sem = RT_NULL; /* 保存设备句柄 */ static rt_device_t s_cdc_dev = RT_NULL; /* RX 回调:有数据到来时被驱动调用(或驱动事件里用 size=0 唤醒) */ static rt_err_t cdc_rx_ind(rt_device_t dev, rt_size_t size) { (void)dev; (void)size; if (s_cdc_rx_sem) { rt_sem_release(s_cdc_rx_sem); } return RT_EOK; } static int cdc_is_configured(rt_device_t dev) { uint8_t cfg = 0; if (rt_device_control(dev, CDC_CTRL_GET_CONFIGURED, &cfg) == RT_EOK) { return cfg ? 1 : 0; } /* control 不支持时,保守认为未配置 */ return 0; } /* echo 线程:等待 -> 读 -> 立刻写回(支持断开重连) */ static void cdc_echo_thread(void *parameter) { (void)parameter; s_cdc_dev = rt_device_find("cdc0"); if (!s_cdc_dev) { rt_kprintf("cdc_echo: cdc0 not found\n"); return; } if (rt_device_open(s_cdc_dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK) { rt_kprintf("cdc_echo: open cdc0 failed\n"); return; } s_cdc_rx_sem = rt_sem_create("cdc_rx", 0, RT_IPC_FLAG_FIFO); if (!s_cdc_rx_sem) { rt_kprintf("cdc_echo: sem create failed\n"); rt_device_close(s_cdc_dev); return; } rt_device_set_rx_indicate(s_cdc_dev, cdc_rx_ind); rt_kprintf("cdc_echo: started, supports plug/unplug\n"); char buf[1024]; while (1) { /* 关键:不要 FOREVER,避免未插线/断开时永远卡住 */ rt_sem_take(s_cdc_rx_sem, rt_tick_from_millisecond(CDC_WAIT_SEM_TIMEOUT_MS)); /* 没枚举好/断开:不读不写,稍等继续 */ if (!cdc_is_configured(s_cdc_dev)) { rt_thread_mdelay(CDC_NOT_CFG_DELAY_MS); continue; } /* 把 ringbuffer 里当前所有数据读光并回写 */ while (1) { rt_ssize_t rn = rt_device_read(s_cdc_dev, 0, buf, sizeof(buf)); if (rn > 0) { rt_ssize_t wn = rt_device_write(s_cdc_dev, 0, buf, (rt_size_t)rn); if (wn < 0) { /* 典型:断开/未配置 => -RT_EIO */ rt_kprintf("cdc_echo: write err=%d\n", (int)wn); break; } } else if (rn == 0) { /* 暂时没数据 */ rt_kprintf("cdc_echo: read err=%d\n", (int)rn); break; } else { /* rn < 0:典型 -RT_EIO(断开/未配置) */ rt_kprintf("cdc_echo: read err=%d\n", (int)rn); break; } } } } /* 创建并启动线程 */ int cdc_echo_start(void) { if (rt_thread_find(CDC_ECHO_THREAD_NAME)) { rt_kprintf("cdc_echo: thread already running\n"); return -RT_EBUSY; } rt_thread_t tid = rt_thread_create(CDC_ECHO_THREAD_NAME, cdc_echo_thread, RT_NULL, CDC_ECHO_THREAD_STACK, CDC_ECHO_THREAD_PRIO, CDC_ECHO_THREAD_TICK); if (!tid) { rt_kprintf("cdc_echo: create thread failed\n"); return -RT_ENOMEM; } rt_thread_startup(tid); return RT_EOK; } MSH_CMD_EXPORT(cdc_echo_start, start usb cdc echo thread);