381 lines
17 KiB
C++
381 lines
17 KiB
C++
#include "VrBeltTearingConfig.h"
|
||
#include "IVrBeltTearingConfig.h"
|
||
#include <algorithm>
|
||
#include <sstream>
|
||
#include "VrLog.h"
|
||
#include <QFile>
|
||
#include <QTextStream>
|
||
#include <QString>
|
||
#include <QTextCodec>
|
||
#include <QXmlStreamReader>
|
||
#include <QXmlStreamWriter>
|
||
|
||
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;
|
||
}
|