204 lines
8.4 KiB
C++
204 lines
8.4 KiB
C++
|
|
#include "VrConfig.h"
|
||
|
|
#include <iostream>
|
||
|
|
#include <vector>
|
||
|
|
#include <string>
|
||
|
|
|
||
|
|
#include "VrLog.h"
|
||
|
|
|
||
|
|
using namespace tinyxml2;
|
||
|
|
|
||
|
|
CVrConfig::CVrConfig() : m_pNotify(nullptr)
|
||
|
|
{
|
||
|
|
// 构造函数
|
||
|
|
}
|
||
|
|
|
||
|
|
CVrConfig::~CVrConfig()
|
||
|
|
{
|
||
|
|
// 析构函数
|
||
|
|
}
|
||
|
|
|
||
|
|
int CVrConfig::LoadConfig(const std::string& filePath, ConfigResult& configResult)
|
||
|
|
{
|
||
|
|
// 使用tinyxml2库加载XML文件
|
||
|
|
XMLDocument doc;
|
||
|
|
XMLError err = doc.LoadFile(filePath.c_str());
|
||
|
|
if (err != XML_SUCCESS)
|
||
|
|
{
|
||
|
|
LOG_ERR("Failed to open config file: %s\n", filePath.c_str());
|
||
|
|
return LOAD_CONFIG_FILE_NOT_FOUND;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取根元素
|
||
|
|
XMLElement* root = doc.RootElement();
|
||
|
|
if (!root || std::string(root->Name()) != "WorkpieceProjectConfig")
|
||
|
|
{
|
||
|
|
LOG_ERR("Config file format error: root element is not WorkpieceProjectConfig\n");
|
||
|
|
return LOAD_CONFIG_INVALID_FORMAT;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 1. 解析 BinocularMark 客户端配置
|
||
|
|
XMLElement* binocularMarkElement = root->FirstChildElement("BinocularMark");
|
||
|
|
if (binocularMarkElement)
|
||
|
|
{
|
||
|
|
if (binocularMarkElement->Attribute("serverIP"))
|
||
|
|
configResult.binocularMarkConfig.serverIP = binocularMarkElement->Attribute("serverIP");
|
||
|
|
|
||
|
|
binocularMarkElement->QueryIntAttribute("serverPort", &configResult.binocularMarkConfig.serverPort);
|
||
|
|
binocularMarkElement->QueryIntAttribute("reconnectInterval", &configResult.binocularMarkConfig.reconnectInterval);
|
||
|
|
binocularMarkElement->QueryIntAttribute("heartbeatInterval", &configResult.binocularMarkConfig.heartbeatInterval);
|
||
|
|
|
||
|
|
LOG_INFO("BinocularMark config: IP=%s, Port=%d\n",
|
||
|
|
configResult.binocularMarkConfig.serverIP.c_str(),
|
||
|
|
configResult.binocularMarkConfig.serverPort);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. 解析 EpicEyeDevice 列表(仅 WorkpiecePositionApp 需要)
|
||
|
|
XMLElement* epicEyeDevicesElement = root->FirstChildElement("EpicEyeDevices");
|
||
|
|
if (epicEyeDevicesElement)
|
||
|
|
{
|
||
|
|
configResult.epicEyeDeviceList.clear();
|
||
|
|
XMLElement* deviceElement = epicEyeDevicesElement->FirstChildElement("Device");
|
||
|
|
while (deviceElement)
|
||
|
|
{
|
||
|
|
DeviceInfo device;
|
||
|
|
if (deviceElement->Attribute("name"))
|
||
|
|
device.name = deviceElement->Attribute("name");
|
||
|
|
|
||
|
|
if (deviceElement->Attribute("ip"))
|
||
|
|
device.ip = deviceElement->Attribute("ip");
|
||
|
|
|
||
|
|
deviceElement->QueryIntAttribute("index", &device.index);
|
||
|
|
|
||
|
|
configResult.epicEyeDeviceList.push_back(device);
|
||
|
|
LOG_INFO("EpicEye Device: name=%s, ip=%s, index=%d\n",
|
||
|
|
device.name.c_str(), device.ip.c_str(), device.index);
|
||
|
|
|
||
|
|
deviceElement = deviceElement->NextSiblingElement("Device");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. 解析调试参数
|
||
|
|
XMLElement* debugElement = root->FirstChildElement("Debug");
|
||
|
|
if (debugElement)
|
||
|
|
{
|
||
|
|
debugElement->QueryBoolAttribute("enableDebug", &configResult.debugParam.enableDebug);
|
||
|
|
debugElement->QueryBoolAttribute("saveDebugImage", &configResult.debugParam.saveDebugImage);
|
||
|
|
debugElement->QueryBoolAttribute("savePointCloud", &configResult.debugParam.savePointCloud);
|
||
|
|
debugElement->QueryBoolAttribute("printDetailLog", &configResult.debugParam.printDetailLog);
|
||
|
|
|
||
|
|
if (debugElement->Attribute("debugOutputPath"))
|
||
|
|
configResult.debugParam.debugOutputPath = debugElement->Attribute("debugOutputPath");
|
||
|
|
|
||
|
|
LOG_INFO("Debug config: enableDebug=%d, saveDebugImage=%d, savePointCloud=%d, debugOutputPath=%s\n",
|
||
|
|
configResult.debugParam.enableDebug,
|
||
|
|
configResult.debugParam.saveDebugImage,
|
||
|
|
configResult.debugParam.savePointCloud,
|
||
|
|
configResult.debugParam.debugOutputPath.c_str());
|
||
|
|
}
|
||
|
|
|
||
|
|
// 4. 解析串口配置(可选,用于机械臂通信)
|
||
|
|
XMLElement* serialElement = root->FirstChildElement("Serial");
|
||
|
|
if (serialElement)
|
||
|
|
{
|
||
|
|
if (serialElement->Attribute("portName"))
|
||
|
|
configResult.serialConfig.portName = serialElement->Attribute("portName");
|
||
|
|
|
||
|
|
serialElement->QueryIntAttribute("baudRate", &configResult.serialConfig.baudRate);
|
||
|
|
serialElement->QueryIntAttribute("dataBits", &configResult.serialConfig.dataBits);
|
||
|
|
serialElement->QueryIntAttribute("stopBits", &configResult.serialConfig.stopBits);
|
||
|
|
serialElement->QueryIntAttribute("parity", &configResult.serialConfig.parity);
|
||
|
|
serialElement->QueryIntAttribute("flowControl", &configResult.serialConfig.flowControl);
|
||
|
|
serialElement->QueryBoolAttribute("enabled", &configResult.serialConfig.enabled);
|
||
|
|
|
||
|
|
LOG_INFO("Serial config: port=%s, baudRate=%d\n",
|
||
|
|
configResult.serialConfig.portName.c_str(),
|
||
|
|
configResult.serialConfig.baudRate);
|
||
|
|
}
|
||
|
|
|
||
|
|
LOG_INFO("Config loaded successfully from: %s\n", filePath.c_str());
|
||
|
|
return LOAD_CONFIG_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CVrConfig::SaveConfig(const std::string& filePath, ConfigResult& configResult)
|
||
|
|
{
|
||
|
|
XMLDocument doc;
|
||
|
|
|
||
|
|
// 创建 XML 声明
|
||
|
|
XMLDeclaration* declaration = doc.NewDeclaration();
|
||
|
|
doc.InsertFirstChild(declaration);
|
||
|
|
|
||
|
|
// 创建根元素
|
||
|
|
XMLElement* root = doc.NewElement("WorkpieceProjectConfig");
|
||
|
|
doc.InsertEndChild(root);
|
||
|
|
|
||
|
|
// 1. 保存 BinocularMark 客户端配置
|
||
|
|
XMLElement* binocularMarkElement = doc.NewElement("BinocularMark");
|
||
|
|
binocularMarkElement->SetAttribute("serverIP", configResult.binocularMarkConfig.serverIP.c_str());
|
||
|
|
binocularMarkElement->SetAttribute("serverPort", configResult.binocularMarkConfig.serverPort);
|
||
|
|
binocularMarkElement->SetAttribute("reconnectInterval", configResult.binocularMarkConfig.reconnectInterval);
|
||
|
|
binocularMarkElement->SetAttribute("heartbeatInterval", configResult.binocularMarkConfig.heartbeatInterval);
|
||
|
|
root->InsertEndChild(binocularMarkElement);
|
||
|
|
|
||
|
|
// 2. 保存 EpicEyeDevice 列表
|
||
|
|
if (!configResult.epicEyeDeviceList.empty())
|
||
|
|
{
|
||
|
|
XMLElement* epicEyeDevicesElement = doc.NewElement("EpicEyeDevices");
|
||
|
|
for (const auto& device : configResult.epicEyeDeviceList)
|
||
|
|
{
|
||
|
|
XMLElement* deviceElement = doc.NewElement("Device");
|
||
|
|
deviceElement->SetAttribute("name", device.name.c_str());
|
||
|
|
deviceElement->SetAttribute("ip", device.ip.c_str());
|
||
|
|
deviceElement->SetAttribute("index", device.index);
|
||
|
|
epicEyeDevicesElement->InsertEndChild(deviceElement);
|
||
|
|
}
|
||
|
|
root->InsertEndChild(epicEyeDevicesElement);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. 保存调试参数
|
||
|
|
XMLElement* debugElement = doc.NewElement("Debug");
|
||
|
|
debugElement->SetAttribute("enableDebug", configResult.debugParam.enableDebug);
|
||
|
|
debugElement->SetAttribute("saveDebugImage", configResult.debugParam.saveDebugImage);
|
||
|
|
debugElement->SetAttribute("savePointCloud", configResult.debugParam.savePointCloud);
|
||
|
|
debugElement->SetAttribute("printDetailLog", configResult.debugParam.printDetailLog);
|
||
|
|
debugElement->SetAttribute("debugOutputPath", configResult.debugParam.debugOutputPath.c_str());
|
||
|
|
root->InsertEndChild(debugElement);
|
||
|
|
|
||
|
|
// 4. 保存串口配置
|
||
|
|
XMLElement* serialElement = doc.NewElement("Serial");
|
||
|
|
serialElement->SetAttribute("portName", configResult.serialConfig.portName.c_str());
|
||
|
|
serialElement->SetAttribute("baudRate", configResult.serialConfig.baudRate);
|
||
|
|
serialElement->SetAttribute("dataBits", configResult.serialConfig.dataBits);
|
||
|
|
serialElement->SetAttribute("stopBits", configResult.serialConfig.stopBits);
|
||
|
|
serialElement->SetAttribute("parity", configResult.serialConfig.parity);
|
||
|
|
serialElement->SetAttribute("flowControl", configResult.serialConfig.flowControl);
|
||
|
|
serialElement->SetAttribute("enabled", configResult.serialConfig.enabled);
|
||
|
|
root->InsertEndChild(serialElement);
|
||
|
|
|
||
|
|
// 保存到文件
|
||
|
|
XMLError err = doc.SaveFile(filePath.c_str());
|
||
|
|
if (err != XML_SUCCESS)
|
||
|
|
{
|
||
|
|
LOG_ERR("Failed to save config file: %s\n", filePath.c_str());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
LOG_INFO("Config saved successfully to: %s\n", filePath.c_str());
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CVrConfig::SetConfigChangeNotify(IVrConfigChangeNotify* notify)
|
||
|
|
{
|
||
|
|
m_pNotify = notify;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IVrConfig::CreateInstance(IVrConfig** ppVrConfig)
|
||
|
|
{
|
||
|
|
if (ppVrConfig == nullptr)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*ppVrConfig = new CVrConfig();
|
||
|
|
return true;
|
||
|
|
}
|