/** * @file fal_execution.c * @author xxx * @date 2023-12-29 11:27:55 * @brief * @copyright Copyright (c) 2024 by xxx, All Rights Reserved. */ /** * 存储模块是一个用于存储和读取数据的函数,它使用了 FAL(Flash Abstraction Layer)库来实现。FAL 库是一个用于访问 Flash 存储器的抽象层, 它提供了一组标准的接口,使得应用程序可以方便地访问 Flash 存储器中的数据。在这段代码中,函数 fal_execution_kv_read() 用于从 KV(Key-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 *)×tamp); 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 }