cmvr_head/board/ports/usb/usb_cdc_init.c

154 lines
4.1 KiB
C
Raw Permalink Normal View History

2026-01-07 11:41:07 +08:00
//
// 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);