diff --git a/app/config/app_config.c b/app/config/app_config.c index 86a45a0..d9ecfa5 100644 --- a/app/config/app_config.c +++ b/app/config/app_config.c @@ -526,6 +526,25 @@ int app_cfg_set_mac_tab(uint8_t mac[6]) return 0; } +int app_cfg_set_ble_mac_tab(uint8_t mac[6]) +{ + for (int i = 0; i < __ARRAY_SIZE(s_cfg_app.ble_mac_tab); i++) + { + if (memcmp(mac, s_cfg_app.ble_mac_tab[i], 6) == 0) + { + return 0; + } + } + + if (++s_cfg_app.ble_mac_index >= __ARRAY_SIZE(s_cfg_app.ble_mac_tab)) + { + s_cfg_app.ble_mac_index = 0; + } + memcpy(s_cfg_app.ble_mac_tab[s_cfg_app.ble_mac_index], mac, sizeof(s_cfg_app.ble_mac_tab[0])); + app_cfg_do_save(1000); + return 0; +} + int app_cfg_set_temp_log_on(bool sw) { // SYS_LOG_INF("set temp log on: %d", sw); @@ -552,3 +571,15 @@ int app_cfg_set_gyro_heat_value(uint8_t value) app_cfg_do_save(100); return 0; } + +int app_cfg_set_bat_led_color(uint32_t color) +{ + if (color > 0xFFFFFF) + { + SYS_LOG_WRN("error color: %d", color); + return -1; + } + s_cfg_app.ws2812_bat_led_color = color & 0xFFFFFF; + app_cfg_do_save(100); + return 0; +} diff --git a/app/config/app_config.h b/app/config/app_config.h index bf8477e..3da8830 100644 --- a/app/config/app_config.h +++ b/app/config/app_config.h @@ -104,7 +104,7 @@ typedef struct // 设备配置统一数据结构 bool strip_pwrup : 1; // 使用灯带上电效果 bool strip_show_rf : 1; // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 bool strip_link_fc : 1; // 开启灯带联动飞控:用于飞控状态监控(MSP) - char ws2812_bat_led_mode : 2; // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控 + char ws2812_bat_led_mode : 3; // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控, 3: 固定翼飞控 uint32_t reserve : 21; // 预留占位(原来是24个uint32) } capacity; @@ -132,8 +132,12 @@ typedef struct // 设备配置统一数据结构 } temperature_log; bool ws2812_bat_led_direction; // 0: 正向,1: 反向(正反向是指灯珠的连接方式,正向是指从第一个灯珠开始,反向是指从最后一个灯珠开始) + uint32_t ws2812_bat_led_color; // 电量灯颜色, RGB颜色值,如 0xFFFFFF 代表白色(默认) - uint32_t reserve[36]; // 预留占位,下次更改时保证参数总长度不变,如超过预留长度后则当作新数据处理,sizeof(cfg_app_t) = 484UL + uint8_t ble_mac_index; // 记录当前通过 BLE 连接过的 APP 的 MAC 地址的序号 + uint8_t ble_mac_tab[6][6]; // 记录当前通过 BLE 连接过的 APP 的 MAC 地址, 6 个 MAC 地址,每个 MAC 地址 6 字节,判断是否 APP 设备连接,用于决定是否停止对飞控状态监测 + + uint32_t reserve[25]; // 预留占位,下次更改时保证参数总长度不变,如超过预留长度后则当作新数据处理,sizeof(cfg_app_t) = 484UL uint32_t crc32; // 校验数据(可放于任何位置) } cfg_app_t; @@ -182,8 +186,11 @@ int app_cfg_set_wifi_sta_ssid(const void *ssid); int app_cfg_set_wifi_sta_password(const void *password); int app_cfg_set_mac_tab(uint8_t mac[6]); +int app_cfg_set_ble_mac_tab(uint8_t mac[6]); int app_cfg_set_temp_log_on(bool sw); int app_cfg_set_temp_log_index(uint8_t index); int app_cfg_set_gyro_heat_value(uint8_t value); + +int app_cfg_set_bat_led_color(uint32_t color); diff --git a/app/config/app_config/SBDEMO.h b/app/config/app_config/SBDEMO.h index 9a71309..d3f57a4 100644 --- a/app/config/app_config/SBDEMO.h +++ b/app/config/app_config/SBDEMO.h @@ -54,9 +54,10 @@ static cfg_app_t const s_cfg_app_default = { .strip_pwrup = 0, // 使用灯带上电效果 .strip_show_rf = 0, // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 .strip_link_fc = 0, // 开启灯带联动飞控 - .ws2812_bat_led_mode = 1, // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控 + .ws2812_bat_led_mode = 1, // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控, 3: 固定翼飞控 }, - .ws2812_bat_led_direction = 0, // 0: 正向,1: 反向(正反向是指灯珠的连接方式,正向是指从第一个灯珠开始,反向是指从最后一个灯珠开始) + .ws2812_bat_led_direction = 0, // 0: 正向,1: 反向(正反向是指灯珠的连接方式,正向是指从第一个灯珠开始,反向是指从最后一个灯珠开始) + .ws2812_bat_led_color = 0xFFFFFF, // 电量灯颜色, RGB颜色值,如 0xFFFFFF 代表白色(默认) .temperature_log = { .temp_log_on = 0, // 温度日志开关 .temp_log_index = 0, // 温度日志最新索引 diff --git a/app/config/app_config/developing.h b/app/config/app_config/developing.h index e66ce08..75246f8 100644 --- a/app/config/app_config/developing.h +++ b/app/config/app_config/developing.h @@ -50,9 +50,21 @@ static cfg_app_t const s_cfg_app_default = { .ble = 1, // 使用 BLE .ap = 0, // 使用 WIFI AP 模式 .sta = 0, // 使用 WIFI STA 模式 + + .strip_pwrup = 0, // 使用灯带上电效果 + .strip_show_rf = 0, // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 + .strip_link_fc = 0, // 开启灯带联动飞控 + .ws2812_bat_led_mode = 0, // 电量灯效, 0: 关闭, 1: 普通飞控, 2: 竞速飞控, 3: 固定翼飞控 }, - .armed2close_rf_sw = 1, // 解锁后自动关闭射频功能的开关,0:关, 1:开 + .ws2812_bat_led_direction = 0, // 0: 正向,1: 反向(正反向是指灯珠的连接方式,正向是指从第一个灯珠开始,反向是指从最后一个灯珠开始) + .ws2812_bat_led_color = 0xFFFFFF, // 电量灯颜色, RGB颜色值,如 0xFFFFFF 代表白色(默认) + .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/ble_spp/ble_spp_server.c b/app/drivers/data_port/ble_spp/ble_spp_server.c index 635555d..caa6ed9 100644 --- a/app/drivers/data_port/ble_spp/ble_spp_server.c +++ b/app/drivers/data_port/ble_spp/ble_spp_server.c @@ -1194,3 +1194,17 @@ const uint8_t *ble_server_get_mac(void) { return s_mac; } + +/** + * @brief 获取远程设备的 MAC 地址 + * + * @return const uint8_t* MAC[6] + */ +void ble_server_get_remote_mac(uint8_t *mac) +{ + if (mac == NULL) + { + return; + } + memcpy(mac, spp_remote_bda, sizeof(esp_bd_addr_t)); +} diff --git a/app/drivers/data_port/ble_spp/ble_spp_server.h b/app/drivers/data_port/ble_spp/ble_spp_server.h index 4589e49..892ede8 100644 --- a/app/drivers/data_port/ble_spp/ble_spp_server.h +++ b/app/drivers/data_port/ble_spp/ble_spp_server.h @@ -48,3 +48,4 @@ ble_server_status_t ble_server_get_gap_status(void); uint32_t ble_server_get_mtu(void); const uint8_t *ble_server_get_mac(void); +void ble_server_get_remote_mac(uint8_t *mac); diff --git a/app/led_strip/Kconfig b/app/led_strip/Kconfig index 4cfa6b5..5b99267 100644 --- a/app/led_strip/Kconfig +++ b/app/led_strip/Kconfig @@ -7,7 +7,7 @@ config LED_STRIP_MAX_LEDS config LED_STRIP_MIN_LEDS depends on CAP_LED_STRIP int "最小灯珠数" - range 1 64 + range 1 68 default 64 config LED_STRIP_DEFAULT_LEDS diff --git a/app/lib-out/spbelib_interface.h b/app/lib-out/spbelib_interface.h index 6bd4a61..14d7f33 100644 --- a/app/lib-out/spbelib_interface.h +++ b/app/lib-out/spbelib_interface.h @@ -16,7 +16,7 @@ typedef enum { SBLIB_INIT_WIRE_TUNE = 0, // 初始化为无线调参功能 - SBLIB_INIT_ADAPTER, // 初始化为 小黄砖4 功能 + SBLIB_INIT_ADAPTER, // 初始化为 静态库 功能 } sblib_init_t; /** @@ -30,12 +30,12 @@ void sblib_init(sblib_init_t init_type); /** * @brief 注册事件回调函数。 - * 当有关于小黄砖功能的事件发生或接收到数据时,调用回调函数。 + * 当有关于静态库功能的事件发生或接收到数据时,调用回调函数。 * 由 lib_notify_event() 和 sblib_notify_datastream() 函数调用。 */ typedef void (*lib_notify_cb)(void); -typedef enum __packed // 小黄砖功能控制命令 +typedef enum __packed // 静态库功能控制命令 { LIB_CONTROL_FCPORT_OFF, // 关闭飞控数据接口 LIB_CONTROL_FCPORT_UART, // 使用 UART 连接飞控 @@ -47,7 +47,7 @@ typedef enum __packed // 小黄砖功能控制命令 LIB_CONTROL_RF_STA, // 打开 WIFI(STA) } lib_control_t; -typedef enum __packed // 小黄砖通知的事件类型 +typedef enum __packed // 通知的事件类型 { LIB_EVENT_NONE = 0, @@ -80,7 +80,7 @@ typedef enum __packed // 小黄砖通知的事件类型 LIB_EVENT_MAX } lib_event_type_t; -typedef struct // 小黄砖通知的事件数据 +typedef struct // 静态库通知的事件数据 { lib_event_type_t type; // 事件类型 uint8_t len; // data[] 有效数据长度 @@ -88,7 +88,7 @@ typedef struct // 小黄砖通知的事件数据 } lib_event_t; /** - * @brief 执行对小黄砖功能的控制。 + * @brief 执行对静态库功能的控制。 * * @param control 控制命令 * @retval 0 表示成功; -1 表示失败。 @@ -97,7 +97,7 @@ int sblib_control(lib_control_t control); /** * @brief 注册事件回调函数。 - * 当有关于小黄砖的新事件发生时,将调用指定的回调函数以通知上层应用。 + * 当有关于静态库的新事件发生时,将调用指定的回调函数以通知上层应用。 * 内部可缓存的记录数为 32 个。 * 使用 sblib_get_event() 可读取这些记录,读取后会清除记录。 * @@ -106,7 +106,7 @@ int sblib_control(lib_control_t control); void sblib_regist_notify_event(lib_notify_cb cb); /** - * @brief 获取小黄砖的事件。线程和中断可用。 + * @brief 获取静态库的事件。线程和中断可用。 * * @return lib_event_t */ diff --git a/components/system/include/drivers/chip/tick.h b/components/system/include/drivers/chip/tick.h index 03ff8b8..8bc2c6e 100755 --- a/components/system/include/drivers/chip/tick.h +++ b/components/system/include/drivers/chip/tick.h @@ -10,6 +10,7 @@ void drv_tick_enable(unsigned freq); void drv_tick_disable(void); unsigned drv_tick_get_counter(void); +unsigned drv_tick_get_period(void); #ifdef __cplusplus } diff --git a/components/system/include/drivers/chip/uart.h b/components/system/include/drivers/chip/uart.h index 0992a1e..3a93f79 100755 --- a/components/system/include/drivers/chip/uart.h +++ b/components/system/include/drivers/chip/uart.h @@ -29,6 +29,12 @@ void drv_uart_disable(hal_id_t id); void drv_uart_init(hal_id_t id, const uart_param_t *param); void drv_uart_deinit(hal_id_t id); +void drv_uart_set_tx_buffer(hal_id_t id, void *buf, unsigned size); +void drv_uart_set_rx_buffer(hal_id_t id, void *buf, unsigned size); + +int drv_uart_get_tx_buffer_available(hal_id_t id); +int drv_uart_get_rx_data_available(hal_id_t id); + void drv_uart_set_br(hal_id_t id, unsigned clk, unsigned baudrate); unsigned drv_uart_get_br(hal_id_t id, unsigned clk); diff --git a/components/system/source/k_kit/k_kit.c b/components/system/source/k_kit/k_kit.c index ff0c955..9427360 100755 --- a/components/system/source/k_kit/k_kit.c +++ b/components/system/source/k_kit/k_kit.c @@ -86,7 +86,7 @@ */ #ifndef CONFIG_K_KIT_LOG_ON -#define CONFIG_K_KIT_LOG_ON 1 /* 0: k_log_sched() 无效; 1: k_log_sched() 生效 */ +#define CONFIG_K_KIT_LOG_ON 0 /* 0: k_log_sched() 无效; 1: k_log_sched() 生效 */ #endif #ifndef CONFIG_K_KIT_DBG_ON diff --git a/main/test.c b/main/test.c new file mode 100644 index 0000000..d56d22f --- /dev/null +++ b/main/test.c @@ -0,0 +1,161 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_log.h" + +// 调试宏 +#define SHOW_TIME_TOKEN 1 // 耗时测试开关 +#ifdef SHOW_TIME_TOKEN +#define RECURSIVE_NUM 100 // 递归进入和退出临界区次数 +#endif + +#define COUT_TO_NS(x) ((x * 1000) / 160) + +static struct +{ + atomic_int suspend_count; + TaskHandle_t task_handle; +} cores_suspend_handle[portNUM_PROCESSORS] = {0}; + +void cores_suspend(void *arg) +{ + while (1) + { + while (atomic_load(&cores_suspend_handle[xPortGetCoreID()].suspend_count) > 0) + { + __asm__ __volatile__("nop"); + } + vTaskSuspend(NULL); + } +} + +void enter_critical(void) +{ + if (atomic_fetch_add(&cores_suspend_handle[xPortGetCoreID()].suspend_count, 1) == 0) + { + // 唤醒其他核的高优先级任务 + for (int i = 0; i < portNUM_PROCESSORS; i++) + { + if (i == xPortGetCoreID()) + { + continue; + } + vTaskResume(cores_suspend_handle[i].task_handle); + } + vTaskSuspendAll(); + } +} + +void exit_critical(void) +{ + if (atomic_fetch_sub(&cores_suspend_handle[xPortGetCoreID()].suspend_count, 1) == 1) + { + xTaskResumeAll(); + } +} + +/* 竞争测试,验证互斥 */ +static int shared_data = 0; + +void taskA(void *pvParameters) +{ + int cnt = 0; + while (1) + { + enter_critical(); + + int before = shared_data; + shared_data++; + + exit_critical(); + if (shared_data != before + 1) + { + ESP_LOGE("TaskA", "发生竞争"); + } + else + { + if (++cnt % 100 == 0) + { + ESP_LOGI("TaskA", "未发生竞争"); + } + } + vTaskDelay(pdMS_TO_TICKS(10)); + } +} + +void taskB(void *pvParameters) +{ + int cnt = 0; + while (1) + { + enter_critical(); + enter_critical(); + // 临界区开始 + + int before = shared_data; + shared_data++; + // 临界区结束 + + exit_critical(); + exit_critical(); + + if (shared_data != before + 1) + { + ESP_LOGE("TaskB", "发生竞争"); + } + else + { + if (++cnt % 100 == 0) + { + ESP_LOGI("TaskB", "未发生竞争"); + } + } + vTaskDelay(pdMS_TO_TICKS(1)); + } +} + +int app_main(void) +{ + // 初始化 + for (int i = 0; i < portNUM_PROCESSORS; i++) + { + xTaskCreatePinnedToCore(cores_suspend, "cores_suspend", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &cores_suspend_handle[i].task_handle, i); + } + + // 竞争测试 + xTaskCreatePinnedToCore(taskA, "TaskA", 4096, NULL, 5, NULL, 0); + xTaskCreatePinnedToCore(taskB, "TaskB", 4096, NULL, 6, NULL, 1); + +#ifdef SHOW_TIME_TOKEN + // 单次耗时测试 + uint32_t start_time = esp_cpu_get_cycle_count(); + enter_critical(); + int32_t enter_time = (esp_cpu_get_cycle_count() - start_time); + start_time = esp_cpu_get_cycle_count(); + exit_critical(); + int32_t exit_time = (esp_cpu_get_cycle_count() - start_time); + + ESP_LOGI("单次耗时", "进入时间:%ld ns, 退出时间:%ld ns", COUT_TO_NS(enter_time), COUT_TO_NS(exit_time)); + + printf("\r\n"); + + // 递归测试 + start_time = esp_cpu_get_cycle_count(); + for (int i = 0; i < RECURSIVE_NUM; i++) + { + enter_critical(); + } + enter_time = (esp_cpu_get_cycle_count() - start_time); + start_time = esp_cpu_get_cycle_count(); + for (int i = 0; i < RECURSIVE_NUM; i++) + { + exit_critical(); + } + exit_time = (esp_cpu_get_cycle_count() - start_time); + + ESP_LOGI("递归耗时", "递归次数:%d, 进入总时间:%ld ns, 退出总时间: %ld ns", RECURSIVE_NUM, COUT_TO_NS(enter_time), COUT_TO_NS(exit_time)); +#endif + return 0; +} diff --git a/sal/esp32/kernel/os_service.c b/sal/esp32/kernel/os_service.c index 4d8e6cb..01f38a4 100755 --- a/sal/esp32/kernel/os_service.c +++ b/sal/esp32/kernel/os_service.c @@ -3,7 +3,8 @@ #include "task.h" static size_t int_flag; -static portMUX_TYPE s_os_service = portMUX_INITIALIZER_UNLOCKED; +static portMUX_TYPE s_spin_lock = portMUX_INITIALIZER_UNLOCKED; +static os_mutex_t s_scheduler_mutex; int os_start(void *heap_mem, size_t heap_size) { @@ -32,12 +33,12 @@ bool os_is_isr_context(void) void os_interrupt_disable(void) { - portENTER_CRITICAL(&s_os_service); + portENTER_CRITICAL(&s_spin_lock); } void os_interrupt_enable(void) { - portEXIT_CRITICAL(&s_os_service); + portEXIT_CRITICAL(&s_spin_lock); } void os_scheduler_suspend(void) @@ -48,7 +49,11 @@ void os_scheduler_suspend(void) OS_ERR("Called in isr"); // 在中断中不要挂起调度器,可能会导致死锁 return; } - vTaskSuspendAll(); + if (!os_mutex_is_valid(&s_scheduler_mutex)) + { + os_mutex_create(&s_scheduler_mutex); + } + os_mutex_lock(&s_scheduler_mutex, OS_WAIT_FOREVER); } void os_scheduler_resume(void) @@ -56,7 +61,7 @@ void os_scheduler_resume(void) // 只有在非中断上下文中才恢复调度器 if (!os_is_isr_context()) { - xTaskResumeAll(); + os_mutex_unlock(&s_scheduler_mutex); } }