From a7df0e1d5521248302e5437a1cf7b14c29b3cbaa Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期五, 05 九月 2025 13:55:31 +0800
Subject: [PATCH] 1.CParam增加站点名称,以便将来知道Glass的工艺参数来自哪台机;
---
SourceCode/Bond/Servo/CMaster.cpp | 866 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 817 insertions(+), 49 deletions(-)
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index ccd1f5d..405eca3 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -4,6 +4,8 @@
#include <future>
#include <vector>
#include "RecipeManager.h"
+#include <fstream>
+#include "SerializeUtil.h"
namespace SERVO {
@@ -53,20 +55,29 @@
m_pActiveRobotTask = nullptr;
m_nLastError = 0;
m_isCompareMapsBeforeProceeding = FALSE;
+ m_bJobMode = FALSE;
m_bEnableEventReport = true;
m_bEnableAlarmReport = true;
m_bContinuousTransfer = false;
+ m_bBatch = false;
m_nContinuousTransferCount = 0;
m_nContinuousTransferStep = CTStep_Unknow;
+ m_pControlJob = nullptr;
+ m_nTestFlag = 0;
InitializeCriticalSection(&m_criticalSection);
}
CMaster::~CMaster()
{
+ // 释放Job相关
for (auto item : m_processJobs) {
delete item;
}
m_processJobs.clear();
+ if (m_pControlJob != nullptr) {
+ delete m_pControlJob;
+ m_pControlJob = nullptr;
+ }
if (m_hEventReadBitsThreadExit[0] != nullptr) {
::CloseHandle(m_hEventReadBitsThreadExit[0]);
@@ -261,6 +272,7 @@
}
m_bContinuousTransfer = false;
+ m_bBatch = false;
setState(MASTERSTATE::STARTING);
m_ullStartTime = GetTickCount64();
@@ -274,6 +286,21 @@
}
m_bContinuousTransfer = true;
+ m_bBatch = false;
+ setState(MASTERSTATE::STARTING);
+ m_ullStartTime = GetTickCount64();
+
+ return 0;
+ }
+
+ int CMaster::startBatch()
+ {
+ if (m_state != MASTERSTATE::READY) {
+ return -1;
+ }
+
+ m_bContinuousTransfer = false;
+ m_bBatch = true;
setState(MASTERSTATE::STARTING);
m_ullStartTime = GetTickCount64();
@@ -283,12 +310,28 @@
int CMaster::stop()
{
// 运行时间为累加结果,本次停止时刷新;
- if (m_state != MASTERSTATE::RUNNING && m_state != MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
+ lock();
+ if (m_state != MASTERSTATE::RUNNING && m_state != MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER
+ && m_state != MASTERSTATE::RUNNING_BATCH) {
+ unlock();
return -1;
}
-
m_ullRunTime += (GetTickCount64() - m_ullStartTime);
+ unlock();
+
+
+ // 更新状态
setState(MASTERSTATE::STOPPING);
+
+
+ // ControlJob暂停
+ lock();
+ if (m_pControlJob != nullptr) {
+ m_pControlJob->pause();
+ saveState();
+ }
+ unlock();
+
return 0;
}
@@ -302,7 +345,8 @@
ULONGLONG CMaster::getRunTime()
{
- if (m_state == MASTERSTATE::RUNNING || m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER)
+ if (m_state == MASTERSTATE::RUNNING || m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER
+ || m_state == MASTERSTATE::RUNNING_BATCH)
return m_ullRunTime + (GetTickCount64() - m_ullStartTime);
else
return m_ullRunTime;
@@ -468,12 +512,13 @@
continue;
}
-
unlock();
- if(!m_bContinuousTransfer)
- setState(MASTERSTATE::RUNNING);
- else
+ if(m_bContinuousTransfer)
setState(MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER);
+ else if (m_bBatch)
+ setState(MASTERSTATE::RUNNING_BATCH);
+ else
+ setState(MASTERSTATE::RUNNING);
continue;
}
@@ -550,37 +595,62 @@
}
- // 此处检测优先类型和次要类型(G1或G2)
- // 如果其中一Bonder有单个玻璃,优先取它的配对类型,否则无所谓了
- primaryType = MaterialsType::G1;
- secondaryType = MaterialsType::G2;
- if ((!pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1))
- && (!pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) {
- // 如果G1和G2都满了,那就看Aligner, 如果Aligner有玻璃为G1, 则取G2
- CGlass* pGlass = pAligner->getGlassFromSlot(1);
- if (pGlass != nullptr && pGlass->getType() == MaterialsType::G1) {
- primaryType = MaterialsType::G2;
- secondaryType = MaterialsType::G1;
- }
+ // Bonder1、Bonder2、Fliper、VacuumBake、Aligner,统计G2和G1的数量, 配对组数, 多出的类型
+ int nG2Count = 0, nG1Count = 0, nGlassGroup, nExtraType;
+ if (pBonder1->slotHasGlass(0)) {
+ nG2Count++;
}
- else if ((pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1))
- || (pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) {
- primaryType = MaterialsType::G2;
- secondaryType = MaterialsType::G1;
+ if (pBonder1->slotHasGlass(1)) {
+ nG1Count++;
}
+
+ if (pBonder2->slotHasGlass(0)) {
+ nG2Count++;
+ }
+ if (pBonder2->slotHasGlass(1)) {
+ nG1Count++;
+ }
+
+ if (pFliper->slotHasGlass(0)) {
+ nG2Count++;
+ }
+
+ if (pVacuumBake->slotHasGlass(0)) {
+ nG1Count++;
+ }
+ if (pVacuumBake->slotHasGlass(1)) {
+ nG1Count++;
+ }
+
+ CGlass* pTempGlass = pAligner->getGlassFromSlot(0);
+ if (pTempGlass != nullptr) {
+ MaterialsType type = pTempGlass->getType();
+ if(type == MaterialsType::G1)
+ nG1Count++;
+ else if (type == MaterialsType::G2)
+ nG2Count++;
+ }
+ nGlassGroup = min(nG1Count, nG2Count);
+
+ if (nG1Count == nG2Count) {
+ nExtraType = 0;
+ }
+ else if (nG1Count > nG2Count) {
+ nExtraType = 1;
+ }
+ else {
+ nExtraType = 2;
+ }
+ secondaryType = MaterialsType::G0;
// Measurement -> LoadPort
- if (rmd.armState[0] || rmd.armState[1]) {
- LOGI("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
- rmd.armState[1] ? _T("不可用") : _T("可用"));
- }
for (int s = 0; s < 4; s++) {
PortType pt = pLoadPorts[s]->getPortType();
if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
&& (pt == PortType::Unloading || pt == PortType::Both)
&& pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
- m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], primaryType, secondaryType);
+ m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], MaterialsType::G1, secondaryType);
if (m_pActiveRobotTask != nullptr) {
goto PORT_PUT;
}
@@ -627,24 +697,269 @@
// Fliper(G2) -> Bonder
+ //m_nTestFlag = 1;
+ //pVacuumBake->m_nTestFlag = 1;
+ auto pSrcSlot = pVacuumBake->getProcessedSlot(MaterialsType::G1);
+ //LOGI("<Master>pSrcSlot = %x", pSrcSlot,);
+ if (pSrcSlot != nullptr && !rmd.armState[1]
+ && pBonder1->canPlaceGlassInSlot(0)) {
+ m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, MaterialsType::G2, MaterialsType::G0, 2);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+ if (pSrcSlot != nullptr && !rmd.armState[1]
+ && pBonder2->canPlaceGlassInSlot(0)) {
+ m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, MaterialsType::G2, MaterialsType::G0, 2);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+ //m_nTestFlag = 0
+ ;
+ // VacuumBake(G1) -> Bonder
+ if (!rmd.armState[0] && pBonder1->slotHasGlass(0) && !pBonder1->slotHasGlass(1)) {
+ m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, MaterialsType::G1, MaterialsType::G0);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+ if (!rmd.armState[0] && pBonder2->slotHasGlass(0) && !pBonder2->slotHasGlass(1)) {
+ m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, MaterialsType::G1, MaterialsType::G0);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+
+ // Aligner -> Fliper(G2)
+ // Aligner -> VacuumBake(G1)
+ if (!rmd.armState[1]) {
+ m_pActiveRobotTask = createTransferTask(pAligner, pFliper, MaterialsType::G2, secondaryType);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+ if (!rmd.armState[0]) {
+ // m_nTestFlag = 1;
+ if (m_nTestFlag == 1) LOGI("createTransferTask 004df %d, %d", MaterialsType::G1, secondaryType);
+ m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, MaterialsType::G1, secondaryType);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ m_nTestFlag = 0;
+ }
+
+
+ // Aligner -> LoadPort
+ if (!rmd.armState[1]) {
+ m_pActiveRobotTask = createTransferTask_restore(pAligner, pLoadPorts);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+
+ // LoadPort -> Aligner
+ if (nGlassGroup >= 2) {
+ unlock();
+ continue;
+ }
+
+ if(nExtraType == 0)
+ primaryType = MaterialsType::G2;
+ else {
+ primaryType = MaterialsType::G1;
+ }
+
+ for (int s = 0; s < 4; s++) {
+ PortType pt = pLoadPorts[s]->getPortType();
+ if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
+ && (pt == PortType::Loading || pt == PortType::Both)
+ && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
+ m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, 1, m_bJobMode);
+ if (m_pActiveRobotTask != nullptr) {
+ CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext();
+ if (pGlass->getBuddy() != nullptr) {
+ delete m_pActiveRobotTask;
+ m_pActiveRobotTask = nullptr;
+ continue;
+ }
+
+ pEFEM->setContext(m_pActiveRobotTask->getContext());
+ goto PORT_GET;
+ }
+ }
+ }
+
+PORT_GET:
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+
+
+ unlock();
+ continue;
+ }
+
+ // 批处理模式,最终以此为准,但先保留之前的单片模式
+ else if (m_state == MASTERSTATE::RUNNING_BATCH) {
+ // 首选检查有没有CControlJob, 状态等
+ if (m_pControlJob == nullptr) {
+ unlock();
+ continue;
+ }
+ CJState state = m_pControlJob->state();
+ if (state == CJState::Completed || state == CJState::Aborted || state == CJState::Failed) {
+ // ConrolJpb已完成
+ LOGI("<Master>ControlJob已经完成或失败中断");
+ unlock();
+ continue;
+ }
+
+
+ if (m_pControlJob->state() == CJState::NoState) {
+ LOGI("<Master>ControlJob已经进入列队");
+ m_pControlJob->queue();
+ }
+ if (m_pControlJob->state() == CJState::Queued) {
+ LOGI("<Master>ControlJob已经启动");
+ m_pControlJob->start();
+
+ if (m_listener.onCjStart != nullptr) {
+ m_listener.onCjStart(this, m_pControlJob);
+ }
+ }
+ if (m_pControlJob->state() == CJState::Paused) {
+ LOGI("<Master>ControlJob已经恢复运行");
+ m_pControlJob->resume();
+ }
+
+
+ // 如果当前未选择CProcessJob, 选择一个
+ if (m_inProcesJobs.empty()) {
+ auto pj = acquireNextProcessJob();
+ if (pj != nullptr) {
+ m_inProcesJobs.push_back(pj);
+
+ // 这里上报PJ Start事件
+ if (m_listener.onPjStart != nullptr) {
+ m_listener.onPjStart(this, pj);
+ }
+ }
+ }
+ if (m_inProcesJobs.empty()) {
+ LOGI("<Master>选择当前ProcessJob失败!");
+ unlock();
+ continue;
+ }
+
+ // 如果当前没有Glass, 选择
+ if (m_queueGlasses.empty()) {
+ int nCount = acquireGlassToQueue();
+ LOGI("<Master>已加入 %d 块Glass到工艺列队!", nCount);
+ }
+
+
+ // 检测判断robot状态
+ RMDATA& rmd = pEFEM->getRobotMonitoringData();
+ if (rmd.status != ROBOT_STATUS::Idle && rmd.status != ROBOT_STATUS::Run) {
+ unlock();
+ continue;
+ }
+
+ if (m_pActiveRobotTask != nullptr) {
+ if (m_pActiveRobotTask->isPicked()) {
+ m_pActiveRobotTask->place();
+ }
+ unlock();
+ // 检测到当前有正在下午的任务,确保当前任务完成或中止后继续
+ // LOGI("检测到当前有正在下午的任务,确保当前任务完成或中止后继续...");
+ continue;
+ }
+
+
+ // 此处检测优先类型和次要类型(G1或G2)
+ // 如果其中一Bonder有单个玻璃,优先取它的配对类型,否则无所谓了
+ primaryType = MaterialsType::G1;
+ secondaryType = MaterialsType::G2;
+ if ((!pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1))
+ && (!pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) {
+ // 如果G1和G2都满了,那就看Aligner, 如果Aligner有玻璃为G1, 则取G2
+ CGlass* pGlass = pAligner->getGlassFromSlot(1);
+ if (pGlass != nullptr && pGlass->getType() == MaterialsType::G1) {
+ primaryType = MaterialsType::G2;
+ secondaryType = MaterialsType::G1;
+ }
+ }
+ else if ((pBonder1->canPlaceGlassInSlot(0) && !pBonder1->canPlaceGlassInSlot(1))
+ || (pBonder2->canPlaceGlassInSlot(0) && !pBonder2->canPlaceGlassInSlot(1))) {
+ primaryType = MaterialsType::G2;
+ secondaryType = MaterialsType::G1;
+ }
+
+
+ // Measurement -> LoadPort
+ if (rmd.armState[0] || rmd.armState[1]) {
+ LOGI("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
+ rmd.armState[1] ? _T("不可用") : _T("可用"));
+ }
+ for (int s = 0; s < 4; s++) {
+ PortType pt = pLoadPorts[s]->getPortType();
+ if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
+ && (pt == PortType::Unloading || pt == PortType::Both)
+ && pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
+ m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], primaryType, secondaryType);
+ if (m_pActiveRobotTask != nullptr) {
+ goto BATCH_PORT_PUT;
+ }
+ }
+ }
+
+ BATCH_PORT_PUT:
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+
+
+ // Measurement NG -> LoadPort
+ // NG回原位
+ if (!rmd.armState[1]) {
+ m_pActiveRobotTask = createTransferTask_restore(pMeasurement, pLoadPorts);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+
+ // BakeCooling ->Measurement
+ if (!rmd.armState[0]) {
+ m_pActiveRobotTask = createTransferTask_bakecooling_to_measurement(pBakeCooling, pMeasurement);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+
+ // BakeCooling内部
+ // Bake -> Cooling
+ if (!rmd.armState[0]) {
+ m_pActiveRobotTask = createTransferTask_bake_to_cooling(pBakeCooling);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+
+ // Bonder -> BakeCooling
+ if (!rmd.armState[0]) {
+ m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder1, pBakeCooling);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+ if (!rmd.armState[0]) {
+ m_pActiveRobotTask = createTransferTask_bonder_to_bakecooling(pBonder2, pBakeCooling);
+ CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+ }
+
+
+ // Fliper(G2) -> Bonder
auto pSrcSlot = pVacuumBake->getProcessedSlot(primaryType);
- if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder1->hasBondClass()) {
+ if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder1->hasBondGlass()) {
m_pActiveRobotTask = createTransferTask(pFliper, pBonder1, primaryType, secondaryType, 2);
CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
}
- if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder2->hasBondClass()) {
+ if (pSrcSlot != nullptr && !rmd.armState[1] && !pBonder2->hasBondGlass()) {
m_pActiveRobotTask = createTransferTask(pFliper, pBonder2, primaryType, secondaryType, 2);
CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
}
// VacuumBake(G1) -> Bonder
- if (!rmd.armState[0] && !pBonder1->hasBondClass()) {
+ if (!rmd.armState[0] && !pBonder1->hasBondGlass()) {
m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, primaryType, secondaryType);
CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
}
- if (!rmd.armState[0] && !pBonder2->hasBondClass()) {
+ if (!rmd.armState[0] && !pBonder2->hasBondGlass()) {
m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, primaryType, secondaryType);
CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
}
@@ -676,15 +991,38 @@
if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
&& (pt == PortType::Loading || pt == PortType::Both)
&& pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
- m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType);
+ m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, m_bJobMode);
if (m_pActiveRobotTask != nullptr) {
- pEFEM->setContext(m_pActiveRobotTask->getContext());
- goto PORT_GET;
+ CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext();
+ if (pGlass->getBuddy() != nullptr) {
+ delete m_pActiveRobotTask;
+ m_pActiveRobotTask = nullptr;
+ continue;
+ }
+
+ pEFEM->setContext(pGlass);
+ pGlass->start();
+ bool bMoved = glassFromQueueToInPorcess(pGlass);
+ if (bMoved) {
+ LOGI("<Master>Glass(%s)从等待列队到工艺列队转移成功.",
+ pGlass->getID().c_str());
+ }
+ else {
+ LOGE("<Master>Glass(%s)从等待列队到工艺列队转移失败.",
+ pGlass->getID().c_str());
+ }
+
+ // 这里上报Panel Start事件
+ if (m_listener.onPanelStart != nullptr) {
+ m_listener.onPanelStart(this, pGlass);
+ }
+
+ goto BATCH_PORT_GET;
}
}
}
-PORT_GET:
+ BATCH_PORT_GET:
CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
@@ -817,7 +1155,7 @@
// Bonder1 -> Bonder2
if ((m_nContinuousTransferStep == CTStep_Unknow || m_nContinuousTransferStep == CTStep_Fliper_Bonder1)
- && !rmd.armState[0] && !pBonder2->hasBondClass()) {
+ && !rmd.armState[0] && !pBonder2->hasBondGlass()) {
m_pActiveRobotTask = createTransferTask_continuous_transfer(pBonder1,
1, pBonder2, 1);
if (m_pActiveRobotTask != nullptr) {
@@ -829,7 +1167,7 @@
// Fliper(G2) -> Bonder1
if ((m_nContinuousTransferStep == CTStep_Unknow || m_nContinuousTransferStep == CTStep_Aligner_Fliper)
- &&!rmd.armState[0] && !pBonder1->hasBondClass()) {
+ &&!rmd.armState[0] && !pBonder1->hasBondGlass()) {
m_pActiveRobotTask = createTransferTask_continuous_transfer(pFliper,
0, pBonder1, 1);
if (m_pActiveRobotTask != nullptr) {
@@ -974,15 +1312,27 @@
BOOL bOk = FALSE;
lock();
if (m_pActiveRobotTask != nullptr) {
+ LOGI("<CMaster>onPreFethedOutJob 0001.");
if (m_pActiveRobotTask->getSrcPosition() == p->getID()) {
+ LOGI("<CMaster>onPreFethedOutJob 0002.");
CGlass* pGlass = p->getGlassFromSlot(m_pActiveRobotTask->getSrcSlot());
if (pGlass != nullptr) {
+ LOGI("<CMaster>onPreFethedOutJob 0003.");
CJobDataS* pJobDataS = pGlass->getJobDataS();
if (pJobDataS != nullptr
&& pJobDataS->getCassetteSequenceNo() == pJobDataB->getCassetteSequenceNo()
&& pJobDataS->getJobSequenceNo() == pJobDataB->getJobSequenceNo()) {
bOk = TRUE;
LOGI("<CMaster>onPreFethedOutJob, 已校验数据一致性.");
+ }
+ LOGI("<CMaster>onPreFethedOutJob 0004.");
+ if (pJobDataS != nullptr) {
+ LOGI("<CMaster>onPreFethedOutJob 0005. %d,%d,%d,%d",
+ pJobDataS->getCassetteSequenceNo(),
+ pJobDataB->getCassetteSequenceNo(),
+ pJobDataS->getJobSequenceNo(),
+ pJobDataB->getJobSequenceNo()
+ );
}
}
}
@@ -1025,7 +1375,7 @@
if (pGlass == nullptr) {
bOk = TRUE;
slot = m_pActiveRobotTask->getTarSlot();
- LOGI("<CMaster>onPreFethedOutJob, 已校验数据一致性.");
+ LOGI("<CMaster>onPreStoredJob, 已校验数据一致性.");
}
}
@@ -1036,7 +1386,7 @@
if (pGlass == nullptr && m_pActiveRobotTask->getSrcSlot() == port) {
bOk = TRUE;
slot = m_pActiveRobotTask->getSrcSlot();
- LOGI("<CMaster>onPreFethedOutJob, 已校验数据一致性.");
+ LOGI("<CMaster>onPreStoredJob, 已校验数据一致性.");
}
}
}
@@ -1094,6 +1444,50 @@
LOGI("放片完成...");
// 完成此条搬送任务,但要把数据和消息上抛应用层
+
+ // 如果是搬送回从AOI搬送回Port, 则glass工艺完成
+ if (m_pActiveRobotTask->getSrcPosition() == EQ_ID_MEASUREMENT) {
+ CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext();
+ pGlass->complete();
+ this->saveState();
+ bool bMoved = glassFromInPorcessToComplete(pGlass);
+ if (bMoved) {
+ LOGI("<Master>Glass(%s)从工艺列队到完成列队转移成功.",
+ pGlass->getID().c_str());
+ }
+ else {
+ LOGE("<Master>Glass(%s)从工艺列队到完成列队转移失败.",
+ pGlass->getID().c_str());
+ }
+ if (m_listener.onPanelEnd != nullptr) {
+ m_listener.onPanelEnd(this, pGlass);
+ }
+
+ // 检查PJ是否已经完成
+ CProcessJob* pJob = getGlassProcessJob((CGlass*)m_pActiveRobotTask->getContext());
+ if (pJob != nullptr && checkAndUpdatePjComplete(pJob)) {
+ this->saveState();
+ LOGE("<Master>ProcessJob(%s)完成.",
+ pJob->id().c_str());
+ if (m_listener.onPjEnd != nullptr) {
+ m_listener.onPjEnd(this, pJob);
+ }
+
+ // 检查CJ是否已经完成
+ ASSERT(m_pControlJob);
+ if (checkAndUpdateCjComplete(m_pControlJob)) {
+ this->saveState();
+ LOGE("<Master>ControlJob(%s)完成.",
+ m_pControlJob->id().c_str());
+ if (m_listener.onCjEnd != nullptr) {
+ m_listener.onCjEnd(this, pJob);
+ }
+ }
+ }
+ }
+
+
+
unlock();
@@ -1135,6 +1529,25 @@
};
listener.onPortStatusChanged = [&](void* pEquipment, short status, __int64 data) {
LOGE("<Master-%s>onPortStatusChanged。status=%d, data=%lld", ((CEquipment*)pEquipment)->getName().c_str(), status);
+ if (status == PORT_INUSE && m_pControlJob != nullptr) {
+ CLoadPort* pPort = (CLoadPort*)pEquipment;
+ auto pjs = m_pControlJob->getPjs();
+ for (auto pj : pjs) {
+ auto carrier = pj->getCarrier(pPort->getCassetteId());
+ if (carrier != nullptr) {
+ for (auto slot : carrier->slots) {
+ CGlass* pGlass = pPort->getGlassFromSlot(slot);
+ carrier->contexts.push_back((void*)pGlass);
+ if (pGlass != nullptr) {
+ pGlass->setProcessJob(pj);
+ }
+ }
+ }
+ }
+
+
+ }
+
if (m_listener.onLoadPortStatusChanged != nullptr) {
m_listener.onLoadPortStatusChanged(this, (CEquipment*)pEquipment, status, data);
}
@@ -1376,6 +1789,61 @@
}
}
+
+
+ // 模拟测试
+ static int aaa = 0;
+ aaa++;
+ if (aaa % 30 == 0) {
+ if (!m_queueGlasses.empty()) {
+ CGlass* pGlass = m_queueGlasses.front();
+ pGlass->start();
+ glassFromQueueToInPorcess(pGlass);
+ this->saveState();
+
+ // 这里上报Panel Start事件
+ if (m_listener.onPanelStart != nullptr) {
+ m_listener.onPanelStart(this, pGlass);
+ }
+ }
+ }
+
+ if (aaa % 45 == 0) {
+ if (!m_inProcesGlasses.empty()) {
+ CGlass* pGlass = m_inProcesGlasses.front();
+ pGlass->complete();
+ glassFromInPorcessToComplete(pGlass);
+ this->saveState();
+
+ // 这里上报Panel End事件
+ if (m_listener.onPanelEnd != nullptr) {
+ m_listener.onPanelEnd(this, pGlass);
+ }
+
+ CProcessJob* pJob = getGlassProcessJob(pGlass);
+ if (pJob != nullptr && checkAndUpdatePjComplete(pJob)) {
+ processJobFromInPorcessToComplete(pJob);
+ this->saveState();
+ LOGE("<Master>ProcessJob(%s)完成.",
+ pJob->id().c_str());
+ if (m_listener.onPjEnd != nullptr) {
+ m_listener.onPjEnd(this, pJob);
+ }
+
+ // 检查CJ是否已经完成
+ ASSERT(m_pControlJob);
+ if (checkAndUpdateCjComplete(m_pControlJob)) {
+ this->saveState();
+ LOGE("<Master>ControlJob(%s)完成.",
+ m_pControlJob->id().c_str());
+ if (m_listener.onCjEnd != nullptr) {
+ m_listener.onCjEnd(this, pJob);
+ }
+ }
+ }
+ }
+ }
+
}
void CMaster::connectEquipments()
@@ -1540,21 +2008,22 @@
static int taskSeqNo = 0;
CRobotTask* CMaster::createTransferTask(CEquipment* pSrcEq, CEquipment* pTarEq,
MaterialsType primaryType/* = MaterialsType::G1*/, MaterialsType secondaryType/* = MaterialsType::G2*/,
- int armNo/* = 1*/)
+ int armNo/* = 1*/, BOOL bJobMode/* = FALSE*/)
{
if (!pSrcEq->IsEnabled()) {
return nullptr;
}
-
CRobotTask* pTask = nullptr;
CSlot* pSrcSlot, * pTarSlot;
+ pSrcEq->m_nTestFlag = m_nTestFlag;
pTarSlot = pTarEq->getAvailableSlotForGlass(primaryType);
- pSrcSlot = pSrcEq->getProcessedSlot(primaryType);
- if (pSrcSlot == nullptr || nullptr == pTarSlot) {
+ pSrcSlot = pSrcEq->getProcessedSlot(primaryType, bJobMode);
+ if (m_nTestFlag == 1) LOGI("createTransferTask 003 %x, %x", pTarSlot, pSrcSlot);
+ if (pSrcSlot == nullptr || nullptr == pTarSlot && secondaryType != SERVO::MaterialsType::G0) {
pTarSlot = pTarEq->getAvailableSlotForGlass(secondaryType);
- pSrcSlot = pSrcEq->getProcessedSlot(secondaryType);
+ pSrcSlot = pSrcEq->getProcessedSlot(secondaryType, bJobMode);
}
-
+ if (m_nTestFlag == 1) LOGI("createTransferTask 004 %x, %x", pTarSlot, pSrcSlot);
if (pSrcSlot != nullptr && nullptr != pTarSlot) {
pTask = new CRobotTask();
@@ -1794,6 +2263,11 @@
m_isCompareMapsBeforeProceeding = bCompare;
}
+ void CMaster::setJobMode(BOOL bJobMode)
+ {
+ m_bJobMode = bJobMode;
+ }
+
void CMaster::datetimeSync(SYSTEMTIME& time)
{
for (auto item : m_listEquipment) {
@@ -1847,22 +2321,83 @@
m_nContinuousTransferCount = round;
}
- int CMaster::setProcessJobs(std::vector<SERVO::CProcessJob*>& pjs)
+ int CMaster::setProcessJobs(std::vector<CProcessJob*>& pjs)
{
std::vector<SERVO::CProcessJob*> temp;
for (auto p : pjs) {
if (p->validate(*this)) {
+ p->queue();
temp.push_back(p);
}
}
m_processJobs = temp;
- return m_processJobs.size();
+ this->saveState();
+
+ return (int)m_processJobs.size();
}
- std::vector<SERVO::CProcessJob*>& CMaster::getProcessJobs()
+ std::vector<CProcessJob*>& CMaster::getProcessJobs()
{
return m_processJobs;
+ }
+
+ CProcessJob* CMaster::getProcessJob(const std::string& id)
+ {
+ for (auto item : m_processJobs) {
+ if (item->id().compare(id) == 0) return item;
+ }
+
+ return nullptr;
+ }
+
+ int CMaster::setControlJob(CControlJob& controlJob)
+ {
+ // 回调:是否参创建ControlJob
+ auto canCreateCjFn = [&](uint32_t& cc, std::string& mm) -> bool {
+ if (m_pControlJob != nullptr) {
+ cc = 1100;
+ mm = "当前ControlJob未结批,不能创建新的ControlJob";
+ return false;
+ }
+ return true;
+ };
+
+
+ // 回调:是否存在
+ auto pjExists = [&](const std::string& id) -> bool {
+ return getProcessJob(id) != nullptr;
+ };
+
+ // 回调:是否可加入 CJ(这里定义:必须是 Queued)
+ auto pjJoinable = [&](const std::string& id) -> bool {
+ auto pj = getProcessJob(id);
+ if (pj == nullptr) return false;
+ return pj->state() == PJState::Queued;
+ };
+
+ bool bRet = controlJob.validateForCreate(canCreateCjFn, pjExists, pjJoinable);
+ if (!bRet) return -1;
+
+ std::vector<CProcessJob*> temps;
+ m_pControlJob = new CControlJob(controlJob);
+ auto pjIds = controlJob.pjIds();
+ for (auto id : pjIds) {
+ auto pj = getProcessJob(id);
+ if (pj != nullptr) {
+ temps.push_back(pj);
+ }
+ }
+ m_pControlJob->setPJs(temps);
+ this->saveState();
+
+
+ return 0;
+ }
+
+ CControlJob* CMaster::getControlJob()
+ {
+ return m_pControlJob;
}
CLoadPort* CMaster::getPortWithCarrierId(const std::string& carrierId) const
@@ -1910,4 +2445,237 @@
return true;
}
+ bool CMaster::saveState() const
+ {
+ std::ofstream ofs(m_strStatePath, std::ios::binary);
+ if (!ofs) return false;
+
+ // 文件头
+ uint32_t magic = 0x4D415354; // 'MAST'
+ uint16_t version = 1;
+ ofs.write(reinterpret_cast<const char*>(&magic), sizeof(magic));
+ ofs.write(reinterpret_cast<const char*>(&version), sizeof(version));
+
+ // 保存 ControlJob
+ bool hasCJ = (m_pControlJob != nullptr);
+ ofs.write(reinterpret_cast<const char*>(&hasCJ), sizeof(hasCJ));
+ if (hasCJ) {
+ m_pControlJob->serialize(ofs);
+ }
+
+ // 保存 ProcessJob 列表
+ uint32_t count = static_cast<uint32_t>(m_processJobs.size());
+ ofs.write(reinterpret_cast<const char*>(&count), sizeof(count));
+ for (const auto& job : m_processJobs) {
+ job->serialize(ofs);
+ }
+
+ // 以后可以在这里追加新字段
+ return true;
+ }
+
+ bool CMaster::loadState(const std::string& path)
+ {
+ // 保存文件路径
+ m_strStatePath = path;
+
+
+ std::ifstream ifs(path, std::ios::binary);
+ if (!ifs) return false;
+
+ // 文件头
+ uint32_t magic = 0;
+ uint16_t version = 0;
+ ifs.read(reinterpret_cast<char*>(&magic), sizeof(magic));
+ ifs.read(reinterpret_cast<char*>(&version), sizeof(version));
+
+ if (magic != 0x4D415354) {
+ // 文件不合法
+ return false;
+ }
+
+ if (m_pControlJob != nullptr) {
+ delete m_pControlJob;
+ m_pControlJob = nullptr;
+ }
+
+ // 读取 ControlJob
+ bool hasCJ = false;
+ ifs.read(reinterpret_cast<char*>(&hasCJ), sizeof(hasCJ));
+ if (hasCJ) {
+ m_pControlJob = new CControlJob();
+ if (!CControlJob::deserialize(ifs, *m_pControlJob)) return false;
+ }
+ else {
+ return false;
+ }
+
+ // 读取 ProcessJob 列表
+ uint32_t count = 0;
+ ifs.read(reinterpret_cast<char*>(&count), sizeof(count));
+ m_processJobs.clear();
+ for (uint32_t i = 0; i < count; i++) {
+ CProcessJob* pProcessJob = new CProcessJob();
+ if (!CProcessJob::deserialize(ifs, *pProcessJob)) return false;
+ m_processJobs.push_back(pProcessJob);
+ }
+
+
+ // 找到CProcessJob指针加入列表中
+ std::vector<CProcessJob*> tempPjs;
+ auto ids = m_pControlJob->pjIds();
+ for (auto id : ids) {
+ auto pj = getProcessJob(id);
+ if (pj != nullptr) {
+ tempPjs.push_back(pj);
+ }
+ }
+ m_pControlJob->setPJs(tempPjs);
+
+
+ // 如果版本升级,可在这里判断 version 来加载新字段
+
+
+ return true;
+ }
+
+ CProcessJob* CMaster::acquireNextProcessJob()
+ {
+ auto& pjs = m_pControlJob->getPjs();
+ for (const auto pj : pjs) {
+ if (pj->state() == PJState::Queued) {
+ pj->start();
+ return pj;
+ }
+ }
+
+
+ return nullptr;
+ }
+
+ CGlass* CMaster::acquireNextGlass()
+ {
+ for (auto* pj : m_inProcesJobs) {
+ // 遍历 PJ 的 carriers 和 slots
+ for (auto& cs : pj->carriers()) {
+ for (auto ctx : cs.contexts) {
+ CGlass* pGlass = (CGlass*)ctx;
+ if (pGlass->state() == GlsState::NoState) {
+ pGlass->queue();
+ return pGlass;
+ }
+ }
+ }
+ }
+ return nullptr; // 没有可加工的 Glass
+ }
+
+ int CMaster::acquireGlassToQueue()
+ {
+ int nCount = 0;
+ for (auto* pj : m_inProcesJobs) {
+ // 遍历 PJ 的 carriers 和 slots
+ for (auto& cs : pj->carriers()) {
+ for (auto ctx : cs.contexts) {
+ CGlass* pGlass = (CGlass*)ctx;
+ if (pGlass->state() == GlsState::NoState) {
+ pGlass->queue();
+ if(addGlassToQueue(pGlass)) nCount++;
+ }
+ }
+ }
+ }
+ return nCount;
+ }
+
+ bool CMaster::addGlassToQueue(CGlass* pGlass)
+ {
+ for (auto g : m_queueGlasses) {
+ if (g == pGlass) return false;
+ }
+
+ m_queueGlasses.push_back(pGlass);
+ return true;
+ }
+
+ bool CMaster::glassFromQueueToInPorcess(CGlass* pGlass)
+ {
+ auto it = std::find(m_queueGlasses.begin(), m_queueGlasses.end(), pGlass);
+ if (it != m_queueGlasses.end()) {
+ m_inProcesGlasses.push_back(*it);
+ m_queueGlasses.erase(it);
+ return true;
+ }
+ return false;
+ }
+
+ bool CMaster::glassFromInPorcessToComplete(CGlass* pGlass)
+ {
+ auto it = std::find(m_inProcesGlasses.begin(), m_inProcesGlasses.end(), pGlass);
+ if (it != m_inProcesGlasses.end()) {
+ m_completeGlasses.push_back(*it);
+ m_inProcesGlasses.erase(it);
+ return true;
+ }
+ return false;
+ }
+
+ bool CMaster::processJobFromInPorcessToComplete(CProcessJob* pProcessJob)
+ {
+ auto it = std::find(m_inProcesJobs.begin(), m_inProcesJobs.end(), pProcessJob);
+ if (it != m_inProcesJobs.end()) {
+ m_completeProcessJobs.push_back(*it);
+ m_inProcesJobs.erase(it);
+ return true;
+ }
+ return false;
+ }
+
+ bool CMaster::checkAndUpdatePjComplete(CProcessJob* pJob)
+ {
+ ASSERT(pJob);
+ auto state = pJob->state();
+ if (state != PJState::InProcess && state != PJState::Paused) return false;
+
+ for (auto c : pJob->carriers()) {
+ for (auto g : c.contexts) {
+ auto state = ((CGlass*)g)->state();
+ if (state != GlsState::Aborted && state != GlsState::Completed
+ && state != GlsState::Failed) return false;
+ }
+ }
+
+ return pJob->complete();
+ }
+
+ bool CMaster::checkAndUpdateCjComplete(CControlJob* pJob)
+ {
+ ASSERT(pJob);
+ auto state = pJob->state();
+ if (state != CJState::Executing && state != CJState::Paused) return false;
+
+ for (auto pj : pJob->getPjs()) {
+ auto state = pj->state();
+ if (state != PJState::Aborted && state != PJState::Completed
+ && state != PJState::Failed) {
+ return false;
+ }
+ }
+
+ return pJob->complete();
+ }
+
+ CProcessJob* CMaster::getGlassProcessJob(CGlass* pGlass)
+ {
+ if (m_pControlJob == nullptr) return nullptr;
+ for (auto pj : m_pControlJob->getPjs()) {
+ for (auto c : pj->carriers()) {
+ for (auto g : c.contexts) {
+ if (g == pGlass) return pj;
+ }
+ }
+ }
+
+ return nullptr;
+ }
}
--
Gitblit v1.9.3