Files
EJM_Display/DataCenter/DataCenter - 副本.cpp
2025-09-15 22:28:43 +08:00

218 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "DataCenter.h"
#include <QDebug>
#include <FileOperation/ConfigFiles.h>
#include <PublicFunctions/Basic.h>
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<QStringList> 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<QStringList> 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<QOpcUaReferenceDescription> refs, QOpcUa::UaStatusCode status){
if (status != QOpcUa::UaStatusCode::Good) {
qDebug() << "浏览失败,状态码:" << status;
return;
}
if (refs.isEmpty()) {
//qDebug() <<prefix<< "没有子节点";
return;
}
for (const auto &ref : refs) {
QString childId = ref.targetNodeId().nodeId();
//qDebug() << prefix << "子节点:" << childId;
doBrowse(childId, depth + 1, "└─ ");
}
});
node->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()<<gOPC_NodeList.length()<<gOPC_NodeList;
}
// 处理读取结果并缓存(仅数据处理)
void DataCenter::handleReadCompleted(const QVariant &value, const QString &nodeId)
{
if (!gOPC_NodeName.contains(nodeId)) return;
// 更新缓存值
if(nodeId == "ns=6;s=::AsGlobalPV:CPU_Info.isVirtualCPU"){
// qDebug()<<"读取到变量!"<<nodeId<<InitNodeId.contains(nodeId)<<InitNodeId;
}
gOPC_NodeValue[nodeId] = value;
if (InitNodeId.contains(nodeId)){
InitNodeId.removeOne(nodeId);
gOPC_NodeList.removeOne(nodeId);
}
// 发送更新信号仅传递数据不涉及UI
emit nodeValueUpdated(nodeId, gOPC_NodeName[nodeId],gOPC_VarName[nodeId], value);
// 移动到下一个节点
// if(DC_SetST.funts_SetSysInitOjb(gSysInfo,gOPC_VarName[nodeId],value)) return;
// else if (DC_SetST.funts_SetSysInitOjb(gSysInfo,gOPC_VarName[nodeId],value)) return;
}