This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/application/src/fal_execution.c

584 lines
22 KiB
C
Raw 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.

/**
* @file fal_execution.c
* @author xxx
* @date 2023-12-29 11:27:55
* @brief
* @copyright Copyright (c) 2024 by xxx, All Rights Reserved.
*/
/**
*
存储模块是一个用于存储和读取数据的函数,它使用了 FALFlash Abstraction Layer库来实现。FAL 库是一个用于访问 Flash 存储器的抽象层,
它提供了一组标准的接口,使得应用程序可以方便地访问 Flash 存储器中的数据。在这段代码中,函数 fal_execution_kv_read()
用于从 KVKey-Value存储中读取指定键的值函数 fal_execution_kv_write() 用于向指定的 KV 存储中写入一个键值对。
函数 fal_execution_inspection() 用于对数据进行检查和存储。在函数 fal_execution_kv_read() 中,首先使用函数 fal_execution_get()
将给定的键转换为相应的执行结构,然后调用函数 fdb_kv_get_blob() 从 KV 存储中读取数据并存储在 blob 变量中。如果读取到的数据长度大于 0
则调用函数 fal_execution_set_crc() 和 fal_execution_set_cmac() 对数据进行 CRC 和 CMAC 校验,并返回 TRUE。否则返回 FALSE。
在函数 fal_execution_kv_write() 中,首先使用函数 fal_execution_get() 将给定的键转换为相应的执行结构,然后调用函数
fdb_kv_set_blob() 将数据写入 KV 存储。如果写入操作成功,则调用函数 fal_execution_set_crc() 和 fal_execution_set_cmac()
对数据进行 CRC 和 CMAC 校验,并返回 TRUE。否则返回 FALSE。在函数 fal_execution_inspection() 中,
首先检查 M95_1 和 FM24 两个执行结构是否已经初始化如果已经初始化则对校准参数、设备参数、HART 参数和 HART 用户参数进行检查和存储。
如果存储失败,则将相应的执行结构的状态标志位设置为 0。如果 FM24 已经初始化,则每隔一段时间对实时数据进行存储。
*/
#include "fal_execution.h"
#include "board.h"
#include "sys.h"
#include "entity.h"
#include "cmac.h"
#define FAL_DBG_ENABLE 0 // 等测试完成后再删除
const char *FAL_KV_KEY[KEY_MAX] =
{
"calibpara_param",
"device",
"hart_device_variable_param",
"real_time_data",
"mode_param",
};
static fal_execution_status_t fal_execution_status; // eeprom状态
static fal_execution_t fal_executions[FAL_EXECUTION_MAX];
static struct fdb_default_kv_node m95_1_kv_table[] = {
{(char *)&FAL_KV_KEY[KEY_CALIBPARA_PARAM], &calib_param, sizeof(calib_param_t) * CALIBPARA_NUM}, // 校准参数
{(char *)&FAL_KV_KEY[KEY_DEVICE], &udevice, sizeof(device_typedef)}, // 设备内设置的信息
{(char *)&FAL_KV_KEY[KEY_MODE_PARAM], &mode_params, sizeof(mode_params_t)}, // 模式参数:控制算法自定义参数
};
static struct fdb_default_kv_node fm24_kv_table[] = {
{(char *)&FAL_KV_KEY[KEY_REAL_TIME_DATA], &rt_data, sizeof(real_time_data_t)}, // 实时数据
};
// 数据加密校验
typedef struct
{
uint8_t mic[4];
} fal_inspection_cmac_t;
static uint8_t cmac_key[] = {
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; // 密钥
static uint16_t fal_inspection_crc[KEY_MAX]; // 用于保存结构体CRC值保证相同数据内容不写入
static fal_inspection_cmac_t fal_inspection_cmac[KEY_MAX]; // 用于保存结构体CMAC值保证相同数据内容不写入
// 内部接口 // 获取时间戳
static fal_execution_t *fal_execution_get(const fal_key_e key); // 获取fal_execution_t结构体
static void fal_execution_set_crc(const uint8_t index, const uint8_t *const data, const uint16_t length); // 数据的CRC计算
static void fal_execution_set_cmac(const uint8_t index, const uint8_t *const data, const uint16_t length); // 数据的CMAC计算
static BOOL fal_execution_data_storage_check(const uint8_t index, const uint8_t *const data, const uint16_t length); // 数据的校验
/**
* @brief fal执行初始化
* @return {*}
* @note
*/
void fal_execution_init(void)
{
fal_execution_status.init.data = 0;
fal_execution_status.read.data = 0;
fal_execution_status.write.data = 0;
fal_execution_t *p = NULL;
fdb_err_t res = FDB_NO_ERR;
osel_memset((uint8_t *)&fal_inspection_crc, 0, sizeof(uint16_t) * KEY_MAX);
// 初始化M95_1
p = &fal_executions[FAL_EXECUTION_EEPROM_M95_1];
p->eeprom_index = FAL_EXECUTION_EEPROM_M95_1;
p->kv.kvs = m95_1_kv_table;
p->kv.num = ARRAY_LEN(m95_1_kv_table);
fdb_kvdb_control(&p->kvdb, FDB_KVDB_CTRL_SET_LOCK, NULL);
fdb_kvdb_control(&p->kvdb, FDB_KVDB_CTRL_SET_UNLOCK, NULL);
res = fdb_kvdb_init(&p->kvdb, "env", "KVDB", &p->kv, NULL);
if (res != FDB_NO_ERR)
{
fal_execution_status.init.bits.M95_1 = 0;
fal_execution_status.read.bits.M95_1 = 0;
fal_execution_status.write.bits.M95_1 = 0;
}
else
{
fal_execution_status.init.bits.M95_1 = 1;
fal_execution_status.read.bits.M95_1 = 1;
fal_execution_status.write.bits.M95_1 = 1;
}
// 初始化M95_2
p = &fal_executions[FAL_EXECUTION_EEPROM_M95_2];
p->eeprom_index = FAL_EXECUTION_EEPROM_M95_2;
fdb_tsdb_control(&p->tsdb, FDB_TSDB_CTRL_SET_LOCK, NULL);
fdb_tsdb_control(&p->tsdb, FDB_TSDB_CTRL_SET_UNLOCK, NULL);
res = fdb_tsdb_init(&p->tsdb, "log", "TSDB", fal_execution_get_time, 128, NULL);
if (res != FDB_NO_ERR)
{
fal_execution_status.init.bits.M95_2 = 0;
fal_execution_status.read.bits.M95_2 = 0;
fal_execution_status.write.bits.M95_2 = 0;
}
else
{
fal_execution_status.init.bits.M95_2 = 1;
fal_execution_status.read.bits.M95_2 = 1;
fal_execution_status.write.bits.M95_2 = 1;
}
// 初始化FM24
p = &fal_executions[FAL_EXECUTION_EEPROM_FM24];
p->eeprom_index = FAL_EXECUTION_EEPROM_FM24;
p->kv.kvs = fm24_kv_table;
p->kv.num = ARRAY_LEN(fm24_kv_table);
fdb_kvdb_control(&p->kvdb, FDB_KVDB_CTRL_SET_LOCK, NULL);
fdb_kvdb_control(&p->kvdb, FDB_KVDB_CTRL_SET_UNLOCK, NULL);
res = fdb_kvdb_init(&p->kvdb, "env", "RTDB", &p->kv, NULL);
if (res != FDB_NO_ERR)
{
fal_execution_status.init.bits.FM24 = 0;
fal_execution_status.read.bits.FM24 = 0;
fal_execution_status.write.bits.FM24 = 0;
}
else
{
fal_execution_status.init.bits.FM24 = 1;
fal_execution_status.read.bits.FM24 = 1;
fal_execution_status.write.bits.FM24 = 1;
}
}
/**
* @brief fal执行清除
* @param {fal_execution_e} index
* @return {*}
* @note
*/
void fal_execution_clear(fal_execution_e index)
{
fal_execution_t *p = NULL;
switch (index)
{
case FAL_EXECUTION_EEPROM_M95_1:
p = &fal_executions[FAL_EXECUTION_EEPROM_M95_1];
fdb_kv_set_default(&p->kvdb);
break;
case FAL_EXECUTION_EEPROM_M95_2:
p = &fal_executions[FAL_EXECUTION_EEPROM_M95_2];
fdb_tsl_clean(&p->tsdb);
break;
case FAL_EXECUTION_EEPROM_FM24:
p = &fal_executions[FAL_EXECUTION_EEPROM_FM24];
fdb_kv_set_default(&p->kvdb);
break;
default:
DBG_ASSERT(FALSE __DBG_LINE);
break;
}
}
/**
* @brief 获取fal_execution_t结构体
* @param {fal_execution_e} index
* @return {*}
* @note
*/
static fal_execution_t *fal_execution_get(const fal_key_e key)
{
fal_execution_t *p = NULL;
switch (key)
{
case KEY_CALIBPARA_PARAM: // 校准参数
case KEY_DEVICE: // 设备内设置的信息
case KEY_MODE_PARAM: // 模式参数:控制算法自定义参数
case KEY_HART_DEVICE_VARIABLE_PARAM: // HART设备信息
if (fal_execution_status.init.bits.M95_1 == 1)
{
p = &fal_executions[FAL_EXECUTION_EEPROM_M95_1];
}
break;
case KEY_REAL_TIME_DATA: // 实时数据
if (fal_execution_status.init.bits.FM24 == 1)
{
p = &fal_executions[FAL_EXECUTION_EEPROM_FM24];
}
break;
default:
break;
}
return p;
}
/**
* @brief 数据的CRC计算
* @param {uint8_t} index 数据索引
* @param {uint8_t} *data 数据指针
* @param {uint16_t} length 数据长度
* @return {*}
* @note
*/
static void fal_execution_set_crc(const uint8_t index, const uint8_t *const data, const uint16_t length)
{
uint16_t crc = crc16_compute(data, length);
fal_inspection_crc[index] = crc;
}
/**
* @brief 数据的CMAC计算
* @param {uint8_t} index 数据索引
* @param {uint8_t} *data 数据指针
* @param {uint16_t} length 数据长度
* @return {*}
* @note
*/
static void fal_execution_set_cmac(const uint8_t index, const uint8_t *const data, const uint16_t length)
{
uint8_t mic[16];
uint8_t *p;
AES_CMAC_CTX AesCmacCtx[1]; // 密钥扩展表
AES_CMAC_Init(AesCmacCtx); // 完成密钥扩展表的初始化
AES_CMAC_SetKey(AesCmacCtx, cmac_key); // 完成密钥扩展表数据 // 存放生成校验数据的数组
AES_CMAC_Update(AesCmacCtx, data, length & 0xFF); // 完成数据的奇偶校验
AES_CMAC_Final(mic, AesCmacCtx); // 生成16个字节的校验表
uint32_t xor_vol = (uint32_t)((uint32_t)mic[3] << 24 | (uint32_t)mic[2] << 16 | (uint32_t)mic[1] << 8 | (uint32_t)mic[0]); // 取表4个字节作为校验码
p = (uint8_t *)&xor_vol;
osel_memcpy(fal_inspection_cmac[index].mic, p, 4);
}
/**
* @brief 数据的校验
* @param {uint8_t} index 数据索引
* @param {uint8_t} *data 数据指针
* @param {uint16_t} length 数据长度
* @return {*}
* @note 这个函数用于对数据进行校验包括CRC校验和CMAC校验。
*/
static BOOL fal_execution_data_storage_check(const uint8_t index, const uint8_t *const data, const uint16_t length)
{
// CRC校验
{
uint16_t crc = 0;
crc = crc16_compute(data, length);
if (crc != fal_inspection_crc[index])
{
return FALSE;
}
}
// CMAC校验
{
uint8_t mic[16];
uint8_t *p;
AES_CMAC_CTX AesCmacCtx[1]; // 密钥扩展表
AES_CMAC_Init(AesCmacCtx); // 完成密钥扩展表的初始化
AES_CMAC_SetKey(AesCmacCtx, cmac_key); // 完成密钥扩展表数据 // 存放生成校验数据的数组
AES_CMAC_Update(AesCmacCtx, data, length & 0xFF); // 完成数据的奇偶校验
AES_CMAC_Final(mic, AesCmacCtx); // 生成16个字节的校验表
uint32_t xor_vol = (uint32_t)((uint32_t)mic[3] << 24 | (uint32_t)mic[2] << 16 | (uint32_t)mic[1] << 8 | (uint32_t)mic[0]); // 取表4个字节作为校验码
p = (uint8_t *)&xor_vol;
if (osel_memcmp(fal_inspection_cmac[index].mic, p, 4) != 0)
{
return FALSE;
}
}
return TRUE;
}
fdb_time_t fal_execution_get_time(void)
{
/* Using the counts instead of timestamp.
* Please change this function to return RTC time.
*/
rtc_date_t dd;
rtc_time_t tt;
uDateTime_TypeDef timestamp; // 时间戳
get_timestamp((uDateTime_TypeDef *)&timestamp);
dd.year = hex_format_dec(timestamp.Date.Year);
dd.month = hex_format_dec(timestamp.Date.Month);
dd.day = hex_format_dec(timestamp.Date.Day);
tt.hour = hex_format_dec(timestamp.Date.Hour);
tt.minute = hex_format_dec(timestamp.Date.Minute);
tt.second = hex_format_dec(timestamp.Date.Second);
return (int32_t)time2stamp(&dd, &tt);
}
/**
* 从 KV 存储中读取指定键的值
*
* @param key 要从 KV 存储中读取的键
* @param data 用于存储读取到的数据的缓冲区
* @param length 缓冲区的长度
*
* @return true 如果读取操作成功false 否则
*
* @note 此函数从 KV 存储中读取指定键的值。首先,它检查给定的键是否与任何预定义的键匹配,如果是,则将相应的执行结构分配给 'p' 变量。然后,它调用 fdb_kv_get_blob() 函数从 KV 存储中读取数据并返回结果。如果给定的键不与任何预定义的键匹配,则断言条件为 false 并返回 false。
*/
BOOL fal_execution_kv_read(const fal_key_e key, const uint8_t *data, uint16_t length)
{
DBG_ASSERT(FAL_KV_KEY[key] != NULL __DBG_LINE);
BOOL rv = FALSE;
struct fdb_blob blob; // 定义一个 fdb_blob 结构体变量 blob
fal_execution_t *p = fal_execution_get(key); // 将给定的键转换为相应的执行结构
if (p == NULL)
{
return FALSE;
}
fdb_kv_get_blob(&p->kvdb, FAL_KV_KEY[key], fdb_blob_make(&blob, data, length)); // 从 KV 存储中读取数据并存储在 blob 变量中
if (blob.saved.len > 0) // 如果 blob 变量中的数据长度大于 0
{
fal_execution_set_crc((uint8_t)key, data, length); // 数据的CRC计算
fal_execution_set_cmac((uint8_t)key, data, length); // 数据的CMAC计算
rv = TRUE; // 返回 true
}
else
{
rv = FALSE; // 返回 false
}
switch (p->eeprom_index)
{
case FAL_EXECUTION_EEPROM_M95_1:
fal_execution_status.read.bits.M95_1 = rv == TRUE ? 1 : 0;
break;
case FAL_EXECUTION_EEPROM_M95_2:
fal_execution_status.read.bits.M95_2 = rv == TRUE ? 1 : 0;
break;
case FAL_EXECUTION_EEPROM_FM24:
fal_execution_status.read.bits.FM24 = rv == TRUE ? 1 : 0;
break;
default:
DBG_ASSERT(FALSE __DBG_LINE);
break;
}
return rv;
}
/**
* @brief 向指定的 KV 存储中写入一个键值对。
*
* @param key 要写入 KV 存储的键。
* @param data 要写入 KV 存储的数据。
* @param length 要写入 KV 存储的数据长度。
*
* @return true 如果写入操作成功false 否则。
*
* @note 此函数将向指定的键在 KV 存储中写入一个键值对。首先,它将检查给定的键是否与任何预定义的键匹配,如果是,则将相应的执行结构分配给 'p' 变量。然后,它调用 fdb_kv_set_blob() 函数将数据写入 KV 存储并返回结果。如果给定的键不与任何预定义的键匹配,则断言条件为 false 并返回 false。
*/
BOOL fal_execution_kv_write(const fal_key_e key, const uint8_t *const data, const uint16_t length)
{
DBG_ASSERT(FAL_KV_KEY[key] != NULL __DBG_LINE);
BOOL rv = FALSE;
struct fdb_blob blob;
fdb_err_t res = FDB_NO_ERR;
fal_execution_t *p = fal_execution_get(key);
if (p == NULL)
{
return FALSE;
}
res = fdb_kv_set_blob(&p->kvdb, FAL_KV_KEY[key], fdb_blob_make(&blob, data, length));
if (res == FDB_NO_ERR)
{
fal_execution_set_crc((uint8_t)key, data, length); // 数据的CRC计算
fal_execution_set_cmac((uint8_t)key, data, length); // 数据的CMAC计算
rv = TRUE;
}
else
{
rv = FALSE;
}
switch (p->eeprom_index)
{
case FAL_EXECUTION_EEPROM_M95_1:
fal_execution_status.read.bits.M95_1 = rv == TRUE ? 1 : 0;
break;
case FAL_EXECUTION_EEPROM_M95_2:
fal_execution_status.read.bits.M95_2 = rv == TRUE ? 1 : 0;
break;
case FAL_EXECUTION_EEPROM_FM24:
fal_execution_status.read.bits.FM24 = rv == TRUE ? 1 : 0;
break;
default:
DBG_ASSERT(FALSE __DBG_LINE);
break;
}
return rv;
}
/**
* @brief 获取fal执行状态
* @param {fal_execution_e} index
* @return {*}
* @note
*/
BOOL fal_execution_status_get(fal_execution_e index)
{
BOOL init = FALSE;
BOOL read = FALSE;
BOOL write = FALSE;
switch (index)
{
case FAL_EXECUTION_EEPROM_M95_1:
init = fal_execution_status.init.bits.M95_1 == 1 ? TRUE : FALSE;
read = fal_execution_status.read.bits.M95_1 == 1 ? TRUE : FALSE;
write = fal_execution_status.write.bits.M95_1 == 1 ? TRUE : FALSE;
break;
case FAL_EXECUTION_EEPROM_M95_2:
init = fal_execution_status.init.bits.M95_2 == 1 ? TRUE : FALSE;
read = fal_execution_status.read.bits.M95_2 == 1 ? TRUE : FALSE;
write = fal_execution_status.write.bits.M95_2 == 1 ? TRUE : FALSE;
break;
case FAL_EXECUTION_EEPROM_FM24:
init = fal_execution_status.init.bits.FM24 == 1 ? TRUE : FALSE;
read = fal_execution_status.read.bits.FM24 == 1 ? TRUE : FALSE;
write = fal_execution_status.write.bits.FM24 == 1 ? TRUE : FALSE;
break;
default:
DBG_ASSERT(FALSE __DBG_LINE);
break;
}
return init && read && write;
}
/**
* @brief 设置fal执行状态
* @param {fal_execution_e} index
* @return {*}
* @note
*/
void fal_execution_status_set(fal_execution_e index, BOOL status)
{
switch (index)
{
case FAL_EXECUTION_EEPROM_M95_1:
fal_execution_status.init.bits.M95_1 = status;
fal_execution_status.read.bits.M95_1 = status;
fal_execution_status.write.bits.M95_1 = status;
break;
case FAL_EXECUTION_EEPROM_M95_2:
fal_execution_status.init.bits.M95_2 = status;
fal_execution_status.read.bits.M95_2 = status;
fal_execution_status.write.bits.M95_2 = status;
break;
case FAL_EXECUTION_EEPROM_FM24:
fal_execution_status.init.bits.FM24 = status;
fal_execution_status.read.bits.FM24 = status;
fal_execution_status.write.bits.FM24 = status;
break;
default:
DBG_ASSERT(FALSE __DBG_LINE);
break;
}
}
#if FAL_DBG_ENABLE
// 测试
static void fal_execution_inspection_test(void)
{
if (FALSE == fal_execution_kv_write(KEY_CALIBPARA_PARAM, (uint8_t *)&calib_param, (CALIBPARA_NUM * sizeof(calib_param_t))))
{
fal_execution_status.write.bits.M95_1 = 0;
}
else
{
fal_execution_status.write.bits.M95_1 = 1;
}
if (FALSE == fal_execution_kv_write(KEY_DEVICE, (uint8_t *)&udevice, sizeof(device_typedef)))
{
fal_execution_status.write.bits.M95_1 = 0;
}
else
{
fal_execution_status.write.bits.M95_1 = 1;
}
if (FALSE == fal_execution_kv_write(KEY_HART_DEVICE_VARIABLE_PARAM, (uint8_t *)hart_storage_variable, sizeof(hart_storage_variable_t)))
{
fal_execution_status.write.bits.M95_1 = 0;
}
else
{
fal_execution_status.write.bits.M95_1 = 1;
}
for (uint8_t i = 0; i < 10; i++)
{
get_timestamp((uDateTime_TypeDef *)&rt_data.save.real_time);
if (FALSE == fal_execution_kv_write(KEY_REAL_TIME_DATA, (uint8_t *)&rt_data.save, sizeof(rt_save_param_t)))
{
fal_execution_status.write.bits.FM24 = 0;
}
else
{
fal_execution_status.write.bits.FM24 = 1;
}
}
}
#endif
void fal_execution_inspection(uint16_t cycle)
{
#if FAL_DBG_ENABLE
fal_execution_inspection_test();
#else
if (fal_execution_status.init.bits.M95_1 == 1) // M95_1初始化成功,才执行下面的操作
{
// 校准参数
{
if (FALSE == fal_execution_data_storage_check(KEY_CALIBPARA_PARAM, (uint8_t *)&calib_param, (CALIBPARA_NUM * sizeof(calib_param_t))))
{
if (FALSE == fal_execution_kv_write(KEY_CALIBPARA_PARAM, (uint8_t *)&calib_param, (CALIBPARA_NUM * sizeof(calib_param_t))))
{
fal_execution_status.write.bits.M95_1 = 0;
}
else
{
fal_execution_status.write.bits.M95_1 = 1;
}
return; // 退出
}
}
// 设备参数
{
if (FALSE == fal_execution_data_storage_check(KEY_DEVICE, (uint8_t *)&udevice, sizeof(device_typedef)))
{
if (FALSE == fal_execution_kv_write(KEY_DEVICE, (uint8_t *)&udevice, sizeof(device_typedef)))
{
fal_execution_status.write.bits.M95_1 = 0;
}
else
{
fal_execution_status.write.bits.M95_1 = 1;
}
return; // 退出
}
}
}
if (fal_execution_status.init.bits.FM24 == 1) // FM24初始化成功,才执行下面的操作
{
// 实时数据
static uint16_t rtdata_cnt = 0;
rtdata_cnt++;
uint32_t save_cycle = udevice.save_cycle * 1000; // ms
uint16_t save_cnt = save_cycle / cycle;
if (rtdata_cnt >= save_cnt)
{
rtdata_cnt = 0;
if (FALSE == fal_execution_data_storage_check(KEY_REAL_TIME_DATA, (uint8_t *)&rt_data.save, sizeof(rt_save_param_t)))
{
get_timestamp((uDateTime_TypeDef *)&rt_data.save.real_time);
if (FALSE == fal_execution_kv_write(KEY_REAL_TIME_DATA, (uint8_t *)&rt_data.save, sizeof(rt_save_param_t)))
{
fal_execution_status.write.bits.FM24 = 0;
}
else
{
fal_execution_status.write.bits.FM24 = 1;
}
return; // 退出
}
}
}
#endif
}