From 1bc4fecb9cc1641ed3ad0a2fda30766fc06fb13e Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期二, 01 四月 2025 16:05:07 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/Servo/CHMPropertyPage.h                                     |   14 
 SourceCode/Bond/Servo/Servo.vcxproj                                         |   16 
 SourceCode/Bond/Servo/CEqPortChangeStep.cpp                                 |  268 ++++++
 .gitignore                                                                  |    1 
 SourceCode/Bond/Servo/CEqReadIntStep.h                                      |   29 
 SourceCode/Bond/Servo/resource.h                                            |    0 
 SourceCode/Bond/Servo/CHMPropertyDlg.h                                      |   52 +
 SourceCode/Bond/Servo/CEqCassetteTransferStateStep.cpp                      |  293 ++++++
 SourceCode/Bond/Servo/CEquipmentPage1.cpp                                   |   80 +
 SourceCode/Bond/Servo/CGlass.h                                              |    5 
 SourceCode/Bond/Servo/CReadStep.h                                           |    3 
 Document/ESWIN_EAS_Equipment_Communication_Specification(CC-LINK)_v1.0.docx |    0 
 SourceCode/Bond/Servo/CMaster.h                                             |   19 
 SourceCode/Bond/Servo/CPath.h                                               |   33 
 SourceCode/Bond/Servo/CHMPropertyDlg.cpp                                    |  212 ++++
 SourceCode/Bond/Servo/EqsGraphWnd.cpp                                       |    9 
 SourceCode/Bond/Servo/CStep.h                                               |    8 
 SourceCode/Bond/Servo/AlarmDlg.cpp                                          |   28 
 SourceCode/Bond/Servo/CEquipment.cpp                                        |  174 +++
 SourceCode/Bond/Servo/Model.h                                               |    1 
 SourceCode/Bond/Servo/Servo.rc                                              |    0 
 SourceCode/Bond/Servo/CMaster.cpp                                           |  379 +++++++-
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.1.xlsx                |    0 
 SourceCode/Bond/Servo/CEqReadIntStep.cpp                                    |   83 +
 SourceCode/Bond/Servo/CEquipmentPage2.h                                     |   43 
 SourceCode/Bond/Servo/CEquipmentPage1.h                                     |   36 
 SourceCode/Bond/Servo/CStep.cpp                                             |    6 
 SourceCode/Bond/Servo/CPageGraph2.cpp                                       |   30 
 SourceCode/Bond/Servo/CReadStep.cpp                                         |   19 
 SourceCode/Bond/Servo/CGlass.cpp                                            |   50 +
 SourceCode/Bond/Servo/CWriteStep.cpp                                        |    6 
 SourceCode/Bond/Servo/CPath.cpp                                             |  125 ++
 SourceCode/Bond/Servo/CEqPortChangeStep.h                                   |   35 
 SourceCode/Bond/Servo/Model.cpp                                             |  103 -
 SourceCode/Bond/Servo/ServoDlg.cpp                                          |    2 
 SourceCode/Bond/Servo/CEqProcessStep.cpp                                    |    8 
 SourceCode/Bond/Servo/CHMPropertyPage.cpp                                   |   20 
 SourceCode/Bond/Servo/Servo.vcxproj.filters                                 |   16 
 SourceCode/Bond/Servo/CEquipmentPage2.cpp                                   |  180 ++++
 SourceCode/Bond/Servo/CEqCassetteTransferStateStep.h                        |   44 +
 SourceCode/Bond/Servo/CEquipment.h                                          |   12 
 SourceCode/Bond/Servo/Common.h                                              |  169 +++
 42 files changed, 2,376 insertions(+), 235 deletions(-)

diff --git a/.gitignore b/.gitignore
index 99779f8..8681c35 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,3 +49,4 @@
 SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.user
 SourceCode/Bond/x64/Debug/ServoConfiguration.ini
 *.iobj
+SourceCode/Bond/x64/Debug/Backups/
diff --git a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.1.xlsx b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.1.xlsx
index 544f8a8..be48abf 100644
--- a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.1.xlsx
+++ b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.1.xlsx
Binary files differ
diff --git "a/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v1.0.docx" "b/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v1.0.docx"
new file mode 100644
index 0000000..1cc33a5
--- /dev/null
+++ "b/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v1.0.docx"
Binary files differ
diff --git a/SourceCode/Bond/Servo/AlarmDlg.cpp b/SourceCode/Bond/Servo/AlarmDlg.cpp
index c1d8ecd..4a483e8 100644
--- a/SourceCode/Bond/Servo/AlarmDlg.cpp
+++ b/SourceCode/Bond/Servo/AlarmDlg.cpp
@@ -55,34 +55,6 @@
 
 			if (RX_CODE_ALARM_SET == code) {
 				UpdatePageData();
-
-
-				// 閫氱煡璁惧鐘舵��
-				/*
-				SERVO::CEqAlarmStep* pStep = nullptr;
-				if (pAny->getPtrValue("ptr", (void*&)pStep)) {
-					if (pStep != nullptr) {
-						// 鑾峰彇 AlarmManager 鍗曚緥
-						AlarmManager& alarmManager = AlarmManager::getInstance();
-
-						// 浠� pStep 鑾峰彇闇�瑕佺殑鍙傛暟锛屽亣璁捐繖浜涘�兼槸浠� pStep 涓幏鍙栫殑
-						AlarmData alarmData;
-						alarmData.nId = pStep->getAlarmId();
-						alarmData.nSeverityLevel = pStep->getAlarmLevel();
-						alarmData.nDeviceId = pStep->getEquipment()->getID();
-						alarmData.nUnitId = pStep->getUnitId();
-						alarmData.strDeviceName = alarmManager.getDeviceNameById(alarmData.nDeviceId);
-						alarmData.strUnitName = alarmManager.getUnitNameById(alarmData.nDeviceId, alarmData.nUnitId);
-						const AlarmInfo* pAlarmInfo = alarmManager.getAlarmInfoByID(pStep->getAlarmId());
-						alarmData.strDescription = pAlarmInfo != nullptr ? pAlarmInfo->strAlarmText : "";
-						if (pStep->getAlarmState() == 1) {
-							alarmData.strStartTime = getCurrentTimeString();
-							alarmData.strEndTime = "";
-							InsertAlarmData(&m_listCtrl, alarmData);
-						}
-					}
-				}
-				*/
 			}
 			else if (RX_CODE_ALARM_CLEAR == code) {
 				UpdatePageData();
diff --git a/SourceCode/Bond/Servo/CEqCassetteTransferStateStep.cpp b/SourceCode/Bond/Servo/CEqCassetteTransferStateStep.cpp
new file mode 100644
index 0000000..22c85a7
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqCassetteTransferStateStep.cpp
@@ -0,0 +1,293 @@
+#include "stdafx.h"
+#include "CEqCassetteTransferStateStep.h"
+#include "Log.h"
+#include "Common.h"
+
+
+namespace SERVO {
+	CEqCassetteTransferStateStep::CEqCassetteTransferStateStep()
+	{
+		m_nPortStatusDev = 0;
+		m_nPortStatus = 0;
+		m_nCassetteSequenceNo = 0;
+		m_nLoadingCassetteType = 0;
+		m_nQTimeFlag = 0;
+		m_nCassetteMappingState = 0;
+		m_nCassetteStatus = 0;
+	}
+
+	CEqCassetteTransferStateStep::~CEqCassetteTransferStateStep()
+	{
+
+	}
+
+	void CEqCassetteTransferStateStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CReadStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Dev",
+			("W" + CToolUnits::toHexString(m_nPortStatusDev, strTemp)).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("Port Status",
+			getPortStatusDescription(strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CassetteSequenceNo",
+			std::to_string(m_nCassetteSequenceNo).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CassetteID",
+			m_strCassetteID.c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("LoadingCassetteType",
+			getLoadingCassetteTypeDescription(strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("Q-Time Flag",
+			getQTimeFlagDescription(strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CassetteMappingState",
+			getCassetteMappingStateDescription(strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CassetteStatus",
+			getCassetteStatusDescription(strTemp).c_str(), ""));
+	}
+
+	int CEqCassetteTransferStateStep::onReadData()
+	{
+		CReadStep::onReadData();
+
+
+		char szBuffer[64];
+		int nRet = m_pCclink->ReadData2(m_station, DeviceType::W, m_nPortStatusDev,
+			64, szBuffer);
+		if (0 != nRet) {
+			return -1;
+		}
+
+
+		// Port status,
+		// 注:也可以根据m_nSignalType的值来判断状态值
+		m_nPortStatus = (unsigned int)CToolUnits::toInt16(&szBuffer[0]);
+
+
+		// Cassette序号、ID
+		m_nCassetteSequenceNo = (unsigned int)CToolUnits::toInt16(&szBuffer[2]);
+		convertString(&szBuffer[4], 20, m_strCassetteID);
+
+
+		// Job Existence Slot
+		if (PORT_INUSE == m_nPortStatus) {
+
+		}
+
+
+		// Q-Time
+		if (PORT_UNLOAD_READY == m_nPortStatus) {
+			m_nQTimeFlag = (unsigned int)CToolUnits::toInt16(&szBuffer[50]);
+		}
+
+		// 其它
+		m_nCassetteMappingState = (unsigned int)CToolUnits::toInt16(&szBuffer[52]);
+		m_nCassetteStatus = (unsigned int)CToolUnits::toInt16(&szBuffer[54]);
+		if (m_nCassetteStatus > 1) {
+			m_nLoadingCassetteType = (unsigned int)CToolUnits::toInt16(&szBuffer[48]);
+		}
+
+
+		LOGI("<CCassetteTranserStateStep>Port status changed<Dev:%d, Status:%d, CassetteSequenceNo:%d>",
+			m_nPortStatusDev, m_nPortStatus, m_nCassetteSequenceNo);
+
+		return 0;
+	}
+
+	int CEqCassetteTransferStateStep::onComplete()
+	{
+		CReadStep::onComplete();
+		LOGI("<CCassetteTranserStateStep> onComplete.");
+
+		return 0;
+	}
+
+	int CEqCassetteTransferStateStep::onTimeout()
+	{
+		CReadStep::onTimeout();
+		LOGI("<CCassetteTranserStateStep> onTimeout.");
+
+		return 0;
+	}
+
+	void CEqCassetteTransferStateStep::setPortStatusDev(int nDev)
+	{
+		m_nPortStatusDev = nDev;
+	}
+
+	int CEqCassetteTransferStateStep::getPortStatus()
+	{
+		return m_nPortStatus;
+	}
+
+	int CEqCassetteTransferStateStep::getCassetteSequenceNo()
+	{
+		return m_nCassetteSequenceNo;
+	}
+
+	std::string& CEqCassetteTransferStateStep::getCassetteID()
+	{
+		return m_strCassetteID;
+	}
+
+	int CEqCassetteTransferStateStep::getLoadingCassetteType()
+	{
+		return m_nLoadingCassetteType;
+	}
+
+	int CEqCassetteTransferStateStep::getQTimeFlag()
+	{
+		return m_nQTimeFlag;
+	}
+
+	int CEqCassetteTransferStateStep::getCassetteMappingState()
+	{
+		return m_nCassetteMappingState;
+	}
+
+	int CEqCassetteTransferStateStep::getCassetteStatus()
+	{
+		return m_nCassetteStatus;
+	}
+
+	/*
+	 1: Load Ready(Load Request)
+	 2: Loaded
+	 3: In Use (Load Complete)
+	 4: Unload Ready (Unload Request)
+	 5: Empty (Unload Complete)
+	 6: Blocked
+	 */
+	std::string& CEqCassetteTransferStateStep::getPortStatusDescription(std::string& strDescription)
+	{
+		switch (m_nPortStatus) {
+		case PORT_LOAD_READY:
+			strDescription = _T("Load Ready(Load Request)");
+			break;
+		case PORT_LOADED:
+			strDescription = _T("Loaded");
+			break;
+		case PORT_INUSE:
+			strDescription = _T("In Use (Load Complete)");
+			break;
+		case PORT_UNLOAD_READY:
+			strDescription = _T("Unload Ready (Unload Request)");
+			break;
+		case PORT_EMPTY:
+			strDescription = _T("Empty (Unload Complete)");
+			break;
+		case PORT_BLOCKED:
+			strDescription = _T("Blocked");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 1: Actual Cassette
+	 2: Empty Cassette
+		*Include this item only when cassette exists
+	 */
+	std::string& CEqCassetteTransferStateStep::getLoadingCassetteTypeDescription(std::string& strDescription)
+	{
+		switch (m_nLoadingCassetteType) {
+		case PORT_LOADING_CASSETTE_ACTUAL:
+			strDescription = _T("Actual Cassette");
+			break;
+		case PORT_LOADING_CASSETTE_EMPTY:
+			strDescription = _T("Empty Cassette");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 1: Normal Un-loading
+	 2: Q-Time Over & Un-loading
+       * Include this item only when Port Status is 'Unload Ready'
+	 */
+	std::string& CEqCassetteTransferStateStep::getQTimeFlagDescription(std::string& strDescription)
+	{
+		switch (m_nQTimeFlag) {
+		case Q_TIME_NORMAL:
+			strDescription = _T("Normal Un-loading");
+			break;
+		case Q_TIME_OVER:
+			strDescription = _T("Q-Time Over & Un-loading");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 1: mapping use
+	 2: mapping not use
+	 */
+	std::string& CEqCassetteTransferStateStep::getCassetteMappingStateDescription(std::string& strDescription)
+	{
+		switch (m_nCassetteMappingState) {
+		case CASSETTE_MAPPING_USE:
+			strDescription = _T("mapping use");
+			break;
+		case CASSETTE_MAPPING_NOT_USE:
+			strDescription = _T("mapping not use");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 1: No Cassette Exist
+	 2: Waiting for Cassette Data
+	 3: Waiting for Start Command
+	 4: Waiting for Processing
+	 5: In Processing
+	 6: Process Paused
+	 7: Process Completed
+	 */
+	std::string& CEqCassetteTransferStateStep::getCassetteStatusDescription(std::string& strDescription)
+	{
+		switch (m_nCassetteStatus) {
+		case CASSETTE_NO_EXIST:
+			strDescription = _T("No Cassette Exist");
+			break;
+		case CASSETTE_WAITING_DATA:
+			strDescription = _T("Waiting for Cassette Data");
+			break;
+		case CASSETTE_WAITING_START:
+			strDescription = _T("Waiting for Start Command");
+			break;
+		case CASSETTE_WAITING_PROCCESSING:
+			strDescription = _T("Waiting for Processing");
+			break;
+		case CASSETTE_IN_PROCCESSING:
+			strDescription = _T("In Processing");
+			break;
+		case CASSETTE_PROCCESS_PAUSED:
+			strDescription = _T("Process Paused");
+			break;
+		case CASSETTE_PROCCESS_COMPLETED:
+			strDescription = _T("Process Completed");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CEqCassetteTransferStateStep.h b/SourceCode/Bond/Servo/CEqCassetteTransferStateStep.h
new file mode 100644
index 0000000..a069226
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqCassetteTransferStateStep.h
@@ -0,0 +1,44 @@
+#pragma once
+#include "CReadStep.h"
+
+
+namespace SERVO {
+	class CEqCassetteTransferStateStep : public CReadStep
+	{
+	public:
+		CEqCassetteTransferStateStep();
+		~CEqCassetteTransferStateStep();
+
+	public:
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		virtual int onReadData();
+		virtual int onComplete();
+		virtual int onTimeout();
+		void setPortStatusDev(int nDev);
+		int getPortStatus();
+		int getCassetteSequenceNo();
+		std::string& getCassetteID();
+		int getLoadingCassetteType();
+		int getQTimeFlag();
+		int getCassetteMappingState();
+		int getCassetteStatus();
+		std::string& getPortStatusDescription(std::string& strDescription);
+		std::string& getLoadingCassetteTypeDescription(std::string& strDescription);
+		std::string& getQTimeFlagDescription(std::string& strDescription);
+		std::string& getCassetteMappingStateDescription(std::string& strDescription);
+		std::string& getCassetteStatusDescription(std::string& strDescription);
+
+	private:
+		int m_nPortStatusDev;
+		int m_nPortStatus;
+		int m_nCassetteSequenceNo;
+		std::string m_strCassetteID;
+		int m_nLoadingCassetteType;
+		int m_nQTimeFlag;
+		int m_nCassetteMappingState;
+		int m_nCassetteStatus;
+
+
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqPortChangeStep.cpp b/SourceCode/Bond/Servo/CEqPortChangeStep.cpp
new file mode 100644
index 0000000..0927225
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqPortChangeStep.cpp
@@ -0,0 +1,268 @@
+#include "stdafx.h"
+#include "CEqPortChangeStep.h"
+#include "Log.h"
+
+
+namespace SERVO {
+	CEqPortChangeStep::CEqPortChangeStep() : CReadStep()
+	{
+		m_nPortDev = 0;
+		m_nPortType = 0;
+		m_nPortMode = 0;
+		m_nPortCassetteType = 0;
+		m_nPortTransferMode = 0;
+		m_nPortEanbleMode = 0;
+		m_nPortTypeAutoChangeMode = 0;
+	}
+
+	CEqPortChangeStep::~CEqPortChangeStep()
+	{
+
+	}
+
+	void CEqPortChangeStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CReadStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Port Dev",
+			("W" + CToolUnits::toHexString(m_nPortDev, strTemp)).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("PortType",
+			std::to_string(m_nPortType).c_str(), getPortTypeDescription(strTemp).c_str()));
+		attrubutes.addAttribute(new CAttribute("PortMode",
+			std::to_string(m_nPortMode).c_str(), getPortModeDescription(strTemp).c_str()));
+		attrubutes.addAttribute(new CAttribute("PortCassetteType",
+			std::to_string(m_nPortCassetteType).c_str(), getPortCassetteTypeDescription(strTemp).c_str()));
+		attrubutes.addAttribute(new CAttribute("PortTransferMode",
+			std::to_string(m_nPortTransferMode).c_str(), getPortTransferModeDescription(strTemp).c_str()));
+		attrubutes.addAttribute(new CAttribute("PortEnableMode",
+			std::to_string(m_nPortEanbleMode).c_str(), getPortEnableModeDescription(strTemp).c_str()));
+		attrubutes.addAttribute(new CAttribute("PortTypeAutoChangeMode",
+			std::to_string(m_nPortTypeAutoChangeMode).c_str(), getPortTypeAutoChangeModeDescription(strTemp).c_str()));
+	}
+
+	int CEqPortChangeStep::onReadData()
+	{
+		CReadStep::onReadData();
+
+
+		char szBuffer[32];
+		int nRet = m_pCclink->ReadData2(m_station, DeviceType::W, m_nPortDev, 32, szBuffer);
+		if (0 != nRet) {
+			return -1;
+		}
+
+		m_nPortType = (unsigned int)CToolUnits::toInt16(&szBuffer[0]);
+		m_nPortMode = (unsigned int)CToolUnits::toInt16(&szBuffer[2]);
+		m_nPortCassetteType = (unsigned int)CToolUnits::toInt32(&szBuffer[4]);
+		m_nPortTransferMode = (unsigned int)CToolUnits::toInt16(&szBuffer[8]);
+		m_nPortEanbleMode = (unsigned int)CToolUnits::toInt16(&szBuffer[10]);
+		m_nPortTypeAutoChangeMode = (unsigned int)CToolUnits::toInt16(&szBuffer[12]);
+
+		/*
+		LOGI("<CEqAlarmStep> Equipment Alarm state Changed<State:%d, Unit:%d, Level:%d, Code:%d, ID:%d>\n",
+			m_nAlarmState, m_nUnitId, m_nAlarmLevel, m_nAlarmCode, m_nAlarmId,
+			m_strText.c_str(), m_strDescription.c_str());
+*/
+
+		return 0;
+	}
+
+	int CEqPortChangeStep::onComplete()
+	{
+		CReadStep::onComplete();
+		LOGI("<CEQPortChangeStep> onComplete.");
+
+		return 0;
+	}
+
+	int CEqPortChangeStep::onTimeout()
+	{
+		CReadStep::onTimeout();
+		LOGI("<CEQPortChangeStep> onTimeout.");
+
+		return 0;
+	}
+
+	void CEqPortChangeStep::setPortDev(int nDev)
+	{
+		m_nPortDev = nDev;
+	}
+
+	int CEqPortChangeStep::getPortType()
+	{
+		return m_nPortType;
+	}
+
+	/*
+	 1: Loading Port
+	 2: Unloading Port
+	 3: Both Port
+	 4: Buffer Port-Buffer Type
+	 5: Buffer Port-Loader in Buffer Type
+	 6: Buffer Port-Un-loader in Buffer Type
+	 7: Unloading Partial Port
+	 */
+	std::string& CEqPortChangeStep::getPortTypeDescription(std::string& strDescription)
+	{
+		switch (m_nPortType) {
+		case 1:
+			strDescription = _T("Loading Port");
+			break;
+		case 2:
+			strDescription = _T("Unloading Port");
+			break;
+		case 3:
+			strDescription = _T("Both Port");
+			break;
+		case 4:
+			strDescription = _T("Buffer Port - Buffer Type");
+			break;
+		case 5:
+			strDescription = _T("Buffer Port - Loader in Buffer Type");
+			break;
+		case 6:
+			strDescription = _T("Buffer Port - Un-loader in Buffer Type");
+			break;
+		case 7:
+			strDescription = _T("Unloading Partial Port");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 0: OutOfService
+	 1: TransferBlocked
+	 2: ReadyToLoad
+	 3: ReadyToUnload
+	 4: InService
+	 5: TransferReady
+	 */
+	std::string& CEqPortChangeStep::getPortModeDescription(std::string& strDescription)
+	{
+		switch (m_nPortMode) {
+		case 0:
+			strDescription = _T("OutOfService");
+			break;
+		case 1:
+			strDescription = _T("TransferBlocked");
+			break;
+		case 2:
+			strDescription = _T("ReadyToLoad");
+			break;
+		case 3:
+			strDescription = _T("ReadyToUnload");
+			break;
+		case 4:
+			strDescription = _T("InService");
+			break;
+		case 5:
+			strDescription = _T("TransferReady");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 1: G1
+	 2: G2
+	 3: G1&G2
+	 */
+	std::string& CEqPortChangeStep::getPortCassetteTypeDescription(std::string& strDescription)
+	{
+		switch (m_nPortCassetteType) {
+		case 1:
+			strDescription = _T("G1");
+			break;
+		case 2:
+			strDescription = _T("G2");
+			break;
+		case 3:
+			strDescription = _T("G1&G2");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 1: MGV Mode
+	 2: AGV Mode
+	 3: Stocker Inline Mode
+	 */
+	std::string& CEqPortChangeStep::getPortTransferModeDescription(std::string& strDescription)
+	{
+		switch (m_nPortTransferMode) {
+		case 1:
+			strDescription = _T("MGV Mode");
+			break;
+		case 2:
+			strDescription = _T("AGV Mode");
+			break;
+		case 3:
+			strDescription = _T("Stocker Inline Mode");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+
+	/*
+	 1 : Enable
+	 2 : Disable
+	 */
+	std::string& CEqPortChangeStep::getPortEnableModeDescription(std::string& strDescription)
+	{
+		switch (m_nPortEanbleMode) {
+		case 1:
+			strDescription = _T("Enable");
+			break;
+		case 2:
+			strDescription = _T("Disable");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	/*
+	 1: Auto Change Enable
+	 2: Auto Change Disable
+	 */
+	std::string& CEqPortChangeStep::getPortTypeAutoChangeModeDescription(std::string& strDescription)
+	{
+		switch (m_nPortTypeAutoChangeMode) {
+		case 1:
+			strDescription = _T("Auto Change Enable");
+			break;
+		case 2:
+			strDescription = _T("Auto Change Disable");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CEqPortChangeStep.h b/SourceCode/Bond/Servo/CEqPortChangeStep.h
new file mode 100644
index 0000000..27f7a99
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqPortChangeStep.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "CReadStep.h"
+
+namespace SERVO {
+	class CEqPortChangeStep : public CReadStep
+	{
+	public:
+		CEqPortChangeStep();
+		~CEqPortChangeStep();
+
+	public:
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		virtual int onReadData();
+		virtual int onComplete();
+		virtual int onTimeout();
+		void setPortDev(int nDev);
+		int getPortType();
+		std::string& getPortTypeDescription(std::string& strDescription);
+		std::string& getPortModeDescription(std::string& strDescription);
+		std::string& getPortCassetteTypeDescription(std::string& strDescription);
+		std::string& getPortTransferModeDescription(std::string& strDescription);
+		std::string& getPortEnableModeDescription(std::string& strDescription);
+		std::string& getPortTypeAutoChangeModeDescription(std::string& strDescription);
+
+	private:
+		int m_nPortDev;
+		int m_nPortType;
+		int m_nPortMode;
+		int m_nPortCassetteType;
+		int m_nPortTransferMode;
+		int m_nPortEanbleMode;
+		int m_nPortTypeAutoChangeMode;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqProcessStep.cpp b/SourceCode/Bond/Servo/CEqProcessStep.cpp
index f566e43..4f08edc 100644
--- a/SourceCode/Bond/Servo/CEqProcessStep.cpp
+++ b/SourceCode/Bond/Servo/CEqProcessStep.cpp
@@ -3,6 +3,7 @@
 #include "CEqProcessStep.h"
 #include "Log.h"
 #include "ToolUnits.h"
+#include "CEquipment.h"
 
 
 namespace SERVO {
@@ -59,7 +60,7 @@
 		// 解释数据
 		// Glass ID(1864~186D)
 		int index = 0;
-		convertString(&szBuffer[index], (0x186d - 0x1864 + 1) * 2, m_strStartTime);
+		convertString(&szBuffer[index], (0x186d - 0x1864 + 1) * 2, m_strGlassId);
 		index += (0x186d - 0x1864 + 1) * 2;
 
 		// Process Start Time(186e~1875)
@@ -94,8 +95,9 @@
 			index += 20;
 		}
 
-		if (m_nCurrentGroup == m_nTotalGroup && m_listener.onEvent != nullptr) {
-			m_listener.onEvent(this, STEP_EVENT_PROCESS_DATA, nullptr);
+		if (m_nCurrentGroup == m_nTotalGroup) {
+			ASSERT(m_pEquipment);
+			m_pEquipment->onStepEvent(this, STEP_EVENT_PROCESS_DATA);
 		}
 
 
diff --git a/SourceCode/Bond/Servo/CEqReadIntStep.cpp b/SourceCode/Bond/Servo/CEqReadIntStep.cpp
new file mode 100644
index 0000000..17174ae
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqReadIntStep.cpp
@@ -0,0 +1,83 @@
+#include "stdafx.h"
+#include "CEqReadIntStep.h"
+#include "Log.h"
+
+
+namespace SERVO {
+	CEqReadIntStep::CEqReadIntStep() : CReadStep()
+	{
+		m_nDataType = __INT16;
+		m_nValueDev = 0;
+		m_nValue = 0;
+	}
+
+	CEqReadIntStep::CEqReadIntStep(int dataType, int dev)
+	{
+		m_nDataType = dataType;
+		m_nValueDev = dev;
+		m_nValue = 0;
+	}
+
+	CEqReadIntStep::~CEqReadIntStep()
+	{
+
+	}
+
+	void CEqReadIntStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CReadStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Dev",
+			("W" + CToolUnits::toHexString(m_nValueDev, strTemp)).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("Value",
+			std::to_string(m_nValue).c_str(), ""));
+	}
+
+	int CEqReadIntStep::onReadData()
+	{
+		CReadStep::onReadData();
+
+
+		char szBuffer[32];
+		int nRet = m_pCclink->ReadData2(m_station, DeviceType::W, m_nValueDev,
+			m_nDataType == __INT16 ? 2 : 4, szBuffer);
+		if (0 != nRet) {
+			return -1;
+		}
+
+		if (m_nDataType == __INT16) {
+			m_nValue = (unsigned int)CToolUnits::toInt16(&szBuffer[0]);
+		}
+		else {
+			m_nValue = (unsigned int)CToolUnits::toInt32(&szBuffer[0]);
+		}
+
+		LOGI("<CEqReadIntStep>Value(%s) Changed<Dev:%d, Value:%d>\n",
+			m_strName.c_str(), m_nValueDev, m_nValue);
+
+		return 0;
+	}
+
+	int CEqReadIntStep::onComplete()
+	{
+		CReadStep::onComplete();
+		LOGI("<CEQPortChangeStep> onComplete.");
+
+		return 0;
+	}
+
+	int CEqReadIntStep::onTimeout()
+	{
+		CReadStep::onTimeout();
+		LOGI("<CEQPortChangeStep> onTimeout.");
+
+		return 0;
+	}
+
+	int CEqReadIntStep::getValue()
+	{
+		return m_nValue;
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CEqReadIntStep.h b/SourceCode/Bond/Servo/CEqReadIntStep.h
new file mode 100644
index 0000000..b3206c0
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqReadIntStep.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "CReadStep.h"
+
+
+namespace SERVO {
+constexpr auto __INT16 = 1;
+constexpr auto __INT32 = 2;
+
+	class CEqReadIntStep : public CReadStep
+	{
+	public:
+		CEqReadIntStep();
+		CEqReadIntStep(int dataType, int dev);
+		~CEqReadIntStep();
+
+	public:
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		virtual int onReadData();
+		virtual int onComplete();
+		virtual int onTimeout();
+		int getValue();
+
+	private:
+		int m_nDataType;
+		int m_nValueDev;
+		int m_nValue;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 393191b..85f5a0b 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -3,11 +3,27 @@
 #include "ToolUnits.h"
 
 
+#define CHECK_READ_STEP_SIGNAL(addr, data, size) {							\
+	BOOL bFlag = isBitOn(data, size, addr);									\
+	SERVO::CStep* pStep = getStep(addr);									\
+	if (pStep != nullptr) {													\
+		((CReadStep*)pStep)->onReadSignal(bFlag ? addr : 0);				\
+	}																		\
+}
+
+#define CHECK_WRITE_STEP_SIGNAL(addr, data, size) {							\
+	BOOL bFlag = isBitOn(data, size, addr);									\
+	SERVO::CStep* pStep = getStep(addr);									\
+	if (pStep != nullptr) {													\
+		((CWriteStep*)pStep)->onRecvSignal(bFlag ? addr : 0);				\
+	}																		\
+}
+
 namespace SERVO {
 
 	CEquipment::CEquipment() : m_nID(0), m_strName(""), m_strDescription(""), m_station(0, 255)
 	{
-		m_listener = { nullptr, nullptr };
+		m_listener = { nullptr, nullptr, nullptr, nullptr };
 		m_alive = {FALSE, 0, FALSE};
 		m_bCimState = FALSE;
 		m_bUpstreamInline = FALSE;
@@ -49,6 +65,8 @@
 	{
 		m_listener.onAlive = listener.onAlive;
 		m_listener.onCimStateChanged = listener.onCimStateChanged;
+		m_listener.onAlarm = listener.onAlarm;
+		m_listener.onDataChanged = listener.onDataChanged;
 	}
 
 	void CEquipment::setCcLink(CCCLinkIEControl* pCcLink)
@@ -357,20 +375,65 @@
 		// Equipment Status Change Report(0x361)
 		// Equipment Alarm Change Report(0x362 ~ 0x366)
 		for (int i = 0; i < 7; i++) {
-			index = 0x360 + i;;
-			bFlag = isBitOn(pszData, size, index);
-			pStep = getStep(index);
-			if (pStep != nullptr) {
-				((CReadStep*)pStep)->onReadSignal(bFlag);
-			}
+			CHECK_READ_STEP_SIGNAL(0x360 + i, pszData, size);
 		}
 
-		index = 0x350;
-		bFlag = isBitOn(pszData, size, index);
-		pStep = getStep(index);
-		if (pStep != nullptr) {
-			((CWriteStep*)pStep)->onRecvSignal(bFlag);
-		}
+
+		// CIM Mode
+		CHECK_WRITE_STEP_SIGNAL(0x350, pszData, size);
+
+
+		// Port1 ~ Port4
+		CHECK_READ_STEP_SIGNAL(0x3e0, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3e1, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3e2, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3e3, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3e8, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3e9, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3ea, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3eb, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3f0, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3f1, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3f2, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3f3, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3f8, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3f9, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3fa, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x3fb, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x400, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x401, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x402, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x403, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x408, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x409, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x40a, pszData, size);
+		CHECK_READ_STEP_SIGNAL(0x40b, pszData, size);
+
+		// CEqCassetteTranserStateStep
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_CASSETTIE_EMPTY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_CASSETTIE_LOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_CASSETTIE_LOADED, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_CASSETTIE_INUSE, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_CASSETTIE_UNLOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_CASSETTIE_BLOCKED, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_CASSETTIE_EMPTY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_CASSETTIE_LOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_CASSETTIE_LOADED, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_CASSETTIE_INUSE, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_CASSETTIE_UNLOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT2_CASSETTIE_BLOCKED, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_CASSETTIE_EMPTY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_CASSETTIE_LOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_CASSETTIE_LOADED, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_CASSETTIE_INUSE, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_CASSETTIE_UNLOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT3_CASSETTIE_BLOCKED, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_CASSETTIE_EMPTY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_CASSETTIE_LOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_CASSETTIE_LOADED, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_CASSETTIE_INUSE, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_CASSETTIE_UNLOAD_READY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT4_CASSETTIE_BLOCKED, pszData, size);
 	}
 
 	BOOL CEquipment::isBitOn(const char* pszData, size_t size, int index)
@@ -421,6 +484,26 @@
 	{
 		if (index >= VCR_MAX) return FALSE;
 		return m_bVCREnable[index];
+	}
+
+	int CEquipment::onStepEvent(CStep* pStep, int code)
+	{
+		if (code == STEP_EVENT_READDATA) {
+			if (isAlarmStep(pStep)) {
+				SERVO::CEqAlarmStep* pEqAlarmStep = (SERVO::CEqAlarmStep*)pStep;
+				int state = pEqAlarmStep->getAlarmState();
+				ASSERT(state == 0 || state == 1);
+				if (m_listener.onAlarm != nullptr) {
+					m_listener.onAlarm(this, state, 
+						pEqAlarmStep->getAlarmId(),
+						pEqAlarmStep->getUnitId(),
+						pEqAlarmStep->getAlarmLevel());
+				}
+			}
+		}
+
+
+		return 0;
 	}
 
 	CPin* CEquipment::addPin(PinType type, char* pszName)
@@ -547,6 +630,7 @@
 
 
 		// 模拟取出第一张Panel,传送到下一环节
+		ULONGLONG time = CToolUnits::getTimestamp();
 		Lock();
 		if (m_glassList.empty()) {
 			Unlock();
@@ -561,8 +645,15 @@
 			LOGE("<CEquipment>对方拒绝接收Intent.");
 		}
 		else if (nRet == FLOW_ACCEPT) {
+			CPath* pPath = pContext->getPathWithSiteID(m_nID);
+			if (pPath != nullptr) {
+				pPath->setOutTime(time);
+			}
 			m_glassList.pop_front();
 			pContext->release();		// 添加到列队时addRef, 取出时release
+			if (m_listener.onDataChanged != nullptr) {
+				m_listener.onDataChanged(this, 0);
+			}
 		}
 
 		pContext->release();
@@ -579,9 +670,15 @@
 	int CEquipment::glassArrived(CGlass* pGlass)
 	{
 		Lock();
+		pGlass->addPath(m_nID);
 		pGlass->addRef();
 		m_glassList.push_back(pGlass);
 		Unlock();
+
+		if (m_listener.onDataChanged != nullptr) {
+			m_listener.onDataChanged(this, 0);
+		}
+
 		return FLOW_ACCEPT;
 	}
 
@@ -593,5 +690,56 @@
 		pGlass->addRef();
 		m_glassList.push_back(pGlass);
 		Unlock();
+
+		if (m_listener.onDataChanged != nullptr) {
+			m_listener.onDataChanged(this, 0);
+		}
 	}
+
+	BOOL CEquipment::removeClass(CGlass* pGlass)
+	{
+		Lock();
+		bool bExist = std::find(m_glassList.begin(), m_glassList.end(), pGlass) != m_glassList.end();
+		if (bExist) {
+			pGlass->addPath(EQ_ID_OPERATOR_REMOVE);
+			pGlass->release();
+			m_glassList.remove(pGlass);
+		}
+		Unlock();
+
+		if (bExist && m_listener.onDataChanged != nullptr) {
+			m_listener.onDataChanged(this, 0);
+		}
+
+		return bExist;
+	}
+
+	void CEquipment::getGlassList(std::list<CGlass*>& list)
+	{
+		Lock();
+		for (auto item : m_glassList) {
+			item->addRef();
+			list.push_back(item);
+		}
+		Unlock();
+	}
+
+	CGlass* CEquipment::getFrontGlass()
+	{
+		CGlass* pGlass = nullptr;
+
+		Lock();
+		if (!m_glassList.empty()) {
+			pGlass = m_glassList.front();
+		}
+		Unlock();
+
+		return pGlass;
+	}
+
+	bool CEquipment::isAlarmStep(SERVO::CStep* pStep)
+	{
+		return CToolUnits::startsWith(pStep->getName(), STEP_ALARM_START);
+	}
+
 }
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index 576adaa..407b505 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -13,6 +13,9 @@
 #include "CEqCimMessageClearStep.h"
 #include "CEqDateTimeSetCmdStep.h"
 #include "CEqVCREnableStep.h"
+#include "CEqPortChangeStep.h"
+#include "CEqReadIntStep.h"
+#include "CEqCassetteTransferStateStep.h"
 #include <vector>
 #include <map>
 #include <list>
@@ -25,10 +28,14 @@
 #define VCR_MAX						1
 
 	typedef std::function<void(void* pEiuipment, BOOL bAlive)> ONALIVE;
+	typedef std::function<void(void* pEiuipment, int code)> ONDATACHANGED;
+	typedef std::function<void(void* pEiuipment, int state, int alarmId, int unitId, int level)> ONALARM;
 	typedef struct _EquipmentListener
 	{
 		ONALIVE				onAlive;
 		ONALIVE				onCimStateChanged;
+		ONALARM				onAlarm;
+		ONDATACHANGED		onDataChanged;
 	} EquipmentListener;
 
 	// Memory Block 结构体定义
@@ -84,6 +91,7 @@
 		virtual void onTimer(UINT nTimerid);
 		virtual void serialize(CArchive& ar);
 		virtual void onReceiveLBData(const char* pszData, size_t size);
+		virtual int onStepEvent(CStep* pStep, int code);
 		virtual CPin* addPin(PinType type, char* pszName);
 		CPin* getPin(char* pszName);
 		std::vector<CPin*>& CEquipment::getInputPins();
@@ -92,6 +100,10 @@
 		virtual BOOL glassWillArrive(CGlass* pGlass);
 		virtual int outputGlass(int port);
 		virtual int glassArrived(CGlass* pGlass);
+		void getGlassList(std::list<CGlass*>& list);
+		CGlass* getFrontGlass();
+		BOOL removeClass(CGlass* pGlass);
+		bool isAlarmStep(SERVO::CStep* pStep);
 
 	// 以下为从CC-Link读取到的Bit标志位检测函数
 	public:
diff --git a/SourceCode/Bond/Servo/CEquipmentPage1.cpp b/SourceCode/Bond/Servo/CEquipmentPage1.cpp
new file mode 100644
index 0000000..30aa397
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEquipmentPage1.cpp
@@ -0,0 +1,80 @@
+锘�// CEquipmentPage1.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CEquipmentPage1.h"
+#include "afxdialogex.h"
+
+
+// CEquipmentPage1 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CEquipmentPage1, CHMPropertyPage)
+
+CEquipmentPage1::CEquipmentPage1(CWnd* pParent /*=nullptr*/)
+	: CHMPropertyPage(IDD_PAGE_EQUIPMENT1, pParent)
+{
+	m_pEquipment = nullptr;
+}
+
+CEquipmentPage1::~CEquipmentPage1()
+{
+}
+
+void CEquipmentPage1::DoDataExchange(CDataExchange* pDX)
+{
+	CHMPropertyPage::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CEquipmentPage1, CHMPropertyPage)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+END_MESSAGE_MAP()
+
+
+// CEquipmentPage1 娑堟伅澶勭悊绋嬪簭
+void CEquipmentPage1::OnApply()
+{
+	__super::OnApply();
+}
+
+void CEquipmentPage1::setEquipment(SERVO::CEquipment* pEquipment)
+{
+	m_pEquipment = pEquipment;
+}
+
+BOOL CEquipmentPage1::OnInitDialog()
+{
+	CHMPropertyPage::OnInitDialog();
+
+	// TODO:  鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+HBRUSH CEquipmentPage1::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CHMPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	// TODO:  鍦ㄦ鏇存敼 DC 鐨勪换浣曠壒鎬�
+
+	// TODO:  濡傛灉榛樿鐨勪笉鏄墍闇�鐢荤瑪锛屽垯杩斿洖鍙︿竴涓敾绗�
+	return hbr;
+}
+
+void CEquipmentPage1::OnDestroy()
+{
+	CHMPropertyPage::OnDestroy();
+
+	// TODO: 鍦ㄦ澶勬坊鍔犳秷鎭鐞嗙▼搴忎唬鐮�
+}
+
+void CEquipmentPage1::OnSize(UINT nType, int cx, int cy)
+{
+	CHMPropertyPage::OnSize(nType, cx, cy);
+
+	// TODO: 鍦ㄦ澶勬坊鍔犳秷鎭鐞嗙▼搴忎唬鐮�
+}
diff --git a/SourceCode/Bond/Servo/CEquipmentPage1.h b/SourceCode/Bond/Servo/CEquipmentPage1.h
new file mode 100644
index 0000000..91e4f90
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEquipmentPage1.h
@@ -0,0 +1,36 @@
+锘�#pragma once
+#include "CHMPropertyPage.h"
+#include "CEquipment.h"
+
+
+// CEquipmentPage1 瀵硅瘽妗�
+
+class CEquipmentPage1 : public CHMPropertyPage
+{
+	DECLARE_DYNAMIC(CEquipmentPage1)
+
+public:
+	CEquipmentPage1(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CEquipmentPage1();
+	virtual void OnApply();
+	void setEquipment(SERVO::CEquipment* pEquipment);
+
+private:
+	SERVO::CEquipment* m_pEquipment;
+
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_PAGE_EQUIPMENT1 };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	afx_msg void OnDestroy();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+};
diff --git a/SourceCode/Bond/Servo/CEquipmentPage2.cpp b/SourceCode/Bond/Servo/CEquipmentPage2.cpp
new file mode 100644
index 0000000..ca4b445
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEquipmentPage2.cpp
@@ -0,0 +1,180 @@
+锘�// CEquipmentPage2.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CEquipmentPage2.h"
+#include "afxdialogex.h"
+
+
+// CEquipmentPage2 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CEquipmentPage2, CHMPropertyPage)
+
+CEquipmentPage2::CEquipmentPage2(CWnd* pParent /*=nullptr*/)
+	: CHMPropertyPage(IDD_PAGE_EQUIPMENT2, pParent)
+{
+	m_pEquipment = nullptr;
+}
+
+CEquipmentPage2::~CEquipmentPage2()
+{
+}
+
+void CEquipmentPage2::DoDataExchange(CDataExchange* pDX)
+{
+	CHMPropertyPage::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_LIST1, m_listCtrl);
+}
+
+
+BEGIN_MESSAGE_MAP(CEquipmentPage2, CHMPropertyPage)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CEquipmentPage2::OnLvnItemchangedList1)
+	ON_BN_CLICKED(IDC_BUTTON_REMOVE, &CEquipmentPage2::OnBnClickedButtonRemove)
+END_MESSAGE_MAP()
+
+
+// CEquipmentPage2 娑堟伅澶勭悊绋嬪簭
+void CEquipmentPage2::OnApply()
+{
+	__super::OnApply();
+}
+
+void CEquipmentPage2::setEquipment(SERVO::CEquipment* pEquipment)
+{
+	m_pEquipment = pEquipment;
+}
+
+
+BOOL CEquipmentPage2::OnInitDialog()
+{
+	CHMPropertyPage::OnInitDialog();
+
+	
+	// 璇诲嚭鍒楀
+	CString strIniFile, strItem;
+	strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+	int width[8] = { 0, 218, 180, 180, 180, 180, 180, 180 };
+	for (int i = 0; i < 8; i++) {
+		strItem.Format(_T("Col_%d_Width"), i);
+		width[i] = GetPrivateProfileInt("EquipmentPage2ListCtrl", strItem, width[i], strIniFile);
+	}
+
+
+	// 鎶ヨ〃鎺т欢
+	DWORD dwStyle = m_listCtrl.GetExtendedStyle();
+	dwStyle |= LVS_EX_FULLROWSELECT;
+	dwStyle |= LVS_EX_GRIDLINES;
+	m_listCtrl.SetExtendedStyle(dwStyle);
+
+	HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1);
+	ListView_SetImageList(m_listCtrl.GetSafeHwnd(), imageList, LVSIL_SMALL);
+	m_listCtrl.InsertColumn(0, _T(""), LVCFMT_RIGHT, width[0]);
+	m_listCtrl.InsertColumn(1, _T("ID"), LVCFMT_LEFT, width[1]);
+	m_listCtrl.InsertColumn(2, _T("鏃堕棿"), LVCFMT_LEFT, width[2]);
+	m_listCtrl.SetColumnWidth(2, LVSCW_AUTOSIZE_USEHEADER);
+
+
+	ASSERT(m_pEquipment);
+	std::list<SERVO::CGlass*> list;
+	m_pEquipment->getGlassList(list);
+	for (auto item : list) {
+		item->addRef();				
+		item->release();		// 閲婃斁list涓殑寮曠敤
+		int index = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), _T(""));
+		m_listCtrl.SetItemData(index, (DWORD_PTR)item);
+		m_listCtrl.SetItemText(index, 1, item->getID().c_str());
+
+	}
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+HBRUSH CEquipmentPage2::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CHMPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	// TODO:  鍦ㄦ鏇存敼 DC 鐨勪换浣曠壒鎬�
+
+	// TODO:  濡傛灉榛樿鐨勪笉鏄墍闇�鐢荤瑪锛屽垯杩斿洖鍙︿竴涓敾绗�
+	return hbr;
+}
+
+void CEquipmentPage2::OnDestroy()
+{
+	CHMPropertyPage::OnDestroy();
+
+	// 淇濆瓨鍒楀
+	CString strIniFile, strItem, strTemp;
+	strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+	CHeaderCtrl* pHeader = m_listCtrl.GetHeaderCtrl();
+	for (int i = 0; i < pHeader->GetItemCount(); i++) {
+		RECT rect;
+		pHeader->GetItemRect(i, &rect);
+		strItem.Format(_T("Col_%d_Width"), i);
+		strTemp.Format(_T("%d"), rect.right - rect.left);
+		WritePrivateProfileString("EquipmentPage2ListCtrl", strItem, strTemp, strIniFile);
+	}
+
+	for (int i = 0; i < m_listCtrl.GetItemCount(); i++) {
+		SERVO::CGlass* pGlass = (SERVO::CGlass*)m_listCtrl.GetItemData(i);
+		pGlass->release();
+	}
+}
+
+void CEquipmentPage2::OnSize(UINT nType, int cx, int cy)
+{
+	CHMPropertyPage::OnSize(nType, cx, cy);
+	if (GetDlgItem(IDC_LIST1) == nullptr) return;
+
+	CWnd* pItem;
+	CRect rcClient, rcItem;
+	GetClientRect(&rcClient);
+
+	int x = 12;
+	int y2 = rcClient.bottom - 12;
+	pItem = GetDlgItem(IDC_BUTTON_REMOVE);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(x, y2 - rcItem.Height(), rcItem.Width(), rcItem.Height());
+	y2 -= rcItem.Height();
+	y2 -= 8;
+
+	m_listCtrl.MoveWindow(x, 58, rcClient.Width() - 24, y2 - 58);
+}
+
+void CEquipmentPage2::OnLvnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult)
+{
+	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
+
+	if (LVIF_STATE == pNMLV->uChanged) {
+		int nItem = pNMLV->iItem;
+		GetDlgItem(IDC_BUTTON_REMOVE)->EnableWindow(GetSelectedItemIndex() >= 0);
+	}
+
+
+	*pResult = 0;
+}
+
+int CEquipmentPage2::GetSelectedItemIndex()
+{
+	POSITION pos = m_listCtrl.GetFirstSelectedItemPosition();
+	return m_listCtrl.GetNextSelectedItem(pos);
+}
+
+void CEquipmentPage2::OnBnClickedButtonRemove()
+{
+	int index = GetSelectedItemIndex();
+	if (index >= 0) {
+		SERVO::CGlass* pGlass = (SERVO::CGlass*)m_listCtrl.GetItemData(index);
+		ASSERT(m_pEquipment);
+		BOOL bRet = m_pEquipment->removeClass(pGlass);
+		if (bRet) {
+			pGlass->release();
+			m_listCtrl.DeleteItem(index);
+		}
+	}
+}
diff --git a/SourceCode/Bond/Servo/CEquipmentPage2.h b/SourceCode/Bond/Servo/CEquipmentPage2.h
new file mode 100644
index 0000000..99a7596
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEquipmentPage2.h
@@ -0,0 +1,43 @@
+锘�#pragma once
+#include "CHMPropertyPage.h"
+#include "CEquipment.h"
+#include "ListCtrlEx.h"
+
+
+// CEpuipmentPage2 瀵硅瘽妗�
+
+class CEquipmentPage2 : public CHMPropertyPage
+{
+	DECLARE_DYNAMIC(CEquipmentPage2)
+
+public:
+	CEquipmentPage2(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CEquipmentPage2();
+	virtual void OnApply();
+	void setEquipment(SERVO::CEquipment* pEquipment);
+
+private:
+	int GetSelectedItemIndex();
+
+private:
+	SERVO::CEquipment* m_pEquipment;
+	CListCtrlEx m_listCtrl;
+
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_PAGE_EQUIPMENT2 };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	afx_msg void OnDestroy();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	afx_msg void OnLvnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult);
+	afx_msg void OnBnClickedButtonRemove();
+};
diff --git a/SourceCode/Bond/Servo/CGlass.cpp b/SourceCode/Bond/Servo/CGlass.cpp
index e9847f9..a21bd7b 100644
--- a/SourceCode/Bond/Servo/CGlass.cpp
+++ b/SourceCode/Bond/Servo/CGlass.cpp
@@ -5,12 +5,18 @@
 namespace SERVO {
 	CGlass::CGlass()
 	{
-
+		m_pPath = nullptr;
 	}
 
 	CGlass::~CGlass()
 	{
-
+		CPath* pPath = m_pPath;
+		while (pPath != nullptr) {
+			CPath* pTemp = pPath->getNext();
+			delete pPath;
+			pPath = pTemp;
+		}
+		m_pPath = nullptr;
 	}
 
 	std::string& CGlass::getClassName()
@@ -39,18 +45,58 @@
 		return m_strID;
 	}
 
+	CPath* CGlass::getPathWithSiteID(unsigned int nSiteId)
+	{
+		CPath* pPath = m_pPath;
+		while (pPath != nullptr) {
+			if (nSiteId == pPath->getSiteID()) {
+				return pPath;
+			}
+			pPath = pPath->getNext();
+		}
+
+		return nullptr;
+	}
+
+	CPath* CGlass::getPath()
+	{
+		return m_pPath;
+	}
+
+	void CGlass::addPath(unsigned int nSiteId)
+	{
+		CPath* pPath = new CPath(nSiteId);
+		if (m_pPath == nullptr) {
+			m_pPath = pPath;
+		}
+		else {
+			m_pPath->addPath(pPath);
+		}
+	}
+
 	void CGlass::serialize(CArchive& ar)
 	{
 		if (ar.IsStoring())
 		{
 			Lock();
 			WriteString(ar, m_strID);
+			ar << (ULONGLONG)m_pPath;
+			if (m_pPath != nullptr) {
+				m_pPath->serialize(ar);
+			}
 			Unlock();
 		}
 		else
 		{
 			Lock();
 			ReadString(ar, m_strID);
+			ULONGLONG ullPath;
+			ar >> ullPath;
+			if (ullPath != 0) {
+				m_pPath = new CPath();
+				m_pPath->serialize(ar);
+			}
+
 			Unlock();
 		}
 	}
diff --git a/SourceCode/Bond/Servo/CGlass.h b/SourceCode/Bond/Servo/CGlass.h
index fe5a704..e19a9a6 100644
--- a/SourceCode/Bond/Servo/CGlass.h
+++ b/SourceCode/Bond/Servo/CGlass.h
@@ -1,6 +1,7 @@
 #pragma once
 #include "Context.h"
 #include <string>
+#include "CPath.h"
 
 
 namespace SERVO {
@@ -15,10 +16,14 @@
 		virtual std::string toString();
 		void setID(const char* pszID);
 		std::string& getID();
+		CPath* getPathWithSiteID(unsigned int nSiteId);
+		CPath* getPath();
+		void addPath(unsigned int nSiteId);
 		void serialize(CArchive& ar);
 
 	private:
 		std::string m_strID;
+		CPath* m_pPath;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CHMPropertyDlg.cpp b/SourceCode/Bond/Servo/CHMPropertyDlg.cpp
new file mode 100644
index 0000000..2542fca
--- /dev/null
+++ b/SourceCode/Bond/Servo/CHMPropertyDlg.cpp
@@ -0,0 +1,212 @@
+锘�// CEquipmentDlg.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CHMPropertyDlg.h"
+#include "afxdialogex.h"
+#include "HmTab.h"
+
+
+// CEquipmentDlg 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CHMPropertyDlg, CDialogEx)
+
+CHMPropertyDlg::CHMPropertyDlg(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_DIALOG_PROPERTY, pParent)
+{
+	m_crBkgnd = APPDLG_BACKGROUND_COLOR;
+	m_hbrBkgnd = nullptr;
+	m_nWndWidth = 0;
+	m_nWndHeight = 0;
+}
+
+CHMPropertyDlg::CHMPropertyDlg(const char* pszTitle, int width, int height)
+	: CDialogEx(IDD_DIALOG_PROPERTY, nullptr)
+{
+	m_crBkgnd = APPDLG_BACKGROUND_COLOR;
+	m_hbrBkgnd = nullptr;
+	m_nWndWidth = width;
+	m_nWndHeight = height;
+	m_strTitle = pszTitle;
+}
+
+CHMPropertyDlg::~CHMPropertyDlg()
+{
+}
+
+void CHMPropertyDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CHMPropertyDlg, CDialogEx)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+	ON_NOTIFY(BYHMTAB_SEL_CHANGED, IDC_TAB1, &CHMPropertyDlg::OnTabSelChanged)
+	ON_BN_CLICKED(IDOK, &CHMPropertyDlg::OnBnClickedOk)
+	ON_BN_CLICKED(IDC_BUTTON_APPLY, &CHMPropertyDlg::OnBnClickedButtonApply)
+END_MESSAGE_MAP()
+
+
+// CEquipmentDlg 娑堟伅澶勭悊绋嬪簭
+
+
+void CHMPropertyDlg::addPage(CHMPropertyPage* pPage, const char* pszName)
+{
+	pPage->SetWindowTextA(pszName);
+	m_pages.push_back(pPage);
+}
+
+BOOL CHMPropertyDlg::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	if (m_nWndWidth != 0 && m_nWndHeight != 0) {
+		SetWindowPos(nullptr, 0, 0, m_nWndWidth, m_nWndHeight, SWP_NOMOVE);
+		CenterWindow();
+	}
+	SetWindowText(m_strTitle);
+
+
+
+	// Tab
+	CString strTitle;
+	CHmTab* m_pTab = CHmTab::Hook(GetDlgItem(IDC_TAB1)->m_hWnd);
+	m_pTab->SetPaddingLeft(20);
+	m_pTab->SetItemMarginLeft(18);
+	for (int i = 0; i < m_pages.size(); i++) {
+		m_pages[i]->SetParent(this);
+		m_pages[i]->GetWindowText(strTitle);
+		m_pTab->AddItem(strTitle, i == m_pages.size() - 1);
+	}
+	m_pTab->SetCurSel(0);
+	ShowChildPage(0);
+
+	Resize();
+
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+HBRUSH CHMPropertyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	if (nCtlColor == CTLCOLOR_STATIC) {
+		pDC->SetBkColor(m_crBkgnd);
+		pDC->SetTextColor(RGB(0, 0, 0));
+	}
+
+	if (m_hbrBkgnd == nullptr) {
+		m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
+	}
+
+	return m_hbrBkgnd;
+}
+
+void CHMPropertyDlg::OnDestroy()
+{
+	CDialogEx::OnDestroy();
+
+	for (auto item : m_pages) {
+		item->DestroyWindow();
+		delete item;
+	}
+
+	if (m_hbrBkgnd != nullptr) {
+		::DeleteObject(m_hbrBkgnd);
+	}
+}
+
+void CHMPropertyDlg::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+	if (GetDlgItem(IDC_TAB1) == nullptr) return;
+	Resize();
+}
+
+void CHMPropertyDlg::Resize()
+{
+	CWnd* pItem;
+	CRect rcClient, rcItem;
+	GetClientRect(&rcClient);
+
+	int x2, y, y2;
+	x2 = rcClient.right - 12;
+	y = 0;
+	y2 = rcClient.bottom - 12;
+	pItem = GetDlgItem(IDC_TAB1);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(0, y, rcClient.Width(), rcItem.Height());
+	y += rcItem.Height();
+
+	// [纭畾]鎸夐挳
+	pItem = GetDlgItem(IDOK);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(x2 - rcItem.Width(), y2 - rcItem.Height(),
+		rcItem.Width(), rcItem.Height());
+	x2 -= rcItem.Width();
+	x2 -= 8;
+
+	// [搴旂敤]鎸夐挳
+	pItem = GetDlgItem(IDC_BUTTON_APPLY);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(x2 - rcItem.Width(), y2 - rcItem.Height(),
+		rcItem.Width(), rcItem.Height());
+	y2 -= rcItem.Height();
+	y2 -= 12;
+
+	// 鍒嗛殧绾�
+	pItem = GetDlgItem(IDC_LINE1);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(0, y2, rcClient.Width(), rcItem.Height());
+
+
+	for (auto item : m_pages) {
+		item->MoveWindow(0, y, rcClient.Width(), y2 - y);
+	}
+}
+
+void CHMPropertyDlg::OnTabSelChanged(NMHDR* nmhdr, LRESULT* result)
+{
+	BYHMTAB_NMHDR* pNmhdrex = (BYHMTAB_NMHDR*)nmhdr;
+	ShowChildPage((int)pNmhdrex->dwData);
+
+	*result = 0;
+}
+
+void CHMPropertyDlg::ShowChildPage(unsigned int index)
+{
+	ASSERT(index < m_pages.size());
+	for (int i = 0; i < m_pages.size(); i++) {
+		m_pages[i]->ShowWindow(i == index ? SW_SHOW : SW_HIDE);
+	}
+}
+
+void CHMPropertyDlg::SetWindowSize(int width, int height)
+{
+	m_nWndWidth = width;
+	m_nWndHeight = height;
+}
+
+void CHMPropertyDlg::OnBnClickedOk()
+{
+	for (auto item : m_pages) {
+		item->OnApply();
+	}
+
+	CDialogEx::OnOK();
+}
+
+void CHMPropertyDlg::OnBnClickedButtonApply()
+{
+	for (int i = 0; i < m_pages.size(); i++) {
+		if (m_pages[i]->IsWindowVisible()) {
+			m_pages[i]->OnApply();
+		}
+	}
+}
diff --git a/SourceCode/Bond/Servo/CHMPropertyDlg.h b/SourceCode/Bond/Servo/CHMPropertyDlg.h
new file mode 100644
index 0000000..9ff65b1
--- /dev/null
+++ b/SourceCode/Bond/Servo/CHMPropertyDlg.h
@@ -0,0 +1,52 @@
+锘�#pragma once
+#include <vector>
+#include "CHMPropertyPage.h"
+
+
+// CEquipmentDlg 瀵硅瘽妗�
+
+class CHMPropertyDlg : public CDialogEx
+{
+	DECLARE_DYNAMIC(CHMPropertyDlg)
+
+public:
+	CHMPropertyDlg(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	CHMPropertyDlg(const char* pszTitle, int width, int height);
+	virtual ~CHMPropertyDlg();
+
+
+public:
+	void addPage(CHMPropertyPage* pPage, const char* pszName);
+	void ShowChildPage(unsigned int index);
+	void SetWindowSize(int width, int height);
+
+private:
+	void Resize();
+
+private:
+	COLORREF m_crBkgnd;
+	HBRUSH m_hbrBkgnd;
+	CString m_strTitle;
+	std::vector<CHMPropertyPage*> m_pages;
+	int m_nWndWidth;
+	int m_nWndHeight;
+
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_DIALOG_PROPERTY };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	afx_msg void OnDestroy();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	afx_msg void OnTabSelChanged(NMHDR* nmhdr, LRESULT* result);
+	afx_msg void OnBnClickedOk();
+	afx_msg void OnBnClickedButtonApply();
+};
diff --git a/SourceCode/Bond/Servo/CHMPropertyPage.cpp b/SourceCode/Bond/Servo/CHMPropertyPage.cpp
new file mode 100644
index 0000000..3591ec4
--- /dev/null
+++ b/SourceCode/Bond/Servo/CHMPropertyPage.cpp
@@ -0,0 +1,20 @@
+#include "stdafx.h"
+#include "CHMPropertyPage.h"
+
+
+IMPLEMENT_DYNAMIC(CHMPropertyPage, CDialogEx)
+
+CHMPropertyPage::CHMPropertyPage(UINT nID, CWnd* pPage) : CDialogEx(nID, pPage)
+{
+
+}
+
+CHMPropertyPage::~CHMPropertyPage()
+{
+
+}
+
+void CHMPropertyPage::OnApply()
+{
+
+}
diff --git a/SourceCode/Bond/Servo/CHMPropertyPage.h b/SourceCode/Bond/Servo/CHMPropertyPage.h
new file mode 100644
index 0000000..8f90c5b
--- /dev/null
+++ b/SourceCode/Bond/Servo/CHMPropertyPage.h
@@ -0,0 +1,14 @@
+#pragma once
+
+class CHMPropertyPage : public CDialogEx
+{
+	DECLARE_DYNAMIC(CHMPropertyPage)
+
+public:
+	CHMPropertyPage(UINT nID, CWnd* pPage);			// 标准构造函数
+	virtual ~CHMPropertyPage();						// 析构函数
+	virtual void OnApply();
+
+
+};
+
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 0975cde..fff1ab0 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -2,6 +2,17 @@
 #include "Common.h"
 #include "CMaster.h"
 
+
+#define ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(name,ws,index,psd) {				\
+	CEqCassetteTransferStateStep* pStep = new CEqCassetteTransferStateStep();	\
+	pStep->setName(name);														\
+	pStep->setWriteSignalDev(ws);												\
+	pStep->setPortStatusDev(psd);												\
+	if (pEquipment->addStep(index, pStep) != 0) {								\
+		delete pStep;															\
+	}																			\
+}
+
 namespace SERVO {
 	CMaster* g_pMaster = NULL;
 	void CALLBACK MasterTimerProc(HWND hWnd, UINT nMsg, UINT nTimerid, DWORD dwTime)
@@ -14,6 +25,7 @@
 	CMaster::CMaster()
 	{
 		m_listener = {nullptr, nullptr, nullptr};
+		m_bDataModify = FALSE;
 	}
 
 	CMaster::~CMaster()
@@ -28,21 +40,12 @@
 	{
 		m_listener.onEqAlive = listener.onEqAlive;
 		m_listener.onEqCimStateChanged = listener.onEqCimStateChanged;
-		m_listener.onEqStepEvent = listener.onEqStepEvent;
+		m_listener.onEqAlarm = listener.onEqAlarm;
 	}
 
 	int CMaster::init()
 	{
 		LOGI("<Master>正在初始化...");
-
-
-		StepListener listener;
-		listener.onEvent = [&](void* pStep, int code, void* pData) -> void {
-			TRACE("<CEquipment>onEvent<%d, 0x%x>.\n", code, pData);
-			if (m_listener.onEqStepEvent != nullptr) {
-				m_listener.onEqStepEvent((CStep*)pStep, code, pData);
-			}
-		};
 
 
 		// 	cclink
@@ -72,17 +75,17 @@
 
 
 		// 初始化添加各子设备
-		addLoadPort(0, listener);
-		addLoadPort(1, listener);
-		addLoadPort(2, listener);
-		addLoadPort(3, listener);
-		addFliper(listener);
-		addVacuumBake(listener);
-		addAligner(listener);
-		addEFEM(listener);
-		addBonder(0, listener);
-		addBonder(1, listener);
-		addBakeCooling(listener);
+		addLoadPort(0);
+		addLoadPort(1);
+		addLoadPort(2);
+		addLoadPort(3);
+		addFliper();
+		addVacuumBake();
+		addAligner();
+		addEFEM();
+		addBonder(0);
+		addBonder(1);
+		addBakeCooling();
 		connectEquipments();
 
 		
@@ -126,6 +129,16 @@
 				m_listener.onEqCimStateChanged(this, p, bOn);
 			}
 		};
+		listener.onAlarm = [&](void* pEquipment, int state, int alarmId, int unitId, int level) -> void {
+			CEquipment* p = (CEquipment*)pEquipment;
+			if (m_listener.onEqAlarm != nullptr) {
+				m_listener.onEqAlarm(this, p, state, alarmId, unitId, level);
+			}
+		};
+		listener.onDataChanged = [&](void* pEquipment, int code) -> void {
+			m_bDataModify = TRUE;
+		};
+
 		pEquipment->setListener(listener);
 		pEquipment->setCcLink(&m_cclink);
 		m_listEquipment.push_back(pEquipment);
@@ -150,7 +163,7 @@
 	/* 添加LoadPort1
 	 * index -- 0~3
 	 */
-	int CMaster::addLoadPort(int index, StepListener& listener)
+	int CMaster::addLoadPort(int index)
 	{
 		ASSERT(index == 0 || index == 1 || index == 2 || index == 3);
 		char szName[64];
@@ -168,7 +181,7 @@
 		return 0;
 	}
 
-	int CMaster::addFliper(StepListener& listener)
+	int CMaster::addFliper()
 	{
 		CFliper* pEquipment = new CFliper();
 		pEquipment->setID(EQ_ID_FLIPER);
@@ -185,7 +198,7 @@
 		return 0;
 	}
 
-	int CMaster::addVacuumBake(StepListener& listener)
+	int CMaster::addVacuumBake()
 	{
 		CVacuumBake* pEquipment = new CVacuumBake();
 		pEquipment->setID(EQ_ID_VACUUMBAKE);
@@ -202,7 +215,7 @@
 		return 0;
 	}
 
-	int CMaster::addAligner(StepListener& listener)
+	int CMaster::addAligner()
 	{
 		CAligner* pEquipment = new CAligner();
 		pEquipment->setID(EQ_ID_ALIGNER);
@@ -219,7 +232,7 @@
 		return 0;
 	}
 
-	int CMaster::addEFEM(StepListener& listener)
+	int CMaster::addEFEM()
 	{
 		CEFEM* pEquipment = new CEFEM();
 		pEquipment->setID(EQ_ID_EFEM);
@@ -235,7 +248,6 @@
 		{
 			CEqModeStep* pStep = new CEqModeStep();
 			pStep->setName(STEP_MODE);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x30);
 			pStep->setModeDev(0x4a8c);
 			if (pEquipment->addStep(0x360, pStep) != 0) {
@@ -245,7 +257,6 @@
 		{
 			CEqStatusStep* pStep = new CEqStatusStep();
 			pStep->setName(STEP_STATUS);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x31);
 			pStep->setStatusDev(0x4a68);
 			if (pEquipment->addStep(0x361, pStep) != 0) {
@@ -255,7 +266,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK1);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x32);
 			pStep->setAlarmDev(0x4c1d);
 			if (pEquipment->addStep(0x362, pStep) != 0) {
@@ -265,7 +275,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK2);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x33);
 			pStep->setAlarmDev(0x4c4a);
 			if (pEquipment->addStep(0x363, pStep) != 0) {
@@ -275,7 +284,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK3);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x34);
 			pStep->setAlarmDev(0x4c77);
 			if (pEquipment->addStep(0x364, pStep) != 0) {
@@ -285,7 +293,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK4);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x35);
 			pStep->setAlarmDev(0x4ca4);
 			if (pEquipment->addStep(0x365, pStep) != 0) {
@@ -295,7 +302,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK5);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x36);
 			pStep->setAlarmDev(0x4cd1);
 			if (pEquipment->addStep(0x366, pStep) != 0) {
@@ -305,7 +311,6 @@
 		{
 			CEqProcessStep* pStep = new CEqProcessStep();
 			pStep->setName(STEP_PROCESS);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x37);
 			pStep->setProcessDev(0x5864);
 			if (pEquipment->addStep(0x367, pStep) != 0) {
@@ -315,7 +320,6 @@
 		{
 			CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
 			pStep->setName(STEP_CIM_MODE_CHANGE);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x50);
 			pStep->setCimModeDev(0x15);
 			if (pEquipment->addStep(0x350, pStep) != 0) {
@@ -325,7 +329,6 @@
 		{
 			CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
 			pStep->setName(STEP_CIM_MESSAGE_CMD);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x51);
 			pStep->setCimMessageDev(0x0);
 			if (pEquipment->addStep(0x351, pStep) != 0) {
@@ -335,7 +338,6 @@
 		{
 			CEqCimMessageClearStep* pStep = new CEqCimMessageClearStep();
 			pStep->setName(STEP_CIM_MESSAGE_CLEAR);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x52);
 			pStep->setClearCimMessageDev(0x13);
 			if (pEquipment->addStep(0x352, pStep) != 0) {
@@ -345,7 +347,6 @@
 		{
 			CEqDateTimeSetCmdStep* pStep = new CEqDateTimeSetCmdStep();
 			pStep->setName(STEP_DATETIME_SET_CMD);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x53);
 			pStep->setDateTimeDev(0x16);
 			if (pEquipment->addStep(0x353, pStep) != 0) {
@@ -355,7 +356,6 @@
 		{
 			CEqVCREnableStep* pStep = new CEqVCREnableStep();
 			pStep->setName(STEP_EQ_VCR_ENABLE);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x54);
 			pStep->setEqVCRModeDev(0x1F);
 			if (pEquipment->addStep(0x354, pStep) != 0) {
@@ -365,13 +365,263 @@
 		{
 			CEqModeChangeStep* pStep = new CEqModeChangeStep();
 			pStep->setName(STEP_EQ_MODE_CHANGE);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(0x55);
 			pStep->setEqModeDev(0x1E);
 			if (pEquipment->addStep(0x355, pStep) != 0) {
 				delete pStep;
 			}
 		}
+
+		// Port1
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d1f);
+			pStep->setName(STEP_EQ_PORT1_TYPE);
+			pStep->setWriteSignalDev(0x80);
+			if (pEquipment->addStep(0x3e0, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d20);
+			pStep->setName(STEP_EQ_PORT1_MODE);
+			pStep->setWriteSignalDev(0x88);
+			if (pEquipment->addStep(0x3e8, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, 0x4d21);
+			pStep->setName(STEP_EQ_PORT1_CASSETTE_TYPE);
+			pStep->setWriteSignalDev(0x90);
+			if (pEquipment->addStep(0x3f0, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d23);
+			pStep->setName(STEP_EQ_PORT1_TRANSFER_MODE);
+			pStep->setWriteSignalDev(0x98);
+			if (pEquipment->addStep(0x3f8, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d24);
+			pStep->setName(STEP_EQ_PORT1_ENABLE);
+			pStep->setWriteSignalDev(0xa0);
+			if (pEquipment->addStep(0x400, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d25);
+			pStep->setName(STEP_EQ_PORT1_TYPE_ATUO);
+			pStep->setWriteSignalDev(0xa8);
+			if (pEquipment->addStep(0x408, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		// Port2
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d2f);
+			pStep->setName(STEP_EQ_PORT2_TYPE);
+			pStep->setWriteSignalDev(0x81);
+			if (pEquipment->addStep(0x3e1, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d30);
+			pStep->setName(STEP_EQ_PORT2_MODE);
+			pStep->setWriteSignalDev(0x89);
+			if (pEquipment->addStep(0x3e9, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, 0x4d31);
+			pStep->setName(STEP_EQ_PORT2_CASSETTE_TYPE);
+			pStep->setWriteSignalDev(0x91);
+			if (pEquipment->addStep(0x3f1, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d33);
+			pStep->setName(STEP_EQ_PORT2_TRANSFER_MODE);
+			pStep->setWriteSignalDev(0x99);
+			if (pEquipment->addStep(0x3f9, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d34);
+			pStep->setName(STEP_EQ_PORT2_ENABLE);
+			pStep->setWriteSignalDev(0xa1);
+			if (pEquipment->addStep(0x401, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d35);
+			pStep->setName(STEP_EQ_PORT2_TYPE_ATUO);
+			pStep->setWriteSignalDev(0xa9);
+			if (pEquipment->addStep(0x409, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		// Port3
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d3f);
+			pStep->setName(STEP_EQ_PORT3_TYPE);
+			pStep->setWriteSignalDev(0x82);
+			if (pEquipment->addStep(0x3e2, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d40);
+			pStep->setName(STEP_EQ_PORT3_MODE);
+			pStep->setWriteSignalDev(0x8a);
+			if (pEquipment->addStep(0x3ea, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, 0x4d41);
+			pStep->setName(STEP_EQ_PORT3_CASSETTE_TYPE);
+			pStep->setWriteSignalDev(0x92);
+			if (pEquipment->addStep(0x3f2, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d43);
+			pStep->setName(STEP_EQ_PORT3_TRANSFER_MODE);
+			pStep->setWriteSignalDev(0x9a);
+			if (pEquipment->addStep(0x3fa, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d44);
+			pStep->setName(STEP_EQ_PORT3_ENABLE);
+			pStep->setWriteSignalDev(0xa2);
+			if (pEquipment->addStep(0x402, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d45);
+			pStep->setName(STEP_EQ_PORT3_TYPE_ATUO);
+			pStep->setWriteSignalDev(0xaa);
+			if (pEquipment->addStep(0x40a, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		// Port4
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d4f);
+			pStep->setName(STEP_EQ_PORT4_TYPE);
+			pStep->setWriteSignalDev(0x83);
+			if (pEquipment->addStep(0x3e3, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d50);
+			pStep->setName(STEP_EQ_PORT4_MODE);
+			pStep->setWriteSignalDev(0x8b);
+			if (pEquipment->addStep(0x3eb, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, 0x4d51);
+			pStep->setName(STEP_EQ_PORT4_CASSETTE_TYPE);
+			pStep->setWriteSignalDev(0x93);
+			if (pEquipment->addStep(0x3f3, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d53);
+			pStep->setName(STEP_EQ_PORT4_TRANSFER_MODE);
+			pStep->setWriteSignalDev(0x9b);
+			if (pEquipment->addStep(0x3fb, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d54);
+			pStep->setName(STEP_EQ_PORT4_ENABLE);
+			pStep->setWriteSignalDev(0xa3);
+			if (pEquipment->addStep(0x403, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, 0x4d55);
+			pStep->setName(STEP_EQ_PORT4_TYPE_ATUO);
+			pStep->setWriteSignalDev(0xab);
+			if (pEquipment->addStep(0x40b, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+
+		// CEqCassetteTranserStateStep
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_EMPTY, 0xb8, 
+			STEP_ID_PORT1_CASSETTIE_EMPTY, 0x4d5f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_LOAD_EADY, 0xc0,
+			STEP_ID_PORT1_CASSETTIE_LOAD_READY, 0x4d5f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_LOADED, 0xc8, 
+			STEP_ID_PORT1_CASSETTIE_LOADED, 0x4d5f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_INUSE, 0xd0,
+			STEP_ID_PORT1_CASSETTIE_INUSE, 0x4d5f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_UNLOAD_EADY, 0xd8,
+			STEP_ID_PORT1_CASSETTIE_UNLOAD_READY, 0x4d5f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_BLOCKED, 0xe0,
+			STEP_ID_PORT1_CASSETTIE_BLOCKED, 0x4d5f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_EMPTY, 
+			STEP_ID_PORT2_CASSETTIE_EMPTY, 0x418, 0x4d7f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_LOAD_EADY,
+			STEP_ID_PORT2_CASSETTIE_LOAD_READY, 0x420, 0x4d7f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_LOADED,
+			STEP_ID_PORT2_CASSETTIE_LOADED, 0x428, 0x4d7f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_INUSE, 
+			STEP_ID_PORT2_CASSETTIE_INUSE, 0x430, 0x4d7f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_UNLOAD_EADY,
+			STEP_ID_PORT2_CASSETTIE_UNLOAD_READY, 0x438, 0x4d7f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_BLOCKED, 
+			STEP_ID_PORT2_CASSETTIE_BLOCKED, 0x440, 0x4d7f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_EMPTY,
+			STEP_ID_PORT3_CASSETTIE_EMPTY, 0x418, 0x4d9f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_LOAD_EADY,
+			STEP_ID_PORT3_CASSETTIE_LOAD_READY, 0x420, 0x4d9f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_LOADED, 
+			STEP_ID_PORT3_CASSETTIE_INUSE, 0x428, 0x4d9f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_INUSE, 
+			STEP_ID_PORT3_CASSETTIE_INUSE, 0x430, 0x4d9f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_UNLOAD_EADY, 
+			STEP_ID_PORT3_CASSETTIE_UNLOAD_READY, 0x438, 0x4d9f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_BLOCKED,
+			STEP_ID_PORT3_CASSETTIE_BLOCKED, 0x440, 0x4d9f);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_EMPTY, 
+			STEP_ID_PORT4_CASSETTIE_EMPTY, 0x418, 0x4dbf);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_LOAD_EADY, 
+			STEP_ID_PORT4_CASSETTIE_LOAD_READY, 0x420, 0x4dbf);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_LOADED, 
+			STEP_ID_PORT4_CASSETTIE_LOADED, 0x428, 0x4dbf);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_INUSE,
+			STEP_ID_PORT4_CASSETTIE_INUSE, 0x430, 0x4dbf);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_UNLOAD_EADY, 
+			STEP_ID_PORT4_CASSETTIE_UNLOAD_READY, 0x438, 0x4dbf);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_BLOCKED, 
+			STEP_ID_PORT4_CASSETTIE_BLOCKED, 0x440, 0x4dbf);
 
 		pEquipment->init();
 		LOGE("已添加“EFEM(ROBOT)”.");
@@ -382,7 +632,7 @@
 	 * index -- 0, bonder1
 	 * index -- 1, bonder2
 	 */
-	int CMaster::addBonder(int index, StepListener& listener)
+	int CMaster::addBonder(int index)
 	{
 		ASSERT(index == 0 || index == 1);
 		CBonder* pEquipment = new CBonder();
@@ -399,7 +649,6 @@
 		{
 			CEqModeStep* pStep = new CEqModeStep();
 			pStep->setName(STEP_MODE);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x330 : 0x630);
 			pStep->setModeDev(index == 0 ? 0x6a8c : 0x848c);
 			if (pEquipment->addStep(0x360, pStep) != 0) {
@@ -409,7 +658,6 @@
 		{
 			CEqStatusStep* pStep = new CEqStatusStep();
 			pStep->setName(STEP_STATUS);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x331 : 0x631);
 			pStep->setStatusDev(index == 0 ? 0x6a68 : 0x8a68);
 			if (pEquipment->addStep(0x361, pStep) != 0) {
@@ -419,7 +667,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK1);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x332 : 0x632);
 			pStep->setAlarmDev(index == 0 ? 0x6c1d : 0x8c1d);
 			if (pEquipment->addStep(0x362, pStep) != 0) {
@@ -429,7 +676,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK2);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x333 : 0x633);
 			pStep->setAlarmDev(index == 0 ? 0x6c4a : 0x8c4a);
 			if (pEquipment->addStep(0x363, pStep) != 0) {
@@ -439,7 +685,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK3);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x334 : 0x634);
 			pStep->setAlarmDev(index == 0 ? 0x6c77 : 0x8c77);
 			if (pEquipment->addStep(0x364, pStep) != 0) {
@@ -449,7 +694,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK4);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x335 : 0x635);
 			pStep->setAlarmDev(index == 0 ? 0x6ca4 : 0x8ca4);
 			if (pEquipment->addStep(0x365, pStep) != 0) {
@@ -459,7 +703,6 @@
 		{
 			CEqAlarmStep* pStep = new CEqAlarmStep();
 			pStep->setName(STEP_ALARM_BLOCK5);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x336 : 0x636);
 			pStep->setAlarmDev(index == 0 ? 0x6cd1 : 0x8cd1);
 			if (pEquipment->addStep(0x366, pStep) != 0) {
@@ -469,7 +712,6 @@
 		{
 			CEqProcessStep* pStep = new CEqProcessStep();
 			pStep->setName(STEP_PROCESS);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x337 : 0x637);
 			pStep->setProcessDev(index == 0 ? 0x7864 : 0x9864);
 			if (pEquipment->addStep(0x367, pStep) != 0) {
@@ -479,7 +721,6 @@
 		{
 			CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
 			pStep->setName(STEP_CIM_MODE_CHANGE);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x350 : 0x650);
 			pStep->setCimModeDev(index == 0 ? 0x965 : 0x12b5);
 			if (pEquipment->addStep(0x350, pStep) != 0) {
@@ -489,7 +730,6 @@
 		{
 			CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
 			pStep->setName(STEP_CIM_MESSAGE_CMD);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x351 : 0x651);
 			pStep->setCimMessageDev(index == 0 ? 0x950 : 0x12a0);
 			if (pEquipment->addStep(0x351, pStep) != 0) {
@@ -499,7 +739,6 @@
 		{
 			CEqCimMessageClearStep* pStep = new CEqCimMessageClearStep();
 			pStep->setName(STEP_CIM_MESSAGE_CLEAR);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x352 : 0x652);
 			pStep->setClearCimMessageDev(index == 0 ? 0x963 : 0x12b3);
 			if (pEquipment->addStep(0x352, pStep) != 0) {
@@ -509,7 +748,6 @@
 		{
 			CEqDateTimeSetCmdStep* pStep = new CEqDateTimeSetCmdStep();
 			pStep->setName(STEP_DATETIME_SET_CMD);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x353 : 0x653);
 			pStep->setDateTimeDev(index == 0 ? 0x966 : 0x12b6);
 			if (pEquipment->addStep(0x353, pStep) != 0) {
@@ -519,7 +757,6 @@
 		{
 			CEqModeChangeStep* pStep = new CEqModeChangeStep();
 			pStep->setName(STEP_EQ_MODE_CHANGE);
-			pStep->setListener(listener);
 			pStep->setWriteSignalDev(index == 0 ? 0x355 : 0x655);
 			pStep->setEqModeDev(index == 0 ? 0x96E : 0x12be);
 			if (pEquipment->addStep(0x355, pStep) != 0) {
@@ -535,7 +772,7 @@
 		return 0;
 	}
 
-	int CMaster::addBakeCooling(StepListener& listener)
+	int CMaster::addBakeCooling()
 	{
 		CBakeCooling* pEquipment = new CBakeCooling();
 		pEquipment->setID(EQ_ID_BAKE_COOLING);
@@ -578,7 +815,13 @@
 
 
 		// 自动保存缓存
-		saveCache();
+		if (i % (4 * 2) == 0) {
+			if (m_bDataModify) {
+				saveCacheAndBackups();
+				m_bDataModify = FALSE;
+			}
+		}
+
 	}
 
 	void CMaster::connectEquipments()
@@ -669,6 +912,30 @@
 		return 0;
 	}
 
+	int CMaster::saveCacheAndBackups()
+	{
+		saveCache();
+
+
+		// 创建备份目录
+		CString strNewFile;
+		CString strFileDir = m_strFilepath.c_str();
+		int index = strFileDir.ReverseFind('\\');
+		ASSERT(index > 0);
+		strFileDir = strFileDir.Left(index);
+		strFileDir = strFileDir + _T("Backups");
+		::CreateDirectory(strFileDir, nullptr);
+
+		CTime time = CTime::GetCurrentTime();
+		strNewFile.Format(_T("%s//Master_%d_%02d_%02d_%02d_%02d_%02d.dat"),
+			(LPTSTR)(LPCTSTR)strFileDir,
+			time.GetYear(), time.GetMonth(), time.GetDay(),
+			time.GetHour(), time.GetMinute(), time.GetSecond());
+		::CopyFile(m_strFilepath.c_str(), strNewFile, FALSE);
+
+		return 0;
+	}
+
 	void CMaster::setCacheFilepath(const char* pszFilepath)
 	{
 		m_strFilepath = pszFilepath;
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index adf5059..c6180cc 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -14,11 +14,12 @@
 namespace SERVO {
     typedef std::function<void(void* pMaster, CEquipment* pEiuipment, BOOL bAlive)> ONEQALIVE;
     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 struct _MasterListener
     {
         ONEQALIVE				onEqAlive;
         ONEQALIVE		        onEqCimStateChanged;
-        ONEQSTEPEVENT		    onEqStepEvent;
+        ONEQALARM               onEqAlarm;
     } MasterListener;
 
     class CMaster
@@ -39,15 +40,16 @@
 
     private:
         int addToEquipmentList(CEquipment* pEquipment);
-        int addLoadPort(int index, StepListener& listener);
-        int addFliper(StepListener& listener);
-        int addVacuumBake(StepListener& listener);
-        int addAligner(StepListener& listener);
-        int addEFEM(StepListener& listener);
-        int addBonder(int index, StepListener& listener);
-        int addBakeCooling(StepListener& listener);
+        int addLoadPort(int index);
+        int addFliper();
+        int addVacuumBake();
+        int addAligner();
+        int addEFEM();
+        int addBonder(int index);
+        int addBakeCooling();
         void connectEquipments();
         int saveCache();
+        int saveCacheAndBackups();
         int readCache();
         void serialize(CArchive& ar);
 
@@ -56,6 +58,7 @@
         CCCLinkIEControl m_cclink;
         std::list<CEquipment*> m_listEquipment;
         std::string m_strFilepath;
+        BOOL m_bDataModify;
     };
 }
 
diff --git a/SourceCode/Bond/Servo/CPageGraph2.cpp b/SourceCode/Bond/Servo/CPageGraph2.cpp
index f29a3bb..4d6b07f 100644
--- a/SourceCode/Bond/Servo/CPageGraph2.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph2.cpp
@@ -5,6 +5,9 @@
 #include "Servo.h"
 #include "CPageGraph2.h"
 #include "afxdialogex.h"
+#include "CHMPropertyDlg.h"
+#include "CEquipmentPage1.h"
+#include "CEquipmentPage2.h"
 
 
 // CPageGraph2 瀵硅瘽妗�
@@ -80,6 +83,20 @@
 	};
 	listener.onDblckEqItem = [&](EQITEM* pItem) -> bool {
 		ASSERT(pItem);
+		SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
+
+		CHMPropertyDlg dlg(pEquipment->getName().c_str(), 600, 680);
+		CEquipmentPage1* pPage1 = new CEquipmentPage1();
+		pPage1->setEquipment(pEquipment);
+		pPage1->Create(IDD_PAGE_EQUIPMENT1);
+		dlg.addPage(pPage1, "test1");
+
+		CEquipmentPage2* pPage2 = new CEquipmentPage2();
+		pPage2->setEquipment(pEquipment);
+		pPage2->Create(IDD_PAGE_EQUIPMENT2);
+		dlg.addPage(pPage2, "Glass");
+
+		dlg.DoModal();
 		return true;
 	};
 	listener.onRclickEqItem = [&](EQITEM* pItem) -> bool {
@@ -130,6 +147,19 @@
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
 			pEquipment->outputGlass(1);
 		}
+		else if (nCmd == ID_EQSGRAPHITEM_TEST3) {
+			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
+			SERVO::CGlass* pGlass = pEquipment->getFrontGlass();
+			if (pGlass != nullptr) {
+				std::string strDescription;
+				SERVO::CPath* pPath = pGlass->getPath();
+				while (pPath != nullptr) {
+					pPath->getDescription(strDescription);
+					AfxMessageBox(strDescription.c_str());
+					pPath = pPath->getNext();
+				}
+			}
+		}
 
 
 		return true;
diff --git a/SourceCode/Bond/Servo/CPath.cpp b/SourceCode/Bond/Servo/CPath.cpp
new file mode 100644
index 0000000..30c004c
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPath.cpp
@@ -0,0 +1,125 @@
+#include "stdafx.h"
+#include "CPath.h"
+#include "ToolUnits.h"
+
+
+namespace SERVO {
+	CPath::CPath()
+	{
+		m_nSiteID = 0;
+		m_timeOut = 0;
+		m_timeIn = CToolUnits::getTimestamp();
+		m_pPrev = nullptr;
+		m_pNext = nullptr;
+	}
+
+	CPath::CPath(unsigned int nSiteId)
+	{
+		m_nSiteID = nSiteId;
+		m_timeOut = 0;
+		m_timeIn = CToolUnits::getTimestamp();
+		m_pPrev = nullptr;
+		m_pNext = nullptr;
+	}
+
+	CPath::~CPath()
+	{
+
+	}
+
+	void CPath::getDescription(std::string& strOut)
+	{
+		strOut.clear();
+		strOut = "CPath<SiteID:";
+		strOut = strOut + std::to_string(m_nSiteID);
+		strOut = strOut + ",InTime:";
+		strOut = strOut + CToolUnits::timeToString2(m_timeIn);
+		strOut = strOut + ",OutTime:";
+		strOut = strOut + (m_timeOut == 0 ? "" : CToolUnits::timeToString2(m_timeOut));
+		strOut = strOut + ">";
+	}
+
+	void CPath::serialize(CArchive& ar)
+	{
+		if (ar.IsStoring()) {
+			ar << m_nSiteID;
+			ar << m_timeIn;
+			ar << m_timeOut;
+			ar << (ULONGLONG)m_pNext;
+			if (m_pNext != nullptr) {
+				m_pNext->serialize(ar);
+			}
+		}
+		else {
+			ar >> m_nSiteID;
+			ar >> m_timeIn;
+			ar >> m_timeOut;
+			ULONGLONG ulNext;
+			ar >> ulNext;
+			if ((CPath*)ulNext != nullptr) {
+				CPath* pPath = new CPath();
+				pPath->serialize(ar);
+				pPath->m_pPrev = this;
+				this->m_pNext = pPath;
+			}
+		}
+	}
+
+	unsigned int CPath::getSiteID()
+	{
+		return m_nSiteID;
+	}
+
+	ULONGLONG CPath::getInTime()
+	{
+		return m_timeIn;
+	}
+
+	void CPath::setOutTime(ULONGLONG time)
+	{
+		m_timeOut = time;
+	}
+
+	ULONGLONG CPath::getOutTime()
+	{
+		return m_timeOut;
+	}
+
+	CPath* CPath::getPrev()
+	{
+		return m_pPrev;
+	}
+
+	CPath* CPath::getNext()
+	{
+		return m_pNext;
+	}
+
+	void CPath::addPath(CPath* pPath)
+	{
+		CPath* pTail = getTailPath();
+		ASSERT(pTail);
+		pTail->m_pNext = pPath;
+		pPath->m_pPrev = this;
+	}
+
+	CPath* CPath::getTailPath()
+	{
+		CPath* pPath = this;
+		while (pPath->m_pNext != nullptr) {
+			pPath = pPath->m_pNext;
+		}
+
+		return pPath;
+	}
+
+	CPath* CPath::getHeadPath()
+	{
+		CPath* pPath = this;
+		while (pPath->m_pPrev != nullptr) {
+			pPath = pPath->m_pPrev;
+		}
+
+		return pPath;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CPath.h b/SourceCode/Bond/Servo/CPath.h
new file mode 100644
index 0000000..b9dcf5f
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPath.h
@@ -0,0 +1,33 @@
+#pragma once
+
+
+namespace SERVO {
+	class CPath
+	{
+	public:
+		CPath();
+		CPath(unsigned int nSiteId);
+		~CPath();
+
+	public:
+		void getDescription(std::string& strOut);
+		void serialize(CArchive& ar);
+		CPath* getPrev();
+		CPath* getNext();
+		void addPath(CPath* pPath);
+		CPath* getTailPath();
+		CPath* getHeadPath();
+		unsigned int getSiteID();
+		ULONGLONG getInTime();
+		void setOutTime(ULONGLONG time);
+		ULONGLONG getOutTime();
+
+	private:	
+		unsigned int m_nSiteID;
+		ULONGLONG m_timeIn;
+		ULONGLONG m_timeOut;
+		CPath* m_pPrev;
+		CPath* m_pNext;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CReadStep.cpp b/SourceCode/Bond/Servo/CReadStep.cpp
index 6c948de..7e05c00 100644
--- a/SourceCode/Bond/Servo/CReadStep.cpp
+++ b/SourceCode/Bond/Servo/CReadStep.cpp
@@ -1,6 +1,7 @@
 #include "stdafx.h"
 #include "CReadStep.h"
 #include "Common.h"
+#include "CEquipment.h"
 
 
 namespace SERVO {
@@ -19,6 +20,7 @@
 		m_hWorkThreadHandle = nullptr;
 		m_hReadSignalOn = ::CreateEvent(NULL, TRUE, FALSE, NULL);
 		m_hReadSignalOff = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+		m_nSignalType = 0;
 		m_nCurStep = 0;
 	}
 
@@ -38,13 +40,14 @@
 		m_nWriteSignalDev = dev;
 	}
 
-	void CReadStep::onReadSignal(BOOL bSignal)
+	void CReadStep::onReadSignal(int nSignalType)
 	{
 		Lock();
-		if (m_nCurStep == 0 && bSignal) {
+		m_nSignalType = nSignalType;
+		if (m_nCurStep == 0 && nSignalType != 0) {
 			SetEvent(m_hReadSignalOn);
 		}
-		else if (m_nCurStep == 3 && !bSignal) {
+		else if (m_nCurStep == 3 && nSignalType == 0) {
 			SetEvent(m_hReadSignalOff);
 		}
 
@@ -81,9 +84,8 @@
 				nextStep();
 				ASSERT(m_pCclink);
 				if (0 == onReadData()) {
-					if (m_listener.onEvent != nullptr) {
-						m_listener.onEvent(this, STEP_EVENT_READDATA, nullptr);
-					}
+					ASSERT(m_pEquipment);
+					m_pEquipment->onStepEvent(this, STEP_EVENT_READDATA);
 				}
 
 				// 2.给对方写ON
@@ -110,9 +112,8 @@
 				// 6.完成
 				nextStep();
 				if (0 == onComplete()) {
-					if (m_listener.onEvent != nullptr) {
-						m_listener.onEvent(this, STEP_EVENT_COMPLETE, nullptr);
-					}
+					ASSERT(m_pEquipment);
+					m_pEquipment->onStepEvent(this, STEP_EVENT_COMPLETE);
 				}
 			}
 		}
diff --git a/SourceCode/Bond/Servo/CReadStep.h b/SourceCode/Bond/Servo/CReadStep.h
index 2b0df3b..e5c88d2 100644
--- a/SourceCode/Bond/Servo/CReadStep.h
+++ b/SourceCode/Bond/Servo/CReadStep.h
@@ -12,7 +12,7 @@
 	public:
 		unsigned WorkingProc();
 		virtual void setWriteSignalDev(int dev);
-		virtual void onReadSignal(BOOL bSignal);
+		virtual void onReadSignal(int nSignalType);
 		virtual int onReadData();
 		virtual void init();
 		virtual void term();
@@ -28,6 +28,7 @@
 		HANDLE m_hWorkStop;
 		HANDLE m_hReadSignalOn;
 		HANDLE m_hReadSignalOff;
+		int m_nSignalType;
 		int m_nCurStep;
 		int m_nWriteSignalDev;			// 对方BIT地址
 	};
diff --git a/SourceCode/Bond/Servo/CStep.cpp b/SourceCode/Bond/Servo/CStep.cpp
index dbbf161..0f23732 100644
--- a/SourceCode/Bond/Servo/CStep.cpp
+++ b/SourceCode/Bond/Servo/CStep.cpp
@@ -6,7 +6,6 @@
 
 	CStep::CStep()
 	{
-		m_listener = {nullptr};
 		m_pCclink = nullptr;
 		InitializeCriticalSection(&m_criticalSection);
 	}
@@ -14,11 +13,6 @@
 	CStep::~CStep()
 	{
 		DeleteCriticalSection(&m_criticalSection);
-	}
-
-	void CStep::setListener(StepListener listener)
-	{
-		m_listener.onEvent = listener.onEvent;
 	}
 
 	void CStep::setCcLink(CCCLinkIEControl* pCcLink)
diff --git a/SourceCode/Bond/Servo/CStep.h b/SourceCode/Bond/Servo/CStep.h
index 95ce06b..aae469e 100644
--- a/SourceCode/Bond/Servo/CStep.h
+++ b/SourceCode/Bond/Servo/CStep.h
@@ -8,12 +8,6 @@
 #define STEP_EVENT_READDATA			0x01
 #define STEP_EVENT_COMPLETE			0x02
 
-	typedef std::function<void(void* pStep, int code, void* pData)> ONSTEPEVENT;
-	typedef struct _StepListener
-	{
-		ONSTEPEVENT			onEvent;
-	} StepListener;
-
 	class CEquipment;
 	class CStep
 	{
@@ -22,7 +16,6 @@
 		virtual ~CStep();
 
 	public:
-		void setListener(StepListener listener);
 		void setCcLink(CCCLinkIEControl* pCcLink);
 		void setEquipment(CEquipment* pEquipment);
 		CEquipment* getEquipment();
@@ -39,7 +32,6 @@
 		void convertString(const char* pszBuffer, int size, std::string& strOut);
 
 	protected:
-		StepListener m_listener;
 		StationIdentifier m_station;
 		std::string m_strName;
 		CEquipment* m_pEquipment;
diff --git a/SourceCode/Bond/Servo/CWriteStep.cpp b/SourceCode/Bond/Servo/CWriteStep.cpp
index 34dc627..6d79f55 100644
--- a/SourceCode/Bond/Servo/CWriteStep.cpp
+++ b/SourceCode/Bond/Servo/CWriteStep.cpp
@@ -1,6 +1,7 @@
 #include "stdafx.h"
 #include "CWriteStep.h"
 #include "Common.h"
+#include "CEquipment.h"
 
 
 namespace SERVO {
@@ -120,9 +121,8 @@
 				// 6.完成
 				nextStep();
 				if (0 == onComplete()) {
-					if (m_listener.onEvent != nullptr) {
-						m_listener.onEvent(this, STEP_EVENT_COMPLETE, nullptr);
-					}
+					ASSERT(m_pEquipment);
+					m_pEquipment->onStepEvent(this, STEP_EVENT_COMPLETE);
 				}
 			}
 		}
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index 3860990..84bc43e 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/SourceCode/Bond/Servo/Common.h
@@ -50,35 +50,111 @@
 #define BTN_ALARM_BKGND_PRESS			RGB(133, 203, 225)
 
 /* Equipment ID */
-#define EQ_ID_EFEM			1
-#define EQ_ID_Bonder1		2
-#define EQ_ID_Bonder2		3
-#define EQ_ID_LOADPORT1		4
-#define EQ_ID_LOADPORT2		5
-#define EQ_ID_LOADPORT3		6
-#define EQ_ID_LOADPORT4		7
-#define EQ_ID_FLIPER		8
-#define EQ_ID_VACUUMBAKE	9
-#define EQ_ID_ALIGNER		10
-#define EQ_ID_BAKE_COOLING	11
+#define EQ_ID_EFEM				1
+#define EQ_ID_Bonder1			2
+#define EQ_ID_Bonder2			3
+#define EQ_ID_LOADPORT1			4
+#define EQ_ID_LOADPORT2			5
+#define EQ_ID_LOADPORT3			6
+#define EQ_ID_LOADPORT4			7
+#define EQ_ID_FLIPER			8
+#define EQ_ID_VACUUMBAKE		9
+#define EQ_ID_ALIGNER			10
+#define EQ_ID_BAKE_COOLING		11
+#define EQ_ID_OPERATOR_REMOVE	999
 
 
 /* step name */
-#define STEP_MODE				_T("EQMode")
-#define STEP_STATUS				_T("EQStatus")
-#define STEP_ALARM_START		_T("EQAlarm")
-#define STEP_ALARM_BLOCK1		_T("EQAlarm1")
-#define STEP_ALARM_BLOCK2		_T("EQAlarm2")
-#define STEP_ALARM_BLOCK3		_T("EQAlarm3")
-#define STEP_ALARM_BLOCK4		_T("EQAlarm4")
-#define STEP_ALARM_BLOCK5		_T("EQAlarm5")
-#define STEP_PROCESS			_T("EQProcess")
-#define STEP_CIM_MODE_CHANGE	_T("EQCimModeChange")
-#define STEP_EQ_MODE_CHANGE		_T("EQModeChange")
-#define STEP_CIM_MESSAGE_CMD	_T("EQCimMessageCmd")
-#define STEP_CIM_MESSAGE_CLEAR	_T("EQCimMessageClear")
-#define STEP_DATETIME_SET_CMD	_T("EQDateTimeSetCmd")
-#define STEP_EQ_VCR_ENABLE		_T("EQVCREnable")
+#define STEP_MODE						_T("EQMode")
+#define STEP_STATUS						_T("EQStatus")
+#define STEP_ALARM_START				_T("EQAlarm")
+#define STEP_ALARM_BLOCK1				_T("EQAlarm1")
+#define STEP_ALARM_BLOCK2				_T("EQAlarm2")
+#define STEP_ALARM_BLOCK3				_T("EQAlarm3")
+#define STEP_ALARM_BLOCK4				_T("EQAlarm4")
+#define STEP_ALARM_BLOCK5				_T("EQAlarm5")
+#define STEP_PROCESS					_T("EQProcess")
+#define STEP_CIM_MODE_CHANGE			_T("EQCimModeChange")
+#define STEP_EQ_MODE_CHANGE				_T("EQModeChange")
+#define STEP_CIM_MESSAGE_CMD			_T("EQCimMessageCmd")
+#define STEP_CIM_MESSAGE_CLEAR			_T("EQCimMessageClear")
+#define STEP_DATETIME_SET_CMD			_T("EQDateTimeSetCmd")
+#define STEP_EQ_VCR_ENABLE				_T("EQVCREnable")
+#define STEP_EQ_PORT1_TYPE				_T("EQPort1Type")
+#define STEP_EQ_PORT1_MODE				_T("EQPort1Mode")
+#define STEP_EQ_PORT1_CASSETTE_TYPE		_T("EQPort1CassetteType")
+#define STEP_EQ_PORT1_TRANSFER_MODE		_T("EQPort1TransferMode")
+#define STEP_EQ_PORT1_ENABLE			_T("EQPort1Enable")
+#define STEP_EQ_PORT1_TYPE_ATUO			_T("EQPort1TypeAuto")
+#define STEP_EQ_PORT2_TYPE				_T("EQPort2Type")
+#define STEP_EQ_PORT2_MODE				_T("EQPort2Mode")
+#define STEP_EQ_PORT2_CASSETTE_TYPE		_T("EQPort2CassetteType")
+#define STEP_EQ_PORT2_TRANSFER_MODE		_T("EQPort2TransferMode")
+#define STEP_EQ_PORT2_ENABLE			_T("EQPort2Enable")
+#define STEP_EQ_PORT2_TYPE_ATUO			_T("EQPort2TypeAuto")
+#define STEP_EQ_PORT3_TYPE				_T("EQPort3Type")
+#define STEP_EQ_PORT3_MODE				_T("EQPort3Mode")
+#define STEP_EQ_PORT3_CASSETTE_TYPE		_T("EQPort3CassetteType")
+#define STEP_EQ_PORT3_TRANSFER_MODE		_T("EQPort3TransferMode")
+#define STEP_EQ_PORT3_ENABLE			_T("EQPort3Enable")
+#define STEP_EQ_PORT3_TYPE_ATUO			_T("EQPort3TypeAuto")
+#define STEP_EQ_PORT4_TYPE				_T("EQPort4Type")
+#define STEP_EQ_PORT4_MODE				_T("EQPort4Mode")
+#define STEP_EQ_PORT4_CASSETTE_TYPE		_T("EQPort4CassetteType")
+#define STEP_EQ_PORT4_TRANSFER_MODE		_T("EQPort4TransferMode")
+#define STEP_EQ_PORT4_ENABLE			_T("EQPort4Enable")
+#define STEP_EQ_PORT4_TYPE_ATUO			_T("EQPort4TypeAuto")
+#define STEP_EQ_P1_CASSETTE_EMPTY		_T("EQPort1CassetteEmpty")
+#define STEP_EQ_P1_CASSETTE_LOAD_EADY	_T("EQPort1CassetteLoadReady")
+#define STEP_EQ_P1_CASSETTE_LOADED		_T("EQPort1CassetteLoaded")
+#define STEP_EQ_P1_CASSETTE_INUSE		_T("EQPort1CassetteInUse")
+#define STEP_EQ_P1_CASSETTE_UNLOAD_EADY	_T("EQPort1CassetteUnloadReady")
+#define STEP_EQ_P1_CASSETTE_BLOCKED		_T("EQPort1CassetteBlocked")
+#define STEP_EQ_P2_CASSETTE_EMPTY		_T("EQPort2CassetteEmpty")
+#define STEP_EQ_P2_CASSETTE_LOAD_EADY	_T("EQPort2CassetteLoadReady")
+#define STEP_EQ_P2_CASSETTE_LOADED		_T("EQPort2CassetteLoaded")
+#define STEP_EQ_P2_CASSETTE_INUSE		_T("EQPort2CassetteInUse")
+#define STEP_EQ_P2_CASSETTE_UNLOAD_EADY	_T("EQPort2CassetteUnloadReady")
+#define STEP_EQ_P2_CASSETTE_BLOCKED		_T("EQPort2CassetteBlocked")
+#define STEP_EQ_P3_CASSETTE_EMPTY		_T("EQPort3CassetteEmpty")
+#define STEP_EQ_P3_CASSETTE_LOAD_EADY	_T("EQPort3CassetteLoadReady")
+#define STEP_EQ_P3_CASSETTE_LOADED		_T("EQPort3CassetteLoaded")
+#define STEP_EQ_P3_CASSETTE_INUSE		_T("EQPort3CassetteInUse")
+#define STEP_EQ_P3_CASSETTE_UNLOAD_EADY	_T("EQPort3CassetteUnloadReady")
+#define STEP_EQ_P3_CASSETTE_BLOCKED		_T("EQPort3CassetteBlocked")
+#define STEP_EQ_P4_CASSETTE_EMPTY		_T("EQPort4CassetteEmpty")
+#define STEP_EQ_P4_CASSETTE_LOAD_EADY	_T("EQPort4CassetteLoadReady")
+#define STEP_EQ_P4_CASSETTE_LOADED		_T("EQPort4CassetteLoaded")
+#define STEP_EQ_P4_CASSETTE_INUSE		_T("EQPort4CassetteInUse")
+#define STEP_EQ_P4_CASSETTE_UNLOAD_EADY	_T("EQPort4CassetteUnloadReady")
+#define STEP_EQ_P4_CASSETTE_BLOCKED		_T("EQPort4CassetteBlocked")
+
+
+/* Step ID */
+#define STEP_ID_PORT1_CASSETTIE_EMPTY			0x418
+#define STEP_ID_PORT1_CASSETTIE_LOAD_READY		0x420
+#define STEP_ID_PORT1_CASSETTIE_LOADED			0x428
+#define STEP_ID_PORT1_CASSETTIE_INUSE			0x430
+#define STEP_ID_PORT1_CASSETTIE_UNLOAD_READY	0x438
+#define STEP_ID_PORT1_CASSETTIE_BLOCKED			0x440
+#define STEP_ID_PORT2_CASSETTIE_EMPTY			0x419
+#define STEP_ID_PORT2_CASSETTIE_LOAD_READY		0x421
+#define STEP_ID_PORT2_CASSETTIE_LOADED			0x429
+#define STEP_ID_PORT2_CASSETTIE_INUSE			0x431
+#define STEP_ID_PORT2_CASSETTIE_UNLOAD_READY	0x439
+#define STEP_ID_PORT2_CASSETTIE_BLOCKED			0x441
+#define STEP_ID_PORT3_CASSETTIE_EMPTY			0x41a
+#define STEP_ID_PORT3_CASSETTIE_LOAD_READY		0x422
+#define STEP_ID_PORT3_CASSETTIE_LOADED			0x42a
+#define STEP_ID_PORT3_CASSETTIE_INUSE			0x432
+#define STEP_ID_PORT3_CASSETTIE_UNLOAD_READY	0x43a
+#define STEP_ID_PORT3_CASSETTIE_BLOCKED			0x442
+#define STEP_ID_PORT4_CASSETTIE_EMPTY			0x41b
+#define STEP_ID_PORT4_CASSETTIE_LOAD_READY		0x423
+#define STEP_ID_PORT4_CASSETTIE_LOADED			0x42b
+#define STEP_ID_PORT4_CASSETTIE_INUSE			0x433
+#define STEP_ID_PORT4_CASSETTIE_UNLOAD_READY	0x43b
+#define STEP_ID_PORT4_CASSETTIE_BLOCKED			0x443
 
 
 /* base alarm */
@@ -103,4 +179,43 @@
 #define FLOW_TEST					0x1000
 #define FLOW_SIGNAL					0x1001
 #define FLOW_DATA					0x1002
-#define FLOW_MOVE_MATERIAL			0x1003
\ No newline at end of file
+#define FLOW_MOVE_MATERIAL			0x1003
+
+
+/* Port Status */
+#define PORT_LOAD_READY				1
+#define PORT_LOADED					2
+#define PORT_INUSE					3
+#define PORT_LOAD_COMPLETE			PORT_INUSE
+#define PORT_UNLOAD_READY			4
+#define PORT_UNLOAD_REQUEST			PORT_RNLOAD_READY
+#define PORT_EMPTY					5
+#define PORT_UNLOAD_COMPLETE		PORT_EMPTY
+#define PORT_BLOCKED				6
+
+
+/* Loading Cassette Type */
+#define PORT_LOADING_CASSETTE_ACTUAL	1
+#define PORT_LOADING_CASSETTE_EMPTY		2
+
+
+/* Q-Time flag */
+#define Q_TIME_NORMAL					1
+#define Q_TIME_OVER						2
+
+
+/* m_nCassetteMappingState */
+#define CASSETTE_MAPPING_USE			1
+#define CASSETTE_MAPPING_NOT_USE		2
+
+
+/* Cassette Status */
+#define CASSETTE_NO_EXIST				1
+#define CASSETTE_WAITING_DATA			2
+#define CASSETTE_WAITING_START			3
+#define CASSETTE_WAITING_PROCCESSING	4
+#define CASSETTE_IN_PROCCESSING			5
+#define CASSETTE_PROCCESS_PAUSED		6
+#define CASSETTE_PROCCESS_COMPLETED		7
+
+
diff --git a/SourceCode/Bond/Servo/EqsGraphWnd.cpp b/SourceCode/Bond/Servo/EqsGraphWnd.cpp
index 50d569d..466ca8e 100644
--- a/SourceCode/Bond/Servo/EqsGraphWnd.cpp
+++ b/SourceCode/Bond/Servo/EqsGraphWnd.cpp
@@ -35,14 +35,7 @@
 	m_hWnd = NULL;
 	m_crFrame = GetSysColor(COLOR_WINDOWFRAME);
 	m_crBkgnd = RGB(255, 255, 255);
-	m_listener.onConnectPin = nullptr;
-	m_listener.onCheckConnectPin = nullptr;
-	m_listener.onDisconnectPin = nullptr;
-	m_listener.onDeleteEqItem = nullptr;
-	m_listener.onEqItemPosChanged = nullptr;
-	m_listener.onDblckEqItem = nullptr;
-	m_listener.onRclickEqItem = nullptr;
-	m_listener.onSelectEqItem = nullptr;
+	m_listener = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
 	m_crItemBackground[0] = RGB(218, 218, 218);
 	m_crItemBackground[1] = RGB(193, 208, 227);
 	m_crItemFrame[0] = RGB(128, 128, 128);
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index a757adc..9ef4836 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -105,64 +105,50 @@
 		notifyPtr(RX_CODE_EQ_ALIVE, pEquipment);
 
 	};
-	masterListener.onEqStepEvent = [&](SERVO::CStep* pStep, int code, void* pData) -> void {
-		if (code == STEP_EVENT_READDATA) {
-			LOGI("<CModel>onEqStepEvent,数据变化:%s(%s, 0x%x).\n", pStep->getEquipment()->getName().c_str(),
-				pStep->getName().c_str(), pData);
-			notifyPtr(RX_CODE_STEP_EVENT_READDATA, pStep);
-			
-			// 处理警告信息
-			if (isAlarmStep(pStep)) {
-				// 保存到数据库
-				AlarmManager& alarmManager = AlarmManager::getInstance();
-				std::string strAlarmText;
-				SERVO::CEquipment* pEquipment = pStep->getEquipment();
-				SERVO::CEqAlarmStep* pEqAlarmStep = (SERVO::CEqAlarmStep*)pStep;
-				const AlarmInfo* pAlarmInfo = alarmManager.getAlarmInfoByID(pEqAlarmStep->getAlarmId());
-				if (pAlarmInfo != nullptr) {
-					strAlarmText = pAlarmInfo->strAlarmText;
-				}
-				int state = pEqAlarmStep->getAlarmState();
-				if (state == 1) {
-					AlarmData alarmData;
-					alarmData.nId = pEqAlarmStep->getAlarmId();
-					alarmData.nSeverityLevel = pEqAlarmStep->getAlarmLevel();
-					alarmData.nDeviceId = pEqAlarmStep->getEquipment()->getID();
-					alarmData.nUnitId = pEqAlarmStep->getUnitId();
-					alarmData.strDeviceName = alarmManager.getDeviceNameById(alarmData.nDeviceId);
-					alarmData.strUnitName = alarmManager.getUnitNameById(alarmData.nDeviceId, alarmData.nUnitId);
-					alarmData.strStartTime = CToolUnits::timeToString2(CToolUnits::getTimestamp());
-					alarmData.strEndTime = "";
-
-					const AlarmInfo* alarmInfo = alarmManager.getAlarmInfoByID(alarmData.nId);
-					alarmData.strDescription = alarmInfo != nullptr ? alarmInfo->strAlarmText : "";
-	
-					int nAlarmEventId = 0;
-					bool result = alarmManager.addAlarm(alarmData, nAlarmEventId);
-					if (result) {
-						LOGI("<CModel> Alarm added successfully!");
-					}
-					else {
-						LOGE("<CModel> Failed to add alarm.");
-					}
-
-					notifyPtr(RX_CODE_ALARM_SET, pStep);					
-				}
-				else {
-					alarmManager.clearAlarmByAttributes(pEqAlarmStep->getAlarmId(),
-						pEqAlarmStep->getEquipment()->getID(),
-						pEqAlarmStep->getUnitId(),
-						CToolUnits::getCurrentTimeString());
-					notifyPtr(RX_CODE_ALARM_CLEAR, pStep);
-				}
-
-				m_hsmsPassive.requestAlarmReport(pEqAlarmStep->getAlarmState(),
-					pEquipment->getBaseAlarmId() + pEqAlarmStep->getAlarmId(),
-					strAlarmText.c_str());
-			}
+	masterListener.onEqAlarm = [&](void* pMaster, SERVO::CEquipment* pEquipment, int state, int alarmId, int unitId, int level) -> void {
+		AlarmManager& alarmManager = AlarmManager::getInstance();
+		std::string strAlarmText;
+		const AlarmInfo* pAlarmInfo = alarmManager.getAlarmInfoByID(alarmId);
+		if (pAlarmInfo != nullptr) {
+			strAlarmText = pAlarmInfo->strAlarmText;
 		}
-	};
+		if (state == 1) {
+			AlarmData alarmData;
+			alarmData.nId = alarmId;
+			alarmData.nSeverityLevel = level;
+			alarmData.nDeviceId = pEquipment->getID();
+			alarmData.nUnitId = unitId;
+			alarmData.strDeviceName = alarmManager.getDeviceNameById(alarmData.nDeviceId);
+			alarmData.strUnitName = alarmManager.getUnitNameById(alarmData.nDeviceId, alarmData.nUnitId);
+			alarmData.strStartTime = CToolUnits::timeToString2(CToolUnits::getTimestamp());
+			alarmData.strEndTime = "";
 
+			const AlarmInfo* alarmInfo = alarmManager.getAlarmInfoByID(alarmData.nId);
+			alarmData.strDescription = alarmInfo != nullptr ? alarmInfo->strAlarmText : "";
+
+			int nAlarmEventId = 0;
+			bool result = alarmManager.addAlarm(alarmData, nAlarmEventId);
+			if (result) {
+				LOGI("<CModel> Alarm added successfully!");
+			}
+			else {
+				LOGE("<CModel> Failed to add alarm.");
+			}
+
+			notify(RX_CODE_ALARM_SET);
+		}
+		else {
+			alarmManager.clearAlarmByAttributes(alarmId,
+				pEquipment->getID(),
+				unitId,
+				CToolUnits::getCurrentTimeString());
+			notify(RX_CODE_ALARM_CLEAR);
+		}
+
+		m_hsmsPassive.requestAlarmReport(state,
+			pEquipment->getBaseAlarmId() + alarmId,
+			strAlarmText.c_str());
+	};
 	m_master.setListener(masterListener);
 
 
@@ -395,9 +381,4 @@
 	}
 
 	return 0;
-}
-
-bool CModel::isAlarmStep(SERVO::CStep* pStep)
-{
-	return CToolUnits::startsWith(pStep->getName(), STEP_ALARM_START);
 }
diff --git a/SourceCode/Bond/Servo/Model.h b/SourceCode/Bond/Servo/Model.h
index 3b92364..6e2655c 100644
--- a/SourceCode/Bond/Servo/Model.h
+++ b/SourceCode/Bond/Servo/Model.h
@@ -14,7 +14,6 @@
 	void setWorkDir(const char* pszWorkDir);
 	int init();
 	int term();
-	bool isAlarmStep(SERVO::CStep* pStep);
 
 public:
 	int notify(int code);
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index cf09ebc..b533912 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 1278d72..36a12e3 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -204,6 +204,7 @@
     <ClInclude Include="CAttributeVector.h" />
     <ClInclude Include="CBakeCooling.h" />
     <ClInclude Include="CBonder.h" />
+    <ClInclude Include="CEqCassetteTransferStateStep.h" />
     <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h" />
     <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h" />
     <ClInclude Include="CEqAlarmStep.h" />
@@ -213,11 +214,17 @@
     <ClInclude Include="CEqDateTimeSetCmdStep.h" />
     <ClInclude Include="CEqModeChangeStep.h" />
     <ClInclude Include="CEqModeStep.h" />
+    <ClInclude Include="CEqPortChangeStep.h" />
     <ClInclude Include="CEqProcessStep.h" />
+    <ClInclude Include="CEqReadIntStep.h" />
     <ClInclude Include="CEqStatusStep.h" />
+    <ClInclude Include="CEquipmentPage1.h" />
+    <ClInclude Include="CEquipmentPage2.h" />
     <ClInclude Include="CEqVCREnableStep.h" />
     <ClInclude Include="CFliper.h" />
     <ClInclude Include="CGlass.h" />
+    <ClInclude Include="CHMPropertyDlg.h" />
+    <ClInclude Include="CHMPropertyPage.h" />
     <ClInclude Include="CLoadPort.h" />
     <ClInclude Include="CMeasurement.h" />
     <ClInclude Include="ColorTransfer.h" />
@@ -226,6 +233,7 @@
     <ClInclude Include="CPanelAttributes.h" />
     <ClInclude Include="CPanelEquipment.h" />
     <ClInclude Include="CPanelMaster.h" />
+    <ClInclude Include="CPath.h" />
     <ClInclude Include="CPin.h" />
     <ClInclude Include="CReadStep.h" />
     <ClInclude Include="CSample.h" />
@@ -272,6 +280,7 @@
     <ClCompile Include="CAttributeVector.cpp" />
     <ClCompile Include="CBakeCooling.cpp" />
     <ClCompile Include="CBonder.cpp" />
+    <ClCompile Include="CEqCassetteTransferStateStep.cpp" />
     <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp" />
     <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp" />
     <ClCompile Include="CEqAlarmStep.cpp" />
@@ -281,11 +290,17 @@
     <ClCompile Include="CEqDateTimeSetCmdStep.cpp" />
     <ClCompile Include="CEqModeChangeStep.cpp" />
     <ClCompile Include="CEqModeStep.cpp" />
+    <ClCompile Include="CEqPortChangeStep.cpp" />
     <ClCompile Include="CEqProcessStep.cpp" />
+    <ClCompile Include="CEqReadIntStep.cpp" />
     <ClCompile Include="CEqStatusStep.cpp" />
+    <ClCompile Include="CEquipmentPage1.cpp" />
+    <ClCompile Include="CEquipmentPage2.cpp" />
     <ClCompile Include="CEqVCREnableStep.cpp" />
     <ClCompile Include="CFliper.cpp" />
     <ClCompile Include="CGlass.cpp" />
+    <ClCompile Include="CHMPropertyDlg.cpp" />
+    <ClCompile Include="CHMPropertyPage.cpp" />
     <ClCompile Include="CLoadPort.cpp" />
     <ClCompile Include="CMeasurement.cpp" />
     <ClCompile Include="ColorTransfer.cpp" />
@@ -294,6 +309,7 @@
     <ClCompile Include="CPanelAttributes.cpp" />
     <ClCompile Include="CPanelEquipment.cpp" />
     <ClCompile Include="CPanelMaster.cpp" />
+    <ClCompile Include="CPath.cpp" />
     <ClCompile Include="CPin.cpp" />
     <ClCompile Include="CReadStep.cpp" />
     <ClCompile Include="CSample.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index ef39ee3..00faaa0 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -74,6 +74,14 @@
     <ClCompile Include="CPageGraph1.cpp" />
     <ClCompile Include="CPageGraph2.cpp" />
     <ClCompile Include="CGlass.cpp" />
+    <ClCompile Include="CPath.cpp" />
+    <ClCompile Include="CEquipmentPage1.cpp" />
+    <ClCompile Include="CEquipmentPage2.cpp" />
+    <ClCompile Include="CHMPropertyPage.cpp" />
+    <ClCompile Include="CHMPropertyDlg.cpp" />
+    <ClCompile Include="CEqPortChangeStep.cpp" />
+    <ClCompile Include="CEqReadIntStep.cpp" />
+    <ClCompile Include="CEqCassetteTransferStateStep.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -146,6 +154,14 @@
     <ClInclude Include="CPageGraph1.h" />
     <ClInclude Include="CPageGraph2.h" />
     <ClInclude Include="CGlass.h" />
+    <ClInclude Include="CPath.h" />
+    <ClInclude Include="CEquipmentPage1.h" />
+    <ClInclude Include="CEquipmentPage2.h" />
+    <ClInclude Include="CHMPropertyPage.h" />
+    <ClInclude Include="CHMPropertyDlg.h" />
+    <ClInclude Include="CEqPortChangeStep.h" />
+    <ClInclude Include="CEqReadIntStep.h" />
+    <ClInclude Include="CEqCassetteTransferStateStep.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index 5d96844..28bbd95 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -218,7 +218,7 @@
 	SetIcon(m_hIcon, FALSE);		// 设置小图标
 
 
-									// 菜单
+	// 菜单
 	CMenu menu;
 	menu.LoadMenu(IDR_MENU_APP);
 	SetMenu(&menu);
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 3f54a12..a676416 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3