work_tmp/property.c

2973 lines
71 KiB
C
Raw Permalink Normal View History

2024-02-07 06:42:32 +00:00
#include "property.h"
#include <string.h>
#include <math.h>
#include <errno.h>
#include <limits.h>
#include "errcode_inc.h"
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
// #include "ff.h"
#if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0))
#include "sha2.h"
#endif
#endif
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
#include "mod_bus.h"
#endif
#if (((!defined PROPERTY_PROV_FS_EN) || (PROPERTY_PROV_FS_EN == 0)) && ((!defined PROPERTY_PROV_REMOTE_EN) || (PROPERTY_PROV_REMOTE_EN == 0)))
#error "define PROPERTY_PROV_FS_EN or PROPERTY_PROV_REMOTE_EN in config.h"
#endif
/**
* pthread库,线
*/
#ifdef __linux__
#include <pthread.h>
#include <stdlib.h>
static pthread_mutex_t prop_mutex;
void prop_lock()
{
pthread_mutex_lock(&prop_mutex);
}
void prop_unlock()
{
pthread_mutex_unlock(&prop_mutex);
}
void prop_lock_init()
{
pthread_mutex_init(&prop_mutex, NULL);
}
void prop_wait(INT32U time)
{
}
#else
#include <stdlib.h>
#include <stdio.h>
void prop_lock()
{
;
}
void prop_unlock()
{
;
}
void prop_lock_init()
{
;
}
void prop_wait(INT32U time)
{
;
}
#endif
#define config_path "./conf"
#define COPY_BUF_SIZE 1024
#define FLOAT_STRING_LEN 32
#define UPDATE_LOG "0:/conf/update.%d.log"
typedef struct
{
const char *key;
const char *value;
INT8U success : 1;
} property_string_item;
typedef INT32U (*property_get)(const char *store, const char *id, const char *key, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj);
typedef INT32U (*property_set)(const char *store, const char *id, property_string_item *list, INT32U count, void *obj);
typedef INT32U (*property_clear_cache)(const char *store, const char *id, void *obj);
typedef struct _sbt_node
{
struct _sbt_node *ch[2];
INT8U valid : 1;
INT8U tryLocal : 1;
INT8U isLocal : 1;
char *key;
char *value;
INT32U size;
} sbt_node;
static sbt_node sbt_nil = {{&sbt_nil, &sbt_nil}, 0, 0, 0, NULL, NULL, 0};
typedef struct _prop_cache
{
char *store;
char *id;
sbt_node *sbt;
struct _prop_cache *next;
} prop_cache;
typedef struct
{
struct
{
INT32U init : 1;
INT32U initPending : 1;
INT32U cache : 1;
INT32U lock : 1;
} flag;
char *id;
#if (defined RTOS_UCOS)
OS_EVENT *sem;
#endif
property_get get;
property_set set;
property_clear_cache clear;
prop_cache *cache;
void *obj;
} property_provider;
static property_provider pp[PROPERTY_PROVIDER_MAX];
static INT8U file_test_random = 0;
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
static INT32U FilePropertyInit(INT32U providerId, const PropertyInitParam *param);
#endif
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
static INT32U RemotePropertyInit(INT32U providerId, const PropertyInitParam *param);
#endif
// linux下malloc是线程安全的
static void *malloc_mt(size_t size)
{
return malloc(size);
}
// linux下malloc是线程安全的
static void free_mt(void *ptr)
{
free(ptr);
}
/**
* SBTSpine Binary Tree
SBT的特点是将所有模式字符串的字符按照字典序排列SpineSBT中
*/
static void SBT_Rotate(sbt_node **x, BOOL flag)
{
// 旋转flag == 0为左旋否则为右旋
sbt_node *y = (*x)->ch[!flag];
(*x)->ch[!flag] = y->ch[flag];
y->ch[flag] = *x;
y->size = (*x)->size;
(*x)->size = (*x)->ch[0]->size + (*x)->ch[1]->size + 1;
*x = y;
}
static void SBT_Maintain(sbt_node **t, BOOL flag)
{
// 维护操作的核心:保持
if ((*t)->ch[flag]->ch[flag]->size > (*t)->ch[!flag]->size)
{ // 情况1
SBT_Rotate(t, !flag);
}
else if ((*t)->ch[flag]->ch[!flag]->size > (*t)->ch[!flag]->size)
{ // 情况2
SBT_Rotate(&(*t)->ch[flag], flag);
SBT_Rotate(t, !flag);
}
else
{ // 无需修复
return;
}
SBT_Maintain(&(*t)->ch[0], 0); // 修复左子树
SBT_Maintain(&(*t)->ch[1], 1); // 修复右子树
SBT_Maintain(t, 0); // 修复整棵树
SBT_Maintain(t, 1);
}
static INT32U SBT_Depth(sbt_node *t)
{
INT32U d[2];
if (t == &sbt_nil)
return 0;
d[0] = SBT_Depth(t->ch[0]);
d[1] = SBT_Depth(t->ch[1]);
if (d[0] > d[1])
return (d[0] + 1);
return (d[1] + 1);
}
// static INT32U SBT_Check(sbt_node* t) {
// if (((INT32U)t < 0xa0000000) || ((INT32U)t >= 0xa0800000))
// return RET_OS_HEAP_CORRUPTED;
// if (t == &sbt_nil)
// return RET_EXT_NO_ERROR;
// if (!SBT_Check(t->ch[0]))
// return RET_OS_HEAP_CORRUPTED;
// if (!SBT_Check(t->ch[1]))
// return RET_OS_HEAP_CORRUPTED;
// return RET_EXT_NO_ERROR;
// }
static int SBT_NodeCmp(sbt_node *x, BOOL yl, const char *ykey)
{
if ((x->tryLocal != 0) && (yl == 0))
return 1;
if ((x->tryLocal == 0) && (yl != 0))
return -1;
if (x->key == ykey) // 两者均为NULL返回0
return 0;
if (ykey == NULL) // 至少有一个不为NULL, y->key == NULL 则 x->key != NULL
return 1;
if (x->key == NULL)
return -1;
return strcmp(x->key, ykey);
}
static sbt_node *SBT_Search(sbt_node *t, BOOL local, const char *key)
{
// 在T中中寻找关键字为key的结点
// 若能找到则返回指向它的指针否则返回NULL
int cmp;
if (t == &sbt_nil)
return NULL;
cmp = SBT_NodeCmp(t, local, key);
if (cmp == 0)
return t;
return SBT_Search(t->ch[cmp < 0], local, key);
}
static void SBT_Insert(sbt_node **t, sbt_node *x)
{
// 将节点x插入树中
if ((*t) == &sbt_nil)
{
(*t) = x;
}
else
{
int cmp = SBT_NodeCmp(x, (*t)->tryLocal, (*t)->key);
if (cmp == 0)
{
sbt_node *old = *t;
x->ch[0] = old->ch[0];
x->ch[1] = old->ch[1];
*t = x;
free_mt(old->key);
if (old->value != NULL)
free_mt(old->value);
free_mt(old);
}
else
{
(*t)->size++;
SBT_Insert(&(*t)->ch[cmp > 0], x);
SBT_Maintain(t, (cmp > 0));
}
}
}
static void SBT_Delete(sbt_node *t)
{
if (t == &sbt_nil)
return;
SBT_Delete(t->ch[0]);
SBT_Delete(t->ch[1]);
free_mt(t->key);
if (t->value != NULL)
free_mt(t->value);
}
/**
* ram缓存
*/
static sbt_node *CacheGet(property_provider *p, const char *store, const char *id, BOOL local, const char *key)
{
prop_cache *ptr;
sbt_node *node;
if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return NULL;
for (ptr = p->cache; ptr != NULL; ptr = ptr->next)
if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0))))
break;
if (ptr == NULL)
return NULL;
node = SBT_Search(ptr->sbt, local, key);
if (node == NULL)
return NULL;
if (!node->valid)
return NULL;
return node;
}
static INT32U CacheSet(property_provider *p, const char *store, const char *id, BOOL tryLocal, const char *key, const char *value, BOOL isLocal)
{
prop_cache *ptr;
sbt_node *node;
INT32U keyLen, valLen;
if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return RET_OS_INVALID_PARAM;
node = (sbt_node *)malloc_mt(sizeof(sbt_node));
if (node == NULL)
return RET_PROPERTY_HEAP_FULL;
keyLen = strlen(key);
valLen = strlen(value);
node->ch[0] = &sbt_nil;
node->ch[1] = &sbt_nil;
node->valid = TRUE;
node->tryLocal = tryLocal;
node->isLocal = isLocal;
node->size = 1;
node->key = (char *)malloc_mt(keyLen + 1);
if (node->key == NULL)
{
free_mt(node);
return RET_PROPERTY_HEAP_FULL;
}
else
{
strncpy(node->key, key, keyLen);
node->key[keyLen] = 0;
}
if (value == NULL)
{
node->value = NULL;
}
else
{
node->value = (char *)malloc_mt(valLen + 1);
if (value == NULL)
{
free_mt(node->key);
free_mt(node);
return RET_PROPERTY_HEAP_FULL;
}
else
{
strncpy(node->value, value, valLen);
node->value[valLen] = 0;
}
}
for (ptr = p->cache; ptr != NULL; ptr = ptr->next)
if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0))))
break;
if (ptr == NULL)
{
ptr = (prop_cache *)malloc_mt(sizeof(prop_cache));
if (ptr != NULL)
{
BOOL mallocErr = FALSE;
ptr->store = NULL;
ptr->id = NULL;
if ((id != NULL) && (*id != 0))
{
INT32U idLen = strlen(id);
ptr->id = (char *)malloc_mt(idLen + 1);
if (ptr->id == NULL)
{
mallocErr = TRUE;
}
else
{
strncpy(ptr->id, id, idLen);
ptr->id[idLen] = 0;
}
}
if (!mallocErr)
{
INT32U storeLen = strlen(store);
ptr->store = (char *)malloc_mt(storeLen + 1);
if (ptr->store == NULL)
{
mallocErr = TRUE;
}
else
{
strncpy(ptr->store, store, storeLen);
ptr->store[storeLen] = 0;
}
}
if (mallocErr)
{
if (ptr->store != NULL)
free_mt(ptr->store);
if (ptr->id != NULL)
free_mt(ptr->id);
free_mt(ptr);
ptr = NULL;
}
else
{
ptr->sbt = &sbt_nil;
ptr->next = p->cache;
p->cache = ptr;
}
}
}
if (ptr == NULL)
{
free_mt(node->key);
if (node->value != NULL)
free_mt(node->value);
free_mt(node);
return RET_PROPERTY_HEAP_FULL;
}
SBT_Insert(&ptr->sbt, node);
return RET_EXT_NO_ERROR;
}
static INT32U CacheInvalid(property_provider *p, const char *store, const char *id, BOOL tryLocal, const char *key)
{
prop_cache *ptr;
sbt_node *node;
if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return RET_OS_INVALID_PARAM;
for (ptr = p->cache; ptr != NULL; ptr = ptr->next)
if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0))))
break;
if (ptr == NULL)
return RET_EXT_NO_ERROR;
node = SBT_Search(ptr->sbt, tryLocal, key);
if (node != NULL)
node->valid = FALSE;
return RET_EXT_NO_ERROR;
}
// store == NULL时清除全部cache
// store != NULL && id == NULL时清除store相关的全部cache
// store != NULL && id != NULL时清除(store, id)的cache
static INT32U CacheClear(property_provider *p, const char *store, const char *id)
{
if (p == NULL)
return NULL;
if ((store == NULL) || (*store == 0))
{
prop_cache *ptr;
for (ptr = p->cache; ptr != NULL;)
{
prop_cache *tmp = ptr;
ptr = ptr->next;
free_mt(tmp->store);
if (tmp->id != NULL)
free_mt(tmp->id);
SBT_Delete(tmp->sbt);
free_mt(tmp);
}
p->cache = NULL;
}
else if ((id == NULL) || (*id == 0))
{
prop_cache *ptr;
prop_cache *tail = NULL;
for (ptr = p->cache; ptr != NULL;)
{
if (strcmp(store, ptr->store) == 0)
{
prop_cache *tmp = ptr;
if (ptr == p->cache)
p->cache = ptr->next;
else
tail->next = ptr->next;
ptr = ptr->next;
free_mt(tmp->store);
if (tmp->id != NULL)
free_mt(tmp->id);
SBT_Delete(tmp->sbt);
free_mt(tmp);
}
else
{
tail = ptr;
ptr = ptr->next;
}
}
}
else
{
prop_cache *ptr;
prop_cache *tail = NULL;
for (ptr = p->cache; ptr != NULL; tail = ptr, ptr = ptr->next)
if ((strcmp(store, ptr->store) == 0) && ((ptr->id != NULL) && (strcmp(id, ptr->id) == 0)))
break;
if (ptr != NULL)
{
if (ptr == p->cache)
p->cache = ptr->next;
else
tail->next = ptr->next;
free_mt(ptr->store);
if (ptr->id != NULL)
free_mt(ptr->id);
SBT_Delete(ptr->sbt);
free_mt(ptr);
}
}
return RET_EXT_NO_ERROR;
}
static void CheckInit(void)
{
static INT8U init = 0;
prop_lock();
if (init == 0)
{
INT8U i;
for (i = 0; i < PROPERTY_PROVIDER_MAX; i++)
{
pp[i].flag.init = 0;
pp[i].flag.initPending = 0;
pp[i].flag.cache = 0;
pp[i].id = NULL;
pp[i].get = NULL;
pp[i].set = NULL;
pp[i].clear = NULL;
pp[i].cache = NULL;
pp[i].obj = NULL;
}
init = 1;
}
prop_unlock();
}
// key规则检查
static INT32U CheckKey(const char *key)
{
if ((key == NULL) || (*key == '\0'))
return RET_OS_INVALID_PARAM;
if (((key[0] >= 'a') && (key[0] <= 'z')) || ((key[0] >= 'A') && (key[0] <= 'Z')))
{
INT32U i;
for (i = 1; key[i] != '\0'; i++)
{
if (((key[i] >= 'a') && (key[i] <= 'z')) || ((key[i] >= 'A') && (key[i] <= 'Z')) || ((key[i] >= '0') && (key[i] <= '9')) || (key[i] == '-') || (key[i] == '_') || (key[i] == '.') || (key[i] == '[') || (key[i] == ']'))
continue;
return RET_PROPERTY_INVALID_KEY;
}
}
else
{
return RET_PROPERTY_INVALID_KEY;
}
// printf("key name is ok\n");
return RET_EXT_NO_ERROR;
}
// TODO:
INT32U PropertyInit(INT32U providerId, const PropertyInitParam *param)
{
INT32U ret = RET_EXT_NO_ERROR;
BOOL doInit = FALSE;
CheckInit();
if ((providerId >= PROPERTY_PROVIDER_MAX) || (param == NULL) || ((param->id != NULL) && (strlen(param->id) > PROPERTY_ID_MAX)))
return RET_OS_INVALID_PARAM;
#if 0 // 这段代码没必要存在 CheckInit()——>pp[providerId].flag.initPending=0
for (;;)
{
BOOL quit = FALSE;
prop_lock();
if (pp[providerId].flag.initPending == 0)
{
if (pp[providerId].flag.init == 0)
{
doInit = TRUE;
pp[providerId].flag.initPending = 1;
}
quit = TRUE;
}
prop_unlock();
if (quit)
break;
prop_wait(1000);
}
#else // 直接启动初始化
doInit = TRUE;
#endif
if (doInit)
{
char *id = NULL;
if ((ret == RET_EXT_NO_ERROR) && (param->id != NULL) && (*param->id != 0))
{
INT32U idLen = strlen(param->id);
id = (char *)malloc_mt(idLen + 1);
if (id == NULL)
{
ret = RET_PROPERTY_HEAP_FULL;
}
else
{
strncpy(id, param->id, idLen);
id[idLen] = 0;
}
}
if (ret == RET_EXT_NO_ERROR)
{
pp[providerId].id = id;
if (param->type == PropertyTypeFS)
{
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
// 锁初始化
prop_lock_init();
ret = FilePropertyInit(providerId, param);
#else
ret = RET_OS_NOT_IMPLEMENT;
#endif
}
else if (param->type == PropertyTypeRemote)
{
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
#if (defined RTOS_UCOS)
pp[providerId].sem = OSSemCreate(1);
if (pp[providerId].sem == NULL)
{
ret = RET_OS_NO_AVAILABLE_EVENT_CTRL_BLK;
}
else
{
#endif
ret = RemotePropertyInit(providerId, param);
#if (defined RTOS_UCOS)
if (ret != RET_EXT_NO_ERROR)
{
INT8U osErr = OS_ERR_NONE;
OSSemDel(pp[providerId].sem, OS_DEL_ALWAYS, &osErr);
pp[providerId].sem = NULL;
}
}
#endif
#else
ret = RET_OS_NOT_IMPLEMENT;
#endif
}
else
{
ret = RET_OS_INVALID_PARAM;
}
}
if (ret != RET_EXT_NO_ERROR)
{
if (id != NULL)
free_mt(id);
pp[providerId].id = NULL;
}
pp[providerId].flag.initPending = 0;
}
// PROP_ENABLE_IRQ();
return ret;
}
INT32U GetProperty(INT32U providerId, const char *store, const char *id, const char *key, BOOL tryLocal, char *value, INT32U sizeOfValue, BOOL *isLocal)
{
INT32U ret = RET_EXT_NO_ERROR;
sbt_node *node = NULL;
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (value == NULL) || (sizeOfValue == 0))
return RET_OS_INVALID_PARAM;
// 检查key命名规范
ret = CheckKey(key);
if (ret != RET_EXT_NO_ERROR)
return ret;
// 检查是否init
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
if (pp[providerId].get == NULL)
return RET_PROPERTY_NOT_INIT;
if ((id == NULL) || (*id == 0))
id = pp[providerId].id;
if (tryLocal && ((id == NULL) || (*id == 0)))
return RET_PROPERTY_INVALID_STORE_ID;
// 加锁
prop_lock();
if (pp[providerId].flag.cache)
node = CacheGet(&pp[providerId], store, id, tryLocal, key);
if (node == NULL)
{
BOOL lt = TRUE;
ret = pp[providerId].get(store, key, (tryLocal ? id : NULL), value, sizeOfValue, &lt, pp[providerId].obj);
if (pp[providerId].flag.cache)
{
if (ret == RET_EXT_NO_ERROR)
CacheSet(&pp[providerId], store, id, tryLocal, key, value, lt);
else if (ret == RET_PROPERTY_NOT_FOUND)
CacheSet(&pp[providerId], store, id, tryLocal, key, NULL, lt);
}
if (isLocal != NULL)
*isLocal = lt;
}
else if (node->value == NULL)
{
ret = RET_PROPERTY_NOT_FOUND;
}
else
{
INT32U valLen = strlen(node->value);
if (valLen > sizeOfValue - 1)
{
valLen = sizeOfValue - 1;
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
}
strncpy(value, node->value, valLen);
value[valLen] = 0;
if (isLocal != NULL)
*isLocal = node->isLocal;
}
prop_unlock();
return ret;
}
INT32U SetProperty(INT32U providerId, const char *store, const char *id, const char *key, const char *value)
{
PropertyItem item;
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return RET_OS_INVALID_PARAM;
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
item.key = key;
if (value == NULL)
{
item.type = VT_NULL;
item.value.str = NULL;
}
else
{
item.type = VT_STR;
item.value.str = value;
}
item.success = 0;
return SetPropertyList(providerId, store, id, &item, 1);
}
INT32U SetPropertyList(INT32U providerId, const char *store, const char *id, PropertyItem *list, INT32U count)
{
INT32U ret = RET_EXT_NO_ERROR;
property_string_item *bufList;
char *stringList;
BOOL fpChked = FALSE;
INT32U idx;
if (providerId >= PROPERTY_PROVIDER_MAX)
return RET_OS_INVALID_PARAM;
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
if (pp[providerId].set == NULL)
return RET_PROPERTY_NOT_INIT;
if ((id == NULL) || (*id == 0))
id = pp[providerId].id;
if ((id == NULL) || (*id == 0))
return RET_PROPERTY_INVALID_STORE_ID;
if (count == 0)
return RET_EXT_NO_ERROR;
bufList = (property_string_item *)malloc_mt(sizeof(property_string_item) * count);
stringList = ((bufList == NULL) ? NULL : (char *)malloc_mt((FLOAT_STRING_LEN + 1) * count));
if ((bufList == NULL) || (stringList == NULL))
{
if (bufList != NULL)
free_mt(bufList);
if (stringList != NULL)
free_mt(stringList);
return RET_PROPERTY_HEAP_FULL;
}
memset(stringList, 0, ((FLOAT_STRING_LEN + 1) * count));
for (idx = 0; idx < count; idx++)
{
ret = CheckKey(list[idx].key);
if (ret != RET_EXT_NO_ERROR)
break;
bufList[idx].key = list[idx].key;
switch (list[idx].type)
{
case VT_NULL:
bufList[idx].value = NULL;
break;
case VT_I4:
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i4);
break;
case VT_I2:
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i2);
break;
case VT_I1:
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i1);
break;
case VT_UI4:
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui4);
break;
case VT_UI2:
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui2);
break;
case VT_UI1:
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui1);
break;
case VT_R4:
if (!fpChked)
{
char str[10];
snprintf(str, sizeof(str), "%e", PI);
if (strncmp(str, "3.14159", strlen("3.14159")) == 0)
fpChked = TRUE;
else
ret = RET_OS_FLOAT_TEST_FAILED;
}
if (ret == RET_EXT_NO_ERROR)
{
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%e", ((isfinite(list[idx].value.r4) || isinf(list[idx].value.r4)) ? list[idx].value.r4 : NAN));
}
break;
case VT_STR:
bufList[idx].value = list[idx].value.str;
break;
case VT_BIT4:
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", ((GetUnsigned(providerId, store, list[idx].key, TRUE, 0, NULL, NULL) & (~list[idx].value.bit4.mask)) | (list[idx].value.bit4.val & list[idx].value.bit4.mask)));
break;
}
if (ret != RET_EXT_NO_ERROR)
break;
bufList[idx].success = 0;
}
prop_lock();
if (ret == RET_EXT_NO_ERROR)
{
if (ret == RET_EXT_NO_ERROR)
ret = pp[providerId].set(store, id, bufList, count, pp[providerId].obj);
if (ret == RET_EXT_NO_ERROR)
{
for (idx = 0; idx < count; idx++)
{
if ((bufList[idx].value == NULL) || (CacheSet(&pp[providerId], store, id, TRUE, bufList[idx].key, bufList[idx].value, TRUE) != RET_EXT_NO_ERROR))
CacheInvalid(&pp[providerId], store, id, TRUE, bufList[idx].key);
}
}
}
prop_unlock();
free_mt(bufList);
free_mt(stringList);
return ret;
}
INT32S GetInteger(INT32U providerId, const char *store, const char *key, BOOL tryLocal, INT32S defaultValue, INT32U *retCode, BOOL *isLocal)
{
char result[PROPERTY_LINE_MAX + 1];
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
INT32S val = 0;
if (ret == RET_EXT_NO_ERROR)
{
char *endptr = NULL;
val = strtol(result, &endptr, 0);
if (endptr == result)
{
ret = RET_PROPERTY_EFORMAT;
}
else
{
for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++)
;
if (*endptr != 0)
ret = RET_PROPERTY_EFORMAT;
else if ((errno == ERANGE) && ((val == LONG_MIN) || (val == LONG_MAX)))
ret = RET_PROPERTY_ERANGE;
}
}
if (ret != RET_EXT_NO_ERROR)
val = defaultValue;
if (retCode != NULL)
*retCode = ret;
return val;
}
INT32U GetUnsigned(INT32U providerId, const char *store, const char *key, BOOL tryLocal, INT32U defaultValue, INT32U *retCode, BOOL *isLocal)
{
char result[PROPERTY_LINE_MAX + 1];
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
INT32U val = 0;
if (ret == RET_EXT_NO_ERROR)
{
char *endptr = NULL;
val = strtoul(result, &endptr, 0);
if (endptr == result)
{
ret = RET_PROPERTY_EFORMAT;
}
else
{
for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++)
;
if (*endptr != 0)
ret = RET_PROPERTY_EFORMAT;
else if ((errno == ERANGE) && (val == ULONG_MAX))
ret = RET_PROPERTY_ERANGE;
}
}
if (ret != RET_EXT_NO_ERROR)
val = defaultValue;
if (retCode != NULL)
*retCode = ret;
return val;
}
FP32 GetFloat(INT32U providerId, const char *store, const char *key, BOOL tryLocal, FP32 defaultValue, INT32U *retCode, BOOL *isLocal)
{
char result[PROPERTY_LINE_MAX + 1];
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
FP32 val = FP_ZERO;
if (ret == RET_EXT_NO_ERROR)
{
char *endptr = NULL;
val = strtof(result, &endptr);
if (!isfinite(val) && !isinf(val))
{
ret = RET_PROPERTY_EFORMAT;
}
else if (endptr == result)
{
ret = RET_PROPERTY_EFORMAT;
}
else
{
for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++)
;
if (*endptr != 0)
ret = RET_PROPERTY_EFORMAT;
else if ((errno == ERANGE) && isinf(val))
ret = RET_PROPERTY_ERANGE;
}
}
if (ret != RET_EXT_NO_ERROR)
val = defaultValue;
if (retCode != NULL)
*retCode = ret;
return val;
}
BOOL GetBoolean(INT32U providerId, const char *store, const char *key, BOOL tryLocal, BOOL defaultValue, INT32U *retCode, BOOL *isLocal)
{
INT32U i;
char result[PROPERTY_LINE_MAX + 1];
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
BOOL val = defaultValue;
if (ret == RET_EXT_NO_ERROR)
{
for (i = 0; ((i < sizeof(result)) && (result[i] != '\0')); i++)
if ((result[i] >= 'A') && (result[i] <= 'Z'))
result[i] += ('a' - 'A');
if ((strcmp("true", result) == 0) || (strcmp("yes", result) == 0) || (strcmp("1", result) == 0))
{
val = TRUE;
}
else if ((strcmp("false", result) == 0) || (strcmp("no", result) == 0) || (strcmp("0", result) == 0))
{
val = FALSE;
}
else
{
ret = RET_PROPERTY_EFORMAT;
}
}
if (ret != RET_EXT_NO_ERROR)
val = defaultValue;
if (retCode != NULL)
*retCode = ret;
return val;
}
INT32U SetInteger(INT32U providerId, const char *store, const char *key, INT32S value)
{
PropertyItem item;
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return RET_OS_INVALID_PARAM;
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
item.key = key;
item.type = VT_I4;
item.value.i4 = value;
item.success = 0;
return SetPropertyList(providerId, store, NULL, &item, 1);
}
INT32U SetUnsigned(INT32U providerId, const char *store, const char *key, INT32U value)
{
PropertyItem item;
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return RET_OS_INVALID_PARAM;
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
item.key = key;
item.type = VT_UI4;
item.value.ui4 = value;
item.success = 0;
return SetPropertyList(providerId, store, NULL, &item, 1);
}
INT32U SetFloat(INT32U providerId, const char *store, const char *key, FP32 value)
{
PropertyItem item;
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return RET_OS_INVALID_PARAM;
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
item.key = key;
item.type = VT_R4;
item.value.r4 = value;
item.success = 0;
return SetPropertyList(providerId, store, NULL, &item, 1);
}
INT32U SetBits(INT32U providerId, const char *store, const char *key, INT32U value, INT32U mask)
{
PropertyItem item;
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
return RET_OS_INVALID_PARAM;
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
if (mask == 0)
return RET_EXT_NO_ERROR;
item.key = key;
item.type = VT_BIT4;
item.value.bit4.val = value;
item.value.bit4.mask = mask;
item.success = 0;
return SetPropertyList(providerId, store, NULL, &item, 1);
}
INT32U ClearPropertyCache(INT32U providerId, const char *store, const char *id)
{
INT32U ret = RET_EXT_NO_ERROR;
if (providerId >= PROPERTY_PROVIDER_MAX)
return RET_OS_INVALID_PARAM;
CheckInit();
if (pp[providerId].flag.init == 0)
return RET_PROPERTY_NOT_INIT;
if (pp[providerId].clear == NULL)
return RET_EXT_NO_ERROR;
if ((id == NULL) || (*id == 0))
id = pp[providerId].id;
if ((id == NULL) || (*id == 0))
id = NULL;
prop_lock();
CacheClear(&pp[providerId], store, id);
ret = pp[providerId].clear(store, id, pp[providerId].obj);
prop_unlock();
return ret;
}
INT32U SetPropertyTestCase(INT32U caseId)
{
if (caseId == 1)
file_test_random = 1; // 随机数设为非0表示启用测试, 也可以设成其他非0值, 该值在测试过程中会被随机更新
else
file_test_random = 0; // 随机数设为0表示禁用测试, 不会再被更新
return RET_EXT_NO_ERROR;
}
// INT32U VerifyPropertyCache(INT32U providerId) {
// INT32U ret = RET_EXT_NO_ERROR;
// prop_cache* ptr;
// #if (defined RTOS_UCOS)
// INT8U osErr = OS_ERR_NONE;
// #endif
//
// if (providerId >= PROPERTY_PROVIDER_MAX)
// return RET_OS_INVALID_PARAM;
// CheckInit();
// if (pp[providerId].flag.init == 0)
// return RET_PROPERTY_NOT_INIT;
//
// #if (defined RTOS_UCOS)
// OSSemPend(pp[providerId].sem, OSmsToTick(1000UL), &osErr);
// if (osErr != OS_ERR_NONE)
// return RET_OS_SYNC_OBJ_FAILED;
// #elif ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1))
// PROP_DISABLE_IRQ();
// if (pp[providerId].flag.lock != 0)
// ret = RET_OS_SYNC_OBJ_FAILED;
// else
// pp[providerId].flag.lock = 1;
// PROP_ENABLE_IRQ();
// if (ret != RET_EXT_NO_ERROR)
// return ret;
// #else
// #error "Target error"
// #endif
//
// for (ptr = pp[providerId].cache; ptr != NULL; ptr = ptr->next) {
// if (((INT32U)ptr < 0xa0000000) || ((INT32U)ptr >= 0xa0800000)) {
// ret = RET_OS_HEAP_CORRUPTED;
// break;
// }
// ret = SBT_Check(ptr->sbt);
// if (ret != RET_EXT_NO_ERROR)
// break;
// }
//
// PROP_UNLOCK(pp[providerId]);
//
// return ret;
//}
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
/**************************************************************
* File property provider
*************************************************************
*/
typedef struct _fileprop_cache
{
char *key;
char *value;
INT32U size;
struct _fileprop_cache *next;
} fileprop_cache;
typedef struct _file_cache
{
BOOL allCache;
char *store;
char *id;
fileprop_cache *cache;
struct _file_cache *next;
} file_cache;
typedef struct
{
#if (!defined RTOS_UCOS) && ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1))
struct
{
INT8U lock : 1;
} flag;
#endif
struct
{
INT8U cache : 1;
INT8U prefetch : 1;
} config;
#if (defined RTOS_UCOS)
OS_EVENT *sem;
#endif
file_cache *cache;
struct
{
INT32U flag;
#if 1
FILE *fil;
FILE *tmp;
#endif
} stream;
} file_provider;
#define STREAM_FLAG_FOPEN (1UL << 0)
static INT32U FileCacheGet(file_cache **head, const char *store, const char *id, const char *key, char *value, INT32U size, BOOL *isNull)
{
file_cache *fc;
fileprop_cache *pc;
for (fc = *head; fc != NULL; fc = fc->next)
{
if ((strcmp(store, fc->store) == 0) && ((((id == NULL) || (*id == 0)) && ((fc->id == NULL) || (*fc->id == 0))) || ((id != NULL) && (fc->id != NULL) && (strcmp(id, fc->id) == 0))))
break;
}
if (fc == NULL)
return RET_PROPERTY_NOT_FOUND;
*isNull = TRUE;
for (pc = fc->cache; pc != NULL; pc = pc->next)
{
if (strcmp(key, pc->key) == 0)
{
INT32U ret = RET_EXT_NO_ERROR;
if (pc->value != NULL)
{
INT32U cpLen = pc->size;
if (cpLen > size - 1)
{
cpLen = size - 1;
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
}
*isNull = FALSE;
strncpy(value, pc->value, cpLen);
value[cpLen] = 0;
}
return ret;
}
}
if (fc->allCache)
return RET_EXT_NO_ERROR;
return RET_PROPERTY_NOT_FOUND;
}
static INT32U FileCacheTouch(file_cache **head, const char *store, const char *id, BOOL allCache, file_cache **found)
{
INT32U ret = RET_EXT_NO_ERROR;
file_cache *fc;
for (fc = *head; fc != NULL; fc = fc->next)
{
if ((strcmp(store, fc->store) == 0) && ((((id == NULL) || (*id == 0)) && ((fc->id == NULL) || (*fc->id == 0))) || ((id != NULL) && (fc->id != NULL) && (strcmp(id, fc->id) == 0))))
break;
}
if (fc == NULL)
{
BOOL fail = FALSE;
fc = (file_cache *)malloc_mt(sizeof(file_cache));
if (fc == NULL)
fail = TRUE;
else
memset(fc, 0, sizeof(file_cache));
if (!fail)
{
INT32U lenStore = strlen(store);
fc->store = (char *)malloc_mt(lenStore + 1);
if (fc->store == NULL)
{
fail = TRUE;
}
else
{
strncpy(fc->store, store, lenStore);
fc->store[lenStore] = 0;
}
}
if (!fail && (id != NULL) && (*id != 0))
{
INT32U lenId = strlen(id);
fc->id = (char *)malloc_mt(lenId + 1);
if (fc->id == NULL)
{
fail = TRUE;
}
else
{
strncpy(fc->id, id, lenId);
fc->id[lenId] = 0;
}
}
if (fail)
{
if (fc != NULL)
{
if (fc->store != NULL)
free_mt(fc->store);
if (fc->id != NULL)
free_mt(fc->id);
free_mt(fc);
fc = NULL;
}
ret = RET_PROPERTY_HEAP_FULL;
}
else
{
fc->allCache = allCache;
fc->next = *head;
*head = fc;
}
}
if (found != NULL)
*found = fc;
return ret;
}
static INT32U FileCacheSet(file_cache **head, const char *store, const char *id, const char *key, const char *value, BOOL allCache)
{
INT32U ret = RET_EXT_NO_ERROR;
file_cache *fc = NULL;
ret = FileCacheTouch(head, store, id, allCache, &fc);
if ((ret == RET_EXT_NO_ERROR) && (fc != NULL))
{
fileprop_cache *pc;
fileprop_cache *ptail = NULL;
for (pc = fc->cache; pc != NULL; ptail = pc, pc = pc->next)
{
if (strcmp(key, pc->key) == 0)
break;
}
if (pc == NULL)
{
BOOL fail = FALSE;
pc = (fileprop_cache *)malloc_mt(sizeof(fileprop_cache));
if (pc == NULL)
fail = TRUE;
else
memset(pc, 0, sizeof(fileprop_cache));
if (!fail)
{
INT32U keyLen = strlen(key);
pc->key = (char *)malloc_mt(keyLen + 1);
if (pc->key == NULL)
{
fail = TRUE;
}
else
{
strncpy(pc->key, key, keyLen);
pc->key[keyLen] = 0;
}
}
if (!fail && (value != NULL))
{
pc->size = strlen(value);
pc->value = (char *)malloc_mt(pc->size + 1);
if (pc->value == NULL)
{
fail = TRUE;
}
else
{
strncpy(pc->value, value, pc->size);
pc->value[pc->size] = 0;
}
}
if (fail)
{
if (pc != NULL)
{
if (pc->key != NULL)
free_mt(pc->key);
if (pc->value != NULL)
free_mt(pc->value);
free_mt(pc);
pc = NULL;
}
fc->allCache = FALSE;
ret = RET_PROPERTY_HEAP_FULL;
}
else
{
pc->next = fc->cache;
fc->cache = pc;
}
}
else
{
BOOL alloc = FALSE;
if (value == NULL)
{
free_mt(pc->key);
if (pc->value != NULL)
free_mt(pc->value);
if (pc == fc->cache)
fc->cache = pc->next;
else
ptail->next = pc->next;
free_mt(pc);
}
else if (pc->value == NULL)
{
alloc = TRUE;
}
else if (pc->size >= strlen(value))
{
strncpy(pc->value, value, strlen(value));
}
else
{
if (pc->value != NULL)
free_mt(pc->value);
pc->value = NULL;
pc->size = 0;
alloc = TRUE;
}
if (alloc)
{
pc->size = strlen(value);
pc->value = (char *)malloc_mt(pc->size + 1);
if (pc->value == NULL)
{
free_mt(pc->key);
if (pc == fc->cache)
fc->cache = pc->next;
else
ptail->next = pc->next;
free_mt(pc);
fc->allCache = FALSE;
ret = RET_PROPERTY_HEAP_FULL;
}
else
{
strncpy(pc->value, value, pc->size);
pc->value[pc->size] = 0;
}
}
}
}
return ret;
}
static INT32U FileCacheClearLinkList(fileprop_cache *ptr)
{
for (; ptr != NULL;)
{
fileprop_cache *tmp = ptr;
ptr = ptr->next;
free_mt(tmp->key);
if (tmp->value != NULL)
free_mt(tmp->value);
free_mt(tmp);
}
return RET_EXT_NO_ERROR;
}
static INT32U FileCacheClear(file_cache **head, const char *store, const char *id)
{
file_cache *fc;
if ((store == NULL) || (*store == 0))
{
for (fc = *head; fc != NULL;)
{
file_cache *tmp = fc;
fc = fc->next;
FileCacheClearLinkList(tmp->cache);
free_mt(tmp->store);
if (tmp->id != NULL)
free_mt(tmp->id);
free_mt(tmp);
}
*head = NULL;
}
else if ((id == NULL) || (*id == 0))
{
file_cache *ftail = NULL;
for (fc = *head; fc != NULL;)
{
if (strcmp(store, fc->store) == 0)
{
file_cache *del = fc;
FileCacheClearLinkList(fc->cache);
free_mt(fc->store);
if (fc->id != NULL)
free_mt(fc->id);
if (fc == *head)
*head = fc->next;
else
ftail->next = fc->next;
fc = fc->next;
free_mt(del);
}
else
{
ftail = fc;
fc = fc->next;
}
}
}
else
{
file_cache *ftail = NULL;
for (fc = *head; fc != NULL; ftail = fc, fc = fc->next)
{
if ((strcmp(store, fc->store) == 0) && ((fc->id != NULL) && (strcmp(id, fc->id) == 0)))
break;
}
if (fc != NULL)
{
FileCacheClearLinkList(fc->cache);
free_mt(fc->store);
if (fc->id != NULL)
free_mt(fc->id);
if (fc == *head)
*head = fc->next;
else
ftail->next = fc->next;
free_mt(fc);
}
}
return RET_EXT_NO_ERROR;
}
static INT32U INT32U2err(INT32U fres)
{
#if 0
switch (fres)
{
case FR_OK:
return RET_EXT_NO_ERROR;
case FR_DISK_ERR:
return RET_FILE_FR_DISK_ERR;
case FR_INT_ERR:
return RET_FILE_FR_INT_ERR;
case FR_NOT_READY:
return RET_FILE_FR_NOT_READY;
case FR_NO_FILE:
return RET_FILE_FR_NO_FILE;
case FR_NO_PATH:
return RET_FILE_FR_NO_PATH;
case FR_INVALID_NAME:
return RET_FILE_FR_INVALID_NAME;
case FR_DENIED:
return RET_FILE_FR_DENIED;
case FR_EXIST:
return RET_FILE_FR_EXIST;
case FR_INVALID_OBJECT:
return RET_FILE_FR_INVALID_OBJECT;
case FR_WRITE_PROTECTED:
return RET_FILE_FR_WRITE_PROTECTED;
case FR_INVALID_DRIVE:
return RET_FILE_FR_INVALID_DRIVE;
case FR_NOT_ENABLED:
return RET_FILE_FR_NOT_ENABLED;
case FR_NO_FILESYSTEM:
return RET_FILE_FR_NO_FILESYSTEM;
case FR_MKFS_ABORTED:
return RET_FILE_FR_MKFS_ABORTED;
case FR_TIMEOUT:
return RET_FILE_FR_TIMEOUT;
// case FR_LOCKED:
// return RET_FILE_FR_LOCKED;
// case FR_NOT_ENOUGH_CORE:
// return RET_FILE_FR_NOT_ENOUGH_CORE;
// case FR_TOO_MANY_OPEN_FILES:
// return RET_FILE_FR_TOO_MANY_OPEN_FILES;
// case FR_INVALID_PARAMETER:
// return RET_FILE_FR_INVALID_PARAMETER;
}
return RET_FILE_UNKNOWN;
#else
return 0;
#endif
}
static void FILE_TEST_RANDOM(INT8U max)
{
if ((file_test_random > 0) && (max > 0))
{
file_test_random = (rand() % max) + 1;
printf("[TEST] file_test_random = %d", file_test_random);
}
}
static void FILE_TEST_RESET(INT8U num)
{
#if 0
if (file_test_random == num)
{
printf("[TEST] swReset() called. file_test_random = %d", file_test_random);
swReset();
}
#endif
}
static INT32U f_copy(const char *src, const char *dest)
{
#if 0
FIL filSrc, filDest;
INT32U fres;
BYTE *buf;
INT32U ret = RET_EXT_NO_ERROR;
fres = f_open(&filSrc, src, FA_OPEN_EXISTING | FA_READ);
if (fres != FR_OK)
return INT32U2err(fres);
fres = f_open(&filDest, dest, FA_CREATE_ALWAYS | FA_WRITE);
if (fres != FR_OK)
{
f_close(&filSrc);
return INT32U2err(fres);
}
buf = malloc_mt(COPY_BUF_SIZE);
if (buf == NULL)
{
f_close(&filSrc);
f_close(&filDest);
return RET_OS_HEAP_FULL;
}
for (;;)
{
INT32U rsize, wsize;
fres = f_read(&filSrc, buf, COPY_BUF_SIZE, &rsize);
if (fres != FR_OK)
{
ret = INT32U2err(fres);
break;
}
if (rsize == 0)
break;
fres = f_write(&filDest, buf, rsize, &wsize);
if (rsize != wsize)
{
ret = RET_FILE_DISK_FULL;
break;
}
if (fres != FR_OK)
{
ret = INT32U2err(fres);
break;
}
}
free_mt(buf);
f_close(&filSrc);
f_close(&filDest);
return ret;
#else
return 0;
#endif
}
static INT32U PropWriteLogClear(INT32U providerId)
{
#if 0
INT32U fres;
char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
snprintf(logname, sizeof(logname), UPDATE_LOG, providerId);
fres = f_unlink(logname);
if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH))
return RET_PROPERTY_FILE_WRITE_ERR;
return RET_EXT_NO_ERROR;
#else
return 0;
#endif
}
static INT32U PropWriteLogWrite(INT32U providerId, const char *path)
{
#if 0
FIL fil;
INT32U fres;
char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
INT32U wsize;
if (path == NULL)
return RET_OS_INVALID_PARAM;
snprintf(logname, sizeof(logname), UPDATE_LOG, providerId);
fres = f_open(&fil, logname, FA_CREATE_ALWAYS | FA_WRITE);
if (fres != FR_OK)
return INT32U2err(fres);
fres = f_write(&fil, path, strlen(path), &wsize);
f_close(&fil);
if ((fres == FR_OK) && (wsize != strlen(path)))
return RET_FILE_DISK_FULL;
return INT32U2err(fres);
#else
return 0;
#endif
}
static INT32U PropWriteLogLoad(INT32U providerId, char *path, INT32U size)
{
#if 0
FIL fil;
INT32U fres;
INT32U rsize = 0;
INT32U i;
char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
if (path == NULL || size == 0)
return RET_OS_INVALID_PARAM;
path[0] = '\0';
snprintf(logname, sizeof(logname), UPDATE_LOG, providerId);
fres = f_open(&fil, logname, FA_OPEN_EXISTING | FA_READ);
if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH))
return RET_EXT_NO_ERROR;
if (fres != FR_OK)
return INT32U2err(fres);
fres = f_read(&fil, path, size, &rsize);
f_close(&fil);
if (rsize == size)
path[size - 1] = '\0';
for (i = 0; path[i] != '\0'; i++)
if (path[i] == '\r' || path[i] == '\n')
{
path[i] = '\0';
break;
}
if (fres == FR_OK)
{
char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
snprintf(filetmp, sizeof(filetmp), "%s.tmp", path);
fres = f_open(&fil, filetmp, FA_OPEN_EXISTING | FA_READ);
f_close(&fil);
if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH))
{
fres = FR_OK;
path[0] = '\0';
}
}
if (fres != FR_OK)
path[0] = '\0';
return INT32U2err(fres);
#else
return 0;
#endif
}
static INT32U PropWriteLogCommit(INT32U providerId, const char *filename)
{
#if 0
INT32U ret = RET_EXT_NO_ERROR;
INT32U fres;
char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
snprintf(filetmp, sizeof(filetmp), "%s.tmp", filename);
FILE_TEST_RESET(1);
fres = f_unlink(filename);
if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH))
ret = RET_PROPERTY_FILE_WRITE_ERR;
FILE_TEST_RESET(2);
if (ret == RET_EXT_NO_ERROR)
ret = f_copy(filetmp, filename);
FILE_TEST_RESET(3);
if (ret == RET_EXT_NO_ERROR)
ret = PropWriteLogClear(providerId);
FILE_TEST_RESET(4);
if (ret == RET_EXT_NO_ERROR)
{
INT32U fres = f_unlink(filetmp);
if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH))
ret = RET_PROPERTY_FILE_WRITE_ERR;
}
FILE_TEST_RESET(5);
return ret;
#else
return 0;
#endif
}
#if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0))
static void FormatSHA1sum(char *buf, INT32U lenOfBuf, INT8U *sig, INT32U lenOfSig)
{
INT8U i = 0;
for (i = 0; i < lenOfSig; i++)
snprintf(&buf[i << 1], (lenOfBuf - (i << 1)), "%02x", sig[i]);
buf[lenOfBuf - 1] = '\0';
}
#endif
// TODO:启用sha校验
static INT32U FileStreamChecksum(const char *filename)
{
#if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0))
FIL fil;
INT8U buf[128];
INT8U hash[32];
char sigStr[sizeof(hash) * 2 + 1];
char sigName[PROPERTY_STORE_MAX + 20];
sha2_context ctx;
INT32U fres;
INT32U br;
INT32U ret = RET_EXT_NO_ERROR;
if ((filename == NULL) || (*filename == 0))
return RET_EXT_NO_ERROR;
fres = f_open(&fil, filename, FA_OPEN_EXISTING | FA_READ);
if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH))
return RET_EXT_NO_ERROR;
if (fres != FR_OK)
return RET_PROPERTY_INVALID_SIGNATURE; // RET_PROPERTY_FILE_OPEN_ERR
sha2_starts(&ctx, 0);
// TODO: 加入其他信息校验信息
for (;;)
{
if (f_read(&fil, buf, sizeof(buf), &br) != FR_OK)
{
ret = RET_PROPERTY_INVALID_SIGNATURE; // RET_PROPERTY_FILE_READ_ERR
break;
}
if (br == 0)
break;
// TODO: 加入加密算法
sha2_update(&ctx, buf, br);
}
f_close(&fil);
sha2_finish(&ctx, hash);
if (ret != RET_EXT_NO_ERROR)
return ret;
snprintf(sigName, sizeof(sigName), "%s.sig", filename);
fres = f_open(&fil, sigName, FA_OPEN_EXISTING | FA_READ);
if (fres != FR_OK)
return RET_PROPERTY_INVALID_SIGNATURE;
if ((f_read(&fil, sigStr, (sizeof(hash) * 2), &br) != FR_OK) || (br != (sizeof(hash) * 2)))
ret = RET_PROPERTY_INVALID_SIGNATURE;
f_close(&fil);
sigStr[sizeof(hash) * 2] = '\0';
if (ret == RET_EXT_NO_ERROR)
{
char hashStr[sizeof(hash) * 2 + 1];
FormatSHA1sum(hashStr, sizeof(hashStr), hash, sizeof(hash));
if (strcmp(hashStr, sigStr) != 0)
ret = RET_PROPERTY_INVALID_SIGNATURE;
}
return ret;
#else
return RET_EXT_NO_ERROR;
#endif
}
static INT32U FileStreamOpen(const char *filename, file_provider *fp)
{
#if 0
INT32U ret = RET_EXT_NO_ERROR;
INT32U fres;
if ((filename == NULL) || (*filename == 0) || (fp == NULL))
return RET_OS_INVALID_PARAM;
fp->stream.flag = 0;
fres = f_open(&fp->stream.fil, filename, FA_OPEN_EXISTING | FA_READ);
if (fres == FR_OK)
{
fp->stream.flag |= STREAM_FLAG_FOPEN;
}
else if ((fres != FR_NO_FILE) && (fres != FR_NO_PATH))
{
ret = RET_PROPERTY_FILE_OPEN_ERR;
}
return ret;
#else
INT32U ret = RET_EXT_NO_ERROR;
INT32U fres;
if ((filename == NULL) || (*filename == 0) || (fp == NULL))
return RET_OS_INVALID_PARAM;
fp->stream.flag = 0;
fp->stream.fil = fopen(filename, "r");
// printf("file name : %s\n",filename);
if (fp->stream.fil != NULL)
{
// printf("file read ok \n");
// 读取到文件了
fp->stream.flag |= STREAM_FLAG_FOPEN;
}
else
{
ret = RET_PROPERTY_FILE_OPEN_ERR;
}
return ret;
#endif
}
static INT32U FileStreamClose(file_provider *fp)
{
#if 0
if (fp == NULL)
return RET_OS_INVALID_PARAM;
if ((fp->stream.flag & STREAM_FLAG_FOPEN) != 0)
f_close(&fp->stream.fil);
fp->stream.flag = 0;
return RET_EXT_NO_ERROR;
#else
// 指针检查
if (fp == NULL)
return RET_OS_INVALID_PARAM;
// 关闭文件
if ((fp->stream.flag & STREAM_FLAG_FOPEN) != 0)
fclose(fp->stream.fil);
fp->stream.fil = NULL;
fp->stream.flag = 0;
return 0;
#endif
}
static INT32U FileStreamGet(char *ch, file_provider *fp)
{
#if 0
if ((ch == NULL) || (fp == NULL))
return RET_OS_INVALID_PARAM;
if ((fp->stream.flag & STREAM_FLAG_FOPEN) == 0)
{
*ch = 0;
}
else
{
INT32U br;
if (f_read(&fp->stream.fil, ch, 1, &br) != FR_OK)
return RET_PROPERTY_FILE_READ_ERR;
if (br == 0)
*ch = 0;
}
return RET_EXT_NO_ERROR;
#else
// 指针检查
if ((ch == NULL) || (fp == NULL))
return RET_OS_INVALID_PARAM;
// 检查下文件是否打开
if ((fp->stream.flag & STREAM_FLAG_FOPEN) == 0)
{
// ch = 0 的话,后续程序会直接退出
*ch = 0;
}
else
{
*ch = fgetc(fp->stream.fil);
// 检查是是否读取错误
if (ferror(fp->stream.fil) != 0)
{
*ch = 0;
}
}
return 0;
#endif
}
static INT32U FileStreamParseLine(BOOL *eof, BOOL *valid, char *lineBuffer, INT32U bufferSize, INT32U *keyIndex, INT32U *keyLen, INT32U *valIndex, INT32U *valLen, file_provider *fp)
{
#if 0
static const INT8U PARSE_STATE_NEW = 0;
static const INT8U PARSE_STATE_SKIP = 1;
static const INT8U PARSE_STATE_KEY_READING = 2;
static const INT8U PARSE_STATE_KEY_FINISHED = 3;
static const INT8U PARSE_STATE_STRING_TRIM = 4;
static const INT8U PARSE_STATE_STRING_READING = 5;
INT8U state = PARSE_STATE_NEW;
INT32U ptr = 0;
BOOL stop = FALSE;
if ((eof == NULL) || (valid == NULL) || (lineBuffer == NULL) || (bufferSize == 0) || (keyIndex == NULL) || (keyLen == NULL) || (valIndex == NULL) || (valLen == NULL) || (fp == NULL))
return RET_OS_INVALID_PARAM;
*valid = FALSE;
for (; !stop;)
{
char ch = 0;
INT32U ret = FileStreamGet(&ch, fp);
if (ret != RET_EXT_NO_ERROR)
return ret;
if (ch != 0)
{
if (ptr < bufferSize - 1)
{
lineBuffer[ptr++] = ch;
}
else
{
if (((ch == '\r') || (ch == '\n')) && (ptr == bufferSize - 1))
lineBuffer[ptr - 1] = ch;
state = PARSE_STATE_SKIP;
*valid = FALSE;
}
}
switch (state)
{
case PARSE_STATE_NEW:
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
{
*keyIndex = ptr - 1;
state = PARSE_STATE_KEY_READING;
}
else if (ch == ' ' || ch == '\t')
{
// do nothing
}
else if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else
{
state = PARSE_STATE_SKIP;
}
break;
case PARSE_STATE_KEY_READING:
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '.') || (ch == '-') || (ch == '_') || (ch == '[') || (ch == ']'))
{
}
else if (ch == '=')
{
*keyLen = ptr - *keyIndex - 1;
state = PARSE_STATE_STRING_TRIM;
}
else if (ch == ' ' || ch == '\t')
{
*keyLen = ptr - *keyIndex - 1;
state = PARSE_STATE_KEY_FINISHED;
}
else if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else
{
state = PARSE_STATE_SKIP;
}
break;
case PARSE_STATE_KEY_FINISHED:
if (ch == '=')
{
state = PARSE_STATE_STRING_TRIM;
}
else if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else if (ch != ' ' && ch != '\t')
{
state = PARSE_STATE_SKIP;
}
break;
case PARSE_STATE_STRING_TRIM:
if (ch == '\r' || ch == '\n' || ch == 0)
{
*valIndex = ptr - 1;
*valLen = 0;
*valid = TRUE;
*eof = (ch == 0);
stop = TRUE;
}
else if (ch != ' ' && ch != '\t')
{
*valIndex = ptr - 1;
*valLen = 1;
*valid = TRUE;
state = PARSE_STATE_STRING_READING;
}
break;
case PARSE_STATE_STRING_READING:
if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else if ((ch != ' ') && (ch != '\t'))
{
*valLen = ptr - *valIndex;
}
break;
case PARSE_STATE_SKIP:
default:
if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
// state = PARSE_STATE_SKIP;
break;
}
}
lineBuffer[ptr] = 0;
return RET_EXT_NO_ERROR;
#else
#define PARSE_STATE_NEW 0
#define PARSE_STATE_SKIP 1
#define PARSE_STATE_KEY_READING 2
#define PARSE_STATE_KEY_FINISHED 3
#define PARSE_STATE_STRING_TRIM 4
#define PARSE_STATE_STRING_READING 5
INT8U state = PARSE_STATE_NEW;
INT32U ptr = 0;
BOOL stop = FALSE;
if ((eof == NULL) || (valid == NULL) || (lineBuffer == NULL) || (bufferSize == 0) || (keyIndex == NULL) || (keyLen == NULL) || (valIndex == NULL) || (valLen == NULL) || (fp == NULL))
return RET_OS_INVALID_PARAM;
*valid = FALSE;
for (; !stop;)
{
char ch = 0;
INT32U ret = FileStreamGet(&ch, fp);
if (ret != RET_EXT_NO_ERROR)
return ret;
if (ch != 0)
{
if (ptr < bufferSize - 1)
{
lineBuffer[ptr++] = ch;
}
else
{
if (((ch == '\r') || (ch == '\n')) && (ptr == bufferSize - 1))
lineBuffer[ptr - 1] = ch;
state = PARSE_STATE_SKIP;
*valid = FALSE;
}
}
switch (state)
{
case PARSE_STATE_NEW:
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
{
*keyIndex = ptr - 1;
state = PARSE_STATE_KEY_READING;
}
else if (ch == ' ' || ch == '\t')
{
// do nothing
}
else if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else
{
state = PARSE_STATE_SKIP;
}
break;
case PARSE_STATE_KEY_READING:
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '.') || (ch == '-') || (ch == '_') || (ch == '[') || (ch == ']'))
{
}
else if (ch == '=')
{
*keyLen = ptr - *keyIndex - 1;
state = PARSE_STATE_STRING_TRIM;
}
else if (ch == ' ' || ch == '\t')
{
*keyLen = ptr - *keyIndex - 1;
state = PARSE_STATE_KEY_FINISHED;
}
else if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else
{
state = PARSE_STATE_SKIP;
}
break;
case PARSE_STATE_KEY_FINISHED:
if (ch == '=')
{
state = PARSE_STATE_STRING_TRIM;
}
else if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else if (ch != ' ' && ch != '\t')
{
state = PARSE_STATE_SKIP;
}
break;
case PARSE_STATE_STRING_TRIM:
if (ch == '\r' || ch == '\n' || ch == 0)
{
*valIndex = ptr - 1;
*valLen = 0;
*valid = TRUE;
*eof = (ch == 0);
stop = TRUE;
}
else if (ch != ' ' && ch != '\t')
{
*valIndex = ptr - 1;
*valLen = 1;
*valid = TRUE;
state = PARSE_STATE_STRING_READING;
}
break;
case PARSE_STATE_STRING_READING:
if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
else if ((ch != ' ') && (ch != '\t'))
{
*valLen = ptr - *valIndex;
}
break;
case PARSE_STATE_SKIP:
default:
if (ch == '\r' || ch == '\n' || ch == 0)
{
*eof = (ch == 0);
stop = TRUE;
}
// state = PARSE_STATE_SKIP;
break;
}
}
lineBuffer[ptr] = 0;
#undef PARSE_STATE_NEW
#undef PARSE_STATE_SKIP
#undef PARSE_STATE_KEY_READING
#undef PARSE_STATE_KEY_FINISHED
#undef PARSE_STATE_STRING_TRIM
#undef PARSE_STATE_STRING_READING
return RET_EXT_NO_ERROR;
#endif
}
static INT32U FileStreamPropertyGet(const char *store, const char *id, const char *key, char *value, INT32U size, BOOL *isNull, file_provider *fp)
{
#if 0
char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
char buffer[PROPERTY_LINE_MAX + 2];
INT32U ret = RET_EXT_NO_ERROR;
#if (defined RTOS_UCOS)
INT8U osRet = OS_ERR_NONE;
#endif
if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (fp == NULL) || (isNull == NULL))
return RET_OS_INVALID_PARAM;
if ((id == NULL) || (*id == 0))
snprintf(filename, sizeof(filename), "0:/conf/%s.conf", store);
else
snprintf(filename, sizeof(filename), "0:/conf/%s.%s.conf", store, id);
#if (defined RTOS_UCOS)
OSSemPend(fp->sem, OSmsToTick(1000UL), &osRet);
if (osRet != OS_ERR_NONE)
return RET_OS_SYNC_OBJ_FAILED;
#elif ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1))
PROP_DISABLE_IRQ();
if (pp[providerId].flag.lock != 0)
ret = RET_OS_SYNC_OBJ_FAILED;
else
pp[providerId].flag.lock = 1;
PROP_ENABLE_IRQ();
if (ret != RET_EXT_NO_ERROR)
return ret;
#else
#error "Target error"
#endif
ret = FileCacheGet(&fp->cache, store, id, key, value, size, isNull);
if ((ret != RET_EXT_NO_ERROR) && (ret != RET_PROPERTY_OUT_OF_VAL_BUF))
{
*isNull = TRUE;
if ((id == NULL) || (*id == 0)) // global config file, checksum is required.
ret = FileStreamChecksum(filename);
else
ret = RET_EXT_NO_ERROR;
if (ret == RET_EXT_NO_ERROR)
ret = FileStreamOpen(filename, fp);
if (ret == RET_EXT_NO_ERROR)
{
for (;;)
{
BOOL eof = FALSE;
BOOL valid = FALSE;
INT32U keyIndex = 0;
INT32U keyLen = 0;
INT32U valIndex = 0;
INT32U valLen = 0;
ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp);
if (ret != RET_EXT_NO_ERROR)
break;
if (valid)
{
BOOL match = FALSE;
if ((keyLen == strlen(key)) && (strncmp(&buffer[keyIndex], key, keyLen) == 0))
{
if (valLen > size - 1)
{
valLen = size - 1;
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
}
*isNull = FALSE;
strncpy(value, &buffer[valIndex], valLen);
value[valLen] = 0;
match = TRUE;
}
if (fp->config.cache && (match || fp->config.prefetch))
{
buffer[keyIndex + keyLen] = 0;
buffer[valIndex + valLen] = 0;
FileCacheSet(&fp->cache, store, id, &buffer[keyIndex], &buffer[valIndex], fp->config.prefetch);
}
if (match && !fp->config.prefetch)
break;
}
if (eof)
break;
}
if ((ret == RET_EXT_NO_ERROR) && fp->config.prefetch)
{
file_cache *cache = NULL;
FileCacheTouch(&fp->cache, store, id, TRUE, &cache);
if (cache != NULL)
cache->allCache = TRUE;
}
}
FileStreamClose(fp);
}
PROP_UNLOCK(*fp);
return ret;
#else
char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
char buffer[PROPERTY_LINE_MAX + 2];
INT32U ret = RET_EXT_NO_ERROR;
if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (fp == NULL) || (isNull == NULL))
return RET_OS_INVALID_PARAM;
if ((id == NULL) || (*id == 0))
snprintf(filename, sizeof(filename), "%s/%s.conf", config_path, store);
ret = FileCacheGet(&fp->cache, store, id, key, value, size, isNull);
if ((ret != RET_EXT_NO_ERROR) && (ret != RET_PROPERTY_OUT_OF_VAL_BUF))
{
*isNull = TRUE;
// TODO:
#if 0
if ((id == NULL) || (*id == 0)) // global config file, checksum is required.
ret = FileStreamChecksum(filename);
else
ret = RET_EXT_NO_ERROR;
#else
ret = RET_EXT_NO_ERROR;
#endif
if (ret == RET_EXT_NO_ERROR)
{
// 打开文件
ret = FileStreamOpen(filename, fp);
// printf("ret = %d\n", ret);
}
if (ret == RET_EXT_NO_ERROR)
{
#if 0
//逻辑重写
for (;;)
{
BOOL eof = FALSE;
BOOL valid = FALSE;
INT32U keyIndex = 0;
INT32U keyLen = 0;
INT32U valIndex = 0;
INT32U valLen = 0;
// 读取单条
ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp);
if (ret != RET_EXT_NO_ERROR)
break;
if (valid)
{
BOOL match = FALSE;
if ((keyLen == strlen(key)) && (strncmp(&buffer[keyIndex], key, keyLen) == 0))
{
if (valLen > size - 1)
{
valLen = size - 1;
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
}
*isNull = FALSE;
strncpy(value, &buffer[valIndex], valLen);
value[valLen] = 0;
match = TRUE;
}
if (fp->config.cache && (match || fp->config.prefetch))
{
buffer[keyIndex + keyLen] = 0;
buffer[valIndex + valLen] = 0;
FileCacheSet(&fp->cache, store, id, &buffer[keyIndex], &buffer[valIndex], fp->config.prefetch);
}
if (match && !fp->config.prefetch)
break;
}
if (eof)
break;
}
#else
while (1)
{
char temp[100];
void *result = fgets(temp, sizeof(temp), fp->stream.fil);
if (result != NULL)
{
// printf("%s\n", temp);
// 搜索到正常的头部
if ((temp[0] >= 'a' && temp[0] <= 'z') || (temp[0] >= 'A' && temp[0] <= 'Z'))
{
// 比对key的情况key必须顶格写
int i = 0;
int result = 1;
while (key[i] != '\0')
{
if (temp[i] != key[i])
{
result = 0;
break;
}
if (temp[i] == '=')
{
result = 0;
break;
}
i++;
}
// 防守配置文件里面的key更长但是后面不相符的情况
if (temp[i] != '=')
{
result = 0;
}
//截断字符串
temp[i] = '\0';
// printf("result : %d ; key = %s ; serch = %s\n", result, key, temp);
// 找到目标
if (result == 1)
{
// 将值拷贝出去
*isNull = FALSE;
i++;
int j = 0;
while (1)
{
value[j] = temp[i];
j++;
i++;
if (temp[i] == ' ' || temp[i] == '\r' || temp[i] == '\t' || temp[i] == '\n')
{
break;
}
if (j >= (size - 1))
{
// 给的缓存太小了,报个错
return RET_PROPERTY_OUT_OF_VAL_BUF;
}
}
value[j] = '\0';
printf("get value = %s\n", value);
// 设置chache
if (fp->config.cache && (fp->config.prefetch))
{
FileCacheSet(&fp->cache, store, id, temp, value, fp->config.prefetch);
}
}
}
// 说明读到尾部了
if (feof(fp->stream.fil) == 1)
{
// printf("file end\n");
break;
}
}
else
{
// 读取失败,退出循环
// printf("file read error\n");
break;
}
}
#endif
if ((ret == RET_EXT_NO_ERROR) && fp->config.prefetch)
{
file_cache *cache = NULL;
FileCacheTouch(&fp->cache, store, id, TRUE, &cache);
if (cache != NULL)
cache->allCache = TRUE;
}
}
FileStreamClose(fp);
}
return ret;
#endif
}
static INT32U FileStreamPropertySet(const char *store, const char *id, property_string_item *list, INT32U count, file_provider *fp)
{
#if 0
char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 20];
char buffer[PROPERTY_LINE_MAX + 2];
INT32U ret = RET_EXT_NO_ERROR;
#if (defined RTOS_UCOS)
INT8U osRet = OS_ERR_NONE;
#endif
BOOL newLine = FALSE;
BOOL changed = FALSE;
INT32U idx;
if ((store == NULL) || (*store == 0) || (list == NULL) || (count == 0) || (fp == NULL))
return RET_OS_INVALID_PARAM;
if ((id == NULL) || (*id == 0))
return RET_PROPERTY_INVALID_STORE_ID;
for (idx = 0; idx < count; idx++)
{
if ((list[idx].key == NULL) || (*list[idx].key == 0))
return RET_OS_INVALID_PARAM;
list[idx].success = 0;
}
snprintf(filename, sizeof(filename), "%s/%s.%s.conf", config_path, store, id);
snprintf(filetmp, sizeof(filetmp), "%s/%s.%s.conf.tmp", config_path, store, id);
FILE_TEST_RANDOM(8);
if (f_open(&fp->stream.tmp, filetmp, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
ret = RET_PROPERTY_FILE_OPEN_ERR;
if (ret == RET_EXT_NO_ERROR)
{
ret = FileStreamOpen(filename, fp);
if (ret == RET_EXT_NO_ERROR)
{
for (;;)
{
BOOL skip = FALSE;
BOOL eof = FALSE;
BOOL valid = FALSE;
INT32U keyIndex = 0;
INT32U keyLen = 0;
INT32U valIndex = 0;
INT32U valLen = 0;
INT32U bw;
char lastCh;
ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp);
if (ret != RET_EXT_NO_ERROR)
break;
bw = strlen(buffer);
lastCh = ((bw > 0) ? buffer[bw - 1] : '\0');
if ((lastCh != '\r') && (lastCh != '\n') && (bw > 0))
newLine = TRUE;
if (valid)
{
for (idx = 0; idx < count; idx++)
{
if (list[idx].success)
continue;
if ((keyLen != strlen(list[idx].key)) || (strncmp(&buffer[keyIndex], list[idx].key, keyLen) != 0))
continue;
if (list[idx].value == NULL)
{
skip = TRUE;
}
else
{
if ((lastCh == '\r') || (lastCh == '\n'))
snprintf(buffer, sizeof(buffer), "%s=%s%c", list[idx].key, list[idx].value, lastCh);
else
snprintf(buffer, sizeof(buffer), "%s=%s", list[idx].key, list[idx].value);
bw = strlen(buffer);
}
if (fp->config.cache)
FileCacheSet(&fp->cache, store, id, list[idx].key, list[idx].value, FALSE);
list[idx].success = 1;
changed = TRUE;
break;
}
}
if (!skip)
{
if (f_write(&fp->stream.tmp, buffer, bw, &bw) != FR_OK)
{
ret = RET_PROPERTY_FILE_WRITE_ERR;
break;
}
}
if (eof)
break;
}
}
if (ret == RET_EXT_NO_ERROR)
{
for (idx = 0; idx < count; idx++)
{
INT32U bw;
if (list[idx].success)
continue;
if (list[idx].value == NULL)
{
list[idx].success = 1;
continue;
}
if (newLine)
{
newLine = FALSE;
bw = strlen("\r\n");
if (f_write(&fp->stream.tmp, "\r\n", bw, &bw) != FR_OK)
{
ret = RET_PROPERTY_FILE_WRITE_ERR;
break;
}
}
snprintf(buffer, sizeof(buffer), "%s=%s\r\n", list[idx].key, list[idx].value);
bw = strlen(buffer);
if (f_write(&fp->stream.tmp, buffer, bw, &bw) != 0)
{
ret = RET_PROPERTY_FILE_WRITE_ERR;
break;
}
if (fp->config.cache)
FileCacheSet(&fp->cache, store, id, list[idx].key, list[idx].value, FALSE);
list[idx].success = 1;
changed = TRUE;
}
}
FileStreamClose(fp);
f_close(&fp->stream.tmp);
// a. 将修改后的配置写入*.conf.tmp
// b. 将字符串"*.conf"写入update.log
// c. 删除*.conf
// d. 复制*.conf.tmp-> *.conf
// e. 删除update.log
// f. 删除 *.conf.tmp
if (ret == RET_EXT_NO_ERROR)
ret = PropWriteLogWrite(0, filename);
if (ret == RET_EXT_NO_ERROR)
PropWriteLogCommit(0, filename);
}
if (changed && (ret != RET_EXT_NO_ERROR))
FileCacheClear(&fp->cache, store, id);
PROP_UNLOCK(*fp);
if (ret != RET_EXT_NO_ERROR)
{
for (idx = 0; idx < count; idx++)
list[idx].success = 0;
}
return ret;
#else
return 0;
#endif
}
/** function comment
* @description:
* @param {char} *store
* @param {char} *key
* @param {char} *id ,NULL
* @param {char} *value
* @param {INT32U} sizeOfValue
* @param {BOOL} *isLocal
* @param {void} *obj
* @return {*}
*/
static INT32U FilePropertyGet(const char *store, const char *key, const char *id, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj)
{
BOOL isNull = TRUE;
INT32U ret = RET_PROPERTY_NOT_FOUND;
file_provider *fp = (file_provider *)obj;
if (fp == NULL)
return RET_OS_INVALID_PARAM;
if (isLocal != NULL)
*isLocal = FALSE;
// id在实际应用中没有找到
if ((id != NULL) && (*id != 0))
{
ret = FileStreamPropertyGet(store, id, key, value, sizeOfValue, &isNull, fp);
if ((ret == RET_EXT_NO_ERROR) && isNull)
ret = RET_PROPERTY_NOT_FOUND;
if ((ret == RET_EXT_NO_ERROR) && (isLocal != NULL))
*isLocal = TRUE;
}
if (ret == RET_PROPERTY_NOT_FOUND)
{
ret = FileStreamPropertyGet(store, NULL, key, value, sizeOfValue, &isNull, fp);
if ((ret == RET_EXT_NO_ERROR) && isNull)
ret = RET_PROPERTY_NOT_FOUND;
}
return ret;
}
static INT32U FilePropertySet(const char *store, const char *id, property_string_item *list, INT32U count, void *obj)
{
file_provider *fp = (file_provider *)obj;
if (fp == NULL)
return RET_OS_INVALID_PARAM;
if ((id != NULL) && (*id != 0))
return FileStreamPropertySet(store, id, list, count, fp);
else
return RET_PROPERTY_INVALID_STORE_ID;
}
static INT32U FilePropertyClear(const char *store, const char *id, void *obj)
{
INT32U ret = RET_EXT_NO_ERROR;
file_provider *fp = (file_provider *)obj;
if (fp == NULL)
return RET_OS_INVALID_PARAM;
if (!fp->config.cache)
return RET_EXT_NO_ERROR;
if ((id == NULL) || (*id == 0))
id = NULL;
if (ret == RET_EXT_NO_ERROR)
ret = FileCacheClear(&fp->cache, store, id);
return ret;
}
static INT32U FilePropertyInit(INT32U providerId, const PropertyInitParam *param)
{
INT32U ret = RET_EXT_NO_ERROR;
file_provider *fp = NULL;
if (ret == RET_EXT_NO_ERROR)
{
fp = (file_provider *)malloc_mt(sizeof(file_provider));
if (fp == NULL)
ret = RET_PROPERTY_HEAP_FULL;
}
if (ret == RET_EXT_NO_ERROR)
{
char storename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
INT32U ret2 = RET_EXT_NO_ERROR;
memset(fp, 0, sizeof(file_provider));
fp->config.cache = param->config.cache;
fp->config.prefetch = (param->config.cache && param->config.prefetch);
fp->cache = NULL;
pp[providerId].get = FilePropertyGet;
pp[providerId].set = FilePropertySet;
pp[providerId].clear = FilePropertyClear;
pp[providerId].obj = fp;
pp[providerId].flag.cache = param->config.cache;
pp[providerId].flag.init = 1;
#if 0 // 意义不明没有storename
ret2 = PropWriteLogLoad(providerId, storename, sizeof(storename));
if ((ret2 == RET_EXT_NO_ERROR) && (storename[0] != '\0'))
{
printf("PropWriteLogCommit(providerId=%d, storename=%s)\n\r", providerId, storename);
PropWriteLogCommit(providerId, storename);
}
#endif
}
else
{
if (fp != NULL)
free_mt(fp);
}
return ret;
}
#endif
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
/**************************************************************
* Remote property provider
*************************************************************
*/
typedef struct
{
INT32U destId;
} remote_provider;
static INT32U RemotePropertyGet(const char *store, const char *key, const char *id, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj)
{
INT8U outBuf[PROPERTY_LINE_MAX + sizeof(INT32U)];
INT8U *inBuf;
INT8U *ptr;
INT32U sizeOfIn;
INT32U sizeOfOut;
INT32U ret = RET_EXT_NO_ERROR;
if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (value == NULL) || (obj == NULL))
return RET_OS_INVALID_PARAM;
sizeOfIn = strlen(store) + strlen(key) + 3;
if (id != NULL)
sizeOfIn += strlen(id);
inBuf = (INT8U *)malloc_mt(sizeOfIn);
if (inBuf == NULL)
return RET_PROPERTY_HEAP_FULL;
ptr = inBuf;
memcpy(ptr, store, (strlen(store) + 1));
ptr += (strlen(store) + 1);
if (id == NULL)
{
*ptr = 0;
ptr++;
}
else
{
memcpy(ptr, id, (strlen(id) + 1));
ptr += (strlen(id) + 1);
}
memcpy(ptr, key, (strlen(key) + 1));
sizeOfOut = (PROPERTY_LINE_MAX + sizeof(INT32U));
ret = bus_host_execute(((remote_provider *)obj)->destId, 2, CMD_mgrGetProp, inBuf, sizeOfIn, outBuf, &sizeOfOut, NULL, NULL, NULL, NULL);
if (ret == RET_EXT_NO_ERROR)
{
if ((sizeOfOut > sizeof(INT32U)) && (outBuf[sizeOfOut - 1] == '\0'))
{
if (isLocal != NULL)
*isLocal = (((outBuf[0] & 0x01) == 0) ? FALSE : TRUE);
strncpy(value, (const char *)&outBuf[sizeof(INT32U)], sizeOfValue);
value[sizeOfValue - 1] = 0;
}
else
{
ret = RET_BUS_INVALID_RET_FORMAT;
}
}
free_mt(inBuf);
return ret;
}
static INT32U RemotePropertySet(const char *store, const char *id, property_string_item *list, INT32U count, void *obj)
{
INT32U i;
INT8U *inBuf;
INT8U *ptr;
INT32U sizeOfIn;
INT32U sizeOfOut = 0;
INT32U ret = RET_EXT_NO_ERROR;
if ((store == NULL) || (*store == 0) || (list == NULL) || (count == 0) || (obj == NULL))
return RET_OS_INVALID_PARAM;
if (count > 0xff)
return RET_PROPERTY_SETP_LIST_EXCEED_MAX;
sizeOfIn = (strlen(store) + 2);
if ((id != NULL) && (*id != 0))
sizeOfIn += strlen(id);
sizeOfIn += sizeof(INT8U);
for (i = 0; i < count; i++)
{
if ((list[i].key == NULL) || (*list[i].key == 0))
return RET_OS_INVALID_PARAM;
sizeOfIn += sizeof(INT8U);
sizeOfIn += (strlen(list[i].key) + 2);
if ((list[i].value != NULL) && (*list[i].value != 0))
sizeOfIn += strlen(list[i].value);
}
inBuf = (INT8U *)malloc_mt(sizeOfIn);
if (inBuf == NULL)
return RET_PROPERTY_HEAP_FULL;
ptr = inBuf;
memcpy(ptr, store, (strlen(store) + 1));
ptr += (strlen(store) + 1);
if (id == NULL)
{
*ptr = 0;
ptr++;
}
else
{
memcpy(ptr, id, (strlen(id) + 1));
ptr += (strlen(id) + 1);
}
*ptr = (count & 0xff);
ptr++;
for (i = 0; i < count; i++)
{
list[i].success = 0;
if (list[i].value == NULL)
*ptr = 0x01; // clear property
else
*ptr = 0x00; // set property
ptr++;
memcpy(ptr, list[i].key, (strlen(list[i].key) + 1));
ptr += (strlen(list[i].key) + 1);
if (list[i].value == NULL)
{
*ptr = 0;
ptr++;
}
else
{
memcpy(ptr, list[i].value, (strlen(list[i].value) + 1));
ptr += (strlen(list[i].value) + 1);
}
}
ret = bus_host_execute(((remote_provider *)obj)->destId, 2, CMD_mgrSetPropL, inBuf, sizeOfIn, NULL, &sizeOfOut, NULL, NULL, NULL, NULL);
if (ret == RET_EXT_NO_ERROR)
{
for (i = 0; i < count; i++)
list[i].success = 0;
}
free_mt(inBuf);
return ret;
}
static INT32U RemotePropertyClear(const char *store, const char *id, void *obj)
{
// RemotePropertyClear(), 远端缓存不需要客户端清除, 由远端根据实际情况自行决定
return RET_EXT_NO_ERROR;
}
static INT32U RemotePropertyInit(INT32U providerId, const PropertyInitParam *param)
{
INT32U ret = RET_EXT_NO_ERROR;
remote_provider *rp = (remote_provider *)malloc_mt(sizeof(remote_provider));
if (rp == NULL)
ret = RET_PROPERTY_HEAP_FULL;
if (ret == RET_EXT_NO_ERROR)
{
memset(rp, 0, sizeof(remote_provider));
rp->destId = param->destId;
pp[providerId].get = RemotePropertyGet;
pp[providerId].set = RemotePropertySet;
pp[providerId].clear = RemotePropertyClear;
pp[providerId].obj = rp;
pp[providerId].flag.cache = param->config.cache;
pp[providerId].flag.init = 1;
}
else
{
if (rp != NULL)
free_mt(rp);
}
return ret;
}
#endif
#if 1
// store name
static char propStoreSystem[40] = "0x1820_system";
static char propStorePanel[40] = "0x1820_0x0000_panel";
static char propStoreTarget[40] = "0x1820_0x0000_target";
static char propStorePipette[40] = "0x1820_0x0000_pipette";
static char propStoreTip[40] = "0x1820_0x0000_tip";
static char propStoreContainer[40] = "0x1820_0x0000_container";
static char propStoreMotor[40] = "0x1820_0x0000_motor";
static char propStoreDispense[40] = "0x1820_0x0000_dispense";
static char propStoreDevMapping[40] = "0x1820_0x0000_dm";
static char propStoreRoute[40] = "0x1820_0x0000_route";
static char propStoreDiv[40] = "0x1820_0x0000_div";
static char propStoreModule[40] = "0x1820_0x0000_module";
static char propStoreWash[40] = "0x1820_0x0000_wash";
static char propStoreRea[40] = "0x1820_0x0000_reagentplate";
const char *GetStoreName(const char *store)
{
if (store == NULL)
return NULL;
if (strcmp(store, "motor") == 0)
return propStoreMotor;
if (strcmp(store, "panel") == 0)
return propStorePanel;
if (strcmp(store, "target") == 0)
return propStoreTarget;
if (strcmp(store, "pipette") == 0)
return propStorePipette;
if (strcmp(store, "tip") == 0)
return propStoreTip;
if (strcmp(store, "container") == 0)
return propStoreContainer;
if (strcmp(store, "dispense") == 0)
return propStoreDispense;
if (strcmp(store, "module") == 0)
return propStoreModule;
if (strcmp(store, "dm") == 0)
return propStoreDevMapping;
if (strcmp(store, "route") == 0)
return propStoreRoute;
if (strcmp(store, "div") == 0)
return propStoreDiv;
if (strcmp(store, "system") == 0)
return propStoreSystem;
if (strcmp(store, "wash") == 0)
return propStoreWash;
return NULL;
}
//unit test
int main(void)
{
INT32U retCode = RET_EXT_NO_ERROR;
PropertyInitParam param;
param.config.cache = 1;
param.config.prefetch = 1;
param.id = 0;
param.type = PropertyTypeFS;
PropertyInit(0, &param);
INT32U ret = 0;
INT32U val = GetUnsigned(0, "0x1820_0x0000_container", "Container0.Bottom", 0, 0, &ret, NULL);
printf("%d,%d\n", val, ret);
val = GetUnsigned(0, "0x1820_0x0000_container", "Container0.Bottom", 0, 0, &ret, NULL);
printf("%d,%d\n", val, ret);
}
#endif