359 lines
9.7 KiB
C
359 lines
9.7 KiB
C
|
|
/*
|
|||
|
|
* Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved.
|
|||
|
|
* Description: CCO meter archive handle.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#include "mrs_cco_archives.h"
|
|||
|
|
#include "mrs_cco_srv.h"
|
|||
|
|
#include "mrs_common_tools.h"
|
|||
|
|
|
|||
|
|
#if defined(PRODUCT_CFG_PRODUCT_TYPE_CCO)
|
|||
|
|
#define ARCHIVES_LOAD_MAX ARCHIVES_NUM_MAX
|
|||
|
|
#define ARCHIVES_ADDR_OFFSET 0x2000
|
|||
|
|
#define METER_ARCHIVES_MAGIC uapi_make_identifier('M', 'R', 'S', 'M')
|
|||
|
|
#define METER_ARCHIVES_ITEM_SIZE (sizeof(meter_item))
|
|||
|
|
|
|||
|
|
meter_archives *g_meter_archives = TD_NULL;
|
|||
|
|
td_bool g_meter_archives_changed = TD_FALSE;
|
|||
|
|
td_u32 g_archives_flash_addr = 0;
|
|||
|
|
|
|||
|
|
/* Free globle context */
|
|||
|
|
td_void mrs_archives_free(td_void);
|
|||
|
|
/* Load head and meters from flash */
|
|||
|
|
td_u32 mrs_archives_load(td_void);
|
|||
|
|
/* Save head and meters to flash */
|
|||
|
|
td_u32 mrs_archives_save(td_void);
|
|||
|
|
/* Verify archives saved be avaliable */
|
|||
|
|
td_u32 mrs_meter_archives_verify(const meter_archives *archives);
|
|||
|
|
|
|||
|
|
/* timeout proc */
|
|||
|
|
td_void mrs_archives_on_timer(td_void)
|
|||
|
|
{
|
|||
|
|
if (g_meter_archives != TD_NULL) {
|
|||
|
|
if (g_meter_archives_changed == TD_TRUE) {
|
|||
|
|
mrs_archives_save();
|
|||
|
|
mrs_cco_setup_whitelist();
|
|||
|
|
|
|||
|
|
/* set back to default value */
|
|||
|
|
g_meter_archives_changed = TD_FALSE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mrs_archives_free();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u32 mrs_archives_init(td_void)
|
|||
|
|
{
|
|||
|
|
td_u32 ret;
|
|||
|
|
ext_flash_partition_table *ptbl = TD_NULL;
|
|||
|
|
|
|||
|
|
if (g_meter_archives != TD_NULL) {
|
|||
|
|
mrs_archives_free();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
g_meter_archives = (meter_archives *)mrs_malloc(sizeof(meter_archives));
|
|||
|
|
if (g_meter_archives == TD_NULL) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ret = (td_u32)memset_s(g_meter_archives, sizeof(meter_archives), 0, sizeof(meter_archives));
|
|||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|||
|
|
mrs_archives_free();
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Get archives address */
|
|||
|
|
ptbl = uapi_get_partition_table();
|
|||
|
|
if (ptbl == TD_NULL) {
|
|||
|
|
mrs_archives_free();
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
g_archives_flash_addr = (td_u32)(ptbl->table[EXT_FLASH_PARTITON_USER_INFO_1].addr_blk * PRODUCT_CFG_FLASH_BLOCK_SIZE
|
|||
|
|
+ ARCHIVES_ADDR_OFFSET);
|
|||
|
|
|
|||
|
|
ret = mrs_archives_load();
|
|||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|||
|
|
mrs_archives_free();
|
|||
|
|
g_meter_archives_changed = TD_FALSE;
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_void mrs_archives_free(td_void)
|
|||
|
|
{
|
|||
|
|
if (g_meter_archives != TD_NULL) {
|
|||
|
|
mrs_free(g_meter_archives);
|
|||
|
|
g_meter_archives = TD_NULL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u32 mrs_archives_load(td_void)
|
|||
|
|
{
|
|||
|
|
td_u32 ret;
|
|||
|
|
td_u32 read_addr = g_archives_flash_addr;
|
|||
|
|
td_u32 read_size = sizeof(meter_archives);
|
|||
|
|
meter_archives *archives = mrs_archives_get();
|
|||
|
|
|
|||
|
|
if ((archives == TD_NULL) || (read_addr == 0)) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Read head from flash first in order to get number of available meters */
|
|||
|
|
ret = uapi_flash_read(read_addr, read_size, (td_u8 *)archives);
|
|||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ret = mrs_meter_archives_verify(archives);
|
|||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|||
|
|
/* Dirty Data on flash, reset */
|
|||
|
|
mrs_archives_clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return EXT_ERR_SUCCESS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u32 mrs_meter_archives_verify(const meter_archives *archives)
|
|||
|
|
{
|
|||
|
|
td_u32 crc = 0;
|
|||
|
|
if (archives == TD_NULL) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (archives->head.magic != METER_ARCHIVES_MAGIC) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* From magic in head to the end, skip size of element crc32 */
|
|||
|
|
crc = uapi_crc32(crc, (EXT_CONST td_u8 *)&archives->head.magic, (td_u32)sizeof(meter_archives) - sizeof(td_u32));
|
|||
|
|
if (crc != archives->head.crc32) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return EXT_ERR_SUCCESS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u32 mrs_archives_save()
|
|||
|
|
{
|
|||
|
|
td_u32 ret;
|
|||
|
|
|
|||
|
|
if ((g_meter_archives == TD_NULL) || (g_archives_flash_addr == 0)) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
g_meter_archives->head.magic = METER_ARCHIVES_MAGIC;
|
|||
|
|
/* From magic in head to the end, skip size of element crc32 */
|
|||
|
|
g_meter_archives->head.crc32 = uapi_crc32(0, (EXT_CONST td_u8 *)&g_meter_archives->head.magic,
|
|||
|
|
(td_u32)sizeof(meter_archives) - sizeof(td_u32));
|
|||
|
|
|
|||
|
|
ret = uapi_flash_erase(g_archives_flash_addr, PRODUCT_CFG_FLASH_BLOCK_SIZE * 2); /* erase 2 block */
|
|||
|
|
|
|||
|
|
ret |= uapi_flash_write(g_archives_flash_addr, sizeof(meter_archives), (EXT_CONST td_u8 *)g_meter_archives,
|
|||
|
|
TD_FALSE);
|
|||
|
|
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
meter_archives *mrs_archives_get(td_void)
|
|||
|
|
{
|
|||
|
|
if (g_meter_archives == TD_NULL) {
|
|||
|
|
if (mrs_archives_init() != EXT_ERR_SUCCESS) {
|
|||
|
|
return TD_NULL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (g_meter_archives != TD_NULL) {
|
|||
|
|
mrs_timer_start(MRS_TIMER_ID_METER_ARCHIVES, ARCHIVES_SLIDE_WINDOW, EXT_TIMER_TYPE_ONCE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return g_meter_archives;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u32 mrs_archives_append(const td_pbyte list, td_u16 count)
|
|||
|
|
{
|
|||
|
|
meter_archives *archives = mrs_archives_get();
|
|||
|
|
td_u16 i;
|
|||
|
|
td_u16 j;
|
|||
|
|
|
|||
|
|
if (archives == TD_NULL) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (archives->head.num == ARCHIVES_NUM_MAX) {
|
|||
|
|
return EXT_ERR_FULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mrs_timer_start(MRS_TIMER_ID_METER_ARCHIVES, ARCHIVES_SLIDE_WINDOW, EXT_TIMER_TYPE_ONCE);
|
|||
|
|
|
|||
|
|
/* Because meter struct is one byte larger than 1376.2 defined, pay attention to the struct size
|
|||
|
|
* CNComments: 因为档案中的表结构比376.2协议报文中的从节点结构不同,
|
|||
|
|
* 在比较和拷贝的时候需要注意。
|
|||
|
|
*/
|
|||
|
|
for (i = 0; (i < count) && (archives->head.num < ARCHIVES_NUM_MAX); i++) {
|
|||
|
|
for (j = 0; j < archives->head.num; j++) {
|
|||
|
|
if (0 == memcmp(list + MRS_1376_2_SEC_NODE_ITEM_SIZE * i,
|
|||
|
|
archives->items + j,
|
|||
|
|
MRS_1376_2_SEC_NODE_ITEM_SIZE)) {
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (j == archives->head.num) {
|
|||
|
|
if (memcpy_s(archives->items + j, sizeof(meter_item),
|
|||
|
|
list + MRS_1376_2_SEC_NODE_ITEM_SIZE * i, MRS_1376_2_SEC_NODE_ITEM_SIZE) != EOK) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
archives->head.num++;
|
|||
|
|
g_meter_archives_changed = TD_TRUE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return EXT_ERR_SUCCESS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u32 mrs_archives_delete(const td_pbyte list, td_u16 count)
|
|||
|
|
{
|
|||
|
|
meter_archives *archives = mrs_archives_get();
|
|||
|
|
meter_archives_head *head = TD_NULL;
|
|||
|
|
meter_item *items = TD_NULL;
|
|||
|
|
td_u16 num_tmp;
|
|||
|
|
td_u16 i;
|
|||
|
|
td_u16 j;
|
|||
|
|
|
|||
|
|
if (archives == TD_NULL) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
head = &archives->head;
|
|||
|
|
items = archives->items;
|
|||
|
|
num_tmp = head->num;
|
|||
|
|
|
|||
|
|
if (num_tmp == 0) {
|
|||
|
|
/* At bottom */
|
|||
|
|
return EXT_ERR_NOT_FOUND;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mrs_timer_start(MRS_TIMER_ID_METER_ARCHIVES, ARCHIVES_SLIDE_WINDOW, EXT_TIMER_TYPE_ONCE);
|
|||
|
|
|
|||
|
|
for (i = 0; i < count; i++) {
|
|||
|
|
for (j = 0; j < head->num; j++) {
|
|||
|
|
if (memcmp(list + ARCHIVES_METER_ADDR_SIZE * i, items + j, ARCHIVES_METER_ADDR_SIZE) != 0) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (j != (head->num - 1)) {
|
|||
|
|
/* Move the last one to fill in */
|
|||
|
|
(td_void) memcpy_s(items + j, sizeof(meter_item),
|
|||
|
|
items + (head->num - 1), sizeof(meter_item));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
(td_void) memset_s(items + (head->num - 1), sizeof(meter_item), 0xff, sizeof(meter_item));
|
|||
|
|
|
|||
|
|
/* Keep updating the head */
|
|||
|
|
head->num--;
|
|||
|
|
g_meter_archives_changed = TD_TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (num_tmp == head->num) {
|
|||
|
|
/* Did NOT delete any meter */
|
|||
|
|
return EXT_ERR_NOT_FOUND;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return EXT_ERR_SUCCESS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u32 mrs_archives_clear(td_void)
|
|||
|
|
{
|
|||
|
|
meter_archives *archives = mrs_archives_get();
|
|||
|
|
|
|||
|
|
if (archives == TD_NULL) {
|
|||
|
|
return EXT_ERR_FAILURE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ((archives->head).num != 0) {
|
|||
|
|
(td_void) memset_s(archives, sizeof(meter_archives), 0xFF, sizeof(meter_archives));
|
|||
|
|
(archives->head).crc32 = 0;
|
|||
|
|
archives->head.magic = METER_ARCHIVES_MAGIC;
|
|||
|
|
(archives->head).num = 0;
|
|||
|
|
g_meter_archives_changed = TD_TRUE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mrs_timer_start(MRS_TIMER_ID_METER_ARCHIVES, ARCHIVES_SLIDE_WINDOW, EXT_TIMER_TYPE_ONCE);
|
|||
|
|
|
|||
|
|
return EXT_ERR_SUCCESS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u16 mrs_archives_get_number(td_void)
|
|||
|
|
{
|
|||
|
|
meter_archives *archives = mrs_archives_get();
|
|||
|
|
|
|||
|
|
if (archives == TD_NULL) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return archives->head.num;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
meter_item *mrs_archives_get_by_idx(td_u16 idx)
|
|||
|
|
{
|
|||
|
|
meter_archives_head *head = TD_NULL;
|
|||
|
|
meter_item *meters = TD_NULL;
|
|||
|
|
meter_archives *archives = mrs_archives_get();
|
|||
|
|
|
|||
|
|
if (archives == TD_NULL) {
|
|||
|
|
return TD_NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
head = &archives->head;
|
|||
|
|
if (head->num <= idx) {
|
|||
|
|
/* No valid meter behind */
|
|||
|
|
return TD_NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
meters = archives->items;
|
|||
|
|
|
|||
|
|
return (meters + idx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
meter_item *mrs_archives_get_meter_by_addr(const td_u8 addr[MRS_METER_ADDR_LEN])
|
|||
|
|
{
|
|||
|
|
meter_archives *archives = mrs_archives_get();
|
|||
|
|
meter_item *items = TD_NULL;
|
|||
|
|
td_u16 item_num = mrs_archives_get_number();
|
|||
|
|
td_u16 idx;
|
|||
|
|
|
|||
|
|
if ((archives == TD_NULL) || (item_num == 0)) {
|
|||
|
|
return TD_NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
items = archives->items;
|
|||
|
|
|
|||
|
|
for (idx = 0; idx < item_num; idx++) {
|
|||
|
|
if (memcmp(items[idx].addr, addr, MRS_METER_ADDR_LEN) == 0) {
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (items + idx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
td_u8 mrs_archives_get_meter_protocol(const td_u8 addr[MRS_METER_ADDR_LEN])
|
|||
|
|
{
|
|||
|
|
meter_item *meter = mrs_archives_get_meter_by_addr(addr);
|
|||
|
|
|
|||
|
|
if (meter != TD_NULL) {
|
|||
|
|
return meter->protocol;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return METER_PROTO_UNKNOWN;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif
|
|||
|
|
|