增加 BLE MAC 地址管理功能,添加电量灯颜色设置,优化调度器挂起和恢复逻辑

This commit is contained in:
LokLiang
2025-06-23 12:02:30 +08:00
parent 176b2c49f6
commit f34eaca585
13 changed files with 259 additions and 20 deletions

View File

@@ -526,6 +526,25 @@ int app_cfg_set_mac_tab(uint8_t mac[6])
return 0; 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) int app_cfg_set_temp_log_on(bool sw)
{ {
// SYS_LOG_INF("set temp log on: %d", 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); app_cfg_do_save(100);
return 0; 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;
}

View File

@@ -104,7 +104,7 @@ typedef struct // 设备配置统一数据结构
bool strip_pwrup : 1; // 使用灯带上电效果 bool strip_pwrup : 1; // 使用灯带上电效果
bool strip_show_rf : 1; // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 bool strip_show_rf : 1; // 在灯带中用一个灯来显示射频数据接口状态的灯效图层
bool strip_link_fc : 1; // 开启灯带联动飞控用于飞控状态监控MSP 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) uint32_t reserve : 21; // 预留占位(原来是24个uint32)
} capacity; } capacity;
@@ -132,8 +132,12 @@ typedef struct // 设备配置统一数据结构
} temperature_log; } temperature_log;
bool ws2812_bat_led_direction; // 0: 正向1: 反向(正反向是指灯珠的连接方式,正向是指从第一个灯珠开始,反向是指从最后一个灯珠开始) 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; // 校验数据(可放于任何位置) uint32_t crc32; // 校验数据(可放于任何位置)
} cfg_app_t; } 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_wifi_sta_password(const void *password);
int app_cfg_set_mac_tab(uint8_t mac[6]); 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_on(bool sw);
int app_cfg_set_temp_log_index(uint8_t index); int app_cfg_set_temp_log_index(uint8_t index);
int app_cfg_set_gyro_heat_value(uint8_t value); int app_cfg_set_gyro_heat_value(uint8_t value);
int app_cfg_set_bat_led_color(uint32_t color);

View File

@@ -54,9 +54,10 @@ static cfg_app_t const s_cfg_app_default = {
.strip_pwrup = 0, // 使用灯带上电效果 .strip_pwrup = 0, // 使用灯带上电效果
.strip_show_rf = 0, // 在灯带中用一个灯来显示射频数据接口状态的灯效图层 .strip_show_rf = 0, // 在灯带中用一个灯来显示射频数据接口状态的灯效图层
.strip_link_fc = 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 = { .temperature_log = {
.temp_log_on = 0, // 温度日志开关 .temp_log_on = 0, // 温度日志开关
.temp_log_index = 0, // 温度日志最新索引 .temp_log_index = 0, // 温度日志最新索引

View File

@@ -50,9 +50,21 @@ static cfg_app_t const s_cfg_app_default = {
.ble = 1, // 使用 BLE .ble = 1, // 使用 BLE
.ap = 0, // 使用 WIFI AP 模式 .ap = 0, // 使用 WIFI AP 模式
.sta = 0, // 使用 WIFI STA 模式 .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 .product_id = PRODUCT_ID, // 产品 ID
.gyro_heat_value = 0, // 陀螺仪加热值,单位温度,0为关闭,最大值为80℃
}; };
#endif #endif

View File

@@ -1194,3 +1194,17 @@ const uint8_t *ble_server_get_mac(void)
{ {
return s_mac; 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));
}

View File

@@ -48,3 +48,4 @@ ble_server_status_t ble_server_get_gap_status(void);
uint32_t ble_server_get_mtu(void); uint32_t ble_server_get_mtu(void);
const uint8_t *ble_server_get_mac(void); const uint8_t *ble_server_get_mac(void);
void ble_server_get_remote_mac(uint8_t *mac);

View File

@@ -7,7 +7,7 @@ config LED_STRIP_MAX_LEDS
config LED_STRIP_MIN_LEDS config LED_STRIP_MIN_LEDS
depends on CAP_LED_STRIP depends on CAP_LED_STRIP
int "最小灯珠数" int "最小灯珠数"
range 1 64 range 1 68
default 64 default 64
config LED_STRIP_DEFAULT_LEDS config LED_STRIP_DEFAULT_LEDS

View File

@@ -16,7 +16,7 @@
typedef enum typedef enum
{ {
SBLIB_INIT_WIRE_TUNE = 0, // 初始化为无线调参功能 SBLIB_INIT_WIRE_TUNE = 0, // 初始化为无线调参功能
SBLIB_INIT_ADAPTER, // 初始化为 小黄砖4 功能 SBLIB_INIT_ADAPTER, // 初始化为 静态库 功能
} sblib_init_t; } sblib_init_t;
/** /**
@@ -30,12 +30,12 @@ void sblib_init(sblib_init_t init_type);
/** /**
* @brief 注册事件回调函数。 * @brief 注册事件回调函数。
* 当有关于小黄砖功能的事件发生或接收到数据时,调用回调函数。 * 当有关于静态库功能的事件发生或接收到数据时,调用回调函数。
* 由 lib_notify_event() 和 sblib_notify_datastream() 函数调用。 * 由 lib_notify_event() 和 sblib_notify_datastream() 函数调用。
*/ */
typedef void (*lib_notify_cb)(void); typedef void (*lib_notify_cb)(void);
typedef enum __packed // 小黄砖功能控制命令 typedef enum __packed // 静态库功能控制命令
{ {
LIB_CONTROL_FCPORT_OFF, // 关闭飞控数据接口 LIB_CONTROL_FCPORT_OFF, // 关闭飞控数据接口
LIB_CONTROL_FCPORT_UART, // 使用 UART 连接飞控 LIB_CONTROL_FCPORT_UART, // 使用 UART 连接飞控
@@ -47,7 +47,7 @@ typedef enum __packed // 小黄砖功能控制命令
LIB_CONTROL_RF_STA, // 打开 WIFI(STA) LIB_CONTROL_RF_STA, // 打开 WIFI(STA)
} lib_control_t; } lib_control_t;
typedef enum __packed // 小黄砖通知的事件类型 typedef enum __packed // 通知的事件类型
{ {
LIB_EVENT_NONE = 0, LIB_EVENT_NONE = 0,
@@ -80,7 +80,7 @@ typedef enum __packed // 小黄砖通知的事件类型
LIB_EVENT_MAX LIB_EVENT_MAX
} lib_event_type_t; } lib_event_type_t;
typedef struct // 小黄砖通知的事件数据 typedef struct // 静态库通知的事件数据
{ {
lib_event_type_t type; // 事件类型 lib_event_type_t type; // 事件类型
uint8_t len; // data[] 有效数据长度 uint8_t len; // data[] 有效数据长度
@@ -88,7 +88,7 @@ typedef struct // 小黄砖通知的事件数据
} lib_event_t; } lib_event_t;
/** /**
* @brief 执行对小黄砖功能的控制。 * @brief 执行对静态库功能的控制。
* *
* @param control 控制命令 * @param control 控制命令
* @retval 0 表示成功; -1 表示失败。 * @retval 0 表示成功; -1 表示失败。
@@ -97,7 +97,7 @@ int sblib_control(lib_control_t control);
/** /**
* @brief 注册事件回调函数。 * @brief 注册事件回调函数。
* 当有关于小黄砖的新事件发生时,将调用指定的回调函数以通知上层应用。 * 当有关于静态库的新事件发生时,将调用指定的回调函数以通知上层应用。
* 内部可缓存的记录数为 32 个。 * 内部可缓存的记录数为 32 个。
* 使用 sblib_get_event() 可读取这些记录,读取后会清除记录。 * 使用 sblib_get_event() 可读取这些记录,读取后会清除记录。
* *
@@ -106,7 +106,7 @@ int sblib_control(lib_control_t control);
void sblib_regist_notify_event(lib_notify_cb cb); void sblib_regist_notify_event(lib_notify_cb cb);
/** /**
* @brief 获取小黄砖的事件。线程和中断可用。 * @brief 获取静态库的事件。线程和中断可用。
* *
* @return lib_event_t * @return lib_event_t
*/ */

View File

@@ -10,6 +10,7 @@ void drv_tick_enable(unsigned freq);
void drv_tick_disable(void); void drv_tick_disable(void);
unsigned drv_tick_get_counter(void); unsigned drv_tick_get_counter(void);
unsigned drv_tick_get_period(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -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_init(hal_id_t id, const uart_param_t *param);
void drv_uart_deinit(hal_id_t id); 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); void drv_uart_set_br(hal_id_t id, unsigned clk, unsigned baudrate);
unsigned drv_uart_get_br(hal_id_t id, unsigned clk); unsigned drv_uart_get_br(hal_id_t id, unsigned clk);

View File

@@ -86,7 +86,7 @@
*/ */
#ifndef CONFIG_K_KIT_LOG_ON #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 #endif
#ifndef CONFIG_K_KIT_DBG_ON #ifndef CONFIG_K_KIT_DBG_ON

161
main/test.c Normal file
View File

@@ -0,0 +1,161 @@
#include <stdio.h>
#include <stdatomic.h>
#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;
}

View File

@@ -3,7 +3,8 @@
#include "task.h" #include "task.h"
static size_t int_flag; 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) 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) void os_interrupt_disable(void)
{ {
portENTER_CRITICAL(&s_os_service); portENTER_CRITICAL(&s_spin_lock);
} }
void os_interrupt_enable(void) void os_interrupt_enable(void)
{ {
portEXIT_CRITICAL(&s_os_service); portEXIT_CRITICAL(&s_spin_lock);
} }
void os_scheduler_suspend(void) void os_scheduler_suspend(void)
@@ -48,7 +49,11 @@ void os_scheduler_suspend(void)
OS_ERR("Called in isr"); // 在中断中不要挂起调度器,可能会导致死锁 OS_ERR("Called in isr"); // 在中断中不要挂起调度器,可能会导致死锁
return; 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) void os_scheduler_resume(void)
@@ -56,7 +61,7 @@ void os_scheduler_resume(void)
// 只有在非中断上下文中才恢复调度器 // 只有在非中断上下文中才恢复调度器
if (!os_is_isr_context()) if (!os_is_isr_context())
{ {
xTaskResumeAll(); os_mutex_unlock(&s_scheduler_mutex);
} }
} }