#include "VrConfig.h" #include #include #include #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; }