RTU/src/system/libdatacenter/src/dc_param.cpp

343 lines
12 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.

#include "dc_param.h"
#include "tinyxml2.h"
// 中央元数据表(以 saddr 为键,初始化时写入,运行时只读)
static std::unordered_map<std::string, stru_signal_param> g_param_metadata;
void dc_param_metadata_store(const std::string &saddr, const stru_signal_param &param)
{
g_param_metadata[saddr] = param;
}
bool dc_param_metadata_lookup(const std::string &saddr, stru_signal_param &out_param)
{
auto it = g_param_metadata.find(saddr);
if (it != g_param_metadata.end())
{
out_param = it->second;
return true;
}
return false;
}
// 解析 param.xml只提取元数据存入 g_param_metadata不注册信号
static int dc_param_parse_metadata(const std::string &path)
{
using namespace tinyxml2;
XMLDocument doc;
if (XML_SUCCESS != doc.LoadFile(path.c_str()))
{
MY_LOG_E("failed to load param file: %s", path.c_str());
return -1;
}
XMLElement *root = doc.RootElement();
if (nullptr == root)
{
MY_LOG_E("param file has no root element");
return -1;
}
// 解析 Ao 段
XMLElement *ao_elem = root->FirstChildElement("Ao");
if (ao_elem)
{
for (XMLElement *sig = ao_elem->FirstChildElement("Signal"); sig != nullptr;
sig = sig->NextSiblingElement("Signal"))
{
const char *saddr = sig->Attribute("saddr");
if (nullptr == saddr)
{
MY_LOG_E("Ao Signal missing saddr, skipping");
continue;
}
stru_signal_param param;
param.min = sig->FloatAttribute("min", 0.0f);
param.max = sig->FloatAttribute("max", 0.0f);
param.step = sig->FloatAttribute("step", 0.0f);
const char *unit = sig->Attribute("unit");
param.unit = unit ? std::string(unit) : std::string();
g_param_metadata[saddr] = param;
}
}
// 解析 Param 段
XMLElement *param_elem = root->FirstChildElement("Param");
if (param_elem)
{
for (XMLElement *sig = param_elem->FirstChildElement("Signal"); sig != nullptr;
sig = sig->NextSiblingElement("Signal"))
{
const char *saddr = sig->Attribute("saddr");
if (nullptr == saddr)
{
MY_LOG_E("Param Signal missing saddr, skipping");
continue;
}
stru_signal_param param;
param.min = sig->FloatAttribute("min", 0.0f);
param.max = sig->FloatAttribute("max", 0.0f);
param.step = sig->FloatAttribute("step", 0.0f);
const char *unit = sig->Attribute("unit");
param.unit = unit ? std::string(unit) : std::string();
g_param_metadata[saddr] = param;
}
}
return 0;
}
// 从 self_param.xml 加载运行时值,返回 saddr → value字符串 的映射
// Ao段: key=saddr, value="value_attr"
// Param段: key=saddr + "_" + index, value="value_attr"
static std::unordered_map<std::string, std::string> dc_self_param_load(const std::string &path)
{
using namespace tinyxml2;
std::unordered_map<std::string, std::string> values;
XMLDocument doc;
if (XML_SUCCESS != doc.LoadFile(path.c_str()))
return values; // 文件不存在或解析失败,返回空映射
XMLElement *root = doc.RootElement();
if (nullptr == root) return values;
// 加载 Ao 段值
XMLElement *ao_elem = root->FirstChildElement("Ao");
if (ao_elem)
{
for (XMLElement *sig = ao_elem->FirstChildElement("Signal"); sig != nullptr;
sig = sig->NextSiblingElement("Signal"))
{
const char *saddr = sig->Attribute("saddr");
const char *val = sig->Attribute("value");
if (saddr && val)
values[saddr] = std::string(val);
}
}
// 加载 Param 段值
XMLElement *param_elem = root->FirstChildElement("Param");
if (param_elem)
{
for (XMLElement *sig = param_elem->FirstChildElement("Signal"); sig != nullptr;
sig = sig->NextSiblingElement("Signal"))
{
const char *saddr = sig->Attribute("saddr");
if (nullptr == saddr) continue;
for (XMLElement *item = sig->FirstChildElement("Item"); item != nullptr;
item = item->NextSiblingElement("Item"))
{
int index = item->IntAttribute("index", -1);
const char *val = item->Attribute("value");
if (index >= 1 && val)
{
std::string key = std::string(saddr) + "_" + std::to_string(index);
values[key] = std::string(val);
}
}
}
}
return values;
}
// 根据 param.xml 和 self_param.xml 的值生成信号并注册
static int dc_param_register_signals(const std::string &param_path,
const std::unordered_map<std::string, std::string> &self_values)
{
using namespace tinyxml2;
XMLDocument doc;
if (XML_SUCCESS != doc.LoadFile(param_path.c_str()))
{
MY_LOG_E("failed to reload param file: %s", param_path.c_str());
return -1;
}
XMLElement *root = doc.RootElement();
if (nullptr == root)
{
MY_LOG_E("param file has no root element");
return -1;
}
// 注册 Ao 段信号
XMLElement *ao_elem = root->FirstChildElement("Ao");
if (ao_elem)
{
for (XMLElement *sig = ao_elem->FirstChildElement("Signal"); sig != nullptr;
sig = sig->NextSiblingElement("Signal"))
{
const char *saddr = sig->Attribute("saddr");
const char *desc = sig->Attribute("desc");
const char *type_str = sig->Attribute("type");
if (nullptr == saddr || nullptr == desc || nullptr == type_str)
{
MY_LOG_E("Ao Signal missing required attributes, skipping");
continue;
}
uint8_t data_type = dc_get_data_type_id_by_str(type_str);
if (0 == data_type)
{
MY_LOG_E("unknown data type %s for saddr %s", type_str, saddr);
continue;
}
// 默认值始终从 param.xml 读取
const char *default_val = sig->Attribute("default");
// 运行时值:优先使用 self_param.xml 中的值,否则使用 param.xml 的 value 属性
const char *val_attr = sig->Attribute("value");
std::string run_val;
auto it = self_values.find(std::string(saddr));
if (it != self_values.end())
run_val = it->second;
else if (val_attr && strlen(val_attr) > 0)
run_val = std::string(val_attr);
else if (default_val && strlen(default_val) > 0)
run_val = std::string(default_val);
void *p_data = dc_create_data_ptr_by_type(data_type);
if (p_data)
{
if (!run_val.empty())
dc_set_signal_val_from_str(p_data, data_type, run_val);
}
void *p_default_data = dc_create_data_ptr_by_type(data_type);
if (p_default_data)
{
if (default_val && strlen(default_val) > 0)
dc_set_signal_val_from_str(p_default_data, data_type, std::string(default_val));
}
if (p_data && p_default_data)
{
dc_signal_ao(saddr, desc, data_type,
SIGNAL_CTRL_TYPE::SBO_NORMAL,
p_data, p_default_data, nullptr);
}
}
}
// 注册 Param 段信号
XMLElement *param_elem = root->FirstChildElement("Param");
if (param_elem)
{
for (XMLElement *sig = param_elem->FirstChildElement("Signal"); sig != nullptr;
sig = sig->NextSiblingElement("Signal"))
{
const char *saddr = sig->Attribute("saddr");
const char *desc = sig->Attribute("desc");
const char *type_str = sig->Attribute("type");
if (nullptr == saddr || nullptr == desc || nullptr == type_str)
{
MY_LOG_E("Param Signal missing required attributes, skipping");
continue;
}
uint8_t data_type = dc_get_data_type_id_by_str(type_str);
if (0 == data_type)
{
MY_LOG_E("unknown data type %s for saddr %s", type_str, saddr);
continue;
}
int num = sig->IntAttribute("num", -1);
if (num < 1) continue;
std::vector<void *> vec_p_data;
std::vector<void *> vec_p_default_data;
for (XMLElement *item = sig->FirstChildElement("Item"); item != nullptr;
item = item->NextSiblingElement("Item"))
{
int index = item->IntAttribute("index", -1);
const char *default_val = item->Attribute("default");
const char *val_attr = item->Attribute("value");
// 运行时值:优先使用 self_param.xml 中的值
std::string key = std::string(saddr) + "_" + std::to_string(index);
std::string run_val;
auto it = self_values.find(key);
if (it != self_values.end())
run_val = it->second;
else if (val_attr && strlen(val_attr) > 0)
run_val = std::string(val_attr);
else if (default_val && strlen(default_val) > 0)
run_val = std::string(default_val);
void *p_data = dc_create_data_ptr_by_type(data_type);
if (p_data)
{
if (!run_val.empty())
dc_set_signal_val_from_str(p_data, data_type, run_val);
vec_p_data.push_back(p_data);
}
void *p_default_data = dc_create_data_ptr_by_type(data_type);
if (p_default_data)
{
if (default_val && strlen(default_val) > 0)
dc_set_signal_val_from_str(p_default_data, data_type, std::string(default_val));
vec_p_default_data.push_back(p_default_data);
}
}
if (!vec_p_data.empty() && vec_p_data.size() == vec_p_default_data.size())
{
dc_signal_param(saddr, desc, data_type,
SIGNAL_CTRL_TYPE::SBO_NORMAL,
vec_p_data.data(), vec_p_default_data.data(), num, nullptr);
}
}
}
// 首次注册后标记变更,触发 self_param.xml 生成
dc_set_param_cfg_change(true);
return 0;
}
int dc_param_cfg_parse(const std::string &path)
{
// 1. 从 param.xml 提取元数据到 g_param_metadata
if (0 != dc_param_parse_metadata(path))
{
MY_LOG_E("dc_param_parse_metadata failed, path:%s", path.c_str());
return -1;
}
// 2. 构造 self_param.xml 路径
std::string self_path = path;
size_t pos = self_path.rfind("param.xml");
if (pos != std::string::npos)
self_path.replace(pos, 9, "self_param.xml");
else
self_path = path.substr(0, path.rfind('/') + 1) + "self_param.xml";
// 3. 尝试加载 self_param.xml 中的运行时值
std::unordered_map<std::string, std::string> self_values = dc_self_param_load(self_path);
if (!self_values.empty())
MY_LOG_I("loaded %zu saved values from self_param.xml", self_values.size());
else
MY_LOG_I("no self_param.xml found, using default values from param.xml");
// 4. 用合并后的值注册所有信号
if (0 != dc_param_register_signals(path, self_values))
{
MY_LOG_E("dc_param_register_signals failed");
return -1;
}
return 0;
}