work_tmp/property.c

2973 lines
71 KiB
C
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 "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的特点是将所有模式字符串的字符按照字典序排列并将它们连接成一个字符串作为树的主干Spine每个模式字符串作为树的一个分支。在SBT中模式字符串的公共前缀被共享从而减少了树的高度提高了匹配效率。
*/
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