feat(protocol): 添加传输状态事件管理协议会话状态
添加了新的 proto_transport_state_event 事件类型来跟踪协议传输连接状态, 包括链接断开和就绪状态。为 BLE NUS 和 USB CDC 模块实现了状态机管理, 替换原有的简单布尔标志,提供更精确的连接状态跟踪。 - 添加 proto_transport_state_event 事件定义和实现 - 为 BLE NUS 模块引入业务状态机管理 - 为 USB CDC 模块引入业务状态机管理 - 实现协议模块中的会话状态管理 - 移除 protocol_module_reset_transport_state 函数 - 更新 CMakeLists.txt 包含新事件源文件
This commit is contained in:
@@ -55,9 +55,11 @@ target_sources(app PRIVATE
|
||||
src/events/keyboard_hid_report_event.c
|
||||
src/events/mode_switch_event.c
|
||||
src/events/proto_rx_event.c
|
||||
src/events/proto_transport_state_event.c
|
||||
src/events/proto_tx_event.c
|
||||
src/events/set_protocol_event.c
|
||||
src/events/theme_rgb_update_event.c
|
||||
src/events/time_sync_event.c
|
||||
src/events/usb_control_event.c
|
||||
src/events/usb_state_event.c
|
||||
)
|
||||
|
||||
@@ -11,6 +11,11 @@ enum proto_transport {
|
||||
PROTO_TRANSPORT_COUNT,
|
||||
};
|
||||
|
||||
enum proto_transport_link_state {
|
||||
PROTO_TRANSPORT_LINK_DOWN = 0,
|
||||
PROTO_TRANSPORT_LINK_READY,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
36
inc/events/proto_transport_state_event.h
Normal file
36
inc/events/proto_transport_state_event.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BLINKY_PROTO_TRANSPORT_STATE_EVENT_H_
|
||||
#define BLINKY_PROTO_TRANSPORT_STATE_EVENT_H_
|
||||
|
||||
#include <app_event_manager.h>
|
||||
#include <app_event_manager_profiler_tracer.h>
|
||||
|
||||
#include "proto_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct proto_transport_state_event {
|
||||
struct app_event_header header;
|
||||
enum proto_transport transport;
|
||||
enum proto_transport_link_state state;
|
||||
};
|
||||
|
||||
APP_EVENT_TYPE_DECLARE(proto_transport_state_event);
|
||||
|
||||
static inline void submit_proto_transport_state_event(
|
||||
enum proto_transport transport, enum proto_transport_link_state state)
|
||||
{
|
||||
struct proto_transport_state_event *event =
|
||||
new_proto_transport_state_event();
|
||||
|
||||
event->transport = transport;
|
||||
event->state = state;
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BLINKY_PROTO_TRANSPORT_STATE_EVENT_H_ */
|
||||
71
inc/events/usb_control_event.h
Normal file
71
inc/events/usb_control_event.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef BLINKY_USB_CONTROL_EVENT_H_
|
||||
#define BLINKY_USB_CONTROL_EVENT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <app_event_manager.h>
|
||||
#include <app_event_manager_profiler_tracer.h>
|
||||
#include <zephyr/device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum usb_control_event_type {
|
||||
USB_CONTROL_EVENT_CDC_LINE_STATE = 0,
|
||||
USB_CONTROL_EVENT_CDC_LINE_CODING,
|
||||
};
|
||||
|
||||
struct usb_control_event {
|
||||
struct app_event_header header;
|
||||
enum usb_control_event_type type;
|
||||
const struct device *dev;
|
||||
union {
|
||||
struct {
|
||||
bool dtr;
|
||||
} cdc_line_state;
|
||||
struct {
|
||||
uint32_t baudrate;
|
||||
uint8_t data_bits;
|
||||
uint8_t stop_bits;
|
||||
uint8_t parity;
|
||||
uint8_t flow_ctrl;
|
||||
} cdc_line_coding;
|
||||
} data;
|
||||
};
|
||||
|
||||
APP_EVENT_TYPE_DECLARE(usb_control_event);
|
||||
|
||||
static inline void submit_usb_control_cdc_line_state_event(
|
||||
const struct device *dev, bool dtr)
|
||||
{
|
||||
struct usb_control_event *event = new_usb_control_event();
|
||||
|
||||
event->type = USB_CONTROL_EVENT_CDC_LINE_STATE;
|
||||
event->dev = dev;
|
||||
event->data.cdc_line_state.dtr = dtr;
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
static inline void submit_usb_control_cdc_line_coding_event(
|
||||
const struct device *dev, uint32_t baudrate, uint8_t data_bits,
|
||||
uint8_t stop_bits, uint8_t parity, uint8_t flow_ctrl)
|
||||
{
|
||||
struct usb_control_event *event = new_usb_control_event();
|
||||
|
||||
event->type = USB_CONTROL_EVENT_CDC_LINE_CODING;
|
||||
event->dev = dev;
|
||||
event->data.cdc_line_coding.baudrate = baudrate;
|
||||
event->data.cdc_line_coding.data_bits = data_bits;
|
||||
event->data.cdc_line_coding.stop_bits = stop_bits;
|
||||
event->data.cdc_line_coding.parity = parity;
|
||||
event->data.cdc_line_coding.flow_ctrl = flow_ctrl;
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BLINKY_USB_CONTROL_EVENT_H_ */
|
||||
@@ -18,8 +18,6 @@ int protocol_module_process_message(enum proto_transport transport,
|
||||
size_t rsp_payload_buf_size,
|
||||
size_t *rsp_payload_len);
|
||||
|
||||
void protocol_module_reset_transport_state(enum proto_transport transport);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -14,30 +14,122 @@
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "proto_rx_event.h"
|
||||
#include "proto_transport_state_event.h"
|
||||
#include "proto_tx_event.h"
|
||||
#include "protocol_module.h"
|
||||
|
||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
|
||||
static struct bt_conn *active_conn;
|
||||
static bool initialized;
|
||||
static bool running;
|
||||
static bool ble_ready;
|
||||
static bool tx_notify_enabled;
|
||||
enum ble_nus_business_state {
|
||||
BLE_NUS_STACK_OFFLINE = 0,
|
||||
BLE_NUS_IDLE,
|
||||
BLE_NUS_WAIT_NOTIFY,
|
||||
BLE_NUS_SESSION_READY,
|
||||
};
|
||||
|
||||
static void notif_enabled(bool enabled, void *ctx)
|
||||
struct ble_nus_ctx {
|
||||
enum module_state lifecycle;
|
||||
enum ble_nus_business_state business;
|
||||
struct bt_conn *active_conn;
|
||||
};
|
||||
|
||||
static struct ble_nus_ctx ctx = {
|
||||
.lifecycle = MODULE_STATE_OFF,
|
||||
.business = BLE_NUS_STACK_OFFLINE,
|
||||
.active_conn = NULL,
|
||||
};
|
||||
|
||||
static bool lifecycle_is_ready(void)
|
||||
{
|
||||
ARG_UNUSED(ctx);
|
||||
|
||||
tx_notify_enabled = enabled;
|
||||
LOG_INF("BLE NUS TX notify %s", enabled ? "enabled" : "disabled");
|
||||
return ctx.lifecycle == MODULE_STATE_READY;
|
||||
}
|
||||
|
||||
static void received(struct bt_conn *conn, const void *data, uint16_t len, void *ctx)
|
||||
static enum proto_transport_link_state transport_link_state_get(void)
|
||||
{
|
||||
ARG_UNUSED(ctx);
|
||||
return (lifecycle_is_ready() &&
|
||||
(ctx.business == BLE_NUS_SESSION_READY)) ?
|
||||
PROTO_TRANSPORT_LINK_READY :
|
||||
PROTO_TRANSPORT_LINK_DOWN;
|
||||
}
|
||||
|
||||
if (!running || !ble_ready || (conn != active_conn)) {
|
||||
static void state_reconcile(enum module_state old_lifecycle,
|
||||
enum ble_nus_business_state old_business)
|
||||
{
|
||||
enum proto_transport_link_state old_link =
|
||||
((old_lifecycle == MODULE_STATE_READY) &&
|
||||
(old_business == BLE_NUS_SESSION_READY)) ?
|
||||
PROTO_TRANSPORT_LINK_READY :
|
||||
PROTO_TRANSPORT_LINK_DOWN;
|
||||
enum proto_transport_link_state new_link = transport_link_state_get();
|
||||
|
||||
if (old_link != new_link) {
|
||||
submit_proto_transport_state_event(PROTO_TRANSPORT_BLE_NUS,
|
||||
new_link);
|
||||
}
|
||||
}
|
||||
|
||||
static void lifecycle_set(enum module_state new_state)
|
||||
{
|
||||
enum module_state old_lifecycle = ctx.lifecycle;
|
||||
enum ble_nus_business_state old_business = ctx.business;
|
||||
|
||||
if (ctx.lifecycle == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.lifecycle = new_state;
|
||||
state_reconcile(old_lifecycle, old_business);
|
||||
module_set_state(new_state);
|
||||
}
|
||||
|
||||
static void business_state_set(enum ble_nus_business_state new_state)
|
||||
{
|
||||
enum module_state old_lifecycle = ctx.lifecycle;
|
||||
enum ble_nus_business_state old_business = ctx.business;
|
||||
|
||||
if (ctx.business == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.business = new_state;
|
||||
state_reconcile(old_lifecycle, old_business);
|
||||
}
|
||||
|
||||
static void business_state_set_stack_ready(void)
|
||||
{
|
||||
if (ctx.business == BLE_NUS_STACK_OFFLINE) {
|
||||
business_state_set(BLE_NUS_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void business_state_set_from_notify(bool enabled)
|
||||
{
|
||||
if (ctx.business == BLE_NUS_STACK_OFFLINE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.active_conn == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
business_state_set(enabled ? BLE_NUS_SESSION_READY :
|
||||
BLE_NUS_WAIT_NOTIFY);
|
||||
}
|
||||
|
||||
static void notif_enabled(bool enabled, void *ctx_ptr)
|
||||
{
|
||||
ARG_UNUSED(ctx_ptr);
|
||||
|
||||
LOG_INF("BLE NUS TX notify %s", enabled ? "enabled" : "disabled");
|
||||
business_state_set_from_notify(enabled);
|
||||
}
|
||||
|
||||
static void received(struct bt_conn *conn, const void *data, uint16_t len,
|
||||
void *ctx_ptr)
|
||||
{
|
||||
ARG_UNUSED(ctx_ptr);
|
||||
|
||||
if (!lifecycle_is_ready() || (ctx.business == BLE_NUS_STACK_OFFLINE) ||
|
||||
(conn != ctx.active_conn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -51,9 +143,11 @@ static struct bt_nus_cb nus_listener = {
|
||||
|
||||
static void reset_connection_state(void)
|
||||
{
|
||||
active_conn = NULL;
|
||||
tx_notify_enabled = false;
|
||||
protocol_module_reset_transport_state(PROTO_TRANSPORT_BLE_NUS);
|
||||
ctx.active_conn = NULL;
|
||||
|
||||
if (ctx.business != BLE_NUS_STACK_OFFLINE) {
|
||||
business_state_set(BLE_NUS_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
static int module_init(void)
|
||||
@@ -66,45 +160,41 @@ static int module_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
reset_connection_state();
|
||||
ctx = (struct ble_nus_ctx) {
|
||||
.lifecycle = MODULE_STATE_OFF,
|
||||
.business = BLE_NUS_STACK_OFFLINE,
|
||||
.active_conn = NULL,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int module_start(void)
|
||||
static void module_start(void)
|
||||
{
|
||||
if (running) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
running = true;
|
||||
return 0;
|
||||
lifecycle_set(MODULE_STATE_READY);
|
||||
}
|
||||
|
||||
static void module_pause(void)
|
||||
{
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
|
||||
running = false;
|
||||
tx_notify_enabled = false;
|
||||
lifecycle_set(MODULE_STATE_STANDBY);
|
||||
}
|
||||
|
||||
static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
||||
{
|
||||
switch (event->state) {
|
||||
case PEER_STATE_CONNECTED:
|
||||
if (active_conn != NULL) {
|
||||
if (ctx.active_conn != NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
active_conn = event->id;
|
||||
tx_notify_enabled = false;
|
||||
protocol_module_reset_transport_state(PROTO_TRANSPORT_BLE_NUS);
|
||||
ctx.active_conn = event->id;
|
||||
if (ctx.business != BLE_NUS_STACK_OFFLINE) {
|
||||
business_state_set(BLE_NUS_WAIT_NOTIFY);
|
||||
}
|
||||
return false;
|
||||
|
||||
case PEER_STATE_DISCONNECTED:
|
||||
if (active_conn != event->id) {
|
||||
if (ctx.active_conn != event->id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -124,11 +214,13 @@ static bool handle_proto_tx_event(const struct proto_tx_event *event)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!running || !ble_ready || (active_conn == NULL) || !tx_notify_enabled) {
|
||||
if ((transport_link_state_get() != PROTO_TRANSPORT_LINK_READY) ||
|
||||
(ctx.active_conn == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
err = bt_nus_send(active_conn, event->dyndata.data, (uint16_t)event->dyndata.size);
|
||||
err = bt_nus_send(ctx.active_conn, event->dyndata.data,
|
||||
(uint16_t)event->dyndata.size);
|
||||
if (err) {
|
||||
LOG_WRN("bt_nus_send failed (%d)", err);
|
||||
}
|
||||
@@ -147,32 +239,29 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
}
|
||||
|
||||
if (is_module_state_event(aeh)) {
|
||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||
int err;
|
||||
const struct module_state_event *event =
|
||||
cast_module_state_event(aeh);
|
||||
|
||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||
if (!initialized) {
|
||||
err = module_init();
|
||||
if (ctx.lifecycle == MODULE_STATE_OFF) {
|
||||
int err = module_init();
|
||||
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
lifecycle_set(MODULE_STATE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
err = module_start();
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
}
|
||||
module_start();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
|
||||
ble_ready = true;
|
||||
if (running) {
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
business_state_set_stack_ready();
|
||||
|
||||
if (lifecycle_is_ready()) {
|
||||
lifecycle_set(MODULE_STATE_READY);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -182,23 +271,16 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
}
|
||||
|
||||
if (is_power_down_event(aeh)) {
|
||||
if (initialized) {
|
||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
||||
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 if (ble_ready) {
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
}
|
||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
||||
module_start();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
56
src/events/proto_transport_state_event.c
Normal file
56
src/events/proto_transport_state_event.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "proto_transport_state_event.h"
|
||||
|
||||
static const char *transport_name(enum proto_transport transport)
|
||||
{
|
||||
switch (transport) {
|
||||
case PROTO_TRANSPORT_USB_CDC:
|
||||
return "usb_cdc";
|
||||
case PROTO_TRANSPORT_BLE_NUS:
|
||||
return "ble_nus";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *state_name(enum proto_transport_link_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case PROTO_TRANSPORT_LINK_DOWN:
|
||||
return "down";
|
||||
case PROTO_TRANSPORT_LINK_READY:
|
||||
return "ready";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static void log_proto_transport_state_event(const struct app_event_header *aeh)
|
||||
{
|
||||
const struct proto_transport_state_event *event =
|
||||
cast_proto_transport_state_event(aeh);
|
||||
|
||||
APP_EVENT_MANAGER_LOG(aeh, "transport:%s state:%s",
|
||||
transport_name(event->transport),
|
||||
state_name(event->state));
|
||||
}
|
||||
|
||||
static void profile_proto_transport_state_event(struct log_event_buf *buf,
|
||||
const struct app_event_header *aeh)
|
||||
{
|
||||
const struct proto_transport_state_event *event =
|
||||
cast_proto_transport_state_event(aeh);
|
||||
|
||||
nrf_profiler_log_encode_uint8(buf, event->transport);
|
||||
nrf_profiler_log_encode_uint8(buf, event->state);
|
||||
}
|
||||
|
||||
APP_EVENT_INFO_DEFINE(proto_transport_state_event,
|
||||
ENCODE(NRF_PROFILER_ARG_U8, NRF_PROFILER_ARG_U8),
|
||||
ENCODE("transport", "state"),
|
||||
profile_proto_transport_state_event);
|
||||
|
||||
APP_EVENT_TYPE_DEFINE(proto_transport_state_event,
|
||||
log_proto_transport_state_event,
|
||||
&proto_transport_state_event_info,
|
||||
APP_EVENT_FLAGS_CREATE(
|
||||
APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE));
|
||||
82
src/events/usb_control_event.c
Normal file
82
src/events/usb_control_event.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "usb_control_event.h"
|
||||
|
||||
static const char *control_event_name(enum usb_control_event_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case USB_CONTROL_EVENT_CDC_LINE_STATE:
|
||||
return "cdc_line_state";
|
||||
case USB_CONTROL_EVENT_CDC_LINE_CODING:
|
||||
return "cdc_line_coding";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static void log_usb_control_event(const struct app_event_header *aeh)
|
||||
{
|
||||
const struct usb_control_event *event = cast_usb_control_event(aeh);
|
||||
|
||||
switch (event->type) {
|
||||
case USB_CONTROL_EVENT_CDC_LINE_STATE:
|
||||
APP_EVENT_MANAGER_LOG(aeh, "type:%s dtr:%u",
|
||||
control_event_name(event->type),
|
||||
event->data.cdc_line_state.dtr);
|
||||
break;
|
||||
|
||||
case USB_CONTROL_EVENT_CDC_LINE_CODING:
|
||||
APP_EVENT_MANAGER_LOG(aeh,
|
||||
"type:%s baud:%u data:%u stop:%u parity:%u flow:%u",
|
||||
control_event_name(event->type),
|
||||
event->data.cdc_line_coding.baudrate,
|
||||
event->data.cdc_line_coding.data_bits,
|
||||
event->data.cdc_line_coding.stop_bits,
|
||||
event->data.cdc_line_coding.parity,
|
||||
event->data.cdc_line_coding.flow_ctrl);
|
||||
break;
|
||||
|
||||
default:
|
||||
APP_EVENT_MANAGER_LOG(aeh, "type:%s",
|
||||
control_event_name(event->type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void profile_usb_control_event(struct log_event_buf *buf,
|
||||
const struct app_event_header *aeh)
|
||||
{
|
||||
const struct usb_control_event *event = cast_usb_control_event(aeh);
|
||||
|
||||
nrf_profiler_log_encode_uint8(buf, event->type);
|
||||
switch (event->type) {
|
||||
case USB_CONTROL_EVENT_CDC_LINE_STATE:
|
||||
nrf_profiler_log_encode_uint8(buf, event->data.cdc_line_state.dtr);
|
||||
break;
|
||||
|
||||
case USB_CONTROL_EVENT_CDC_LINE_CODING:
|
||||
nrf_profiler_log_encode_uint32(buf, event->data.cdc_line_coding.baudrate);
|
||||
nrf_profiler_log_encode_uint8(buf, event->data.cdc_line_coding.data_bits);
|
||||
nrf_profiler_log_encode_uint8(buf, event->data.cdc_line_coding.stop_bits);
|
||||
nrf_profiler_log_encode_uint8(buf, event->data.cdc_line_coding.parity);
|
||||
nrf_profiler_log_encode_uint8(buf, event->data.cdc_line_coding.flow_ctrl);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
APP_EVENT_INFO_DEFINE(usb_control_event,
|
||||
ENCODE(NRF_PROFILER_ARG_U8,
|
||||
NRF_PROFILER_ARG_U32,
|
||||
NRF_PROFILER_ARG_U8,
|
||||
NRF_PROFILER_ARG_U8,
|
||||
NRF_PROFILER_ARG_U8,
|
||||
NRF_PROFILER_ARG_U8),
|
||||
ENCODE("type", "baud_or_zero", "arg1", "arg2", "arg3", "arg4"),
|
||||
profile_usb_control_event);
|
||||
|
||||
APP_EVENT_TYPE_DEFINE(usb_control_event,
|
||||
log_usb_control_event,
|
||||
&usb_control_event_info,
|
||||
APP_EVENT_FLAGS_CREATE(
|
||||
APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE));
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "function_bitmap_update_event.h"
|
||||
#include "hid_led_event.h"
|
||||
#include "proto_rx_event.h"
|
||||
#include "proto_transport_state_event.h"
|
||||
#include "proto_tx_event.h"
|
||||
#include "protocol_module.h"
|
||||
#include "theme_rgb_update_event.h"
|
||||
@@ -39,7 +40,14 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
|
||||
static bool initialized;
|
||||
static bool running;
|
||||
static bool hello_done[PROTO_TRANSPORT_COUNT];
|
||||
|
||||
enum proto_session_state {
|
||||
PROTO_SESSION_DOWN = 0,
|
||||
PROTO_SESSION_WAIT_HELLO,
|
||||
PROTO_SESSION_ACTIVE,
|
||||
};
|
||||
|
||||
static enum proto_session_state session_state[PROTO_TRANSPORT_COUNT];
|
||||
|
||||
static int decode_body(const uint8_t *payload, size_t payload_len,
|
||||
CdcPacketBody *body)
|
||||
@@ -151,8 +159,8 @@ static int encode_function_bitmap_state(const uint8_t *bitmap, uint8_t *payload,
|
||||
|
||||
static int module_init(void)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(hello_done); i++) {
|
||||
hello_done[i] = false;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
|
||||
session_state[i] = PROTO_SESSION_DOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -174,22 +182,13 @@ static void module_pause(void)
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(hello_done); i++) {
|
||||
hello_done[i] = false;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(session_state); i++) {
|
||||
session_state[i] = PROTO_SESSION_DOWN;
|
||||
}
|
||||
|
||||
running = false;
|
||||
}
|
||||
|
||||
void protocol_module_reset_transport_state(enum proto_transport transport)
|
||||
{
|
||||
if (transport >= PROTO_TRANSPORT_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
hello_done[transport] = false;
|
||||
}
|
||||
|
||||
int protocol_module_process_message(enum proto_transport transport,
|
||||
const uint8_t *req_payload,
|
||||
size_t req_payload_len,
|
||||
@@ -216,6 +215,10 @@ int protocol_module_process_message(enum proto_transport transport,
|
||||
|
||||
switch (body.which_body) {
|
||||
case CdcPacketBody_hello_req_tag:
|
||||
if (session_state[transport] == PROTO_SESSION_DOWN) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
LOG_INF("HelloReq transport:%u protocol_version:%u",
|
||||
transport, body.body.hello_req.protocol_version);
|
||||
|
||||
@@ -224,11 +227,11 @@ int protocol_module_process_message(enum proto_transport transport,
|
||||
body.body.hello_req.protocol_version);
|
||||
}
|
||||
|
||||
hello_done[transport] = true;
|
||||
session_state[transport] = PROTO_SESSION_ACTIVE;
|
||||
return encode_hello_rsp(rsp_payload, rsp_payload_buf_size, rsp_payload_len);
|
||||
|
||||
case CdcPacketBody_bitmap_tag:
|
||||
if (!hello_done[transport]) {
|
||||
if (session_state[transport] != PROTO_SESSION_ACTIVE) {
|
||||
return encode_error(CdcPacketBody_bitmap_tag,
|
||||
ErrorCode_ERROR_CODE_NOT_READY,
|
||||
rsp_payload, rsp_payload_buf_size,
|
||||
@@ -255,7 +258,7 @@ int protocol_module_process_message(enum proto_transport transport,
|
||||
rsp_payload_buf_size, rsp_payload_len);
|
||||
|
||||
case CdcPacketBody_time_sync_tag:
|
||||
if (!hello_done[transport]) {
|
||||
if (session_state[transport] != PROTO_SESSION_ACTIVE) {
|
||||
return encode_error(CdcPacketBody_time_sync_tag,
|
||||
ErrorCode_ERROR_CODE_NOT_READY,
|
||||
rsp_payload, rsp_payload_buf_size,
|
||||
@@ -278,7 +281,7 @@ int protocol_module_process_message(enum proto_transport transport,
|
||||
rsp_payload_buf_size, rsp_payload_len);
|
||||
|
||||
case CdcPacketBody_theme_rgb_tag:
|
||||
if (!hello_done[transport]) {
|
||||
if (session_state[transport] != PROTO_SESSION_ACTIVE) {
|
||||
return encode_error(CdcPacketBody_theme_rgb_tag,
|
||||
ErrorCode_ERROR_CODE_NOT_READY,
|
||||
rsp_payload, rsp_payload_buf_size,
|
||||
@@ -340,6 +343,29 @@ static bool handle_proto_rx_event(const struct proto_rx_event *event)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_proto_transport_state_event(
|
||||
const struct proto_transport_state_event *event)
|
||||
{
|
||||
if (event->transport >= PROTO_TRANSPORT_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event->state) {
|
||||
case PROTO_TRANSPORT_LINK_DOWN:
|
||||
session_state[event->transport] = PROTO_SESSION_DOWN;
|
||||
break;
|
||||
|
||||
case PROTO_TRANSPORT_LINK_READY:
|
||||
session_state[event->transport] = PROTO_SESSION_WAIT_HELLO;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_function_bitmap_state_event(
|
||||
const struct function_bitmap_state_event *event)
|
||||
{
|
||||
@@ -353,7 +379,7 @@ static bool handle_function_bitmap_state_event(
|
||||
|
||||
for (enum proto_transport transport = 0; transport < PROTO_TRANSPORT_COUNT;
|
||||
transport++) {
|
||||
if (!hello_done[transport]) {
|
||||
if (session_state[transport] != PROTO_SESSION_ACTIVE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -388,7 +414,7 @@ static bool handle_hid_led_event(const struct hid_led_event *event)
|
||||
PROTO_TRANSPORT_USB_CDC :
|
||||
PROTO_TRANSPORT_BLE_NUS;
|
||||
|
||||
if (!hello_done[transport]) {
|
||||
if (session_state[transport] != PROTO_SESSION_ACTIVE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -412,6 +438,11 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
return handle_proto_rx_event(cast_proto_rx_event(aeh));
|
||||
}
|
||||
|
||||
if (is_proto_transport_state_event(aeh)) {
|
||||
return handle_proto_transport_state_event(
|
||||
cast_proto_transport_state_event(aeh));
|
||||
}
|
||||
|
||||
if (is_function_bitmap_state_event(aeh)) {
|
||||
return handle_function_bitmap_state_event(
|
||||
cast_function_bitmap_state_event(aeh));
|
||||
@@ -480,5 +511,6 @@ APP_EVENT_SUBSCRIBE(MODULE, function_bitmap_state_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, hid_led_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, proto_rx_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, proto_transport_state_event);
|
||||
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include "proto_rx_event.h"
|
||||
#include "proto_transport_state_event.h"
|
||||
#include "proto_tx_event.h"
|
||||
#include "protocol_module.h"
|
||||
#include "usb_control_event.h"
|
||||
#include "usb_state_event.h"
|
||||
|
||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
@@ -27,10 +28,22 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
#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_CONTROL_POLL_INTERVAL K_MSEC(100)
|
||||
#define USB_CDC_PROTO_RX_FLUSH_DELAY K_MSEC(3)
|
||||
#define USB_CDC_EXPECTED_BAUDRATE 115200U
|
||||
|
||||
enum usb_cdc_business_state {
|
||||
USB_CDC_BUS_OFFLINE = 0,
|
||||
USB_CDC_WAIT_DTR,
|
||||
USB_CDC_SESSION_READY,
|
||||
};
|
||||
|
||||
struct usb_cdc_ctx {
|
||||
enum module_state lifecycle;
|
||||
enum usb_cdc_business_state business;
|
||||
bool usb_active;
|
||||
size_t proto_rx_len;
|
||||
};
|
||||
|
||||
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];
|
||||
@@ -38,15 +51,37 @@ 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 struct k_work_delayable rx_flush_work;
|
||||
static bool initialized;
|
||||
static bool running;
|
||||
static bool usb_active;
|
||||
static bool dtr_ready;
|
||||
static bool rx_enabled;
|
||||
static uint8_t proto_rx_buf[USB_CDC_PROTO_RX_BUF_SIZE];
|
||||
static size_t proto_rx_len;
|
||||
static struct usb_cdc_ctx ctx = {
|
||||
.lifecycle = MODULE_STATE_OFF,
|
||||
.business = USB_CDC_BUS_OFFLINE,
|
||||
.usb_active = false,
|
||||
.proto_rx_len = 0U,
|
||||
};
|
||||
|
||||
static void validate_line_coding(void);
|
||||
|
||||
static bool lifecycle_is_ready(void)
|
||||
{
|
||||
return ctx.lifecycle == MODULE_STATE_READY;
|
||||
}
|
||||
|
||||
static enum proto_transport_link_state transport_link_state_get(void)
|
||||
{
|
||||
return (lifecycle_is_ready() &&
|
||||
(ctx.business == USB_CDC_SESSION_READY)) ?
|
||||
PROTO_TRANSPORT_LINK_READY :
|
||||
PROTO_TRANSPORT_LINK_DOWN;
|
||||
}
|
||||
|
||||
static bool control_poll_needed(enum module_state lifecycle,
|
||||
enum usb_cdc_business_state business)
|
||||
{
|
||||
ARG_UNUSED(lifecycle);
|
||||
ARG_UNUSED(business);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void reset_ring_buffers(void)
|
||||
{
|
||||
@@ -62,16 +97,98 @@ static void disable_uart_io(void)
|
||||
{
|
||||
uart_irq_rx_disable(cdc_dev);
|
||||
uart_irq_tx_disable(cdc_dev);
|
||||
rx_enabled = false;
|
||||
dtr_ready = false;
|
||||
proto_rx_len = 0U;
|
||||
ctx.proto_rx_len = 0U;
|
||||
k_work_cancel_delayable(&rx_flush_work);
|
||||
reset_ring_buffers();
|
||||
}
|
||||
|
||||
static void state_reconcile(enum module_state old_lifecycle,
|
||||
enum usb_cdc_business_state old_business)
|
||||
{
|
||||
enum proto_transport_link_state old_link =
|
||||
((old_lifecycle == MODULE_STATE_READY) &&
|
||||
(old_business == USB_CDC_SESSION_READY)) ?
|
||||
PROTO_TRANSPORT_LINK_READY :
|
||||
PROTO_TRANSPORT_LINK_DOWN;
|
||||
enum proto_transport_link_state new_link = transport_link_state_get();
|
||||
|
||||
if ((old_lifecycle == MODULE_STATE_READY) &&
|
||||
(old_business == USB_CDC_SESSION_READY) &&
|
||||
(new_link == PROTO_TRANSPORT_LINK_DOWN)) {
|
||||
disable_uart_io();
|
||||
}
|
||||
|
||||
if ((old_link == PROTO_TRANSPORT_LINK_DOWN) &&
|
||||
(new_link == PROTO_TRANSPORT_LINK_READY)) {
|
||||
int err;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uart_irq_rx_enable(cdc_dev);
|
||||
}
|
||||
|
||||
if (old_link != new_link) {
|
||||
submit_proto_transport_state_event(PROTO_TRANSPORT_USB_CDC,
|
||||
new_link);
|
||||
}
|
||||
}
|
||||
|
||||
static void lifecycle_set(enum module_state new_state)
|
||||
{
|
||||
enum module_state old_lifecycle = ctx.lifecycle;
|
||||
enum usb_cdc_business_state old_business = ctx.business;
|
||||
|
||||
if (ctx.lifecycle == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.lifecycle = new_state;
|
||||
state_reconcile(old_lifecycle, old_business);
|
||||
module_set_state(new_state);
|
||||
}
|
||||
|
||||
static void business_state_set(enum usb_cdc_business_state new_state)
|
||||
{
|
||||
enum module_state old_lifecycle = ctx.lifecycle;
|
||||
enum usb_cdc_business_state old_business = ctx.business;
|
||||
|
||||
if (ctx.business == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.business = new_state;
|
||||
state_reconcile(old_lifecycle, old_business);
|
||||
}
|
||||
|
||||
static void business_state_sync_from_usb(void)
|
||||
{
|
||||
if (!ctx.usb_active) {
|
||||
business_state_set(USB_CDC_BUS_OFFLINE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lifecycle_is_ready()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.business == USB_CDC_BUS_OFFLINE) {
|
||||
business_state_set(USB_CDC_WAIT_DTR);
|
||||
}
|
||||
}
|
||||
|
||||
static void kick_tx(void)
|
||||
{
|
||||
if (!running || !usb_active || !dtr_ready) {
|
||||
if (transport_link_state_get() != PROTO_TRANSPORT_LINK_READY) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -133,15 +250,15 @@ static void rx_work_handler(struct k_work *work)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((proto_rx_len + len) > sizeof(proto_rx_buf)) {
|
||||
if ((ctx.proto_rx_len + len) > sizeof(proto_rx_buf)) {
|
||||
LOG_WRN("Drop oversized CDC protobuf message len:%u",
|
||||
(uint32_t)(proto_rx_len + len));
|
||||
proto_rx_len = 0U;
|
||||
(uint32_t)(ctx.proto_rx_len + len));
|
||||
ctx.proto_rx_len = 0U;
|
||||
}
|
||||
|
||||
if (len > 0U) {
|
||||
memcpy(&proto_rx_buf[proto_rx_len], buffer, len);
|
||||
proto_rx_len += len;
|
||||
memcpy(&proto_rx_buf[ctx.proto_rx_len], buffer, len);
|
||||
ctx.proto_rx_len += len;
|
||||
k_work_reschedule(&rx_flush_work, USB_CDC_PROTO_RX_FLUSH_DELAY);
|
||||
}
|
||||
}
|
||||
@@ -151,59 +268,14 @@ static void rx_flush_work_handler(struct k_work *work)
|
||||
{
|
||||
ARG_UNUSED(work);
|
||||
|
||||
if (!running || !usb_active || !dtr_ready || (proto_rx_len == 0U)) {
|
||||
if ((transport_link_state_get() != PROTO_TRANSPORT_LINK_READY) ||
|
||||
(ctx.proto_rx_len == 0U)) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)submit_proto_rx_event(PROTO_TRANSPORT_USB_CDC, proto_rx_buf, proto_rx_len);
|
||||
proto_rx_len = 0U;
|
||||
}
|
||||
|
||||
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);
|
||||
(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)
|
||||
@@ -229,7 +301,8 @@ static void cdc_interrupt_handler(const struct device *dev, void *user_data)
|
||||
irq_unlock(key);
|
||||
|
||||
if (written < (uint32_t)recv_len) {
|
||||
LOG_WRN("Drop %d CDC RX bytes", recv_len - (int)written);
|
||||
LOG_WRN("Drop %d CDC RX bytes",
|
||||
recv_len - (int)written);
|
||||
}
|
||||
|
||||
k_work_submit(&rx_work);
|
||||
@@ -271,61 +344,97 @@ static int module_init(void)
|
||||
|
||||
reset_ring_buffers();
|
||||
k_work_init(&rx_work, rx_work_handler);
|
||||
k_work_init_delayable(&control_work, control_work_handler);
|
||||
k_work_init_delayable(&rx_flush_work, rx_flush_work_handler);
|
||||
uart_irq_callback_set(cdc_dev, cdc_interrupt_handler);
|
||||
proto_rx_len = 0U;
|
||||
ctx = (struct usb_cdc_ctx) {
|
||||
.lifecycle = MODULE_STATE_OFF,
|
||||
.business = USB_CDC_BUS_OFFLINE,
|
||||
.usb_active = false,
|
||||
.proto_rx_len = 0U,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int module_start(void)
|
||||
static void module_start(void)
|
||||
{
|
||||
if (running) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
running = true;
|
||||
if (usb_active) {
|
||||
k_work_reschedule(&control_work, K_NO_WAIT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
lifecycle_set(MODULE_STATE_READY);
|
||||
business_state_sync_from_usb();
|
||||
}
|
||||
|
||||
static void module_pause(void)
|
||||
{
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
|
||||
k_work_cancel_delayable(&control_work);
|
||||
k_work_cancel_delayable(&rx_flush_work);
|
||||
disable_uart_io();
|
||||
running = false;
|
||||
business_state_set(USB_CDC_BUS_OFFLINE);
|
||||
lifecycle_set(MODULE_STATE_STANDBY);
|
||||
}
|
||||
|
||||
static bool handle_usb_state_event(const struct usb_state_event *event)
|
||||
{
|
||||
bool new_usb_active = (event->state == USB_STATE_ACTIVE);
|
||||
|
||||
if (new_usb_active == usb_active) {
|
||||
if (new_usb_active == ctx.usb_active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_active = new_usb_active;
|
||||
|
||||
if (!usb_active) {
|
||||
k_work_cancel_delayable(&control_work);
|
||||
k_work_cancel_delayable(&rx_flush_work);
|
||||
protocol_module_reset_transport_state(PROTO_TRANSPORT_USB_CDC);
|
||||
disable_uart_io();
|
||||
} else if (running) {
|
||||
k_work_reschedule(&control_work, K_NO_WAIT);
|
||||
}
|
||||
ctx.usb_active = new_usb_active;
|
||||
business_state_sync_from_usb();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_usb_control_event(const struct usb_control_event *event)
|
||||
{
|
||||
if (event->dev != cdc_dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event->type) {
|
||||
case USB_CONTROL_EVENT_CDC_LINE_STATE:
|
||||
if (!ctx.usb_active || !lifecycle_is_ready()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event->data.cdc_line_state.dtr) {
|
||||
LOG_INF("CDC DTR set");
|
||||
business_state_set(USB_CDC_SESSION_READY);
|
||||
kick_tx();
|
||||
} else {
|
||||
LOG_INF("CDC DTR cleared");
|
||||
business_state_set(USB_CDC_WAIT_DTR);
|
||||
}
|
||||
return false;
|
||||
|
||||
case USB_CONTROL_EVENT_CDC_LINE_CODING:
|
||||
if (event->data.cdc_line_coding.baudrate != 0U) {
|
||||
LOG_INF("CDC baudrate %u",
|
||||
event->data.cdc_line_coding.baudrate);
|
||||
if (event->data.cdc_line_coding.baudrate !=
|
||||
USB_CDC_EXPECTED_BAUDRATE) {
|
||||
LOG_WRN("Expected CDC baudrate %u, got %u",
|
||||
USB_CDC_EXPECTED_BAUDRATE,
|
||||
event->data.cdc_line_coding.baudrate);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
||||
if ((event->data.cdc_line_coding.data_bits != 0U) ||
|
||||
(event->data.cdc_line_coding.stop_bits != 0U) ||
|
||||
(event->data.cdc_line_coding.parity != 0U) ||
|
||||
(event->data.cdc_line_coding.flow_ctrl != 0U)) {
|
||||
LOG_INF("CDC line coding data:%u stop:%u parity:%u flow:%u",
|
||||
event->data.cdc_line_coding.data_bits,
|
||||
event->data.cdc_line_coding.stop_bits,
|
||||
event->data.cdc_line_coding.parity,
|
||||
event->data.cdc_line_coding.flow_ctrl);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool handle_proto_tx_event(const struct proto_tx_event *event)
|
||||
{
|
||||
uint32_t written;
|
||||
@@ -335,7 +444,7 @@ static bool handle_proto_tx_event(const struct proto_tx_event *event)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!running || !usb_active || !dtr_ready) {
|
||||
if (transport_link_state_get() != PROTO_TRANSPORT_LINK_READY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -365,51 +474,41 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
return handle_proto_tx_event(cast_proto_tx_event(aeh));
|
||||
}
|
||||
|
||||
if (is_usb_control_event(aeh)) {
|
||||
return handle_usb_control_event(cast_usb_control_event(aeh));
|
||||
}
|
||||
|
||||
if (is_module_state_event(aeh)) {
|
||||
const struct module_state_event *event = cast_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 (ctx.lifecycle == MODULE_STATE_OFF) {
|
||||
int err = module_init();
|
||||
|
||||
if (!initialized) {
|
||||
err = module_init();
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
lifecycle_set(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);
|
||||
}
|
||||
module_start();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_power_down_event(aeh)) {
|
||||
if (initialized) {
|
||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
||||
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);
|
||||
}
|
||||
if (ctx.lifecycle != MODULE_STATE_OFF) {
|
||||
module_start();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -421,6 +520,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, proto_tx_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, usb_control_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, usb_state_event);
|
||||
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
#include <caf/events/module_suspend_event.h>
|
||||
#include <caf/events/power_event.h>
|
||||
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/usb/usbd.h>
|
||||
|
||||
#include <caf/events/power_manager_event.h>
|
||||
|
||||
#include "usb_function_hook.h"
|
||||
#include "usb_control_event.h"
|
||||
#include "usb_state_event.h"
|
||||
|
||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
@@ -147,6 +149,54 @@ static void usbd_msg_cb(struct usbd_context *const usbd_ctx,
|
||||
{
|
||||
ARG_UNUSED(usbd_ctx);
|
||||
|
||||
if (msg->type == USBD_MSG_CDC_ACM_CONTROL_LINE_STATE) {
|
||||
uint32_t dtr = 0U;
|
||||
int err = uart_line_ctrl_get(msg->dev, UART_LINE_CTRL_DTR, &dtr);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Failed to get CDC DTR (%d)", err);
|
||||
} else {
|
||||
submit_usb_control_cdc_line_state_event(msg->dev, dtr != 0U);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->type == USBD_MSG_CDC_ACM_LINE_CODING) {
|
||||
uint32_t baudrate = 0U;
|
||||
uint8_t data_bits = 0U;
|
||||
uint8_t stop_bits = 0U;
|
||||
uint8_t parity = 0U;
|
||||
uint8_t flow_ctrl = 0U;
|
||||
int err;
|
||||
|
||||
err = uart_line_ctrl_get(msg->dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to get CDC baudrate (%d)", err);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
||||
{
|
||||
struct uart_config cfg;
|
||||
|
||||
err = uart_config_get(msg->dev, &cfg);
|
||||
if (err) {
|
||||
LOG_WRN("uart_config_get failed (%d)", err);
|
||||
} else {
|
||||
data_bits = (uint8_t)cfg.data_bits;
|
||||
stop_bits = (uint8_t)cfg.stop_bits;
|
||||
parity = (uint8_t)cfg.parity;
|
||||
flow_ctrl = (uint8_t)cfg.flow_ctrl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
submit_usb_control_cdc_line_coding_event(msg->dev, baudrate,
|
||||
data_bits, stop_bits,
|
||||
parity, flow_ctrl);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg->type) {
|
||||
case USBD_MSG_VBUS_READY:
|
||||
update_power_manager_restriction(true);
|
||||
|
||||
Reference in New Issue
Block a user