diff --git a/CMakeLists.txt b/CMakeLists.txt index e24e090..ec06ef8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ target_sources(app PRIVATE src/ble_adv_uuid16.c src/ble_bas_module.c src/ble_hid_module.c - src/ble_serial_module.c + src/ble_nus_module.c src/display_module.c src/encoder_module.c src/hid_flowctrl_module.c @@ -35,15 +35,11 @@ target_sources(app PRIVATE src/led_strip_module.c src/time_sync_module.c src/ui/ui_main.c - src/cdc_wrapper_module.c src/protocol_module.c src/usb_cdc_module.c src/usb_device_module.c src/usb_hid_module.c src/events/bat_state_event.c - src/events/ble_serial_rx_event.c - src/events/ble_serial_tx_event.c - src/events/cdc_proto_tx_event.c src/events/datetime_event.c src/events/encoder_event.c src/events/function_bitmap_update_event.c @@ -56,10 +52,10 @@ target_sources(app PRIVATE src/mode_switch_module.c src/events/keyboard_hid_report_event.c src/events/mode_switch_event.c + src/events/proto_rx_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_cdc_rx_event.c - src/events/usb_cdc_tx_event.c src/events/usb_state_event.c ) diff --git a/inc/cdc_wrapper_module.h b/inc/cdc_wrapper_module.h deleted file mode 100644 index f024ebe..0000000 --- a/inc/cdc_wrapper_module.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef BLINKY_CDC_WRAPPER_MODULE_H_ -#define BLINKY_CDC_WRAPPER_MODULE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* BLINKY_CDC_WRAPPER_MODULE_H_ */ diff --git a/inc/events/ble_serial_rx_event.h b/inc/events/ble_serial_rx_event.h deleted file mode 100644 index 3b2204d..0000000 --- a/inc/events/ble_serial_rx_event.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef BLINKY_BLE_SERIAL_RX_EVENT_H_ -#define BLINKY_BLE_SERIAL_RX_EVENT_H_ - -#include -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct ble_serial_rx_event { - struct app_event_header header; - struct event_dyndata dyndata; -}; - -APP_EVENT_TYPE_DYNDATA_DECLARE(ble_serial_rx_event); - -static inline int submit_ble_serial_rx_event(const uint8_t *data, size_t len) -{ - struct ble_serial_rx_event *event; - - if ((data == NULL) && (len > 0U)) { - return -EINVAL; - } - - event = new_ble_serial_rx_event(len); - if (len > 0U) { - memcpy(event->dyndata.data, data, len); - } - - APP_EVENT_SUBMIT(event); - return 0; -} - -#ifdef __cplusplus -} -#endif - -#endif /* BLINKY_BLE_SERIAL_RX_EVENT_H_ */ diff --git a/inc/events/ble_serial_tx_event.h b/inc/events/ble_serial_tx_event.h deleted file mode 100644 index 93cac48..0000000 --- a/inc/events/ble_serial_tx_event.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef BLINKY_BLE_SERIAL_TX_EVENT_H_ -#define BLINKY_BLE_SERIAL_TX_EVENT_H_ - -#include -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct ble_serial_tx_event { - struct app_event_header header; - struct event_dyndata dyndata; -}; - -APP_EVENT_TYPE_DYNDATA_DECLARE(ble_serial_tx_event); - -static inline int submit_ble_serial_tx_event(const uint8_t *data, size_t len) -{ - struct ble_serial_tx_event *event; - - if ((data == NULL) && (len > 0U)) { - return -EINVAL; - } - - event = new_ble_serial_tx_event(len); - if (len > 0U) { - memcpy(event->dyndata.data, data, len); - } - - APP_EVENT_SUBMIT(event); - return 0; -} - -#ifdef __cplusplus -} -#endif - -#endif /* BLINKY_BLE_SERIAL_TX_EVENT_H_ */ diff --git a/inc/events/cdc_proto_tx_event.h b/inc/events/cdc_proto_tx_event.h deleted file mode 100644 index 68b7d14..0000000 --- a/inc/events/cdc_proto_tx_event.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef BLINKY_CDC_PROTO_TX_EVENT_H_ -#define BLINKY_CDC_PROTO_TX_EVENT_H_ - -#include -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct cdc_proto_tx_event { - struct app_event_header header; - uint8_t type; - struct event_dyndata dyndata; -}; - -APP_EVENT_TYPE_DYNDATA_DECLARE(cdc_proto_tx_event); - -static inline int submit_cdc_proto_tx_event(uint8_t type, const uint8_t *payload, - size_t payload_len) -{ - struct cdc_proto_tx_event *event; - - if ((payload == NULL) && (payload_len > 0U)) { - return -EINVAL; - } - - event = new_cdc_proto_tx_event(payload_len); - event->type = type; - if (payload_len > 0U) { - memcpy(event->dyndata.data, payload, payload_len); - } - - APP_EVENT_SUBMIT(event); - return 0; -} - -#ifdef __cplusplus -} -#endif - -#endif /* BLINKY_CDC_PROTO_TX_EVENT_H_ */ diff --git a/inc/events/proto_common.h b/inc/events/proto_common.h new file mode 100644 index 0000000..479e851 --- /dev/null +++ b/inc/events/proto_common.h @@ -0,0 +1,18 @@ +#ifndef BLINKY_PROTO_COMMON_H_ +#define BLINKY_PROTO_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum proto_transport { + PROTO_TRANSPORT_USB_CDC = 0, + PROTO_TRANSPORT_BLE_NUS, + PROTO_TRANSPORT_COUNT, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* BLINKY_PROTO_COMMON_H_ */ diff --git a/inc/events/proto_rx_event.h b/inc/events/proto_rx_event.h new file mode 100644 index 0000000..394674f --- /dev/null +++ b/inc/events/proto_rx_event.h @@ -0,0 +1,50 @@ +#ifndef BLINKY_PROTO_RX_EVENT_H_ +#define BLINKY_PROTO_RX_EVENT_H_ + +#include +#include +#include + +#include +#include + +#include "proto_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct proto_rx_event { + struct app_event_header header; + enum proto_transport transport; + struct event_dyndata dyndata; +}; + +APP_EVENT_TYPE_DYNDATA_DECLARE(proto_rx_event); + +static inline int submit_proto_rx_event(enum proto_transport transport, + const uint8_t *data, size_t len) +{ + struct proto_rx_event *event; + + if ((transport >= PROTO_TRANSPORT_COUNT) || + ((data == NULL) && (len > 0U))) { + return -EINVAL; + } + + event = new_proto_rx_event(len); + event->transport = transport; + + if (len > 0U) { + memcpy(event->dyndata.data, data, len); + } + + APP_EVENT_SUBMIT(event); + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* BLINKY_PROTO_RX_EVENT_H_ */ diff --git a/inc/events/proto_tx_event.h b/inc/events/proto_tx_event.h new file mode 100644 index 0000000..8010ae5 --- /dev/null +++ b/inc/events/proto_tx_event.h @@ -0,0 +1,50 @@ +#ifndef BLINKY_PROTO_TX_EVENT_H_ +#define BLINKY_PROTO_TX_EVENT_H_ + +#include +#include +#include + +#include +#include + +#include "proto_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct proto_tx_event { + struct app_event_header header; + enum proto_transport transport; + struct event_dyndata dyndata; +}; + +APP_EVENT_TYPE_DYNDATA_DECLARE(proto_tx_event); + +static inline int submit_proto_tx_event(enum proto_transport transport, + const uint8_t *data, size_t len) +{ + struct proto_tx_event *event; + + if ((transport >= PROTO_TRANSPORT_COUNT) || + ((data == NULL) && (len > 0U))) { + return -EINVAL; + } + + event = new_proto_tx_event(len); + event->transport = transport; + + if (len > 0U) { + memcpy(event->dyndata.data, data, len); + } + + APP_EVENT_SUBMIT(event); + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* BLINKY_PROTO_TX_EVENT_H_ */ diff --git a/inc/events/usb_cdc_rx_event.h b/inc/events/usb_cdc_rx_event.h deleted file mode 100644 index dd981e9..0000000 --- a/inc/events/usb_cdc_rx_event.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef BLINKY_USB_CDC_RX_EVENT_H_ -#define BLINKY_USB_CDC_RX_EVENT_H_ - -#include -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct usb_cdc_rx_event { - struct app_event_header header; - struct event_dyndata dyndata; -}; - -APP_EVENT_TYPE_DYNDATA_DECLARE(usb_cdc_rx_event); - -static inline int submit_usb_cdc_rx_event(const uint8_t *data, size_t len) -{ - struct usb_cdc_rx_event *event; - - if ((data == NULL) && (len > 0U)) { - return -EINVAL; - } - - event = new_usb_cdc_rx_event(len); - if (len > 0U) { - memcpy(event->dyndata.data, data, len); - } - - APP_EVENT_SUBMIT(event); - return 0; -} - -#ifdef __cplusplus -} -#endif - -#endif /* BLINKY_USB_CDC_RX_EVENT_H_ */ diff --git a/inc/events/usb_cdc_tx_event.h b/inc/events/usb_cdc_tx_event.h deleted file mode 100644 index 5ad457c..0000000 --- a/inc/events/usb_cdc_tx_event.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef BLINKY_USB_CDC_TX_EVENT_H_ -#define BLINKY_USB_CDC_TX_EVENT_H_ - -#include -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct usb_cdc_tx_event { - struct app_event_header header; - struct event_dyndata dyndata; -}; - -APP_EVENT_TYPE_DYNDATA_DECLARE(usb_cdc_tx_event); - -static inline int submit_usb_cdc_tx_event(const uint8_t *data, size_t len) -{ - struct usb_cdc_tx_event *event; - - if ((data == NULL) && (len > 0U)) { - return -EINVAL; - } - - event = new_usb_cdc_tx_event(len); - if (len > 0U) { - memcpy(event->dyndata.data, data, len); - } - - APP_EVENT_SUBMIT(event); - return 0; -} - -#ifdef __cplusplus -} -#endif - -#endif /* BLINKY_USB_CDC_TX_EVENT_H_ */ diff --git a/inc/protocol_module.h b/inc/protocol_module.h index e6c1238..437acb8 100644 --- a/inc/protocol_module.h +++ b/inc/protocol_module.h @@ -1,30 +1,24 @@ #ifndef BLINKY_PROTOCOL_MODULE_H_ #define BLINKY_PROTOCOL_MODULE_H_ +#include #include #include +#include "proto_common.h" + #ifdef __cplusplus extern "C" { #endif -#define CDC_PROTO_TYPE_HELLO_REQ 0x01U -#define CDC_PROTO_TYPE_HELLO_RSP 0x02U -#define CDC_PROTO_TYPE_BITMAP 0x10U -#define CDC_PROTO_TYPE_FUNCTION_KEY_EVENT 0x20U -#define CDC_PROTO_TYPE_LED_STATE 0x21U -#define CDC_PROTO_TYPE_TIME_SYNC 0x30U -#define CDC_PROTO_TYPE_THEME_RGB 0x31U -#define CDC_PROTO_TYPE_ACK 0x7EU -#define CDC_PROTO_TYPE_ERROR 0x7FU +int protocol_module_process_message(enum proto_transport transport, + const uint8_t *req_payload, + size_t req_payload_len, + uint8_t *rsp_payload, + size_t rsp_payload_buf_size, + size_t *rsp_payload_len); -int protocol_module_process_cdc_packet(uint8_t req_type, - const uint8_t *req_payload, - size_t req_payload_len, - uint8_t *rsp_type, - uint8_t *rsp_payload, - size_t rsp_payload_buf_size, - size_t *rsp_payload_len); +void protocol_module_reset_transport_state(enum proto_transport transport); #ifdef __cplusplus } diff --git a/inc/usb_device_module.h b/inc/usb_device_module.h deleted file mode 100644 index 549e803..0000000 --- a/inc/usb_device_module.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef BLINKY_USB_DEVICE_MODULE_H_ -#define BLINKY_USB_DEVICE_MODULE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -enum usb_function { - USB_FUNCTION_HID = 0x01, - USB_FUNCTION_CDC_ACM = 0x02, -}; - -enum usb_device_state { - USB_DEVICE_STATE_DISCONNECTED, - USB_DEVICE_STATE_POWERED, - USB_DEVICE_STATE_ACTIVE, - USB_DEVICE_STATE_SUSPENDED, -}; - -#ifdef __cplusplus -} -#endif - -#endif /* BLINKY_USB_DEVICE_MODULE_H_ */ diff --git a/prj.conf b/prj.conf index ea70a72..aee3568 100644 --- a/prj.conf +++ b/prj.conf @@ -45,6 +45,7 @@ CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n # BLE CONFIG_BT=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ZEPHYR_NUS=y CONFIG_BT_SMP=y CONFIG_BT_BONDABLE=y CONFIG_BT_SETTINGS=y diff --git a/src/ble_nus_module.c b/src/ble_nus_module.c new file mode 100644 index 0000000..7972dfd --- /dev/null +++ b/src/ble_nus_module.c @@ -0,0 +1,215 @@ +#include +#include +#include + +#include + +#define MODULE ble_nus_module +#include +#include + +#include +#include +#include +#include + +#include "proto_rx_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; + +static void notif_enabled(bool enabled, void *ctx) +{ + ARG_UNUSED(ctx); + + tx_notify_enabled = enabled; + LOG_INF("BLE NUS TX notify %s", enabled ? "enabled" : "disabled"); +} + +static void received(struct bt_conn *conn, const void *data, uint16_t len, void *ctx) +{ + ARG_UNUSED(ctx); + + if (!running || !ble_ready || (conn != active_conn)) { + return; + } + + (void)submit_proto_rx_event(PROTO_TRANSPORT_BLE_NUS, data, len); +} + +static struct bt_nus_cb nus_listener = { + .notif_enabled = notif_enabled, + .received = received, +}; + +static void reset_connection_state(void) +{ + active_conn = NULL; + tx_notify_enabled = false; + protocol_module_reset_transport_state(PROTO_TRANSPORT_BLE_NUS); +} + +static int module_init(void) +{ + int err; + + err = bt_nus_cb_register(&nus_listener, NULL); + if (err) { + LOG_ERR("bt_nus_cb_register failed (%d)", err); + return err; + } + + reset_connection_state(); + return 0; +} + +static int module_start(void) +{ + if (running) { + return 0; + } + + running = true; + return 0; +} + +static void module_pause(void) +{ + if (!running) { + return; + } + + running = false; + tx_notify_enabled = false; +} + +static bool handle_ble_peer_event(const struct ble_peer_event *event) +{ + switch (event->state) { + case PEER_STATE_CONNECTED: + if (active_conn != NULL) { + return false; + } + + active_conn = event->id; + tx_notify_enabled = false; + protocol_module_reset_transport_state(PROTO_TRANSPORT_BLE_NUS); + return false; + + case PEER_STATE_DISCONNECTED: + if (active_conn != event->id) { + return false; + } + + reset_connection_state(); + return false; + + default: + return false; + } +} + +static bool handle_proto_tx_event(const struct proto_tx_event *event) +{ + int err; + + if (event->transport != PROTO_TRANSPORT_BLE_NUS) { + return false; + } + + if (!running || !ble_ready || (active_conn == NULL) || !tx_notify_enabled) { + return false; + } + + err = bt_nus_send(active_conn, event->dyndata.data, (uint16_t)event->dyndata.size); + if (err) { + LOG_WRN("bt_nus_send failed (%d)", err); + } + + return false; +} + +static bool app_event_handler(const struct app_event_header *aeh) +{ + if (is_proto_tx_event(aeh)) { + return handle_proto_tx_event(cast_proto_tx_event(aeh)); + } + + if (is_ble_peer_event(aeh)) { + return handle_ble_peer_event(cast_ble_peer_event(aeh)); + } + + if (is_module_state_event(aeh)) { + const struct module_state_event *event = cast_module_state_event(aeh); + int err; + + if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { + 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); + } + + return false; + } + + if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) { + ble_ready = true; + if (running) { + module_set_state(MODULE_STATE_READY); + } + + return false; + } + + 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 if (ble_ready) { + 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, proto_tx_event); +APP_EVENT_SUBSCRIBE_EARLY(MODULE, ble_peer_event); +APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); +APP_EVENT_SUBSCRIBE(MODULE, wake_up_event); diff --git a/src/ble_serial_module.c b/src/ble_serial_module.c deleted file mode 100644 index 32604e7..0000000 --- a/src/ble_serial_module.c +++ /dev/null @@ -1,300 +0,0 @@ -#include -#include -#include -#include - -#include - -#define MODULE ble_serial_module -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "ble_serial_rx_event.h" -#include "ble_serial_tx_event.h" - -LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); - -#define BLE_SERIAL_RX_MAX_LEN 64U -#define BLE_SERIAL_MIN_PAYLOAD_LEN 32U -#define BLE_SERIAL_NOTIFY_OVERHEAD 3U -#define BLE_SERIAL_SERVICE_UUID_VAL \ - BT_UUID_128_ENCODE(0x0b7f6000, 0x38d2, 0x4f62, 0x8f6f, 0x36c4fd73a110) -#define BLE_SERIAL_RX_UUID_VAL \ - BT_UUID_128_ENCODE(0x0b7f6001, 0x38d2, 0x4f62, 0x8f6f, 0x36c4fd73a110) -#define BLE_SERIAL_TX_UUID_VAL \ - BT_UUID_128_ENCODE(0x0b7f6002, 0x38d2, 0x4f62, 0x8f6f, 0x36c4fd73a110) - -static struct bt_conn *active_conn; -static bool initialized; -static bool running; -static bool ble_ready; -static bool secured; -static bool tx_notify_enabled; - -static const struct bt_uuid_128 ble_serial_service_uuid = - BT_UUID_INIT_128(BLE_SERIAL_SERVICE_UUID_VAL); -static const struct bt_uuid_128 ble_serial_rx_uuid = - BT_UUID_INIT_128(BLE_SERIAL_RX_UUID_VAL); -static const struct bt_uuid_128 ble_serial_tx_uuid = - BT_UUID_INIT_128(BLE_SERIAL_TX_UUID_VAL); - -static void tx_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) -{ - ARG_UNUSED(attr); - - tx_notify_enabled = (value == BT_GATT_CCC_NOTIFY); - LOG_INF("BLE serial TX notify %s", tx_notify_enabled ? "enabled" : "disabled"); -} - -static ssize_t rx_write_handler(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, - uint16_t len, - uint16_t offset, - uint8_t flags) -{ - ARG_UNUSED(attr); - ARG_UNUSED(flags); - - if (!running || !ble_ready || !secured || (conn != active_conn)) { - return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); - } - - if (offset != 0U) { - return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); - } - - if ((buf == NULL) || (len == 0U) || (len > BLE_SERIAL_RX_MAX_LEN)) { - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); - } - - (void)submit_ble_serial_rx_event(buf, len); - return len; -} - -BT_GATT_SERVICE_DEFINE(ble_serial_svc, - BT_GATT_PRIMARY_SERVICE(&ble_serial_service_uuid.uuid), - BT_GATT_CHARACTERISTIC(&ble_serial_rx_uuid.uuid, - BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, - BT_GATT_PERM_WRITE_ENCRYPT, - NULL, rx_write_handler, NULL), - BT_GATT_CHARACTERISTIC(&ble_serial_tx_uuid.uuid, - BT_GATT_CHRC_NOTIFY, - BT_GATT_PERM_NONE, - NULL, NULL, NULL), - BT_GATT_CCC(tx_ccc_cfg_changed, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT) -); - -static void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) -{ - if (conn != active_conn) { - return; - } - - LOG_INF("BLE serial MTU updated tx:%u rx:%u", tx, rx); -} - -static struct bt_gatt_cb gatt_callbacks = { - .att_mtu_updated = mtu_updated, -}; - -static size_t notify_payload_max(void) -{ - uint16_t mtu; - - if (active_conn == NULL) { - return 0U; - } - - mtu = bt_gatt_get_mtu(active_conn); - if (mtu <= BLE_SERIAL_NOTIFY_OVERHEAD) { - return 0U; - } - - return (size_t)(mtu - BLE_SERIAL_NOTIFY_OVERHEAD); -} - -static void reset_connection_state(void) -{ - active_conn = NULL; - secured = false; - tx_notify_enabled = false; -} - -static int module_init(void) -{ - bt_gatt_cb_register(&gatt_callbacks); - reset_connection_state(); - return 0; -} - -static int module_start(void) -{ - if (running) { - return 0; - } - - running = true; - return 0; -} - -static void module_pause(void) -{ - if (!running) { - return; - } - - running = false; - tx_notify_enabled = false; -} - -static bool handle_ble_peer_event(const struct ble_peer_event *event) -{ - switch (event->state) { - case PEER_STATE_CONNECTED: - if (active_conn != NULL) { - return false; - } - - active_conn = event->id; - secured = false; - tx_notify_enabled = false; - return false; - - case PEER_STATE_SECURED: - if (active_conn != event->id) { - return false; - } - - secured = true; - return false; - - case PEER_STATE_DISCONNECTED: - if (active_conn != event->id) { - return false; - } - - reset_connection_state(); - return false; - - default: - return false; - } -} - -static bool handle_ble_serial_tx_event(const struct ble_serial_tx_event *event) -{ - size_t payload_max; - int err; - - if (!running || !ble_ready || (active_conn == NULL) || !secured || !tx_notify_enabled) { - return false; - } - - payload_max = notify_payload_max(); - if (payload_max < BLE_SERIAL_MIN_PAYLOAD_LEN) { - LOG_WRN("BLE serial MTU payload too small:%u", (uint32_t)payload_max); - return false; - } - - if (event->dyndata.size > payload_max) { - LOG_WRN("BLE serial TX too large len:%u max:%u", - (uint32_t)event->dyndata.size, (uint32_t)payload_max); - return false; - } - - err = bt_gatt_notify(active_conn, &ble_serial_svc.attrs[4], - event->dyndata.data, - (uint16_t)event->dyndata.size); - if (err) { - LOG_WRN("bt_gatt_notify failed (%d)", err); - } - - return false; -} - -static bool app_event_handler(const struct app_event_header *aeh) -{ - if (is_ble_serial_tx_event(aeh)) { - return handle_ble_serial_tx_event(cast_ble_serial_tx_event(aeh)); - } - - if (is_ble_peer_event(aeh)) { - return handle_ble_peer_event(cast_ble_peer_event(aeh)); - } - - if (is_module_state_event(aeh)) { - const struct module_state_event *event = cast_module_state_event(aeh); - int err; - - if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { - 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); - } - - return false; - } - - if (check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) { - ble_ready = true; - if (running) { - module_set_state(MODULE_STATE_READY); - } - - return false; - } - - 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 if (ble_ready) { - 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, ble_serial_tx_event); -APP_EVENT_SUBSCRIBE_EARLY(MODULE, ble_peer_event); -APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); -APP_EVENT_SUBSCRIBE(MODULE, wake_up_event); diff --git a/src/cdc_wrapper_module.c b/src/cdc_wrapper_module.c deleted file mode 100644 index 7bcd813..0000000 --- a/src/cdc_wrapper_module.c +++ /dev/null @@ -1,298 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#define MODULE cdc_wrapper_module -#include -#include - -#include - -#include "cdc_proto_tx_event.h" -#include "protocol_module.h" -#include "usb_cdc_rx_event.h" -#include "usb_cdc_tx_event.h" - -LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); - -#define CDC_WRAPPER_HEAD1 0xAAU -#define CDC_WRAPPER_HEAD2 0x55U -#define CDC_WRAPPER_MAX_PAYLOAD_LEN 64U -#define CDC_WRAPPER_MAX_FRAME_LEN (2U + 1U + 1U + CDC_WRAPPER_MAX_PAYLOAD_LEN + 1U) - -enum frame_parse_state { - FRAME_PARSE_HEAD1, - FRAME_PARSE_HEAD2, - FRAME_PARSE_LEN, - FRAME_PARSE_TYPE, - FRAME_PARSE_PAYLOAD, - FRAME_PARSE_CHECKSUM, -}; - -struct cdc_frame_parser { - enum frame_parse_state state; - uint8_t len; - uint8_t type; - uint8_t checksum; - uint8_t payload[CDC_WRAPPER_MAX_PAYLOAD_LEN]; - size_t payload_pos; -}; - -static bool initialized; -static bool running; -static struct cdc_frame_parser parser; - -static void parser_reset(void) -{ - parser.state = FRAME_PARSE_HEAD1; - parser.len = 0U; - parser.type = 0U; - parser.checksum = 0U; - parser.payload_pos = 0U; -} - -static uint8_t frame_checksum(uint8_t len, uint8_t type, - const uint8_t *payload, size_t payload_len) -{ - uint8_t checksum = CDC_WRAPPER_HEAD1 ^ CDC_WRAPPER_HEAD2 ^ len ^ type; - - for (size_t i = 0; i < payload_len; i++) { - checksum ^= payload[i]; - } - - return checksum; -} - -static void submit_tx_frame(uint8_t type, const uint8_t *payload, size_t payload_len) -{ - size_t frame_len = 2U + 1U + 1U + payload_len + 1U; - uint8_t frame_buf[CDC_WRAPPER_MAX_FRAME_LEN]; - - frame_buf[0] = CDC_WRAPPER_HEAD1; - frame_buf[1] = CDC_WRAPPER_HEAD2; - frame_buf[2] = (uint8_t)payload_len; - frame_buf[3] = type; - memcpy(&frame_buf[4], payload, payload_len); - frame_buf[4U + payload_len] = - frame_checksum((uint8_t)payload_len, type, payload, payload_len); - (void)submit_usb_cdc_tx_event(frame_buf, frame_len); -} - -static void process_complete_frame(void) -{ - uint8_t rsp_type; - uint8_t rsp_payload[CDC_WRAPPER_MAX_PAYLOAD_LEN]; - size_t rsp_payload_len = 0U; - int err; - - err = protocol_module_process_cdc_packet(parser.type, - parser.payload, - parser.payload_pos, - &rsp_type, - rsp_payload, - sizeof(rsp_payload), - &rsp_payload_len); - if (err == -ENOTSUP) { - LOG_WRN("Ignore unsupported CDC packet type:0x%02x", parser.type); - return; - } - - if (err) { - LOG_WRN("Protocol processing failed (%d)", err); - return; - } - - LOG_INF("CDC response type:0x%02x len:%u", - rsp_type, (uint32_t)rsp_payload_len); - submit_tx_frame(rsp_type, rsp_payload, rsp_payload_len); -} - -static void consume_byte(uint8_t byte) -{ - switch (parser.state) { - case FRAME_PARSE_HEAD1: - if (byte == CDC_WRAPPER_HEAD1) { - parser.state = FRAME_PARSE_HEAD2; - } - break; - - case FRAME_PARSE_HEAD2: - if (byte == CDC_WRAPPER_HEAD2) { - parser.state = FRAME_PARSE_LEN; - } else if (byte != CDC_WRAPPER_HEAD1) { - parser.state = FRAME_PARSE_HEAD1; - } - break; - - case FRAME_PARSE_LEN: - if (byte > CDC_WRAPPER_MAX_PAYLOAD_LEN) { - LOG_WRN("Drop CDC frame with invalid len:%u", byte); - parser_reset(); - break; - } - - parser.len = byte; - parser.payload_pos = 0U; - parser.state = FRAME_PARSE_TYPE; - break; - - case FRAME_PARSE_TYPE: - parser.type = byte; - parser.state = (parser.len == 0U) ? FRAME_PARSE_CHECKSUM : - FRAME_PARSE_PAYLOAD; - break; - - case FRAME_PARSE_PAYLOAD: - parser.payload[parser.payload_pos++] = byte; - if (parser.payload_pos >= parser.len) { - parser.state = FRAME_PARSE_CHECKSUM; - } - break; - - case FRAME_PARSE_CHECKSUM: - if (byte != frame_checksum(parser.len, parser.type, - parser.payload, parser.payload_pos)) { - LOG_WRN("Drop CDC frame with invalid checksum"); - parser_reset(); - break; - } - - process_complete_frame(); - parser_reset(); - break; - - default: - parser_reset(); - break; - } -} - -static bool handle_usb_cdc_rx_event(const struct usb_cdc_rx_event *event) -{ - if (!running) { - return false; - } - - for (size_t i = 0; i < event->dyndata.size; i++) { - consume_byte(event->dyndata.data[i]); - } - - return false; -} - -static bool handle_cdc_proto_tx_event(const struct cdc_proto_tx_event *event) -{ - if (!running) { - return false; - } - - if (event->dyndata.size > CDC_WRAPPER_MAX_PAYLOAD_LEN) { - LOG_WRN("Drop CDC proto TX len:%u max:%u", - (uint32_t)event->dyndata.size, - (uint32_t)CDC_WRAPPER_MAX_PAYLOAD_LEN); - return false; - } - - submit_tx_frame(event->type, event->dyndata.data, event->dyndata.size); - return false; -} - -static int module_init(void) -{ - parser_reset(); - return 0; -} - -static int module_start(void) -{ - if (running) { - return 0; - } - - running = true; - return 0; -} - -static void module_pause(void) -{ - if (!running) { - return; - } - - running = false; - parser_reset(); -} - -static bool app_event_handler(const struct app_event_header *aeh) -{ - if (is_usb_cdc_rx_event(aeh)) { - return handle_usb_cdc_rx_event(cast_usb_cdc_rx_event(aeh)); - } - - if (is_cdc_proto_tx_event(aeh)) { - return handle_cdc_proto_tx_event(cast_cdc_proto_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, cdc_proto_tx_event); -APP_EVENT_SUBSCRIBE(MODULE, module_state_event); -APP_EVENT_SUBSCRIBE(MODULE, usb_cdc_rx_event); -APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); -APP_EVENT_SUBSCRIBE(MODULE, wake_up_event); diff --git a/src/events/ble_serial_rx_event.c b/src/events/ble_serial_rx_event.c deleted file mode 100644 index 10a0b2d..0000000 --- a/src/events/ble_serial_rx_event.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include - -#include "ble_serial_rx_event.h" - -#define BLE_SERIAL_RX_EVENT_LOG_BUF_LEN 384 - -static void log_ble_serial_rx_event(const struct app_event_header *aeh) -{ - const struct ble_serial_rx_event *event = cast_ble_serial_rx_event(aeh); - char log_buf[BLE_SERIAL_RX_EVENT_LOG_BUF_LEN]; - int pos; - - pos = snprintf(log_buf, sizeof(log_buf), "len:%zu ascii:\"", - event->dyndata.size); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "log message preparation failure"); - return; - } - - for (size_t i = 0; i < event->dyndata.size; i++) { - int tmp = snprintf(&log_buf[pos], sizeof(log_buf) - pos, "%c", - isprint(event->dyndata.data[i]) ? - event->dyndata.data[i] : '.'); - - if ((tmp < 0) || ((pos + tmp) >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - pos += tmp; - } - - pos += snprintf(&log_buf[pos], sizeof(log_buf) - pos, "\" hex:"); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - for (size_t i = 0; i < event->dyndata.size; i++) { - int tmp = snprintf(&log_buf[pos], sizeof(log_buf) - pos, " %02x", - event->dyndata.data[i]); - - if ((tmp < 0) || ((pos + tmp) >= sizeof(log_buf))) { - break; - } - - pos += tmp; - } - - APP_EVENT_MANAGER_LOG(aeh, "%s", log_buf); -} - -static void profile_ble_serial_rx_event(struct log_event_buf *buf, - const struct app_event_header *aeh) -{ - const struct ble_serial_rx_event *event = cast_ble_serial_rx_event(aeh); - - nrf_profiler_log_encode_uint8(buf, (uint8_t)event->dyndata.size); -} - -APP_EVENT_INFO_DEFINE(ble_serial_rx_event, - ENCODE(NRF_PROFILER_ARG_U8), - ENCODE("len"), - profile_ble_serial_rx_event); - -APP_EVENT_TYPE_DEFINE(ble_serial_rx_event, - log_ble_serial_rx_event, - &ble_serial_rx_event_info, - APP_EVENT_FLAGS_CREATE( - APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/ble_serial_tx_event.c b/src/events/ble_serial_tx_event.c deleted file mode 100644 index 8e75ae6..0000000 --- a/src/events/ble_serial_tx_event.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -#include "ble_serial_tx_event.h" - -#define BLE_SERIAL_TX_EVENT_LOG_BUF_LEN 256 - -static void log_ble_serial_tx_event(const struct app_event_header *aeh) -{ - const struct ble_serial_tx_event *event = cast_ble_serial_tx_event(aeh); - char log_buf[BLE_SERIAL_TX_EVENT_LOG_BUF_LEN]; - int pos; - - pos = snprintf(log_buf, sizeof(log_buf), "len:%zu ascii:\"", - event->dyndata.size); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "log message preparation failure"); - return; - } - - for (size_t i = 0; i < event->dyndata.size; i++) { - int tmp = snprintf(&log_buf[pos], sizeof(log_buf) - pos, "%c", - isprint(event->dyndata.data[i]) ? - event->dyndata.data[i] : '.'); - - if ((tmp < 0) || ((pos + tmp) >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - pos += tmp; - } - - pos += snprintf(&log_buf[pos], sizeof(log_buf) - pos, "\""); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - APP_EVENT_MANAGER_LOG(aeh, "%s", log_buf); -} - -static void profile_ble_serial_tx_event(struct log_event_buf *buf, - const struct app_event_header *aeh) -{ - const struct ble_serial_tx_event *event = cast_ble_serial_tx_event(aeh); - - nrf_profiler_log_encode_uint8(buf, (uint8_t)event->dyndata.size); -} - -APP_EVENT_INFO_DEFINE(ble_serial_tx_event, - ENCODE(NRF_PROFILER_ARG_U8), - ENCODE("len"), - profile_ble_serial_tx_event); - -APP_EVENT_TYPE_DEFINE(ble_serial_tx_event, - log_ble_serial_tx_event, - &ble_serial_tx_event_info, - APP_EVENT_FLAGS_CREATE( - APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/cdc_proto_tx_event.c b/src/events/cdc_proto_tx_event.c deleted file mode 100644 index e1dcffe..0000000 --- a/src/events/cdc_proto_tx_event.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "cdc_proto_tx_event.h" - -static void log_cdc_proto_tx_event(const struct app_event_header *aeh) -{ - const struct cdc_proto_tx_event *event = cast_cdc_proto_tx_event(aeh); - - APP_EVENT_MANAGER_LOG(aeh, "type:0x%02x len:%zu", - event->type, event->dyndata.size); -} - -static void profile_cdc_proto_tx_event(struct log_event_buf *buf, - const struct app_event_header *aeh) -{ - const struct cdc_proto_tx_event *event = cast_cdc_proto_tx_event(aeh); - - nrf_profiler_log_encode_uint8(buf, event->type); - nrf_profiler_log_encode_uint8(buf, (uint8_t)event->dyndata.size); -} - -APP_EVENT_INFO_DEFINE(cdc_proto_tx_event, - ENCODE(NRF_PROFILER_ARG_U8, NRF_PROFILER_ARG_U8), - ENCODE("type", "len"), - profile_cdc_proto_tx_event); - -APP_EVENT_TYPE_DEFINE(cdc_proto_tx_event, - log_cdc_proto_tx_event, - &cdc_proto_tx_event_info, - APP_EVENT_FLAGS_CREATE( - APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/proto_rx_event.c b/src/events/proto_rx_event.c new file mode 100644 index 0000000..6e090f4 --- /dev/null +++ b/src/events/proto_rx_event.c @@ -0,0 +1,42 @@ +#include "proto_rx_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 void log_proto_rx_event(const struct app_event_header *aeh) +{ + const struct proto_rx_event *event = cast_proto_rx_event(aeh); + + APP_EVENT_MANAGER_LOG(aeh, "transport:%s len:%zu", + transport_name(event->transport), + event->dyndata.size); +} + +static void profile_proto_rx_event(struct log_event_buf *buf, + const struct app_event_header *aeh) +{ + const struct proto_rx_event *event = cast_proto_rx_event(aeh); + + nrf_profiler_log_encode_uint8(buf, event->transport); + nrf_profiler_log_encode_uint16(buf, (uint16_t)event->dyndata.size); +} + +APP_EVENT_INFO_DEFINE(proto_rx_event, + ENCODE(NRF_PROFILER_ARG_U8, NRF_PROFILER_ARG_U16), + ENCODE("transport", "len"), + profile_proto_rx_event); + +APP_EVENT_TYPE_DEFINE(proto_rx_event, + log_proto_rx_event, + &proto_rx_event_info, + APP_EVENT_FLAGS_CREATE( + APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/proto_tx_event.c b/src/events/proto_tx_event.c new file mode 100644 index 0000000..5ef5a13 --- /dev/null +++ b/src/events/proto_tx_event.c @@ -0,0 +1,42 @@ +#include "proto_tx_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 void log_proto_tx_event(const struct app_event_header *aeh) +{ + const struct proto_tx_event *event = cast_proto_tx_event(aeh); + + APP_EVENT_MANAGER_LOG(aeh, "transport:%s len:%zu", + transport_name(event->transport), + event->dyndata.size); +} + +static void profile_proto_tx_event(struct log_event_buf *buf, + const struct app_event_header *aeh) +{ + const struct proto_tx_event *event = cast_proto_tx_event(aeh); + + nrf_profiler_log_encode_uint8(buf, event->transport); + nrf_profiler_log_encode_uint16(buf, (uint16_t)event->dyndata.size); +} + +APP_EVENT_INFO_DEFINE(proto_tx_event, + ENCODE(NRF_PROFILER_ARG_U8, NRF_PROFILER_ARG_U16), + ENCODE("transport", "len"), + profile_proto_tx_event); + +APP_EVENT_TYPE_DEFINE(proto_tx_event, + log_proto_tx_event, + &proto_tx_event_info, + APP_EVENT_FLAGS_CREATE( + APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/usb_cdc_rx_event.c b/src/events/usb_cdc_rx_event.c deleted file mode 100644 index a941afe..0000000 --- a/src/events/usb_cdc_rx_event.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include - -#include "usb_cdc_rx_event.h" - -#define USB_CDC_RX_EVENT_LOG_BUF_LEN 384 - -static void log_usb_cdc_rx_event(const struct app_event_header *aeh) -{ - const struct usb_cdc_rx_event *event = cast_usb_cdc_rx_event(aeh); - char log_buf[USB_CDC_RX_EVENT_LOG_BUF_LEN]; - int pos; - - pos = snprintf(log_buf, sizeof(log_buf), "len:%zu ascii:\"", - event->dyndata.size); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "log message preparation failure"); - return; - } - - for (size_t i = 0; i < event->dyndata.size; i++) { - int tmp = snprintf(&log_buf[pos], sizeof(log_buf) - pos, "%c", - isprint(event->dyndata.data[i]) ? - event->dyndata.data[i] : '.'); - - if ((tmp < 0) || ((pos + tmp) >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - pos += tmp; - } - - pos += snprintf(&log_buf[pos], sizeof(log_buf) - pos, "\" hex:"); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - for (size_t i = 0; i < event->dyndata.size; i++) { - int tmp = snprintf(&log_buf[pos], sizeof(log_buf) - pos, " %02x", - event->dyndata.data[i]); - - if ((tmp < 0) || ((pos + tmp) >= sizeof(log_buf))) { - break; - } - - pos += tmp; - } - - APP_EVENT_MANAGER_LOG(aeh, "%s", log_buf); -} - -static void profile_usb_cdc_rx_event(struct log_event_buf *buf, - const struct app_event_header *aeh) -{ - const struct usb_cdc_rx_event *event = cast_usb_cdc_rx_event(aeh); - - nrf_profiler_log_encode_uint8(buf, (uint8_t)event->dyndata.size); -} - -APP_EVENT_INFO_DEFINE(usb_cdc_rx_event, - ENCODE(NRF_PROFILER_ARG_U8), - ENCODE("len"), - profile_usb_cdc_rx_event); - -APP_EVENT_TYPE_DEFINE(usb_cdc_rx_event, - log_usb_cdc_rx_event, - &usb_cdc_rx_event_info, - APP_EVENT_FLAGS_CREATE( - APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/events/usb_cdc_tx_event.c b/src/events/usb_cdc_tx_event.c deleted file mode 100644 index 8524105..0000000 --- a/src/events/usb_cdc_tx_event.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -#include "usb_cdc_tx_event.h" - -#define USB_CDC_TX_EVENT_LOG_BUF_LEN 256 - -static void log_usb_cdc_tx_event(const struct app_event_header *aeh) -{ - const struct usb_cdc_tx_event *event = cast_usb_cdc_tx_event(aeh); - char log_buf[USB_CDC_TX_EVENT_LOG_BUF_LEN]; - int pos; - - pos = snprintf(log_buf, sizeof(log_buf), "len:%zu ascii:\"", - event->dyndata.size); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "log message preparation failure"); - return; - } - - for (size_t i = 0; i < event->dyndata.size; i++) { - int tmp = snprintf(&log_buf[pos], sizeof(log_buf) - pos, "%c", - isprint(event->dyndata.data[i]) ? - event->dyndata.data[i] : '.'); - - if ((tmp < 0) || ((pos + tmp) >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - pos += tmp; - } - - pos += snprintf(&log_buf[pos], sizeof(log_buf) - pos, "\""); - if ((pos < 0) || (pos >= sizeof(log_buf))) { - APP_EVENT_MANAGER_LOG(aeh, "len:%zu ascii:\"...\"", - event->dyndata.size); - return; - } - - APP_EVENT_MANAGER_LOG(aeh, "%s", log_buf); -} - -static void profile_usb_cdc_tx_event(struct log_event_buf *buf, - const struct app_event_header *aeh) -{ - const struct usb_cdc_tx_event *event = cast_usb_cdc_tx_event(aeh); - - nrf_profiler_log_encode_uint8(buf, (uint8_t)event->dyndata.size); -} - -APP_EVENT_INFO_DEFINE(usb_cdc_tx_event, - ENCODE(NRF_PROFILER_ARG_U8), - ENCODE("len"), - profile_usb_cdc_tx_event); - -APP_EVENT_TYPE_DEFINE(usb_cdc_tx_event, - log_usb_cdc_tx_event, - &usb_cdc_tx_event_info, - APP_EVENT_FLAGS_CREATE( - APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE)); diff --git a/src/protocol_module.c b/src/protocol_module.c index 40bf560..e30dc1a 100644 --- a/src/protocol_module.c +++ b/src/protocol_module.c @@ -18,14 +18,9 @@ #include -#include "theme_rgb_update_event.h" -#include "time_sync_event.h" -#include "cdc_proto_tx_event.h" -#include "function_bitmap_update_event.h" -#include "hid_led_event.h" -#include "key_function_event.h" +#include "proto_rx_event.h" +#include "proto_tx_event.h" #include "protocol_module.h" -#include "usb_state_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); @@ -34,39 +29,12 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); #define PROTOCOL_PRODUCT_ID 0x52F0U #define PROTOCOL_FIRMWARE_MAJOR 0U #define PROTOCOL_FIRMWARE_MINOR 0U -#define PROTOCOL_CAPABILITY_FLAGS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) +#define PROTOCOL_CAPABILITY_FLAGS 0U +#define PROTOCOL_MAX_MSG_LEN 128U static bool initialized; static bool running; -static bool keyboard_core_ready; -static bool usb_active; -static bool hello_done; - -static bool type_matches_body(uint8_t type, const CdcPacketBody *body) -{ - switch (type) { - case CDC_PROTO_TYPE_HELLO_REQ: - return body->which_body == CdcPacketBody_hello_req_tag; - case CDC_PROTO_TYPE_HELLO_RSP: - return body->which_body == CdcPacketBody_hello_rsp_tag; - case CDC_PROTO_TYPE_BITMAP: - return body->which_body == CdcPacketBody_bitmap_tag; - case CDC_PROTO_TYPE_FUNCTION_KEY_EVENT: - return body->which_body == CdcPacketBody_function_key_event_tag; - case CDC_PROTO_TYPE_LED_STATE: - return body->which_body == CdcPacketBody_led_state_tag; - case CDC_PROTO_TYPE_TIME_SYNC: - return body->which_body == CdcPacketBody_time_sync_tag; - case CDC_PROTO_TYPE_THEME_RGB: - return body->which_body == CdcPacketBody_theme_rgb_tag; - case CDC_PROTO_TYPE_ACK: - return body->which_body == CdcPacketBody_ack_tag; - case CDC_PROTO_TYPE_ERROR: - return body->which_body == CdcPacketBody_error_tag; - default: - return false; - } -} +static bool hello_done[PROTO_TRANSPORT_COUNT]; static int decode_body(const uint8_t *payload, size_t payload_len, CdcPacketBody *body) @@ -123,94 +91,12 @@ static int encode_hello_rsp(uint8_t *rsp_payload, size_t rsp_payload_buf_size, return encode_body(&body, rsp_payload, rsp_payload_buf_size, rsp_payload_len); } -static int encode_ack(uint8_t acked_type, uint8_t *rsp_payload, - size_t rsp_payload_buf_size, size_t *rsp_payload_len) -{ - CdcPacketBody body = CdcPacketBody_init_zero; - - body.which_body = CdcPacketBody_ack_tag; - body.body.ack.acked_type = acked_type; - - return encode_body(&body, rsp_payload, rsp_payload_buf_size, rsp_payload_len); -} - -static int encode_error(uint8_t error_type, ErrorCode error_code, - uint8_t *rsp_payload, size_t rsp_payload_buf_size, - size_t *rsp_payload_len) -{ - CdcPacketBody body = CdcPacketBody_init_zero; - - body.which_body = CdcPacketBody_error_tag; - body.body.error.error_type = error_type; - body.body.error.error_code = error_code; - - return encode_body(&body, rsp_payload, rsp_payload_buf_size, rsp_payload_len); -} - -static int encode_function_key_event(uint16_t usage, uint8_t action, - uint8_t *payload, - size_t payload_buf_size, - size_t *payload_len) -{ - CdcPacketBody body = CdcPacketBody_init_zero; - - body.which_body = CdcPacketBody_function_key_event_tag; - body.body.function_key_event.usage = usage; - body.body.function_key_event.action = (KeyAction)action; - - return encode_body(&body, payload, payload_buf_size, payload_len); -} - -static int encode_led_state(uint32_t led_mask, uint8_t *payload, - size_t payload_buf_size, size_t *payload_len) -{ - CdcPacketBody body = CdcPacketBody_init_zero; - - body.which_body = CdcPacketBody_led_state_tag; - body.body.led_state.led_mask = led_mask; - - return encode_body(&body, payload, payload_buf_size, payload_len); -} - -static int encode_error_response(uint8_t req_type, ErrorCode error_code, - uint8_t *rsp_type, uint8_t *rsp_payload, - size_t rsp_payload_buf_size, - size_t *rsp_payload_len) -{ - int err; - - err = encode_error(req_type, error_code, rsp_payload, - rsp_payload_buf_size, rsp_payload_len); - if (err) { - return err; - } - - *rsp_type = CDC_PROTO_TYPE_ERROR; - return 0; -} - -static int encode_ack_response(uint8_t acked_type, uint8_t *rsp_type, - uint8_t *rsp_payload, - size_t rsp_payload_buf_size, - size_t *rsp_payload_len) -{ - int err; - - err = encode_ack(acked_type, rsp_payload, rsp_payload_buf_size, - rsp_payload_len); - if (err) { - return err; - } - - *rsp_type = CDC_PROTO_TYPE_ACK; - return 0; -} - static int module_init(void) { - keyboard_core_ready = false; - usb_active = false; - hello_done = false; + for (size_t i = 0; i < ARRAY_SIZE(hello_done); i++) { + hello_done[i] = false; + } + return 0; } @@ -230,22 +116,34 @@ static void module_pause(void) return; } - hello_done = false; + for (size_t i = 0; i < ARRAY_SIZE(hello_done); i++) { + hello_done[i] = false; + } + running = false; } -int protocol_module_process_cdc_packet(uint8_t req_type, - const uint8_t *req_payload, - size_t req_payload_len, - uint8_t *rsp_type, - uint8_t *rsp_payload, - size_t rsp_payload_buf_size, - size_t *rsp_payload_len) +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, + uint8_t *rsp_payload, + size_t rsp_payload_buf_size, + size_t *rsp_payload_len) { CdcPacketBody body; int err; - if ((rsp_type == NULL) || (rsp_payload == NULL) || (rsp_payload_len == NULL)) { + if ((transport >= PROTO_TRANSPORT_COUNT) || + (rsp_payload == NULL) || (rsp_payload_len == NULL)) { return -EINVAL; } @@ -255,191 +153,53 @@ int protocol_module_process_cdc_packet(uint8_t req_type, err = decode_body(req_payload, req_payload_len, &body); if (err) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_LENGTH, - rsp_type, rsp_payload, - rsp_payload_buf_size, rsp_payload_len); + return err; } - if (!type_matches_body(req_type, &body)) { - LOG_WRN("CDC type/body mismatch type:0x%02x body_case:%d", - req_type, body.which_body); - return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_PARAM, - rsp_type, rsp_payload, - rsp_payload_buf_size, rsp_payload_len); + if (body.which_body != CdcPacketBody_hello_req_tag) { + LOG_WRN("Unsupported protobuf body case %d", body.which_body); + return -ENOTSUP; } - switch (req_type) { - case CDC_PROTO_TYPE_HELLO_REQ: - LOG_INF("HelloReq protocol_version:%u", + LOG_INF("HelloReq transport:%u protocol_version:%u", + transport, body.body.hello_req.protocol_version); + + if (body.body.hello_req.protocol_version != PROTOCOL_VERSION) { + LOG_WRN("Unexpected protocol version:%u", body.body.hello_req.protocol_version); - - if (body.body.hello_req.protocol_version != PROTOCOL_VERSION) { - LOG_WRN("Unexpected protocol version:%u", - body.body.hello_req.protocol_version); - } - - hello_done = true; - err = encode_hello_rsp(rsp_payload, rsp_payload_buf_size, rsp_payload_len); - if (err) { - return err; - } - - *rsp_type = CDC_PROTO_TYPE_HELLO_RSP; - return 0; - - case CDC_PROTO_TYPE_BITMAP: - if (!hello_done) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_NOT_READY, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - if (!keyboard_core_ready) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_NOT_READY, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - if (body.body.bitmap.usage_bitmap.size != KEYBOARD_PROTOCOL_BITMAP_BYTES) { - LOG_WRN("Bitmap len:%u expected:%u", - (unsigned int)body.body.bitmap.usage_bitmap.size, - KEYBOARD_PROTOCOL_BITMAP_BYTES); - return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_LENGTH, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - err = submit_function_bitmap_update_event( - body.body.bitmap.usage_bitmap.bytes); - if (err) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_PARAM, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - return encode_ack_response(req_type, rsp_type, rsp_payload, - rsp_payload_buf_size, rsp_payload_len); - - case CDC_PROTO_TYPE_TIME_SYNC: - if (!hello_done) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_NOT_READY, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - if (body.body.time_sync.version != 1U) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_PARAM, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - submit_time_sync_event(body.body.time_sync.version, - body.body.time_sync.flags, - body.body.time_sync.timezone_min, - body.body.time_sync.utc_ms, - body.body.time_sync.accuracy_ms); - return encode_ack_response(req_type, rsp_type, rsp_payload, - rsp_payload_buf_size, rsp_payload_len); - - case CDC_PROTO_TYPE_THEME_RGB: - if (!hello_done) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_NOT_READY, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - if ((body.body.theme_rgb.red > 255U) || - (body.body.theme_rgb.green > 255U) || - (body.body.theme_rgb.blue > 255U)) { - return encode_error_response(req_type, ErrorCode_ERROR_CODE_INVALID_PARAM, - rsp_type, rsp_payload, - rsp_payload_buf_size, - rsp_payload_len); - } - - submit_theme_rgb_update_event((struct theme_rgb) { - .r = (uint8_t)body.body.theme_rgb.red, - .g = (uint8_t)body.body.theme_rgb.green, - .b = (uint8_t)body.body.theme_rgb.blue, - }); - return encode_ack_response(req_type, rsp_type, rsp_payload, - rsp_payload_buf_size, rsp_payload_len); - - default: - LOG_WRN("Unsupported CDC protocol type:0x%02x", req_type); - return encode_error_response(req_type, ErrorCode_ERROR_CODE_UNKNOWN_TYPE, - rsp_type, rsp_payload, - rsp_payload_buf_size, rsp_payload_len); } + + hello_done[transport] = true; + return encode_hello_rsp(rsp_payload, rsp_payload_buf_size, rsp_payload_len); } -static bool handle_key_function_event(const struct key_function_event *event) +static bool handle_proto_rx_event(const struct proto_rx_event *event) { - uint8_t payload[64]; - size_t payload_len; + uint8_t rsp_payload[PROTOCOL_MAX_MSG_LEN]; + size_t rsp_payload_len = 0U; int err; - if (!running || !usb_active || !hello_done) { + if (!running) { return false; } - err = encode_function_key_event(event->usage, event->action, payload, - sizeof(payload), &payload_len); + err = protocol_module_process_message(event->transport, + event->dyndata.data, + event->dyndata.size, + rsp_payload, + sizeof(rsp_payload), + &rsp_payload_len); if (err) { - LOG_WRN("FunctionKeyEvent encode failed (%d)", err); + if (err != -ENOTSUP) { + LOG_WRN("Protocol processing failed (%d)", err); + } + return false; } - err = submit_cdc_proto_tx_event(CDC_PROTO_TYPE_FUNCTION_KEY_EVENT, - payload, payload_len); + err = submit_proto_tx_event(event->transport, rsp_payload, rsp_payload_len); if (err) { - LOG_WRN("FunctionKeyEvent submit failed (%d)", err); - } - - return false; -} - -static bool handle_hid_led_event(const struct hid_led_event *event) -{ - uint8_t payload[64]; - size_t payload_len; - int err; - - if (!running || !usb_active || !hello_done) { - return false; - } - - err = encode_led_state(event->led_bm, payload, sizeof(payload), &payload_len); - if (err) { - LOG_WRN("LedState encode failed (%d)", err); - return false; - } - - err = submit_cdc_proto_tx_event(CDC_PROTO_TYPE_LED_STATE, payload, payload_len); - if (err) { - LOG_WRN("LedState submit failed (%d)", err); - } - - return false; -} - -static bool handle_usb_state_event(const struct usb_state_event *event) -{ - if ((event->op != USB_STATE_EVENT_OP_SNAPSHOT) || - (event->src_module_id != MODULE_ID(usb_device_module))) { - return false; - } - - usb_active = (event->flags & USB_STATEF_ACTIVE) != 0U; - if (!usb_active) { - hello_done = false; + LOG_WRN("Proto TX submit failed (%d)", err); } return false; @@ -447,16 +207,8 @@ static bool handle_usb_state_event(const struct usb_state_event *event) static bool app_event_handler(const struct app_event_header *aeh) { - if (is_key_function_event(aeh)) { - return handle_key_function_event(cast_key_function_event(aeh)); - } - - if (is_hid_led_event(aeh)) { - return handle_hid_led_event(cast_hid_led_event(aeh)); - } - - if (is_usb_state_event(aeh)) { - return handle_usb_state_event(cast_usb_state_event(aeh)); + if (is_proto_rx_event(aeh)) { + return handle_proto_rx_event(cast_proto_rx_event(aeh)); } if (is_module_state_event(aeh)) { @@ -484,11 +236,6 @@ static bool app_event_handler(const struct app_event_header *aeh) return false; } - if (check_state(event, MODULE_ID(keyboard_core_module), MODULE_STATE_READY)) { - keyboard_core_ready = true; - return false; - } - return false; } @@ -519,9 +266,7 @@ static bool app_event_handler(const struct app_event_header *aeh) } APP_EVENT_LISTENER(MODULE, app_event_handler); -APP_EVENT_SUBSCRIBE(MODULE, hid_led_event); -APP_EVENT_SUBSCRIBE(MODULE, key_function_event); APP_EVENT_SUBSCRIBE(MODULE, module_state_event); -APP_EVENT_SUBSCRIBE(MODULE, usb_state_event); +APP_EVENT_SUBSCRIBE(MODULE, proto_rx_event); APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); APP_EVENT_SUBSCRIBE(MODULE, wake_up_event); diff --git a/src/usb_cdc_module.c b/src/usb_cdc_module.c index 2a1b385..d310578 100644 --- a/src/usb_cdc_module.c +++ b/src/usb_cdc_module.c @@ -16,8 +16,9 @@ #include #include -#include "usb_cdc_rx_event.h" -#include "usb_cdc_tx_event.h" +#include "proto_rx_event.h" +#include "proto_tx_event.h" +#include "protocol_module.h" #include "usb_state_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); @@ -25,7 +26,9 @@ 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_CONTROL_POLL_INTERVAL K_MSEC(100) +#define USB_CDC_PROTO_RX_FLUSH_DELAY K_MSEC(3) #define USB_CDC_EXPECTED_BAUDRATE 115200U static const struct device *const cdc_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart); @@ -36,12 +39,15 @@ 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 usb_function_prepared; 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 bool is_usb_owner_snapshot(const struct usb_state_event *event) { @@ -66,6 +72,8 @@ static void disable_uart_io(void) uart_irq_tx_disable(cdc_dev); rx_enabled = false; dtr_ready = false; + proto_rx_len = 0U; + k_work_cancel_delayable(&rx_flush_work); reset_ring_buffers(); } @@ -133,10 +141,32 @@ static void rx_work_handler(struct k_work *work) return; } - (void)submit_usb_cdc_rx_event(buffer, len); + if ((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; + } + + if (len > 0U) { + memcpy(&proto_rx_buf[proto_rx_len], buffer, len); + proto_rx_len += len; + k_work_reschedule(&rx_flush_work, USB_CDC_PROTO_RX_FLUSH_DELAY); + } } } +static void rx_flush_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + + if (!running || !usb_active || !dtr_ready || (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; @@ -250,8 +280,10 @@ 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); usb_function_prepared = false; + proto_rx_len = 0U; return 0; } @@ -276,6 +308,7 @@ static void module_pause(void) } k_work_cancel_delayable(&control_work); + k_work_cancel_delayable(&rx_flush_work); disable_uart_io(); running = false; } @@ -304,6 +337,8 @@ static bool handle_usb_state_event(const struct usb_state_event *event) 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); @@ -312,11 +347,15 @@ static bool handle_usb_state_event(const struct usb_state_event *event) return false; } -static bool handle_usb_cdc_tx_event(const struct usb_cdc_tx_event *event) +static bool handle_proto_tx_event(const struct proto_tx_event *event) { uint32_t written; unsigned int key; + if (event->transport != PROTO_TRANSPORT_USB_CDC) { + return false; + } + if (!running || !usb_active || !dtr_ready) { return false; } @@ -343,8 +382,8 @@ static bool app_event_handler(const struct app_event_header *aeh) return handle_usb_state_event(cast_usb_state_event(aeh)); } - if (is_usb_cdc_tx_event(aeh)) { - return handle_usb_cdc_tx_event(cast_usb_cdc_tx_event(aeh)); + if (is_proto_tx_event(aeh)) { + return handle_proto_tx_event(cast_proto_tx_event(aeh)); } if (is_module_state_event(aeh)) { @@ -402,7 +441,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_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);