feat(proto): 添加设备通信协议v1修订版及统一帧格式
- 新增docs/device_communication_protocol_v1.md文档,定义V1修订版协议 - CDC和BLE GATT均改为直接传输业务消息,去掉外层协议封装 - BLE改为使用NUS(Nordic UART Service)替代原有GATT服务 - 统一键盘位图为29字节格式,FunctionKeyEvent改为上报全键盘位图 - 顶层消息增加msg_id和reply_to字段用于请求响应匹配 - Ack和Error合并为统一Response消息类型 - CDC和NUS均增加统一外层帧格式:magic(2) + len(1) + protobuf - 添加Proto frame常量定义及长度验证逻辑 - 更新proto文件定义,包含DeviceMessage统一信封和ResponseCode枚举 - 重构hid_flowctrl_module.c中的上下文访问方式,统一使用ctx前缀
This commit is contained in:
@@ -28,8 +28,7 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
#define USB_CDC_RX_RING_BUF_SIZE 256
|
||||
#define USB_CDC_TX_RING_BUF_SIZE 256
|
||||
#define USB_CDC_RX_CHUNK_SIZE 32
|
||||
#define USB_CDC_PROTO_RX_BUF_SIZE 128
|
||||
#define USB_CDC_PROTO_RX_FLUSH_DELAY K_MSEC(3)
|
||||
#define USB_CDC_PROTO_RX_BUF_SIZE PROTO_MAX_FRAME_LEN
|
||||
#define USB_CDC_EXPECTED_BAUDRATE 115200U
|
||||
|
||||
enum usb_cdc_business_state {
|
||||
@@ -47,7 +46,6 @@ struct usb_cdc_ctx {
|
||||
struct ring_buf rx_ringbuf;
|
||||
struct ring_buf tx_ringbuf;
|
||||
struct k_work rx_work;
|
||||
struct k_work_delayable rx_flush_work;
|
||||
uint8_t proto_rx_buf[USB_CDC_PROTO_RX_BUF_SIZE];
|
||||
bool usb_active;
|
||||
size_t proto_rx_len;
|
||||
@@ -79,8 +77,6 @@ static struct usb_cdc_ctx ctx = {
|
||||
.proto_rx_len = 0U,
|
||||
};
|
||||
|
||||
#define proto_rx_buf ctx.proto_rx_buf
|
||||
|
||||
static void validate_line_coding(void);
|
||||
|
||||
static const char *usb_cdc_business_state_name(enum usb_cdc_business_state state)
|
||||
@@ -137,7 +133,6 @@ static void disable_uart_io(void)
|
||||
uart_irq_rx_disable(ctx.cdc_dev);
|
||||
uart_irq_tx_disable(ctx.cdc_dev);
|
||||
ctx.proto_rx_len = 0U;
|
||||
k_work_cancel_delayable(&ctx.rx_flush_work);
|
||||
reset_ring_buffers();
|
||||
}
|
||||
|
||||
@@ -280,6 +275,46 @@ static void validate_line_coding(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool try_extract_frame(void)
|
||||
{
|
||||
uint8_t *buf = ctx.proto_rx_buf;
|
||||
size_t frame_len;
|
||||
uint16_t magic;
|
||||
|
||||
if (ctx.proto_rx_len < PROTO_FRAME_HEADER_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
magic = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
|
||||
if (magic != PROTO_FRAME_MAGIC) {
|
||||
LOG_WRN("CDC invalid frame magic 0x%04x", magic);
|
||||
memmove(buf, &buf[1], ctx.proto_rx_len - 1U);
|
||||
ctx.proto_rx_len--;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (buf[2] > PROTO_MAX_PAYLOAD_LEN) {
|
||||
LOG_WRN("CDC invalid frame len:%u", buf[2]);
|
||||
memmove(buf, &buf[1], ctx.proto_rx_len - 1U);
|
||||
ctx.proto_rx_len--;
|
||||
return true;
|
||||
}
|
||||
|
||||
frame_len = PROTO_FRAME_HEADER_SIZE + buf[2];
|
||||
if (ctx.proto_rx_len < frame_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INF("CDC submit framed proto_rx len:%u", (unsigned int)frame_len);
|
||||
(void)submit_proto_rx_event(PROTO_TRANSPORT_USB_CDC, buf, frame_len);
|
||||
|
||||
if (ctx.proto_rx_len > frame_len) {
|
||||
memmove(buf, &buf[frame_len], ctx.proto_rx_len - frame_len);
|
||||
}
|
||||
ctx.proto_rx_len -= frame_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rx_work_handler(struct k_work *work)
|
||||
{
|
||||
uint8_t buffer[USB_CDC_RX_CHUNK_SIZE];
|
||||
@@ -290,47 +325,30 @@ static void rx_work_handler(struct k_work *work)
|
||||
uint32_t len;
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
len = ring_buf_get(&ctx.rx_ringbuf, buffer, sizeof(buffer));
|
||||
len = ring_buf_get(&ctx.rx_ringbuf, buffer, sizeof(buffer));
|
||||
irq_unlock(key);
|
||||
|
||||
if (len == 0U) {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_INF("CDC rx_work pulled %u bytes from RX ring (proto_rx_len:%u)",
|
||||
(unsigned int)len, (unsigned int)ctx.proto_rx_len);
|
||||
|
||||
if ((ctx.proto_rx_len + len) > sizeof(proto_rx_buf)) {
|
||||
LOG_WRN("Drop oversized CDC protobuf message len:%u",
|
||||
if ((ctx.proto_rx_len + len) > sizeof(ctx.proto_rx_buf)) {
|
||||
LOG_WRN("Drop oversized CDC framed data len:%u",
|
||||
(uint32_t)(ctx.proto_rx_len + len));
|
||||
ctx.proto_rx_len = 0U;
|
||||
}
|
||||
|
||||
if (len > 0U) {
|
||||
memcpy(&proto_rx_buf[ctx.proto_rx_len], buffer, len);
|
||||
memcpy(&ctx.proto_rx_buf[ctx.proto_rx_len], buffer, len);
|
||||
ctx.proto_rx_len += len;
|
||||
k_work_reschedule(&ctx.rx_flush_work, USB_CDC_PROTO_RX_FLUSH_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rx_flush_work_handler(struct k_work *work)
|
||||
{
|
||||
ARG_UNUSED(work);
|
||||
|
||||
if ((transport_link_state_get() != PROTO_TRANSPORT_LINK_READY) ||
|
||||
(ctx.proto_rx_len == 0U)) {
|
||||
LOG_INF("CDC rx_flush skipped: link=%s proto_rx_len:%u business:%s",
|
||||
proto_link_state_name(transport_link_state_get()),
|
||||
(unsigned int)ctx.proto_rx_len,
|
||||
usb_cdc_business_state_name(ctx.business));
|
||||
return;
|
||||
while (try_extract_frame()) {
|
||||
}
|
||||
|
||||
LOG_INF("CDC rx_flush submit proto_rx len:%u", (unsigned int)ctx.proto_rx_len);
|
||||
(void)submit_proto_rx_event(PROTO_TRANSPORT_USB_CDC, proto_rx_buf,
|
||||
ctx.proto_rx_len);
|
||||
ctx.proto_rx_len = 0U;
|
||||
}
|
||||
|
||||
static void cdc_interrupt_handler(const struct device *dev, void *user_data)
|
||||
@@ -408,7 +426,6 @@ static int do_init(void)
|
||||
|
||||
reset_ring_buffers();
|
||||
k_work_init(&ctx.rx_work, rx_work_handler);
|
||||
k_work_init_delayable(&ctx.rx_flush_work, rx_flush_work_handler);
|
||||
uart_irq_callback_set(ctx.cdc_dev, cdc_interrupt_handler);
|
||||
ctx.business = USB_CDC_BUS_OFFLINE;
|
||||
ctx.usb_active = false;
|
||||
|
||||
Reference in New Issue
Block a user