diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e5ce963..7b25bf2 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND incs "../components/system/source/shell") list(APPEND incs "drivers/data_port/usb-host") list(APPEND incs "drivers/data_port/ble_spp") list(APPEND incs "drivers/data_port/socket_inet") +list(APPEND incs "lib-out") diff --git a/app/config/app_config.c b/app/config/app_config.c index acdfee9..86a45a0 100644 --- a/app/config/app_config.c +++ b/app/config/app_config.c @@ -495,7 +495,7 @@ int app_cfg_set_fc_protocol_type(uint8_t type) int app_cfg_set_led_strip_sw(uint8_t sw) { - s_cfg_app.strip_sw = !!sw; + s_cfg_app.led_strip_ctrl_sw = !!sw; app_cfg_do_save(100); return 0; } diff --git a/app/config/app_config.h b/app/config/app_config.h index 43b551c..bf8477e 100644 --- a/app/config/app_config.h +++ b/app/config/app_config.h @@ -101,10 +101,10 @@ typedef struct // 设备配置统一数据结构 bool ap : 1; // 使用 WIFI AP 模式 bool sta : 1; // 使用 WIFI STA 模式 - bool strip_pwrup : 1; // 使用灯带上电效果 - bool strip_show_rf : 1; // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 - bool strip_link_fc : 1; // 开启灯带联动飞控:用于飞控状态监控(MSP) - bool bat_led_startup : 1; // 开启电量灯效 + bool strip_pwrup : 1; // 使用灯带上电效果 + bool strip_show_rf : 1; // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 + bool strip_link_fc : 1; // 开启灯带联动飞控:用于飞控状态监控(MSP) + char ws2812_bat_led_mode : 2; // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控 uint32_t reserve : 21; // 预留占位(原来是24个uint32) } capacity; @@ -114,7 +114,7 @@ typedef struct // 设备配置统一数据结构 uint8_t protocol_type; // @ref fc_comm_protocol_type_t } fc; - uint8_t strip_sw; // 记录当前灯带的模拟开关状态,0: 表示切换到由飞控控制, 1: 表示切换到由本固件控制 + uint8_t led_strip_ctrl_sw; // 记录当前灯带的模拟开关状态,0: 表示切换到由飞控控制, 1: 表示切换到由本固件控制 uint8_t armed2close_rf_sw; // 解锁后自动关闭射频功能的开关,0: 关, 1: 开 @@ -131,7 +131,9 @@ typedef struct // 设备配置统一数据结构 uint8_t temp_log_index : 5; // 温度日志最新索引 } temperature_log; - uint32_t reserve[37]; // 预留占位,下次更改时保证参数总长度不变,如超过预留长度后则当作新数据处理,sizeof(cfg_app_t) = 484UL + bool ws2812_bat_led_direction; // 0: 正向,1: 反向(正反向是指灯珠的连接方式,正向是指从第一个灯珠开始,反向是指从最后一个灯珠开始) + + uint32_t reserve[36]; // 预留占位,下次更改时保证参数总长度不变,如超过预留长度后则当作新数据处理,sizeof(cfg_app_t) = 484UL uint32_t crc32; // 校验数据(可放于任何位置) } cfg_app_t; diff --git a/app/config/app_config/SBDEMO.h b/app/config/app_config/SBDEMO.h index ed9f657..9a71309 100644 --- a/app/config/app_config/SBDEMO.h +++ b/app/config/app_config/SBDEMO.h @@ -1,7 +1,7 @@ #if (CONFIG_PRODUCT_ID_SBDEMO) -#define _DEFAULT_DEVICE_NAME_BLE "demo V1" -#define _DEFAULT_DEVICE_NAME_WIFI "demo V1-WIFI" +#define _DEFAULT_DEVICE_NAME_BLE "SpeedyBee DEMO-BLE" +#define _DEFAULT_DEVICE_NAME_WIFI "SpeedyBee DEMO-WIFI" #define _DEFAULT_DRONE_DATA "MODE1_1.0" static cfg_app_t const s_cfg_app_default = { @@ -46,13 +46,24 @@ static cfg_app_t const s_cfg_app_default = { /* 功能模块开关 */ .capacity = { - .pwrup_light = 0, // 短亮黄灯表示启动(方便观察是否有重启) + .pwrup_light = 1, // 短亮黄灯表示启动(方便观察是否有重启) .ble = 1, // 使用 BLE - .ap = 0, // 使用 WIFI AP 模式 - .sta = 0, // 使用 WIFI STA 模式 + .ap = 1, // 使用 WIFI AP 模式 + .sta = 1, // 使用 WIFI STA 模式 + + .strip_pwrup = 0, // 使用灯带上电效果 + .strip_show_rf = 0, // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 + .strip_link_fc = 0, // 开启灯带联动飞控 + .ws2812_bat_led_mode = 1, // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控 }, - .armed2close_rf_sw = 1, // 解锁后自动关闭射频功能的开关,0:关, 1:开 + .ws2812_bat_led_direction = 0, // 0: 正向,1: 反向(正反向是指灯珠的连接方式,正向是指从第一个灯珠开始,反向是指从最后一个灯珠开始) + .temperature_log = { + .temp_log_on = 0, // 温度日志开关 + .temp_log_index = 0, // 温度日志最新索引 + }, + .armed2close_rf_sw = 0, // 解锁后自动关闭射频功能的开关,0:关, 1:开 .product_id = PRODUCT_ID, // 产品 ID + .gyro_heat_value = 0, // 陀螺仪加热值,单位温度,0为关闭,最大值为80℃ }; #endif diff --git a/app/drivers/data_port/usb-host/msc/msc_host.c b/app/drivers/data_port/usb-host/msc/msc_host.c index aff928b..0837ebb 100755 --- a/app/drivers/data_port/usb-host/msc/msc_host.c +++ b/app/drivers/data_port/usb-host/msc/msc_host.c @@ -288,13 +288,15 @@ volatile static int s_out_buffered_data_len = 0; (setup_pkt_ptr)->wLength = 255; \ }) +#ifndef USB_SETUP_PACKET_INIT_GET_STATUS #define USB_SETUP_PACKET_INIT_GET_STATUS(setup_pkt_ptr) ({ \ (setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \ - (setup_pkt_ptr)->bRequest = STM32_DFU_REQUEST_GETSTATUS; \ + (setup_pkt_ptr)->bRequest = STM32_DFU_REQUEST_GETSTATUS; \ (setup_pkt_ptr)->wValue = 0; \ (setup_pkt_ptr)->wIndex = 0; \ (setup_pkt_ptr)->wLength = 6; \ }) +#endif #define USB_SETUP_PACKET_INIT_CLEAR_STATUS(setup_pkt_ptr) ({ \ (setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \ diff --git a/app/drivers/data_port/usb-host/usbport.c b/app/drivers/data_port/usb-host/usbport.c index 14af70c..6b0b47d 100644 --- a/app/drivers/data_port/usb-host/usbport.c +++ b/app/drivers/data_port/usb-host/usbport.c @@ -18,6 +18,8 @@ #include "errno.h" #include "esp_vfs.h" +#include "spbelib_interface.h" + #include "config/hardware_define.h" // #include "usb/cdc_acm_host.h" @@ -58,7 +60,7 @@ typedef struct } __usb_data_t; static QueueHandle_t app_queue; -static SemaphoreHandle_t ready_to_uninstall_usb; +// static SemaphoreHandle_t ready_to_uninstall_usb; static msc_host_vfs_handle_t vfs_handle; static usbport_status_e g_usb_status = USBPORT_STATUS_NO_CONNECTION; @@ -89,6 +91,7 @@ static SemaphoreHandle_t s_usb_write_mux = NULL; static portMUX_TYPE s_out_ringbuf_mux = portMUX_INITIALIZER_UNLOCKED; volatile static int s_in_buffered_data_len = 0; volatile static int s_out_buffered_data_len = 0; +volatile static usb_connect_type_t s_usb_connect_type = USB_CONNECTED_UNKNOWN; //////////// End CDC 全局变量 //////////// @@ -100,27 +103,41 @@ static uint16_t g_msc_file_count = 0; //////////// End MSC 全局变量 //////////// +static TaskHandle_t s_usb_task_handle, s_device_task_handle; //, workthread_handle; + static void usb_device_event_cb(const msc_host_event_t *event, void *arg) { switch (event->event) { case MSC_DEVICE_CONNECTED: + s_usb_connect_type = USB_CONNECTED_MSC; SYS_LOG_INF("MSC device connected"); + sblib_send_event(LIB_EVENT_USBH_MSC, 0, NULL); break; case MSC_DEVICE_DISCONNECTED: + s_usb_connect_type = USB_CONNECTED_UNKNOWN; SYS_LOG_INF("MSC device disconnected"); + sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL); break; case CDC_DEVICE_CONNECTED: + s_usb_connect_type = USB_CONNECTED_CDC; SYS_LOG_INF("CDC device connected"); + sblib_send_event(LIB_EVENT_USBH_CDC, 0, NULL); break; case CDC_DEVICE_DISCONNECTED: + s_usb_connect_type = USB_CONNECTED_UNKNOWN; SYS_LOG_INF("CDC device disconnected"); + sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL); break; case DFU_DEVICE_CONNECTED: + s_usb_connect_type = USB_CONNECTED_DFU; SYS_LOG_INF("DFU device connected"); + sblib_send_event(LIB_EVENT_USBH_DFU, 0, NULL); break; case DFU_DEVICE_DISCONNECTED: + s_usb_connect_type = USB_CONNECTED_UNKNOWN; SYS_LOG_INF("DFU device disconnected"); + sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL); break; } @@ -133,20 +150,26 @@ static void handle_usb_events(void *args) while (1) { uint32_t event_flags; + SYS_LOG_INF("usb_host_lib_handle_events(portMAX_DELAY, &event_flags);"); usb_host_lib_handle_events(portMAX_DELAY, &event_flags); // Release devices once all clients has deregistered if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { + SYS_LOG_INF("usb_host_device_free_all();"); usb_host_device_free_all(); + // SYS_LOG_INF("xSemaphoreGive(ready_to_uninstall_usb);"); + // xSemaphoreGive(ready_to_uninstall_usb); + break; } // Give ready_to_uninstall_usb semaphore to indicate that USB Host library // can be deinitialized, and terminate this task. - if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) - { - xSemaphoreGive(ready_to_uninstall_usb); - } + // if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) + // { + // SYS_LOG_INF("xSemaphoreGive(ready_to_uninstall_usb);"); + // xSemaphoreGive(ready_to_uninstall_usb); + // } } - + s_usb_task_handle = NULL; vTaskDelete(NULL); } @@ -308,6 +331,7 @@ static void handle_device_events(void *args) msc_host_event_t app_event; while (1) { + SYS_LOG_INF("xQueueReceive(app_queue, &app_event, portMAX_DELAY);"); xQueueReceive(app_queue, &app_event, portMAX_DELAY); switch (app_event.event) @@ -501,19 +525,22 @@ static int _usbhost_port_read(sb_data_port_t *port, void *buffer, uint32_t lengt } } +static bool s_is_started = false; static int _usbhost_start(sb_data_port_t *port) { + s_is_started = true; return 0; } static int _usbhost_stop(sb_data_port_t *port) { + s_is_started = false; return 0; } static bool _usbhost_is_started(sb_data_port_t *port) { - return true; + return s_is_started; } static uint32_t _usbhost_get_rx_length(sb_data_port_t *port) @@ -705,8 +732,11 @@ static sb_data_port_vtable_t const usbhost_port_vtable = { //////////// STM32固件升级相关的函数结束 ////////////// +// static TaskHandle_t s_usb_task_handle, s_device_task_handle; //, workthread_handle; + int usbport_init(void) { + SYS_LOG_INF("usbport_init"); if (s_port.vtable) { SYS_LOG_WRN("repeated initialize"); @@ -716,26 +746,33 @@ int usbport_init(void) s_port.vtable = &usbhost_port_vtable; s_port.data = &s_usb_data; - TaskHandle_t usb_task_handle, device_task_handle; //, workthread_handle; - memset(&s_usb_data, 0, sizeof(__usb_data_t)); os_pipe_create(&s_usb_data.pipe_obj, 1024 * 2); - ready_to_uninstall_usb = xSemaphoreCreateBinary(); + // if (ready_to_uninstall_usb == NULL) + // { + // ready_to_uninstall_usb = xSemaphoreCreateBinary(); + // } app_queue = xQueueCreate(3, sizeof(msc_host_event_t)); assert(app_queue); static usb_host_config_t const host_config = { - // .skip_phy_setup = false, + .skip_phy_setup = false, .intr_flags = ESP_INTR_FLAG_LEVEL1, }; ESP_ERROR_CHECK(usb_host_install(&host_config)); - xTaskCreatePinnedToCore(handle_usb_events, "usb_events", 4096, NULL, SBTASK_PRIORITY_USB_HOST, &usb_task_handle, SBTASK_CORE_INDEX_USB_HOST); - assert(usb_task_handle); - xTaskCreatePinnedToCore(handle_device_events, "device_events", 4096, NULL, SBTASK_PRIORITY_USB_DEVICE, &device_task_handle, SBTASK_CORE_INDEX_USB_DEVICE); - assert(device_task_handle); + if (s_usb_task_handle == NULL) + { + xTaskCreatePinnedToCore(handle_usb_events, "usb_events", 4096, NULL, SBTASK_PRIORITY_USB_HOST, &s_usb_task_handle, SBTASK_CORE_INDEX_USB_HOST); + assert(s_usb_task_handle); + } + if (s_device_task_handle == NULL) + { + xTaskCreatePinnedToCore(handle_device_events, "device_events", 4096, NULL, SBTASK_PRIORITY_USB_DEVICE, &s_device_task_handle, SBTASK_CORE_INDEX_USB_DEVICE); + assert(s_device_task_handle); + } const msc_host_driver_config_t msc_config = { .create_backround_task = true, @@ -748,6 +785,70 @@ int usbport_init(void) return 0; } +void usbport_deinit(void) +{ + SYS_LOG_INF("usbport_deinit"); + if (s_port.vtable == NULL) + { + SYS_LOG_WRN("usb host not initialized"); + return; + } + + if (g_connected_usb_device) + { + if (vfs_handle) + { + msc_host_vfs_unregister(vfs_handle); + vfs_handle = NULL; + } + msc_host_uninstall_device(g_connected_usb_device); + g_connected_usb_device = NULL; + } + + if (g_cdc_dev) + { + cdc_host_close(g_cdc_dev); + g_cdc_dev = NULL; + } + + ESP_ERROR_CHECK(msc_host_uninstall()); + + vTaskDelay(pdMS_TO_TICKS(100)); + + // if (s_device_task_handle) + // { + // vTaskDelete(s_device_task_handle); + // s_device_task_handle = NULL; + // } + + // if (s_usb_task_handle) + // { + // vTaskDelete(s_usb_task_handle); + // s_usb_task_handle = NULL; + // } + + ESP_ERROR_CHECK(usb_host_uninstall()); + + if (app_queue) + { + vQueueDelete(app_queue); + app_queue = NULL; + } + + // if (ready_to_uninstall_usb) + // { + // vSemaphoreDelete(ready_to_uninstall_usb); + // ready_to_uninstall_usb = NULL; + // } + + if (os_pipe_is_valid(&s_usb_data.pipe_obj)) + { + os_pipe_delete(&s_usb_data.pipe_obj); + } + + s_port.vtable = NULL; +} + sb_data_port_t *usbport_bind(os_work_t *rx_resume_work) { if (s_port.data == NULL) @@ -764,6 +865,21 @@ sb_data_port_t *usbport_bind(os_work_t *rx_resume_work) return &s_port; } +void usbport_unbind(sb_data_port_t *port) +{ + if (port == NULL) + { + SYS_LOG_WRN("usb host not initialized"); + return; + } + + __usb_data_t *usb_data = port->data; + + os_pipe_unregist(&usb_data->pipe_obj); + + usb_data->rx_resume_work = NULL; +} + usbport_status_e usbport_get_state(void) { return g_usb_status; @@ -785,3 +901,8 @@ msc_file_info *msc_get_cached_file_list(uint16_t *out_file_count) } return g_msc_file_lists; } + +usb_connect_type_t usbport_get_usb_type(void) +{ + return s_usb_connect_type; +} diff --git a/app/drivers/data_port/usb-host/usbport.h b/app/drivers/data_port/usb-host/usbport.h index 4b27c21..4d41a7e 100644 --- a/app/drivers/data_port/usb-host/usbport.h +++ b/app/drivers/data_port/usb-host/usbport.h @@ -62,7 +62,10 @@ typedef struct #pragma pack(pop) int usbport_init(void); +void usbport_deinit(void); sb_data_port_t *usbport_bind(os_work_t *rx_resume_work); +void usbport_unbind(sb_data_port_t *port); + usbport_status_e usbport_get_state(void); // 读取flash layout信息 @@ -111,3 +114,12 @@ void _usbh_pre_disconnect_deivce(void); msc_file_info *msc_get_file_list(uint16_t *out_file_count, const excluding_file_item_t *excluding_files, uint8_t excluding_file_count); msc_file_info *msc_get_cached_file_list(uint16_t *out_file_count); +typedef enum +{ + USB_CONNECTED_CDC = 0, + USB_CONNECTED_DFU = 1, + USB_CONNECTED_MSC = 2, + USB_CONNECTED_UNKNOWN = 3, +} usb_connect_type_t; + +usb_connect_type_t usbport_get_usb_type(void); diff --git a/app/led_strip/Kconfig b/app/led_strip/Kconfig index a0790b1..4cfa6b5 100644 --- a/app/led_strip/Kconfig +++ b/app/led_strip/Kconfig @@ -2,7 +2,13 @@ config LED_STRIP_MAX_LEDS depends on CAP_LED_STRIP int "最大灯珠数" range 1 164 - default 88 + default 164 + +config LED_STRIP_MIN_LEDS + depends on CAP_LED_STRIP + int "最小灯珠数" + range 1 64 + default 64 config LED_STRIP_DEFAULT_LEDS depends on CAP_LED_STRIP @@ -10,4 +16,22 @@ config LED_STRIP_DEFAULT_LEDS range 1 LED_STRIP_MAX_LEDS default LED_STRIP_MAX_LEDS +config LED_STRIP_MAX_LAYER + depends on CAP_LED_STRIP + int "最大图层数" + range 1 8 + default 2 +menuconfig LED_STRIP_RACING_MODE + depends on CAP_LED_STRIP + bool "编译竞速模式" + default n + help + 竞速飞塔项目新增的选项,通过收藏列表中的默认主题快速来实现仅一个简单的效果 + + config LED_STRIP_DEFAULT_FAVORITE_ID + depends on LED_STRIP_RACING_MODE + int "选择默认主题。对应代码中 led_ctrl_playmode_t 的枚举值" + range 1 14 + default 18 + diff --git a/app/lib-out/spbelib_interface.h b/app/lib-out/spbelib_interface.h new file mode 100644 index 0000000..6bd4a61 --- /dev/null +++ b/app/lib-out/spbelib_interface.h @@ -0,0 +1,194 @@ +/** + * @file spbelib_interface.h + * @author LokLiang + * @brief 无线调参功能接口 + * @version 0.1 + * @date 2025-03-14 + * + * @copyright Copyright (c) 2025 + * + */ + +#pragma once + +#include "sys_types.h" + +typedef enum +{ + SBLIB_INIT_WIRE_TUNE = 0, // 初始化为无线调参功能 + SBLIB_INIT_ADAPTER, // 初始化为 小黄砖4 功能 +} sblib_init_t; + +/** + * @brief 初始化功能库。 + */ +void sblib_init(sblib_init_t init_type); + +/*************************************************************************************************/ +/**** 事件操作部分 ********************************************************************************/ +/*************************************************************************************************/ + +/** + * @brief 注册事件回调函数。 + * 当有关于小黄砖功能的事件发生或接收到数据时,调用回调函数。 + * 由 lib_notify_event() 和 sblib_notify_datastream() 函数调用。 + */ +typedef void (*lib_notify_cb)(void); + +typedef enum __packed // 小黄砖功能控制命令 +{ + LIB_CONTROL_FCPORT_OFF, // 关闭飞控数据接口 + LIB_CONTROL_FCPORT_UART, // 使用 UART 连接飞控 + LIB_CONTROL_FCPORT_OTG, // 使用 OTG 连接飞控 + + LIB_CONTROL_RF_OFF, // 关闭射频连接 + LIB_CONTROL_RF_BLE, // 打开 BLE + LIB_CONTROL_RF_AP, // 打开 WIFI(AP) + LIB_CONTROL_RF_STA, // 打开 WIFI(STA) +} lib_control_t; + +typedef enum __packed // 小黄砖通知的事件类型 +{ + LIB_EVENT_NONE = 0, + + LIB_EVENT_FC_PORT_OFF, // 飞控数据接口关闭。参数:无 + LIB_EVENT_FC_PORT_UART, // 飞控数据接口为串口。参数:无 + LIB_EVENT_FC_PORT_OTG, // 飞控数据接口为 USBH。参数:无 + + LIB_EVENT_USBH_NO_START, // USBH 接口未启动。参数:无 + LIB_EVENT_USBH_CDC, // USBH 接口已连接 CDC 设备。参数:无 + LIB_EVENT_USBH_DFU, // USBH 接口已连接 DFU 设备。参数:无 + LIB_EVENT_USBH_MSC, // USBH 接口已连接 MSC 设备。参数:无 + LIB_EVENT_USBH_UNKNOW_DEVICE, // USBH 接口已连接未知设备。参数:无 + + LIB_EVENT_RF_OFF, // 无线连接已关闭。参数:无 + LIB_EVENT_RF_CHANGE_MODE, // 提示模式切换已就绪。参数:无 + LIB_EVENT_RF_BLE_IDLE, // 蓝牙模式未连接。参数:无 + LIB_EVENT_RF_BLE_CONNECTED, // 蓝牙模式已连接。参数:无 + LIB_EVENT_RF_AP_IDLE, // WIFI AP 模式未连接。参数:无 + LIB_EVENT_RF_AP_CONNECTED, // WIFI AP 模式已连接。参数:无 + LIB_EVENT_RF_STA_IDLE, // WIFI STA 模式未连接。参数:无 + LIB_EVENT_RF_STA_CONNECTED, // WIFI STA 模式已连接。参数:已连接设备的 MAC 地址 + + LIB_EVENT_BLE_NAME_SET, // BLE 名称已设置。参数:无 + LIB_EVENT_BLE_PASSWD_SET, // BLE 密码已设置。参数:无 + LIB_EVENT_WIFI_AP_SSID_SET, // WIFI AP SSID 已设置。参数:无 + LIB_EVENT_WIFI_AP_PASSWD_SET, // WIFI AP 密码已设置。参数:无 + LIB_EVENT_WIFI_STA_SSID_SET, // WIFI STA SSID 已设置。参数:无 + LIB_EVENT_WIFI_STA_PASSWD_SET, // WIFI STA 密码已设置。参数:无 + + LIB_EVENT_MAX +} lib_event_type_t; + +typedef struct // 小黄砖通知的事件数据 +{ + lib_event_type_t type; // 事件类型 + uint8_t len; // data[] 有效数据长度 + uint8_t data[6]; // 事件数据 +} lib_event_t; + +/** + * @brief 执行对小黄砖功能的控制。 + * + * @param control 控制命令 + * @retval 0 表示成功; -1 表示失败。 + */ +int sblib_control(lib_control_t control); + +/** + * @brief 注册事件回调函数。 + * 当有关于小黄砖的新事件发生时,将调用指定的回调函数以通知上层应用。 + * 内部可缓存的记录数为 32 个。 + * 使用 sblib_get_event() 可读取这些记录,读取后会清除记录。 + * + * @param cb 指定的回调函数。建议在回调函数中执行发送信号的操作。 + */ +void sblib_regist_notify_event(lib_notify_cb cb); + +/** + * @brief 获取小黄砖的事件。线程和中断可用。 + * + * @return lib_event_t + */ +lib_event_t sblib_get_event(void); + +/** + * @brief 发送通知。 + * 通知信息保存到内部队列中,长度为 32。 + * 每次发送通知时,由 sblib_regist_notify_event() 注册的回调函数会被调用。 + * @param type 事件类型 + * @param len 事件数据长度。范围 0..6。如果取值大于最大值时,事件数据被截断。 + * @param data 事件数据 + */ +void sblib_send_event(lib_event_type_t type, uint8_t len, const uint8_t data[]); + +/*************************************************************************************************/ +/**** 通过无线接口与 APP 通讯部分 ******************************************************************/ +/*************************************************************************************************/ + +/** + * @brief 当无线接口接收到 APP 数据时的回调函数。 + * @param port 收到的端口号,这个号码与注册时的 port 一致。 + * @param cmd 收到的命令代号,这个号码与注册时的 cmd 一致。 + * @param payload 收到的数据指针,指向数据的内存地址。 + * @param size 收到的数据长度。 + */ +typedef void (*cmd_func_cb)(uint8_t port, uint8_t cmd, const void *payload, uint16_t size); + +typedef enum +{ + SBLIB_CMD_PORT_DEBUG = 0, // 保留的端口,用于 debug 等 + SBLIB_CMD_PORT_ADAPTER, // 无线调参扩展命令集 + SBLIB_CMD_PORT_FINDTAG, // 寻机命令集 + SBLIB_CMD_PORT_JOYSTICK, // 遥控器命令集 + SBLIB_CMD_PORT_ELRS, // 接收机命令集 +} sblib_cmd_port_t; + +typedef struct // 注册命令的结构体 +{ + uint8_t cmd; // 命令代号 + cmd_func_cb cb; // 命令处理函数 +} sblib_cmd_t; + +typedef enum // 返回的发送状态 +{ + SBLIB_SEND_STATUS_OK = 0, // 当前等发送数据已缓存到待发送区中,数据将会被发送 + SBLIB_SEND_STATUS_NO_SPACE, // 当前没有缓存空间,数据不会被处理 + SBLIB_SEND_STATUS_NO_CONNECT, // 当前没有连接,数据不会被处理 +} sblib_cmd_send_status_t; + +/** + * @brief 注册一个通过无线接口接收 APP 数据的外部命令集。 + * 当收到 APP 发出的命令和数据时,会调 cmd_struct 中对应的 port 和 cmd 的函数。 + * 回调过程中允许调用 sblib_send_event() 向 APP 发送数据。 + * 注意:回调函数附带的参数不会被缓存,并且必须尽快处理,如果需要缓存需要自行处理。 + * + * @param port 端口号。一个端口号对应一个应用的命令集合标识,具体序号由收发双方的应用层协商,一旦确定后,不能更改。收发双向都使用同一个端口号。 + * @param cmd_struct 指向一个命令集合的结构体数组。这个命令集合与参数 port 绑定。当收到 APP 发出的命令时,会调 cmd_struct 中对应的 port 和 cmd 的函数。 + * @param struct_size 命令集结构体大小。使用 sizeof() 计算。 + * @retval 0 成功 + * @retval -1 失败:内置预设的命令集已满,无法注册新的命令集。 + */ +int sblib_register_cmd(sblib_cmd_port_t port, const sblib_cmd_t *cmd_struct, uint32_t struct_size); + +/** + * @brief 通过无线接口发送数据到 APP。 + * 发送的数据会被缓存到待发送区中,当收到 APP 的回应时缓存会被自动清除,通过 sblib_get_cmd_sned_buf() 函数可以获取当前未被成功发送的数据包的数量。 + * + * @param port 端口号。一个端口号对应一个应用的命令集合标识,具体序号由收发双方的应用层协商,一旦确定后,不能更改。收发双向都使用同一个端口号。 + * @param cmd 命令代号。命令代号由收发双方的应用层协商,一旦确定后,不能更改。 + * @param data 数据指针。指向要发送的数据的内存地址。指向的内存地址的数据会被复制到缓存区中,发送结束后会被自动释放。 + * @param length 数据长度。长度任意,建议最大为 1460 字节 + * @return + * SBLIB_SEND_STATUS_OK 当前等发送数据已缓存到待发送区中,数据将会被发送 + * SBLIB_SEND_STATUS_NO_SPACE 当前没有缓存空间,数据不会被处理 + * SBLIB_SEND_STATUS_NO_CONNECT 当前没有连接,数据不会被处理 + */ +sblib_cmd_send_status_t sblib_cmd_send(sblib_cmd_port_t port, uint8_t cmd, const void *data, uint16_t length); + +/** + * @brief 获取当前已缓存但未发送成功的数据包的数量。 + * + * @return uint32_t 未发送完成的数据包的数量 + */ +uint32_t sblib_get_cmd_sned_buf(void); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt deleted file mode 100644 index 6da7f0a..0000000 --- a/components/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -list(APPEND incs "system/include") - -list(APPEND srcs "system/source/k_kit/k_kit.c") -list(APPEND srcs "system/source/shell/sh_vt100.c") -list(APPEND srcs "system/source/shell/sh_vset.c") -list(APPEND srcs "system/source/shell/sh.c") - -idf_component_register( - INCLUDE_DIRS ${incs} - SRCS ${srcs} -) diff --git a/components/system/CMakeLists.txt b/components/system/CMakeLists.txt new file mode 100644 index 0000000..d1429fd --- /dev/null +++ b/components/system/CMakeLists.txt @@ -0,0 +1,11 @@ +list(APPEND incs "include") + +list(APPEND srcs "source/k_kit/k_kit.c") +list(APPEND srcs "source/shell/sh_vt100.c") +list(APPEND srcs "source/shell/sh_vset.c") +list(APPEND srcs "source/shell/sh.c") + +idf_component_register( + INCLUDE_DIRS ${incs} + SRCS ${srcs} +) diff --git a/components/system/include/drivers/chip/misc.h b/components/system/include/drivers/chip/misc.h index 1ff12e9..b2a9be6 100755 --- a/components/system/include/drivers/chip/misc.h +++ b/components/system/include/drivers/chip/misc.h @@ -21,6 +21,15 @@ void drv_misc_busy_wait(unsigned us); */ unsigned *drv_misc_bitband(void *mem); +/** + * @brief 读取 MCU 身份信息的 MD5 值 + * + * @param out[out] 输出 + * @retval 0 成功 + * @retval -1 失败 + */ +int drv_misc_read_id_md5(unsigned char out[16]); + /** * @brief 设置中断向量地址 * diff --git a/components/system/include/drivers/chip/tim.h b/components/system/include/drivers/chip/tim.h index 669c21f..7629b4b 100755 --- a/components/system/include/drivers/chip/tim.h +++ b/components/system/include/drivers/chip/tim.h @@ -51,7 +51,7 @@ void drv_pwm_pin_configure(hal_id_t id, uint8_t pin); void drv_pwm_enable(hal_id_t id); void drv_pwm_disable(hal_id_t id); -void drv_pwm_init(hal_id_t id, unsigned period_ns, unsigned reload_enable); +void drv_pwm_init(hal_id_t id, unsigned channel_mask, unsigned period_ns, unsigned reload_enable); void drv_pwm_deinit(hal_id_t id); int drv_pwm_irq_callback_enable(hal_id_t id, tim_isr_cb_fn cb); diff --git a/components/system/source/k_kit/kk.h b/components/system/source/k_kit/kk.h index c533e9b..a8246fa 100755 --- a/components/system/source/k_kit/kk.h +++ b/components/system/source/k_kit/kk.h @@ -40,9 +40,10 @@ typedef k_pipe_t kk_pipe_t; #define kk_work_q_delete() k_work_q_delete(WORK_Q_HDL) // 删除一个工作队列的对象 #define kk_work_q_is_valid() k_work_q_is_valid(WORK_Q_HDL) // 获取工作队列是否有效 -#define kk_work_create(work_handle, work_route, arg, priority) k_work_create(work_handle, #work_route, work_route, arg, priority) // 创建由工作队列管理的任务 -#define kk_work_delete(work_handle) k_work_delete(work_handle) // 删除由工作队列管理的任务 -#define kk_work_submit(work_q_handle, work_handle, delay) k_work_submit(work_q_handle, work_handle, delay) // 多少时间后唤醒任务 +#define kk_work_create(work_handle, work_route, arg, priority) k_work_create(work_handle, #work_route, work_route, arg, priority) // 创建由工作队列管理的任务 +#define kk_work_create_default(work_handle, work_route, arg, priority, delay) k_work_create_default(work_handle, #work_route, work_route, arg, priority, delay) // 创建由工作队列管理的任务,使用默认的工作队列 +#define kk_work_delete(work_handle) k_work_delete(work_handle) // 删除由工作队列管理的任务 +#define kk_work_submit(work_q_handle, work_handle, delay) k_work_submit(work_q_handle, work_handle, delay) // 多少时间后唤醒任务 #define kk_work_is_valid(work_handle) k_work_is_valid(work_handle) // 获取任务对象是否有效 #define kk_work_is_pending(work_handle) k_work_is_pending(work_handle) // 获取任务是否在就绪或延时的状态 diff --git a/components/system/source/shell/sh.c b/components/system/source/shell/sh.c index ffffecb..37a5b08 100755 --- a/components/system/source/shell/sh.c +++ b/components/system/source/shell/sh.c @@ -469,43 +469,40 @@ static void _find_and_run_key(sh_t *sh_hdl, char c) */ static void _insert_str(sh_t *sh_hdl, const char *str) { + int remain = _SH_ARRAY_COUNT(sh_hdl->cmd_line) - (sh_hdl->cmd_buf - sh_hdl->cmd_line) - sh_hdl->cmd_stored - 1; // -1: 保留 '\0' int len = strlen(str); + if (len > remain) + { + len = remain; + } if (len) { - int remain = _SH_ARRAY_COUNT(sh_hdl->cmd_line) - (sh_hdl->cmd_buf - sh_hdl->cmd_line) - sh_hdl->cmd_stored - 1; - if (len > remain) - { - len = remain; - } _apply_history(sh_hdl); - if (sh_hdl->cmd_stored < remain) + if (sh_hdl->port.insert_str) /* 设置终端插入一个字符 */ { - if (sh_hdl->port.insert_str) /* 设置终端插入一个字符 */ - { - sh_hdl->port.insert_str(sh_hdl, str); - } + sh_hdl->port.insert_str(sh_hdl, str); + } - for (int i = sh_hdl->cmd_stored - 1 + len; i > sh_hdl->cmd_input; i--) /* 使光标之后的数据往后移动 len 个字节 */ - { - sh_hdl->cmd_buf[i] = sh_hdl->cmd_buf[i - len]; - } + for (int i = sh_hdl->cmd_stored - 1 + len; i > sh_hdl->cmd_input; i--) /* 使光标之后的数据往后移动 len 个字节 */ + { + sh_hdl->cmd_buf[i] = sh_hdl->cmd_buf[i - len]; + } - for (int i = 0; i < len; i++) - { - sh_hdl->cmd_buf[sh_hdl->cmd_input + i] = str[i]; - } + for (int i = 0; i < len; i++) + { + sh_hdl->cmd_buf[sh_hdl->cmd_input + i] = str[i]; + } - sh_hdl->cmd_input += len; - sh_hdl->cmd_stored += len; - sh_hdl->sync_cursor += len; + sh_hdl->cmd_input += len; + sh_hdl->cmd_stored += len; + sh_hdl->sync_cursor += len; - sh_hdl->cmd_buf[sh_hdl->cmd_stored] = '\0'; + sh_hdl->cmd_buf[sh_hdl->cmd_stored] = '\0'; - /* 启用刷新命令行模式 */ - if (sh_hdl->port.clear_line) - { - sh_refresh_line(sh_hdl); - } + /* 启用刷新命令行模式 */ + if (sh_hdl->port.clear_line) + { + sh_refresh_line(sh_hdl); } } } @@ -525,7 +522,7 @@ static char *_parse_input(int *argc, const char *argv[], char *dest, const char char *ret = dest; bool end = false; *argc = 0; - while (end == false && *argc < CONFIG_SH_MAX_PARAM) + while (*src != '\0' && end == false && *argc < CONFIG_SH_MAX_PARAM) { int len = 0; @@ -2763,6 +2760,7 @@ void sh_ctrl_print_cmd_line(sh_t *sh_hdl) sh_echo(sh_hdl, line); sh_hdl->cmd_input = strlen(line); + sh_hdl->cmd_stored = sh_hdl->cmd_input; sh_hdl->sync_cursor = sh_hdl->cmd_input; _update_cursor(sh_hdl); } diff --git a/sdkconfig_defaults/sdkconfig.release_ESPEVB_esp32s3_evb.defaults b/sdkconfig_defaults/sdkconfig.release_ESPEVB_esp32s3_evb.defaults index aeacac7..7bf15a7 100644 --- a/sdkconfig_defaults/sdkconfig.release_ESPEVB_esp32s3_evb.defaults +++ b/sdkconfig_defaults/sdkconfig.release_ESPEVB_esp32s3_evb.defaults @@ -1,5 +1,5 @@ # This file was generated using idf.py save-defconfig. It can be edited manually. -# Espressif IoT Development Framework (ESP-IDF) 5.2.1 Project Minimal Configuration +# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration # CONFIG_IDF_TARGET="esp32s3" CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y @@ -8,11 +8,10 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_BOARD_NAME_DEVKIT_ESP32S3=y CONFIG_BUILD_WIFI=y CONFIG_BT_ENABLED=y -CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1=y CONFIG_BT_LOG_HCI_TRACE_LEVEL_ERROR=y CONFIG_BT_LOG_APPL_TRACE_LEVEL_ERROR=y CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y -CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P21=y +CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P20=y CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y CONFIG_ESP_IPC_TASK_STACK_SIZE=1536 diff --git a/sdkconfig_defaults/sdkconfig.release_SBDEMO_esp32s3.defaults b/sdkconfig_defaults/sdkconfig.release_SBDEMO_esp32s3.defaults index e36fa7a..ebf37e2 100644 --- a/sdkconfig_defaults/sdkconfig.release_SBDEMO_esp32s3.defaults +++ b/sdkconfig_defaults/sdkconfig.release_SBDEMO_esp32s3.defaults @@ -12,7 +12,7 @@ CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1=y CONFIG_BT_LOG_HCI_TRACE_LEVEL_ERROR=y CONFIG_BT_LOG_APPL_TRACE_LEVEL_ERROR=y CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y -CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P21=y +CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P20=y CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y CONFIG_ESP_IPC_TASK_STACK_SIZE=1536