Files
ESPC3-wireless/app/config/app_config.c
LokLiang e9b5e42ef2 重构项目配置并添加对 SBDEMO 的支持
更新多个 ESP32 芯片(C2、C3、S3)
的版本配置为 SBDEMO
产品添加新的配置文件实现板卡和应用程序配置模块添加 CRC 实用函数修改系统日志以支持动态日志控制更新 Kconfig 和 sdkconfig 的默认设置以适应新产品
2025-02-21 10:38:22 +08:00

448 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file app_config.c
* @author LokLiang
* @brief app_config.h 模块源码
* @version 0.1
* @date 2023-11-242
*
* @copyright Copyright (c) 2023
*
*/
#include "app_config.h"
#include "config/board_config.h"
#include "config/version.h"
#include "app_main.h"
#include "nvs.h"
#include "utils/crc.h"
#include "os/os.h"
#include "esp_mac.h"
#undef CONFIG_SYS_LOG_LEVEL
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF
#define SYS_LOG_DOMAIN "APCFG"
#include "sys_log.h"
#include "sys_types.h"
#define _NVS_KEY_MAIN "app-main" // 主应用
#define _NVS_KEY_BKUP "app-bkup" // 备份副本,用于数据校验错误时回滚
/* 数据区 -------------------------------------------------------------------------------------- */
extern nvs_handle g_nvs_hdl;
static cfg_app_t s_cfg_app;
const cfg_app_t *g_cfg_app = (const cfg_app_t *)&s_cfg_app;
const int *g_sys_log_on = &s_cfg_app.sys_log_on;
static os_work_t s_work_hdl_save;
/* 默认的程序设置代码文件 */
#include "app_config/developing.h"
#include "app_config/SBDEMO.h"
/* nvs 接口 ------------------------------------------------------------------------------------ */
static int _read_key(const char *key, void *out_value, size_t tar_length, uint32_t *crc_base);
static int _set_crc(const void *struct_base, size_t struct_length, uint32_t *crc_base);
static void _work_handler_save(void *arg);
/**
* @brief 读取指定的数据,并按给出的特性进行校验,返回校验结果
*
* @param key 在 nvs 的存储块的键值
* @param out_value[out] 输出内存
* @param tar_length 输出的内存预期的长度
* @param crc_base[io] CRC 校验值所在内存块的地址(绝对值)。输入:校验值,输出:新的正确校验值
* @retval 0 正确读取了已存储数据
* @retval 1 nvs 模块可用, CRC 校验值已更新
* @retval -1 nvs 模块不可用
*/
static int _read_key(const char *key, void *out_value, size_t tar_length, uint32_t *crc_base)
{
size_t required_size = 0;
esp_err_t err = ESP_OK;
/* 在确认已存储的数据长度前,仅获取长度以免数据溢出 */
err = nvs_get_blob(g_nvs_hdl, key, NULL, &required_size);
if (err != ESP_OK)
{
SYS_LOG_WRN("failed to read prfsdata data length, err:%d", err);
return -1;
}
if (required_size != tar_length)
{
SYS_LOG_WRN("invalid prfsdata length, length:%d, err:%d", required_size, err);
return -1;
}
/* 读出已存储的数据 */
err = nvs_get_blob(g_nvs_hdl, key, out_value, &required_size);
if (err != ESP_OK)
{
SYS_LOG_ERR("failed to read prfsdata data, err:%d", err);
return -1;
}
/* 设置并校验 CRC */
if (_set_crc(out_value, tar_length, crc_base))
{
SYS_LOG_WRN("read frs failed, incorrect crc and update");
return 1;
}
return 0;
}
/**
* @brief 校验并更新结构体中 CRC 的值。
* 这将校验整个结构(包含 CRC 本身),因此 CRC 自身的初始值为 0然后更新 CRC 的结果到结构中
*
* @param struct_base 待分析和设置的内存块
* @param struct_length 待分析和设置的内存块的实际长度
* @param crc_base[io] CRC 校验值所在内存块的地址(绝对值)
* @retval 0 校验正确
* @retval 1 校验错误,并且设置了正确的校验值
*/
static int _set_crc(const void *struct_base, size_t struct_length, uint32_t *crc_base)
{
// 校验读出来的数据的正确性
uint32_t crc_read = *crc_base;
*crc_base = 0;
*crc_base = crc32_calc(0, struct_base, struct_length);
return (crc_read != *crc_base);
}
/**
* @brief 立即执行保存 配置数据 到 nvs 的动作
*
* @param arg
*/
static void _work_handler_save(void *arg)
{
_set_crc(&s_cfg_app, sizeof(s_cfg_app), &s_cfg_app.crc32);
nvs_set_blob(g_nvs_hdl, _NVS_KEY_BKUP, &s_cfg_app, sizeof(s_cfg_app));
nvs_set_blob(g_nvs_hdl, _NVS_KEY_MAIN, &s_cfg_app, sizeof(s_cfg_app));
}
/**
* @brief 初始化。将从 nvs 读取已保存的数据到内存 s_cfg_app 中。
* 当出现以下情况时,配置数据被恢复到默认值:
* nvs 未初始化或操作失败;
* 使用 app_cfg_factory_set() 立即恢复到默认值;
* 结构体的长度 s_cfg_app 发生改变;
* APP_CONFIG_DATA_VER 定义的值发生改变;
*
* @retval 0 成功读取已有记录
* @retval 1 已恢复默认设置
* @retval -1 nvs 操作失败
*/
int app_cfg_init(void)
{
int ret = -1;
SYS_ASSERT(g_nvs_hdl != 0, "");
/* 创建延时保存的任务 */
if (!os_work_is_valid(&s_work_hdl_save))
{
os_work_create(&s_work_hdl_save, "", _work_handler_save, NULL, OS_PRIORITY_LOWER);
os_work_submit(default_os_work_q_hdl, &s_work_hdl_save, OS_WAIT_FOREVER);
}
/* 读取映射为 _NVS_KEY_MAIN 数据 */
ret = _read_key(_NVS_KEY_MAIN, &s_cfg_app, sizeof(s_cfg_app), &s_cfg_app.crc32);
if (ret)
{
/* 如果读取失败,则读取备份区并恢复 */
ret = _read_key(_NVS_KEY_BKUP, &s_cfg_app, sizeof(s_cfg_app), &s_cfg_app.crc32);
if (ret)
{
goto use_default_prfs;
}
else
{
SYS_LOG_WRN("Data verification failed, recovered from backup area");
app_cfg_do_save(0);
}
}
if (s_cfg_app.version != APP_CONFIG_DATA_VER || memcmp(s_cfg_app.product_id, PRODUCT_ID, sizeof(s_cfg_app.product_id)) != 0)
{
ret = 1;
SYS_LOG_WRN("Upgrade to the latest version");
goto use_default_prfs;
}
return ret;
use_default_prfs:
app_cfg_factory_set();
app_cfg_do_save(0);
return ret;
}
/**
* @brief 使内存的数据恢复到默认设置
*
* @return int 0
*/
int app_cfg_factory_set(void)
{
memcpy(&s_cfg_app, &s_cfg_app_default, sizeof(s_cfg_app));
/* s_cfg_app.dev_mac_str */
uint8_t macAddress[6];
ESP_ERROR_CHECK(esp_efuse_mac_get_default(macAddress));
snprintf(s_cfg_app.dev_mac_str, sizeof(s_cfg_app.dev_mac_str), "%02X%02X%02X%02X%02X%02X",
macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]);
s_cfg_app.salt_random = rand();
app_cfg_do_save(1000);
return 0;
}
/**
* @brief 立即执行保存 配置数据 到 nvs 的动作
*
* @param delay_ms 0: 立即保存, > 0 多少毫秒后执行保存
* @return int @ref esp_err_t
*/
int app_cfg_do_save(uint32_t delay_ms)
{
if (delay_ms == 0)
{
os_work_suspend(&s_work_hdl_save);
_work_handler_save(NULL);
}
else
{
os_work_resume(&s_work_hdl_save, delay_ms);
}
return 0;
}
/* 写接口 -------------------------------------------------------------------------------------- */
void app_cfg_set_sys_log(bool on)
{
s_cfg_app.sys_log_on = on;
app_cfg_do_save(0);
}
void app_cfg_set_rf_mode_change(void)
{
for (;;)
{
s_cfg_app.rf_mode++;
if (s_cfg_app.rf_mode >= DATA_BRIDGE_RF_MODE_MAX)
{
s_cfg_app.rf_mode = 0;
}
#if !(CONFIG_BUILD_BLE)
if (s_cfg_app.rf_mode == DATA_BRIDGE_RF_MODE_BLE)
{
continue;
}
#endif
#if !(CONFIG_BUILD_WIFI)
if (s_cfg_app.rf_mode == DATA_BRIDGE_RF_MODE_WIFI_AP || s_cfg_app.rf_mode == DATA_BRIDGE_RF_MODE_WIFI_STA)
{
continue;
}
#endif
break;
}
app_cfg_do_save(1000);
}
int app_cfg_set_psPassword(const void *psPassword, int size)
{
if (size > sizeof(s_cfg_app.psPassword))
{
SYS_LOG_WRN("size: %u > %u", size, sizeof(s_cfg_app.psPassword));
return -1;
}
memset(s_cfg_app.psPassword, 0, sizeof(s_cfg_app.psPassword));
if (size > 0)
{
memcpy(s_cfg_app.psPassword, psPassword, size);
}
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_device_name_ble(const void *device_name_ble, int size)
{
if (size > 19 || size < 1)
{
SYS_LOG_WRN("size: %d", size);
return -1;
}
if (size > sizeof(s_cfg_app.device_name_ble) - 1)
{
SYS_LOG_WRN("size: %u > %u", size, sizeof(s_cfg_app.device_name_ble));
return -1;
}
memset(s_cfg_app.device_name_ble, 0, sizeof(s_cfg_app.device_name_ble));
if (size > 0)
{
memcpy(s_cfg_app.device_name_ble, device_name_ble, size);
}
app_cfg_do_save(0); // 由于下个操作为重启,所以立即需要保存
return 0;
}
void split_string(const char *str, size_t total_size, char delimiter, char result1[], char result2[], char result3[], char result4[], char result5[], char result6[])
{
if (str == NULL)
{
return; // 检查输入字符串是否为空
}
const char *start = str;
const char *end;
SYS_LOG_INF("start addr:%p,size:%d", &str, total_size);
uint8_t index = 0;
char *results[] = {result1, result2, result3, result4, result5, result6};
// 循环查找分隔符并拆解字符串
while (index < sizeof(results) / sizeof(char *))
{
end = strchr(start, delimiter); // 查找分隔符
if (end != NULL && (end - start) < total_size)
{
SYS_LOG_WRN("read:%d", (end - start));
size_t len = end - start; // 计算子字符串长度
strncpy(results[index], start, len); // 复制子字符串到结果数组
results[index][len] = '\0'; // 添加字符串结束符
start = end + 1; // 更新起始指针
}
else
{
size_t remind = total_size - (start - str); // 剩余字符串长度
SYS_LOG_INF("str addr:%p,start addr%p,end addr:%p,remind:%d", str, start, end, remind);
strncpy(results[index], start, remind); // 复制剩余字符串到结果数组
results[index][remind] = '\0'; // 添加字符串结束符
break; // 如果没有更多分隔符,退出循环
}
index++; // 更新索引
}
}
int app_cfg_set_rf_parameters(const void *wifi_parameters, size_t size)
{
if (wifi_parameters == NULL)
{
SYS_LOG_WRN("rf parameters is empty");
return -1;
}
// parse_rf_parameters(wifi_parameters);
split_string((char *)wifi_parameters, size, '\n',
s_cfg_app.device_name_ble,
s_cfg_app.psPassword,
s_cfg_app.app_config_wifi_para.wifi_ap_ssid,
s_cfg_app.app_config_wifi_para.wifi_ap_password,
s_cfg_app.app_config_wifi_para.wifi_sta_ssid,
s_cfg_app.app_config_wifi_para.wifi_sta_password);
SYS_LOG_DUMP(wifi_parameters, sizeof(wifi_parameters), 0, 0);
app_cfg_do_save(0); // 由于下个操作为重启,所以立即需要保存
return 0;
}
int app_cfg_set_drone_data(const void *drone_data, int size)
{
if (size > sizeof(s_cfg_app.drone_data))
{
SYS_LOG_WRN("size: %u > %u", size, sizeof(s_cfg_app.drone_data));
return -1;
}
memset(s_cfg_app.drone_data, 0, sizeof(s_cfg_app.drone_data));
if (size > 0)
{
memcpy(s_cfg_app.drone_data, drone_data, size);
}
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_wifi_setting_ardupilot_passthrough_tcp_port(uint16_t ardupilot_passthrough_tcp_port)
{
s_cfg_app.wifi_setting.ardupilot_passthrough_tcp_port = ardupilot_passthrough_tcp_port;
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_wifi_setting_ardupilot_passthrough_udp_port(uint16_t ardupilot_passthrough_udp_port)
{
s_cfg_app.wifi_setting.ardupilot_passthrough_udp_port = ardupilot_passthrough_udp_port;
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_wifi_setting_ardupilot_passthrough_udp_transfer_in_raw_mode(uint8_t ardupilot_passthrough_udp_transfer_in_raw_mode)
{
s_cfg_app.wifi_setting.ardupilot_passthrough_udp_transfer_in_raw_mode = ardupilot_passthrough_udp_transfer_in_raw_mode;
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_wifi_setting_wifi_max_connection_num(uint8_t wifi_max_connection_num)
{
s_cfg_app.wifi_setting.wifi_max_connection_num = wifi_max_connection_num;
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_wifi_setting_uartBaudRate(uint32_t uartBaudRate)
{
s_cfg_app.wifi_setting.uartBaudRate = uartBaudRate;
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_fc_protocol_type(uint8_t type)
{
s_cfg_app.fc.protocol_type = type;
app_cfg_do_save(1000);
return 0;
}
int app_cfg_set_led_strip_sw(uint8_t sw)
{
s_cfg_app.strip_sw = !!sw;
app_cfg_do_save(100);
return 0;
}
int app_cfg_set_armed2close_rf_sw(bool sw)
{
s_cfg_app.armed2close_rf_sw = !!sw;
app_cfg_do_save(100);
return 0;
}
int app_cfg_set_mac_tab(uint8_t mac[6])
{
for (int i = 0; i < __ARRAY_SIZE(s_cfg_app.mac_tab); i++)
{
if (memcmp(mac, s_cfg_app.mac_tab[i], 6) == 0)
{
return 0;
}
}
if (++s_cfg_app.mac_index >= __ARRAY_SIZE(s_cfg_app.mac_tab))
{
s_cfg_app.mac_index = 0;
}
memcpy(s_cfg_app.mac_tab[s_cfg_app.mac_index], mac, sizeof(s_cfg_app.mac_tab[0]));
app_cfg_do_save(1000);
return 0;
}