Files
2026-04-09 10:14:20 +08:00

394 lines
10 KiB
C

#include "flash_port.h"
#include <string.h>
#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));
}