12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037 |
- /* USER CODE BEGIN Header */
- /**@Doxygen风格注释
- ******************************************************************************
- * @file : kv_flash.c
- * @brief :
- ******************************************************************************
- * @attention
- *
- *
- *
- *
- *
- *
- *
- *
- ******************************************************************************
- */
-
- /* USER CODE END Header */
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "kv_flash.h"
- #include "uType.h"
- #include "Printf.h"
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "cmsis_os.h"
- #include <inttypes.h> // PRIu32 等宏
- #include <ctype.h> // for isprint
- #include <stddef.h> // offsetof
- /* USER CODE END Includes */
- /* Exported types ------------------------------------------------------------*/
- /* USER CODE BEGIN ET */
- #define KV_ROOT(root, name, type) { #name, offsetof(root, name), type, sizeof(((root*)0)->name), 0 }
- #define KV_WORK(root, name, type) { #name, offsetof(root, name), type, sizeof(((root*)0)->name), 1 }
- extern IWDG_HandleTypeDef hiwdg;
- size_t init_index = 0;
- static char db_cache[3][DB_FLASH_SIZE]; // 每个数据库的缓存
- static uint16_t db_cache_len[3]; // 每个数据库内的缓存长度
- /**@BEGIN ------------ 映射表 -------------------*/
- static const uint32_t DB_ADDR[DB_ID_MAX] = {
- [DB_ID_SYSTEM] = 0x0803C000,
- [DB_ID_CALIB] = 0x0803C800,
- [DB_ID_SNAPSHOT] = 0x0803D000,
- };
- static const InitEntry init_table[] = {
- // SystemConfig
- {DB_ID_SYSTEM, KV_KEY_MAC "=001800000000"},
- {DB_ID_SYSTEM, KV_KEY_ROLE "=1"},
- {DB_ID_SYSTEM, KV_KEY_CONSOLE "=1"},
- {DB_ID_SYSTEM, KV_KEY_ADDR "=255"},
- {DB_ID_SYSTEM, KV_KEY_BAUDRATE "=2"},
- {DB_ID_SYSTEM, KV_KEY_VERSION "=0007C128"},
-
- // CalibrationParams
- {DB_ID_CALIB, KV_KEY_ROD_VOL0 "=2.637"},
- {DB_ID_CALIB, KV_KEY_ROD_VOL1 "=2.905"},
- {DB_ID_CALIB, KV_KEY_ROD_VOL2 "=3.165"},
- {DB_ID_CALIB, KV_KEY_ROD_VOL3 "=3.504"},
- {DB_ID_CALIB, KV_KEY_ROD_VOL4 "=3.863"},
- {DB_ID_CALIB, KV_KEY_ROD_VOL5 "=4.125"},
- {DB_ID_CALIB, KV_KEY_ROD_VOL6 "=4.402"},
-
- {DB_ID_CALIB, KV_KEY_OIL_CAP0 "=1.86"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP1 "=2.01"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP2 "=2.14"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP3 "=2.35"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP4 "=3.05"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP5 "=3.12"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP6 "=3.22"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP7 "=3.39"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP8 "=3.65"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP9 "=3.84"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP10 "=3.98"},
-
- {DB_ID_CALIB, KV_KEY_RES_VOL0 "=2.713"},
- {DB_ID_CALIB, KV_KEY_RES_VOL1 "=2.739"},
- {DB_ID_CALIB, KV_KEY_RES_VOL2 "=2.766"},
- {DB_ID_CALIB, KV_KEY_RES_VOL3 "=2.788"},
- {DB_ID_CALIB, KV_KEY_RES_VOL4 "=2.821"},
- {DB_ID_CALIB, KV_KEY_RES_VOL5 "=2.855"},
-
- {DB_ID_CALIB, KV_KEY_RES_CAP0 "=2.678"},
- {DB_ID_CALIB, KV_KEY_RES_CAP1 "=2.356"},
- {DB_ID_CALIB, KV_KEY_RES_CAP2 "=1.863"},
- {DB_ID_CALIB, KV_KEY_RES_CAP3 "=1.545"},
- {DB_ID_CALIB, KV_KEY_RES_CAP4 "=9.87"},
- {DB_ID_CALIB, KV_KEY_RES_CAP5 "=3.98"},
-
- {DB_ID_CALIB, KV_KEY_ROD_VOL_OFFSET "=0.008"},
- {DB_ID_CALIB, KV_KEY_ROD_DIALOG "=10"},
- {DB_ID_CALIB, KV_KEY_ROD_COL_TIME "=10"},
-
- {DB_ID_CALIB, KV_KEY_OIL_PARA_INDU "=18"},
- {DB_ID_CALIB, KV_KEY_OIL_PARA_CAP "=33"},
- {DB_ID_CALIB, KV_KEY_OIL_CAP_OFFSET "=0"},
- {DB_ID_CALIB, KV_KEY_OIL_DIALOG "=10"},
- {DB_ID_CALIB, KV_KEY_OIL_COL_TIME "=10"},
-
- {DB_ID_CALIB, KV_KEY_RES_PARA_INDU "=18"},
- {DB_ID_CALIB, KV_KEY_RES_PARA_CAP "=33"},
- {DB_ID_CALIB, KV_KEY_RES_CAP_OFFSET "=0"},
- {DB_ID_CALIB, KV_KEY_RES_VOL_OFFSET "=0.008"},
- {DB_ID_CALIB, KV_KEY_RES_CAP_DIALOG "=10"},
- {DB_ID_CALIB, KV_KEY_RES_VOL_DIALOG "=10"},
- {DB_ID_CALIB, KV_KEY_RES_CAP_COL_TIME "=10"},
- {DB_ID_CALIB, KV_KEY_RES_VOL_COL_TIME "=10"},
-
- {DB_ID_CALIB, KV_KEY_TEMP_VOL_OFFSET "=0.008"},
- {DB_ID_CALIB, KV_KEY_TEMP_DIALOG "=10"},
- {DB_ID_CALIB, KV_KEY_TEMP_COL_TIME "=10"},
-
- // SnapshotInfo
- {DB_ID_SNAPSHOT, KV_KEY_IAP_LOAD "=0"},
- {DB_ID_SNAPSHOT, KV_KEY_IAP_SIZE "=40960"},
- {DB_ID_SNAPSHOT, KV_KEY_IAP_MD5 "=00000000"},
- {DB_ID_SNAPSHOT, KV_KEY_UPDATE_OK "=2"},
- {DB_ID_SNAPSHOT, KV_KEY_UPDATE_ERR "=2"},
- {DB_ID_SNAPSHOT, KV_KEY_UBOOTBACK "=400"}
- };
- typedef enum {
- FIELD_INT,
- FIELD_UINT8,
- FIELD_UINT16,
- FIELD_UINT32,
- FIELD_FLOAT,
- FIELD_STRING
- } FieldType;
- typedef struct {
- const char *key; // KV 名
- size_t offset; // 在 JsRoot/J sRoot.work 中的偏移
- FieldType type; // 字段类型
- size_t size; // 字段大小(字符串用)
- uint8_t in_work; // 0 表示在 JsRoot,1 表示在 JsRoot.work
- } KvFieldMap;
- const KvFieldMap kv_map[] = {
- // ===== JsRoot =====
- {"mac", offsetof(JsonDat_Root, mac), FIELD_STRING, sizeof(JsRoot.mac), 0},
- {"role", offsetof(JsonDat_Root, role), FIELD_INT, sizeof(JsRoot.role), 0},
- {"console", offsetof(JsonDat_Root, console), FIELD_INT, sizeof(JsRoot.console), 0},
- {"addr", offsetof(JsonDat_Root, addr), FIELD_UINT8, sizeof(JsRoot.addr), 0},
- {"baudrate", offsetof(JsonDat_Root, baudrate), FIELD_INT, sizeof(JsRoot.baudrate), 0},
- {"version", offsetof(JsonDat_Root, vers_id), FIELD_UINT32, sizeof(JsRoot.vers_id), 0},
- {"iapLoadStatus", offsetof(JsonDat_Root, iapLoadStatus), FIELD_UINT32, sizeof(JsRoot.iapLoadStatus), 0},
- {"iapsize", offsetof(JsonDat_Root, iapSize), FIELD_INT, sizeof(JsRoot.iapSize), 0},
- {"iapmd5", offsetof(JsonDat_Root, iapMd5), FIELD_STRING, sizeof(JsRoot.iapMd5), 0},
- {"subcode", offsetof(JsonDat_Root, subcode), FIELD_UINT16, sizeof(JsRoot.subcode), 0},
- {"update_ok", offsetof(JsonDat_Root, update_ok), FIELD_INT, sizeof(JsRoot.update_ok), 0},
- {"update_err",offsetof(JsonDat_Root, update_err),FIELD_INT, sizeof(JsRoot.update_err), 0},
- {"ubootback", offsetof(JsonDat_Root, ubootback), FIELD_INT, sizeof(JsRoot.ubootback), 0},
- // ===== JsWork =====
- {"rod_vol0", offsetof(JsonDat_Work, calib_rod) + offsetof(Calib_rod_t, vol_values[0]), FIELD_FLOAT, sizeof(JsWork.calib_rod.vol_values[0]), 1},
- {"rod_vol1", offsetof(JsonDat_Work, calib_rod) + offsetof(Calib_rod_t, vol_values[1]), FIELD_FLOAT, sizeof(JsWork.calib_rod.vol_values[1]), 1},
- {"rod_vol2", offsetof(JsonDat_Work, calib_rod) + offsetof(Calib_rod_t, vol_values[2]), FIELD_FLOAT, sizeof(JsWork.calib_rod.vol_values[2]), 1},
- {"rod_vol3", offsetof(JsonDat_Work, calib_rod) + offsetof(Calib_rod_t, vol_values[3]), FIELD_FLOAT, sizeof(JsWork.calib_rod.vol_values[3]), 1},
- {"rod_vol4", offsetof(JsonDat_Work, calib_rod) + offsetof(Calib_rod_t, vol_values[4]), FIELD_FLOAT, sizeof(JsWork.calib_rod.vol_values[4]), 1},
- {"rod_vol5", offsetof(JsonDat_Work, calib_rod) + offsetof(Calib_rod_t, vol_values[5]), FIELD_FLOAT, sizeof(JsWork.calib_rod.vol_values[5]), 1},
- {"rod_vol6", offsetof(JsonDat_Work, calib_rod) + offsetof(Calib_rod_t, vol_values[6]), FIELD_FLOAT, sizeof(JsWork.calib_rod.vol_values[6]), 1},
- {"oil_cap0", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[0]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[0]), 1},
- {"oil_cap1", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[1]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[1]), 1},
- {"oil_cap2", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[2]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[2]), 1},
- {"oil_cap3", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[3]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[3]), 1},
- {"oil_cap4", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[4]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[4]), 1},
- {"oil_cap5", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[5]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[5]), 1},
- {"oil_cap6", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[6]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[6]), 1},
- {"oil_cap7", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[7]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[7]), 1},
- {"oil_cap8", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[8]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[8]), 1},
- {"oil_cap9", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[9]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[9]), 1},
- {"oil_cap10", offsetof(JsonDat_Work, calib_oil_water) + offsetof(CalibPoints_t, cap_values[10]), FIELD_FLOAT, sizeof(JsWork.calib_oil_water.cap_values[10]), 1},
- {"res_vol0", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, vol_values[0]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.vol_values[0]), 1},
- {"res_vol1", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, vol_values[1]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.vol_values[1]), 1},
- {"res_vol2", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, vol_values[2]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.vol_values[2]), 1},
- {"res_vol3", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, vol_values[3]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.vol_values[3]), 1},
- {"res_vol4", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, vol_values[4]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.vol_values[4]), 1},
- {"res_vol5", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, vol_values[5]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.vol_values[5]), 1},
- {"res_cap0", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, cap_values[0]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.cap_values[0]), 1},
- {"res_cap1", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, cap_values[1]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.cap_values[1]), 1},
- {"res_cap2", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, cap_values[2]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.cap_values[2]), 1},
- {"res_cap3", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, cap_values[3]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.cap_values[3]), 1},
- {"res_cap4", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, cap_values[4]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.cap_values[4]), 1},
- {"res_cap5", offsetof(JsonDat_Work, calib_residual_oil) + offsetof(Calib_residual_oil_t, cap_values[5]), FIELD_FLOAT, sizeof(JsWork.calib_residual_oil.cap_values[5]), 1},
- {"rod_vol_offset", offsetof(JsonDat_Work, rod_vol_offset), FIELD_FLOAT, sizeof(JsWork.rod_vol_offset), 1},
- {"rod_dialog", offsetof(JsonDat_Work, rod_dialog), FIELD_FLOAT, sizeof(JsWork.rod_dialog), 1},
- {"rod_coltime", offsetof(JsonDat_Work, rod_coltime), FIELD_UINT16, sizeof(JsWork.rod_coltime), 1},
- {"oil_para_indu", offsetof(JsonDat_Work, oil_para_indu), FIELD_FLOAT, sizeof(JsWork.oil_para_indu), 1},
- {"oil_para_cap", offsetof(JsonDat_Work, oil_para_cap), FIELD_FLOAT, sizeof(JsWork.oil_para_cap), 1},
- {"oil_cap_offset", offsetof(JsonDat_Work, oil_cap_offset), FIELD_FLOAT, sizeof(JsWork.oil_cap_offset), 1},
- {"oil_dialog", offsetof(JsonDat_Work, oil_dialog), FIELD_FLOAT, sizeof(JsWork.oil_dialog), 1},
- {"rod_oil_coltime", offsetof(JsonDat_Work, rod_oil_coltime), FIELD_UINT16, sizeof(JsWork.rod_oil_coltime), 1},
- {"res_para_indu", offsetof(JsonDat_Work, res_para_indu), FIELD_FLOAT, sizeof(JsWork.res_para_indu), 1},
- {"res_para_cap", offsetof(JsonDat_Work, res_para_cap), FIELD_FLOAT, sizeof(JsWork.res_para_cap), 1},
- {"res_cap_offset", offsetof(JsonDat_Work, res_cap_offset), FIELD_FLOAT, sizeof(JsWork.res_cap_offset), 1},
- {"res_vol_offset", offsetof(JsonDat_Work, res_vol_offset), FIELD_FLOAT, sizeof(JsWork.res_vol_offset), 1},
- {"res_cap_dialog", offsetof(JsonDat_Work, res_cap_dialog), FIELD_FLOAT, sizeof(JsWork.res_cap_dialog), 1},
- {"res_vol_dialog", offsetof(JsonDat_Work, res_vol_dialog), FIELD_FLOAT, sizeof(JsWork.res_vol_dialog), 1},
- {"res_oil_cap_coltime", offsetof(JsonDat_Work, res_oil_cap_coltime), FIELD_UINT16, sizeof(JsWork.res_oil_cap_coltime), 1},
- {"res_oil_vol_coltime", offsetof(JsonDat_Work, res_oil_vol_coltime), FIELD_UINT16, sizeof(JsWork.res_oil_vol_coltime), 1},
- {"temp_vol_offset",offsetof(JsonDat_Work, temp_vol_offset), FIELD_FLOAT, sizeof(JsWork.temp_vol_offset), 1},
- {"temp_dialog", offsetof(JsonDat_Work, temp_dialog), FIELD_FLOAT, sizeof(JsWork.temp_dialog), 1},
- {"temp_coltime", offsetof(JsonDat_Work, temp_coltime), FIELD_UINT16, sizeof(JsWork.temp_coltime), 1},
- };
- /**@END ---映射表 */
- /* USER CODE END ET */
- /* Exported functions prototypes ---------------------------------------------*/
- /**@BEGIN ------------ 小工具函数 -------------------*/
- static uint8_t is_valid_db_id(uint8_t id) { // 数据库编号是否过界
- return id < DB_ID_MAX;
- }
- size_t get_db_used_len(uint8_t db_id){ // 倒着查找该数据库里写入了多少数据
- uint32_t addr = DB_ADDR[db_id];
- const uint8_t *p = (const uint8_t *)addr;
- for (int i = 2047; i >= 0; i--) {
- if (p[i] != 0xFF) {
- return i + 1;
- }
- }
- return 0; // 全空
- }
- static inline float str_to_float(const char *s) { // char转float
- return (float)strtof(s, NULL);
- }
- const char* memmem_custom(const char *haystack, size_t haylen,const char *needle, size_t neelen) {
- if (!haystack || !needle || neelen == 0 || haylen < neelen) return NULL;
- for (size_t i = 0; i <= haylen - neelen; i++) {
- if (memcmp(haystack + i, needle, neelen) == 0)
- return haystack + i;
- }
- return NULL;
- }
- /**@END --- 小工具函数 */
- /**@BEGIN ------------ FLASH擦除写入函数 -------------------*/
- static uint8_t flash_erase_page(uint32_t addr) { // 擦除指定数据库区域(2KB) 20~40ms
- __disable_irq(); // 关闭全局中断
- HAL_IWDG_Refresh(&hiwdg);
- HAL_FLASH_Unlock();
- FLASH_EraseInitTypeDef erase;
- uint32_t PageError = 0;
- erase.TypeErase = FLASH_TYPEERASE_PAGES;
- erase.Page = (addr - FLASH_BASE) / DB_FLASH_PAGE_SIZE;
- erase.NbPages = 1;
- erase.Banks = FLASH_BANK_1;
- if (HAL_FLASHEx_Erase(&erase, &PageError) != HAL_OK) {
- HAL_FLASH_Lock();
- return 0;
- }
- HAL_FLASH_Lock();
- HAL_IWDG_Refresh(&hiwdg);
- __enable_irq(); // 开启全局中断
- return 1;
- }
- uint8_t DB_Save(uint8_t id, const char *buf, uint16_t len) { // 写入Flash(整个数据库内容)
- if (!is_valid_db_id(id) || buf == NULL || len > DB_FLASH_SIZE) {
- printf("DB_Save par error\n");
- return 0;
- }
- uint32_t addr = DB_ADDR[id];
- // Step1: 擦除整页
- if (!flash_erase_page(addr)) {
- printf("DB_Save: flash_erase fail 0x%08X\n", addr);
- return 0;
- }
- // Step2: 写入字符串数据(按64位字节写入)
- HAL_FLASH_Unlock();
- for (uint32_t i = 0; i < len; i += 8) {
- uint64_t word64 = 0xFFFFFFFFFFFFFFFFULL;
- memcpy(&word64, &buf[i], (len - i >= 8) ? 8 : (len - i));
- if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr + i, word64) != HAL_OK) {
- KV_PRINTF("DB_Save: flash_write fail 0x%08X\n", addr + i);
- HAL_FLASH_Lock();
- return 0;
- }
- }
- HAL_FLASH_Lock();
- KV_PRINTF("DB_Save: flash_write succ id=%d, len=%d\n", id, len);
- return 1;
- }
- /**@END --- FLASH擦除写入函数 */
- /**@BEGIN ------------ 键值对处理函数 -------------------*/
- uint8_t SaveKvCache(uint8_t id, const char *kv_str){ // 支持有则更新,无则新增,值为空则删除
- static char db_buf[DB_FLASH_SIZE];
- static char new_buf[DB_FLASH_SIZE];
- if (!is_valid_db_id(id) || kv_str == NULL || strlen(kv_str) >= KV_ITEM_MAX_LEN) {
- printf("[KV] Invalid DB ID or kv_str too long/null\n");
- return 0;
- }
- char key[KV_MAX_KEY_LEN + 1] = {0};
- const char *eq = strchr(kv_str, '=');
- if (!eq || eq - kv_str > KV_MAX_KEY_LEN) {
- printf("[KV] '=' not found or key too long in '%s'\n", kv_str);
- return 0;
- }
- strncpy(key, kv_str, eq - kv_str);
- key[eq - kv_str] = '\0';
- KV_PRINTF("[KV] Processing key='%s'\n", key);
- memset(db_buf, 0, DB_FLASH_SIZE);
- uint16_t old_len = DB_Dump(id, db_buf, DB_FLASH_SIZE); // 从 flash 对应 DB 区域读取数据到 db_buf
- KV_PRINTF("[KV] Existing DB length: %u bytes\n", old_len);
- memset(new_buf, 0, DB_FLASH_SIZE);
- int found = 0; // 是否找到相同 key
- const char *pos = db_buf;
- while ((pos = strstr(pos, "##")) != NULL) {
- const char *kv = pos + 2;
- const char *next = strstr(kv, "##");
- size_t len = next ? (size_t)(next - kv) : strlen(kv);
- char temp[KV_ITEM_MAX_LEN] = {0};
- strncpy(temp, kv, len);
- temp[len] = '\0';
- const char *eq_in = strchr(temp, '=');
- if (eq_in) {
- char key_in[KV_MAX_KEY_LEN + 1] = {0};
- strncpy(key_in, temp, eq_in - temp);
- key_in[eq_in - temp] = '\0';
- if (strcmp(key_in, key) == 0) {
- // 找到相同 key
- found = 1;
- if (strlen(eq + 1) > 0) { // 找到相同 key , 更新值或删除
- // 更新:保持位置不变
- strcat(new_buf, "##");
- strcat(new_buf, kv_str);
- KV_PRINTF("[KV] Updating key in place: %s\n", kv_str);
- } else {
- // 删除:跳过这个 key
- KV_PRINTF("[KV] Deleting key: %s\n", key_in);
- }
- } else {
- // 不是目标 key,原样拷贝
- strcat(new_buf, "##");
- strcat(new_buf, temp); // 找不到相同 key , 复制到 new_buf
- }
- }
- if (!next) break;
- pos = next;
- }
- // 如果没找到,且新值不为空 → 追加到末尾
- if (!found && strlen(eq + 1) > 0) {
- strcat(new_buf, "##");
- strcat(new_buf, kv_str);
- KV_PRINTF("[KV] Adding new kv at end: %s\n", kv_str);
- }
- strcat(new_buf, "##"); // 结尾
- KV_PRINTF("[KV] Final DB content (len=%u):\n%s\n", (unsigned int)strlen(new_buf), new_buf);
- uint8_t result = DB_Save(id, new_buf, strlen(new_buf)); // 把更新后的数据存回 flash
- if (result) {
- // KV_PRINTF("[KV] Flash save success\n");
- } else {
- // printf("[KV] Flash save failed\n");
- }
- return result;
- }
- void handle_cfg_set_common(uint8_t db_id, const char *key, const char *value){ // 通用处理函数 删除 更新 新增
- if (!is_valid_db_id(db_id)) {
- printf("error=invalid db id, rlt=411\r\n");
- return;
- }
- if (strlen(value) == 0) {
- // value 为空,删除 key
- KV_HandleDelete(db_id, key);
- return;
- }
- char tmp[64] = {0};
- if (pickup_string_from_key(db_id, key, tmp, sizeof(tmp))) {
- // key 存在 → 更新
- KV_HandleUpdate(db_id, key, value);
- } else {
- // key 不存在 → 新建
- KV_HandleInsert(db_id, key, value);
- }
- }
- void KV_HandleQuery(uint8_t db_id, const char* key){ // 读取
- if (!is_valid_db_id(db_id) || key == NULL) {
- printf("error=invalid db id or null key, rlt=450\r\n");
- return;
- }
- char val[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_key(db_id, key, val, sizeof(val))) {
- printf("fileid=%d, [%s=%s], ok\r\n", db_id, key, val);
- } else {
- printf("rlt=404, error=not exist\r\n");
- }
- }
- void KV_HandleUpdate(uint8_t db_id, const char* key, const char* value){ // 更新
- if (!is_valid_db_id(db_id) || key == NULL || value == NULL) {
- printf("error=invalid params, rlt=451\r\n");
- return;
- }
- char kv_buf[KV_ITEM_MAX_LEN] = {0};
- snprintf(kv_buf, sizeof(kv_buf), "%s=%s", key, value);
- uint8_t ok = SaveKvCache(db_id, kv_buf);
- if (ok) {
- printf("ok\r\n");
- } else {
- printf("error=update fail, rlt=452\r\n");
- }
- }
- void KV_HandleDelete(uint8_t db_id, const char* key){ // 删除
- if (!is_valid_db_id(db_id) || key == NULL) {
- printf("error=invalid params, rlt=453\r\n");
- return;
- }
- char kv_buf[KV_ITEM_MAX_LEN] = {0};
- char value[1] = {0}; // 空串表示删除
- snprintf(kv_buf, sizeof(kv_buf), "%s=%s", key, value);
- uint8_t ok = SaveKvCache(db_id, kv_buf);
- if (ok) {
- printf("ok\r\n");
- } else {
- printf("error=delete fail, rlt=454\r\n");
- }
- }
- void KV_HandleInsert(uint8_t db_id, const char* key, const char* value){ // 新增
- if (!is_valid_db_id(db_id) || key == NULL || value == NULL) {
- printf("error=invalid params, rlt=455\r\n");
- return;
- }
- char tmp[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_key(db_id, key, tmp, sizeof(tmp))) {
- printf("error=exists, rlt=456\r\n");
- return;
- }
- char kv_buf[KV_ITEM_MAX_LEN] = {0};
- snprintf(kv_buf, sizeof(kv_buf), "%s=%s", key, value);
- uint8_t ok = SaveKvCache(db_id, kv_buf);
- if (ok) {
- printf("ok\r\n");
- } else {
- printf("error=insert fail, rlt=457\r\n");
- }
- }
- void DB_SaveUInt(uint8_t dbId, const char *key, uint32_t value){ // 将数值存入 KV 数据库
- char kv_str[KV_MAX_VAL_LEN]; // 足够存 "key=value"
- snprintf(kv_str, sizeof(kv_str), "%s=%" PRIu32, key, value);
- SaveKvCache(dbId, kv_str);
- }
- void DB_SaveChar(uint8_t db_id, const char *key, const char *value){
- char buf[128];
- snprintf(buf, sizeof(buf), "%s=%s", key, value);
- SaveKvCache(db_id, buf);
- }
- void DB_SaveInt(uint8_t dbId, const char *key, int32_t value){
- char kv_str[KV_MAX_VAL_LEN];
- snprintf(kv_str, sizeof(kv_str), "%s=%" PRId32, key, value);
- SaveKvCache(dbId, kv_str);
- }
- void DB_SaveFloat(uint8_t dbId, const char *key, float value){
- char kv_str[KV_MAX_VAL_LEN];
- snprintf(kv_str, sizeof(kv_str), "%s=%.6f", key, value); // 保留 6 位小数
- SaveKvCache(dbId, kv_str);
- }
- /**@END --- 键值对处理函数 */
- /**@BEGIN ---------- 提取数据库数据函数 ---------------------------*/
- static int extract_kv(const char *src, const char *key, char *val_out, uint8_t max_len) { // 查找"##"分隔符,在分隔符之间查找提取指定key对应的value
- const char *pos = strstr(src, "##");
- while (pos) {
- const char *kv = pos + 2;
- const char *eq = strchr(kv, '=');
- const char *end = strstr(kv, "##");
- KV_PRINTF("[extract_kv] Searching key '%s' from segment: %.32s\n", key, kv);
-
- if (eq && end && eq < end) {
- char key_buf[KV_MAX_KEY_LEN + 1] = {0};
- strncpy(key_buf, kv, eq - kv);
- key_buf[eq - kv] = '\0';
- KV_PRINTF("[extract_kv] Found key: '%s'\n", key_buf);
-
- if (strcmp(key_buf, key) == 0) {
- size_t val_len = end - eq - 1;
- if (val_len >= max_len) val_len = max_len - 1;
- strncpy(val_out, eq + 1, val_len);
- val_out[val_len] = '\0';
- KV_PRINTF("[extract_kv] Matched key! Value: '%s'\n", val_out);
- return 1;
- }
- }else {
- // printf("[extract_kv] No valid key=value between ##...\n");
- }
- pos = strstr(pos + 2, "##");
- }
- // printf("[extract_kv] Key '%s' not found.\n", key);
- return 0;
- }
- uint8_t pickup_string_from_key(uint8_t id, const char *key, char *val_out, uint8_t max_len) { // 从指定数据库ID的键值存储中提取字符串值
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL) {
- printf("[pickup_string_from_key] Invalid input\n");
- return 0;
- }
- static char db_buf[DB_FLASH_SIZE];
- memset(db_buf, 0, sizeof(db_buf));
- uint16_t len = DB_Dump(id, db_buf, DB_FLASH_SIZE);
- KV_PRINTF("[pickup_string_from_key] Dumped len: %u\n", len);
- uint8_t res = extract_kv(db_buf, key, val_out, max_len);
- return res;
- }
- uint8_t pickup_int_from_key(uint8_t id, const char *key, int *val_out) { // 从指定数据库ID的键值存储中提取整数值
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL)
- return 0;
- char val_str[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_key(id, key, val_str, sizeof(val_str))) {
- *val_out = atoi(val_str);
- return 1;
- }
- return 0;
- }
- uint8_t pickup_uint32_from_key(uint8_t id, const char *key, uint32_t *val_out) { // 从数据库提取 uint32_t 类型
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL)
- return 0;
- char val_str[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_key(id, key, val_str, sizeof(val_str))) {
- *val_out = (uint32_t)strtoul(val_str, NULL, 10);
- return 1;
- }
- return 0;
- }
- uint8_t pickup_long_from_key(uint8_t id, const char *key, long *val_out) { // 从数据库提取 long 类型
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL)
- return 0;
-
- char val_str[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_key(id, key, val_str, sizeof(val_str))) {
- *val_out = strtol(val_str, NULL, 10);
- return 1;
- }
- return 0;
- }
- /**@END --- 提取数据库数据函数 */
- /**@BEGIN ------------ 控制台命令 一层入口函数 -------------------*/
- void handle_mac_set_cmd(const char *buf){ // 处理 ###::{"mac":"112233445566"} 设置设备SN号也就是MAC号
- uint8_t db_id = 0; // 固定数据库 0
- const char *prefix = "{\"mac\":\"";
- size_t prefix_len = strlen(prefix);
- // 必须匹配前缀
- if (strncmp(buf, prefix, prefix_len) != 0) {
- printf("error=invalid mac cmd\r\n");
- return;
- }
- // 找到结束的引号
- const char *end = strchr(buf + prefix_len, '"');
- if (!end) {
- printf("error=invalid mac format\r\n");
- return;
- }
- // 提取 value
- char value[128] = {0};
- size_t vlen = end - (buf + prefix_len);
- if (vlen >= sizeof(value)) {
- printf("error=mac too long\r\n");
- return;
- }
- strncpy(value, buf + prefix_len, vlen);
- value[vlen] = '\0';
- handle_cfg_set_common(db_id, "mac", value); // 更新数据库
-
- strncpy(JsRoot.mac, value, sizeof(JsRoot.mac) - 1); // 同步更新结构体
- JsRoot.mac[sizeof(JsRoot.mac) - 1] = '\0'; // 确保结尾有 '\0'
- }
- void handle_cfg_set_cmd(const char *buf){ // 处理 --cfg_set=${key1}=${val1} 系统配置-KV设置 专门处理数据库0的键值对
- uint8_t db_id = 0;
- char key[KV_MAX_VAL_LEN];
- char value[128];
-
- if (parse_cfg_set_cmd(buf, &db_id, key, sizeof(key), value, sizeof(value)) != 0) {
- printf("error=invalid cfg_set format, rlt=410\r\n");
- return;
- }
- handle_cfg_set_common(db_id, key, value); // 更新数据库
- sync_JsRoot_field(key, value); // 同步更新 JsRoot 对应字段
- }
- void handle_cfg_setx_cmd(const char *buf){ // 处理 --cfg_setx=X,${key}=${val} 通用配置-KV设置
- uint8_t db_id;
- char key[KV_MAX_VAL_LEN];
- char value[128];
-
- if (parse_cfg_setx_cmd(buf, &db_id, key, sizeof(key), value, sizeof(value)) != 0) {
- printf("error=invalid cfg_setx format, rlt=410\r\n");
- return;
- }
- handle_cfg_set_common(db_id, key, value); // 更新数据库
- sync_JsRoot_field(key, value); // 同步更新 JsRoot 对应字段
- }
- void handle_cfg_get_cmd(const char *buf){ // 处理 --cfg_get=${key} 读取键值内容
- const char *prefix = "--cfg_get=";
- size_t prefix_len = strlen(prefix);
- if (!buf || strncmp(buf, prefix, prefix_len) != 0) {
- printf("error=invalid cfg_get format, rlt=420\r\n");
- return;
- }
- const char *key = buf + prefix_len;
- if (strlen(key) == 0) {
- printf("error=empty key, rlt=421\r\n");
- return;
- }
- char val[128] = {0};
- for (uint8_t db_id = 0; db_id < DB_ID_MAX; db_id++) {
- if (pickup_string_from_key(db_id, key, val, sizeof(val))) {
- printf("fileid=%d, [%s=%s], ok\r\n", db_id, key, val);
- return; // 找到就退出
- }
- }
- // 遍历完还没找到
- printf("rlt=404, error=not exist.\r\n");
- }
- void handle_fileid_cmd(const char *buf){ // 处理 --fileid=X,0 读取库存信息
- const char *prefix = "--fileid=";
- size_t prefix_len = strlen(prefix);
- if (!buf || strncmp(buf, prefix, prefix_len) != 0) {
- printf("error=invalid fileid format, rlt=430\r\n");
- return;
- }
- // 解析 X,0
- uint8_t db_id = 0;
- int offset = 0;
- if (sscanf(buf + prefix_len, "%hhu,%d", &db_id, &offset) != 2) {
- printf("error=invalid fileid params, rlt=431\r\n");
- return;
- }
- if (!is_valid_db_id(db_id)) {
- printf("error=invalid db id, rlt=432\r\n");
- return;
- }
- // 读取数据库内容
- uint32_t addr = DB_ADDR[db_id];
- const uint8_t *db_addr = (const uint8_t *)addr;
- size_t db_len = get_db_used_len(db_id);
- if (!db_addr || db_len == 0) {
- printf("error=empty db, rlt=433\r\n");
- return;
- }
- // 打印头信息
- printf("DB_DUMP, fileid=%d, len=%u,\r\n", db_id, (unsigned)db_len);
- printf("addr=0x%08X+%d,content=\r\n", (unsigned int)db_addr, offset);
- // 数据库内容是以##key=value##key2=value2## 存储
- printf("[");
- for (size_t i = 0; i < db_len; i++) {
- char c = db_addr[i];
- if (c >= 32 && c <= 126) {
- putchar(c);
- }
- }
- printf("], ok\r\n");
- }
- void handle_clear_fileid_cmd(const char *buf){ // 处理 --clear_fileid=X 清除内部配置库
- const char *prefix = "--clear_fileid=";
- size_t prefix_len = strlen(prefix);
- if (!buf || strncmp(buf, prefix, prefix_len) != 0) {
- printf("error=invalid clear_fileid format, rlt=440\r\n");
- return;
- }
- uint8_t db_id = (uint8_t)atoi(buf + prefix_len);
- if (!is_valid_db_id(db_id)) {
- printf("error=invalid db id, rlt=441\r\n");
- return;
- }
- uint32_t addr = DB_ADDR[db_id];
- if (flash_erase_page(addr)) {
- printf("ok\r\n");
- } else {
- printf("error=erase fail, rlt=442\r\n");
- }
- }
- /**@END --- 控制台命令 一层入口函数 */
- /**@BEGIN ------------ 控制台命令 二层提取函数---------*/
- int parse_cfg_set_cmd(const char *buf, uint8_t *db_id, char *key, size_t key_sz, char *val, size_t val_sz){ // --cfg_set (固定 db=0) 提取 key、value---------
- if (!buf || !db_id || !key || !val) return -1;
- const char *prefix = "--cfg_set=";
- size_t prefix_len = strlen(prefix);
- if (strncmp(buf, prefix, prefix_len) != 0) return -1;
- *db_id = 0; // 固定 0 号库
- const char *kv_str = buf + prefix_len;
- char *eq = strchr(kv_str, '=');
- if (!eq) return -1;
- // 提取 key
- size_t klen = eq - kv_str;
- if (klen >= key_sz) return -1;
- strncpy(key, kv_str, klen);
- key[klen] = '\0';
- // 提取 value(可能为空串)
- const char *val_str = eq + 1;
- if (strlen(val_str) >= val_sz) return -1;
- strcpy(val, val_str);
- return 0;
- }
- int parse_cfg_setx_cmd(const char *buf, uint8_t *db_id, char *key, size_t key_sz, char *val, size_t val_sz){ // --cfg_setx 提取 db、key、value--------------
- if (!buf || !db_id || !key || !val) return -1;
- // 格式: --cfg_setx=X,key=value
- // 先找到 '=' 号
- const char *prefix = "--cfg_setx=";
- size_t prefix_len = strlen(prefix);
- if (strncmp(buf, prefix, prefix_len) != 0) return -1;
- // 解析 DB ID
- const char *p = buf + prefix_len;
- char *comma = strchr(p, ',');
- if (!comma) return -1;
- *comma = '\0';
- *db_id = (uint8_t)atoi(p);
- *comma = ','; // 还原
- // 解析 key 和 value
- const char *kv_str = comma + 1; // 指向 key=value
- char *eq = strchr(kv_str, '=');
- if (!eq) return -1;
- // 提取 key
- size_t klen = eq - kv_str;
- if (klen >= key_sz) return -1;
- strncpy(key, kv_str, klen);
- key[klen] = '\0';
- // 提取 value(可能为空串)
- const char *val_str = eq + 1;
- if (strlen(val_str) >= val_sz) return -1;
- strcpy(val, val_str);
- return 0;
- }
- /**@END --- 控制台命令 二层提取函数 */
- /**@BEGIN --------------- 初始化函数 ------------------*/
- void DB_InitAllConfigs(void) { // 初始化数据库
- size_t total = sizeof(init_table) / sizeof(init_table[0]);
- for (size_t i = 0; i < total; i++) {
- const char *kv_str = init_table[i].kv_str;
- char key_name[KV_MAX_KEY_LEN + 1] = {0};
- const char *eq = strchr(kv_str, '=');
- if (eq) {
- strncpy(key_name, kv_str, eq - kv_str);
- key_name[eq - kv_str] = '\0';
- char existing_val[KV_MAX_VAL_LEN] = {0};
- uint8_t exists = pickup_string_from_key(init_table[i].db_id,
- key_name,
- existing_val,
- sizeof(existing_val));
- if (!exists) {
- if (!SaveKvCache(init_table[i].db_id, kv_str)) {
- // printf("SaveKvCache fail: %s\n", kv_str);
- } else {
- // printf("SaveKvCache succ: %s\n", kv_str);
- }
- }
- }
- HAL_IWDG_Refresh(&hiwdg); // 喂狗,防止初始化太久被复位
- osDelay(1);
- }
-
- JsRoot.vers_id = CURRENT_FIRMWARE_VERSION;
- DB_SaveUInt(DB_ID_SYSTEM, KV_KEY_VERSION , JsRoot.vers_id ); // 存入 VERSION 到 SYSTEM 数据库
-
- printf("DB_InitAllConfigs complete.\n");
- osDelay(100);
- DB_Dump_to_JsRoot();
- printf("DB_Dump_to_JsRoot ok \r\n");
- }
- uint16_t DB_Dump(uint8_t id, char *buf, uint16_t buf_len) { // 从Flash读取区域内容到缓存
- if (!is_valid_db_id(id)) {
- printf("[DB_Dump] Invalid DB ID: %d\n", id);
- return 0;
- }
- if (buf == NULL) {
- printf("[DB_Dump] NULL buffer pointer\n");
- return 0;
- }
- if (buf_len < DB_FLASH_SIZE) {
- printf("[DB_Dump] Buffer too small: buf_len = %d, required = %d\n", buf_len, DB_FLASH_SIZE);
- return 0;
- }
- uint32_t addr = DB_ADDR[id];
- const uint8_t *flash_ptr = (const uint8_t *)addr;
- // printf("[DB_Dump] Start reading from address: 0x%08X (DB_ID: %d)\n", addr, id);
-
- uint16_t i;
- for (i = 0; i < DB_FLASH_SIZE && i < buf_len - 1; i++) {
- buf[i] = flash_ptr[i];
- if (flash_ptr[i] == 0xFF) {
- // printf("[DB_Dump] Reached 0xFF at offset %d\n", i);
- break;
- }
- }
- buf[i] = '\0'; // null终止
- return i;
- }
- uint8_t pickup_string_from_cache(uint8_t id, const char *key, char *val_out, uint8_t max_len) { // 从缓存提取字符串
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL) {
- return 0;
- }
- return extract_kv(db_cache[id], key, val_out, max_len);
- }
- uint8_t pickup_int_from_cache(uint8_t id, const char *key, int *val_out) { // 从缓存提取 int
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL) {
- return 0;
- }
- char val_str[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_cache(id, key, val_str, sizeof(val_str))) {
- *val_out = atoi(val_str);
- return 1;
- }
- return 0;
- }
- uint8_t pickup_uint32_from_cache(uint8_t id, const char *key, uint32_t *val_out) { // 从缓存提取 uint32_t
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL) {
- return 0;
- }
- char val_str[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_cache(id, key, val_str, sizeof(val_str))) {
- *val_out = (uint32_t)strtoul(val_str, NULL, 10);
- return 1;
- }
- return 0;
- }
- uint8_t pickup_long_from_cache(uint8_t id, const char *key, long *val_out) { // 从缓存提取 long
- if (!is_valid_db_id(id) || key == NULL || val_out == NULL) {
- return 0;
- }
- char val_str[KV_MAX_VAL_LEN] = {0};
- if (pickup_string_from_cache(id, key, val_str, sizeof(val_str))) {
- *val_out = strtol(val_str, NULL, 10);
- return 1;
- }
- return 0;
- }
- void DB_Dump_to_JsRoot(void) { // 从数据库同步到 缓存结构体 JsRoot
- DB_Load_All(); // 一次性加载所有数据库到缓存里
- DB_SyncAllToJsRoot(); // 使用缓存解析,不再访问 Flash
- }
- void DB_Load_All(void) { // 一次性读取所有数据库到 RAM
-
- for (uint8_t id = 0; id < 3; id++) {
- db_cache_len[id] = DB_Dump(id, db_cache[id], DB_FLASH_SIZE); // db_cache用来缓存每个库的数据
- }
- }
- void DB_SyncAllToJsRoot(void) {
- char key[64]; char val[128];
-
- if(JsRoot.work == NULL) JsRoot.work = &JsWork; // 自动赋值
-
- for (uint8_t id = 0; id < 3; id++) {
-
- const char *p = db_cache[id];
- const char *pend = p + db_cache_len[id];
- // printf(">>> Start parsing DB[%d], len=%u\n", id, db_cache_len[id]);
-
- while (p < pend) { // 找到 "##" 开头
- const char *start = memmem_custom(p, pend - p, "##", 2);
-
- if (!start) break;
- start += 2; // 跳过 ##
-
- const char *end = memmem_custom(start, pend - start, "##", 2);
- if (!end) end = pend; // 没找到结束标记
-
- // 在 start 到 end 之间找 '='
- const char *sep = memchr(start, '=', end - start);
- if (!sep) {
- // printf("DB[%d] stop: no '=' found at offset=%ld\n", id, start - db_cache[id]);
- p = end;
- continue;
- }
-
- size_t klen = sep - start;
- size_t vlen = end - (sep + 1);
-
- if (klen >= sizeof(key)) klen = sizeof(key) - 1;
- if (vlen >= sizeof(val)) vlen = sizeof(val) - 1;
-
- strncpy(key, start, klen); key[klen] = '\0';
- strncpy(val, sep + 1, vlen); val[vlen] = '\0';
-
- // printf("DB[%d] key=%s, val=%s, p_offset=%ld\n", id, key, val, start - db_cache[id]);
-
- sync_JsRoot_field(key, val);
- p = end; // 移动到下一个 "##" 开头或结尾
- HAL_IWDG_Refresh(&hiwdg); // 刷新看门狗
-
- }
- // printf("<<< End of DB[%d]\n\n", id);
- }
-
- }
- void sync_JsRoot_field(const char *key, const char *value) { // 查询更新某个缓存结构体参数
- for (size_t i = 0; i < sizeof(kv_map) / sizeof(kv_map[0]); i++) {
- if (strcmp(key, kv_map[i].key) == 0) {
- // uint8_t *base = kv_map[i].in_work ? (uint8_t*)&JsRoot.work : (uint8_t*)&JsRoot;
- uint8_t *base = kv_map[i].in_work ? (uint8_t*)JsRoot.work : (uint8_t*)&JsRoot;
- void *field_ptr = base + kv_map[i].offset;
- switch (kv_map[i].type) {
- case FIELD_STRING:
- snprintf((char*)field_ptr, kv_map[i].size, "%s", value);
- break;
- case FIELD_INT:
- *(int*)field_ptr = strtol(value, NULL, 10);
- break;
- case FIELD_UINT8:
- *(uint8_t*)field_ptr = (uint8_t)strtoul(value, NULL, 10);
- break;
- case FIELD_UINT16:
- *(uint16_t*)field_ptr = (uint16_t)strtoul(value, NULL, 10);
- break;
- case FIELD_UINT32:
- *(uint32_t*)field_ptr = strtoul(value, NULL, 0);
- break;
- case FIELD_FLOAT:
- *(float*)field_ptr = str_to_float(value);
- break;
- }
- HAL_IWDG_Refresh(&hiwdg); // 刷新看门狗
- return; // 找到并更新完成
- }
- }
- printf("sync_JsRoot_field: unknown key = %s\n", key);
- }
- void DB__Dump_IAP_LOAD(void){
- int iapload =0;
- pickup_int_from_key(2,KV_KEY_IAP_LOAD,&iapload);
- JsRoot.iapLoadStatus = iapload;
- printf("iapLoadStatus %d\r\n",JsRoot.iapLoadStatus);
- }
- /**@END --- 初始化函数 */
- /* USER CODE BEGIN EFP */
|