From 10f48622c553729352dce9a4484def4bfeaa1083 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期三, 02 七月 2025 14:51:33 +0800
Subject: [PATCH] 1.将OnPanelDataReport相关功能由EFEM移到Aligner; 2.Glass增加最初来源Port和Slot,以便在Aligner检测NG时加退; 3.物流调度增加一个参数,是否检测OK作为调度依据。 4.Alginer检测NG,送回原处;

---
 SourceCode/Bond/Servo/Servo.vcxproj  |    4 
 SourceCode/Bond/Servo/CGlass.cpp     |   44 +++++
 SourceCode/Bond/Servo/CGlass.h       |    8 +
 SourceCode/Bond/Servo/CPath.cpp      |   18 ++
 SourceCode/Bond/Servo/CMaster.h      |    3 
 SourceCode/Bond/Servo/CLoadPort.cpp  |   63 ++++----
 SourceCode/Bond/Servo/CPath.h        |    4 
 SourceCode/Bond/Servo/CAligner.cpp   |   28 ++++
 SourceCode/Bond/Servo/CEquipment.cpp |   58 ++++++--
 SourceCode/Bond/Servo/CAligner.h     |    2 
 SourceCode/Bond/Servo/CEFEM.cpp      |   19 --
 SourceCode/Bond/Servo/CMaster.cpp    |  103 ++++++++++++--
 SourceCode/Bond/Servo/CEquipment.h   |    7 +
 SourceCode/Bond/Servo/ServoCommo.h   |   26 +++
 14 files changed, 294 insertions(+), 93 deletions(-)

diff --git a/SourceCode/Bond/Servo/CAligner.cpp b/SourceCode/Bond/Servo/CAligner.cpp
index c15885e..815b1ee 100644
--- a/SourceCode/Bond/Servo/CAligner.cpp
+++ b/SourceCode/Bond/Servo/CAligner.cpp
@@ -48,6 +48,34 @@
 		m_slot[0].setName("Slot 1");
 	}
 
+	void CAligner::initSteps()
+	{
+		CEquipment::initSteps();
+
+		{
+			// Panel Data Report
+			CEqReadStep* pStep = new CEqReadStep(0x617f, 386 * 2,
+				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
+					if (code == ROK && pszData != nullptr && size > 0) {
+						decodePanelDataReport((CStep*)pFrom, pszData, size);
+					}
+					return -1;
+				});
+			pStep->setName(STEP_EQ_PANEL_DATA_REPORT);
+			pStep->setProp("Port", (void*)1);
+			pStep->setWriteSignalDev(0x15e);
+			if (addStep(STEP_ID_PANEL_DATA_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+	}
+
+	void CAligner::onReceiveLBData(const char* pszData, size_t size)
+	{
+		__super::onReceiveLBData(pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PANEL_DATA_REPORT, pszData, size);
+	}
+
 	void CAligner::onTimer(UINT nTimerid)
 	{
 		CEquipment::onTimer(nTimerid);
diff --git a/SourceCode/Bond/Servo/CAligner.h b/SourceCode/Bond/Servo/CAligner.h
index a1ce3be..a6081ca 100644
--- a/SourceCode/Bond/Servo/CAligner.h
+++ b/SourceCode/Bond/Servo/CAligner.h
@@ -16,6 +16,8 @@
         virtual void term();
         virtual void initPins();
         virtual void initSlots();
+        virtual void initSteps();
+        virtual void onReceiveLBData(const char* pszData, size_t size);
         virtual void onTimer(UINT nTimerid);
         virtual void serialize(CArchive& ar);
         virtual void getAttributeVector(CAttributeVector& attrubutes);
diff --git a/SourceCode/Bond/Servo/CEFEM.cpp b/SourceCode/Bond/Servo/CEFEM.cpp
index fdaf6c1..941b834 100644
--- a/SourceCode/Bond/Servo/CEFEM.cpp
+++ b/SourceCode/Bond/Servo/CEFEM.cpp
@@ -677,23 +677,6 @@
 		}
 
 		{
-			// Panel Data Report
-			CEqReadStep* pStep = new CEqReadStep(0x617f, 386 * 2,
-				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
-					if (code == ROK && pszData != nullptr && size > 0) {
-						decodePanelDataReport((CStep*)pFrom, pszData, size);
-					}
-					return -1;
-				});
-			pStep->setName(STEP_EQ_PANEL_DATA_REPORT);
-			pStep->setProp("Port", (void*)1);
-			pStep->setWriteSignalDev(0x15e);
-			if (addStep(STEP_ID_PANEL_DATA_REPORT, pStep) != 0) {
-				delete pStep;
-			}
-		}
-
-		{
 			// FAC Data Report
 			CEqReadStep* pStep = new CEqReadStep(0x6301, 108 * 2,
 				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
@@ -804,6 +787,8 @@
 				m_pPort[i]->onReceiveLBData(pszData, size);
 			}
 		}
+		m_pAligner->onReceiveLBData(pszData, size);
+
 
 		// 更新信号到LoadPort, Robot, Aligner, Fliper
 		m_pPort[0]->setLinkSignalUpstreamBlock(0, &m_bLinkSignalToUpstream[0][0]);
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index bef7c8d..70c6134 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -7,22 +7,6 @@
 #include "Servo.h"
 
 
-#define CHECK_READ_STEP_SIGNAL(addr, data, size) {							\
-	BOOL bFlag = isBitOn(data, size, addr);									\
-	SERVO::CStep* pStep = getStep(addr);									\
-	if (pStep != nullptr) {													\
-		((CReadStep*)pStep)->onReadSignal(bFlag ? addr : 0);				\
-	}																		\
-}
-
-#define CHECK_WRITE_STEP_SIGNAL(addr, data, size) {							\
-	BOOL bFlag = isBitOn(data, size, addr);									\
-	SERVO::CStep* pStep = getStep(addr);									\
-	if (pStep != nullptr) {													\
-		((CWriteStep*)pStep)->onRecvSignal(bFlag ? addr : 0);				\
-	}																		\
-}
-
 namespace SERVO {
 
 	CEquipment::CEquipment() : m_nID(0), m_strName(""), m_strDescription(""), m_station(0, 255)
@@ -1313,6 +1297,7 @@
 			CGlass* pGlass = (CGlass*)m_slot[i].getContext();
 			if (!isSlotProcessed(i)) continue;
 			if (pGlass == nullptr) continue;
+			if(pGlass->getInspResult(m_nID, 0) == InspResult::Fail) continue;
 			int lsPath = m_slot[i].getLinkSignalPath();
 			if(!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
 				|| m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
@@ -1352,6 +1337,26 @@
 					return &m_slot[i];
 				}
 			}
+		}
+
+		return nullptr;
+	}
+
+	CSlot* CEquipment::getInspFailSlot()
+	{
+		for (int i = 0; i < SLOT_MAX; i++) {
+			if (!m_slot[i].isEnable()) continue;
+			if (m_slot[i].isLock()) continue;
+			CGlass* pGlass = (CGlass*)m_slot[i].getContext();
+			if (pGlass == nullptr) continue;
+			if (pGlass->getInspResult(m_nID, 0) != InspResult::Fail) continue;
+			int lsPath = m_slot[i].getLinkSignalPath();
+			if (!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
+				|| m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
+				|| !m_bLinkSignalToUpstream[lsPath][SIGNAL_INTERLOCK]
+				|| !m_bLinkSignalToUpstream[lsPath][SIGNAL_SEND_ABLE]) continue;
+
+			return &m_slot[i];
 		}
 
 		return nullptr;
@@ -1634,6 +1639,15 @@
 		pStep->addAttribute(new CAttribute("PanelGradeData",
 			strPanelGradeData.c_str(), "", weight++));
 
+
+		// 更新检测结果
+		CGlass* pGlass = getGlassWithCassette(cassetteNo, jobSequenceNo);
+		if (pGlass == nullptr) {
+			LOGE("<CEquipment-%s>更新Panel Data失败,找不到对应的Glass.cassetteNo=%d, jobSequenceNo=%d",
+				getName().c_str(), cassetteNo, jobSequenceNo);
+			return -1;
+		}
+		pGlass->setInspResult(m_nID, 0, judgeStringToInspResult(strPanelJudgeData));
 
 		return 0;
 	}
@@ -1974,4 +1988,16 @@
 			);
 		}
 	}
+
+	InspResult CEquipment::judgeStringToInspResult(std::string& strJudge)
+	{
+		if (strJudge.compare("N") == 0) {
+			return InspResult::Fail;
+		}
+		if (strJudge.compare("G") == 0) {
+			return InspResult::Pass;
+		}
+
+		return InspResult::NotInspected;
+	}
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index f7ca3bc..465354d 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -179,6 +179,7 @@
 		// 获取一个指定物料类型(G1,G2,G1&G2)的且已经加工处理的槽位
 		CSlot* getProcessedSlot(MaterialsType putSlotType);
 		CSlot* getProcessedSlot2(MaterialsType putSlotType, const std::vector<int>& candidates);
+		CSlot* getInspFailSlot();
 
 		// 获取玻璃物料
 		CGlass* getGlassFromSlot(int slotNo);
@@ -199,6 +200,12 @@
 		// 手动移除物料
 		int removeGlass(int slotNo);
 
+		// 字符串检测结果转换
+		InspResult judgeStringToInspResult(std::string& strJudge);
+
+
+
+
 	// 以下为从CC-Link读取到的Bit标志位检测函数
 	public:
 		BOOL isAlive();
diff --git a/SourceCode/Bond/Servo/CGlass.cpp b/SourceCode/Bond/Servo/CGlass.cpp
index a88255a..6d1a1ee 100644
--- a/SourceCode/Bond/Servo/CGlass.cpp
+++ b/SourceCode/Bond/Servo/CGlass.cpp
@@ -8,6 +8,8 @@
 		m_pPath = nullptr;
 		m_type = MaterialsType::G1;
 		m_pBuddy = nullptr;
+		m_nOriginPort = 0;
+		m_nOriginSlot = 0;
 	}
 
 	CGlass::~CGlass()
@@ -66,6 +68,18 @@
 		return m_strID;
 	}
 
+	void CGlass::setOriginPort(int port, int slot)
+	{
+		m_nOriginPort = port;
+		m_nOriginSlot = slot;
+	}
+
+	void CGlass::getOrginPort(int& port, int& slot)
+	{
+		port = m_nOriginPort;
+		slot = m_nOriginSlot;
+	}
+
 	CPath* CGlass::getPath()
 	{
 		return m_pPath;
@@ -103,6 +117,8 @@
 			Lock();
 			ar << (int)m_type;
 			WriteString(ar, m_strID);
+			ar << m_nOriginPort;
+			ar << m_nOriginSlot;
 			ar << (ULONGLONG)m_pPath;
 			if (m_pPath != nullptr) {
 				m_pPath->serialize(ar);
@@ -123,6 +139,8 @@
 			ar >> type;
 			m_type = (MaterialsType)type;
 			ReadString(ar, m_strID);
+			ar >> m_nOriginPort;
+			ar >> m_nOriginSlot;
 			ar >> ullPath;
 			if (ullPath != 0) {
 				m_pPath = new CPath();
@@ -182,12 +200,13 @@
 		return m_strBuddyId;
 	}
 
-	void CGlass::processEnd(unsigned int nEqId, unsigned int nUnit)
+	int CGlass::processEnd(unsigned int nEqId, unsigned int nUnit)
 	{
 		CPath* pPath = getPathWithEq(nEqId, nUnit);
-		if (pPath != nullptr) {
-			pPath->processEnd();
-		}
+		if (pPath == nullptr) return -1;
+
+		pPath->processEnd();
+		return 0;
 	}
 
 	BOOL CGlass::isProcessed(unsigned int nEqId, unsigned int nUnit)
@@ -197,4 +216,21 @@
 
 		return pPath->isProcessEnd();
 	}
+
+	int CGlass::setInspResult(unsigned int nEqId, unsigned int nUnit, InspResult result)
+	{
+		CPath* pPath = getPathWithEq(nEqId, nUnit);
+		if (pPath == nullptr) return -1;
+			
+		pPath->setInspResult(result);
+		return 0;
+	}
+
+	InspResult CGlass::getInspResult(unsigned int nEqId, unsigned int nUnit)
+	{
+		CPath* pPath = getPathWithEq(nEqId, nUnit);
+		if (pPath == nullptr) return InspResult::NotInspected;
+
+		return pPath->getInspResult();
+	}
 }
diff --git a/SourceCode/Bond/Servo/CGlass.h b/SourceCode/Bond/Servo/CGlass.h
index f5e1945..3127839 100644
--- a/SourceCode/Bond/Servo/CGlass.h
+++ b/SourceCode/Bond/Servo/CGlass.h
@@ -24,6 +24,8 @@
 		void setType(MaterialsType type);
 		void setID(const char* pszID);
 		std::string& getID();
+		void setOriginPort(int port, int slot);
+		void getOrginPort(int& port, int& slot);
 		CPath* getPathWithEq(unsigned int nEqId, unsigned int nUnit);
 		CPath* getPath();
 		void addPath(unsigned int nEqId, unsigned int nUnit);
@@ -35,8 +37,10 @@
 		BOOL forceSetBuddy(CGlass* pGlass);
 		CGlass* getBuddy();
 		std::string& getBuddyId();
-		void processEnd(unsigned int nEqId, unsigned int nUnit);
+		int processEnd(unsigned int nEqId, unsigned int nUnit);
 		BOOL isProcessed(unsigned int nEqId, unsigned int nUnit);
+		int setInspResult(unsigned int nEqId, unsigned int nUnit, InspResult result);
+		InspResult getInspResult(unsigned int nEqId, unsigned int nUnit);
 
 	private:
 		MaterialsType m_type;
@@ -45,6 +49,8 @@
 		CJobDataS m_jobDataS;
 		CGlass* m_pBuddy;
 		std::string m_strBuddyId;
+		int m_nOriginPort;
+		int m_nOriginSlot;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CLoadPort.cpp b/SourceCode/Bond/Servo/CLoadPort.cpp
index aa096e3..f6afed4 100644
--- a/SourceCode/Bond/Servo/CLoadPort.cpp
+++ b/SourceCode/Bond/Servo/CLoadPort.cpp
@@ -2,23 +2,8 @@
 #include "CLoadPort.h"
 #include "CGlassPool.h"
 #include "Servo.h"
+#include "ServoCommo.h"
 
-
-#define CHECK_READ_STEP_SIGNAL2(addr, data, size) {							\
-	BOOL bFlag = isBitOn(data, size, addr);									\
-	SERVO::CStep* pStep = getStep(addr);									\
-	if (pStep != nullptr) {													\
-		((CReadStep*)pStep)->onReadSignal(bFlag ? addr : 0);				\
-	}																		\
-}
-
-#define CHECK_WRITE_STEP_SIGNAL2(addr, data, size) {							\
-	BOOL bFlag = isBitOn(data, size, addr);									\
-	SERVO::CStep* pStep = getStep(addr);									\
-	if (pStep != nullptr) {													\
-		((CWriteStep*)pStep)->onRecvSignal(bFlag ? addr : 0);				\
-	}																		\
-}
 
 namespace SERVO {
 	CLoadPort::CLoadPort() : CEquipment()
@@ -429,15 +414,18 @@
 		SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getCassetteCtrlCmdStep();
 		ASSERT(pStep);
 
-		ASSERT(jobExistenceSize == 12);
-		ASSERT(pJobDataA);
-
 		char szBuffer[1024] = { 0 };
 		memcpy(&szBuffer[0], &cmd, sizeof(short));
-		memcpy(&szBuffer[2], jobExistence, sizeof(short) * jobExistenceSize);
+		if (jobExistence != nullptr && jobExistenceSize == 12) {
+			memcpy(&szBuffer[2], jobExistence, sizeof(short) * jobExistenceSize);
+		}
+
 		memcpy(&szBuffer[26], &slotProcess, sizeof(short));
 		memcpy(&szBuffer[36], &jopCount, sizeof(short));
-		int nLen = pJobDataA->serialize(&szBuffer[38], 1024 - 38);
+		if (pJobDataA != nullptr) {
+			pJobDataA->serialize(&szBuffer[38], 1024 - 38);
+		}
+
 		return pStep->writeDataEx(szBuffer, 352 * 2, onWritedBlock);
 	}
 
@@ -860,12 +848,12 @@
 		static int autoType[] = { STEP_ID_PORT1_TYPE_AUTO_CHANGE, STEP_ID_PORT2_TYPE_AUTO_CHANGE,
 			STEP_ID_PORT3_TYPE_AUTO_CHANGE, STEP_ID_PORT4_TYPE_AUTO_CHANGE };
 
-		CHECK_READ_STEP_SIGNAL2(type[m_nIndex], pszData, size);
-		CHECK_READ_STEP_SIGNAL2(mode[m_nIndex], pszData, size);
-		CHECK_READ_STEP_SIGNAL2(cassetteType[m_nIndex], pszData, size);
-		CHECK_READ_STEP_SIGNAL2(transferMode[m_nIndex], pszData, size);
-		CHECK_READ_STEP_SIGNAL2(enable[m_nIndex], pszData, size);
-		CHECK_READ_STEP_SIGNAL2(autoType[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL(type[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL(mode[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL(cassetteType[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL(transferMode[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL(enable[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL(autoType[m_nIndex], pszData, size);
 
 
 		static int typeReply[] = { STEP_ID_PROT1_TYPE_CHANGE_REPLY, STEP_ID_PROT2_TYPE_CHANGE_REPLY,
@@ -881,12 +869,12 @@
 		static int cassetteTypeReply[] = { STEP_ID_PROT1_CASSETTE_TYPE_CHANGE_REPLY, STEP_ID_PROT2_CASSETTE_TYPE_CHANGE_REPLY,
 			STEP_ID_PROT3_CASSETTE_TYPE_CHANGE_REPLY, STEP_ID_PROT4_CASSETTE_TYPE_CHANGE_REPLY };
 
-		CHECK_WRITE_STEP_SIGNAL2(typeReply[m_nIndex], pszData, size);
-		CHECK_WRITE_STEP_SIGNAL2(modeReply[m_nIndex], pszData, size);
-		CHECK_WRITE_STEP_SIGNAL2(transferModeReply[m_nIndex], pszData, size);
-		CHECK_WRITE_STEP_SIGNAL2(enableModeReply[m_nIndex], pszData, size);
-		CHECK_WRITE_STEP_SIGNAL2(typeAutoReply[m_nIndex], pszData, size);
-		CHECK_WRITE_STEP_SIGNAL2(cassetteTypeReply[m_nIndex], pszData, size);
+		CHECK_WRITE_STEP_SIGNAL(typeReply[m_nIndex], pszData, size);
+		CHECK_WRITE_STEP_SIGNAL(modeReply[m_nIndex], pszData, size);
+		CHECK_WRITE_STEP_SIGNAL(transferModeReply[m_nIndex], pszData, size);
+		CHECK_WRITE_STEP_SIGNAL(enableModeReply[m_nIndex], pszData, size);
+		CHECK_WRITE_STEP_SIGNAL(typeAutoReply[m_nIndex], pszData, size);
+		CHECK_WRITE_STEP_SIGNAL(cassetteTypeReply[m_nIndex], pszData, size);
 	}
 
 	int CLoadPort::decodePortStatusReport(CStep* pStep, const char* pszData, size_t size)
@@ -895,6 +883,11 @@
 		int nRet = portStatusReport.unserialize(&pszData[0], (int)size);
 		if (nRet < 0) return nRet;
 		m_portStatusReport.copyEx(portStatusReport);
+
+		if (m_portStatusReport.getPortStatus() == PORT_INUSE) {
+			this->sendCassetteCtrlCmd(5, nullptr, 0, 0, 0, nullptr, nullptr);
+		}
+
 
 
 		// 缓存Attribute,用于调试时显示信息
@@ -909,6 +902,8 @@
 			LOGI("<CCassetteTranserStateStep>InUse<JobExistenceSlot:%d>",
 				m_portStatusReport.getJobExistenceSlot());
 		}
+
+
 		return nRet;
 	}
 
@@ -1144,6 +1139,7 @@
 			js.setMaterialsType((int)type);
 
 			CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
+			pGlass->setOriginPort(m_nIndex, i);
 			pGlass->addPath(m_nID, 0);
 			pGlass->processEnd(m_nID, 0);
 			pGlass->setID(szBuffer);
@@ -1182,6 +1178,7 @@
 			js.setGlass1Id(szBuffer);
 
 			CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
+			pGlass->setOriginPort(m_nIndex, nSlotIndex);
 			pGlass->addPath(m_nID, 0);
 			pGlass->processEnd(m_nID, 0);
 			pGlass->setID(szBuffer);
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index cba74ae..6fd1c50 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -297,11 +297,12 @@
 
 
 		// 各种机器
+		CLoadPort* pLoadPorts[4];
 		CEFEM* pEFEM = (CEFEM*)getEquipment(EQ_ID_EFEM);
-		CLoadPort* pLoadPort1 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT1);
-		CLoadPort* pLoadPort2 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT2);
-		CLoadPort* pLoadPort3 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT3);
-		CLoadPort* pLoadPort4 = (CLoadPort*)getEquipment(EQ_ID_LOADPORT4);
+		pLoadPorts[0] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT1);
+		pLoadPorts[1] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT2);
+		pLoadPorts[2] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT3);
+		pLoadPorts[3] = (CLoadPort*)getEquipment(EQ_ID_LOADPORT4);
 		CFliper* pFliper = (CFliper*)getEquipment(EQ_ID_FLIPER);
 		CVacuumBake* pVacuumBake = (CVacuumBake*)getEquipment(EQ_ID_VACUUMBAKE);
 		CAligner* pAligner = (CAligner*)getEquipment(EQ_ID_ALIGNER);
@@ -311,10 +312,10 @@
 		CMeasurement* pMeasurement = (CMeasurement*)getEquipment(EQ_ID_MEASUREMENT);
 
 		ASSERT(pEFEM);
-		ASSERT(pLoadPort1);
-		ASSERT(pLoadPort2);
-		ASSERT(pLoadPort3);
-		ASSERT(pLoadPort4);
+		ASSERT(pLoadPorts[0]);
+		ASSERT(pLoadPorts[1]);
+		ASSERT(pLoadPorts[2]);
+		ASSERT(pLoadPorts[3]);
 		ASSERT(pFliper);
 		ASSERT(pVacuumBake);
 		ASSERT(pAligner);
@@ -544,17 +545,16 @@
 					LOGI("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
 						rmd.armState[1] ? _T("不可用") : _T("可用"));
 				}
-				CLoadPort* pEqLoadPort[] = { pLoadPort1, pLoadPort2, pLoadPort3, pLoadPort4 };
 				CEquipment* pEqTar[] = { pVacuumBake, pFliper };
 				if (primaryType == MaterialsType::G2) {
 					pEqTar[0] = pFliper;
 					pEqTar[1] = pVacuumBake;
 				}
 				for (int s = 0; s < 4; s++) {
-					if (!rmd.armState[0] && pEqLoadPort[s]->isEnable()
-						&& pEqLoadPort[s]->getPortType() == PortType::Unloading
-						&& pEqLoadPort[s]->getPortMode() == PortMode::ReadyToUnload) {
-						m_pActiveRobotTask = createTransferTask(pMeasurement, pEqLoadPort[s], primaryType, secondaryType);
+					if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
+						&& pLoadPorts[s]->getPortType() == PortType::Unloading
+						&& pLoadPorts[s]->getPortMode() == PortMode::ReadyToUnload) {
+						m_pActiveRobotTask = createTransferTask(pMeasurement, pLoadPorts[s], primaryType, secondaryType);
 						if (m_pActiveRobotTask != nullptr) {
 							goto PORT_PUT;
 						}
@@ -572,6 +572,25 @@
 					LOGI("创建新任务<%s>...", strDescription.c_str());
 					continue;
 				}
+
+
+				// Measurement NG -> LoadPort
+				// NG回原位
+				if (!rmd.armState[1]) {
+					m_pActiveRobotTask = createTransferTask_restore(pMeasurement, pLoadPorts);
+					if (m_pActiveRobotTask != nullptr) {
+						m_pActiveRobotTask->pick();
+						std::string strDescription = m_pActiveRobotTask->getDescription();
+						unlock();
+						if (m_listener.onRobotTaskEvent != nullptr) {
+							m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
+						}
+						LOGI("创建Measurement回退任务<%s>...", strDescription.c_str());
+						continue;
+					}
+				}
+
+
 
 
 				// BakeCooling ->Measurement
@@ -727,12 +746,30 @@
 					}
 				}
 
+				// Aligner -> LoadPort
+				if (!rmd.armState[1]) {
+					m_pActiveRobotTask = createTransferTask_restore(pAligner, pLoadPorts);
+					if (m_pActiveRobotTask != nullptr) {
+						m_pActiveRobotTask->pick();
+						std::string strDescription = m_pActiveRobotTask->getDescription();
+						unlock();
+						if (m_listener.onRobotTaskEvent != nullptr) {
+							m_listener.onRobotTaskEvent(this, m_pActiveRobotTask, ROBOT_EVENT_CREATE);
+						}
+						LOGI("创建Aligner回退任务<%s>...", strDescription.c_str());
+						continue;
+					}
+				}
+
+
+
+
 				// LoadPort -> Aligner
 				for (int s = 0; s < 4; s++) {
-					if (!rmd.armState[0] && pEqLoadPort[s]->isEnable()
-						&& pEqLoadPort[s]->getPortType() == PortType::Loading
-						&& pEqLoadPort[s]->getPortMode() == PortMode::ReadyToLoad) {
-						m_pActiveRobotTask = createTransferTask(pEqLoadPort[s], pAligner, primaryType, secondaryType);
+					if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
+						&& pLoadPorts[s]->getPortType() == PortType::Loading
+						&& pLoadPorts[s]->getPortMode() == PortMode::ReadyToLoad) {
+						m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType);
 						if (m_pActiveRobotTask != nullptr) {
 							pEFEM->setContext(m_pActiveRobotTask->getContext());
 							goto PORT_GET;
@@ -1454,6 +1491,38 @@
 		return pTask;
 	}
 
+	CRobotTask* CMaster::createTransferTask_restore(CEquipment* pEqSrc, CLoadPort** pPorts)
+	{
+		CRobotTask* pTask = nullptr;
+		CSlot* pSrcSlot, * pTarSlot = nullptr, * pTempSlot;
+		pSrcSlot = pEqSrc->getInspFailSlot();
+		if (pSrcSlot != nullptr) {
+			CGlass* pGlass = (CGlass*)pSrcSlot->getContext();
+			ASSERT(pGlass);
+			int port, slot;
+			pGlass->getOrginPort(port, slot);
+			pGlass->setInspResult(pPorts[port]->getID(), 0, InspResult::Fail);
+			ASSERT(0 <= port && port < 4);
+			ASSERT(0 <= slot && slot < 8);
+			pTempSlot = pPorts[port]->getSlot(slot);
+			if (pTempSlot->getContext() == nullptr) {
+				pTarSlot = pTempSlot;
+			}
+		}
+
+
+		if (pSrcSlot != nullptr && nullptr != pTarSlot) {
+			pTask = new CRobotTask();
+			pTask->setContext(pSrcSlot->getContext());
+			pTask->setEFEM((CEFEM*)getEquipment(EQ_ID_EFEM));
+			taskSeqNo = pTask->setRobotTransferParam(taskSeqNo, 1, pSrcSlot->getPosition(),
+				pTarSlot->getPosition(), pSrcSlot->getNo(), pTarSlot->getNo());
+		}
+
+
+		return pTask;
+	}
+
 	int CMaster::abortCurrentTask()
 	{
 		lock();
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index 4ff2252..37ff05b 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -96,7 +96,8 @@
         CRobotTask* createTransferTask_bonder_to_bakecooling(CEquipment* pSrcEq, CEquipment* pTarEq);
         CRobotTask* createTransferTask_bake_to_cooling(CEquipment* pSrcEq);
         CRobotTask* createTransferTask_bakecooling_to_measurement(CEquipment* pSrcEq, CEquipment* pTarEq);
-
+        CRobotTask* createTransferTask_restore(CEquipment* pEqSrc, CLoadPort** pPorts);
+ 
     private:
         CRITICAL_SECTION m_criticalSection;
         MasterListener m_listener;
diff --git a/SourceCode/Bond/Servo/CPath.cpp b/SourceCode/Bond/Servo/CPath.cpp
index 3eb286b..6f71f45 100644
--- a/SourceCode/Bond/Servo/CPath.cpp
+++ b/SourceCode/Bond/Servo/CPath.cpp
@@ -10,6 +10,7 @@
 		m_timeOut = 0;
 		m_timeIn = CToolUnits::getTimestamp();
 		m_bProcessed = FALSE;
+		m_inspResult = InspResult::NotInspected;
 		m_pPrev = nullptr;
 		m_pNext = nullptr;
 	}
@@ -20,9 +21,10 @@
 		m_nUnit = nUnit;
 		m_timeOut = 0;
 		m_timeIn = CToolUnits::getTimestamp();
+		m_bProcessed = FALSE;
+		m_inspResult = InspResult::NotInspected;
 		m_pPrev = nullptr;
 		m_pNext = nullptr;
-		m_bProcessed = FALSE;
 	}
 
 	CPath::~CPath()
@@ -52,17 +54,21 @@
 			ar << m_timeIn;
 			ar << m_timeOut;
 			ar << m_bProcessed;
+			ar << (int)m_inspResult;
 			ar << (ULONGLONG)m_pNext;
 			if (m_pNext != nullptr) {
 				m_pNext->serialize(ar);
 			}
 		}
 		else {
+			int temp;
+
 			ar >> m_nEqID;
 			ar >> m_nUnit;
 			ar >> m_timeIn;
 			ar >> m_timeOut;
 			ar >> m_bProcessed;
+			ar >> temp; m_inspResult = (InspResult)temp;
 			ULONGLONG ulNext;
 			ar >> ulNext;
 			if ((CPath*)ulNext != nullptr) {
@@ -109,6 +115,16 @@
 		return m_bProcessed;
 	}
 
+	void CPath::setInspResult(InspResult result)
+	{
+		m_inspResult = result;
+	}
+
+	InspResult CPath::getInspResult()
+	{
+		return m_inspResult;
+	}
+
 	CPath* CPath::getPrev()
 	{
 		return m_pPrev;
diff --git a/SourceCode/Bond/Servo/CPath.h b/SourceCode/Bond/Servo/CPath.h
index 577d07a..2c96c49 100644
--- a/SourceCode/Bond/Servo/CPath.h
+++ b/SourceCode/Bond/Servo/CPath.h
@@ -1,4 +1,5 @@
 #pragma once
+#include "ServoCommo.h"
 
 
 namespace SERVO {
@@ -24,6 +25,8 @@
 		ULONGLONG getOutTime();
 		void processEnd();
 		BOOL isProcessEnd();
+		void setInspResult(InspResult result);
+		InspResult getInspResult();
 
 	private:	
 		unsigned int m_nEqID;
@@ -31,6 +34,7 @@
 		ULONGLONG m_timeIn;
 		ULONGLONG m_timeOut;
 		BOOL m_bProcessed;
+		InspResult m_inspResult;
 		CPath* m_pPrev;
 		CPath* m_pNext;
 	};
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 4eddc5d..c3e7398 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -135,8 +135,8 @@
     </ResourceCompile>
     <PostBuildEvent>
       <Command>if exist "\\DESKTOP-IODBVIQ\Servo\Debug\" (
-    xcopy /Y /D "$(OutDir)*.exe" "\\DESKTOP-IODBVIQ\Servo\Debug\"
-    xcopy /Y /D "$(OutDir)*.pdb" "\\DESKTOP-IODBVIQ\Servo\Debug\"
+    xcopy /Y /D "$(OutDir)Servo.exe" "\\DESKTOP-IODBVIQ\Servo\Debug\"
+    xcopy /Y /D "$(OutDir)Servo.pdb" "\\DESKTOP-IODBVIQ\Servo\Debug\"
 )</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
diff --git a/SourceCode/Bond/Servo/ServoCommo.h b/SourceCode/Bond/Servo/ServoCommo.h
index 1e63c8e..09ca1d0 100644
--- a/SourceCode/Bond/Servo/ServoCommo.h
+++ b/SourceCode/Bond/Servo/ServoCommo.h
@@ -2,6 +2,23 @@
 #include <string>
 #include <vector>
 
+
+#define CHECK_READ_STEP_SIGNAL(addr, data, size) {							\
+	BOOL bFlag = isBitOn(data, size, addr);									\
+	SERVO::CStep* pStep = getStep(addr);									\
+	if (pStep != nullptr) {													\
+		((CReadStep*)pStep)->onReadSignal(bFlag ? addr : 0);				\
+	}																		\
+}
+
+#define CHECK_WRITE_STEP_SIGNAL(addr, data, size) {							\
+	BOOL bFlag = isBitOn(data, size, addr);									\
+	SERVO::CStep* pStep = getStep(addr);									\
+	if (pStep != nullptr) {													\
+		((CWriteStep*)pStep)->onRecvSignal(bFlag ? addr : 0);				\
+	}																		\
+}
+
 namespace SERVO {
 #define BLOCK_BUFFER_MAX			1024
 #define ALIVE_TIMEOUT				15
@@ -14,7 +31,14 @@
 		OK = 1,
 		NG,
 	};
-	typedef RET JobDataRequestAck;
+	using JobDataRequestAck = RET;
+
+	enum class InspResult
+	{
+		NotInspected = 0,  // 初始化状态,尚未检测
+		Pass,              // 检测合格
+		Fail               // 检测不合格
+	};
 
 	enum class PortType {
 		Loading = 1,

--
Gitblit v1.9.3