fusion/hal/hal_env/hal_env.c

378 lines
10 KiB
C
Raw Normal View History

2025-08-05 07:53:44 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <iobuffer.h>
#include <crc32.h>
#include <hal_interface_flash.h>
#include "hal_env.h"
#include "hlog.h"
#define TAG "TAG_ENV"
#define BACKUP_MAGIC 0x5A5AA5A5
static int8_t g_actflag = -1;
static int8_t g_modifyed_flag = 0;
static int8_t g_inited = 0;
static OS_MUTEX g_env_mutex = {0};
static Env_Header g_env_header = {0};
static char * g_env_values[ENV_CFG_MAX] = {0}; //all string are hv_malloc-ed
static inline int32_t hal_env_is_valid(int32_t index) {
if ( index <= ENV_CFG_START || index >= ENV_CFG_MAX) {
hloge("Invalid env index : %d\n", index);
return 0;
}
return 1;
}
static void hal_env_header_print(const char * prefix, const Env_Header* header)
{
hlogd("%s crc:%x age:%d version:%d\n", prefix,header->crc, header->age, header->version);
}
int32_t hal_env_mutex_lock()
{
return os_mutex_lock(&g_env_mutex);
}
int32_t hal_env_mutex_unlock()
{
return os_mutex_unlock(&g_env_mutex);
}
//load header and g_env_values from envbuff
static int32_t hal_env_load_head_values(const void * envbuff, Env_Header * header)
{
//backup headers.
memcpy(header, envbuff, sizeof(Env_Header));
//hv_free old value
int32_t i = 0;
for (; i < ENV_CFG_MAX; i++) {
if ( g_env_values[i]) {
hv_free(g_env_values[i]);
g_env_values[i] = NULL;
}
}
//extract/parse all values.
ENV_CFG e;
const unsigned char * p = (const unsigned char *)envbuff + sizeof(Env_Header);
int32_t index;
int32_t values = 0;
//envbuff is sth like header+3hello\02world\0(the end of valid data)+\0
while ( (e = (ENV_CFG)*p) != ENV_CFG_START) {
index = e;
p++; //p now point to string value start
if (hal_env_is_valid(index)) {
g_env_values[index] = strdup((const char *)p); //clone a string for easy use
values++;
}
while(*p) p++; //to string end
p+=1; //skip '\0', p now is next ENV_CFG
}
return values;
}
int32_t hal_env_dump(){
int32_t i = 1;
for (; i < ENV_CFG_MAX; i++) {
const char * value = g_env_values[i];
if ( value && value[0]) {
hlogd("#%d=%s\n", i, value);
}
else {
hlogd("#%d not set.\n", i);
}
}
return 0;
}
int32_t hal_env_save()
{
iobuffer buf;
iobuffer_init(&buf);
unsigned char key;
unsigned char zero = 0;
int32_t hasZero = 0;
if (!g_modifyed_flag)
return 0;
hal_env_mutex_lock();
g_env_header.age++;
//Note: the crc is not right at this time, will update later.
iobuffer_appendData(&buf, &g_env_header, sizeof(g_env_header));
int32_t i = 0;
for (; i < ENV_CFG_MAX; i++) {
key = i;
char * value = g_env_values[i];
if ( value && value[0] ) {
iobuffer_appendData(&buf, &key, 1);
iobuffer_appendData(&buf,value, strlen(value));
iobuffer_appendData(&buf, &zero, 1);
hasZero = 1;
}
}
iobuffer_appendData(&buf,&zero, 1);
if (!hasZero) {
//write 0 again as no any value has written
iobuffer_appendData(&buf,&zero, 1);
}
Env_Header* header = (Env_Header*)buf.iodata;
//update crc, exclude crc(4 bytes), already contains last 00 2 bytes.
g_env_header.crc = header->crc = crc32(0, buf.iodata + 4, buf.size - 4);
if (0 == g_actflag) {
hlogd("update env1 addr : %p, size=%d,age=%d\n", ENV_CFG_1, buf.size, g_env_header.age);
hal_flash_write(ENV_CFG_1, buf.iodata, buf.size);
g_actflag = 1;
}
else {
hlogd("update env0 addr : %p, size=%d,age=%d\n", ENV_CFG_0, buf.size, g_env_header.age);
hal_flash_write(ENV_CFG_0, buf.iodata, buf.size);
g_actflag = 0;
}
g_modifyed_flag = 0;
hal_env_mutex_unlock();
return g_modifyed_flag;
}
int32_t hal_env_set_string(ENV_CFG e, const char * value)
{
int32_t index = (int32_t)e;
if (!hal_env_is_valid(index))
return 0;
//set both value and current not null for strcmp
const char * current = hal_env_get_string(e, "");
value = value ? value : "";
if ( strcmp(current, value) == 0)
return 0; //no change
g_modifyed_flag = 1;
hv_free(g_env_values[index]);
if ( *value != '\0' ) {
g_env_values[index] = strdup(value);
}else {
g_env_values[index] = NULL;
}
return 1;
}
const char* hal_env_get_string(ENV_CFG e, const char * def_val)
{
int32_t index = (int32_t)e;
if (!hal_env_is_valid(index))
return def_val;
const char * value = g_env_values[index];
if (!value || value[0] == '\0')
return def_val;
return value;
}
int32_t hal_env_is_same_value(ENV_CFG e, const char * value){
const char * val = hal_env_get_string(e, NULL);
if (val == NULL || value == NULL)
return 0;
return !strcmp(val, value);
}
int32_t hal_env_get_int(ENV_CFG e, int32_t def_val)
{
const char * str = hal_env_get_string(e, NULL);
if (str == NULL)
{
//hlogd("%s, e:%d, str NULL\n", __func__, e);
return def_val;
}
//hlogd("%s, e:%d, str:%s\n", __func__, e, str);
char *endptr;
long ret = strtol(str, &endptr, 10);
if ( *endptr != '\0' )
{
hlogd("env(%d) contains a invalid int32_t: %s\n", e, str);
return def_val;
}
return (int32_t)ret;
}
int32_t hal_env_set_int(ENV_CFG e, int32_t value)
{
char buf[64];
sprintf(buf, "%d", value);
return hal_env_set_string(e, buf);
}
//used by cli_command.cpp only, so no definition in .h file
extern void hal_env_clear() {
int32_t i = ENV_CFG_START+1;
for (; i < ENV_CFG_MAX; i++)
{
if ( g_env_values[i])
{
hv_free(g_env_values[i]);
g_env_values[i] = NULL;
}
}
// no need u-boot as well
g_modifyed_flag = 1;
}
int32_t hal_env_active_age_load(Env_Header* header)
{
const char* start = (const char*)header;
const char* tail = start + ENV_SIZE - 1;
//找到两个连续?知道env有效长度的结?
const char * p = start + sizeof(Env_Header);
while( (p < tail) && (p[0] || p[1]))
p++;
if (p >= tail)
{
hloge("env data not found end,age=%d\n", header->age);
return -1;
}
//p指向第一个结尾的0, 加上最后一0也参与crc验证需要加2然后去掉最前面的crc本身
int32_t avalid = p - start + 2 - 4;
uint32_t crc = crc32(0, &header->age, avalid);
if ( crc != header->crc)
{
hloge("env data crc error, age:%d, len:%d, crc %X!=%X\n", header->age, avalid, crc, header->crc);
return -1;
}
//Good
// hlogd("env data len:%d,crc:%X,age:%d\n", avalid, crc, header->age);
return avalid;
}
//find which address is the right env.
static int32_t find_right_env(char* buf0, char* buf1)
{
int32_t actflag = -1; //invalid value
Env_Header* header0 = (Env_Header* )buf0;
Env_Header* header1= (Env_Header* )buf1;
hal_flash_read(ENV_CFG_0, buf0, ENV_SIZE);
hal_flash_read(ENV_CFG_1, buf1, ENV_SIZE);
if (header0->age >= header1->age)
{
if (hal_env_active_age_load(header0) > 0)
actflag = 0;
else if (hal_env_active_age_load(header1) > 0)
actflag = 1;
} else {
if (hal_env_active_age_load(header1) > 0)
actflag = 1;
else if (hal_env_active_age_load(header0) > 0)
actflag = 0;
}
return actflag;
}
int32_t hal_env_init()
{
int32_t ret = -1;
if (!g_inited)
{
Env_Header* env0 = NULL, * env1 = NULL;
Env_Header* cur_env;
os_mutex_create(&g_env_mutex);
env0 = (Env_Header*)hv_malloc(ENV_SIZE);
env1 = (Env_Header*)hv_malloc(ENV_SIZE);
if (!env0 || !env1 )
{
hloge("memory alloc error!\n");
goto exit;
}
//read boot env
g_actflag = find_right_env((char *)env0, (char *)env1);
if (g_actflag < 0)
{
memset(env0, 0, ENV_SIZE);
env0->age = 1;
env0->version = 1;
env0->crc = crc32(0, &env0->age, sizeof(Env_Header) - 4 + 2); // exclude crc(4 bytes), plus 2 bytes for 00
hal_flash_write(ENV_CFG_1, (char *)env0, sizeof(Env_Header) + 2);
env0->crc = crc32(0, &env0->age, sizeof(Env_Header) - 4 + 2); // exclude crc(4 bytes), plus 2 bytes for 00
hal_flash_write(ENV_CFG_0, (char *)env0, sizeof(Env_Header) + 2);
g_actflag = 0;
}
cur_env = (g_actflag == 0) ? env0 : env1;
int32_t valid_items = hal_env_load_head_values(cur_env, &g_env_header);
char buf[128];
snprintf(buf, sizeof(buf), "Active env=%d items=%d", g_actflag, valid_items);
hal_env_header_print(buf, cur_env);
ret = 0;
g_inited = 1;
exit:
hv_free(env0);
hv_free(env1);
}else{
ret = 0;
}
return ret;
}
int32_t hal_env_deinit(){
if (g_inited){
g_inited = 0;
os_mutex_delete(&g_env_mutex);
}
return 0;
}
static int32_t hal_env_cmd(int32_t argc, char ** argv)
{
hal_env_mutex_lock();
if ( argc == 1 ) {
hal_env_dump();
}
else if ( !strcmp(argv[1], "get")) {
const char * key = argv[2];
if (!key) {
hal_env_dump();
}
else {
hlogd("%s\n", hal_env_get_string((ENV_CFG)atoi(key), ""));
}
}
else if ( !strcmp(argv[1], "save")) {
hal_env_save();
}
else if ( !strcmp(argv[1], "set")) {
const char * key = argv[2];
const char * value = argv[3];
if (key){
hal_env_set_string((ENV_CFG)atoi(key), value);
}
}
else if ( !strcmp(argv[1], "clear")) {
hal_env_clear();
}else if ( !strcmp(argv[1], "both")) {
hal_env_dump();
}
else {
hlogd("Unknown command: <%s>\n", argv[1]);
}
hal_env_mutex_unlock();
return 0;
}