From 349f26accd28cd83356334239b11728ce50b7f95 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期三, 14 五月 2025 18:10:21 +0800
Subject: [PATCH] 1.重新理顺Glass的流转,CJobDataB, CJobDataS在CEquipment的列表存储等;

---
 SourceCode/Bond/Servo/Servo.vcxproj         |    4 
 SourceCode/Bond/Servo/CVacuumBake.cpp       |   25 +
 SourceCode/Bond/Servo/CDoubleGlass.h        |   26 +
 SourceCode/Bond/Servo/CJobDataS.h           |    3 
 SourceCode/Bond/Servo/CFliper.cpp           |   25 +
 SourceCode/Bond/Servo/CGlass.h              |   15 
 SourceCode/Bond/Servo/CJobDataS.cpp         |   46 ++
 SourceCode/Bond/Servo/CEFEM.h               |    6 
 SourceCode/Bond/Servo/CEquipment.cpp        |  187 ++++++++++
 SourceCode/Bond/Servo/CMaster.cpp           |    8 
 SourceCode/Bond/Servo/CBonder.h             |    5 
 SourceCode/Bond/Servo/CEqReadStep.h         |    2 
 SourceCode/Bond/Servo/CPageGraph2.cpp       |   32 +
 SourceCode/Bond/Servo/CProcessData.cpp      |  146 +++++++++
 SourceCode/Bond/Servo/CGlass.cpp            |   42 ++
 SourceCode/Bond/Servo/CLoadPort.h           |    1 
 SourceCode/Bond/Servo/CJobDataB.cpp         |   18 
 SourceCode/Bond/Servo/CProcessData.h        |   34 ++
 SourceCode/Bond/Servo/CLoadPort.cpp         |   55 ++
 SourceCode/Bond/Servo/CVacuumBake.h         |    1 
 SourceCode/Bond/Servo/CDoubleGlass.cpp      |   87 +++++
 SourceCode/Bond/Servo/Servo.vcxproj.filters |    4 
 SourceCode/Bond/Servo/CJobDataA.cpp         |    6 
 SourceCode/Bond/Servo/CJobDataB.h           |    3 
 SourceCode/Bond/Servo/CEFEM.cpp             |   64 ++-
 SourceCode/Bond/Servo/CEquipment.h          |   22 +
 SourceCode/Bond/Servo/CBonder.cpp           |   67 ++++
 SourceCode/Bond/Servo/CFliper.h             |    1 
 SourceCode/Bond/Servo/Common.h              |    2 
 29 files changed, 870 insertions(+), 67 deletions(-)

diff --git a/SourceCode/Bond/Servo/CBonder.cpp b/SourceCode/Bond/Servo/CBonder.cpp
index 9d18867..16f2d39 100644
--- a/SourceCode/Bond/Servo/CBonder.cpp
+++ b/SourceCode/Bond/Servo/CBonder.cpp
@@ -6,6 +6,7 @@
 	CBonder::CBonder() : CEquipment()
 	{
 		m_nIndex = 0;
+		m_bPermittedStore = FALSE;
 	}
 
 	CBonder::~CBonder()
@@ -88,10 +89,25 @@
 
 		{
 			// eq process
+			// 使用CEqReadStep替换CEqProcessStep
+			/*
 			CEqProcessStep* pStep = new CEqProcessStep();
 			pStep->setName(STEP_PROCESS);
 			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x347 : 0x647);
 			pStep->setProcessDev(m_nIndex == 0 ? 0xab55 : 0xeb55);
+			if (addStep(STEP_ID_PROCESS_DATA_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+			*/
+			CEqReadStep* pStep = new CEqReadStep((m_nIndex == 0 ? 0xab55 : 0xeb55), 538 * 2,
+				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
+					if (code == ROK && pszData != nullptr && size > 0) {
+						decodeProcessDataReport((CStep*)pFrom, pszData, size);
+					}
+					return -1;
+				});
+			pStep->setName(STEP_PROCESS);
+			pStep->setWriteSignalDev((m_nIndex == 0 ? 0x347 : 0x647));
 			if (addStep(STEP_ID_PROCESS_DATA_REPORT, pStep) != 0) {
 				delete pStep;
 			}
@@ -410,4 +426,55 @@
 	{
 		return m_nIndex;
 	}
+
+	int CBonder::onReceivedJob(int port, CJobDataS* pJobDataS)
+	{
+		m_bPermittedStore = FALSE;
+		Lock();
+		size_t size = m_glassList.size();
+		if (size == 0) {
+			m_bPermittedStore = TRUE;
+		}
+		else if (size == 1) {
+			CGlass* pGlass = m_glassList.front();
+			if ( (pGlass->getType() == MaterialsType::G1 && pJobDataS->getMaterialsType() == (int)MaterialsType::G2)
+				|| (pGlass->getType() == MaterialsType::G2 && pJobDataS->getMaterialsType() == (int)MaterialsType::G1)) {
+				m_bPermittedStore = TRUE;
+			}
+		}
+		Unlock();
+
+		if (m_bPermittedStore) {
+			return CEquipment::onReceivedJob(port, pJobDataS);
+		}
+		else {
+			return -1;
+		}
+	}
+
+	int CBonder::onSentOutJob(int port, CJobDataS* pJobDataS)
+	{
+		CEquipment::onSentOutJob(port, pJobDataS);
+
+		return 0;
+	}
+
+	int CBonder::onProcessData(CProcessData* pProcessData)
+	{
+		CEquipment::onProcessData(pProcessData);
+
+
+		return 0;
+	}
+
+	// Bonder检查腔体玻璃信息,如腔体为空可进G1或G2,
+	// 如腔体只有一片G1,可进G2,如腔体只有一片G2, 可进G1
+	// 其它情况不可进片
+	int CBonder::storedJob(CJobDataB* pJobDataB)
+	{
+		if (!m_bPermittedStore)
+			return -1;
+
+		return CEquipment::storedJob(pJobDataB);
+	}
 }
diff --git a/SourceCode/Bond/Servo/CBonder.h b/SourceCode/Bond/Servo/CBonder.h
index 04785d3..089878d 100644
--- a/SourceCode/Bond/Servo/CBonder.h
+++ b/SourceCode/Bond/Servo/CBonder.h
@@ -21,6 +21,10 @@
         virtual void getAttributeVector(CAttributeVector& attrubutes);
         virtual int recvIntent(CPin* pPin, CIntent* pIntent);
         virtual BOOL glassWillArrive(CGlass* pGlass);
+        virtual int storedJob(CJobDataB* pJobDataB);
+        virtual int onReceivedJob(int port, CJobDataS* pJobDataS);
+        virtual int onSentOutJob(int port, CJobDataS* pJobDataS);
+        virtual int onProcessData(CProcessData* pProcessData);
 
     public:
         void setIndex(unsigned int index);
@@ -28,6 +32,7 @@
 
     private:
         unsigned int m_nIndex;
+        BOOL m_bPermittedStore;
     };
 }
 
diff --git a/SourceCode/Bond/Servo/CDoubleGlass.cpp b/SourceCode/Bond/Servo/CDoubleGlass.cpp
new file mode 100644
index 0000000..1701145
--- /dev/null
+++ b/SourceCode/Bond/Servo/CDoubleGlass.cpp
@@ -0,0 +1,87 @@
+#include "stdafx.h"
+#include "CDoubleGlass.h"
+
+
+namespace SERVO {
+	CDoubleGlass::CDoubleGlass()
+	{
+		m_pGlass1 = nullptr;
+		m_pGlass2 = nullptr;
+	}
+
+	CDoubleGlass::CDoubleGlass(CGlass* pGlass1, CGlass* pGlass2)
+	{
+		m_pGlass1 = pGlass1;
+		m_pGlass2 = pGlass2;
+	}
+
+	CDoubleGlass::~CDoubleGlass()
+	{
+
+	}
+
+	std::string& CDoubleGlass::getClassName()
+	{
+		static std::string strName = "CDoubleGlass";
+		return strName;
+	}
+
+	std::string CDoubleGlass::toString()
+	{
+		std::string strText;
+		strText += "CGlass[";
+		if (m_pGlass1 != nullptr) {
+			strText += ("Glass1ID:" + m_pGlass1->getID() + ";");
+		}
+		if (m_pGlass2 != nullptr) {
+			strText += ("Glass2ID:" + m_pGlass2->getID() + ";");
+		}
+		strText += "]";
+
+		return strText;
+	}
+
+	CGlass* CDoubleGlass::getGlass1()
+	{
+		return m_pGlass1;
+	}
+
+	CGlass* CDoubleGlass::getGlass2()
+	{
+		return m_pGlass2;
+	}
+
+	void CDoubleGlass::serialize(CArchive& ar)
+	{
+		if (ar.IsStoring())
+		{
+			Lock();
+			ar << (ULONGLONG)m_pGlass1;
+			if (m_pGlass1 != nullptr) {
+				m_pGlass1->serialize(ar);
+			}
+			ar << (ULONGLONG)m_pGlass2;
+			if (m_pGlass2 != nullptr) {
+				m_pGlass2->serialize(ar);
+			}
+			Unlock();
+		}
+		else
+		{
+			Lock();
+			ULONGLONG ulGlass1;
+			ar >> ulGlass1;
+			if (ulGlass1 != 0) {
+				m_pGlass1 = new CGlass();
+				m_pGlass1->serialize(ar);
+			}
+			if (ulGlass1 != 0) {
+				m_pGlass2 = new CGlass();
+				m_pGlass2->serialize(ar);
+			}
+
+			Unlock();
+		}
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CDoubleGlass.h b/SourceCode/Bond/Servo/CDoubleGlass.h
new file mode 100644
index 0000000..a688fe7
--- /dev/null
+++ b/SourceCode/Bond/Servo/CDoubleGlass.h
@@ -0,0 +1,26 @@
+#pragma once
+#include "Context.h"
+#include "CGlass.h"
+
+
+namespace SERVO {
+	class CDoubleGlass : public CContext
+	{
+	public:
+		CDoubleGlass();
+		CDoubleGlass(CGlass* pGlass1, CGlass* pGlass2);
+		virtual ~CDoubleGlass();
+
+	public:
+		virtual std::string& getClassName();
+		virtual std::string toString();
+		CGlass* getGlass1();
+		CGlass* getGlass2();
+		void serialize(CArchive& ar);
+
+	private:
+		CGlass* m_pGlass1;
+		CGlass* m_pGlass2;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEFEM.cpp b/SourceCode/Bond/Servo/CEFEM.cpp
index 6b28e45..99e9b0c 100644
--- a/SourceCode/Bond/Servo/CEFEM.cpp
+++ b/SourceCode/Bond/Servo/CEFEM.cpp
@@ -426,61 +426,89 @@
 		}
 	}
 
-	int CEFEM::onFetchedOutJob(int port, const char* pszGlassId)
+	int CEFEM::onReceivedJob(int port, CJobDataS* pJobDataS)
+	{
+		m_pPort[0]->onReceivedJob(port, pJobDataS);
+		m_pPort[1]->onReceivedJob(port, pJobDataS);
+		m_pPort[2]->onReceivedJob(port, pJobDataS);
+		m_pPort[3]->onReceivedJob(port, pJobDataS);
+		m_pArmTray[0]->onReceivedJob(port, pJobDataS);
+		m_pArmTray[1]->onReceivedJob(port, pJobDataS);
+		m_pAligner->onReceivedJob(port, pJobDataS);
+		m_pFliper->onReceivedJob(port, pJobDataS);
+
+		return 0;
+	}
+
+	int CEFEM::onSentOutJob(int port, CJobDataS* pJobDataS)
+	{
+		m_pPort[0]->onSentOutJob(port, pJobDataS);
+		m_pPort[1]->onSentOutJob(port, pJobDataS);
+		m_pPort[2]->onSentOutJob(port, pJobDataS);
+		m_pPort[3]->onSentOutJob(port, pJobDataS);
+		m_pArmTray[0]->onSentOutJob(port, pJobDataS);
+		m_pArmTray[1]->onSentOutJob(port, pJobDataS);
+		m_pAligner->onSentOutJob(port, pJobDataS);
+		m_pFliper->onSentOutJob(port, pJobDataS);
+
+		return 0;
+	}
+
+	int CEFEM::onFetchedOutJob(int port, CJobDataB* pJobDataB)
 	{
 		if (port == 1) {
-			return m_pPort[0]->fetchedOutJob(pszGlassId);
+			return m_pPort[0]->onFetchedOutJob(port, pJobDataB);
 		}
 		if (port == 2) {
-			return m_pPort[1]->fetchedOutJob(pszGlassId);
+			return m_pPort[1]->onFetchedOutJob(port, pJobDataB);
 		}
 		if (port == 3) {
-			return m_pPort[2]->fetchedOutJob(pszGlassId);
+			return m_pPort[2]->onFetchedOutJob(port, pJobDataB);
 		}
 		if (port == 4) {
-			return m_pPort[3]->fetchedOutJob(pszGlassId);
+			return m_pPort[3]->onFetchedOutJob(port, pJobDataB);
 		}
 		if (port == 5) {
-			return m_pArmTray[0]->fetchedOutJob(pszGlassId);
+			return m_pArmTray[0]->onFetchedOutJob(port, pJobDataB);
 		}
 		if (port == 6) {
-			return m_pArmTray[1]->fetchedOutJob(pszGlassId);
+			return m_pArmTray[1]->onFetchedOutJob(port, pJobDataB);
 		}
 		if (port == 7) {
-			return m_pAligner->fetchedOutJob(pszGlassId);
+			return m_pAligner->onFetchedOutJob(port, pJobDataB);
 		}
 		if (port == 8) {
-			return m_pFliper->fetchedOutJob(pszGlassId);
+			return m_pFliper->onFetchedOutJob(port, pJobDataB);
 		}
 
 		return -1;
 	}
 
-	int CEFEM::onStoreJob(int port, const char* pszGlassId)
+	int CEFEM::onStoredJob(int port, CJobDataB* pJobDataB)
 	{
 		if (port == 1) {
-			return m_pPort[0]->storedJob(pszGlassId);
+			return m_pPort[0]->onStoredJob(port, pJobDataB);
 		}
 		if (port == 2) {
-			return m_pPort[1]->storedJob(pszGlassId);
+			return m_pPort[1]->onStoredJob(port, pJobDataB);
 		}
 		if (port == 3) {
-			return m_pPort[2]->storedJob(pszGlassId);
+			return m_pPort[2]->onStoredJob(port, pJobDataB);
 		}
 		if (port == 4) {
-			return m_pPort[3]->storedJob(pszGlassId);
+			return m_pPort[3]->onStoredJob(port, pJobDataB);
 		}
 		if (port == 5) {
-			return m_pArmTray[0]->storedJob(pszGlassId);
+			return m_pArmTray[0]->onStoredJob(port, pJobDataB);
 		}
 		if (port == 6) {
-			return m_pArmTray[1]->storedJob(pszGlassId);
+			return m_pArmTray[1]->onStoredJob(port, pJobDataB);
 		}
 		if (port == 7) {
-			return m_pAligner->storedJob(pszGlassId);
+			return m_pAligner->onStoredJob(port, pJobDataB);
 		}
 		if (port == 8) {
-			return m_pFliper->storedJob(pszGlassId);
+			return m_pFliper->onStoredJob(port, pJobDataB);
 		}
 
 		return -1;
diff --git a/SourceCode/Bond/Servo/CEFEM.h b/SourceCode/Bond/Servo/CEFEM.h
index 5bc4c0c..b2ce0aa 100644
--- a/SourceCode/Bond/Servo/CEFEM.h
+++ b/SourceCode/Bond/Servo/CEFEM.h
@@ -27,8 +27,10 @@
         virtual int recvIntent(CPin* pPin, CIntent* pIntent);
         virtual BOOL glassWillArrive(CGlass* pGlass);
         virtual void onReceiveLBData(const char* pszData, size_t size);
-        virtual int onFetchedOutJob(int port, const char* pszGlassId);
-        virtual int onStoreJob(int port, const char* pszGlassId);
+        virtual int onReceivedJob(int port, CJobDataS* pJobDataS);
+        virtual int onSentOutJob(int port, CJobDataS* pJobDataS);
+        virtual int onFetchedOutJob(int port, CJobDataB* pJobDataB);
+        virtual int onStoredJob(int port, CJobDataB* pJobDataB);
 
     public:
         void setPort(unsigned int index, CLoadPort* pPort);
diff --git a/SourceCode/Bond/Servo/CEqReadStep.h b/SourceCode/Bond/Servo/CEqReadStep.h
index 3a83c35..567f1cf 100644
--- a/SourceCode/Bond/Servo/CEqReadStep.h
+++ b/SourceCode/Bond/Servo/CEqReadStep.h
@@ -3,7 +3,7 @@
 #include <functional>
 
 
-#define READ_BUFFER_MAX		1024
+#define READ_BUFFER_MAX		2048
 
 #define ROK				0					/* 读数据OK */
 #define RTIMEOUT		-1					/* 读数据超时 */
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 3b15620..cea483e 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -85,6 +85,11 @@
 		m_pArm = pEquipment;
 	}
 
+	CEquipment* CEquipment::getArm()
+	{
+		return m_pArm;
+	}
+
 	void CEquipment::setBaseAlarmId(int nBaseId)
 	{
 		m_nBaseAlarmId = nBaseId;
@@ -822,7 +827,7 @@
 		return pGlass;
 	}
 
-	int CEquipment::fetchedOutJob(const char* pszGlassId)
+	int CEquipment::fetchedOutJob(CJobDataB* pJobDataB)
 	{
 		if (m_pArm == nullptr) {
 			return -1;
@@ -837,7 +842,7 @@
 
 		CGlass* pContext = nullptr;
 		for (auto iter = m_glassList.begin(); iter != m_glassList.end(); iter++) {
-			if ((*iter)->getID().compare(pszGlassId) == 0) {
+			if ((*iter)->getID().compare(pJobDataB->getGlassId()) == 0) {
 				pContext = (*iter);
 				m_glassList.erase(iter);
 				break;
@@ -859,7 +864,7 @@
 		return 0;
 	}
 
-	int CEquipment::storedJob(const char* pszGlassId)
+	int CEquipment::storedJob(CJobDataB* pJobDataB)
 	{
 		if (m_pArm == nullptr) {
 			return -1;
@@ -1061,6 +1066,24 @@
 		return m_recipesManager.decodeRecipeParameterReport(pszData, size);
 	}
 
+	int CEquipment::decodeProcessDataReport(CStep* pStep, const char* pszData, size_t size)
+	{
+		CProcessData processData;
+		int nRet = processData.unserialize(&pszData[0], (int)size);
+		if (nRet < 0) return nRet;
+
+		// 缓存Attribute,用于调试时显示信息
+		unsigned int weight = 201;
+		CAttributeVector attrubutes;
+		processData.getAttributeVector(attrubutes, weight);
+		pStep->addAttributeVector(attrubutes);
+
+
+		onProcessData(&processData);
+
+		return nRet;
+	}
+
 	int CEquipment::decodeReceivedJobReport(CStep* pStep, int port, const char* pszData, size_t size)
 	{
 		CJobDataS jobDataS;
@@ -1082,7 +1105,8 @@
 	int CEquipment::onReceivedJob(int port, CJobDataS* pJobDataS)
 	{
 		LOGI("<CEquipment-%s>onReceivedJob.", m_strName.c_str());
-		// return fetchedOutJob(pszGlassId);
+
+		addJobDataS(pJobDataS);
 		return 0;
 	}
 
@@ -1107,7 +1131,15 @@
 	int CEquipment::onSentOutJob(int port, CJobDataS* pJobDataS)
 	{
 		LOGI("<CEquipment-%s>onSentOutJob.", m_strName.c_str());
-		// return fetchedOutJob(pszGlassId);
+
+		int count = removeJobDataS(pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo());
+		if (count == 1) {
+			LOGI("<CEquipment-%s>onSentOutJob,删除数据 %d 条", m_strName.c_str(), count);
+		}
+		else {
+			LOGE("<CEquipment-%s>onSentOutJob,删除数据 %d 条,注意排查风险", m_strName.c_str(), count);
+		}
+
 		return 0;
 	}
 
@@ -1148,16 +1180,32 @@
 			jobDataB.getGlassId().c_str(), "", weight++));
 
 
-		onFetchedOutJob(port, jobDataB.getGlassId().c_str());
+		onFetchedOutJob(port, &jobDataB);
 
 		return index;
 	}
 
-	int CEquipment::onFetchedOutJob(int port, const char* pszGlassId)
+	int CEquipment::onPreFetchedOutJob(int port, CJobDataB* pJobDataB)
+	{
+		LOGI("<CEquipment-%s>onPreFetchedOutJob:port:%d|GlassId:%s",
+			m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
+		return TRUE;
+	}
+
+	int CEquipment::onFetchedOutJob(int port, CJobDataB* pJobDataB)
 	{
 		LOGI("<CEquipment-%s>onFetchedOutJob:port:%d|GlassId:%s", 
-			m_strName.c_str(), port, pszGlassId);
-		return fetchedOutJob(pszGlassId);
+			m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
+
+		BOOL bCheck = onPreFetchedOutJob(port, pJobDataB);
+		if (bCheck) {
+			return fetchedOutJob(pJobDataB);
+		}
+
+		// 数据异常,处理或显示
+		LOGI("<CEquipment-%s>onFetchedOutJob Error.ort:%d|GlassId:%s",
+			m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
+		return -1;
 	}
 
 	int CEquipment::decodeStoredJobReport(CStep* pStep, int port, const char* pszData, size_t size)
@@ -1197,15 +1245,128 @@
 			jobDataB.getGlassId().c_str(), "", weight++));
 
 
-		onStoreJob(port, jobDataB.getGlassId().c_str());
+		onStoredJob(port, &jobDataB);
 
 		return index;
 	}
 
-	int CEquipment::onStoreJob(int port, const char* pszGlassId)
+	int CEquipment::onPreStoredJob(int port, CJobDataB* pJobDataB)
+	{
+		LOGI("<CEquipment-%s>onPreStoredJob:port:%d|GlassId:%s",
+			m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
+		return TRUE;
+	}
+
+	int CEquipment::onStoredJob(int port, CJobDataB* pJobDataB)
 	{
 		LOGI("<CEquipment-%s>onStore:port:%d|GlassId:%s",
-			m_strName.c_str(), port, pszGlassId);
-		return storedJob(pszGlassId);
+			m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
+
+		BOOL bCheck = onPreStoredJob(port, pJobDataB);
+		if (bCheck) {
+			addJobDataB(pJobDataB);
+			return storedJob(pJobDataB);
+		}
+
+		// 数据异常,处理或显示
+		LOGI("<CEquipment-%s>onStoredJob Error.ort:%d|GlassId:%s",
+			m_strName.c_str(), port, pJobDataB->getGlassId().c_str());
+		return -1;
+	}
+
+	int CEquipment::onProcessData(CProcessData* pProcessData)
+	{
+		LOGI("<CEquipment-%s>onProcessData.", m_strName.c_str());
+		return 0;
+	}
+
+	int CEquipment::addJobDataB(CJobDataB* pJobDataB)
+	{
+		// 添加之前先删除旧的,以免数据重复
+		Lock();
+		int count = removeJobDataB(pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo());
+		if (count > 0) {
+			LOGE("<CEquipment-%s>addJobDataB,删除重复数据 %d 条,注意排查风险", m_strName.c_str(), count);
+		}
+
+		m_listJobDataB.push_back(std::move(*pJobDataB));
+		Unlock();
+
+		return (int)m_listJobDataB.size();
+	}
+
+	int CEquipment::removeJobDataB(int nCassetteSequenceNo, int nJobSequenceNo)
+	{
+		int count = 0;
+		for (auto it = m_listJobDataB.begin(); it != m_listJobDataB.end(); ) {
+			if ((*it).getCassetteSequenceNo() == nCassetteSequenceNo
+				&& (*it).getJobSequenceNo() == nJobSequenceNo) {
+				it = m_listJobDataB.erase(it);
+				count++;
+			}
+			else {
+				++it;
+			}
+		}
+
+		return count;
+	}
+
+	CJobDataB* CEquipment::getJobDataB(int nCassetteSequenceNo, int nJobSequenceNo)
+	{
+		for (auto& item : m_listJobDataB) {
+			if (item.getCassetteSequenceNo() == nCassetteSequenceNo
+				&& item.getJobSequenceNo() == nJobSequenceNo) {
+				return &item;
+			}
+		}
+
+		return nullptr;
+	}
+
+	int CEquipment::addJobDataS(CJobDataS* pJobDataS)
+	{
+		// 添加之前先删除旧的,以免数据重复
+		Lock();
+		int count = removeJobDataS(pJobDataS->getCassetteSequenceNo(), pJobDataS->getJobSequenceNo());
+		if (count > 0) {
+			LOGE("<CEquipment-%s>addJobDataS,删除重复数据 %d 条,注意排查风险", m_strName.c_str(), count);
+		}
+
+		m_listJobDataS.push_back(std::move(*pJobDataS));
+		Unlock();
+
+		return (int)m_listJobDataB.size();
+	}
+
+	int CEquipment::removeJobDataS(int nCassetteSequenceNo, int nJobSequenceNo)
+	{
+		int count = 0;
+		Lock();
+		for (auto it = m_listJobDataS.begin(); it != m_listJobDataS.end(); ) {
+			if ((*it).getCassetteSequenceNo() == nCassetteSequenceNo
+				&& (*it).getJobSequenceNo() == nJobSequenceNo) {
+				it = m_listJobDataS.erase(it);
+				count++;
+			}
+			else {
+				++it;
+			}
+		}
+		Unlock();
+
+		return count;
+	}
+
+	CJobDataS* CEquipment::getJobDataS(int nCassetteSequenceNo, int nJobSequenceNo)
+	{
+		for (auto& item : m_listJobDataS) {
+			if (item.getCassetteSequenceNo() == nCassetteSequenceNo
+				&& item.getJobSequenceNo() == nJobSequenceNo) {
+				return &item;
+			}
+		}
+
+		return nullptr;
 	}
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index 24eb6ff..831a3df 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -31,6 +31,7 @@
 #include "CJobDataB.h"
 #include "CJobDataC.h"
 #include "CJobDataS.h"
+#include "CProcessData.h"
 
 
 namespace SERVO {
@@ -80,6 +81,7 @@
 		void setCcLink(CCCLinkIEControl* pCcLink);
 		virtual BOOL isArm() { return FALSE; };
 		void setArm(CEquipment* pEquipment);
+		CEquipment* getArm();
 		void setBaseAlarmId(int nBaseId);
 		int getBaseAlarmId();
 		void setID(int nID);
@@ -116,10 +118,15 @@
 		virtual BOOL glassWillArrive(CGlass* pGlass);
 		virtual int outputGlass(int port);
 		virtual int glassArrived(CGlass* pGlass);
+		virtual int fetchedOutJob(CJobDataB* pJobDataB);
+		virtual int storedJob(CJobDataB* pJobDataB);
 		virtual int onReceivedJob(int port, CJobDataS* pJobDataS);
 		virtual int onSentOutJob(int port, CJobDataS* pJobDataS);
-		virtual int onFetchedOutJob(int port, const char* pszGlassId);
-		virtual int onStoreJob(int port, const char* pszGlassId);
+		virtual BOOL onPreFetchedOutJob(int port, CJobDataB* pJobDataB);
+		virtual int onFetchedOutJob(int port, CJobDataB* pJobDataB);
+		virtual BOOL onPreStoredJob(int port, CJobDataB* pJobDataB);
+		virtual int onStoredJob(int port, CJobDataB* pJobDataB);
+		virtual int onProcessData(CProcessData* pProcessData);
 		void getGlassList(std::list<CGlass*>& list);
 		CGlass* getFrontGlass();
 		BOOL removeClass(CGlass* pGlass);
@@ -150,8 +157,6 @@
 		int recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo);
 
 	public:
-		int fetchedOutJob(const char* pszGlassId);
-		int storedJob(const char* pszGlassId);
 		BOOL isGlassListEmpty();
 
 
@@ -173,10 +178,17 @@
 		void addGlassToList(CGlass* pGlass);
 		short decodeRecipeListReport(const char* pszData, size_t size);
 		short decodeRecipeParameterReport(const char* pszData, size_t size);
+		int decodeProcessDataReport(CStep* pStep, const char* pszData, size_t size);
 		int decodeReceivedJobReport(CStep* pStep, int port, const char* pszData, size_t size);
 		int decodeSentOutJobReport(CStep* pStep, int port, const char* pszData, size_t size);
 		int decodeFetchedOutJobReport(CStep* pStep, int port, const char* pszData, size_t size);
 		int decodeStoredJobReport(CStep* pStep, int port, const char* pszData, size_t size);
+		int addJobDataB(CJobDataB* pJobDataB);
+		int removeJobDataB(int nCassetteSequenceNo, int nJobSequenceNo);
+		CJobDataB* getJobDataB(int nCassetteSequenceNo, int nJobSequenceNo);
+		int addJobDataS(CJobDataS* pJobDataS);
+		int removeJobDataS(int nCassetteSequenceNo, int nJobSequenceNo);
+		CJobDataS* getJobDataS(int nCassetteSequenceNo, int nJobSequenceNo);
 
 	protected:
 		EquipmentListener m_listener;
@@ -210,6 +222,8 @@
 
 	private:
 		CEquipment* m_pArm;
+		std::list<CJobDataS> m_listJobDataS;
+		std::list<CJobDataB> m_listJobDataB;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CFliper.cpp b/SourceCode/Bond/Servo/CFliper.cpp
index acd7654..cdc0431 100644
--- a/SourceCode/Bond/Servo/CFliper.cpp
+++ b/SourceCode/Bond/Servo/CFliper.cpp
@@ -67,4 +67,29 @@
 
 		return m_glassList.empty();
 	}
+
+	BOOL CFliper::onPreStoredJob(int port, CJobDataB* pJobDataB)
+	{
+		CJobDataS* pJobDataS = getJobDataS(pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo());
+		if (pJobDataS == nullptr) {
+			LOGE("<CEquipment-%s>onPreFetchedOutJob,找不到对应的JobDataS(CassetteSequenceNo:%d, JobSequenceNo:%d), 注意排查风险!", m_strName.c_str(), 
+				pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo());
+			return FALSE;
+		}
+
+		// 当前不能有任何玻璃,且当前准备进的片是G2
+		Lock();
+		if (!m_glassList.empty()) {
+			Unlock();
+			LOGE("<CEquipment-%s>onPreFetchedOutJob,当前机器或单元存在玻璃片,不能进料,请注意风险!", m_strName.c_str());
+			return FALSE;
+		}
+
+		if (pJobDataS->getMaterialsType() != (int)MaterialsType::G2) {
+			LOGE("<CEquipment-%s>onPreFetchedOutJob,当前机器或单元只能进G2玻璃片,请注意风险!", m_strName.c_str());
+			return FALSE;
+		}
+
+		return TRUE;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CFliper.h b/SourceCode/Bond/Servo/CFliper.h
index a010953..4d3c859 100644
--- a/SourceCode/Bond/Servo/CFliper.h
+++ b/SourceCode/Bond/Servo/CFliper.h
@@ -20,6 +20,7 @@
         virtual void getAttributeVector(CAttributeVector& attrubutes);
         virtual int recvIntent(CPin* pPin, CIntent* pIntent);
         virtual BOOL glassWillArrive(CGlass* pGlass);
+        virtual BOOL onPreStoredJob(int port, CJobDataB* pJobDataB);
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CGlass.cpp b/SourceCode/Bond/Servo/CGlass.cpp
index a21bd7b..410868a 100644
--- a/SourceCode/Bond/Servo/CGlass.cpp
+++ b/SourceCode/Bond/Servo/CGlass.cpp
@@ -6,6 +6,7 @@
 	CGlass::CGlass()
 	{
 		m_pPath = nullptr;
+		m_type = MaterialsType::G1;
 	}
 
 	CGlass::~CGlass()
@@ -33,6 +34,16 @@
 		strText += "]";
 
 		return strText;
+	}
+
+	MaterialsType CGlass::getType()
+	{
+		return m_type;
+	}
+
+	void CGlass::setType(MaterialsType type)
+	{
+		m_type = type;
 	}
 
 	void CGlass::setID(const char* pszID)
@@ -84,6 +95,11 @@
 			if (m_pPath != nullptr) {
 				m_pPath->serialize(ar);
 			}
+			char temp[JOBDATAS_SIZE] = { 0 };
+			m_jobDataB.serialize(temp, JOBDATAB_SIZE);
+			ar.Write(temp, JOBDATAB_SIZE);
+			m_jobDataS.serialize(temp, JOBDATAS_SIZE);
+			ar.Write(temp, JOBDATAS_SIZE);
 			Unlock();
 		}
 		else
@@ -96,8 +112,32 @@
 				m_pPath = new CPath();
 				m_pPath->serialize(ar);
 			}
-
+			char temp[JOBDATAS_SIZE];
+			ar.Read(temp, JOBDATAB_SIZE);
+			m_jobDataB.unserialize(temp, JOBDATAB_SIZE);
+			ar.Read(temp, JOBDATAS_SIZE);
+			m_jobDataS.unserialize(temp, JOBDATAS_SIZE);
 			Unlock();
 		}
 	}
+
+	void CGlass::setJobDataB(CJobDataB* pJobDataB)
+	{
+		m_jobDataB.copy(pJobDataB);
+	}
+
+	CJobDataB* CGlass::getJobDataB()
+	{
+		return &m_jobDataB;
+	}
+
+	void CGlass::setJobDataS(CJobDataS* pJobDataS)
+	{
+		m_jobDataS.copy(pJobDataS);
+	}
+
+	CJobDataS* CGlass::getJobDataS()
+	{
+		return &m_jobDataS;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CGlass.h b/SourceCode/Bond/Servo/CGlass.h
index 38ecaf2..4fa6b33 100644
--- a/SourceCode/Bond/Servo/CGlass.h
+++ b/SourceCode/Bond/Servo/CGlass.h
@@ -9,6 +9,12 @@
 
 
 namespace SERVO {
+	enum MaterialsType {
+		G1 = 0,
+		G2 = 1,
+		G1G2 = 2
+	};
+
 	class CGlass : public CContext
 	{
 	public:
@@ -18,16 +24,25 @@
 	public:
 		virtual std::string& getClassName();
 		virtual std::string toString();
+		MaterialsType getType();
+		void setType(MaterialsType type);
 		void setID(const char* pszID);
 		std::string& getID();
 		CPath* getPathWithSiteID(unsigned int nSiteId);
 		CPath* getPath();
 		void addPath(unsigned int nSiteId);
 		void serialize(CArchive& ar);
+		void setJobDataB(CJobDataB* pJobDataB);
+		CJobDataB* getJobDataB();
+		void setJobDataS(CJobDataS* pJobDataS);
+		CJobDataS* getJobDataS();
 
 	private:
+		MaterialsType m_type;
 		std::string m_strID;
 		CPath* m_pPath;
+		CJobDataB m_jobDataB;
+		CJobDataS m_jobDataS;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CJobDataA.cpp b/SourceCode/Bond/Servo/CJobDataA.cpp
index 03d90ff..cf33400 100644
--- a/SourceCode/Bond/Servo/CJobDataA.cpp
+++ b/SourceCode/Bond/Servo/CJobDataA.cpp
@@ -37,11 +37,11 @@
 		memcpy(&pszBuffer[index], &m_nPortNo, sizeof(short));
 		index += sizeof(short);
 
-		int strLen = min(20, m_strCarrierId.size());
+		int strLen = min(20, (int)m_strCarrierId.size());
 		memcpy(&pszBuffer[index], m_strCarrierId.c_str(), strLen);
 		index += 20;
 
-		strLen = min(20, m_pruductId.size());
+		strLen = min(20, (int)m_pruductId.size());
 		memcpy(&pszBuffer[index], m_pruductId.c_str(), strLen);
 		index += 20;
 
@@ -56,7 +56,7 @@
 
 		for (int i = 0; i < min(25, m_glassIds.size()); i++) {
 			std::string& strGlassId = m_glassIds.at(i);
-			strLen = min(20, strGlassId.size());
+			strLen = min(20, (int)strGlassId.size());
 			memcpy(&pszBuffer[index], strGlassId.c_str(), strLen);
 			index += 20;
 		}
diff --git a/SourceCode/Bond/Servo/CJobDataB.cpp b/SourceCode/Bond/Servo/CJobDataB.cpp
index 9c00cb7..596259a 100644
--- a/SourceCode/Bond/Servo/CJobDataB.cpp
+++ b/SourceCode/Bond/Servo/CJobDataB.cpp
@@ -10,9 +10,21 @@
 		m_nJobSequenceNo = 0;
 	}
 
+	CJobDataB::CJobDataB(CJobDataB&& other) noexcept
+	{
+		copy(&other);
+	}
+
 	CJobDataB::~CJobDataB()
 	{
 
+	}
+
+	void CJobDataB::copy(CJobDataB* pScr)
+	{
+		m_nCassetteSequenceNo = pScr->m_nCassetteSequenceNo;
+		m_nJobSequenceNo = pScr->m_nJobSequenceNo;
+		m_strGlassId = pScr->m_strGlassId;
 	}
 
 	int CJobDataB::getCassetteSequenceNo()
@@ -47,7 +59,7 @@
 
 	int CJobDataB::serialize(char* pszBuffer, int nBufferSize)
 	{
-		if (nBufferSize < 28) return -1;
+		if (nBufferSize < JOBDATAB_SIZE) return -1;
 
 		int index = 0;
 		memcpy(&pszBuffer[index], &m_nCassetteSequenceNo, sizeof(short));
@@ -60,12 +72,12 @@
 		memcpy(&pszBuffer[index], m_strGlassId.c_str(), strLen);
 		index += 20;
 
-		return 14 * 2;
+		return JOBDATAB_SIZE;
 	}
 
 	int CJobDataB::unserialize(const char* pszBuffer, int nBufferSize)
 	{
-		if (nBufferSize < 14) return -1;
+		if (nBufferSize < 14 * 2) return -1;
 
 		int index = 0;
 		memcpy(&m_nCassetteSequenceNo, &pszBuffer[index], sizeof(short));
diff --git a/SourceCode/Bond/Servo/CJobDataB.h b/SourceCode/Bond/Servo/CJobDataB.h
index c1ed9c2..34945c5 100644
--- a/SourceCode/Bond/Servo/CJobDataB.h
+++ b/SourceCode/Bond/Servo/CJobDataB.h
@@ -1,14 +1,17 @@
 #pragma once
 
 
+#define JOBDATAB_SIZE		(14 * 2)
 namespace SERVO {
 	class CJobDataB
 	{
 	public:
 		CJobDataB();
+		CJobDataB::CJobDataB(CJobDataB&& other) noexcept;
 		~CJobDataB();
 
 	public:
+		void copy(CJobDataB* pScr);
 		int getCassetteSequenceNo();
 		void setCassetteSequenceNo(int no);
 		int getJobSequenceNo();
diff --git a/SourceCode/Bond/Servo/CJobDataS.cpp b/SourceCode/Bond/Servo/CJobDataS.cpp
index 0c9de03..9351215 100644
--- a/SourceCode/Bond/Servo/CJobDataS.cpp
+++ b/SourceCode/Bond/Servo/CJobDataS.cpp
@@ -36,12 +36,54 @@
 		}
 	}
 
+	CJobDataS::CJobDataS(CJobDataS&& other) noexcept
+	{
+		copy(&other);
+		m_pRawData = other.m_pRawData;      // 偷资源
+		other.m_pRawData = nullptr;			// 防止释放两次
+	}
+
 	CJobDataS::~CJobDataS()
 	{
 		if (m_pRawData != nullptr) {
 			delete[] m_pRawData;
 			m_pRawData = nullptr;
 		}
+	}
+
+	void CJobDataS::copy(CJobDataS* pScr)
+	{
+		m_nCassetteSequenceNo = pScr->m_nCassetteSequenceNo;
+		m_nJobSequenceNo = pScr->m_nJobSequenceNo;
+		m_strLotId = pScr->m_strLotId;
+		m_strProductId = pScr->m_strProductId;
+		m_strOperationId = pScr->m_strOperationId;
+		m_strGlass1Id = pScr->m_strGlass1Id;
+		m_strGlass2Id = pScr->m_strGlass2Id;
+		m_nJobType = pScr->m_nJobType;
+		m_nMaterialsType = pScr->m_nMaterialsType;
+		m_nProductType = pScr->m_nProductType;
+		m_nDummyType = pScr->m_nDummyType;
+		m_nSkipFlag = pScr->m_nSkipFlag;
+		m_nProcessFlag = pScr->m_nProcessFlag;
+		m_nProcessResonCode = pScr->m_nProcessResonCode;
+		m_nLastGlassFlag = pScr->m_nLastGlassFlag;
+		m_nFirstGlassFlag = pScr->m_nFirstGlassFlag;
+		m_nQTime[0] = pScr->m_nQTime[0];
+		m_nQTime[1] = pScr->m_nQTime[1];
+		m_nQTime[2] = pScr->m_nQTime[2];
+		m_nQTimeOverFlag = pScr->m_nQTimeOverFlag;
+		m_nMasterRecipe = pScr->m_nMasterRecipe;
+		m_strProductRecipeId = pScr->m_strProductRecipeId;
+		m_strPCode = pScr->m_strPCode;
+		m_strUseType = pScr->m_strUseType;
+		m_strPanelMeasure = pScr->m_strPanelMeasure;
+		m_nMode = pScr->m_nMode;
+		m_nSlotUnitSelectFlag = pScr->m_nSlotUnitSelectFlag;
+		m_nSourcePortNo = pScr->m_nSourcePortNo;
+		m_nSourceSlotNo = pScr->m_nSourceSlotNo;
+		m_nTargetPortNo = pScr->m_nTargetPortNo;
+		m_nTargetSlotNo = pScr->m_nTargetSlotNo;
 	}
 
 	int CJobDataS::getCassetteSequenceNo()
@@ -455,7 +497,7 @@
 
 	int CJobDataS::unserialize(const char* pszBuffer, int nBufferSize)
 	{
-		if (nBufferSize < 256 * 2) return -1;
+		if (nBufferSize < JOBDATAS_SIZE) return -1;
 
 		int index = 0;
 		memcpy(&m_nCassetteSequenceNo, &pszBuffer[index], sizeof(short));
@@ -558,7 +600,7 @@
 		}
 
 
-		return 256 * 2;
+		return JOBDATAS_SIZE;
 	}
 
 	void CJobDataS::getAttributeVector(CAttributeVector& attrubutes, int beginWeight)
diff --git a/SourceCode/Bond/Servo/CJobDataS.h b/SourceCode/Bond/Servo/CJobDataS.h
index 3894db2..8f5bae6 100644
--- a/SourceCode/Bond/Servo/CJobDataS.h
+++ b/SourceCode/Bond/Servo/CJobDataS.h
@@ -2,14 +2,17 @@
 #include "CAttributeVector.h"
 
 
+#define JOBDATAS_SIZE		(256 * 2)
 namespace SERVO {
 	class CJobDataS
 	{
 	public:
 		CJobDataS();
+		CJobDataS::CJobDataS(CJobDataS&& other) noexcept;
 		~CJobDataS();
 
 	public:
+		void copy(CJobDataS* pScr);
 		int getCassetteSequenceNo();
 		void setCassetteSequenceNo(int no);
 		int getJobSequenceNo();
diff --git a/SourceCode/Bond/Servo/CLoadPort.cpp b/SourceCode/Bond/Servo/CLoadPort.cpp
index 9cab3d1..ff98b63 100644
--- a/SourceCode/Bond/Servo/CLoadPort.cpp
+++ b/SourceCode/Bond/Servo/CLoadPort.cpp
@@ -206,19 +206,6 @@
 
 	int CLoadPort::outputGlass(int port)
 	{
-		// 如果列表中没有Panel,模拟生成10张
-		if (m_glassList.empty()) {
-			static int ii = 0;
-			char szBuffer[64];
-			LOGI("<CLoadPort>模拟生成10张PANEL");
-			for (int i = 0; i < 10; i++) {
-				sprintf_s(szBuffer, "P20250320A1A%d", ++ii);
-				CGlass* pGlass = new CGlass();
-				pGlass->setID(szBuffer);
-				addGlassToList(pGlass);
-			}
-		}
-
 		return __super::outputGlass(port);
 	}
 
@@ -515,4 +502,46 @@
 
 		return 0;
 	}
+
+	/*
+	 * 生成测试用的玻璃列表
+	 */
+	int CLoadPort::testGenerateGlassList(MaterialsType type, int count, const char* pszPrefix, int startSuffix)
+	{
+		// 如果非空就不生成了
+		Lock();
+		if (!m_glassList.empty()) {
+			Unlock();
+			return -1;
+		}
+		Unlock();
+
+
+		char szBuffer[64];
+		int suffix = startSuffix;
+		for (int i = 0; i < count; i++) {
+			CJobDataB jb;
+			CJobDataS js;
+
+			sprintf_s(szBuffer, "%s%d", pszPrefix, suffix++);
+			jb.setGlassId(szBuffer);
+			js.setMaterialsType((int)type);
+			if (type == MaterialsType::G1) {
+				js.setGlass1Id(szBuffer);
+			}
+			else if (type == MaterialsType::G2) {
+				js.setGlass2Id(szBuffer);
+			}
+
+			CGlass* pGlass = new CGlass();
+			pGlass->setID(szBuffer);
+			pGlass->setJobDataB(&jb);
+			pGlass->setType(type);
+			pGlass->setJobDataS(&js);
+			addGlassToList(pGlass);
+		}
+
+		return 0;
+	}
+
 }
diff --git a/SourceCode/Bond/Servo/CLoadPort.h b/SourceCode/Bond/Servo/CLoadPort.h
index ae63fe7..0b28400 100644
--- a/SourceCode/Bond/Servo/CLoadPort.h
+++ b/SourceCode/Bond/Servo/CLoadPort.h
@@ -33,6 +33,7 @@
 		int getCessetteType();
 		int getTransferMode();
 		BOOL isAutoChange();
+		int testGenerateGlassList(MaterialsType type, int count, const char* pszPrefix, int startSuffix);
 
 	public:
 		static std::string& getPortTypeDescription(int portType, std::string& strDescription);
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 6394380..927cecf 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -304,8 +304,8 @@
 		CFliper* pEquipment = new CFliper();
 		pEquipment->setID(EQ_ID_FLIPER);
 		pEquipment->setBaseAlarmId(BASE_ALARM_EFEM);
-		pEquipment->setName("Fliper");
-		pEquipment->setDescription("Fliper.");
+		pEquipment->setName("Fliper(G2)");
+		pEquipment->setDescription("Fliper(G2).");
 		pEquipment->setReadBitBlock(0x4000, 0x45ff);
 		pEquipment->setStation(0, 255);
 		addToEquipmentList(pEquipment);
@@ -321,8 +321,8 @@
 		CVacuumBake* pEquipment = new CVacuumBake();
 		pEquipment->setID(EQ_ID_VACUUMBAKE);
 		pEquipment->setBaseAlarmId(BASE_ALARM_EFEM);
-		pEquipment->setName("VacuumBake");
-		pEquipment->setDescription("VacuumBake.");
+		pEquipment->setName("VacuumBake(G1)");
+		pEquipment->setDescription("VacuumBake(G1).");
 		pEquipment->setReadBitBlock(0x4000, 0x45ff);
 		pEquipment->setStation(0, 255);
 		addToEquipmentList(pEquipment);
diff --git a/SourceCode/Bond/Servo/CPageGraph2.cpp b/SourceCode/Bond/Servo/CPageGraph2.cpp
index cc44782..e8493da 100644
--- a/SourceCode/Bond/Servo/CPageGraph2.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph2.cpp
@@ -10,6 +10,7 @@
 #include "CEquipmentPage2.h"
 #include "CPagePortProperty.h"
 #include "CPageCassetteCtrlCmd.h"
+#include "CJobDataB.h"
 
 
 // CPageGraph2 瀵硅瘽妗�
@@ -191,13 +192,38 @@
 		else if (nCmd == ID_EQSGRAPHITEM_TEST1) {
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
 			if (pEquipment->getID() == EQ_ID_LOADPORT1) {
-				pEquipment->outputGlass(1);
+				((SERVO::CLoadPort*)pEquipment)->testGenerateGlassList(SERVO::MaterialsType::G1, 10, 
+					"P20250320G1X", 1);
 			}
-			pEquipment->fetchedOutJob("P20250320A1A2");
+			else if (pEquipment->getID() == EQ_ID_LOADPORT2) {
+				((SERVO::CLoadPort*)pEquipment)->testGenerateGlassList(SERVO::MaterialsType::G2, 10,
+					"P20250320G2X", 1);
+			}
+			SERVO::CGlass* pGlass = pEquipment->getFrontGlass();
+			if (pGlass != nullptr) {
+				SERVO::CJobDataB* pJobDataB = pGlass->getJobDataB();
+				SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS();
+				if (pJobDataB != nullptr && pJobDataS != nullptr) {
+					pEquipment->fetchedOutJob(pJobDataB);
+					pEquipment->onSentOutJob(0, pJobDataS);
+				}
+			}
 		}
 		else if (nCmd == ID_EQSGRAPHITEM_TEST2) {
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
-			pEquipment->storedJob("P20250320A1A2");
+			SERVO::CArm* pArm = (SERVO::CArm*)pEquipment->getArm();
+			if (pArm != nullptr) {
+				SERVO::CGlass* pGlass = pArm->getFrontGlass();
+				if (pGlass != nullptr) {
+					SERVO::CJobDataB* pJobDataB = pGlass->getJobDataB();
+					SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS();
+					if (pJobDataB != nullptr && pJobDataS != nullptr) {
+						pEquipment->onReceivedJob(0, pJobDataS);
+						Sleep(600);
+						pEquipment->onStoredJob(0, pJobDataB);
+					}
+				}
+			}
 		}
 		else if (nCmd == ID_EQSGRAPHITEM_TEST3) {
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
diff --git a/SourceCode/Bond/Servo/CProcessData.cpp b/SourceCode/Bond/Servo/CProcessData.cpp
new file mode 100644
index 0000000..bf9a8de
--- /dev/null
+++ b/SourceCode/Bond/Servo/CProcessData.cpp
@@ -0,0 +1,146 @@
+#include "stdafx.h"
+#include "CProcessData.h"
+#include <iterator>
+#include "ToolUnits.h"
+
+
+namespace SERVO {
+	CProcessData::CProcessData()
+	{
+
+	}
+
+	CProcessData::~CProcessData()
+	{
+
+	}
+
+	std::string& CProcessData::getGlassId()
+	{
+		return m_strGlassId;
+	}
+
+	std::string& CProcessData::getStartTime()
+	{
+		return m_strStartTime;
+	}
+
+	std::string& CProcessData::getEndTime()
+	{
+		return m_strEndTime;
+	}
+
+	unsigned int CProcessData::getTotalParameter()
+	{
+		return m_nTotalParameter;
+	}
+
+	const std::list<std::string>& CProcessData::getParameters()
+	{
+		return m_params;
+	}
+
+	void CProcessData::getParameters(std::list<std::string>& list)
+	{
+		std::copy(m_params.begin(), m_params.end(), std::back_inserter(list));
+	}
+
+	int CProcessData::serialize(char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 538 * 2) return -1;
+
+		// 解释数据
+		// Glass ID
+		int index = 0;
+		CToolUnits::convertString(&pszBuffer[index], 10 * 2, m_strGlassId);
+		index += 10 * 2;
+
+		// Process Start Time
+		CToolUnits::convertString(&pszBuffer[index], 8 * 2, m_strStartTime);
+		index += 8 * 2;
+
+		// Process End Time
+		CToolUnits::convertString(&pszBuffer[index], 8 * 2, m_strEndTime);
+		index += 8 * 2;
+
+		// parameter count
+		m_nTotalParameter = (unsigned int)CToolUnits::toInt16(&pszBuffer[index]);
+		index += 2;
+
+		// total group
+		m_nTotalGroup = (unsigned int)CToolUnits::toInt16(&pszBuffer[index]);
+		index += 2;
+
+		// current group
+		m_nCurrentGroup = (unsigned int)CToolUnits::toInt16(&pszBuffer[index]);
+		index += 2;
+
+		// param list(0x1881~0x1a74), 共1000 bytes, 20个字符为一个参数, 50组
+		// 最后一group可能不满足50, 以m_nTotalParameter为依据
+		int size = (m_nCurrentGroup == m_nTotalGroup) ? m_nTotalParameter % 50 : 50;
+		for (int i = 0; i < size; i++) {
+			std::string strParam;
+			CToolUnits::convertString(&pszBuffer[index], 20, strParam);
+			if (!strParam.empty()) {
+				m_params.push_back(strParam);
+			}
+			index += 20;
+		}
+
+		return 538 * 2;
+	}
+
+	int CProcessData::unserialize(const char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 538 * 2) return -1;
+
+		int index = 0;
+		CToolUnits::convertString(&pszBuffer[index], 10 * 2, m_strGlassId);
+		index += 10 * 2;
+
+		CToolUnits::convertString(&pszBuffer[index], 8 * 2, m_strStartTime);
+		index += 8 * 2;
+
+		CToolUnits::convertString(&pszBuffer[index], 8 * 2, m_strEndTime);
+		index += 8 * 2;
+
+		memcpy(&m_nTotalParameter, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nTotalGroup, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nCurrentGroup, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		// 多分组如何处理?待考虑
+
+
+		return 538 * 2;
+	}
+
+	void CProcessData::getAttributeVector(CAttributeVector& attrubutes, int beginWeight)
+	{
+		unsigned int weight = beginWeight;
+		attrubutes.addAttribute(new CAttribute("Glass ID",
+			m_strGlassId.c_str(), "", weight++));
+		attrubutes.addAttribute(new CAttribute("Start Time",
+			m_strStartTime.c_str(), "", weight++));
+		attrubutes.addAttribute(new CAttribute("End Time",
+			m_strEndTime.c_str(), "", weight++));
+		attrubutes.addAttribute(new CAttribute("Total Parameter",
+			std::to_string(m_nTotalParameter).c_str(), "", weight++));
+		attrubutes.addAttribute(new CAttribute("Total Group",
+			std::to_string(m_nTotalGroup).c_str(), "", weight++));
+		attrubutes.addAttribute(new CAttribute("Current Group",
+			std::to_string(m_nCurrentGroup).c_str(), "", weight++));
+
+		char szName[256];
+		int index = 0;
+		for (auto item : m_params) {
+			sprintf_s(szName, 256, "Parameter %d", ++index);
+			attrubutes.addAttribute(new CAttribute(szName,
+				item.c_str(), "", weight++));
+		}
+	}
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CProcessData.h b/SourceCode/Bond/Servo/CProcessData.h
new file mode 100644
index 0000000..270a359
--- /dev/null
+++ b/SourceCode/Bond/Servo/CProcessData.h
@@ -0,0 +1,34 @@
+#pragma once
+#include <list>
+#include "CAttributeVector.h"
+
+
+namespace SERVO {
+	class CProcessData
+	{
+	public:
+		CProcessData();
+		~CProcessData();
+
+	public:
+		std::string& getGlassId();
+		std::string& getStartTime();
+		std::string& getEndTime();
+		unsigned int getTotalParameter();
+		const std::list<std::string>& getParameters();
+		void getParameters(std::list<std::string>& list);
+		int serialize(char* pszBuffer, int nBufferSize);
+		int unserialize(const char* pszBuffer, int nBufferSize);
+		void getAttributeVector(CAttributeVector& attrubutes, int beginWeight);
+
+	private:
+		std::string m_strGlassId;
+		std::string m_strStartTime;
+		std::string m_strEndTime;
+		unsigned int m_nTotalParameter;
+		unsigned int m_nTotalGroup;
+		unsigned int m_nCurrentGroup;
+		std::list<std::string> m_params;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CVacuumBake.cpp b/SourceCode/Bond/Servo/CVacuumBake.cpp
index 556d029..30e6da5 100644
--- a/SourceCode/Bond/Servo/CVacuumBake.cpp
+++ b/SourceCode/Bond/Servo/CVacuumBake.cpp
@@ -67,4 +67,29 @@
 
 		return m_glassList.empty();
 	}
+
+	BOOL CVacuumBake::onPreStoredJob(int port, CJobDataB* pJobDataB)
+	{
+		CJobDataS* pJobDataS = getJobDataS(pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo());
+		if (pJobDataS == nullptr) {
+			LOGE("<CEquipment-%s>onPreFetchedOutJob,找不到对应的JobDataS(CassetteSequenceNo:%d, JobSequenceNo:%d), 注意排查风险!", m_strName.c_str(),
+				pJobDataB->getCassetteSequenceNo(), pJobDataB->getJobSequenceNo());
+			return FALSE;
+		}
+
+		// 当前不能有任何玻璃,且当前准备进的片是G1
+		Lock();
+		if (!m_glassList.empty()) {
+			Unlock();
+			LOGE("<CEquipment-%s>onPreFetchedOutJob,当前机器或单元存在玻璃片,不能进料,请注意风险!", m_strName.c_str());
+			return FALSE;
+		}
+
+		if (pJobDataS->getMaterialsType() != (int)MaterialsType::G1) {
+			LOGE("<CEquipment-%s>onPreFetchedOutJob,当前机器或单元只能进G2玻璃片,请注意风险!", m_strName.c_str());
+			return FALSE;
+		}
+
+		return TRUE;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CVacuumBake.h b/SourceCode/Bond/Servo/CVacuumBake.h
index f8b4bff..dc0c59f 100644
--- a/SourceCode/Bond/Servo/CVacuumBake.h
+++ b/SourceCode/Bond/Servo/CVacuumBake.h
@@ -20,6 +20,7 @@
         virtual void getAttributeVector(CAttributeVector& attrubutes);
         virtual int recvIntent(CPin* pPin, CIntent* pIntent);
         virtual BOOL glassWillArrive(CGlass* pGlass);
+        virtual BOOL onPreStoredJob(int port, CJobDataB* pJobDataB);
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index b4b4a75..957fc81 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/SourceCode/Bond/Servo/Common.h
@@ -1,6 +1,8 @@
 #pragma once
 
 
+#define TESTMODE						1
+
 /* Rx Code */
 #define RX_CODE_TEST					0
 #define RX_CODE_LOG						1000
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index c894f16..d7a30ed 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -195,6 +195,8 @@
     <Text Include="ReadMe.txt" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="CDoubleGlass.h" />
+    <ClInclude Include="CProcessData.h" />
     <ClInclude Include="PageAlarm.h" />
     <ClInclude Include="AlarmManager.h" />
     <ClInclude Include="ApredTreeCtrl2.h" />
@@ -289,6 +291,8 @@
     <ClInclude Include="VerticalLine.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="CDoubleGlass.cpp" />
+    <ClCompile Include="CProcessData.cpp" />
     <ClCompile Include="PageAlarm.cpp" />
     <ClCompile Include="AlarmManager.cpp" />
     <ClCompile Include="ApredTreeCtrl2.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index e250419..958f369 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -100,6 +100,8 @@
     <ClCompile Include="CArm.cpp" />
     <ClCompile Include="CArmTray.cpp" />
     <ClCompile Include="ProductionLogManager.cpp" />
+    <ClCompile Include="CDoubleGlass.cpp" />
+    <ClCompile Include="CProcessData.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -198,6 +200,8 @@
     <ClInclude Include="CArm.h" />
     <ClInclude Include="CArmTray.h" />
     <ClInclude Include="ProductionLogManager.h" />
+    <ClInclude Include="CDoubleGlass.h" />
+    <ClInclude Include="CProcessData.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />

--
Gitblit v1.9.3