#include "flash_port.h" #include #include "mx_log.h" #undef MX_LOGD #undef MX_LOGI #undef MX_LOGW #undef MX_LOGE #define MX_LOGD FLASH_PORT_LOGD #define MX_LOGI FLASH_PORT_LOGI #define MX_LOGW FLASH_PORT_LOGW #define MX_LOGE FLASH_PORT_LOGE #define FLASH_PORT_TAG FLASH_PORT_LOG_TAG #define FLASH_PORT_ERASE_PROBE_BYTES 8U #define FLASH_PORT_VERIFY_CHUNK_BYTES 64U static flash_port_ops_t s_flash_ops = {0}; void flash_port_init(const flash_port_ops_t *ops) { if (ops != NULL) { s_flash_ops = *ops; } } static uint8_t hal_read(uint32_t addr, void *buf, uint32_t len) { if (s_flash_ops.read) { return s_flash_ops.read(addr, buf, len/2); } return 0; } static uint8_t hal_write(uint32_t addr, const void *buf, uint32_t len) { if (s_flash_ops.write) { return s_flash_ops.write(addr, buf, len); } return 0; } static uint8_t hal_erase(uint32_t addr, uint32_t len) { if (s_flash_ops.erase) { return s_flash_ops.erase(addr, len); } return 0; } static uint8_t hal_is_erased(uint32_t addr, uint32_t len) { if (s_flash_ops.is_erased) { return s_flash_ops.is_erased(addr, len); } return 0; } static uint32_t flash_port_min_u32(uint32_t a, uint32_t b) { return (a < b) ? a : b; } static uint8_t flash_port_addr_is_erased(uint32_t addr, uint32_t bytes) { uint32_t probe_bytes = flash_port_min_u32(bytes, FLASH_PORT_ERASE_PROBE_BYTES); if (probe_bytes == 0U) { probe_bytes = FLASH_PORT_ERASE_PROBE_BYTES; } return hal_is_erased(addr, probe_bytes); } static uint8_t flash_port_erase_range(uint32_t start_addr, uint32_t bytes) { if (!hal_erase(start_addr, bytes)) { return 0; } return flash_port_addr_is_erased(start_addr, bytes); } static uint8_t flash_port_verify_bytes(uint32_t addr, const void *expect, uint32_t bytes) { uint8_t verify_buf[FLASH_PORT_VERIFY_CHUNK_BYTES]; const uint8_t *expect_bytes = (const uint8_t *)expect; uint32_t offset = 0U; if ((expect == NULL) && (bytes > 0U)) { return 0; } while (offset < bytes) { uint32_t chunk = flash_port_min_u32(bytes - offset, FLASH_PORT_VERIFY_CHUNK_BYTES); if (!hal_read(addr + offset, verify_buf, chunk)) { MX_LOGE(FLASH_PORT_TAG, "verify read failed addr=0x%08X offset=%u", (unsigned int)addr, (unsigned int)offset); return 0; } if (memcmp(verify_buf, expect_bytes + offset, chunk) != 0) { MX_LOGE(FLASH_PORT_TAG, "verify failed addr=0x%08X offset=%u", (unsigned int)addr, (unsigned int)offset); return 0; } offset += chunk; } return 1; } static uint8_t flash_port_load_cali_raw(app_math_cali_t *params) { if (params == NULL) { MX_LOGE(FLASH_PORT_TAG, "load cali raw null params"); return 0; } if (sizeof(app_math_cali_t) > FLASH_PORT_CALI_REGION_SIZE) { MX_LOGE(FLASH_PORT_TAG, "cali region too small: need=%u size=%u", (unsigned int)sizeof(app_math_cali_t), (unsigned int)FLASH_PORT_CALI_REGION_SIZE); return 0; } return hal_read(FLASH_PORT_CALI_REGION_ADDR, params, sizeof(app_math_cali_t)); } static uint8_t flash_port_store_cali_raw(const app_math_cali_t *params) { if (params == NULL) { MX_LOGE(FLASH_PORT_TAG, "store cali raw null params"); return 0; } if (sizeof(app_math_cali_t) > FLASH_PORT_CALI_REGION_SIZE) { MX_LOGE(FLASH_PORT_TAG, "cali region too small: need=%u size=%u", (unsigned int)sizeof(app_math_cali_t), (unsigned int)FLASH_PORT_CALI_REGION_SIZE); return 0; } if (!flash_port_erase_range(FLASH_PORT_CALI_REGION_ADDR, FLASH_PORT_CALI_REGION_SIZE)) { MX_LOGE(FLASH_PORT_TAG, "erase cali region failed"); return 0; } if (!hal_write(FLASH_PORT_CALI_REGION_ADDR, params, sizeof(app_math_cali_t))) { MX_LOGE(FLASH_PORT_TAG, "write cali raw failed"); return 0; } return flash_port_verify_bytes(FLASH_PORT_CALI_REGION_ADDR, params, sizeof(app_math_cali_t)); } uint8_t flash_port_math_load(app_math_cali_t *params) { if (!flash_port_load_cali_raw(params)) { return 0; } if ((params->min_trigger_res_value == 0xFFFFU) && (params->max_trigger_res_value == 0xFFFFU) && (params->div_trigger_res_value == 0xFFFFU) && (params->max_display_value == 0xFFFFU)) { MX_LOGW(FLASH_PORT_TAG, "math area is empty"); return 0; } return 1; } uint8_t flash_port_math_save(const app_math_cali_t *params) { app_math_cali_t merged = {0}; if (params == NULL) { MX_LOGE(FLASH_PORT_TAG, "math save null params"); return 0; } (void)flash_port_load_cali_raw(&merged); merged.check_cail = params->check_cail; merged.min_trigger_res_value = params->min_trigger_res_value; merged.max_trigger_res_value = params->max_trigger_res_value; merged.div_trigger_res_value = params->div_trigger_res_value; merged.max_display_value = params->max_display_value; merged.sensor_data_type = params->sensor_data_type; return flash_port_store_cali_raw(&merged); } uint8_t flash_port_math_clear(void) { if (!flash_port_erase_range(FLASH_PORT_CALI_REGION_ADDR, FLASH_PORT_CALI_REGION_SIZE)) { MX_LOGE(FLASH_PORT_TAG, "math clear erase failed"); return 0; } return 1; } uint8_t flash_port_pressure_load(app_math_cali_t *params) { if (!flash_port_load_cali_raw(params)) { return 0; } if ((params->num_points == 0xFFFFU) || (params->num_points > MAX_PRESSURE_POINTS)) { MX_LOGW(FLASH_PORT_TAG, "invalid pressure points=%u", (unsigned int)params->num_points); return 0; } return 1; } uint8_t flash_port_pressure_save(const app_math_cali_t *params) { app_math_cali_t merged = {0}; if ((params == NULL) || (params->num_points > MAX_PRESSURE_POINTS)) { MX_LOGE(FLASH_PORT_TAG, "pressure save invalid params, num_points=%u", (unsigned int)(params ? params->num_points : 0U)); return 0; } (void)flash_port_load_cali_raw(&merged); merged.num_points = params->num_points; memcpy(merged.pressure_points, params->pressure_points, sizeof(merged.pressure_points)); return flash_port_store_cali_raw(&merged); } uint8_t flash_port_pressure_clear(void) { app_math_cali_t merged = {0}; (void)flash_port_load_cali_raw(&merged); merged.num_points = 0U; memset(merged.pressure_points, 0, sizeof(merged.pressure_points)); return flash_port_store_cali_raw(&merged); } uint8_t flash_port_map_load(uint16_t *map_matrix, uint32_t map_words) { uint32_t map_bytes = map_words * sizeof(uint16_t); if ((map_matrix == NULL) || (map_words != FLASH_PORT_MAP_WORDS)) { MX_LOGE(FLASH_PORT_TAG, "map load bad arg, words=%u", (unsigned int)map_words); return 0; } if (map_bytes > FLASH_PORT_MAP_REGION_SIZE) { MX_LOGE(FLASH_PORT_TAG, "map region too small: need=%u size=%u", (unsigned int)map_bytes, (unsigned int)FLASH_PORT_MAP_REGION_SIZE); return 0; } if (flash_port_addr_is_erased(FLASH_PORT_MAP_REGION_ADDR, map_bytes)) { MX_LOGW(FLASH_PORT_TAG, "map area is empty"); return 0; } return hal_read(FLASH_PORT_MAP_REGION_ADDR, map_matrix, map_bytes); } uint8_t flash_port_map_save(const uint16_t *map_matrix, uint32_t map_words) { uint32_t map_bytes = map_words * sizeof(uint16_t); if ((map_matrix == NULL) || (map_words != FLASH_PORT_MAP_WORDS)) { MX_LOGE(FLASH_PORT_TAG, "map save bad arg, words=%u", (unsigned int)map_words); return 0; } if (map_bytes > FLASH_PORT_MAP_REGION_SIZE) { MX_LOGE(FLASH_PORT_TAG, "map region too small: need=%u size=%u", (unsigned int)map_bytes, (unsigned int)FLASH_PORT_MAP_REGION_SIZE); return 0; } if (!flash_port_erase_range(FLASH_PORT_MAP_REGION_ADDR, FLASH_PORT_MAP_REGION_SIZE)) { MX_LOGE(FLASH_PORT_TAG, "map erase failed"); return 0; } if (!hal_write(FLASH_PORT_MAP_REGION_ADDR, map_matrix, map_bytes)) { MX_LOGE(FLASH_PORT_TAG, "map write failed"); return 0; } return flash_port_verify_bytes(FLASH_PORT_MAP_REGION_ADDR, map_matrix, map_bytes); } uint8_t flash_port_map_clear(void) { if (!flash_port_erase_range(FLASH_PORT_MAP_REGION_ADDR, FLASH_PORT_MAP_REGION_SIZE)) { MX_LOGE(FLASH_PORT_TAG, "map clear erase failed"); return 0; } return 1; } uint8_t flash_port_creep_load(app_creep_params *params) { uint32_t raw_data[2]; if (params == NULL) { return 0; } if (!hal_read(FLASH_PORT_CREEP_REGION_ADDR, raw_data, sizeof(raw_data))) { return 0; } if ((raw_data[0] == 0xFFFFFFFFUL) && (raw_data[1] == 0xFFFFFFFFUL)) { return 0; } params->creep_strength = (uint8_t)raw_data[0]; params->creep_level = (uint8_t)raw_data[1]; return 1; } uint8_t flash_port_creep_save(const app_creep_params *params) { uint32_t raw_data[2]; if (params == NULL) { return 0; } raw_data[0] = (uint32_t)params->creep_strength; raw_data[1] = (uint32_t)params->creep_level; if (!flash_port_erase_range(FLASH_PORT_CREEP_REGION_ADDR, FLASH_PORT_CREEP_REGION_SIZE)) { return 0; } if (!hal_write(FLASH_PORT_CREEP_REGION_ADDR, raw_data, sizeof(raw_data))) { return 0; } return flash_port_verify_bytes(FLASH_PORT_CREEP_REGION_ADDR, raw_data, sizeof(raw_data)); } uint8_t flash_port_creep_clear(void) { if (!flash_port_erase_range(FLASH_PORT_CREEP_REGION_ADDR, FLASH_PORT_CREEP_REGION_SIZE)) { return 0; } return 1; } uint8_t flash_port_device_info_load(app_dev_info *info) { if (info == NULL) { return 0; } if (flash_port_addr_is_erased(FLASH_PORT_DEVICE_INFO_REGION_ADDR, sizeof(*info))) { return 0; } return hal_read(FLASH_PORT_DEVICE_INFO_REGION_ADDR, info, sizeof(*info)); } uint8_t flash_port_device_info_save(const app_dev_info *info) { if (info == NULL) { return 0; } if (!flash_port_erase_range(FLASH_PORT_DEVICE_INFO_REGION_ADDR, FLASH_PORT_DEVICE_INFO_REGION_SIZE)) { return 0; } if (!hal_write(FLASH_PORT_DEVICE_INFO_REGION_ADDR, info, sizeof(*info))) { return 0; } return flash_port_verify_bytes(FLASH_PORT_DEVICE_INFO_REGION_ADDR, info, sizeof(*info)); }