#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);
//}