378 lines
10 KiB
C
378 lines
10 KiB
C
|
#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;
|
|||
|
}
|