fusion/hal/hal_env/hal_env.c

378 lines
10 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}