#include "Pou.h" #include "WindowAppItemInterface.h" #include "WindowAppBlockStandard.h" #include "WindowAppBlockStandardBase.h" #include "WindowAppBlockGoto.h" #include "WindowAppBlockWait.h" #include "WindowAppVariableTable.h" #include "GvlManager.h" #include "TaskManager.h" #include "WindowAppTaskView.h" #include "WindowAppPouScene.h" #include "WindowAppPouFrame.h" #include "../Common/CameraBaseClass/IBaseCamCommon.h" #include "../Common/CameraBaseClass/IBaseCamera.h" //====================================================================== // // 与Pou执行相关的函数集合 // //====================================================================== /// /// 2022-9-6,执行前预检查 /// /// /// /// VPEnum::RETURN_VALUE POU::ToolExecutionDispatcherPreCheck(TOOL*& pTool, TOOL_RUN_MODE runMode) { Q_UNUSED(runMode); // 如果本工具加入了并行组,则需要特殊处理一下 if (pTool->isParallelSubTool()) { //// 如果处于并行模式下运行,则等待执行信号 //if (runMode == TOOL_RUN_MODE::IN_PARALLEL) //{ // // 设置Tool为Wait状态 // pTool->execParams.nStatus = VPEnum::EXEC_STATUS::Wait; // vDebug() << "ParallelSubTool [" << pTool->strInstanceName << "] waiting..."; // pTool->waitForExecution(); // vDebug() << "ParallelSubTool [" << pTool->strInstanceName << "] waiting finished."; //} //// 否则,直接跳过执行 //else //{ vDebug() << "Ignore Tool[" + pTool->strInstanceName + "], reason: isParallelized."; return VPEnum::RETURN_VALUE::Abort; //} } // 如果本工具加入了For循环,则跳过执行 else if (pTool->isForloopSubTool()) { vDebug() << "Ignore Tool[" + pTool->strInstanceName + "], reason: isForlooped."; return VPEnum::RETURN_VALUE::Abort; } return VPEnum::RETURN_VALUE::Success; } /// /// 2022-5-1 工具的执行总调度 /// /// /// VPEnum::RETURN_VALUE POU::ToolExecutionDispatcher(TOOL*& pTool, TOOL_RUN_MODE runMode) { VPEnum::RETURN_VALUE ret = VPEnum::RETURN_VALUE::None; // 执行预检查 ret = this->ToolExecutionDispatcherPreCheck(pTool, runMode); if (ret != VPEnum::RETURN_VALUE::Success) { return ret; } // 正常流程 // 设置Tool为Busy状态 pTool->execParams.nStatus = VPEnum::EXEC_STATUS::Busy; // 执行标准工具 if (pTool->isStandardTool()) { ret = this->ToolExecuteStandard(pTool); } // 执行Goto工具 else if (pTool->isGotoTool()) { int nNextIndex = 0; // 执行Goto工具 ret = this->ToolExecuteGoto(pTool, nNextIndex); // TODO:此处是否需要跳转到下一个工具继续执行 if (ret == VPEnum::RETURN_VALUE::Goto) { TOOL* pNextTool = m_StandardTools[nNextIndex]; ret = this->ToolExecuteStandard(pNextTool); } } // 执行并行工具 else if (pTool->isParallelTool()) { ret = this->ToolExecuteParallel(pTool); } // 执行ForLoop工具 else if (pTool->isForloopTool()) { ret = this->ToolExecuteForloop(pTool); } // 执行Wait工具 else if (pTool->isWaitTool()) { ret = this->ToolExecuteWait(pTool, runMode); } else { qDebug() << "[Error] POU::ToolExecute - Unknown tool type:" << (short)pTool->Type; ret = VPEnum::RETURN_VALUE::Error; } // 设置Tool为完成状态 pTool->execParams.nStatus = VPEnum::EXEC_STATUS::Done; return ret; } /// /// 2022-5-1 工具的执行总调度(Task中使用,关联执行序号) /// /// /// /// VPEnum::RETURN_VALUE POU::ToolExecutionDispatcher(TOOL*& pTool, int& index, TOOL_RUN_MODE runMode) { VPEnum::RETURN_VALUE ret = VPEnum::RETURN_VALUE::None; // 执行预检查 ret = this->ToolExecutionDispatcherPreCheck(pTool, runMode); if (ret != VPEnum::RETURN_VALUE::Success) { return ret; } // 设置Tool为Busy状态 pTool->execParams.nStatus = VPEnum::EXEC_STATUS::Busy; // 如果是标准工具,正常执行 if (pTool->isStandardTool()) { ret = this->ToolExecuteStandard(pTool); index++; } // 如果是Goto工具,要做跳转 else if (pTool->isGotoTool()) { // 执行Goto ret = this->ToolExecuteGoto(pTool, index); // 如果执行过程中没有发生跳转,那么继续执行下一个工具 if (ret != VPEnum::RETURN_VALUE::Goto) { index++; } } // 如果是并行工具,则并行执行 else if (pTool->isParallelTool()) { ret = this->ToolExecuteParallel(pTool); index++; } // 如果是For循环工具,则执行For循环 else if (pTool->isForloopTool()) { ret = this->ToolExecuteForloop(pTool); index++; } // 如果是Wait工具,则执行等待 else if (pTool->isWaitTool()) { ret = this->ToolExecuteWait(pTool, runMode); index++; } // 设置Tool为完成状态 pTool->execParams.nStatus = VPEnum::EXEC_STATUS::Done; return ret; } ///// ///// 执行当前工具 ///// ///// //VPEnum::RETURN_VALUE POU::ToolExecuteStandard(WindowAppBlockStandardBase* pBlockItem) //{ // // 重置所有工具执行状态 // ResetToolExecCode(); // // TOOL* pActiveTool = m_itemToTools.value(pBlockItem); // // // 交给调度器执行 // return this->ToolExecutionDispatcher(pActiveTool); //} /// /// 执行当前工具 /// /// VPEnum::RETURN_VALUE POU::ToolExecuteStandard(TOOL* pActiveTool) { VPEnum::RETURN_VALUE nRet = VPEnum::RETURN_VALUE::None; if (pActiveTool == nullptr) { qDebug() << "[Error] [POU:" << m_strPouName << "] ToolExecuteStandard failed: pActiveTool is nullptr."; return VPEnum::RETURN_VALUE::Error; } // Execute前更新上连接口 nRet = this->ToolPreExecute(pActiveTool); // TODO:此处是否需要处理更新上行接口的执行结果 // 然后执行本工具的Execute if (pActiveTool->pDllPtr != nullptr) { nRet = pActiveTool->pDllPtr->Execute(); } else { qDebug() << "[POU:" << m_strPouName << "][Tool:" << pActiveTool->strInstanceName << "] executed finished."; } // 在窗体可见时候,才调用调试窗口。以便在后台运行的时候,提高运行速度 if (this->parentScene()->parentFrame()->isVisible()) { try { DebugData data = pActiveTool->pDllPtr->GetDebugData(); this->parentScene()->parentFrame()->UpdataDebugData(data); } catch (...){ } } // 保存工具执行返回值 pActiveTool->execParams.nRetValue = nRet; // 如果返回值不是成功的话,就需要加一个错误计数(Pou和Tool的都需要+1) if (nRet != VPEnum::RETURN_VALUE::Success) { pActiveTool->execParams.nErrorCount++; this->execParams.nErrorCount++; } // Execute后更新下连接口 /*nRet =*/ this->ToolPostExecute(pActiveTool); //// 根据是否在Task中执行,输出不同的log //if (m_pParentTask == nullptr) //{ qDebug() << "[POU:" << m_strPouName << "][Tool:" << pActiveTool->strInstanceName << "][Index:" << pActiveTool->nIndex << "] executed finished."; //} // 执行完之后,重绘一下此工具,用于功能块的状态显示 WindowAppBlockBase* pBlock = this->m_instNameToToolItems[pActiveTool->strInstanceName]; pBlock->update(); // 执行计数 +1 pActiveTool->execParams.nExecCount++; return nRet; } /// /// Execute前更新上连接口 /// VPEnum::RETURN_VALUE POU::ToolPreExecute(TOOL* pActiveTool) { VPEnum::RETURN_VALUE nRet = VPEnum::RETURN_VALUE::None; // qDebug() << "[POU] Execute tool start ------- " << pActiveTool->strInstanceName; // 先检查一下所有的输入接口 for (_INTERFACE* pInf : pActiveTool->Interfaces) { // 2022-4-30,跳过Tool类型接口(尽管这种情况不会出现,但是以防万一还是加上) if (pInf->isToolInterface()) { continue; } // 如果本接口有link连接的话,需要先到link那边去取值 if (pInf->Direction == INF_DIRECTION::INF_DIR_IN && pInf->pUpLinkInterface != nullptr) { // 从工具Dll中更新值 if (pInf->pUpLinkInterface->Type == INF_TYPE::INF_TYPE_STANDARD) { // 2022-8-26增加,由于标准接口的情况分为两种,一种是dll工具,还有一种是系统内置工具,所以这里要区分一下 // 如果上联工具为标准工具,则从Dll中更新值(这里这里要用realParent,防止Port工具绑定的情况) if (pInf->pUpLinkInterface->realParent()->Type == TOOL_TYPE::TOOL_TYPE_STANDARD) { QString strValueString = updateInterfaceValue(pInf, UPDATE_VALUE_MODE::MODE_FROM_TOOL); if (!strValueString.isEmpty()) { qDebug() << "[POU] updateInterfaceValue from up link dll[" << pInf->strFullName << "], Value:" << strValueString; } else { // return nRet; continue; } } // 2022-8-26 是否应该是内置工具,直接从接口中取值,和变量一样 else { QString strValueString = updateInterfaceValue(pInf, UPDATE_VALUE_MODE::MODE_FROM_VARIABLE); if (!strValueString.isEmpty()) { qDebug() << "[POU] updateInterfaceValue from up link internal[" << pInf->strFullName << "], Value:" << strValueString; } else { // return nRet; continue; } } } // 从变量中更新值 else if (pInf->pUpLinkInterface->Type == INF_TYPE::INF_TYPE_VALUE) { // 判断下上联的端口(全局变量组或者局部变量组)是否存在 TOOL* pGvl = pInf->pUpLinkInterface->bindedParent(); // 如果查询到了对应的变量组 if (pGvl != nullptr) { QString strValueString = updateInterfaceValue(pInf, UPDATE_VALUE_MODE::MODE_FROM_VARIABLE); if (!strValueString.isEmpty()) { qDebug() << "[POU] updateInterfaceValue from up link variable[" << pInf->strFullName << "], Value:" << strValueString; } else { // return nRet; continue; } } // 没查询到对应的全局变量或局部变量 else { // 把端口的状态设置为Error TOOL* pPort = pInf->pUpLinkInterface->parent(); if (pPort != nullptr) { pPort->setPortError(); } QString strErrorMsg = pInf->pUpLinkInterface->strName + " ----------->" + pActiveTool->strInstanceName + "." + pInf->strName; qWarning() << strErrorMsg << "Error"; } } // 2022-3-25 增加一个错误处理(此处屏蔽,因为有Goto连接到Tool的时候,一定会走到这里) else { qWarning() << "[Warning] POU::ToolPreExecute - Ingore value update, invalid interface category:" << (short)pInf->pUpLinkInterface->Type; } } } // 加上前延时 Utility::qSleep(pActiveTool->execParams.nPreDelay); return nRet; } /// /// Execute后更新下连接口 /// MEMO:对于Tool的接口来说不需要更新下联接口,但是对于Value类型,是需要更新下联接口的 /// VPEnum::RETURN_VALUE POU::ToolPostExecute(TOOL* pActiveTool) { VPEnum::RETURN_VALUE nRet = VPEnum::RETURN_VALUE::None; // 加上后延时 Utility::qSleep(pActiveTool->execParams.nPostDelay); // qDebug() << "[POU] Execute tool - " << pActiveTool->strInstanceName << " Index - " << pActiveTool->nIndex; // LOG("[POU] Execute tool - {} , index - {}.", pActiveTool->strInstanceName.toStdString(), pActiveTool->nIndex); // 2021-11-9,添加要向UI同步的接口 QList<_INTERFACE*> syncInfs; // 2021-11-14,添加要向界面表格同步的接口 QList syncValues; // 2021-12-12,添加要向复杂控件同步的接口(直接发向Runtime) // 复杂控件的同步机制就是直接从Pou中索引链接的数值变动直接向Runtime触发的 QList syncComplexIndexes; // 2021-5-29添加,execute完毕之后,如果有下联接口是Value类型的话(全局变量或局部变量) // 需要额外更新一下Value的值 for (_INTERFACE* pInf : pActiveTool->Interfaces) { // 2022-4-30,跳过Top类型 // REASON: 因为Top类型都是用来下联Tool的,不需要执行更新 if (pInf->isToolEnd()) { continue; } QVector<_INTERFACE*> pDownLinks = pInf->pDownLinkInterfaces; // 增加需要同步到Runtime的接口信息 if (pInf->bDataLink) { syncInfs.push_back(pInf); } // 2021-12-15 如果是复杂控件索引,加入推送通知列表中 if (pInf->bComplexLinkIndex) { syncComplexIndexes.push_back(pInf); } // 遍历所有的下联接口 for (int i = 0; i < pDownLinks.size(); i++) { _INTERFACE* pDownInf = pDownLinks[i]; // 只需要更新数值类型的输出接口 if (pInf->Direction == INF_DIRECTION::INF_DIR_OUT && pDownInf->Type == INF_TYPE::INF_TYPE_VALUE) { // 判断下上联的端口(全局变量组或者局部变量组)是否存在 TOOL* pGvl = pDownInf->bindedParent(); if (pGvl != nullptr) { // 将值更新到下接接口中 QString strValueString = updateInterfaceValue(pDownInf, UPDATE_VALUE_MODE::MODE_TO_VARIABLE); if (strValueString.isEmpty()) { // return nRet; continue; } qDebug() << "[POU] updateInterfaceValue to down link value - " << pDownInf->strFullName; } else // 没查询到对应的全局变量或局部变量 { // 把端口的状态设置为Error TOOL* pPort = pDownInf->parent(); if (pPort != nullptr) { pPort->setPortError(); } QString strErrorMsg = pActiveTool->strInstanceName + "." + pInf->strName + " ----------->" + pDownInf->strName; qWarning() << strErrorMsg << "Error"; } // 添加需要刷新到变量界面表格的接口 syncValues.push_back(pDownInf); // 添加需要刷新到界面的接口 if (pDownInf->bDataLink) { syncInfs.push_back(pDownInf); } // 2021-12-15 如果是复杂控件索引,加入推送通知列表中 if (pDownInf->bComplexLinkIndex) { syncComplexIndexes.push_back(pInf); } } } } // 2021-11-14 增加,一次性使用postEvent异步刷新所有变量界面表格 if (syncValues.size() > 0) { syncValuesToTableUI(syncValues); } // 如果需要的话,则向UI同步(只有非硬件工具才触发execute后的更新动作) if (syncInfs.size() > 0 && !pActiveTool->isHardwareTool()) { syncValuesToUi(syncInfs); } // 2021-12-15 进行复杂控件索引到Runtime的推送 if (syncComplexIndexes.size() > 0) { syncComplexIndexesToRuntime(syncComplexIndexes); } return nRet; } /// /// 执行Goto工具(应该为内部工具专门设计一套数据结构,暂时先放在这里) /// /// /// goto的下一步跳转目标 VPEnum::RETURN_VALUE POU::ToolExecuteGoto(TOOL* pTool, int& index) { // 是否执行了跳转 VPEnum::RETURN_VALUE nRet = VPEnum::RETURN_VALUE::None; // Execute前更新上连接口 nRet = this->ToolPreExecute(pTool); // TODO:此处是否需要处理上联接口状态 //// 如果返回值不是成功的话,就需要加一个错误计数(Pou和Tool的都需要+1) //if (nRet != VPEnum::RETURN_VALUE::Success) //{ // pGoto->execParams.nErrorCount++; // this->execParams.nErrorCount++; //} // 然后开始执行Goto的内部逻辑 // 如果这个Goto已经绑定了工具 if (pTool->Interfaces[GOTO_OUTPUT_INDX]->isBinded()) { // 获取输入接口的值 bool bInput = false; if (pTool->Interfaces[GOTO_INPUT_INDX]->value.Ptr != nullptr) { bInput = pTool->Interfaces[GOTO_INPUT_INDX]->value.getValue(); } // 然后根据取反位决定是否执行跳转 WindowAppBlockGoto* pGotoBlock = qgraphicsitem_cast(m_instNameToToolItems[pTool->strInstanceName]); bool bNegation = pGotoBlock->m_bNegation; bool bJmp = false; // 是否取反 bNegation ? bJmp = !bInput : bJmp = bInput; if (bJmp) { // 执行跳转 // index = pGoto->Interfaces[1]->bindedParent()->nIndex; // 取出跳转的Tool QString strToolName = pTool->Interfaces[GOTO_OUTPUT_INDX]->pBindInterface->strName; TOOL* pGotoTool = this->GetToolByName(strToolName); if (pGotoTool != nullptr) { index = pGotoTool->nIndex; // 设置Goto工具状态 pGotoTool->execParams.nRetValue = VPEnum::RETURN_VALUE::Goto; // Goto工具只有执行跳转,执行计数才会 +1 pGotoTool->execParams.nExecCount++; //qDebug() << "[POU] Execute Goto tool - " << pGoto->strInstanceName << " Index[" << pGoto->nIndex // << "] Goto Index[" << index << "]."; if (m_pParentTask == nullptr) { qDebug() << "[POU:" << m_strPouName << "][Tool:" << pGotoTool->strInstanceName << "][Index:" << pGotoTool->nIndex << "] executed finished: GOTO Index[" << index << "]."; } // 返回跳转标志 return VPEnum::RETURN_VALUE::Goto; } } } // 不执行跳转 qDebug() << "[POU:" << m_strPouName << "][Tool:" << pTool->strInstanceName << "][Index:" << pTool->nIndex << "] executed finished: but not GOTO."; //// 根据是否在Task中执行,输出不同的log //if (m_pParentTask != nullptr) //{ // qDebug() << "[TASK:" << m_pParentTask->strName << "][POU:" << m_strGroup << "][Tool:" << pGoto->strInstanceName << "] executed finished."; //} //else //{ // qDebug() << "[TASK:null][POU:" << m_strGroup << "][Tool:" << pGoto->strInstanceName << "] executed finished."; //} // 设置Goto工具状态 pTool->execParams.nRetValue = VPEnum::RETURN_VALUE::Success; return VPEnum::RETURN_VALUE::Success;; } /// /// 2022-4-30 执行Parallel工具 /// /// /// VPEnum::RETURN_VALUE POU::ToolExecuteParallel(TOOL* pTool) { // 并行工具一定需要有ToolEnd接口 Q_ASSERT(pTool->ToolInterfaces.size() >=0 ); QString strLog; // QVector runningTools; // 首先解析出本并行工具组中有几个并行子工具,并且逐一触发执行 for (auto pDownInf : pTool->ToolInterfaces[INF_END]->pDownLinkInterfaces) { TOOL* pRunningTool = pDownInf->parent(); if (pRunningTool == nullptr) { continue; } strLog += pRunningTool->strInstanceName + " "; // 启动线程执行此工具 m_ParallelThreadPool.start( new _ParallelThread(this, pRunningTool) ); //// 触发并行子工具执行 //pRunningTool->activator.wakeAll(); //runningTools.push_back(pRunningTool); } //qDebug() << "[POU:" << m_strPouName << "][Parallel:" << pTool->strInstanceName // << "] Run parallel tools [" << strLog << "] start."; //// 等待所有Tool执行完毕(所有工具都是Done的状态) // //bool bContinue = true; //while (bContinue) //{ // bContinue = false; // for (int i = 0; i < runningTools.size(); i++) // { // if (runningTools[i]->execParams.nStatus == VPEnum::EXEC_STATUS::Busy) // { // bContinue = true; // Utility::qSleep(10); // break; // } // } //} //qDebug() << "[POU:" << m_strPouName << "][Parallel:" << pTool->strInstanceName // << "] Run parallel tools [" << strLog << "] finished."; qDebug() << "[POU:" << m_strPouName << "][Parallel:" << pTool->strInstanceName << "] Run parallel tools [" << strLog << "] start."; // 等待所有线程执行完毕 m_ParallelThreadPool.waitForDone(); qDebug() << "[POU:" << m_strPouName << "][Parallel:" << pTool->strInstanceName << "] Run parallel tools [" << strLog << "] finished."; return VPEnum::RETURN_VALUE::Success; } /// /// 针对TOOL的index,从小到大排序 /// /// /// /// bool sortLoopTool(TOOL*& a, TOOL*& b) { if (a->nIndex < b->nIndex) { return true; } else { return false; } } /// /// 2022-8-25 执行ForLoop工具 /// /// /// VPEnum::RETURN_VALUE POU::ToolExecuteForloop(TOOL* pTool) { // 执行返回值 VPEnum::RETURN_VALUE nRet = VPEnum::RETURN_VALUE::None; // ForLoop工具的计数与其他工具不同,需要在ForLoop工具内部处理运行计数,统计For循环的真正执行次数 // Execute前首先更新上连接口,获取执行的Size(此处也有可能是通过对话框设置的Size,所以没有上级连接) nRet = this->ToolPreExecute(pTool); // 如果没有取到上联接口的值,则跳过ForLoop的执行,因为没有Size if (pTool->Interfaces[0]->isValueNullptr()) { // 跳过执行 qDebug() << "[POU:" << m_strPouName << "][Tool:" << pTool->strInstanceName << "][Index:" << pTool->nIndex << "] executed ignore: input size is <=0."; return VPEnum::RETURN_VALUE::Success; } // 然后开始执行Forloop的内部逻辑 // 如果没有下联标准工具,直接跳过执行 if (pTool->ToolInterfaces[INF_END]->pDownLinkInterfaces.size() <=0 ) { // 跳过执行 qDebug() << "[POU:" << m_strPouName << "][Tool:" << pTool->strInstanceName << "][Index:" << pTool->nIndex << "] executed ignore: invalid standard tool count in forloop."; return VPEnum::RETURN_VALUE::Success; } // 找到所有下联的工具,按照Index排序执行 QVector loopTools; for (auto& inf : pTool->ToolInterfaces[INF_END]->pDownLinkInterfaces) { if (inf->parent() != nullptr) { loopTools.push_back(inf->parent()); } } // 按照Index排序(从小到大) qSort(loopTools.begin(), loopTools.end(), sortLoopTool); // 取出循环的Size(从Size输入接口中取) // 0号接口固定为ForLoop工具的Size输入值 int nSize = pTool->Interfaces[0]->value.toInt(); // 开始循环执行 for (int i = 0; i < nSize; i++) { // 输出当前Index // 1号接口固定为ForLoop工具的Index输出值 pTool->Interfaces[1]->value.setValue(i); // 遍历所有For循环内部的工具,依次执行 for (int toolIndex = 0; toolIndex < loopTools.size(); toolIndex++) { // 取出当前需要执行的工具 TOOL* runningTool = loopTools[toolIndex]; // 执行此工具 this->ToolExecuteStandard(runningTool); qDebug() << "[ForLoop(" << pTool->strInstanceName << ") Index:" << i << "] | [POU:" << m_strPouName << "][Tool:" << runningTool->strInstanceName << "] executed finished."; } // 2022-8-28 ,执行次数 +1 pTool->execParams.nExecCount++; } vDebug() << "[POU:" << m_strPouName << "][Forloop:" << pTool->strInstanceName << "] Round[" << nSize << "] finished."; // 设置ForLoop工具状态 pTool->execParams.nRetValue = VPEnum::RETURN_VALUE::Success; return nRet; } /// /// 2022-9-3 执行Wait工具 /// /// /// VPEnum::RETURN_VALUE POU::ToolExecuteWait(TOOL* pTool, TOOL_RUN_MODE runMode) { // WaitBlock指针,用于获取用户设定的功能块执行参数 WindowAppBlockWait* pWaitBlock = qgraphicsitem_cast(m_instNameToToolItems[pTool->strInstanceName]); // 异常 if (pWaitBlock == nullptr) { vDebug() << "[Error] pWaitBlock is nullptr."; return VPEnum::RETURN_VALUE::Error; } // 如果处于单步执行状态,需要看一下用户是否选择了单步执行跳过等待 if (runMode == TOOL_RUN_MODE::SINGLE_STEP) { if (pWaitBlock->m_bSkipWait) { vDebug() << "[POU:" << m_strPouName << "][Wait:" << pTool->strInstanceName << "] ignore waiting, reason: m_bSkipWait = true."; return VPEnum::RETURN_VALUE::Abort; } } // 如果本Wait工具都没有注册触发事件,则跳过等待 if (!g_pTaskManager->isToolTriggerable(pTool)) { vDebug() << "[POU:" << m_strPouName << "][Wait:" << pTool->strInstanceName << "] ignore waiting, reason: no event trigger."; return VPEnum::RETURN_VALUE::Abort; } // 启动等待机制 vDebug() << "[POU:" << m_strPouName << "][Wait:" << pTool->strInstanceName << "] start waiting for " << pWaitBlock->m_nTimeout << "ms ......."; // 设置Tool为Wait状态 pTool->execParams.nStatus = VPEnum::EXEC_STATUS::Wait; // 2022-9-26,为接口的等待时长计时 QElapsedTimer waitTimer; waitTimer.start(); // 直接开始等待工具事件触发 pTool->waitForExecution(pWaitBlock->m_nTimeout); // 2022-9-26,然后将本轮等待时长输出到1号接口中 int nWaitTime = waitTimer.elapsed(); pTool->Interfaces[1]->value.setValue(nWaitTime); // 等待结束,设置Tool为Busy状态 pTool->execParams.nStatus = VPEnum::EXEC_STATUS::Busy; vDebug() << "[POU:" << m_strPouName << "][Wait:" << pTool->strInstanceName << "] waiting finished, elapse:" << nWaitTime; return VPEnum::RETURN_VALUE::Success; } /// /// BreakPoint /// /// void POU::ToolBreakPoint(WindowAppBlockStandardBase* pBlockItem) { TOOL* pTool = m_itemToTools.value(pBlockItem); if (pTool) { pTool->bEnableBreakPoint = !pTool->bEnableBreakPoint; if (pTool->bEnableBreakPoint) { qDebug() << "Enable Tool" << pTool->strName << "Enable BreakPoint "; } } } /// /// 从当前位置执行 /// /// void POU::ToolExecuteSub(WindowAppBlockStandardBase* pBlockItem) { int nExecuteIndex = m_itemToTools.value(pBlockItem)->nIndex; // 从当前序号开始执行 this->ToolExecuteAll(nExecuteIndex); } /// /// 全部按顺序执行 /// void POU::ToolExecuteAll(const int startIndex) { qDebug() << "[POU:" << this->pouName() << "] ExecuteAll Start..."; VPEnum::RETURN_VALUE ret = VPEnum::RETURN_VALUE::None; for (int index = startIndex; index < m_StandardTools.size(); ) { TOOL* pRunningTool = m_StandardTools[index]; //// 设置为busy状态 //pRunningTool->execParams.nStatus = VPEnum::EXEC_STATUS::Busy; // 交给Pou执行调度器执行 ret = this->ToolExecutionDispatcher(pRunningTool, index, TOOL_RUN_MODE::SEQUENTIAL); //// 设置为完成状态 //pRunningTool->execParams.nStatus = VPEnum::EXEC_STATUS::Done; } qDebug() << "[POU:" << this->pouName() << "] ExecuteAll Finish."; } /// /// 单步执行 /// void POU::ToolExecuteSingleStep() { int index = m_nExecuteIndex; VPEnum::RETURN_VALUE ret = VPEnum::RETURN_VALUE::None; if ((index >= 0) && (index < m_StandardTools.size())) { // 将前一个执行完毕的工具状态设置为Done if ((index == 0)) { int nIndex = m_StandardTools.size() - 1; TOOL* pRunningTool = m_StandardTools[nIndex]; pRunningTool->execParams.nStatus = VPEnum::EXEC_STATUS::Done; } else { int nIndex = index - 1; TOOL* pRunningTool = m_StandardTools[nIndex]; pRunningTool->execParams.nStatus = VPEnum::EXEC_STATUS::Done; } TOOL* pRunningTool = m_StandardTools[index]; // 2022-8-28,通过Dispatcher统一调度执行(以单步执行模式) ret = this->ToolExecutionDispatcher(pRunningTool, index, TOOL_RUN_MODE::SINGLE_STEP); } // 执行指针返回 m_nExecuteIndex++; if (m_StandardTools.size() <= m_nExecuteIndex) { m_nExecuteIndex = 0; } } /// /// 根据不同的传值情况从dll中取值 /// /// /// /// /// template void POU::MoveValue(T& tValue, _INTERFACE* pInf, UPDATE_VALUE_MODE mode) { // 被标记为废弃的端口,不参与数据链接 if (pInf->pUpLinkInterface->Discard != INF_DISCARD::INF_DEFAULT || pInf->Discard != INF_DISCARD::INF_DEFAULT ) { qWarning() << "[LinkError]" << m_strPouName << "." << pInf->pUpLinkInterface->strFullName << " to " << pInf->strFullName << "Error Interface Is Discard."; return; } if (mode == UPDATE_VALUE_MODE::MODE_FROM_TOOL) { if (pInf->value.passMode == VALUE_PASS_MODE::PASS_BY_VALUE) { this->MoveValueByConverter(tValue, pInf->pUpLinkInterface, pInf); } else { T& value = GetDllInfValue(pInf->pUpLinkInterface); SetDllInfValue(value, pInf); tValue = value; } } else if (mode == UPDATE_VALUE_MODE::MODE_FROM_VARIABLE) { tValue = pInf->pUpLinkInterface->getValue(); SetDllInfValue(tValue, pInf); } else if (mode == UPDATE_VALUE_MODE::MODE_TO_VARIABLE) { tValue = GetDllInfValue(pInf->pUpLinkInterface); pInf->setValue(tValue, VALUE_PASS_MODE::PASS_BY_VALUE); } } /// /// 2021-8-24 将基础数据类型转换后,再执行操作 /// /// /// template void POU::MoveValueByConverter(T& tValue, _INTERFACE* pSrcInf, _INTERFACE* pDstInf) { // 走到这个函数里的,应该都是两种类型相同的接口,那么直接计算即可 tValue = GetDllInfValue(pSrcInf); SetDllInfValue(tValue, pDstInf); //// 异常,不应该执行到这里 //else //{ // qWarning() << "[POU Execute] MoveValueByConverter(), but unknown value type."; //} } /// /// 模板特例化 - 目标类型是QString时(为了实现自动接口数值类型转换) /// /// /// /// void POU::MoveValueByConverter(QString& tValue, _INTERFACE* pSrcInf, _INTERFACE* pDstInf) { VALUE_TYPE srcType = pSrcInf->value.type; if (srcType == VALUE_TYPE::Type_Int) { int nValue = GetDllInfValue(pSrcInf); tValue = QString::number(nValue); } // float else if (srcType == VALUE_TYPE::Type_Float) { float fValue = GetDllInfValue(pSrcInf); tValue = QString("%1").arg(fValue); } // double else if (srcType == VALUE_TYPE::Type_Double) { double dValue = GetDllInfValue(pSrcInf); tValue = QString("%1").arg(dValue); } // bool else if (srcType == VALUE_TYPE::Type_Bool) { bool bValue = GetDllInfValue(pSrcInf); tValue = QString("%1").arg(bValue); } else { tValue = GetDllInfValue(pSrcInf); } SetDllInfValue(tValue, pDstInf); } /// /// 模板特例化 - 目标类型是int时(为了实现自动接口数值类型转换) /// /// /// /// void POU::MoveValueByConverter(int& tValue, _INTERFACE* pSrcInf, _INTERFACE* pDstInf) { VALUE_TYPE srcType = pSrcInf->value.type; // QString if (srcType == VALUE_TYPE::Type_String) { QString strValue = GetDllInfValue(pSrcInf); tValue = strValue.toInt(); } // float else if (srcType == VALUE_TYPE::Type_Float) { float fValue = GetDllInfValue(pSrcInf); tValue = static_cast(fValue); } // double else if (srcType == VALUE_TYPE::Type_Double) { double dValue = GetDllInfValue(pSrcInf); tValue = static_cast(dValue); } // bool else if (srcType == VALUE_TYPE::Type_Bool) { bool bValue = GetDllInfValue(pSrcInf); tValue = static_cast(bValue); } else { tValue = GetDllInfValue(pSrcInf); } SetDllInfValue(tValue, pDstInf); } /// /// 模板特例化 - 目标类型是float时(为了实现自动接口数值类型转换) /// /// /// /// void POU::MoveValueByConverter(float& tValue, _INTERFACE* pSrcInf, _INTERFACE* pDstInf) { VALUE_TYPE srcType = pSrcInf->value.type; // QString if (srcType == VALUE_TYPE::Type_String) { QString strValue = GetDllInfValue(pSrcInf); tValue = strValue.toFloat(); } // int else if (srcType == VALUE_TYPE::Type_Int) { int nValue = GetDllInfValue(pSrcInf); tValue = static_cast(nValue); } // double else if (srcType == VALUE_TYPE::Type_Double) { double dValue = GetDllInfValue(pSrcInf); tValue = static_cast(dValue); } // bool else if (srcType == VALUE_TYPE::Type_Bool) { bool bValue = GetDllInfValue(pSrcInf); tValue = static_cast(bValue); } else { tValue = GetDllInfValue(pSrcInf); } SetDllInfValue(tValue, pDstInf); } /// /// 模板特例化 - 目标类型是double时(为了实现自动接口数值类型转换) /// /// /// /// void POU::MoveValueByConverter(double& tValue, _INTERFACE* pSrcInf, _INTERFACE* pDstInf) { VALUE_TYPE srcType = pSrcInf->value.type; // QString if (srcType == VALUE_TYPE::Type_String) { QString strValue = GetDllInfValue(pSrcInf); tValue = strValue.toDouble(); } // int else if (srcType == VALUE_TYPE::Type_Int) { int nValue = GetDllInfValue(pSrcInf); tValue = static_cast(nValue); } // float else if (srcType == VALUE_TYPE::Type_Float) { float fValue = GetDllInfValue(pSrcInf); tValue = static_cast(fValue); } // bool else if (srcType == VALUE_TYPE::Type_Bool) { bool bValue = GetDllInfValue(pSrcInf); tValue = static_cast(bValue); } else { tValue = GetDllInfValue(pSrcInf); } SetDllInfValue(tValue, pDstInf); } /// /// 模板特例化 - 目标类型是bool时(为了实现自动接口数值类型转换) /// /// /// /// void POU::MoveValueByConverter(bool& tValue, _INTERFACE* pSrcInf, _INTERFACE* pDstInf) { VALUE_TYPE srcType = pSrcInf->value.type; // QString if (srcType == VALUE_TYPE::Type_String) { QString strValue = GetDllInfValue(pSrcInf); if (strValue == STRING_TRUE || strValue == "1") { tValue = true; } else { tValue = false; } } // int else if (srcType == VALUE_TYPE::Type_Int) { int nValue = GetDllInfValue(pSrcInf); tValue = static_cast(nValue); } // float else if (srcType == VALUE_TYPE::Type_Double) { double dValue = GetDllInfValue(pSrcInf); tValue = static_cast(dValue); } // double else if (srcType == VALUE_TYPE::Type_Double) { double dValue = GetDllInfValue(pSrcInf); tValue = static_cast(dValue); } else { tValue = GetDllInfValue(pSrcInf); } SetDllInfValue(tValue, pDstInf); } /// /// 2021-11-9 向UI同步接口数值 /// /// void POU::syncValuesToUi(QList<_INTERFACE*> pInfs) { SyncValueEvent* valueEvent = new SyncValueEvent(); // 携带需要同步的多个接口 valueEvent->setSyncValues(pInfs); // post数值同步消息,post内部会自动释放event的指针,无需手工释放 QCoreApplication::postEvent((QObject*)g_pUiManager, valueEvent); } /// /// 2021-11-14 向变量表界面同步数值 /// /// void POU::syncValuesToTableUI(QList<_INTERFACE*> pInfs) { SyncValueEvent* valueEvent = new SyncValueEvent(); // 携带需要同步的多个接口 valueEvent->setSyncValues(pInfs); // post数值同步消息,post内部会自动释放event的指针,无需手工释放 QCoreApplication::postEvent((QObject*)g_pGvlManager, valueEvent); } /// /// 2021-12-15 向Runtime推送索引数值的变动 /// /// void POU::syncComplexIndexesToRuntime(QList pIndexes) { SyncValueEvent* valueEvent = new SyncValueEvent(); // 携带需要同步的多个接口 valueEvent->setSyncValues(pIndexes); // post数值同步消息,post内部会自动释放event的指针,无需手工释放 QCoreApplication::postEvent((QObject*)g_pRuntime, valueEvent); } /// /// 更新接口的值(根据不同的模式) /// /// /// QString POU::updateInterfaceValue(_INTERFACE* pInf, UPDATE_VALUE_MODE mode) { // 2021-6-5 增加, 防止变量中的变量被删除的情况,首先检查值是否为空 //if (mode == UPDATE_VALUE_MODE::MODE_FROM_VARIABLE) //{ // if (pInf->pUpLinkInterface->value.Ptr == nullptr) // { // Utility::VPCriticalMessageBox("Can't update value from " + pInf->pUpLinkInterface->strFullName + ", Reason: value is invalid."); // return false; // } //} // 被标记为废弃的端口,不参与数据链接 if (pInf == nullptr || pInf->Discard != INF_DISCARD::INF_DEFAULT) { return "Interface Error"; } // 根据不同类型分别进行操作 VALUE_TYPE type = pInf->value.type; switch (type) { case VALUE_TYPE::Type_Bool: { bool value = false; MoveValue(value, pInf, mode); pInf->valueString = QString(value); } break; case VALUE_TYPE::Type_Int: { int value = 0; MoveValue(value, pInf, mode); // 2021-11-9,保存接口数值 pInf->valueString = QString::number(value); } break; case VALUE_TYPE::Type_Float: { float value = 0; MoveValue(value, pInf, mode); pInf->valueString = QString("%1").arg(value); } break; case VALUE_TYPE::Type_Double: { double value = 0.0; MoveValue(value, pInf, mode); pInf->valueString = QString("%1").arg(value); } break; //case VALUE_TYPE::Type_CharP: //{ // char* value = nullptr; // MoveValue(value, pInf, mode); // return QString("%1").arg(value); //} //break; case VALUE_TYPE::Type_StdString: { std::string value = ""; MoveValue(value, pInf, mode); pInf->valueString = QString("%1").arg(value.c_str()); } break; case VALUE_TYPE::Type_String: { QString value = ""; MoveValue(value, pInf, mode); pInf->valueString = value; } break; case VALUE_TYPE::Type_QImage: { QImage value; MoveValue(value, pInf, mode); //pInf->valueString = QString("%1 - %1").arg(value.size().width()).arg(value.size().height()); pInf->valueString = QString("QImage"); } break; case VALUE_TYPE::Type_Mat: { Mat value; MoveValue(value, pInf, mode); //pInf->valueString = QString("%1 - %1").arg(value.size().width()).arg(value.size().height()); pInf->valueString = QString("Mat"); } break; case VALUE_TYPE::Type_HTuple: { HTuple value; MoveValue(value, pInf, mode); pInf->valueString = QString("HTuple"); } break; case VALUE_TYPE::Type_HObject: { HObject value; MoveValue(value, pInf, mode); pInf->valueString = QString("HObject"); } break; case VALUE_TYPE::Type_HImage: { HImage value; MoveValue(value, pInf, mode); pInf->valueString = QString("HImage"); } break; case VALUE_TYPE::Type_ST_Pos: { ST_POS value; MoveValue(value, pInf, mode); pInf->valueString = QString("ST Pose"); } break; case VALUE_TYPE::Type_ST_HomMat2D: { HHomMat2D value; MoveValue(value, pInf, mode); pInf->valueString = QString("HHomMat2D"); } break; case VALUE_TYPE::Type_ST_Point: { } break; case VALUE_TYPE::Type_ST_Line: { } break; case VALUE_TYPE::Type_ST_Circle: { } break; case VALUE_TYPE::Type_ST_Disp: { } break; case VALUE_TYPE::Type_ST_Window: { } break; case VALUE_TYPE::Type_ST_Ncc_Modle: { } break; case VALUE_TYPE::Type_ST_Shape_Modle: { } break; case VALUE_TYPE::Type_ST_Calibration: { } break; case VALUE_TYPE::Type_ST_CamParam_PoseCalib: { } break; case VALUE_TYPE::Type_pIBaseCamera: { IBaseCamera* value= nullptr; MoveValue(value, pInf, mode); if (value != nullptr) { pInf->valueString = QString("%1").arg(value->serial()); } else { pInf->valueString = "null"; } } break; case VALUE_TYPE::Type_pIpImage: { } break; case VALUE_TYPE::Type_pISocket: { } break; case VALUE_TYPE::Type_pArrayIn: { } break; case VALUE_TYPE::Type_pArrayOut: { } break; case VALUE_TYPE::Type_pArrayRobotPos: { } break; default: qWarning() << "[POU][LINK][ERROR]: updateInterfaceValue - Unknown value type: " << (short)type; return ""; pInf->valueString.clear(); } return pInf->valueString; // return ""; } /// /// 重置所有工具执行状态 /// void POU::ResetToolExecCode() { QHash::iterator iter = m_itemToTools.begin(); while (iter != m_itemToTools.end()) { // 返回值 iter.value()->execParams.nRetValue = VPEnum::RETURN_VALUE::None; // 状态 iter.value()->execParams.nStatus = VPEnum::EXEC_STATUS::StandBy; iter++; } } /// /// 从Dll获取接口的值 /// /// /// /// template T& POU::GetDllInfValue(_INTERFACE* pInf) { // DllTool* pDllTool = pInf->pParentTool->pDllPtr; // 2022-3-23 根据真实的Parent获取对应的Dll(处理Port绑定的情况) DllTool* pDllTool = pInf->realParent()->pDllPtr; return pDllTool->Value(pInf->nIndex); } /// /// 设置Dll中接口的值 /// /// /// /// template void POU::SetDllInfValue(T& tValue, _INTERFACE* pInf) { DllTool* pDllTool = pInf->realParent()->pDllPtr; if (pDllTool != nullptr) { if (pInf->value.passMode == VALUE_PASS_MODE::PASS_BY_VALUE) { pDllTool->UpdateValue(pInf->nIndex, tValue); } else { pDllTool->UpdateValue(pInf->nIndex, tValue, VALUE_PASS_MODE::PASS_BY_ADDRESS); } } else { pInf->setValue(tValue, VALUE_PASS_MODE::PASS_BY_VALUE); } } /// /// 2022-9-25,查询WaitTool的等待Value(用于在TaskManager触发WaitTool执行的时候进行判断) /// /// /// VALUE* POU::getWaitToolValue(TOOL* pTool) { WindowAppBlockWait* pWaitBlock = qgraphicsitem_cast(m_instNameToToolItems[pTool->strInstanceName]); return &pWaitBlock->m_WaitValue; } //============================================================ // // Task 线程 // //============================================================ /// /// 线程函数 /// void _ParallelThread::run() { // 调用函数执行任务 this->m_pPou->ToolExecutionDispatcher(m_pParallelSubTool, TOOL_RUN_MODE::IN_PARALLEL); } ///// ///// 线程函数 ///// //void _ParallelThread::run() //{ // VPEnum::RETURN_VALUE ret = VPEnum::RETURN_VALUE::None; // // // 循环执行任务,直到工具退出为止 // while (ret != VPEnum::RETURN_VALUE::Abort) // { // // 调用函数执行任务 // this->m_pPou->ToolExecutionDispatcher(m_pParallelSubTool, TOOL_RUN_MODE::IN_PARALLEL); // } // // vDebug() << " _ParallelThread of SubTool[" << m_pParallelSubTool->strInstanceName << "] exit."; //} // // ///// ///// 将本工具加入到并行子工具的预启动中 ///// ///// //void POU::addParallelSubTool(TOOL* pTool) //{ // // 并行子工具在刚链接的时候,就直接启动线程,但是处于等待状态不执行 // m_ParallelThreadPool.start(new _ParallelThread(this, pTool)); // // vDebug() << "ParallelSubTool[" << pTool->strInstanceName << "] thread start..."; //} // // ///// ///// 移除一个并行子工具 ///// ///// //void POU::removeParallelSubTool(TOOL* pTool) //{ // Q_UNUSED(pTool); //}