#include "VrBeltTearingConfig.h" #include "IVrBeltTearingConfig.h" #include #include #include "VrLog.h" #include #include #include #include #include #include VrBeltTearingConfig::VrBeltTearingConfig() : m_notify(nullptr) { } VrBeltTearingConfig::~VrBeltTearingConfig() { } // Also add the static CreateInstance method to the interface class bool IVrBeltTearingConfig::CreateInstance(IVrBeltTearingConfig** ppVrConfig) { if (!ppVrConfig) { return false; } *ppVrConfig = new VrBeltTearingConfig(); return true; } BeltTearingConfigResult VrBeltTearingConfig::LoadConfig(const std::string& filePath) { BeltTearingConfigResult result; // 使用QString处理可能包含中文的路径 QString qFilePath = QString::fromStdString(filePath); QFile file(qFilePath); // 检查文件是否存在并可读 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { LOG_DEBUG("Failed to open file: %s\n", filePath.c_str()); return result; } // 使用QXmlStreamReader解析XML内容 QXmlStreamReader xml(&file); // 读取到根元素 if (xml.readNextStartElement()) { if (xml.name() != "BeltTearingConfig") { xml.raiseError(QObject::tr("Not a BeltTearingConfig file")); } } else { xml.raiseError(QObject::tr("Failed to read root element")); } // 解析XML内容 while (!xml.atEnd() && !xml.hasError()) { xml.readNext(); // 解析服务器配置 if (xml.isStartElement() && xml.name() == "ClientServers") { while (xml.readNextStartElement()) { if (xml.name() == "Server") { ServerInfo server; server.name = xml.attributes().value("name").toString().toStdString(); server.ip = xml.attributes().value("ip").toString().toStdString(); server.port = xml.attributes().value("port").toInt(); result.servers.push_back(server); xml.skipCurrentElement(); } } } // 解析算法参数 else if (xml.isStartElement() && xml.name() == "AlgorithmParams") { while (xml.readNextStartElement()) { // 皮带撕裂参数 if (xml.name() == "BeltTearingParam") { // 读取简化的SDK兼容参数 result.algorithmParams.beltTearingParam.scanXScale = xml.attributes().value("ScanXScale").toDouble(); result.algorithmParams.beltTearingParam.scanYScale = xml.attributes().value("ScanYScale").toDouble(); result.algorithmParams.beltTearingParam.differnceBinTh = xml.attributes().value("DiffernceBinTh").toDouble(); result.algorithmParams.beltTearingParam.tearingMinLen = xml.attributes().value("TearingMinLen").toDouble(); result.algorithmParams.beltTearingParam.tearingMinGap = xml.attributes().value("TearingMinGap").toDouble(); result.algorithmParams.beltTearingParam.sameGapTh = xml.attributes().value("SameGapTh").toDouble(); result.algorithmParams.beltTearingParam.gapChkWin = xml.attributes().value("GapChkWin").toInt(); // 设置默认值(如果参数不存在) if (result.algorithmParams.beltTearingParam.scanXScale == 0.0) { result.algorithmParams.beltTearingParam.scanXScale = 1.0; } if (result.algorithmParams.beltTearingParam.scanYScale == 0.0) { result.algorithmParams.beltTearingParam.scanYScale = 1.0; } if (result.algorithmParams.beltTearingParam.differnceBinTh == 0.0) { result.algorithmParams.beltTearingParam.differnceBinTh = 1.0; } if (result.algorithmParams.beltTearingParam.tearingMinLen == 0.0) { result.algorithmParams.beltTearingParam.tearingMinLen = 5.0; } if (result.algorithmParams.beltTearingParam.tearingMinGap == 0.0) { result.algorithmParams.beltTearingParam.tearingMinGap = 2.0; } if (result.algorithmParams.beltTearingParam.sameGapTh == 0.0) { result.algorithmParams.beltTearingParam.sameGapTh = 2.0; } if (result.algorithmParams.beltTearingParam.gapChkWin == 0) { result.algorithmParams.beltTearingParam.gapChkWin = 5; } xml.skipCurrentElement(); } // 监控参数 else if (xml.name() == "MonitoringParam") { result.algorithmParams.monitoringParam.checkInterval = xml.attributes().value("CheckInterval").toInt(); result.algorithmParams.monitoringParam.alertThreshold = xml.attributes().value("AlertThreshold").toDouble(); // 向后兼容:忽略不再使用的参数 // maxHistorySize 已移除,不再读取 xml.skipCurrentElement(); } // 跳过不再使用的图像处理参数 else if (xml.name() == "ImageProcessingParam") { // 向后兼容:跳过图像处理参数,不再使用 xml.skipCurrentElement(); } else { xml.skipCurrentElement(); } } } // 解析调试参数 else if (xml.isStartElement() && xml.name() == "DebugParam") { result.debugParam.enableDebug = xml.attributes().value("enableDebug").toInt(); result.debugParam.saveDebugImage = xml.attributes().value("saveDebugImage").toInt(); result.debugParam.printDetailLog = xml.attributes().value("printDetailLog").toInt(); result.debugParam.debugOutputPath = xml.attributes().value("debugOutputPath").toString().toStdString(); xml.skipCurrentElement(); } // 解析队列处理参数 else if (xml.isStartElement() && xml.name() == "QueueProcessParam") { int maxQueueSize = xml.attributes().value("maxQueueSize").toInt(); int generationInterval = xml.attributes().value("generationInterval").toInt(); // 设置默认值(如果参数不存在或为0) result.queueProcessParam.maxQueueSize = (maxQueueSize > 0) ? maxQueueSize : 300; result.queueProcessParam.generationInterval = (generationInterval > 0) ? generationInterval : 100; xml.skipCurrentElement(); } // 解析项目类型 else if (xml.isStartElement() && xml.name() == "ProjectType") { QString typeStr = xml.attributes().value("type").toString(); if (typeStr == "BeltMonitoring") { result.projectType = BeltTearingProjectType::BeltMonitoring; } else { result.projectType = BeltTearingProjectType::BeltTearing; } xml.skipCurrentElement(); } // 解析服务端配置 else if (xml.isStartElement() && xml.name() == "LocalServerConfig") { while (xml.readNextStartElement()) { if (xml.name() == "ServerPort") { result.serverPort = xml.attributes().value("port").toInt(); xml.skipCurrentElement(); } else if (xml.name() == "TcpPort") { result.tcpPort = xml.attributes().value("port").toInt(); if (result.tcpPort == 0) { result.tcpPort = 5901; // 默认值 } xml.skipCurrentElement(); } else if (xml.name() == "ModbusTCPProtocol") { // 解析ModbusTCP协议类型,默认为简化协议 QString protocolStr = xml.attributes().value("type").toString().toLower(); if (protocolStr == "standard") { result.modbusTCPProtocol = ModbusTCPProtocolType::Standard; } else { result.modbusTCPProtocol = ModbusTCPProtocolType::Simplified; // 默认简化协议 } xml.skipCurrentElement(); } else { xml.skipCurrentElement(); } } } // 解析相机配置 else if (xml.isStartElement() && xml.name() == "Cameras") { while (xml.readNextStartElement()) { if (xml.name() == "Camera") { CameraParam camera; camera.name = xml.attributes().value("name").toString().toStdString(); camera.cameraIP = xml.attributes().value("ip").toString().toStdString(); result.cameras.push_back(camera); xml.skipCurrentElement(); } } } // 解析串口配置(用于 Modbus RTU) else if (xml.isStartElement() && xml.name() == "SerialPort") { QString portName = xml.attributes().value("portName").toString(); int baudRate = xml.attributes().value("baudRate").toInt(); QString parity = xml.attributes().value("parity").toString(); int dataBits = xml.attributes().value("dataBits").toInt(); int stopBits = xml.attributes().value("stopBits").toInt(); // 如果配置文件中有串口配置,则使用配置值 if (!portName.isEmpty()) { result.serialPortParam.portName = portName.toStdString(); } if (baudRate > 0) { result.serialPortParam.baudRate = baudRate; } if (!parity.isEmpty() && parity.length() > 0) { result.serialPortParam.parity = parity.at(0).toLatin1(); } if (dataBits > 0) { result.serialPortParam.dataBits = dataBits; } if (stopBits > 0) { result.serialPortParam.stopBits = stopBits; } xml.skipCurrentElement(); } } file.close(); // 检查解析错误 if (xml.hasError()) { LOG_ERROR("XML parsing error: %s\n", xml.errorString().toStdString().c_str()); return BeltTearingConfigResult(); // 返回空结果 } return result; } bool VrBeltTearingConfig::SaveConfig(const std::string& filePath, BeltTearingConfigResult& configResult) { // 使用QString处理可能包含中文的路径 QString qFilePath = QString::fromStdString(filePath); QFile file(qFilePath); // 打开文件进行写入 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { LOG_DEBUG("Failed to open file for writing: %s\n", filePath.c_str()); return false; } // 使用QXmlStreamWriter写入XML内容 QXmlStreamWriter xml(&file); xml.setAutoFormatting(true); xml.setCodec("UTF-8"); // Explicitly set UTF-8 encoding to handle Chinese characters correctly xml.writeStartDocument(); // 设置编码为UTF-8以正确处理中文 xml.writeStartElement("BeltTearingConfig"); // 保存服务器配置 if (!configResult.servers.empty()) { xml.writeStartElement("ClientServers"); for (const auto& server : configResult.servers) { xml.writeStartElement("Server"); xml.writeAttribute("name", QString::fromStdString(server.name)); xml.writeAttribute("ip", QString::fromStdString(server.ip)); xml.writeAttribute("port", QString::number(server.port)); xml.writeEndElement(); // Server } xml.writeEndElement(); // ClientServers } // 保存算法参数 xml.writeStartElement("AlgorithmParams"); // 皮带撕裂参数 - 简化版本 xml.writeStartElement("BeltTearingParam"); xml.writeAttribute("ScanXScale", QString::number(configResult.algorithmParams.beltTearingParam.scanXScale)); xml.writeAttribute("ScanYScale", QString::number(configResult.algorithmParams.beltTearingParam.scanYScale)); xml.writeAttribute("DiffernceBinTh", QString::number(configResult.algorithmParams.beltTearingParam.differnceBinTh)); xml.writeAttribute("TearingMinLen", QString::number(configResult.algorithmParams.beltTearingParam.tearingMinLen)); xml.writeAttribute("TearingMinGap", QString::number(configResult.algorithmParams.beltTearingParam.tearingMinGap)); xml.writeAttribute("SameGapTh", QString::number(configResult.algorithmParams.beltTearingParam.sameGapTh)); xml.writeAttribute("GapChkWin", QString::number(configResult.algorithmParams.beltTearingParam.gapChkWin)); xml.writeEndElement(); // BeltTearingParam // 监控参数 xml.writeStartElement("MonitoringParam"); xml.writeAttribute("CheckInterval", QString::number(configResult.algorithmParams.monitoringParam.checkInterval)); xml.writeAttribute("AlertThreshold", QString::number(configResult.algorithmParams.monitoringParam.alertThreshold)); xml.writeEndElement(); // MonitoringParam xml.writeEndElement(); // AlgorithmParams // 保存调试参数 xml.writeStartElement("DebugParam"); xml.writeAttribute("enableDebug", QString::number(configResult.debugParam.enableDebug)); xml.writeAttribute("saveDebugImage", QString::number(configResult.debugParam.saveDebugImage)); xml.writeAttribute("printDetailLog", QString::number(configResult.debugParam.printDetailLog)); xml.writeAttribute("debugOutputPath", QString::fromStdString(configResult.debugParam.debugOutputPath)); xml.writeEndElement(); // DebugParam // 保存队列处理参数 xml.writeStartElement("QueueProcessParam"); xml.writeAttribute("maxQueueSize", QString::number(configResult.queueProcessParam.maxQueueSize)); xml.writeAttribute("generationInterval", QString::number(configResult.queueProcessParam.generationInterval)); xml.writeEndElement(); // QueueProcessParam // 保存项目类型 xml.writeStartElement("ProjectType"); QString typeStr = (configResult.projectType == BeltTearingProjectType::BeltMonitoring) ? "BeltMonitoring" : "BeltTearing"; xml.writeAttribute("type", typeStr); xml.writeEndElement(); // ProjectType // 保存服务端配置 xml.writeStartElement("LocalServerConfig"); xml.writeStartElement("ServerPort"); xml.writeAttribute("port", QString::number(configResult.serverPort)); xml.writeEndElement(); // ServerPort xml.writeStartElement("TcpPort"); xml.writeAttribute("port", QString::number(configResult.tcpPort)); xml.writeEndElement(); // TcpPort // 保存ModbusTCP协议类型 xml.writeStartElement("ModbusTCPProtocol"); QString protocolTypeStr = (configResult.modbusTCPProtocol == ModbusTCPProtocolType::Standard) ? "standard" : "simplified"; xml.writeAttribute("type", protocolTypeStr); xml.writeEndElement(); // ModbusTCPProtocol xml.writeEndElement(); // LocalServerConfig // 保存相机配置 xml.writeStartElement("Cameras"); for (const auto& camera : configResult.cameras) { xml.writeStartElement("Camera"); xml.writeAttribute("name", QString::fromStdString(camera.name)); xml.writeAttribute("ip", QString::fromStdString(camera.cameraIP)); xml.writeEndElement(); // Camera } xml.writeEndElement(); // Cameras // 保存串口配置(用于 Modbus RTU) xml.writeStartElement("SerialPort"); xml.writeAttribute("portName", QString::fromStdString(configResult.serialPortParam.portName)); xml.writeAttribute("baudRate", QString::number(configResult.serialPortParam.baudRate)); xml.writeAttribute("parity", QString(QChar(configResult.serialPortParam.parity))); xml.writeAttribute("dataBits", QString::number(configResult.serialPortParam.dataBits)); xml.writeAttribute("stopBits", QString::number(configResult.serialPortParam.stopBits)); xml.writeEndElement(); // SerialPort xml.writeEndElement(); // BeltTearingConfig xml.writeEndDocument(); file.close(); // 通知配置改变 if (m_notify) { m_notify->OnConfigChanged(configResult); } return true; } void VrBeltTearingConfig::SetConfigChangeNotify(IVrBeltTearingConfigChangeNotify* notify) { m_notify = notify; }