#include "board_config.h" #include "config/version.h" #include "driver/uart.h" #include "hal/spi_types.h" #include "utils/crc.h" #include "esp_partition.h" #include "spi_flash_mmap.h" #define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_ERR #define SYS_LOG_DOMAIN "CFG" #define CONS_ABORT() #include "sys_log.h" #include "board_config/devkit_esp32c2.h" #include "board_config/devkit_esp32c3.h" #include "board_config/devkit_esp32s3.h" typedef struct { uint8_t license_code[CONFIG_LICENSE_CODE_LENGTH]; // 在烧录器设置的保存滚码的字段 uint32_t crc_32; // 从 size 成员开始到数据结束的 crc32 校验值 uint16_t size; // 整个数据结构的长度 uint16_t version; // 仅指本结构的版本代号 cfg_board_t cfg; // 板载配置数据 } __cfg_board_partition_t; static const esp_partition_t *s_partition_hdl; const __cfg_board_partition_t *p_cfg_board_partition; const cfg_board_t *g_cfg_board = &s_cfg_board_default; const uint8_t *g_license_code; static void _read_partition_data(__cfg_board_partition_t *out, const cfg_board_t *cfg); static const uint8_t *_read_legacy_license_code(void); static uint32_t _get_data_crc(const __cfg_board_partition_t *cfg); /** * @brief 初始化,使 g_cfg_board 指向正确的 * @retval 0 指向了自定义分区中的数据 * @retval 1 在自定义分区中的数据校验失败,指向了默认的配置 */ int board_cfg_init(void) { s_partition_hdl = esp_partition_find_first((esp_partition_type_t)CONFIG_CFG_BOARD_PARTITION_TYPE, (esp_partition_subtype_t)CONFIG_CFG_BOARD_PARTITION_SUBTYPE, CONFIG_CFG_BOARD_PARTITION_NAME); *(int *)g_sys_log_on = 1; if (s_partition_hdl == NULL) { g_license_code = _read_legacy_license_code(); SYS_LOG_ERR("esp_partition_find_first() fail"); return 1; } const void *cfg_board_partition; esp_partition_mmap_handle_t mmp_data_handle; esp_err_t err = esp_partition_mmap(s_partition_hdl, 0, 0x1000, ESP_PARTITION_MMAP_DATA, &cfg_board_partition, &mmp_data_handle); if (err != ESP_OK) { g_license_code = _read_legacy_license_code(); SYS_LOG_ERR("esp_partition_mmap() fail"); return 1; } p_cfg_board_partition = cfg_board_partition; g_license_code = p_cfg_board_partition->license_code; if (p_cfg_board_partition->version != BOARD_CONFIG_DATA_VER || p_cfg_board_partition->size != sizeof(__cfg_board_partition_t) || p_cfg_board_partition->crc_32 != _get_data_crc(p_cfg_board_partition)) { SYS_LOG_WRN("no config data, using default config"); return 1; } else { g_cfg_board = &p_cfg_board_partition->cfg; SYS_LOG_INF("config data checked valid"); /* 如果代码区中的析载数据长度大于已有的数据区配置长度,则把多出来的部分添加到数据区中 */ if (sizeof(__cfg_board_partition_t) > p_cfg_board_partition->size && p_cfg_board_partition->size > sizeof(__cfg_board_partition_t) - sizeof(cfg_board_t)) { cfg_board_t new_cfg; memcpy(&new_cfg, &s_cfg_board_default, sizeof(new_cfg)); // 复制新的默认配置 memcpy(&new_cfg, g_cfg_board, sizeof(cfg_board_t) - (sizeof(__cfg_board_partition_t) - p_cfg_board_partition->size)); // 用旧的固化数据覆已有部分 board_cfg_fresh(&new_cfg); // 固化新配置 } return 0; } } /** * @brief 写入激活码 * * @param license_code * @return int */ int board_license_fresh(const uint8_t license_code[CONFIG_LICENSE_CODE_LENGTH]) { if (p_cfg_board_partition == NULL) { SYS_LOG_WRN("never exec board_cfg_init()"); return -1; } __cfg_board_partition_t cfg_buf_partition; memcpy(&cfg_buf_partition, p_cfg_board_partition, sizeof(cfg_buf_partition)); memcpy(&cfg_buf_partition.license_code[0], license_code, sizeof(cfg_buf_partition.license_code)); cfg_buf_partition.version = BOARD_CONFIG_DATA_VER; cfg_buf_partition.size = sizeof(cfg_buf_partition); esp_err_t err; err = esp_partition_erase_range(s_partition_hdl, 0, 0x1000); if (err != ESP_OK) { SYS_LOG_WRN("esp_partition_erase_range() fail. err: %d", err); return 1; } err = esp_partition_write_raw(s_partition_hdl, 0, &cfg_buf_partition, sizeof(cfg_buf_partition)); if (err != ESP_OK) { SYS_LOG_WRN("esp_partition_read_raw() fail. err: %d", err); return 1; } SYS_LOG_INF("done."); return 0; } /** * @brief 把板载数据固化到自定义分区中。 * 当数据被固化后,除非擦除芯片,否则在代码区的配置数据不生效 * * @param cfg * @return int */ int board_cfg_fresh(const cfg_board_t *cfg) { if (p_cfg_board_partition == NULL) { SYS_LOG_WRN("never exec board_cfg_init()"); return -1; } __cfg_board_partition_t cfg_buf_partition; _read_partition_data(&cfg_buf_partition, cfg); esp_err_t err; err = esp_partition_erase_range(s_partition_hdl, 0, 0x1000); if (err != ESP_OK) { SYS_LOG_WRN("esp_partition_erase_range() fail. err: %d", err); return 1; } err = esp_partition_write_raw(s_partition_hdl, 0, &cfg_buf_partition, sizeof(cfg_buf_partition)); if (err != ESP_OK) { SYS_LOG_WRN("esp_partition_read_raw() fail. err: %d", err); return 1; } g_cfg_board = &p_cfg_board_partition->cfg; SYS_LOG_INF("done."); return 0; } /** * @brief 通过终端打印 cfg 的二进制数,用于帮助制作对应 __cfg_board_partition_t 的 bin 文件。 * * @param cfg 如果为 NULL 时则表示打印保存在自定义分区位置的数据 * @retval 0 操作成功 * @retval -1 数据校验无效 */ int board_cfg_dump(const cfg_board_t *cfg) { if (p_cfg_board_partition == NULL) { SYS_LOG_WRN("never exec board_cfg_init()"); return -1; } if (cfg == NULL) { if (p_cfg_board_partition->size > 0x1000 || p_cfg_board_partition->size < CONFIG_LICENSE_CODE_LENGTH || p_cfg_board_partition->crc_32 != _get_data_crc(p_cfg_board_partition)) { SYS_LOG_WRN("No internal records, currently displayed as default configuration"); } cfg = &s_cfg_board_default; } __cfg_board_partition_t cfg_buf_partition; _read_partition_data(&cfg_buf_partition, cfg); SYS_LOG_WRN("The data in the custom partition is as follows %u bytes:\r\n", sizeof(cfg_buf_partition)); int i = 0; int len; const uint8_t *p = (uint8_t *)&cfg_buf_partition; SYS_PRINT("/* license code */\r\n"); len = sizeof(cfg_buf_partition.license_code); for (i = 0; i < len; i++) SYS_PRINT("0x%02X,%s", *p++, i + 1 < len ? " " : "\r\n"); SYS_PRINT("/* crc, size, version */\r\n"); len = cfg_buf_partition.size - sizeof(cfg_buf_partition.license_code) - sizeof(cfg_buf_partition.cfg); for (i = 0; i < len; i++) SYS_PRINT("0x%02X,%s", *p++, i + 1 < len ? " " : "\r\n"); SYS_PRINT("/* board configuration (from %s area) */\r\n", cfg == &s_cfg_board_default ? "code" : "data"); len = sizeof(cfg_buf_partition.cfg); for (i = 0; i < len; i++) SYS_PRINT("0x%02X,%s", *p++, i + 1 < len ? " " : "\r\n"); SYS_PRINT("\r\n"); return 0; } static void _read_partition_data(__cfg_board_partition_t *out, const cfg_board_t *cfg) { memcpy(out, p_cfg_board_partition, sizeof(*out)); memcpy(&out->cfg, cfg, sizeof(out->cfg)); out->version = BOARD_CONFIG_DATA_VER; out->size = sizeof(*out); out->crc_32 = _get_data_crc(out); } /** * @brief 旧的版本的激活码所在(历史遗留) * * @return const uint8_t* license_code */ static const uint8_t *_read_legacy_license_code(void) { spi_flash_mmap_handle_t handle; const uint32_t LEGACY_LICENSE_CODE_START_ADDR = 0x3E0000; uint32_t start = LEGACY_LICENSE_CODE_START_ADDR; uint32_t end = LEGACY_LICENSE_CODE_START_ADDR + CONFIG_LICENSE_CODE_LENGTH; const void *license_code; spi_flash_mmap(LEGACY_LICENSE_CODE_START_ADDR, end - start, SPI_FLASH_MMAP_DATA, &license_code, &handle); return license_code; } static uint32_t _get_data_crc(const __cfg_board_partition_t *cfg) { int cfg_size = cfg->size - sizeof(cfg->license_code) - sizeof(cfg->crc_32); return crc32_calc(0, &cfg->size, cfg_size); }