From 1e7d3ca649456469440d74fabfc16e191433f9b4 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期五, 09 五月 2025 17:47:25 +0800
Subject: [PATCH] 1.实现FetchOut Job功能;

---
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5(5).xlsx                   |    0 
 SourceCode/Bond/Servo/Servo.vcxproj                                               |    6 
 SourceCode/Bond/Servo/CArmTray.h                                                  |   23 +
 SourceCode/Bond/Servo/CArm.cpp                                                    |   97 +++++
 SourceCode/Bond/Servo/CPageGraph2.h                                               |    2 
 SourceCode/Bond/Servo/Servo.vcxproj.user                                          |    6 
 SourceCode/Bond/Servo/CJobDataS.h                                                 |    3 
 SourceCode/Bond/Servo/CJobDataS.cpp                                               |  218 +++++++++++
 SourceCode/Bond/Servo/CEFEM.h                                                     |   11 
 SourceCode/Bond/Servo/CMaster.h                                                   |   16 
 SourceCode/Bond/Servo/EqsGraphWnd.cpp                                             |   27 +
 SourceCode/Bond/Servo/CStep.h                                                     |    5 
 SourceCode/Bond/Servo/CEquipment.cpp                                              |  114 ++++++
 SourceCode/Bond/Servo/CEqJobEventStep.h                                           |    6 
 SourceCode/Bond/Servo/Servo.rc                                                    |    0 
 SourceCode/Bond/Servo/CMaster.cpp                                                 |  114 +++++
 SourceCode/Bond/Servo/CEqReadStep.cpp                                             |    8 
 SourceCode/Bond/Servo/CArm.h                                                      |   30 +
 SourceCode/Bond/Servo/CStep.cpp                                                   |   12 
 SourceCode/Bond/Servo/CEqReadStep.h                                               |    2 
 SourceCode/Bond/Servo/CPageGraph2.cpp                                             |   54 ++
 SourceCode/Bond/Servo/EqsGraphWnd.h                                               |    2 
 Document/ESWIN_EAS_Equipment_Communication_Specification(CC-LINK)_v3.1(翻译结果).docx |    0 
 SourceCode/Bond/Servo/CJobDataB.cpp                                               |    2 
 SourceCode/Bond/Servo/Model.cpp                                                   |    4 
 Document/2860MES交握表.xlsx                                                          |    0 
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx                      |    0 
 SourceCode/Bond/Servo/CPageGraph1.cpp                                             |    5 
 /dev/null                                                                         |    0 
 SourceCode/Bond/Servo/Servo.vcxproj.filters                                       |    4 
 SourceCode/Bond/Servo/CEqJobEventStep.cpp                                         |  113 ++++-
 SourceCode/Bond/Servo/CJobDataA.cpp                                               |    2 
 SourceCode/Bond/Servo/CJobDataA.h                                                 |    2 
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx                      |    0 
 SourceCode/Bond/Servo/CJobDataB.h                                                 |    2 
 SourceCode/Bond/Servo/CEqStatusStep.cpp                                           |    2 
 SourceCode/Bond/Servo/CArmTray.cpp                                                |   56 ++
 SourceCode/Bond/Servo/CEFEM.cpp                                                   |   74 +++
 SourceCode/Bond/Servo/CEquipment.h                                                |   16 
 SourceCode/Bond/Servo/CBonder.cpp                                                 |    8 
 SourceCode/Bond/Servo/Common.h                                                    |   35 +
 41 files changed, 1,010 insertions(+), 71 deletions(-)

diff --git "a/Document/2860MES\344\272\244\346\217\241\350\241\250.xlsx" "b/Document/2860MES\344\272\244\346\217\241\350\241\250.xlsx"
new file mode 100644
index 0000000..a27567c
--- /dev/null
+++ "b/Document/2860MES\344\272\244\346\217\241\350\241\250.xlsx"
Binary files differ
diff --git a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx
index fe5bd01..77c0949 100644
--- a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx
+++ b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx
Binary files differ
diff --git "a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0505\051.xlsx" "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0505\051.xlsx"
index 35d3f51..0e5b4b9 100644
--- "a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0505\051.xlsx"
+++ "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0505\051.xlsx"
Binary files differ
diff --git a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx
index ca31dfe..e7d314b 100644
--- a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx
+++ b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx
Binary files differ
diff --git "a/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx" "b/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
index a920e8a..f9457c2 100644
--- "a/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
+++ "b/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
Binary files differ
diff --git "a/Document/~$WIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx" "b/Document/~$WIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
deleted file mode 100644
index ac59be7..0000000
--- "a/Document/~$WIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
+++ /dev/null
Binary files differ
diff --git a/SourceCode/Bond/Servo/CArm.cpp b/SourceCode/Bond/Servo/CArm.cpp
new file mode 100644
index 0000000..e698692
--- /dev/null
+++ b/SourceCode/Bond/Servo/CArm.cpp
@@ -0,0 +1,97 @@
+#include "stdafx.h"
+#include "CArm.h"
+
+
+namespace SERVO {
+	CArm::CArm() : CEquipment()
+	{
+	}
+
+	CArm::~CArm()
+	{
+
+	}
+
+	const char* CArm::getClassName()
+	{
+		static char* pszName = "CArm";
+		return pszName;
+	}
+
+	void CArm::init()
+	{
+		CEquipment::init();
+	}
+
+	void CArm::term()
+	{
+		CEquipment::term();
+	}
+
+	// 必须要实现的虚函数,在此初始化Pin列表
+	void CArm::initPins()
+	{
+
+	}
+
+	void CArm::onTimer(UINT nTimerid)
+	{
+		CEquipment::onTimer(nTimerid);
+	}
+
+	void CArm::serialize(CArchive& ar)
+	{
+		CEquipment::serialize(ar);
+	}
+
+	void CArm::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		__super::getAttributeVector(attrubutes);
+	}
+
+	int CArm::recvIntent(CPin* pPin, CIntent* pIntent)
+	{
+		return __super::recvIntent(pPin, pIntent);
+	}
+
+	int CArm::tempStore(CGlass* pGlass)
+	{
+		// 保证列表中只存储一个物料
+		Lock();
+		for (auto item : m_glassList) {
+			item->release();
+		}
+		m_glassList.clear();
+		addGlassToList(pGlass);
+		Unlock();
+
+		if (m_listener.onDataChanged != nullptr) {
+			m_listener.onDataChanged(this, 0);
+		}
+
+		return 0;
+	}
+
+	int CArm::tempFetchOut(OUT CGlass*& pGlass)
+	{
+		Lock();
+		if (m_glassList.empty()) {
+			Unlock();
+			return -1;
+		}
+
+		pGlass = m_glassList.front();
+		pGlass->addRef();
+		for (auto item : m_glassList) {
+			item->release();
+		}
+		m_glassList.clear();
+		Unlock();
+
+		if (m_listener.onDataChanged != nullptr) {
+			m_listener.onDataChanged(this, 0);
+		}
+
+		return 0;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CArm.h b/SourceCode/Bond/Servo/CArm.h
new file mode 100644
index 0000000..4a12834
--- /dev/null
+++ b/SourceCode/Bond/Servo/CArm.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "CEquipment.h"
+
+
+namespace SERVO {
+	class CArm : public CEquipment
+	{
+    public:
+        CArm();
+        virtual ~CArm();
+
+    public:
+        virtual const char* getClassName();
+        virtual BOOL isArm() { return TRUE; };
+        virtual void init();
+        virtual void term();
+        virtual void initPins();
+        virtual void onTimer(UINT nTimerid);
+        virtual void serialize(CArchive& ar);
+        virtual void getAttributeVector(CAttributeVector& attrubutes);
+        virtual int recvIntent(CPin* pPin, CIntent* pIntent);
+
+    public:
+        int tempStore(CGlass* pGlass);
+
+        // 调用tempFetchOut后,pGlass必须release一次
+        int tempFetchOut(OUT CGlass*& pGlass);
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CArmTray.cpp b/SourceCode/Bond/Servo/CArmTray.cpp
new file mode 100644
index 0000000..ddb8b30
--- /dev/null
+++ b/SourceCode/Bond/Servo/CArmTray.cpp
@@ -0,0 +1,56 @@
+#include "stdafx.h"
+#include "CArmTray.h"
+
+
+namespace SERVO {
+	CArmTray::CArmTray() : CEquipment()
+	{
+	}
+
+	CArmTray::~CArmTray()
+	{
+
+	}
+
+	const char* CArmTray::getClassName()
+	{
+		static char* pszName = "CArmTray";
+		return pszName;
+	}
+
+	void CArmTray::init()
+	{
+		CEquipment::init();
+	}
+
+	void CArmTray::term()
+	{
+		CEquipment::term();
+	}
+
+	// 必须要实现的虚函数,在此初始化Pin列表
+	void CArmTray::initPins()
+	{
+
+	}
+
+	void CArmTray::onTimer(UINT nTimerid)
+	{
+		CEquipment::onTimer(nTimerid);
+	}
+
+	void CArmTray::serialize(CArchive& ar)
+	{
+		CEquipment::serialize(ar);
+	}
+
+	void CArmTray::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		__super::getAttributeVector(attrubutes);
+	}
+
+	int CArmTray::recvIntent(CPin* pPin, CIntent* pIntent)
+	{
+		return __super::recvIntent(pPin, pIntent);
+	}
+}
diff --git a/SourceCode/Bond/Servo/CArmTray.h b/SourceCode/Bond/Servo/CArmTray.h
new file mode 100644
index 0000000..8a08cf0
--- /dev/null
+++ b/SourceCode/Bond/Servo/CArmTray.h
@@ -0,0 +1,23 @@
+#pragma once
+#include "CEquipment.h"
+
+
+namespace SERVO {
+	class CArmTray : public CEquipment
+	{
+    public:
+        CArmTray();
+        virtual ~CArmTray();
+
+    public:
+        virtual const char* getClassName();
+        virtual void init();
+        virtual void term();
+        virtual void initPins();
+        virtual void onTimer(UINT nTimerid);
+        virtual void serialize(CArchive& ar);
+        virtual void getAttributeVector(CAttributeVector& attrubutes);
+        virtual int recvIntent(CPin* pPin, CIntent* pIntent);
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CBonder.cpp b/SourceCode/Bond/Servo/CBonder.cpp
index 2596d31..04747f5 100644
--- a/SourceCode/Bond/Servo/CBonder.cpp
+++ b/SourceCode/Bond/Servo/CBonder.cpp
@@ -113,7 +113,7 @@
 			CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
 			pStep->setName(STEP_CIM_MESSAGE_CMD);
 			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x361 : 0x661);
-			pStep->setCimMessageDev(m_nIndex == 0 ? 0x963 : 0x12b3);
+			pStep->setCimMessageDev(m_nIndex == 0 ? 0x950 : 0x12a0);
 			if (addStep(STEP_ID_CIM_MSG_SET_CMD_REPLY, pStep) != 0) {
 				delete pStep;
 			}
@@ -132,6 +132,8 @@
 
 		{
 			// CIM Message Confirm
+			// 要将int32的值拆分为两个short, 分别为msg id和panel id
+			// 65538, 2为msg id, 1为panel id
 			CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, m_nIndex == 0 ? 0x9d80 : 0xdd80);
 			pStep->setName(STEP_EQ_CIM_MESSAGE_CONFIRM);
 			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x349 : 0x649);
@@ -185,7 +187,7 @@
 		{
 			// master recipe list report
 			CEqReadStep* pStep = new CEqReadStep(m_nIndex == 0 ? 0xa955 : 0xe955, 255 * 2,
-				[&](int code, const char* pszData, size_t size) -> int {
+				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
 					if (code == ROK && pszData != nullptr && size > 0) {
 						// 此处解释配方数据
 						short ret = decodeRecipeListReport(pszData, size);
@@ -216,7 +218,7 @@
 		{
 			// recipe parameter report
 			CEqReadStep* pStep = new CEqReadStep(m_nIndex == 0 ? 0xaa54 : 0xea54, 257 * 2,
-				[&](int code, const char* pszData, size_t size) -> int {
+				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
 					if (code == ROK && pszData != nullptr && size > 0) {
 						// 此处解释配方数据
 						short ret = decodeRecipeParameterReport(pszData, size);
diff --git a/SourceCode/Bond/Servo/CEFEM.cpp b/SourceCode/Bond/Servo/CEFEM.cpp
index 4520495..3918188 100644
--- a/SourceCode/Bond/Servo/CEFEM.cpp
+++ b/SourceCode/Bond/Servo/CEFEM.cpp
@@ -19,6 +19,8 @@
 		m_pPort[1] = nullptr;
 		m_pPort[2] = nullptr;
 		m_pPort[3] = nullptr;
+		m_pAligner = nullptr;
+		m_pFliper = nullptr;
 	}
 
 	CEFEM::~CEFEM()
@@ -36,6 +38,23 @@
 	{
 		if (index < 4) {
 			m_pPort[index] = pPort;
+		}
+	}
+
+	void CEFEM::setAligner(CAligner* pAligner)
+	{
+		m_pAligner = pAligner;
+	}
+
+	void CEFEM::setFliper(CFliper* pFliper)
+	{
+		m_pFliper = pFliper;
+	}
+
+	void CEFEM::setArmTray(unsigned int index, CArmTray* pArmTray)
+	{
+		if (index < 2) {
+			m_pArmTray[index] = pArmTray;
 		}
 	}
 
@@ -213,7 +232,6 @@
 			}
 		}
 
-
 		{
 			// 请求主配方列表的step
 			CEqWriteStep* pStep = new CEqWriteStep();
@@ -274,6 +292,30 @@
 			STEP_ID_PORT4_CASSETTIE_UNLOAD_READY, 0x60b0);
 		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_BLOCKED, 0x103,
 			STEP_ID_PORT4_CASSETTIE_BLOCKED, 0x60b0);
+
+		{
+			// Fetched Out Job Report #1~15
+			char szBuffer[256];
+			for (int i = 0; i < 15; i++) {
+				CEqReadStep* pStep = new CEqReadStep(0x5c31 + 18 * i, 18 * 2,
+					[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
+						if (code == ROK && pszData != nullptr && size > 0) {
+							int port = (int)((CEqReadStep*)pFrom)->getProp("Port");
+							if (port > 0) {
+								decodeFetchedOutJobReport(port, pszData, size);
+							}
+						}
+						return -1;
+					});
+				sprintf_s(szBuffer, "%s%d", STEP_EQ_FETCHED_OUT_JOBn, i+1);
+				pStep->setName(szBuffer);
+				pStep->setProp("Port", (void*)(__int64)(i + 1));
+				pStep->setWriteSignalDev(0x023 + i);
+				if (addStep(STEP_ID_FETCHED_OUT_JOB_REPORT1 + i, pStep) != 0) {
+					delete pStep;
+				}
+			}
+		}
 	}
 
 	int CEFEM::onStepEvent(CStep* pStep, int code)
@@ -335,4 +377,34 @@
 			}
 		}
 	}
+
+	int CEFEM::onFetchedOut(int port, const char* pszGlassId)
+	{
+		if (port == 1) {
+			return m_pPort[0]->fetchedOut(pszGlassId);
+		}
+		if (port == 2) {
+			return m_pPort[1]->fetchedOut(pszGlassId);
+		}
+		if (port == 3) {
+			return m_pPort[2]->fetchedOut(pszGlassId);
+		}
+		if (port == 4) {
+			return m_pPort[3]->fetchedOut(pszGlassId);
+		}
+		if (port == 5) {
+			return m_pArmTray[0]->fetchedOut(pszGlassId);
+		}
+		if (port == 6) {
+			return m_pArmTray[1]->fetchedOut(pszGlassId);
+		}
+		if (port == 7) {
+			return m_pAligner->fetchedOut(pszGlassId);
+		}
+		if (port == 8) {
+			return m_pFliper->fetchedOut(pszGlassId);
+		}
+
+		return -1;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CEFEM.h b/SourceCode/Bond/Servo/CEFEM.h
index 2d7cc4b..522456b 100644
--- a/SourceCode/Bond/Servo/CEFEM.h
+++ b/SourceCode/Bond/Servo/CEFEM.h
@@ -1,6 +1,9 @@
 #pragma once
 #include "CEquipment.h"
 #include "CLoadPort.h"
+#include "CAligner.h"
+#include "CFliper.h"
+#include "CArmTray.h"
 
 
 namespace SERVO {
@@ -24,13 +27,19 @@
         virtual int recvIntent(CPin* pPin, CIntent* pIntent);
         virtual BOOL glassWillArrive(CGlass* pGlass);
         virtual void onReceiveLBData(const char* pszData, size_t size);
+        virtual int onFetchedOut(int port, const char* pszGlassId);
 
     public:
         void setPort(unsigned int index, CLoadPort* pPort);
-
+        void setAligner(CAligner* pAligner);
+        void setFliper(CFliper* pFliper);
+        void setArmTray(unsigned int index, CArmTray* pArmTray);
 
     private:
         CLoadPort* m_pPort[4];
+        CAligner* m_pAligner;
+        CFliper* m_pFliper;
+        CArmTray* m_pArmTray[2];
     };
 }
 
diff --git a/SourceCode/Bond/Servo/CEqJobEventStep.cpp b/SourceCode/Bond/Servo/CEqJobEventStep.cpp
index a0efb8b..49d43b8 100644
--- a/SourceCode/Bond/Servo/CEqJobEventStep.cpp
+++ b/SourceCode/Bond/Servo/CEqJobEventStep.cpp
@@ -26,23 +26,96 @@
 		std::string strTemp;
 		attrubutes.addAttribute(new CAttribute("Dev",
 			("W" + CToolUnits::toHexString(m_nJobDataADev, strTemp)).c_str(), ""));
-		attrubutes.addAttribute(new CAttribute("PortNo",
-			std::to_string(m_jobDataA.getPortNo()).c_str(), ""));
-		attrubutes.addAttribute(new CAttribute("CarrierId",
-			m_jobDataA.getCarrierId().c_str(), ""));
-		attrubutes.addAttribute(new CAttribute("PruductId",
-			m_jobDataA.getPruductId().c_str(), ""));
-		attrubutes.addAttribute(new CAttribute("CarrierState",
-			m_jobDataA.getCarrierStateDescription(strTemp).c_str(), ""));
-		attrubutes.addAttribute(new CAttribute("SlotMapping",
-			std::to_string(m_jobDataA.getSlotMapping()).c_str(), ""));
-		attrubutes.addAttribute(new CAttribute("SlotSelectedFlag",
-			std::to_string(m_jobDataA.getSlotSelectedFlag()).c_str(), ""));
-		std::vector<std::string>& ids = m_jobDataA.getGlassIds();
-		for (int i = 0; i < ids.size(); i++) {
-			attrubutes.addAttribute(new CAttribute((std::string("GlassId") + std::to_string(i+1)).c_str(),
-				ids[i].c_str(), ""));
-		}
+	
+		attrubutes.addAttribute(new CAttribute("CassetteSequenceNo",
+			std::to_string(m_jobDataS.getCassetteSequenceNo()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("JobSequenceNo",
+			std::to_string(m_jobDataS.getJobSequenceNo()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("LotId",
+			m_jobDataS.getLotId().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("ProductId",
+			m_jobDataS.getProductId().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("OperationId",
+			m_jobDataS.getOperationId().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("Glass1Id",
+			m_jobDataS.getGlass1Id().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("Glass2Id",
+			m_jobDataS.getGlass2Id().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("JobType",
+			std::to_string(m_jobDataS.getJobType()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("MaterialsType",
+			std::to_string(m_jobDataS.getMaterialsType()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("ProductType",
+			std::to_string(m_jobDataS.getProductType()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("DummyType",
+			std::to_string(m_jobDataS.getDummyType()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("SkipFlag",
+			std::to_string(m_jobDataS.getSkipFlag()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("ProcessFlag",
+			std::to_string(m_jobDataS.getProcessFlag()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("ProcessResonCode",
+			std::to_string(m_jobDataS.getProcessResonCode()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("LastGlassFlag",
+			std::to_string(m_jobDataS.getLastGlassFlag()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("FirstGlassFlag",
+			std::to_string(m_jobDataS.getFirstGlassFlag()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("QTime1",
+			std::to_string(m_jobDataS.getQTime(0)).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("QTime2",
+			std::to_string(m_jobDataS.getQTime(1)).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("QTime3",
+			std::to_string(m_jobDataS.getQTime(2)).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("QTimeOverFlag",
+			std::to_string(m_jobDataS.getQTimeOverFlag()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("MasterRecipe",
+			std::to_string(m_jobDataS.getMasterRecipe()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("ProductRecipeId",
+			m_jobDataS.getProductRecipeId().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("PCode",
+			m_jobDataS.getPCode().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("UseType",
+			m_jobDataS.getUseType().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("PanelMeasure",
+			m_jobDataS.getPanelMeasure().c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("SlotUnitSelectFlag",
+			std::to_string(m_jobDataS.getSlotUnitSelectFlag()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("SourcePortNo",
+			std::to_string(m_jobDataS.getSourcePortNo()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("SourceSlotNo",
+			std::to_string(m_jobDataS.getSourceSlotNo()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("TargetPortNo",
+			std::to_string(m_jobDataS.getTargetPortNo()).c_str(), ""));
+
+		attrubutes.addAttribute(new CAttribute("TargetSlotNo",
+			std::to_string(m_jobDataS.getTargetSlotNo()).c_str(), ""));
 	}
 
 	int CEqJobEventStep::onReadData()
@@ -57,7 +130,7 @@
 			return -1;
 		}
 
-		m_jobDataA.unserialize(szBuffer, 640);
+		m_jobDataS.unserialize(szBuffer, 640);
 		LOGI("<CEqJobEventStep-%s>Read JobDataA\n", m_strName.c_str());
 
 		return 0;
@@ -79,8 +152,8 @@
 		return 0;
 	}
 
-	CJobDataA* CEqJobEventStep::getJobDataA()
+	CJobDataS* CEqJobEventStep::getJobDataS()
 	{
-		return &m_jobDataA;
+		return &m_jobDataS;
 	}
 }
diff --git a/SourceCode/Bond/Servo/CEqJobEventStep.h b/SourceCode/Bond/Servo/CEqJobEventStep.h
index 380470f..71eb425 100644
--- a/SourceCode/Bond/Servo/CEqJobEventStep.h
+++ b/SourceCode/Bond/Servo/CEqJobEventStep.h
@@ -1,6 +1,6 @@
 #pragma once
 #include "CReadStep.h"
-#include "CJobDataA.h"
+#include "CJobDataS.h"
 
 
 namespace SERVO {
@@ -16,11 +16,11 @@
 		virtual int onComplete();
 		virtual int onTimeout();
 		void setJobDataDev(int nDev);
-		CJobDataA* getJobDataA();
+		CJobDataS* getJobDataS();
 
 	private:
 		int m_nJobDataADev;
-		CJobDataA m_jobDataA;
+		CJobDataS m_jobDataS;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CEqReadStep.cpp b/SourceCode/Bond/Servo/CEqReadStep.cpp
index 854338e..c1bf97d 100644
--- a/SourceCode/Bond/Servo/CEqReadStep.cpp
+++ b/SourceCode/Bond/Servo/CEqReadStep.cpp
@@ -43,14 +43,14 @@
 		if (0 != nRet) {
 			LOGI("<CEqReadStep>Read data error.");
 			if (m_onReadBlock != nullptr) {
-				m_onReadBlock(RERROR, nullptr, 0);
+				m_onReadBlock(this, RERROR, nullptr, 0);
 			}
 			return -1;
 		}
 
 		LOGI("<CEqReadStep>read data succeed.");
 		if (m_onReadBlock != nullptr) {
-			m_onReadBlock(ROK, szBuffer, m_nReadSize);
+			m_onReadBlock(this, ROK, szBuffer, m_nReadSize);
 		}
 
 
@@ -62,7 +62,7 @@
 		CReadStep::onComplete();
 		LOGI("<CEqReadStep> onComplete.");
 		if (m_onReadBlock != nullptr) {
-			m_onReadBlock(RCOMPLETE, nullptr, 0);
+			m_onReadBlock(this, RCOMPLETE, nullptr, 0);
 		}
 
 		return 0;
@@ -73,7 +73,7 @@
 		CReadStep::onTimeout();
 		LOGI("<CEqReadStep> onTimeout.");
 		if (m_onReadBlock != nullptr) {
-			m_onReadBlock(RTIMEOUT, nullptr, 0);
+			m_onReadBlock(this, RTIMEOUT, nullptr, 0);
 		}
 
 		return 0;
diff --git a/SourceCode/Bond/Servo/CEqReadStep.h b/SourceCode/Bond/Servo/CEqReadStep.h
index fa9a2b3..3a83c35 100644
--- a/SourceCode/Bond/Servo/CEqReadStep.h
+++ b/SourceCode/Bond/Servo/CEqReadStep.h
@@ -11,7 +11,7 @@
 #define RCOMPLETE		1					/* 读数据流程完成 */
 
 namespace SERVO {
-	typedef std::function<int(int code, const char* pszData, size_t size)> ONREAD;
+	typedef std::function<int(void* pFrom, int code, const char* pszData, size_t size)> ONREAD;
 
 	class CEqReadStep : public CReadStep
 	{
diff --git a/SourceCode/Bond/Servo/CEqStatusStep.cpp b/SourceCode/Bond/Servo/CEqStatusStep.cpp
index 52eaa0f..bfc2e19 100644
--- a/SourceCode/Bond/Servo/CEqStatusStep.cpp
+++ b/SourceCode/Bond/Servo/CEqStatusStep.cpp
@@ -9,7 +9,7 @@
 	{
 		m_nStatusDev = 0;
 		for (int i = 0; i < STATUS_MAX; i++) {
-			m_nStatus[i] = 7;
+			m_nStatus[i] = 0;
 			m_nReasonCode[i] = 0;
 		}
 	
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index b2e3ad3..fe9cfe6 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -2,6 +2,7 @@
 #include "CEquipment.h"
 #include "ToolUnits.h"
 #include <regex>
+#include "CArm.h"
 
 
 #define CHECK_READ_STEP_SIGNAL(addr, data, size) {							\
@@ -34,6 +35,7 @@
 		m_bVCREnable[0] = FALSE;
 		m_pCclink = nullptr;
 		m_nBaseAlarmId = 0;
+		m_pArm = nullptr;
 		InitializeCriticalSection(&m_criticalSection);
 	}
 
@@ -74,6 +76,13 @@
 	void CEquipment::setCcLink(CCCLinkIEControl* pCcLink)
 	{
 		m_pCclink = pCcLink;
+	}
+
+	void CEquipment::setArm(CEquipment* pEquipment)
+	{
+		ASSERT(pEquipment->isArm());
+		ASSERT(!this->isArm());
+		m_pArm = pEquipment;
 	}
 
 	void CEquipment::setBaseAlarmId(int nBaseId)
@@ -382,6 +391,14 @@
 			CHECK_READ_STEP_SIGNAL(STEP_ID_EQMODE_CHANGED + i, pszData, size);
 		}
 
+		// process data report
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PROCESS_DATA_REPORT, pszData, size);
+
+		// 配方改变
+		CHECK_READ_STEP_SIGNAL(STEP_ID_CURRENT_RECIPE_CHANGE_REPORT, pszData, size);
+		
+		// 主配方上报
+		CHECK_READ_STEP_SIGNAL(STEP_ID_MASTER_RECIPE_LIST_REPORT, pszData, size);
 
 		// CIM Mode
 		CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIMMODE_CHANGED_CMD_REPLY, pszData, size);
@@ -769,6 +786,75 @@
 		return pGlass;
 	}
 
+	int CEquipment::fetchedOut(const char* pszGlassId)
+	{
+		if (m_pArm == nullptr) {
+			return -1;
+		}
+
+		// 找到指定的glass id, 
+		Lock();
+		if (m_glassList.empty()) {
+			Unlock();
+			return -2;
+		}
+
+		CGlass* pContext = nullptr;
+		for (auto iter = m_glassList.begin(); iter != m_glassList.end(); iter++) {
+			if ((*iter)->getID().compare(pszGlassId) == 0) {
+				pContext = (*iter);
+				m_glassList.erase(iter);
+				break;
+			}
+		}
+		if (pContext == nullptr) {
+			Unlock();
+			return -3;
+		}
+
+		((CArm*)m_pArm)->tempStore(pContext);
+		pContext->release();
+		Unlock();
+
+		if (m_listener.onDataChanged != nullptr) {
+			m_listener.onDataChanged(this, 0);
+		}
+
+		return 0;
+	}
+
+	int CEquipment::storeJob(const char* pszGlassId)
+	{
+		if (m_pArm == nullptr) {
+			return -1;
+		}
+
+		CGlass* pGlass = nullptr;
+		if (((CArm*)m_pArm)->tempFetchOut(pGlass) != 0) {
+			return -2;
+		}
+
+
+		ASSERT(pGlass);
+		Lock();
+		pGlass->addPath(m_nID);
+		pGlass->addRef();					// 加入list,addRef
+		m_glassList.push_back(pGlass);
+		pGlass->release();				// tempFetchOut需要调用一次release
+		Unlock();
+
+		if (m_listener.onDataChanged != nullptr) {
+			m_listener.onDataChanged(this, 0);
+		}
+
+		return 0;
+	}
+
+	BOOL CEquipment::isGlassListEmpty()
+	{
+		return m_glassList.empty();
+	}
+
 	bool CEquipment::isAlarmStep(SERVO::CStep* pStep)
 	{
 		return CToolUnits::startsWith(pStep->getName(), STEP_ALARM_START);
@@ -938,4 +1024,32 @@
 	{
 		return m_recipesManager.decodeRecipeParameterReport(pszData, size);
 	}
+
+	int CEquipment::decodeFetchedOutJobReport(int port, const char* pszData, size_t size)
+	{
+		int index = 0;
+		short unitOrPort, unitOrPortNo, subUnitNo, subSlotNo;
+		CJobDataB jobDataB;
+		int nRet = jobDataB.unserialize(&pszData[index], size);
+		if (nRet < 0) return nRet;
+		index += nRet;
+
+		memcpy(&unitOrPort, &pszData[index], sizeof(short));
+		index += sizeof(short);
+		memcpy(&unitOrPortNo, &pszData[index], sizeof(short));
+		index += sizeof(short);
+		memcpy(&subUnitNo, &pszData[index], sizeof(short));
+		index += sizeof(short);
+		memcpy(&subSlotNo, &pszData[index], sizeof(short));
+		index += sizeof(short);
+
+		onFetchedOut(port, jobDataB.getGlassId().c_str());
+
+		return index;
+	}
+
+	int CEquipment::onFetchedOut(int port, const char* pszGlassId)
+	{
+		return fetchedOut(pszGlassId);
+	}
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index 0b66f2f..e655f2c 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -27,6 +27,10 @@
 #include <list>
 #include "CGlass.h"
 #include "CRecipesManager.h"
+#include "CJobDataA.h"
+#include "CJobDataB.h"
+#include "CJobDataC.h"
+#include "CJobDataS.h"
 
 
 namespace SERVO {
@@ -74,6 +78,8 @@
 		virtual const char* getClassName() = 0;
 		virtual void setListener(EquipmentListener listener);
 		void setCcLink(CCCLinkIEControl* pCcLink);
+		virtual BOOL isArm() { return FALSE; };
+		void setArm(CEquipment* pEquipment);
 		void setBaseAlarmId(int nBaseId);
 		int getBaseAlarmId();
 		void setID(int nID);
@@ -139,6 +145,11 @@
 		// unitNo: 0:local; Others:unit No
 		int recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo);
 
+	public:
+		int fetchedOut(const char* pszGlassId);
+		int storeJob(const char* pszGlassId);
+		BOOL isGlassListEmpty();
+
 
 	// 以下为从CC-Link读取到的Bit标志位检测函数
 	public:
@@ -158,6 +169,8 @@
 		void addGlassToList(CGlass* pGlass);
 		short decodeRecipeListReport(const char* pszData, size_t size);
 		short decodeRecipeParameterReport(const char* pszData, size_t size);
+		int decodeFetchedOutJobReport(int port, const char* pszData, size_t size);
+		int onFetchedOut(int port, const char* pszGlassId);
 
 	protected:
 		EquipmentListener m_listener;
@@ -188,6 +201,9 @@
 		std::map<unsigned int, CStep*> m_mapStep;
 		int m_nBaseAlarmId;
 		CRecipesManager m_recipesManager;
+
+	private:
+		CEquipment* m_pArm;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CJobDataA.cpp b/SourceCode/Bond/Servo/CJobDataA.cpp
index 4c5e3e4..03d90ff 100644
--- a/SourceCode/Bond/Servo/CJobDataA.cpp
+++ b/SourceCode/Bond/Servo/CJobDataA.cpp
@@ -64,7 +64,7 @@
 		return 320 * 2;
 	}
 
-	int CJobDataA::unserialize(char* pszBuffer, int nBufferSize)
+	int CJobDataA::unserialize(const char* pszBuffer, int nBufferSize)
 	{
 		if (nBufferSize < 640) return -1;
 
diff --git a/SourceCode/Bond/Servo/CJobDataA.h b/SourceCode/Bond/Servo/CJobDataA.h
index 86b761a..c3879d4 100644
--- a/SourceCode/Bond/Servo/CJobDataA.h
+++ b/SourceCode/Bond/Servo/CJobDataA.h
@@ -20,7 +20,7 @@
 		int getSlotSelectedFlag();
 		std::vector<std::string>& getGlassIds();
 		int serialize(char* pszBuffer, int nBufferSize);
-		int unserialize(char* pszBuffer, int nBufferSize);
+		int unserialize(const char* pszBuffer, int nBufferSize);
 
 	private:
 		short m_nPortNo;
diff --git a/SourceCode/Bond/Servo/CJobDataB.cpp b/SourceCode/Bond/Servo/CJobDataB.cpp
index c269779..9c00cb7 100644
--- a/SourceCode/Bond/Servo/CJobDataB.cpp
+++ b/SourceCode/Bond/Servo/CJobDataB.cpp
@@ -63,7 +63,7 @@
 		return 14 * 2;
 	}
 
-	int CJobDataB::unserialize(char* pszBuffer, int nBufferSize)
+	int CJobDataB::unserialize(const char* pszBuffer, int nBufferSize)
 	{
 		if (nBufferSize < 14) return -1;
 
diff --git a/SourceCode/Bond/Servo/CJobDataB.h b/SourceCode/Bond/Servo/CJobDataB.h
index a02cb98..c1ed9c2 100644
--- a/SourceCode/Bond/Servo/CJobDataB.h
+++ b/SourceCode/Bond/Servo/CJobDataB.h
@@ -16,7 +16,7 @@
 		std::string& getGlassId();
 		void setGlassId(const char* pszGlassId);
 		int serialize(char* pszBuffer, int nBufferSize);
-		int unserialize(char* pszBuffer, int nBufferSize);
+		int unserialize(const char* pszBuffer, int nBufferSize);
 
 	private:
 		int m_nCassetteSequenceNo;
diff --git a/SourceCode/Bond/Servo/CJobDataS.cpp b/SourceCode/Bond/Servo/CJobDataS.cpp
index f474931..0b2b4f7 100644
--- a/SourceCode/Bond/Servo/CJobDataS.cpp
+++ b/SourceCode/Bond/Servo/CJobDataS.cpp
@@ -1,5 +1,6 @@
 #include "stdafx.h"
 #include "CJobDataS.h"
+#include "ToolUnits.h"
 
 
 namespace SERVO {
@@ -94,7 +95,7 @@
 
 	std::string& CJobDataS::getGlass2Id()
 	{
-		return m_strGlass1Id;
+		return m_strGlass2Id;
 	}
 
 	void CJobDataS::setGlass2Id(const char* pszId)
@@ -327,4 +328,219 @@
 	{
 		m_nTargetSlotNo = no;
 	}
+
+	int CJobDataS::serialize(char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 256 * 2) return -1;
+
+		int index = 0;
+		memcpy(&pszBuffer[index], &m_nCassetteSequenceNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nJobSequenceNo, sizeof(short));
+		index += sizeof(short);
+
+		int strLen = min(40, m_strLotId.size());
+		memcpy(&pszBuffer[index], m_strLotId.c_str(), strLen);
+		index += 40;
+
+		strLen = min(20, m_strProductId.size());
+		memcpy(&pszBuffer[index], m_strProductId.c_str(), strLen);
+		index += 20;
+
+		strLen = min(20, m_strOperationId.size());
+		memcpy(&pszBuffer[index], m_strOperationId.c_str(), strLen);
+		index += 20;
+
+		strLen = min(20, m_strGlass1Id.size());
+		memcpy(&pszBuffer[index], m_strGlass1Id.c_str(), strLen);
+		index += 20;
+
+		strLen = min(20, m_strGlass2Id.size());
+		memcpy(&pszBuffer[index], m_strGlass2Id.c_str(), strLen);
+		index += 20;
+
+		memcpy(&pszBuffer[index], &m_nJobType, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nMaterialsType, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nProductType, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nDummyType, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nSkipFlag, sizeof(int));
+		index += sizeof(int);
+		
+		memcpy(&pszBuffer[index], &m_nProcessFlag, sizeof(int));
+		index += sizeof(int);
+
+		memcpy(&pszBuffer[index], &m_nProcessResonCode, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nLastGlassFlag, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nFirstGlassFlag, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nLastGlassFlag, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nQTime[0], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nQTime[1], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nQTime[2], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nQTimeOverFlag, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nMasterRecipe, sizeof(short));
+		index += sizeof(short);
+
+		strLen = min(10, m_strProductRecipeId.size());
+		memcpy(&pszBuffer[index], m_strProductRecipeId.c_str(), strLen);
+		index += 10;
+
+		strLen = min(10, m_strPCode.size());
+		memcpy(&pszBuffer[index], m_strPCode.c_str(), strLen);
+		index += 10;
+
+		strLen = min(10, m_strUseType.size());
+		memcpy(&pszBuffer[index], m_strUseType.c_str(), strLen);
+		index += 10;
+
+		strLen = min(80, m_strPanelMeasure.size());
+		memcpy(&pszBuffer[index], m_strPanelMeasure.c_str(), strLen);
+		index += 80;
+
+		memcpy(&pszBuffer[index], &m_nMode, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nSlotUnitSelectFlag, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nSourcePortNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nSourceSlotNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nTargetPortNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nTargetSlotNo, sizeof(short));
+		index += sizeof(short);
+
+		return 256 * 2;
+	}
+
+	int CJobDataS::unserialize(const char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 256 * 2) return -1;
+
+		int index = 0;
+		memcpy(&m_nCassetteSequenceNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nJobSequenceNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		CToolUnits::convertString(&pszBuffer[index], 40, m_strLotId);
+		index += 40;
+
+		CToolUnits::convertString(&pszBuffer[index], 20, m_strProductId);
+		index += 20;
+
+		CToolUnits::convertString(&pszBuffer[index], 20, m_strOperationId);
+		index += 20;
+
+		CToolUnits::convertString(&pszBuffer[index], 20, m_strGlass1Id);
+		index += 20;
+
+		CToolUnits::convertString(&pszBuffer[index], 20, m_strGlass2Id);
+		index += 20;
+
+		memcpy(&m_nJobType, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nMaterialsType, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nProductType, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nDummyType, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nSkipFlag, &pszBuffer[index], sizeof(int));
+		index += sizeof(int);
+
+		memcpy(&m_nProcessFlag, &pszBuffer[index], sizeof(int));
+		index += sizeof(int);
+
+		memcpy(&m_nProcessResonCode, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nLastGlassFlag, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nFirstGlassFlag, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nQTime[0], &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nQTime[1], &pszBuffer[index], sizeof(short));
+		index += sizeof(int);
+
+		memcpy(&m_nQTime[2], &pszBuffer[index], sizeof(int));
+		index += sizeof(short);
+
+		memcpy(&m_nQTimeOverFlag, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nMasterRecipe, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		CToolUnits::convertString(&pszBuffer[index], 10, m_strProductRecipeId);
+		index += 10;
+
+		CToolUnits::convertString(&pszBuffer[index], 10, m_strProductRecipeId);
+		index += 10;
+
+		CToolUnits::convertString(&pszBuffer[index], 10, m_strProductRecipeId);
+		index += 10;
+
+		CToolUnits::convertString(&pszBuffer[index], 80, m_strProductRecipeId);
+		index += 80;
+
+		memcpy(&m_nMode, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nSlotUnitSelectFlag, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nSourcePortNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nSourceSlotNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nTargetPortNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nTargetSlotNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+
+		return 256 * 2;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CJobDataS.h b/SourceCode/Bond/Servo/CJobDataS.h
index a2e3964..62087b4 100644
--- a/SourceCode/Bond/Servo/CJobDataS.h
+++ b/SourceCode/Bond/Servo/CJobDataS.h
@@ -67,6 +67,9 @@
 		void setTargetPortNo(int no);
 		int getTargetSlotNo();
 		void setTargetSlotNo(int no);
+		int serialize(char* pszBuffer, int nBufferSize);
+		int unserialize(const char* pszBuffer, int nBufferSize);
+
 
 	private:
 		int m_nCassetteSequenceNo;
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 40f4705..6394380 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -24,7 +24,7 @@
 
 	CMaster::CMaster()
 	{
-		m_listener = {nullptr, nullptr, nullptr, nullptr};
+		m_listener = {nullptr, nullptr, nullptr, nullptr, nullptr};
 		m_bDataModify = FALSE;
 		m_hEventReadBitsThreadExit[0] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
 		m_hEventReadBitsThreadExit[1] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -56,6 +56,7 @@
 		m_listener.onEqCimStateChanged = listener.onEqCimStateChanged;
 		m_listener.onEqAlarm = listener.onEqAlarm;
 		m_listener.onEqVcrEventReport = listener.onEqVcrEventReport;
+		m_listener.onEqDataChanged = listener.onEqDataChanged;
 	}
 
 	int CMaster::init()
@@ -91,24 +92,63 @@
 
 		// 初始化添加各子设备
 		CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
+		CBonder* pBonder1, * pBonder2;
 		CEFEM* pEfem;
+		CArm* pArm;
+		CArmTray* pArmTray1, * pArmTray2;
+		CFliper* pFliper;
+		CVacuumBake* pVacuumBake;
+		CAligner* pAligner;
+		CBakeCooling* pBakeCooling;
+
 		pPort1 = addLoadPort(0);
 		pPort2 = addLoadPort(1);
 		pPort3 = addLoadPort(2);
 		pPort4 = addLoadPort(3);
 		pEfem = addEFEM();
+		pArm = addArm();
+		pArmTray1 = addArmTray(0);
+		pArmTray2 = addArmTray(1);
+		pFliper = addFliper();
+		pVacuumBake = addVacuumBake();
+		pAligner = addAligner();
+		pBonder1 = addBonder(0);
+		pBonder2 = addBonder(1);
+		pBakeCooling = addBakeCooling();
+
+		ASSERT(pEfem);
+		ASSERT(pFliper);
+		ASSERT(pVacuumBake);
+		ASSERT(pAligner);
+		ASSERT(pBonder1);
+		ASSERT(pBonder2);
+		ASSERT(pBakeCooling);
+
 		pEfem->setPort(0, pPort1);
 		pEfem->setPort(1, pPort1);
 		pEfem->setPort(2, pPort1);
 		pEfem->setPort(3, pPort1);
+		pEfem->setFliper(pFliper);
+		pEfem->setAligner(pAligner);
+		pEfem->setArmTray(0, pArmTray1);
+		pEfem->setArmTray(1, pArmTray2);
+		pPort1->setArm(pArm);
+		pPort2->setArm(pArm);
+		pPort3->setArm(pArm);
+		pPort4->setArm(pArm);
+		pArmTray1->setArm(pArm);
+		pArmTray2->setArm(pArm);
+		pFliper->setArm(pArm);
+		pVacuumBake->setArm(pArm);
+		pAligner->setArm(pArm);
+		pBonder1->setArm(pArm);
+		pBonder2->setArm(pArm);
+		pBakeCooling->setArm(pArm);
 
-		addFliper();
-		addVacuumBake();
-		addAligner();
-		addBonder(0);
-		addBonder(1);
-		addBakeCooling();
 		connectEquipments();
+
+
+
 
 		
 		// 读缓存数据
@@ -206,6 +246,10 @@
 		};
 		listener.onDataChanged = [&](void* pEquipment, int code) -> void {
 			m_bDataModify = TRUE;
+			CEquipment* p = (CEquipment*)pEquipment;
+			if (m_listener.onEqDataChanged != nullptr) {
+				m_listener.onEqDataChanged(this, p, 0);
+			}
 		};
 
 		pEquipment->setListener(listener);
@@ -255,7 +299,7 @@
 		return pEquipment;
 	}
 
-	int CMaster::addFliper()
+	CFliper* CMaster::addFliper()
 	{
 		CFliper* pEquipment = new CFliper();
 		pEquipment->setID(EQ_ID_FLIPER);
@@ -269,10 +313,10 @@
 
 		pEquipment->init();
 		LOGE("已添加“Fliper”.");
-		return 0;
+		return pEquipment;
 	}
 
-	int CMaster::addVacuumBake()
+	CVacuumBake* CMaster::addVacuumBake()
 	{
 		CVacuumBake* pEquipment = new CVacuumBake();
 		pEquipment->setID(EQ_ID_VACUUMBAKE);
@@ -286,10 +330,11 @@
 
 		pEquipment->init();
 		LOGE("已添加“VacuumBake”.");
-		return 0;
+
+		return pEquipment;
 	}
 
-	int CMaster::addAligner()
+	CAligner* CMaster::addAligner()
 	{
 		CAligner* pEquipment = new CAligner();
 		pEquipment->setID(EQ_ID_ALIGNER);
@@ -303,7 +348,8 @@
 
 		pEquipment->init();
 		LOGE("已添加“Aligner”.");
-		return 0;
+
+		return pEquipment;
 	}
 
 	CEFEM* CMaster::addEFEM()
@@ -324,11 +370,43 @@
 		return pEquipment;
 	}
 
+	CArm* CMaster::addArm()
+	{
+		CArm* pEquipment = new CArm();
+		pEquipment->setID(EQ_ID_ARM);
+		pEquipment->setBaseAlarmId(BASE_ALARM_EFEM);
+		pEquipment->setName("ARM");
+		pEquipment->setDescription("ARM.");
+		addToEquipmentList(pEquipment);
+
+
+		pEquipment->init();
+		LOGE("已添加“ARM”.");
+
+		return pEquipment;
+	}
+
+	CArmTray* CMaster::addArmTray(int index)
+	{
+		CArmTray* pEquipment = new CArmTray();
+		pEquipment->setID(index == 0 ? EQ_ID_ARM_TRAY1 : EQ_ID_ARM_TRAY2);
+		pEquipment->setBaseAlarmId(BASE_ALARM_EFEM);
+		pEquipment->setName(index == 0 ? "Arm Tray1" : "Arm Tray2");
+		pEquipment->setDescription(index == 0 ? "Arm Tray1." : "Arm Tray2.");
+		addToEquipmentList(pEquipment);
+
+
+		pEquipment->init();
+		LOGE("已添加“%s”.", pEquipment->getName().c_str());
+
+		return pEquipment;
+	}
+
 	/* 添加bonder1 或 bonder2 
 	 * index -- 0, bonder1
 	 * index -- 1, bonder2
 	 */
-	int CMaster::addBonder(int index)
+	CBonder* CMaster::addBonder(int index)
 	{
 		ASSERT(index == 0 || index == 1);
 		CBonder* pEquipment = new CBonder();
@@ -346,10 +424,10 @@
 		LOGE("已添加“%s”.", pEquipment->getName().c_str());
 
 
-		return 0;
+		return pEquipment;
 	}
 
-	int CMaster::addBakeCooling()
+	CBakeCooling* CMaster::addBakeCooling()
 	{
 		CBakeCooling* pEquipment = new CBakeCooling();
 		pEquipment->setID(EQ_ID_BAKE_COOLING);
@@ -360,10 +438,10 @@
 		pEquipment->setStation(0, 255);
 		addToEquipmentList(pEquipment);
 
-
 		pEquipment->init();
 		LOGE("已添加“Aligner”.");
-		return 0;
+
+		return pEquipment;
 	}
 
 	void CMaster::onTimer(UINT nTimerid)
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index 913d1c9..31ea5da 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -8,6 +8,8 @@
 #include "CAligner.h"
 #include "CVacuumBake.h"
 #include "CBakeCooling.h"
+#include "CArm.h"
+#include "CArmTray.h"
 #include "CCLinkIEControl.h"
 
 
@@ -16,12 +18,14 @@
     typedef std::function<void(CStep* pStep, int code, void* pData)> ONEQSTEPEVENT;
     typedef std::function<void(void* pMaster, CEquipment* pEquipment, int state, int alarmId, int unitId, int level)> ONEQALARM;
     typedef std::function<void(void* pMaster, CEquipment* pEquipment, CVcrEventReport* pReport)> ONEQVCREVENTREPORT;
+    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int code)> ONEQDATACHANGED;
     typedef struct _MasterListener
     {
         ONEQALIVE				onEqAlive;
         ONEQALIVE		        onEqCimStateChanged;
         ONEQALARM               onEqAlarm;
         ONEQVCREVENTREPORT	    onEqVcrEventReport;
+        ONEQDATACHANGED         onEqDataChanged;
     } MasterListener;
 
     class CMaster
@@ -44,12 +48,14 @@
     private:
         int addToEquipmentList(CEquipment* pEquipment);
         CLoadPort* addLoadPort(int index);
-        int addFliper();
-        int addVacuumBake();
-        int addAligner();
+        CFliper* addFliper();
+        CVacuumBake* addVacuumBake();
+        CAligner* addAligner();
         CEFEM* addEFEM();
-        int addBonder(int index);
-        int addBakeCooling();
+        CArm* addArm();
+        CArmTray* addArmTray(int index);
+        CBonder* addBonder(int index);
+        CBakeCooling* addBakeCooling();
         void connectEquipments();
         int saveCache();
         int saveCacheAndBackups();
diff --git a/SourceCode/Bond/Servo/CPageGraph1.cpp b/SourceCode/Bond/Servo/CPageGraph1.cpp
index 243dea1..f1f3195 100644
--- a/SourceCode/Bond/Servo/CPageGraph1.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph1.cpp
@@ -276,6 +276,11 @@
 	if (m_hbrBkgnd != nullptr) {
 		::DeleteObject(m_hbrBkgnd);
 	}
+
+	if (m_pObserver != nullptr) {
+		m_pObserver->unsubscribe();
+		m_pObserver = NULL;
+	}
 }
 
 void CPageGraph1::OnSize(UINT nType, int cx, int cy)
diff --git a/SourceCode/Bond/Servo/CPageGraph2.cpp b/SourceCode/Bond/Servo/CPageGraph2.cpp
index 7ead0b6..3a7d3bf 100644
--- a/SourceCode/Bond/Servo/CPageGraph2.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph2.cpp
@@ -22,6 +22,7 @@
 	m_pEqsGraphWnd = nullptr;
 	m_crBkgnd = PAGE_GRPAH2_BACKGROUND_COLOR;
 	m_hbrBkgnd = nullptr;
+	m_pObserver = nullptr;
 }
 
 CPageGraph2::~CPageGraph2()
@@ -44,6 +45,40 @@
 
 // CPageGraph2 娑堟伅澶勭悊绋嬪簭
 
+
+void CPageGraph2::InitRxWindows()
+{
+	/* code */
+	// 璁㈤槄鏁版嵁
+	IRxWindows* pRxWindows = RX_GetRxWindows();
+	pRxWindows->enableLog(5);
+	if (m_pObserver == NULL) {
+		m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
+			// onNext
+			pAny->addRef();
+			int code = pAny->getCode();
+			if (RX_CODE_EQ_DATA_CHANGED == code) {
+				// 閫氱煡璁惧鐘舵��
+				SERVO::CEquipment* pEquipment = nullptr;
+				if (pAny->getPtrValue("ptr", (void*&)pEquipment)) {
+					if (pEquipment != nullptr) {
+						m_pEqsGraphWnd->ShowItemIndicator((DWORD_PTR)pEquipment, !pEquipment->isGlassListEmpty());
+					}
+				}
+			}
+
+			pAny->release();
+			}, [&]() -> void {
+				// onComplete
+			}, [&](IThrowable* pThrowable) -> void {
+				// onErrorm
+				pThrowable->printf();
+			});
+
+		theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
+			->subscribe(m_pObserver);
+	}
+}
 
 BOOL CPageGraph2::OnInitDialog()
 {
@@ -154,11 +189,14 @@
 		// 娴嬭瘯
 		else if (nCmd == ID_EQSGRAPHITEM_TEST1) {
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
-			pEquipment->outputGlass(0);
+			if (pEquipment->getID() == EQ_ID_LOADPORT1) {
+				pEquipment->outputGlass(1);
+			}
+			pEquipment->fetchedOut("P20250320A1A2");
 		}
 		else if (nCmd == ID_EQSGRAPHITEM_TEST2) {
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
-			pEquipment->outputGlass(1);
+			pEquipment->storeJob("P20250320A1A2");
 		}
 		else if (nCmd == ID_EQSGRAPHITEM_TEST3) {
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
@@ -216,13 +254,13 @@
 			}
 			*/
 			
-			/*
+			
 			if (pEquipment->getID() == EQ_ID_Bonder1
 				|| pEquipment->getID() == EQ_ID_Bonder2) {
 				static int ii = 0; ii++;
 				pEquipment->setEqMode((ii % 5) + 1);
 			}
-			*/
+			
 
 			/*
 			SERVO::CGlass* pGlass = pEquipment->getFrontGlass();
@@ -290,6 +328,11 @@
 	if (m_hbrBkgnd != nullptr) {
 		::DeleteObject(m_hbrBkgnd);
 	}
+
+	if (m_pObserver != nullptr) {
+		m_pObserver->unsubscribe();
+		m_pObserver = NULL;
+	}
 }
 
 
@@ -325,11 +368,14 @@
 	for (auto outPin : outPins) {
 		m_pEqsGraphWnd->AddPin(pItem, OUTPIN, outPin->getName().c_str(), (DWORD_PTR)outPin);
 	}
+
+	m_pEqsGraphWnd->ShowItemIndicator((DWORD_PTR)pEquipment, !pEquipment->isGlassListEmpty());
 }
 
 void CPageGraph2::OnTimer(UINT_PTR nIDEvent)
 {
 	if (1 == nIDEvent) {
+		InitRxWindows();
 		KillTimer(1);
 		std::list<SERVO::CEquipment*>& eqs = theApp.m_model.m_master.getEquipmentList();
 		for (auto eq : eqs) {
diff --git a/SourceCode/Bond/Servo/CPageGraph2.h b/SourceCode/Bond/Servo/CPageGraph2.h
index a90ca36..736fb65 100644
--- a/SourceCode/Bond/Servo/CPageGraph2.h
+++ b/SourceCode/Bond/Servo/CPageGraph2.h
@@ -14,11 +14,13 @@
 
 
 private:
+	void InitRxWindows();
 	void AddEqToGraphWnd(SERVO::CEquipment* pEquipment);
 	void SaveEqsGraphData();
 	void GetItemDataFormIni(const char* pszItemName, int& left, int& top);
 
 private:
+	IObserver* m_pObserver;
 	CEqsGraphWnd* m_pEqsGraphWnd;
 	COLORREF m_crBkgnd;
 	HBRUSH m_hbrBkgnd;
diff --git a/SourceCode/Bond/Servo/CStep.cpp b/SourceCode/Bond/Servo/CStep.cpp
index 7ffc65d..e600414 100644
--- a/SourceCode/Bond/Servo/CStep.cpp
+++ b/SourceCode/Bond/Servo/CStep.cpp
@@ -70,6 +70,18 @@
 
 	}
 
+	void CStep::setProp(const char* pszKey, void* pValue)
+	{
+		m_mapProp[pszKey] = pValue;
+	}
+
+	void* CStep::getProp(const char* pszKey)
+	{
+		auto iter = m_mapProp.find(pszKey);
+		if (iter == m_mapProp.end()) return nullptr;
+		return iter->second;
+	}
+
 	void CStep::convertString(const char* pszBuffer, int size, std::string& strOut)
 	{
 		strOut.clear();
diff --git a/SourceCode/Bond/Servo/CStep.h b/SourceCode/Bond/Servo/CStep.h
index 866e6f2..d82e99a 100644
--- a/SourceCode/Bond/Servo/CStep.h
+++ b/SourceCode/Bond/Servo/CStep.h
@@ -2,6 +2,7 @@
 #include "CCLinkIEControl.h"
 #include "CAttributeVector.h"
 #include "ToolUnits.h"
+#include <map>
 
 
 namespace SERVO {
@@ -26,7 +27,8 @@
 		virtual void getAttributeVector(CAttributeVector& attrubutes);
 		virtual void init();
 		virtual void term();
-
+		void setProp(const char* pszKey, void* pValue);
+		void* getProp(const char* pszKey);
 
 	protected:
 		inline void Lock() { EnterCriticalSection(&m_criticalSection); }
@@ -40,6 +42,7 @@
 		CEquipment* m_pEquipment;
 		CCCLinkIEControl* m_pCclink;
 		CRITICAL_SECTION m_criticalSection;
+		std::map<std::string, void*> m_mapProp;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index e1d382a..39f19d7 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/SourceCode/Bond/Servo/Common.h
@@ -13,6 +13,7 @@
 #define RX_CODE_SELECT_STEP				1007
 #define RX_CODE_ALARM_SET				1008
 #define RX_CODE_ALARM_CLEAR				1009
+#define RX_CODE_EQ_DATA_CHANGED			1010
 
 
 /* Channel Name */
@@ -61,6 +62,9 @@
 #define EQ_ID_VACUUMBAKE		9
 #define EQ_ID_ALIGNER			10
 #define EQ_ID_BAKE_COOLING		11
+#define EQ_ID_ARM				12
+#define EQ_ID_ARM_TRAY1			13
+#define EQ_ID_ARM_TRAY2			14
 #define EQ_ID_OPERATOR_REMOVE	999
 
 
@@ -143,6 +147,22 @@
 #define STEP_EQ_MASTER_RECIPE_LIST		_T("EQMasterRecipeListReport")
 #define STEP_EQ_RECIPE_PARAMETER_REQ	_T("EQRecipeParameterReq")
 #define STEP_EQ_RECIPE_PARAMETER		_T("EQRecipeParameterReport")
+#define STEP_EQ_FETCHED_OUT_JOBn		_T("EQFetchedOutJobReport")
+#define STEP_EQ_FETCHED_OUT_JOB1		_T("EQFetchedOutJobReport1")
+#define STEP_EQ_FETCHED_OUT_JOB2		_T("EQFetchedOutJobReport2")
+#define STEP_EQ_FETCHED_OUT_JOB3		_T("EQFetchedOutJobReport3")
+#define STEP_EQ_FETCHED_OUT_JOB4		_T("EQFetchedOutJobReport4")
+#define STEP_EQ_FETCHED_OUT_JOB5		_T("EQFetchedOutJobReport5")
+#define STEP_EQ_FETCHED_OUT_JOB6		_T("EQFetchedOutJobReport6")
+#define STEP_EQ_FETCHED_OUT_JOB7		_T("EQFetchedOutJobReport7")
+#define STEP_EQ_FETCHED_OUT_JOB8		_T("EQFetchedOutJobReport8")
+#define STEP_EQ_FETCHED_OUT_JOB9		_T("EQFetchedOutJobReport9")
+#define STEP_EQ_FETCHED_OUT_JOB10		_T("EQFetchedOutJobReport10")
+#define STEP_EQ_FETCHED_OUT_JOB11		_T("EQFetchedOutJobReport11")
+#define STEP_EQ_FETCHED_OUT_JOB12		_T("EQFetchedOutJobReport12")
+#define STEP_EQ_FETCHED_OUT_JOB13		_T("EQFetchedOutJobReport13")
+#define STEP_EQ_FETCHED_OUT_JOB14		_T("EQFetchedOutJobReport14")
+#define STEP_EQ_FETCHED_OUT_JOB15		_T("EQFetchedOutJobReport15")
 
 
 /* Step ID */
@@ -171,6 +191,21 @@
 #define STEP_ID_RECIVE_JOB_UPS2					0x581
 #define STEP_ID_SENT_OUT_JOB_DOWNS1				0x590
 #define STEP_ID_SENT_OUT_JOB_DOWNS2				0x591
+#define STEP_ID_FETCHED_OUT_JOB_REPORT1			0x5AF
+#define STEP_ID_FETCHED_OUT_JOB_REPORT2			0x5B0
+#define STEP_ID_FETCHED_OUT_JOB_REPORT3			0x5B1
+#define STEP_ID_FETCHED_OUT_JOB_REPORT4			0x5B2
+#define STEP_ID_FETCHED_OUT_JOB_REPORT5			0x5B3
+#define STEP_ID_FETCHED_OUT_JOB_REPORT6			0x5B4
+#define STEP_ID_FETCHED_OUT_JOB_REPORT7			0x5B5
+#define STEP_ID_FETCHED_OUT_JOB_REPORT8			0x5B6
+#define STEP_ID_FETCHED_OUT_JOB_REPORT9			0x5B7
+#define STEP_ID_FETCHED_OUT_JOB_REPORT10		0x5B8
+#define STEP_ID_FETCHED_OUT_JOB_REPORT11		0x5B9
+#define STEP_ID_FETCHED_OUT_JOB_REPORT12		0x5BA
+#define STEP_ID_FETCHED_OUT_JOB_REPORT13		0x5BB
+#define STEP_ID_FETCHED_OUT_JOB_REPORT14		0x5BC
+#define STEP_ID_FETCHED_OUT_JOB_REPORT15		0x5BD
 #define STEP_ID_PORT1_TYPE_CHANGE				0x600
 #define STEP_ID_PORT2_TYPE_CHANGE				0x601
 #define STEP_ID_PORT3_TYPE_CHANGE				0x602
diff --git a/SourceCode/Bond/Servo/EqsGraphWnd.cpp b/SourceCode/Bond/Servo/EqsGraphWnd.cpp
index 466ca8e..9aa534d 100644
--- a/SourceCode/Bond/Servo/EqsGraphWnd.cpp
+++ b/SourceCode/Bond/Servo/EqsGraphWnd.cpp
@@ -1911,10 +1911,12 @@
 	HBRUSH hbrItemBackground[2];
 	HBRUSH hbrItemFrame[2];
 	HBRUSH hbrPinBackground[3];
+	HBRUSH hbrIndicator;
 	hbrItemBackground[0] = CreateSolidBrush(m_crItemBackground[0]);
 	hbrItemBackground[1] = CreateSolidBrush(m_crItemBackground[1]);
 	hbrItemFrame[0] = CreateSolidBrush(m_crItemFrame[0]);
 	hbrItemFrame[1] = CreateSolidBrush(m_crItemFrame[1]);
+	hbrIndicator = CreateSolidBrush(RGB(34, 177, 76));
 	for (int i = 0; i < 3; i++) {
 		hbrPinBackground[i] = CreateSolidBrush(m_crPinBkgnd[i]);
 	}
@@ -1960,6 +1962,21 @@
 			HFONT hFontOld = (HFONT)::SelectObject(hMemDC, m_hFontName);
 			::SetTextColor(hMemDC, pItem->bHighlight ? m_crItemNameText[1] : m_crItemNameText[0]);
 			::DrawText(hMemDC, pItem->text, (int)strlen(pItem->text), &rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+
+			
+			// 添加一个小绿点指示器
+			if(pItem->bShowIndicator[0]){
+				RECT rcIndicator;
+				rcIndicator.left = rcItem.left + 5;
+				rcIndicator.top = rcItem.top + 5;
+				rcIndicator.right = rcIndicator.left + 12;
+				rcIndicator.bottom = rcIndicator.top + 12;
+				HRGN hRgn = CreateRoundRectRgn(rcIndicator.left, rcIndicator.top, rcIndicator.right, rcIndicator.bottom, 2, 2);
+				::FillRgn(hMemDC, hRgn, hbrIndicator);
+				::FrameRgn(hMemDC, hRgn, hbrItemFrame[0], 1, 1);
+				::DeleteObject(hRgn);
+			}
+
 
 			if (pItem->nShowType != ITEM_SMALL) {
 				RECT rcId = rcItem;
@@ -2074,6 +2091,7 @@
 		::DeleteObject(hbrItemBackground[1]);
 		::DeleteObject(hbrItemFrame[0]);
 		::DeleteObject(hbrItemFrame[1]);
+		::DeleteObject(hbrIndicator);		
 	}
 
 
@@ -2390,6 +2408,15 @@
 	SetTimer(m_hWnd, TIMER_ANIMATION_RECT, uElpase, NULL);
 }
 
+void CEqsGraphWnd::ShowItemIndicator(DWORD_PTR dwItemData, BOOL bShow)
+{
+	EQITEM* pItem = GetItem(dwItemData);
+	if (pItem != nullptr) {
+		pItem->bShowIndicator[0] = bShow;
+		::InvalidateRect(m_hWnd, nullptr, TRUE);
+	}
+}
+
 double CEqsGraphWnd::PointToSegDist(double x, double y, double x1, double y1, double x2, double y2)
 {
 	double cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1);
diff --git a/SourceCode/Bond/Servo/EqsGraphWnd.h b/SourceCode/Bond/Servo/EqsGraphWnd.h
index 89b56f5..c54d768 100644
--- a/SourceCode/Bond/Servo/EqsGraphWnd.h
+++ b/SourceCode/Bond/Servo/EqsGraphWnd.h
@@ -54,6 +54,7 @@
 	DWORD_PTR pInPins;
 	DWORD_PTR pOutPins;
 	int nFlashFlag;
+	BOOL bShowIndicator[2];
 } EQITEM;
 
 typedef struct tagPIN
@@ -143,6 +144,7 @@
 	void SetItemPos(EQITEM* pItem, int x, int y);
 	void FlashItem(EQITEM* pItem);
 	void AnimationItem(EQITEM*pItem);
+	void ShowItemIndicator(DWORD_PTR dwItemData, BOOL bShow);
 
 private:
 	void Init();
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 5dab65a..0c50bac 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -152,6 +152,10 @@
 	masterListener.onEqVcrEventReport = [&](void* pMaster, SERVO::CEquipment* pEquipment, SERVO::CVcrEventReport* pReport) {
 		LOGE("<CModel>onEqVcrEventReport.");
 	};
+	masterListener.onEqDataChanged = [&](void* pMaster, SERVO::CEquipment* pEquipment, int code) {
+		LOGE("<CModel>onEqDataChanged.");
+		notifyPtr(RX_CODE_EQ_DATA_CHANGED, pEquipment);
+	};
 	m_master.setListener(masterListener);
 
 
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 9569c6b..7f3bbce 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 1f07ff6..508d6da 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -133,7 +133,7 @@
       <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ResourceCompile>
     <PostBuildEvent>
-      <Command>copy "$(TargetDir)$(ProjectName).exe" "\\Boounion-0106\Servo\\$(ProjectName).exe"</Command>
+      <Command>copy "$(TargetDir)$(ProjectName).exe" "\\DESKTOP-IODBVIQ\Servo\Debug\$(ProjectName).exe"</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -200,6 +200,8 @@
     <ClInclude Include="ApredTreeCtrl2.h" />
     <ClInclude Include="BlButton.h" />
     <ClInclude Include="CAligner.h" />
+    <ClInclude Include="CArm.h" />
+    <ClInclude Include="CArmTray.h" />
     <ClInclude Include="CAttribute.h" />
     <ClInclude Include="CAttributeVector.h" />
     <ClInclude Include="CBakeCooling.h" />
@@ -291,6 +293,8 @@
     <ClCompile Include="ApredTreeCtrl2.cpp" />
     <ClCompile Include="BlButton.cpp" />
     <ClCompile Include="CAligner.cpp" />
+    <ClCompile Include="CArm.cpp" />
+    <ClCompile Include="CArmTray.cpp" />
     <ClCompile Include="CAttribute.cpp" />
     <ClCompile Include="CAttributeVector.cpp" />
     <ClCompile Include="CBakeCooling.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 7e9e760..d3afc4d 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -97,6 +97,8 @@
     <ClCompile Include="CEqReadStep.cpp" />
     <ClCompile Include="CRecipesManager.cpp" />
     <ClCompile Include="CRecipeList.cpp" />
+    <ClCompile Include="CArm.cpp" />
+    <ClCompile Include="CArmTray.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -192,6 +194,8 @@
     <ClInclude Include="CEqReadStep.h" />
     <ClInclude Include="CRecipesManager.h" />
     <ClInclude Include="CRecipeList.h" />
+    <ClInclude Include="CArm.h" />
+    <ClInclude Include="CArmTray.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.user b/SourceCode/Bond/Servo/Servo.vcxproj.user
index 86e9faf..405156d 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.user
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.user
@@ -4,9 +4,9 @@
     <RESOURCE_FILE>Servo.rc</RESOURCE_FILE>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <RemoteDebuggerCommand>D:\CLH\Servo\Servo.exe</RemoteDebuggerCommand>
-    <RemoteDebuggerWorkingDirectory>D:\CLH\Servo\</RemoteDebuggerWorkingDirectory>
-    <RemoteDebuggerServerName>Boounion-0106</RemoteDebuggerServerName>
+    <RemoteDebuggerCommand>D:\Servo\Debug\Servo.exe</RemoteDebuggerCommand>
+    <RemoteDebuggerWorkingDirectory>D:\Servo\Debug\</RemoteDebuggerWorkingDirectory>
+    <RemoteDebuggerServerName>DESKTOP-IODBVIQ</RemoteDebuggerServerName>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
   </PropertyGroup>
 </Project>
\ No newline at end of file

--
Gitblit v1.9.3