154 lines
4.1 KiB
C
154 lines
4.1 KiB
C
|
|
//
|
|||
|
|
// Created by Administrator on 2025/12/31.
|
|||
|
|
//
|
|||
|
|
#include "usb_cdc_char_device.h"
|
|||
|
|
#include <board.h>
|
|||
|
|
|
|||
|
|
// 例如在 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);
|