343 lines
12 KiB
C++
343 lines
12 KiB
C++
#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 ¶m)
|
||
{
|
||
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 ¶m_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;
|
||
}
|