Files
blinky/src/usb_cdc_module.c

411 lines
8.7 KiB
C
Raw Normal View History

#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <app_event_manager.h>
#define MODULE usb_cdc_module
#include <caf/events/module_state_event.h>
#include <caf/events/power_event.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/ring_buffer.h>
#include <zephyr/sys/util.h>
#include "usb_cdc_rx_event.h"
#include "usb_cdc_tx_event.h"
#include "usb_function_ready_event.h"
#include "usb_prepare_event.h"
#include "usb_device_module.h"
#include "usb_device_state_event.h"
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_CONTROL_POLL_INTERVAL K_MSEC(100)
#define USB_CDC_EXPECTED_BAUDRATE 115200U
static const struct device *const cdc_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
static uint8_t rx_ring_buffer[USB_CDC_RX_RING_BUF_SIZE];
static uint8_t tx_ring_buffer[USB_CDC_TX_RING_BUF_SIZE];
static struct ring_buf rx_ringbuf;
static struct ring_buf tx_ringbuf;
static struct k_work rx_work;
static struct k_work_delayable control_work;
static bool initialized;
static bool running;
static bool usb_active;
static bool usb_function_prepared;
static bool dtr_ready;
static bool rx_enabled;
static void reset_ring_buffers(void)
{
unsigned int key = irq_lock();
ring_buf_init(&rx_ringbuf, sizeof(rx_ring_buffer), rx_ring_buffer);
ring_buf_init(&tx_ringbuf, sizeof(tx_ring_buffer), tx_ring_buffer);
irq_unlock(key);
}
static void disable_uart_io(void)
{
uart_irq_rx_disable(cdc_dev);
uart_irq_tx_disable(cdc_dev);
rx_enabled = false;
dtr_ready = false;
reset_ring_buffers();
}
static void kick_tx(void)
{
if (!running || !usb_active || !dtr_ready) {
return;
}
uart_irq_tx_enable(cdc_dev);
}
static void validate_line_coding(void)
{
uint32_t baudrate = 0U;
int err;
err = uart_line_ctrl_get(cdc_dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
if (err) {
LOG_WRN("Failed to get CDC baudrate (%d)", err);
} else {
LOG_INF("CDC baudrate %u", baudrate);
if (baudrate != USB_CDC_EXPECTED_BAUDRATE) {
LOG_WRN("Expected CDC baudrate %u, got %u",
USB_CDC_EXPECTED_BAUDRATE, baudrate);
}
}
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
{
struct uart_config cfg;
err = uart_config_get(cdc_dev, &cfg);
if (err) {
LOG_WRN("uart_config_get failed (%d)", err);
} else {
LOG_INF("CDC line coding data:%u stop:%u parity:%u flow:%u",
cfg.data_bits, cfg.stop_bits, cfg.parity,
cfg.flow_ctrl);
if ((cfg.data_bits != UART_CFG_DATA_BITS_8) ||
(cfg.stop_bits != UART_CFG_STOP_BITS_1) ||
(cfg.parity != UART_CFG_PARITY_NONE) ||
(cfg.flow_ctrl != UART_CFG_FLOW_CTRL_NONE)) {
LOG_WRN("Expected CDC line coding 115200 8N1 no flow control");
}
}
}
#endif
}
static void rx_work_handler(struct k_work *work)
{
uint8_t buffer[USB_CDC_RX_CHUNK_SIZE];
ARG_UNUSED(work);
while (true) {
uint32_t len;
unsigned int key = irq_lock();
len = ring_buf_get(&rx_ringbuf, buffer, sizeof(buffer));
irq_unlock(key);
if (len == 0U) {
return;
}
feat(events): 添加事件提交函数到各个头文件中 为多个事件头文件添加了静态内联提交函数,包括: - bat_state_event: 添加submit_bat_state_event函数 - ble_serial_rx_event: 添加submit_ble_serial_rx_event函数 - ble_serial_tx_event: 添加submit_ble_serial_tx_event函数 - cdc_proto_tx_event: 添加submit_cdc_proto_tx_event函数 - datetime_event: 添加submit_datetime_event函数 - encoder_event: 添加submit_encoder_event函数 - function_bitmap_update_event: 添加submit_function_bitmap_update_event函数 - hid_led_event: 添加submit_hid_led_event函数 - hid_report_sent_event: 添加submit_hid_report_sent_event函数 - hid_transport_state_event: 添加submit_hid_transport_state_event函数 - hid_tx_report_event: 添加submit_hid_tx_report_event函数 - key_function_event: 添加submit_key_function_event函数 - keyboard_hid_report_event: 添加submit_keyboard_hid_report_event函数 - led_strip_en_event: 添加submit_led_strip_en_event函数 - mode_switch_event: 添加submit_mode_switch_event函数 - set_protocol_event: 添加submit_set_protocol_event函数 - theme_rgb_update_event: 添加submit_theme_rgb_update_event函数 - time_sync_event: 添加submit_time_sync_event函数 - usb_cdc_rx_event: 添加submit_usb_cdc_rx_event函数 - usb_cdc_tx_event: 添加submit_usb_cdc_tx_event函数 - usb_device_state_event: 添加submit_usb_device_state_event函数 - usb_function_ready_event: 添加submit_usb_function_ready_event函数 - usb_prepare_event: 添加submit_usb_prepare_event函数 这些函数提供了一致的事件提交接口,简化了事件创建和提交过程。
2026-04-14 16:42:04 +08:00
(void)submit_usb_cdc_rx_event(buffer, len);
}
}
static void control_work_handler(struct k_work *work)
{
uint32_t dtr = 0U;
int err;
ARG_UNUSED(work);
if (!running || !usb_active) {
return;
}
err = uart_line_ctrl_get(cdc_dev, UART_LINE_CTRL_DTR, &dtr);
if (err) {
LOG_WRN("Failed to get CDC DTR (%d)", err);
goto reschedule;
}
if (dtr && !dtr_ready) {
dtr_ready = true;
LOG_INF("CDC DTR set");
validate_line_coding();
err = uart_line_ctrl_set(cdc_dev, UART_LINE_CTRL_DCD, 1);
if (err) {
LOG_WRN("Failed to set DCD (%d)", err);
}
err = uart_line_ctrl_set(cdc_dev, UART_LINE_CTRL_DSR, 1);
if (err) {
LOG_WRN("Failed to set DSR (%d)", err);
}
if (!rx_enabled) {
uart_irq_rx_enable(cdc_dev);
rx_enabled = true;
}
kick_tx();
} else if (!dtr && dtr_ready) {
LOG_INF("CDC DTR cleared");
disable_uart_io();
}
reschedule:
k_work_reschedule(&control_work, USB_CDC_CONTROL_POLL_INTERVAL);
}
static void cdc_interrupt_handler(const struct device *dev, void *user_data)
{
ARG_UNUSED(user_data);
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
if (uart_irq_rx_ready(dev)) {
uint8_t buffer[USB_CDC_RX_CHUNK_SIZE];
int recv_len = uart_fifo_read(dev, buffer, sizeof(buffer));
if (recv_len < 0) {
LOG_ERR("Failed to read CDC RX FIFO");
continue;
}
if (recv_len > 0) {
uint32_t written;
unsigned int key = irq_lock();
written = ring_buf_put(&rx_ringbuf, buffer,
(uint32_t)recv_len);
irq_unlock(key);
if (written < (uint32_t)recv_len) {
LOG_WRN("Drop %d CDC RX bytes", recv_len - (int)written);
}
k_work_submit(&rx_work);
}
}
if (uart_irq_tx_ready(dev)) {
uint8_t buffer[USB_CDC_RX_CHUNK_SIZE];
uint32_t len;
int sent_len;
unsigned int key = irq_lock();
len = ring_buf_get(&tx_ringbuf, buffer, sizeof(buffer));
irq_unlock(key);
if (len == 0U) {
uart_irq_tx_disable(dev);
continue;
}
sent_len = uart_fifo_fill(dev, buffer, len);
if (sent_len < 0) {
LOG_ERR("Failed to write CDC TX FIFO");
uart_irq_tx_disable(dev);
} else if ((uint32_t)sent_len < len) {
LOG_WRN("Drop %u CDC TX bytes",
(unsigned int)(len - (uint32_t)sent_len));
}
}
}
}
static int module_init(void)
{
if (!device_is_ready(cdc_dev)) {
LOG_ERR("CDC ACM device not ready");
return -ENODEV;
}
reset_ring_buffers();
k_work_init(&rx_work, rx_work_handler);
k_work_init_delayable(&control_work, control_work_handler);
uart_irq_callback_set(cdc_dev, cdc_interrupt_handler);
usb_function_prepared = false;
return 0;
}
static int module_start(void)
{
if (running) {
return 0;
}
running = true;
if (usb_active) {
k_work_reschedule(&control_work, K_NO_WAIT);
}
return 0;
}
static void module_pause(void)
{
if (!running) {
return;
}
k_work_cancel_delayable(&control_work);
disable_uart_io();
running = false;
}
static bool handle_usb_prepare_event(const struct usb_prepare_event *event)
{
ARG_UNUSED(event);
if (!running || usb_function_prepared) {
return false;
}
usb_function_prepared = true;
feat(events): 添加事件提交函数到各个头文件中 为多个事件头文件添加了静态内联提交函数,包括: - bat_state_event: 添加submit_bat_state_event函数 - ble_serial_rx_event: 添加submit_ble_serial_rx_event函数 - ble_serial_tx_event: 添加submit_ble_serial_tx_event函数 - cdc_proto_tx_event: 添加submit_cdc_proto_tx_event函数 - datetime_event: 添加submit_datetime_event函数 - encoder_event: 添加submit_encoder_event函数 - function_bitmap_update_event: 添加submit_function_bitmap_update_event函数 - hid_led_event: 添加submit_hid_led_event函数 - hid_report_sent_event: 添加submit_hid_report_sent_event函数 - hid_transport_state_event: 添加submit_hid_transport_state_event函数 - hid_tx_report_event: 添加submit_hid_tx_report_event函数 - key_function_event: 添加submit_key_function_event函数 - keyboard_hid_report_event: 添加submit_keyboard_hid_report_event函数 - led_strip_en_event: 添加submit_led_strip_en_event函数 - mode_switch_event: 添加submit_mode_switch_event函数 - set_protocol_event: 添加submit_set_protocol_event函数 - theme_rgb_update_event: 添加submit_theme_rgb_update_event函数 - time_sync_event: 添加submit_time_sync_event函数 - usb_cdc_rx_event: 添加submit_usb_cdc_rx_event函数 - usb_cdc_tx_event: 添加submit_usb_cdc_tx_event函数 - usb_device_state_event: 添加submit_usb_device_state_event函数 - usb_function_ready_event: 添加submit_usb_function_ready_event函数 - usb_prepare_event: 添加submit_usb_prepare_event函数 这些函数提供了一致的事件提交接口,简化了事件创建和提交过程。
2026-04-14 16:42:04 +08:00
submit_usb_function_ready_event(USB_FUNCTION_CDC_ACM);
return false;
}
static bool handle_usb_device_state_event(const struct usb_device_state_event *event)
{
bool new_usb_active = (event->state == USB_DEVICE_STATE_ACTIVE);
if (new_usb_active == usb_active) {
return false;
}
usb_active = new_usb_active;
if (!usb_active) {
k_work_cancel_delayable(&control_work);
disable_uart_io();
} else if (running) {
k_work_reschedule(&control_work, K_NO_WAIT);
}
return false;
}
static bool handle_usb_cdc_tx_event(const struct usb_cdc_tx_event *event)
{
uint32_t written;
unsigned int key;
if (!running || !usb_active || !dtr_ready) {
return false;
}
key = irq_lock();
written = ring_buf_put(&tx_ringbuf, event->dyndata.data,
(uint32_t)event->dyndata.size);
irq_unlock(key);
if (written < event->dyndata.size) {
LOG_WRN("Drop %zu CDC TX bytes", event->dyndata.size - written);
}
if (written > 0U) {
kick_tx();
}
return false;
}
static bool app_event_handler(const struct app_event_header *aeh)
{
if (is_usb_device_state_event(aeh)) {
return handle_usb_device_state_event(cast_usb_device_state_event(aeh));
}
if (is_usb_prepare_event(aeh)) {
return handle_usb_prepare_event(cast_usb_prepare_event(aeh));
}
if (is_usb_cdc_tx_event(aeh)) {
return handle_usb_cdc_tx_event(cast_usb_cdc_tx_event(aeh));
}
if (is_module_state_event(aeh)) {
const struct module_state_event *event = cast_module_state_event(aeh);
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
int err;
if (!initialized) {
err = module_init();
if (err) {
module_set_state(MODULE_STATE_ERROR);
return false;
}
initialized = true;
}
err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
}
return false;
}
if (is_power_down_event(aeh)) {
if (initialized) {
module_pause();
module_set_state(MODULE_STATE_STANDBY);
}
return false;
}
if (is_wake_up_event(aeh)) {
if (initialized) {
int err = module_start();
if (err) {
module_set_state(MODULE_STATE_ERROR);
} else {
module_set_state(MODULE_STATE_READY);
}
}
return false;
}
return false;
}
APP_EVENT_LISTENER(MODULE, app_event_handler);
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
APP_EVENT_SUBSCRIBE(MODULE, usb_prepare_event);
APP_EVENT_SUBSCRIBE(MODULE, usb_device_state_event);
APP_EVENT_SUBSCRIBE(MODULE, usb_cdc_tx_event);
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);