initial commit
This commit is contained in:
2
hal/hal_env/config.mk
Executable file
2
hal/hal_env/config.mk
Executable file
@@ -0,0 +1,2 @@
|
||||
SRC += $(wildcard $(HAL_DIR)/hal_env/*.c)
|
||||
CFLAGS += -I$(HAL_DIR)/hal_env
|
||||
378
hal/hal_env/hal_env.c
Executable file
378
hal/hal_env/hal_env.c
Executable file
@@ -0,0 +1,378 @@
|
||||
#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;
|
||||
}
|
||||
103
hal/hal_env/hal_env.h
Executable file
103
hal/hal_env/hal_env.h
Executable file
@@ -0,0 +1,103 @@
|
||||
/*************************************************************************
|
||||
File name : hal_env.h
|
||||
Module : hal_env
|
||||
Author :
|
||||
Copyright :
|
||||
Version : 0.1
|
||||
Created on : 2022-02-10
|
||||
Creator : amir.liang
|
||||
Description :
|
||||
get/set/save enviroment paramters.
|
||||
Modify History:
|
||||
1. Date: Author: Modification:
|
||||
2022-04-20 amir need add a task or threadpool to save in some time.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __HAL_ENV_H__
|
||||
#define __HAL_ENV_H__
|
||||
#include <stdint.h>
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! ***************************Flash layout***************************************
|
||||
//! HEADER: 64K(env_back) + 64K(env1) + 64K(env2)
|
||||
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define ENV_CFG_0 "env0"
|
||||
#define ENV_CFG_1 "env1"
|
||||
#define ENV_CFG_BACKUP "env_backup"//not modify after factory
|
||||
#define ENV_SIZE ((uint16_t)(64*1024))
|
||||
|
||||
|
||||
//each env field is an enum, supports up to 255
|
||||
typedef enum{
|
||||
ENV_CFG_START = 0,
|
||||
ENV_CFG_DEV,
|
||||
ENV_CFG_TEST,
|
||||
ENV_CFG_TEST2,
|
||||
ENV_CFG_MAX
|
||||
}ENV_CFG;
|
||||
|
||||
//boot和rtos公用的头结构
|
||||
typedef struct
|
||||
{
|
||||
uint32_t crc; //the crc value calculated from age to the end of value, last 2 zero is counted
|
||||
uint32_t age; //the times of upgrading the firmware
|
||||
uint32_t version;
|
||||
} Env_Header;
|
||||
|
||||
//grep -rl newString . | xargs sed -i 's/newString/newString/g'
|
||||
/**
|
||||
* hal_env init, must be called before use any functions of env
|
||||
* @return !=0 err
|
||||
*/
|
||||
int32_t hal_env_init();
|
||||
|
||||
/**
|
||||
* hal env deinit
|
||||
* @return 0 ok
|
||||
*/
|
||||
int32_t hal_env_deinit();
|
||||
|
||||
//*****************************************************************************
|
||||
//! if want to change the env info, please follows the steps:
|
||||
//! 1. env_mutex_lock
|
||||
//! 2. change the values of env by call env_set_string/env_set_int
|
||||
//! 3. call env_save to save to spi flash
|
||||
//! 4. env_mutex_unlock
|
||||
//*****************************************************************************
|
||||
|
||||
|
||||
int32_t hal_env_mutex_lock();
|
||||
int32_t hal_env_mutex_unlock();
|
||||
int32_t hal_env_save();
|
||||
|
||||
/**
|
||||
* get the integer of e
|
||||
* @param [in] e ENV_CFG to get
|
||||
* @param [in] def_val return def_val if e has not been set
|
||||
* @return 0 ok
|
||||
*/
|
||||
|
||||
//下面的get/set函数都需要调用hal_env_mutex_lock/hal_env_mutex_unlock 保护一下。
|
||||
int32_t hal_env_get_int(ENV_CFG e, int32_t def_val);
|
||||
|
||||
/**
|
||||
* return true if the value is changed, false is the value is same as the old one
|
||||
*/
|
||||
int32_t hal_env_set_int(ENV_CFG e, int32_t value);
|
||||
|
||||
//留意返回的这个字符串自己要备份起来。否则返回的这个指针可能会被内部hv_free掉。
|
||||
// never return "" except def_val is "",
|
||||
const char * hal_env_get_string(ENV_CFG e, const char * def_val);
|
||||
|
||||
//return true if the value is changed, false is the value is same as the old one
|
||||
int32_t hal_env_set_string(ENV_CFG e, const char * value);
|
||||
|
||||
int32_t hal_env_is_same_value(ENV_CFG e, const char * value);
|
||||
|
||||
void hal_env_clear();
|
||||
|
||||
|
||||
#endif /* __HAL_ENV_H__ */
|
||||
Reference in New Issue
Block a user