#include "DataCenter.h" #include #include #include DataCenter* DataCenter::m_instance = nullptr; // 初始化为空 QMutex DataCenter::m_mutex; // 初始化互斥锁 QStringList InitNodeId; // 私有构造函数(原有逻辑不变,仅参数由外部传入改为单例获取) DataCenter::DataCenter(OpcUaManager *opcManager, QObject *parent) : QObject(parent) , m_opcManager(opcManager) , m_cyclicTimer(new QTimer(this)) , m_currentReadIndex(0) { Q_ASSERT(opcManager != nullptr); // 确保OPC管理器有效(单例场景下不会为空) connect(m_cyclicTimer, &QTimer::timeout, this, &DataCenter::onTimerTimeout); connect(m_opcManager, &OpcUaManager::readCompleted, this, &DataCenter::handleReadCompleted); connect(m_opcManager, &OpcUaManager::errorOccurred, this, &DataCenter::errorOccurred); connect(m_opcManager, &OpcUaManager::reconnected, this, &DataCenter::refreshAllNodes); } // ===================== 新增:实现单例全局获取接口 ===================== DataCenter* DataCenter::instance(QObject *parent) { if (!m_instance) { QMutexLocker locker(&m_mutex); if (!m_instance) { // 关联 OpcUaManager 单例(确保 DataCenter 依赖的 OPC 实例唯一) OpcUaManager* opc = OpcUaManager::instance(parent); m_instance = new DataCenter(opc, parent); } } return m_instance; } // void DataCenter::InitData(){ QList FileDataInit = ConfigFiles().ReadFile_Csv("./ProgramConfig/OpcUA_初始化读取节点_配置.csv"); for (int row = 1; row < FileDataInit.size()-1; ++row) { addMonitoredNode(FileDataInit.at(row)[3], FileDataInit.at(row)[0],FileDataInit.at(row)[2],FileDataInit.at(row)[1],FileDataInit.at(row)[2]); InitNodeId.append(FileDataInit.at(row)[3]); } QList FileData = ConfigFiles().ReadFile_Csv("./ProgramConfig/OpcUA_循环读取节点_配置.csv"); for (int row = 1; row < FileData.size()-1; ++row) { addMonitoredNode(FileData.at(row)[3], FileData.at(row)[0],FileData.at(row)[2],FileData.at(row)[1],FileData.at(row)[2]); } } // 添加监控节点(仅数据层操作,不涉及UI) void DataCenter::addMonitoredNode(const QString &nodeId, const QString &nodeName,const QString &varName,const QString &TableName,const QString &FieldName) { if (gOPC_NodeName.contains(nodeId)) { qWarning() << "节点已存在:" << nodeId; return; }else{ } QString NName = nodeName.isEmpty() ? nodeId : nodeName; QString VName = varName.isEmpty() ? nodeId : varName; gOPC_NodeName[nodeId] = NName; gOPC_VarName[nodeId] = VName; gOPC_SqlTable[nodeId] = TableName; gOPC_SqlField[nodeId] = FieldName; gOPC_NodeList.append(nodeId); gOPC_NodeValue[nodeId] = QVariant(); // 初始化值 } void DataCenter::browseRecursive(const QString &nodeId) { doBrowse(nodeId, 6, ""); } void DataCenter::doBrowse(const QString &nodeId, int depth, QString prefix) { //() << "正在浏览节点:" << nodeId << ",深度:" << depth; if (!m_opcManager->getClient() || m_opcManager->getClient()->state() != QOpcUaClient::Connected) { qDebug() << "客户端未连接"; return; } /* 只要命中 ns=6 全局变量就输出并返回,不再递归 */ if (nodeId.startsWith("ns=6;s=::", Qt::CaseInsensitive) && !nodeId.contains("#")) { addMonitoredNode(nodeId,"","","",""); //return; // 关键:到此为止 } QOpcUaNode *node = m_opcManager->getClient()->node(nodeId); if (!node) { return; } /* 继续浏览子节点 */ connect(node, &QOpcUaNode::browseFinished, this, [this, depth, prefix](QVector refs, QOpcUa::UaStatusCode status){ if (status != QOpcUa::UaStatusCode::Good) { qDebug() << "浏览失败,状态码:" << status; return; } if (refs.isEmpty()) { //qDebug() <browseChildren(QOpcUa::ReferenceTypeId::HierarchicalReferences, QOpcUa::NodeClass::Undefined); } // 开始循环读取(纯数据操作) void DataCenter::startCyclicRead(int intervalMs) { if (gOPC_NodeList.isEmpty()) { emit errorOccurred("没有需要监控的节点,请先添加节点"); return; } int actualInterval = qMax(intervalMs, 1); // 最小间隔100ms m_cyclicTimer->stop(); // <-- 关键:先停 m_cyclicTimer->start(actualInterval); // <-- 再启 m_currentReadIndex = 0; } // 停止循环读取 void DataCenter::stopCyclicRead() { m_cyclicTimer->stop(); } void DataCenter::refreshAllNodes() { if (gOPC_NodeList.isEmpty()) return; // 重置索引 m_currentReadIndex = 0; // 如果定时器没开,重新启动它 if (!m_cyclicTimer->isActive()) { m_cyclicTimer->start(); // 使用之前设置的间隔 } // 立即触发一次读取(可选) onTimerTimeout(); } // 通过节点ID获取值 QVariant DataCenter::getNodeValue(const QString &nodeId) const { return gOPC_NodeValue.value(nodeId, QVariant()); } // 通过节点名称获取值 QVariant DataCenter::getNodeValueByName(const QString &nodeName) const { for (auto it = gOPC_NodeName.constBegin(); it != gOPC_NodeName.constEnd(); ++it) { if (it.value() == nodeName) { return gOPC_NodeValue.value(it.key(), QVariant()); } } return QVariant(); } // 定时器触发,循环读取下一个节点(纯数据逻辑) void DataCenter::onTimerTimeout() { if (gOPC_NodeList.isEmpty()) return; // 循环索引处理 if (m_currentReadIndex >= gOPC_NodeList.size()) { m_currentReadIndex = 0; } // 读取当前节点(仅数据操作) QString nodeId = gOPC_NodeList[m_currentReadIndex]; if (!m_opcManager->readNodeValue(nodeId)) { emit errorOccurred("读取节点失败: " + nodeId); } m_currentReadIndex++; // 无论成功与否都移动到下一个 //qDebug()<