From cacea2da59a3acd73f3161d819a10e0060762616 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期二, 06 五月 2025 14:54:13 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/Servo/CPagePortProperty.h                                         |   40 
 SourceCode/Bond/Servo/CReadStep.h                                                 |    8 
 SourceCode/Bond/Servo/CJobDataS.cpp                                               |  330 ++++
 SourceCode/Bond/Servo/CEFEM.h                                                     |   11 
 SourceCode/Bond/Servo/CRecipesManager.cpp                                         |  187 ++
 SourceCode/Bond/Servo/ToolUnits.cpp                                               |   13 
 SourceCode/Bond/Servo/Servo.rc                                                    |    0 
 SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h                         |    2 
 SourceCode/Bond/Servo/CEqReadStep.cpp                                             |   82 +
 SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp                                    |  116 +
 SourceCode/Bond/Servo/CBonder.h                                                   |    8 
 SourceCode/Bond/Servo/CEqVcrEventStep.cpp                                         |   90 +
 SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.h                                |   29 
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5(4).xlsx                   |    0 
 SourceCode/Bond/Servo/CJobDataC.cpp                                               |   66 
 SourceCode/Bond/Servo/CWriteStep.cpp                                              |   10 
 SourceCode/Bond/Servo/CJobDataB.cpp                                               |   46 
 SourceCode/Bond/Servo/CLoadPort.cpp                                               |  430 +++++
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx                      |    0 
 SourceCode/Bond/Servo/CRecipeList.h                                               |   27 
 SourceCode/Bond/Servo/CEqWriteStep.h                                              |   32 
 SourceCode/Bond/Servo/Servo.vcxproj.filters                                       |   34 
 SourceCode/Bond/Servo/CJobDataA.cpp                                               |  157 ++
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx                      |    0 
 SourceCode/Bond/Servo/CJobDataB.h                                                 |   25 
 SourceCode/Bond/Servo/CVcrEventReport.h                                           |   32 
 SourceCode/Bond/Servo/CEFEM.cpp                                                   |  272 +++
 SourceCode/Bond/Servo/CRecipeList.cpp                                             |   81 +
 SourceCode/Bond/Servo/CVcrEventReport.cpp                                         |  119 +
 SourceCode/Bond/Servo/CEquipment.h                                                |   42 
 SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.h                                    |   27 
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5(5).xlsx                   |    0 
 SourceCode/Bond/Servo/CPagePortProperty.cpp                                       |  139 +
 SourceCode/Bond/Servo/Servo.vcxproj                                               |   30 
 SourceCode/Bond/Servo/AlarmManager.cpp                                            |   11 
 .gitignore                                                                        |    2 
 SourceCode/Bond/Servo/resource.h                                                  |    0 
 SourceCode/Bond/Servo/CEqVcrEventStep.h                                           |   27 
 SourceCode/Bond/Servo/CJobDataS.h                                                 |  103 +
 SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.cpp                                  |   49 
 Document/~$WIN_EAS_Equipment_Communication_Specification(CC-LINK)_v3.1(翻译结果).docx |    0 
 SourceCode/Bond/Servo/CMaster.h                                                   |   12 
 SourceCode/Bond/Servo/CStep.h                                                     |    3 
 SourceCode/Bond/Servo/CEqWriteStep.cpp                                            |   66 
 SourceCode/Bond/Servo/CEquipment.cpp                                              |  244 ++
 SourceCode/Bond/Servo/CEqJobEventStep.h                                           |   26 
 SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.cpp                              |   86 +
 SourceCode/Bond/Servo/CMaster.cpp                                                 |  641 +------
 SourceCode/Bond/Servo/CEqReadIntStep.cpp                                          |    6 
 SourceCode/Bond/Servo/CStep.cpp                                                   |   11 
 SourceCode/Bond/Servo/ToolUnits.h                                                 |    1 
 SourceCode/Bond/Servo/CEqReadStep.h                                               |   35 
 SourceCode/Bond/Servo/CPageGraph2.cpp                                             |   91 +
 SourceCode/Bond/Servo/CReadStep.cpp                                               |   36 
 SourceCode/Bond/Servo/CPageCassetteCtrlCmd.h                                      |   36 
 Document/ESWIN_EAS_Equipment_Communication_Specification(CC-LINK)_v3.1(翻译结果).docx |    0 
 SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h                       |    4 
 SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp                     |    8 
 SourceCode/Bond/Servo/CLoadPort.h                                                 |   36 
 SourceCode/Bond/Servo/Model.cpp                                                   |    3 
 SourceCode/Bond/Servo/CPageGraph1.cpp                                             |   33 
 SourceCode/Bond/Servo/CRecipesManager.h                                           |   42 
 SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp                       |    4 
 SourceCode/Bond/Servo/CEqJobEventStep.cpp                                         |   86 +
 SourceCode/Bond/Servo/CJobDataA.h                                                 |   35 
 SourceCode/Bond/Servo/CJobDataC.h                                                 |   31 
 SourceCode/Bond/Servo/LogDlg.cpp                                                  |    2 
 Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.4(1).xlsx                   |    0 
 SourceCode/Bond/Servo/CBonder.cpp                                                 |  214 ++
 SourceCode/Bond/Servo/Common.h                                                    |  127 +
 70 files changed, 3,960 insertions(+), 636 deletions(-)

diff --git a/.gitignore b/.gitignore
index 8681c35..f1a3d18 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,3 +50,5 @@
 SourceCode/Bond/x64/Debug/ServoConfiguration.ini
 *.iobj
 SourceCode/Bond/x64/Debug/Backups/
+Document/鍏变韩鏂囦欢澶�/
+Document/鍏变韩鏂囦欢澶�.rar
diff --git a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx
new file mode 100644
index 0000000..fe5bd01
--- /dev/null
+++ b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.2.xlsx
Binary files differ
diff --git "a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.4\0501\051.xlsx" "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.4\0501\051.xlsx"
new file mode 100644
index 0000000..907bfd3
--- /dev/null
+++ "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.4\0501\051.xlsx"
Binary files differ
diff --git "a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0504\051.xlsx" "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0504\051.xlsx"
new file mode 100644
index 0000000..0a62420
--- /dev/null
+++ "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0504\051.xlsx"
Binary files differ
diff --git "a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0505\051.xlsx" "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0505\051.xlsx"
new file mode 100644
index 0000000..35d3f51
--- /dev/null
+++ "b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5\0505\051.xlsx"
Binary files differ
diff --git a/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx
new file mode 100644
index 0000000..ca31dfe
--- /dev/null
+++ b/Document/ESWIN_EAS_Bonder_Inline_Mapping_Address_v1.1.5.xlsx
Binary files differ
diff --git "a/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx" "b/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
new file mode 100644
index 0000000..a920e8a
--- /dev/null
+++ "b/Document/ESWIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
Binary files differ
diff --git "a/Document/~$WIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx" "b/Document/~$WIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
new file mode 100644
index 0000000..ac59be7
--- /dev/null
+++ "b/Document/~$WIN_EAS_Equipment_Communication_Specification\050CC-LINK\051_v3.1\050\347\277\273\350\257\221\347\273\223\346\236\234\051.docx"
Binary files differ
diff --git a/SourceCode/Bond/Servo/AlarmManager.cpp b/SourceCode/Bond/Servo/AlarmManager.cpp
index 6c30cfc..0a4acf9 100644
--- a/SourceCode/Bond/Servo/AlarmManager.cpp
+++ b/SourceCode/Bond/Servo/AlarmManager.cpp
@@ -215,6 +215,17 @@
     
         return result;
     #else
+        for (AlarmDataMap::const_iterator it = m_mapCache.begin(); it != m_mapCache.end(); ++it) {
+            const AlarmData& alarm = it->second;
+            if (alarm.nId == alarmData.nId &&
+                alarm.nDeviceId == alarmData.nDeviceId &&
+                alarm.nUnitId == alarmData.nUnitId) {
+
+                alarmEventId = it->first;
+                return false;
+            }
+        }
+
         // 构建插入查询并使用 RETURNING 获取插入后的 alarm_event_id
         std::ostringstream query;
         query << "INSERT INTO alarms (id, severity_level, device_id, unit_id, description, start_time, end_time) "
diff --git a/SourceCode/Bond/Servo/CBonder.cpp b/SourceCode/Bond/Servo/CBonder.cpp
index 1bb185f..5ce0745 100644
--- a/SourceCode/Bond/Servo/CBonder.cpp
+++ b/SourceCode/Bond/Servo/CBonder.cpp
@@ -5,7 +5,7 @@
 namespace SERVO {
 	CBonder::CBonder() : CEquipment()
 	{
-
+		m_nIndex = 0;
 	}
 
 	CBonder::~CBonder()
@@ -38,6 +38,208 @@
 		addPin(SERVO::PinType::OUTPUT, _T("Out"));
 	}
 
+	void CBonder::initSteps()
+	{
+		CEquipment::initSteps();
+
+
+		{
+			// eq mode
+			CEqModeStep* pStep = new CEqModeStep();
+			pStep->setName(STEP_MODE);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x350 : 0x650);
+			pStep->setModeDev(m_nIndex == 0 ? 0x9d7d : 0xdd7d);
+			if (addStep(STEP_ID_EQMODE_CHANGED, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq status
+			CEqStatusStep* pStep = new CEqStatusStep();
+			pStep->setName(STEP_STATUS);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x351 : 0x651);
+			pStep->setStatusDev(m_nIndex == 0 ? 0x9d59 : 0xdd59);
+			if (addStep(STEP_ID_EQSTATUS_CHANGED, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Eq Alarm
+			static char* pszName[] = { STEP_ALARM_BLOCK1, STEP_ALARM_BLOCK2, STEP_ALARM_BLOCK3, STEP_ALARM_BLOCK4, STEP_ALARM_BLOCK5 };
+			static int dev[2][5] = { { 0x9f0e , 0x9f3b, 0x9f68, 0x9f95, 0x9fc2 },
+				{ 0xdf0e , 0xdf3b, 0xdf68, 0xdf95, 0xdfc2 } };
+			static int writeSignalDev[2][5] = { { 0x352, 0x353, 0x354, 0x355, 0x356 },
+				{ 0x652, 0x653, 0x654, 0x655, 0x656 } };
+			static int addr[] = { STEP_ID_EQALARM1, STEP_ID_EQALARM2, STEP_ID_EQALARM3, STEP_ID_EQALARM4, STEP_ID_EQALARM5 };
+
+			for (int i = 0; i < 5; i++) {
+				CEqAlarmStep* pStep = new CEqAlarmStep();
+				pStep->setName(pszName[i]);
+				pStep->setWriteSignalDev(writeSignalDev[m_nIndex][i]);
+				pStep->setAlarmDev(dev[m_nIndex][i]);
+				if (addStep(addr[i], pStep) != 0) {
+					delete pStep;
+				}
+			}
+
+		}
+
+		{
+			// eq process
+			CEqProcessStep* pStep = new CEqProcessStep();
+			pStep->setName(STEP_PROCESS);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x357 : 0x657);
+			pStep->setProcessDev(m_nIndex == 0 ? 0xab55 : 0xeb55);
+			if (addStep(STEP_ID_PROCESS_DATA_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq cim mode change
+			CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
+			pStep->setName(STEP_CIM_MODE_CHANGE);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x370 : 0x670);
+			pStep->setCimModeDev(m_nIndex == 0 ? 0x965 : 0x12b5);
+			if (addStep(STEP_ID_CIMMODE_CHANGED_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq cim message cmd
+			CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
+			pStep->setName(STEP_CIM_MESSAGE_CMD);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x371 : 0x671);
+			pStep->setCimMessageDev(m_nIndex == 0 ? 0x950 : 0x12a0);
+			if (addStep(STEP_ID_CIM_MSG_SET_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq current recipe change
+			CEqCurrentRecipeChangeStep* pStep = new CEqCurrentRecipeChangeStep();
+			pStep->setName(STEP_EQ_RURRENT_RECIPE_CHANGE);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x348 : 0x648);
+			pStep->setDataDev(m_nIndex == 0 ? 0xa850 : 0xe850);
+			if (addStep(STEP_ID_CURRENT_RECIPE_CHANGE_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// CIM Message Confirm
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, m_nIndex == 0 ? 0x9d80 : 0xdd80);
+			pStep->setName(STEP_EQ_CIM_MESSAGE_CONFIRM);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x359 : 0x659);
+			if (addStep(STEP_ID_CIM_MSG_CONFIRM_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			CEqCimMessageClearStep* pStep = new CEqCimMessageClearStep();
+			pStep->setName(STEP_CIM_MESSAGE_CLEAR);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x372 : 0x672);
+			pStep->setClearCimMessageDev(m_nIndex == 0 ? 0x963 : 0x12b3);
+			if (addStep(STEP_ID_CIM_MSG_CLEAR_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+
+		{
+			CEqDateTimeSetCmdStep* pStep = new CEqDateTimeSetCmdStep();
+			pStep->setName(STEP_DATETIME_SET_CMD);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x373 : 0x673);
+			pStep->setDateTimeDev(m_nIndex == 0 ? 0x966 : 0x12b6);
+			if (addStep(STEP_ID_DATETIME_SET_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			CEqModeChangeStep* pStep = new CEqModeChangeStep();
+			pStep->setName(STEP_EQ_MODE_CHANGE);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x375 : 0x675);
+			pStep->setEqModeDev(m_nIndex == 0 ? 0x96E : 0x12be);
+			if (addStep(STEP_ID_EQMODE_CHANGE_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// 请求主配方列表的step
+			CEqWriteStep* pStep = new CEqWriteStep();
+			pStep->setName(STEP_EQ_MASTER_RECIPE_LIST_REQ);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x366 : 0x666);
+			pStep->setDataDev(m_nIndex == 0 ? 0x125a : 0x1baa);
+			if (addStep(STEP_ID_MASTER_RECIPE_LIST_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// master recipe list report
+			CEqReadStep* pStep = new CEqReadStep(m_nIndex == 0 ? 0xa955 : 0xe955, 255 * 2,
+				[&](int code, const char* pszData, size_t size) -> int {
+					if (code == ROK && pszData != nullptr && size > 0) {
+						// 此处解释配方数据
+						short ret = decodeRecipeListReport(pszData, size);
+						pStep->setReturnCode(ret);
+					}
+					pStep->setReturnCode(MRLRC_OK);
+					return -1;
+				});
+			pStep->setName(STEP_EQ_MASTER_RECIPE_LIST);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x34b : 0x64b);
+			pStep->setReturnDev(m_nIndex == 0 ? 0x126d : 0x1bbd);
+			if (addStep(STEP_ID_MASTER_RECIPE_LIST_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			CEqJobEventStep* pStep = new CEqJobEventStep();
+			pStep->setName(STEP_EQ_RECEIVED_JOB_UPS1);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x300 : 0x600);
+			pStep->setJobDataDev(m_nIndex == 0 ? 0x8c90 : 0xcc90);
+			if (addStep(STEP_ID_RECIVE_JOB_UPS1, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqJobEventStep* pStep = new CEqJobEventStep();
+			pStep->setName(STEP_EQ_RECEIVED_JOB_UPS2);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x301 : 0x601);
+			pStep->setJobDataDev(m_nIndex == 0 ? 0x8dd0 : 0xcdd0);
+			if (addStep(STEP_ID_RECIVE_JOB_UPS2, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqJobEventStep* pStep = new CEqJobEventStep();
+			pStep->setName(STEP_EQ_SENT_OUT_JOB_DOWNS1);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x310 : 0x610);
+			pStep->setJobDataDev(m_nIndex == 0 ? 0x8000 : 0xc000);
+			if (addStep(STEP_ID_SENT_OUT_JOB_DOWNS1, pStep) != 0) {
+				delete pStep;
+			}
+		}
+		{
+			CEqJobEventStep* pStep = new CEqJobEventStep();
+			pStep->setName(STEP_EQ_SENT_OUT_JOB_DOWNS2);
+			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x311 : 0x611);
+			pStep->setJobDataDev(m_nIndex == 0 ? 0x8140 : 0xc140);
+			if (addStep(STEP_ID_SENT_OUT_JOB_DOWNS2, pStep) != 0) {
+				delete pStep;
+			}
+		}
+	}
+
 	void CBonder::onTimer(UINT nTimerid)
 	{
 		CEquipment::onTimer(nTimerid);
@@ -67,4 +269,14 @@
 
 		return m_glassList.empty();
 	}
+
+	void CBonder::setIndex(unsigned int index)
+	{
+		m_nIndex = index;
+	}
+
+	unsigned int CBonder::getIndex()
+	{
+		return m_nIndex;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CBonder.h b/SourceCode/Bond/Servo/CBonder.h
index e6f9843..04785d3 100644
--- a/SourceCode/Bond/Servo/CBonder.h
+++ b/SourceCode/Bond/Servo/CBonder.h
@@ -15,11 +15,19 @@
         virtual void init();
         virtual void term();
         virtual void initPins();
+        virtual void initSteps();
         virtual void onTimer(UINT nTimerid);
         virtual void serialize(CArchive& ar);
         virtual void getAttributeVector(CAttributeVector& attrubutes);
         virtual int recvIntent(CPin* pPin, CIntent* pIntent);
         virtual BOOL glassWillArrive(CGlass* pGlass);
+
+    public:
+        void setIndex(unsigned int index);
+        unsigned int getIndex();
+
+    private:
+        unsigned int m_nIndex;
     };
 }
 
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp
index baad0d5..8315cc3 100644
--- a/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp
@@ -80,7 +80,7 @@
     return 0; // 校验通过
 }
 
-int CCCLinkIEControl::ReadData2(const StationIdentifier& station, DeviceType enDevType, short devNo, short size, void* pData)
+int CCCLinkIEControl::ReadData2(const StationIdentifier& station, DeviceType enDevType, long devNo, long size, void* pData)
 {
     // 验证站点参数和数据有效性
     int nRet = ValidateStationAndSize(station, size);
@@ -93,7 +93,7 @@
     {
         std::lock_guard<std::mutex> lock(m_mtx);
         const short nDevType = CalculateDeviceType(station, enDevType);
-        nRet = mdReceive(m_nPath, CombineStation(station), nDevType, devNo, &size, pData);
+        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, devNo, &size, pData);
     }
 
     if (nRet != 0) {
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h
index 5d92f9e..60f4e7d 100644
--- a/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h
@@ -59,7 +59,7 @@
     // 读取LED状态
     int ReadLedStatus(LedStatus& outLedStatus);
 
-    int ReadData2(const StationIdentifier& station, DeviceType enDevType, short devNo, short size, void* pData);
+    int ReadData2(const StationIdentifier& station, DeviceType enDevType, long devNo, long size, void* pData);
 
 private:
     static CCLinkIEControlMode ConvertToCCLinkIEControlMode(short nMode);
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
index 141634c..7bc469d 100644
--- a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
@@ -442,7 +442,7 @@
 }
 
 // 通用读数据
-int CPerformanceMelsec::ReadData(const StationIdentifier& station, const short nDevType, const short nDevNo, short nSize, std::vector<short>& vecData) {
+int CPerformanceMelsec::ReadData(const StationIdentifier& station, const long nDevType, const long nDevNo, long nSize, std::vector<short>& vecData) {
     // 验证站点参数和数据有效性
     int nRet = ValidateStationAndSize(station, nSize);
     if (nRet != 0) {
@@ -459,7 +459,7 @@
         std::lock_guard<std::mutex> lock(m_mtx);
         short* pData = vecData.data();
         nSize *= sizeof(short);
-        nRet = mdReceive(m_nPath, CombineStation(station), nDevType, nDevNo, &nSize, pData);
+        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, (long)(unsigned short)nDevNo, &nSize, pData);
     }
 
     if (nRet != 0) {
@@ -559,7 +559,7 @@
 }
 
 // 通用写数据
-int CPerformanceMelsec::WriteData(const StationIdentifier& station, const short nDevType, const short nDevNo, short nSize, short* pData) {
+int CPerformanceMelsec::WriteData(const StationIdentifier& station, const long nDevType, const long nDevNo, long nSize, short* pData) {
     // 验证站点参数
     int nRet = ValidateStation(station);
     if (nRet != 0) {
@@ -577,7 +577,7 @@
     {
         std::lock_guard<std::mutex> lock(m_mtx);
         nSize *= sizeof(short);
-        nRet = mdSend(m_nPath, CombineStation(station), nDevType, nDevNo, &nSize, pData);
+        nRet = mdSendEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, pData);
     }
 
     if (nRet != 0) {
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
index a6020c4..84b7a9d 100644
--- a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
@@ -377,11 +377,11 @@
 	int GetBoardStatus(BoardStatus& status);
 
 	// 读写数据
-	int ReadData(const StationIdentifier& station, short nDevType, short nDevNo, short nSize, std::vector<short>& vecData);
+	int ReadData(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<short>& vecData);
 	int ReadBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nBitCount, BitContainer& vecData);
 	int ReadWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nWordCount, WordContainer& vecData);
 	int ReadDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nDWordCount, DWordContainer& vecData);
-	int WriteData(const StationIdentifier& station, short nDevType, short nDevNo, short nSize, short* pData);
+	int WriteData(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, short* pData);
 	int WriteBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const BitContainer& vecData);
 	int WriteWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const WordContainer& vecData);
 	int WriteDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const DWordContainer& vecData);
diff --git a/SourceCode/Bond/Servo/CEFEM.cpp b/SourceCode/Bond/Servo/CEFEM.cpp
index 6b0548f..4520495 100644
--- a/SourceCode/Bond/Servo/CEFEM.cpp
+++ b/SourceCode/Bond/Servo/CEFEM.cpp
@@ -2,10 +2,23 @@
 #include "CEFEM.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 (addStep(index, pStep) != 0) {											\
+		delete pStep;															\
+	}																			\
+}
+
 namespace SERVO {
 	CEFEM::CEFEM() : CEquipment()
 	{
-
+		m_pPort[0] = nullptr;
+		m_pPort[1] = nullptr;
+		m_pPort[2] = nullptr;
+		m_pPort[3] = nullptr;
 	}
 
 	CEFEM::~CEFEM()
@@ -17,6 +30,13 @@
 	{
 		static char* pszName = "CEFEM";
 		return pszName;
+	}
+
+	void CEFEM::setPort(unsigned int index, CLoadPort* pPort)
+	{
+		if (index < 4) {
+			m_pPort[index] = pPort;
+		}
 	}
 
 	void CEFEM::init()
@@ -34,6 +54,245 @@
 	{
 		// 加入Pin初始化代码
 		LOGI("<CEFEM>initPins");
+	}
+
+	void CEFEM::initSteps()
+	{
+		CEquipment::initSteps();
+
+
+		{
+			// Eq mode
+			CEqModeStep* pStep = new CEqModeStep();
+			pStep->setName(STEP_MODE);
+			pStep->setWriteSignalDev(0x50);
+			pStep->setModeDev(0x5d7d);
+			if (addStep(STEP_ID_EQMODE_CHANGED, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Eq Status
+			CEqStatusStep* pStep = new CEqStatusStep();
+			pStep->setName(STEP_STATUS);
+			pStep->setWriteSignalDev(0x51);
+			pStep->setStatusDev(0x5d59);
+			if (addStep(STEP_ID_EQSTATUS_CHANGED, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Eq Alarm
+			static char* pszName[] = { STEP_ALARM_BLOCK1, STEP_ALARM_BLOCK2, STEP_ALARM_BLOCK3, STEP_ALARM_BLOCK4, STEP_ALARM_BLOCK5 };
+			static int dev[] = { 0x5f0e , 0x5f3b, 0x5f68, 0x5f95, 0x5fc2 };
+			static int writeSignalDev[] = { 0x52, 0x53, 0x54, 0x55, 0x56 };
+			static int addr[] = { STEP_ID_EQALARM1, STEP_ID_EQALARM2, STEP_ID_EQALARM3, STEP_ID_EQALARM4, STEP_ID_EQALARM5 };
+
+			for (int i = 0; i < 5; i++) {
+				CEqAlarmStep* pStep = new CEqAlarmStep();
+				pStep->setName(pszName[i]);
+				pStep->setWriteSignalDev(writeSignalDev[i]);
+				pStep->setAlarmDev(dev[i]);
+				if (addStep(addr[i], pStep) != 0) {
+					delete pStep;
+				}
+			}
+
+		}
+
+		{
+			// eq process
+			CEqProcessStep* pStep = new CEqProcessStep();
+			pStep->setName(STEP_PROCESS);
+			pStep->setWriteSignalDev(0x57);
+			pStep->setProcessDev(0x6b55);
+			if (addStep(STEP_ID_PROCESS_DATA_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq cim mode change
+			CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
+			pStep->setName(STEP_CIM_MODE_CHANGE);
+			pStep->setWriteSignalDev(0x70);
+			pStep->setCimModeDev(0x15);
+			if (addStep(STEP_ID_CIMMODE_CHANGED_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq cim message
+			CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
+			pStep->setName(STEP_CIM_MESSAGE_CMD);
+			pStep->setWriteSignalDev(0x71);
+			pStep->setCimMessageDev(0x0);
+			if (addStep(STEP_ID_CIM_MSG_SET_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+
+		{
+			// CIM Message Confirm
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT32, 0x5f80);
+			pStep->setName(STEP_EQ_CIM_MESSAGE_CONFIRM);
+			pStep->setWriteSignalDev(0x59);
+			if (addStep(STEP_ID_CIM_MSG_CONFIRM_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// VCR1 Event Report
+			CEqVcrEventStep* pStep = new CEqVcrEventStep();
+			pStep->setName(STEP_EQ_VCR1_EVENT_REPORT);
+			pStep->setWriteSignalDev(0x4a);
+			pStep->setReturnDev(0x91e);
+			pStep->setVcrEventReportDev(0x5fef);
+			if (addStep(STEP_ID_VCR1_EVENT_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq cim message clear
+			CEqCimMessageClearStep* pStep = new CEqCimMessageClearStep();
+			pStep->setName(STEP_CIM_MESSAGE_CLEAR);
+			pStep->setWriteSignalDev(0x72);
+			pStep->setClearCimMessageDev(0x13);
+			if (addStep(STEP_ID_CIM_MSG_CLEAR_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// datetime set cmd
+			CEqDateTimeSetCmdStep* pStep = new CEqDateTimeSetCmdStep();
+			pStep->setName(STEP_DATETIME_SET_CMD);
+			pStep->setWriteSignalDev(0x73);
+			pStep->setDateTimeDev(0x16);
+			if (addStep(STEP_ID_DATETIME_SET_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// vcr enable
+			CEqVCREnableStep* pStep = new CEqVCREnableStep();
+			pStep->setName(STEP_EQ_VCR_ENABLE);
+			pStep->setWriteSignalDev(0x74);
+			pStep->setEqVCRModeDev(0x1F);
+			if (addStep(STEP_ID_VCR_ENABLE_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// eq mode change
+			CEqModeChangeStep* pStep = new CEqModeChangeStep();
+			pStep->setName(STEP_EQ_MODE_CHANGE);
+			pStep->setWriteSignalDev(0x75);
+			pStep->setEqModeDev(0x1E);
+			if (addStep(STEP_ID_EQMODE_CHANGE_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// current recipe change
+			CEqCurrentRecipeChangeStep* pStep = new CEqCurrentRecipeChangeStep();
+			pStep->setName(STEP_EQ_RURRENT_RECIPE_CHANGE);
+			pStep->setWriteSignalDev(0x48);
+			pStep->setDataDev(0x6850);
+			if (addStep(STEP_ID_CURRENT_RECIPE_CHANGE_REPORT, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+
+		{
+			// 请求主配方列表的step
+			CEqWriteStep* pStep = new CEqWriteStep();
+			pStep->setName(STEP_EQ_MASTER_RECIPE_LIST_REQ);
+			pStep->setWriteSignalDev(0x66);
+			pStep->setDataDev(0x90a);
+			if (addStep(STEP_ID_MASTER_RECIPE_LIST_CMD_REPLY, pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		// CEqCassetteTranserStateStep
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_EMPTY, 0xd8,
+			STEP_ID_PORT1_CASSETTIE_EMPTY, 0x6050);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_LOAD_EADY, 0xe0,
+			STEP_ID_PORT1_CASSETTIE_LOAD_READY, 0x6050);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_LOADED, 0xe8,
+			STEP_ID_PORT1_CASSETTIE_LOADED, 0x6050);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_INUSE, 0xf0,
+			STEP_ID_PORT1_CASSETTIE_INUSE, 0x6050);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_UNLOAD_EADY, 0xf8,
+			STEP_ID_PORT1_CASSETTIE_UNLOAD_READY, 0x60f50);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P1_CASSETTE_BLOCKED, 0x100,
+			STEP_ID_PORT1_CASSETTIE_BLOCKED, 0x6050);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_EMPTY, 0xd9,
+			STEP_ID_PORT2_CASSETTIE_EMPTY, 0x6070);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_LOAD_EADY, 0xe1,
+			STEP_ID_PORT2_CASSETTIE_LOAD_READY, 0x6070);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_LOADED, 0xe9,
+			STEP_ID_PORT2_CASSETTIE_LOADED, 0x6070);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_INUSE, 0xf1,
+			STEP_ID_PORT2_CASSETTIE_INUSE, 0x6070);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_UNLOAD_EADY, 0xf9,
+			STEP_ID_PORT2_CASSETTIE_UNLOAD_READY, 0x6070);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P2_CASSETTE_BLOCKED, 0x101,
+			STEP_ID_PORT2_CASSETTIE_BLOCKED, 0x6070);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_EMPTY, 0xda,
+			STEP_ID_PORT3_CASSETTIE_EMPTY, 0x6090);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_LOAD_EADY, 0xe2,
+			STEP_ID_PORT3_CASSETTIE_LOAD_READY, 0x6090);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_LOADED, 0xea,
+			STEP_ID_PORT3_CASSETTIE_INUSE, 0x6090);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_INUSE, 0xf2,
+			STEP_ID_PORT3_CASSETTIE_INUSE, 0x6090);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_UNLOAD_EADY, 0xfa,
+			STEP_ID_PORT3_CASSETTIE_UNLOAD_READY, 0x6090);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P3_CASSETTE_BLOCKED, 0x102,
+			STEP_ID_PORT3_CASSETTIE_BLOCKED, 0x6090);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_EMPTY, 0xdb,
+			STEP_ID_PORT4_CASSETTIE_EMPTY, 0x60b0);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_LOAD_EADY, 0xe3,
+			STEP_ID_PORT4_CASSETTIE_LOAD_READY, 0x60b0);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_LOADED, 0xeb,
+			STEP_ID_PORT4_CASSETTIE_LOADED, 0x60b0);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_INUSE, 0xf3,
+			STEP_ID_PORT4_CASSETTIE_INUSE, 0x60b0);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_UNLOAD_EADY, 0xfb,
+			STEP_ID_PORT4_CASSETTIE_UNLOAD_READY, 0x60b0);
+		ADD_EQ_CASSETTE_TRANSFER_STATE_STEP(STEP_EQ_P4_CASSETTE_BLOCKED, 0x103,
+			STEP_ID_PORT4_CASSETTIE_BLOCKED, 0x60b0);
+	}
+
+	int CEFEM::onStepEvent(CStep* pStep, int code)
+	{
+		int nRet = CEquipment::onStepEvent(pStep, code);
+		if (nRet > 0) return nRet;
+
+		if (code == STEP_EVENT_READDATA) {
+			if (isCassetteTransferStateStep(pStep)) {
+				SERVO::CEqCassetteTransferStateStep* pEqCassetteStep = (SERVO::CEqCassetteTransferStateStep*)pStep;
+				int id = pEqCassetteStep->getID();
+				if (id == STEP_ID_PORT1_CASSETTIE_EMPTY) {
+
+				}
+			}
+		}
+
+
+		return 0;
 	}
 
 	void CEFEM::onTimer(UINT nTimerid)
@@ -65,4 +324,15 @@
 
 		return m_glassList.empty();
 	}
+
+	void CEFEM::onReceiveLBData(const char* pszData, size_t size)
+	{
+		__super::onReceiveLBData(pszData, size);
+
+		for (unsigned int i = 0; i < 4; i++) {
+			if (m_pPort[i] != nullptr) {
+				m_pPort[i]->onReceiveLBData(pszData, size);
+			}
+		}
+	}
 }
diff --git a/SourceCode/Bond/Servo/CEFEM.h b/SourceCode/Bond/Servo/CEFEM.h
index 35d8db2..2d7cc4b 100644
--- a/SourceCode/Bond/Servo/CEFEM.h
+++ b/SourceCode/Bond/Servo/CEFEM.h
@@ -1,5 +1,6 @@
 #pragma once
 #include "CEquipment.h"
+#include "CLoadPort.h"
 
 
 namespace SERVO {
@@ -15,11 +16,21 @@
         virtual void init();
         virtual void term();
         virtual void initPins();
+        virtual void initSteps();
+        virtual int onStepEvent(CStep* pStep, int code);
         virtual void onTimer(UINT nTimerid);
         virtual void serialize(CArchive& ar);
         virtual void getAttributeVector(CAttributeVector& attrubutes);
         virtual int recvIntent(CPin* pPin, CIntent* pIntent);
         virtual BOOL glassWillArrive(CGlass* pGlass);
+        virtual void onReceiveLBData(const char* pszData, size_t size);
+
+    public:
+        void setPort(unsigned int index, CLoadPort* pPort);
+
+
+    private:
+        CLoadPort* m_pPort[4];
     };
 }
 
diff --git a/SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.cpp b/SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.cpp
new file mode 100644
index 0000000..fd4b4a8
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.cpp
@@ -0,0 +1,49 @@
+#include "stdafx.h"
+#include "CEqCassetteCtrlCmdStep.h"
+
+
+namespace SERVO {
+	CEqCassetteCtrlCmdStep::CEqCassetteCtrlCmdStep() : CWriteStep()
+	{
+		m_nCtrlCmdDev = 0;
+	}
+
+	CEqCassetteCtrlCmdStep::~CEqCassetteCtrlCmdStep()
+	{
+
+	}
+
+	void CEqCassetteCtrlCmdStep::setCtrlCmdDev(int nDev)
+	{
+		m_nCtrlCmdDev = nDev;
+	}
+
+	int CEqCassetteCtrlCmdStep::sendCtrlCmd(short cmd,
+		short* jobExistence,
+		int jobExistenceSize,
+		short slotProcess,
+		short jopCount,
+		CJobDataA* pJobDataA)
+	{
+		ASSERT(jobExistenceSize == 12);
+		ASSERT(pJobDataA);
+
+		char szBuffer[1024] = { 0 };
+		memcpy(&szBuffer[0], &cmd, sizeof(short));
+		memcpy(&szBuffer[2], jobExistence, sizeof(short) * jobExistenceSize);
+		memcpy(&szBuffer[26], &slotProcess, sizeof(short));
+		memcpy(&szBuffer[36], &jopCount, sizeof(short));
+		int nLen = pJobDataA->serialize(&szBuffer[38], 1024 - 38);
+		return writeData(m_nCtrlCmdDev, (const char*)szBuffer, 38 + nLen);
+	}
+
+	void CEqCassetteCtrlCmdStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CWriteStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Control Command Dev",
+			("W" + CToolUnits::toHexString(m_nCtrlCmdDev, strTemp)).c_str(), ""));
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.h b/SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.h
new file mode 100644
index 0000000..e86ca92
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqCassetteCtrlCmdStep.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "CWriteStep.h"
+#include "CJobDataA.h"
+
+
+namespace SERVO {
+	class CEqCassetteCtrlCmdStep : public CWriteStep
+	{
+	public:
+		CEqCassetteCtrlCmdStep();
+		~CEqCassetteCtrlCmdStep();
+
+	public:
+		void setCtrlCmdDev(int nDev);
+		int sendCtrlCmd(short cmd,
+			short* jobExistence,
+			int jobExistenceSize,
+			short slotProcess, 
+			short jopCount,
+			CJobDataA* pJobDataA);
+		void getAttributeVector(CAttributeVector& attrubutes);
+
+	private:
+		int m_nCtrlCmdDev;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.cpp b/SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.cpp
new file mode 100644
index 0000000..37a7abe
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.cpp
@@ -0,0 +1,86 @@
+#include "stdafx.h"
+#include "CEqCurrentRecipeChangeStep.h"
+#include "Log.h"
+#include "ToolUnits.h"
+
+
+namespace SERVO {
+	CEqCurrentRecipeChangeStep::CEqCurrentRecipeChangeStep() : CReadStep()
+	{
+		m_nDataDev = 0;
+	}
+
+	CEqCurrentRecipeChangeStep::~CEqCurrentRecipeChangeStep()
+	{
+
+	}
+
+	void CEqCurrentRecipeChangeStep::setDataDev(int nDev)
+	{
+		m_nDataDev = nDev;
+	}
+
+	void CEqCurrentRecipeChangeStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CReadStep::getAttributeVector(attrubutes);
+
+		attrubutes.addAttribute(new CAttribute("UnitNo",
+			std::to_string(m_nUnitNo).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CurrentMasterRecipeId",
+			std::to_string(m_nCurrentMasterRecipeId).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("LocalRecipeId",
+			std::to_string(m_nLocalRecipeId).c_str(), ""));
+	}
+
+	int CEqCurrentRecipeChangeStep::onReadData()
+	{
+		CReadStep::onReadData();
+
+		char szBuffer[64];
+		int nRet = m_pCclink->ReadData2(m_station, DeviceType::W,
+			m_nDataDev, 6, szBuffer);
+		if (0 != nRet) {
+			return -1;
+		}
+
+		m_nUnitNo = (unsigned int)CToolUnits::toInt16(&szBuffer[0]);
+		m_nCurrentMasterRecipeId = (unsigned int)CToolUnits::toInt16(&szBuffer[2]);
+		m_nLocalRecipeId = (unsigned int)CToolUnits::toInt16(&szBuffer[4]);
+
+		LOGI("<CEqCurrentRecipeChangeStep> Current Recipe Changed<UnitNo:%d, CurrentMasterRecipeId:%d, LocalRecipeId:%d>\n",
+			m_nUnitNo, m_nCurrentMasterRecipeId, m_nLocalRecipeId);
+
+		return 0;
+	}
+
+	int CEqCurrentRecipeChangeStep::onComplete()
+	{
+		CReadStep::onComplete();
+		LOGI("<CEqCurrentRecipeChangeStep> onComplete.");
+
+		return 0;
+	}
+
+	int CEqCurrentRecipeChangeStep::onTimeout()
+	{
+		CReadStep::onTimeout();
+		LOGI("<CEqCurrentRecipeChangeStep> onTimeout.");
+
+		return 0;
+	}
+
+	int CEqCurrentRecipeChangeStep::getUnitNo()
+	{
+		return m_nUnitNo;
+	}
+
+	int CEqCurrentRecipeChangeStep::getCurrentMasterRecipeId()
+	{
+		return m_nCurrentMasterRecipeId;
+	}
+
+	int CEqCurrentRecipeChangeStep::getLocalRecipeId()
+	{
+		return m_nLocalRecipeId;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.h b/SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.h
new file mode 100644
index 0000000..7e05701
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqCurrentRecipeChangeStep.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "CReadStep.h"
+
+
+namespace SERVO {
+	class CEqCurrentRecipeChangeStep : public CReadStep
+	{
+	public:
+		CEqCurrentRecipeChangeStep();
+		~CEqCurrentRecipeChangeStep();
+
+	public:
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		virtual int onReadData();
+		virtual int onComplete();
+		virtual int onTimeout();
+		void setDataDev(int nDev);
+		int getUnitNo();
+		int getCurrentMasterRecipeId();
+		int getLocalRecipeId();
+
+	private:
+		int m_nDataDev;
+		int m_nUnitNo;
+		int m_nCurrentMasterRecipeId;
+		int m_nLocalRecipeId;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqJobEventStep.cpp b/SourceCode/Bond/Servo/CEqJobEventStep.cpp
new file mode 100644
index 0000000..a0efb8b
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqJobEventStep.cpp
@@ -0,0 +1,86 @@
+#include "stdafx.h"
+#include "CEqJobEventStep.h"
+#include "Log.h"
+
+
+namespace SERVO {
+	CEqJobEventStep::CEqJobEventStep() : CReadStep()
+	{
+		m_nJobDataADev = 0;
+	}
+
+	CEqJobEventStep::~CEqJobEventStep()
+	{
+
+	}
+
+	void CEqJobEventStep::setJobDataDev(int nDev)
+	{
+		m_nJobDataADev = nDev;
+	}
+
+	void CEqJobEventStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CReadStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Dev",
+			("W" + CToolUnits::toHexString(m_nJobDataADev, strTemp)).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("PortNo",
+			std::to_string(m_jobDataA.getPortNo()).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CarrierId",
+			m_jobDataA.getCarrierId().c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("PruductId",
+			m_jobDataA.getPruductId().c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CarrierState",
+			m_jobDataA.getCarrierStateDescription(strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("SlotMapping",
+			std::to_string(m_jobDataA.getSlotMapping()).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("SlotSelectedFlag",
+			std::to_string(m_jobDataA.getSlotSelectedFlag()).c_str(), ""));
+		std::vector<std::string>& ids = m_jobDataA.getGlassIds();
+		for (int i = 0; i < ids.size(); i++) {
+			attrubutes.addAttribute(new CAttribute((std::string("GlassId") + std::to_string(i+1)).c_str(),
+				ids[i].c_str(), ""));
+		}
+	}
+
+	int CEqJobEventStep::onReadData()
+	{
+		CReadStep::onReadData();
+
+
+		char szBuffer[1024];
+		int nRet = m_pCclink->ReadData2(m_station, DeviceType::W, m_nJobDataADev,
+			640, szBuffer);
+		if (0 != nRet) {
+			return -1;
+		}
+
+		m_jobDataA.unserialize(szBuffer, 640);
+		LOGI("<CEqJobEventStep-%s>Read JobDataA\n", m_strName.c_str());
+
+		return 0;
+	}
+
+	int CEqJobEventStep::onComplete()
+	{
+		CReadStep::onComplete();
+		LOGI("<CEqJobEventStep> onComplete.");
+
+		return 0;
+	}
+
+	int CEqJobEventStep::onTimeout()
+	{
+		CReadStep::onTimeout();
+		LOGI("<CEqJobEventStep> onTimeout.");
+
+		return 0;
+	}
+
+	CJobDataA* CEqJobEventStep::getJobDataA()
+	{
+		return &m_jobDataA;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CEqJobEventStep.h b/SourceCode/Bond/Servo/CEqJobEventStep.h
new file mode 100644
index 0000000..380470f
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqJobEventStep.h
@@ -0,0 +1,26 @@
+#pragma once
+#include "CReadStep.h"
+#include "CJobDataA.h"
+
+
+namespace SERVO {
+	class CEqJobEventStep : public CReadStep
+	{
+	public:
+		CEqJobEventStep();
+		~CEqJobEventStep();
+
+	public:
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		virtual int onReadData();
+		virtual int onComplete();
+		virtual int onTimeout();
+		void setJobDataDev(int nDev);
+		CJobDataA* getJobDataA();
+
+	private:
+		int m_nJobDataADev;
+		CJobDataA m_jobDataA;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqReadIntStep.cpp b/SourceCode/Bond/Servo/CEqReadIntStep.cpp
index 17174ae..e966f42 100644
--- a/SourceCode/Bond/Servo/CEqReadIntStep.cpp
+++ b/SourceCode/Bond/Servo/CEqReadIntStep.cpp
@@ -53,7 +53,7 @@
 			m_nValue = (unsigned int)CToolUnits::toInt32(&szBuffer[0]);
 		}
 
-		LOGI("<CEqReadIntStep>Value(%s) Changed<Dev:%d, Value:%d>\n",
+		LOGI("<CEqReadIntStep-%s>Value Changed<Dev:%d, Value:%d>\n",
 			m_strName.c_str(), m_nValueDev, m_nValue);
 
 		return 0;
@@ -62,7 +62,7 @@
 	int CEqReadIntStep::onComplete()
 	{
 		CReadStep::onComplete();
-		LOGI("<CEQPortChangeStep> onComplete.");
+		LOGI("<CEqReadIntStep> onComplete.");
 
 		return 0;
 	}
@@ -70,7 +70,7 @@
 	int CEqReadIntStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEQPortChangeStep> onTimeout.");
+		LOGI("<CEqReadIntStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEqReadStep.cpp b/SourceCode/Bond/Servo/CEqReadStep.cpp
new file mode 100644
index 0000000..854338e
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqReadStep.cpp
@@ -0,0 +1,82 @@
+#include "stdafx.h"
+#include "CEqReadStep.h"
+#include "Log.h"
+
+
+namespace SERVO {
+	CEqReadStep::CEqReadStep() : CReadStep()
+	{
+		m_nDataDev = 0;
+		m_nReadSize = 0;
+		m_onReadBlock = nullptr;
+	}
+
+	CEqReadStep::CEqReadStep(int dev, size_t readSize, ONREAD onReadBlock)
+	{
+		m_nDataDev = dev;
+		m_nReadSize = readSize;
+		m_onReadBlock = onReadBlock;
+	}
+
+	CEqReadStep::~CEqReadStep()
+	{
+
+	}
+
+	void CEqReadStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CReadStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Dev",
+			("W" + CToolUnits::toHexString(m_nDataDev, strTemp)).c_str(), ""));
+	}
+
+	int CEqReadStep::onReadData()
+	{
+		CReadStep::onReadData();
+
+
+		char szBuffer[READ_BUFFER_MAX];
+		int nRet = m_pCclink->ReadData2(m_station, DeviceType::W, m_nDataDev,
+			(long)min(READ_BUFFER_MAX, m_nReadSize), szBuffer);
+		if (0 != nRet) {
+			LOGI("<CEqReadStep>Read data error.");
+			if (m_onReadBlock != nullptr) {
+				m_onReadBlock(RERROR, nullptr, 0);
+			}
+			return -1;
+		}
+
+		LOGI("<CEqReadStep>read data succeed.");
+		if (m_onReadBlock != nullptr) {
+			m_onReadBlock(ROK, szBuffer, m_nReadSize);
+		}
+
+
+		return 0;
+	}
+
+	int CEqReadStep::onComplete()
+	{
+		CReadStep::onComplete();
+		LOGI("<CEqReadStep> onComplete.");
+		if (m_onReadBlock != nullptr) {
+			m_onReadBlock(RCOMPLETE, nullptr, 0);
+		}
+
+		return 0;
+	}
+
+	int CEqReadStep::onTimeout()
+	{
+		CReadStep::onTimeout();
+		LOGI("<CEqReadStep> onTimeout.");
+		if (m_onReadBlock != nullptr) {
+			m_onReadBlock(RTIMEOUT, nullptr, 0);
+		}
+
+		return 0;
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CEqReadStep.h b/SourceCode/Bond/Servo/CEqReadStep.h
new file mode 100644
index 0000000..fa9a2b3
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqReadStep.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "CReadStep.h"
+#include <functional>
+
+
+#define READ_BUFFER_MAX		1024
+
+#define ROK				0					/* 读数据OK */
+#define RTIMEOUT		-1					/* 读数据超时 */
+#define RERROR			-2					/* 读数据出错 */
+#define RCOMPLETE		1					/* 读数据流程完成 */
+
+namespace SERVO {
+	typedef std::function<int(int code, const char* pszData, size_t size)> ONREAD;
+
+	class CEqReadStep : public CReadStep
+	{
+	public:
+		CEqReadStep();
+		CEqReadStep(int dev, size_t readSize, ONREAD onReadBlock);
+		~CEqReadStep();
+
+	public:
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		virtual int onReadData();
+		virtual int onComplete();
+		virtual int onTimeout();
+
+	private:
+		ONREAD m_onReadBlock;
+		int m_nDataDev;
+		size_t m_nReadSize;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqVcrEventStep.cpp b/SourceCode/Bond/Servo/CEqVcrEventStep.cpp
new file mode 100644
index 0000000..e4c14d7
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqVcrEventStep.cpp
@@ -0,0 +1,90 @@
+#include "stdafx.h"
+#include "CEqVcrEventStep.h"
+#include "Log.h"
+
+
+namespace SERVO {
+	CEqVcrEventStep::CEqVcrEventStep() : CReadStep()
+	{
+		m_nVcrEventReportDev = 0;
+	}
+
+	CEqVcrEventStep::~CEqVcrEventStep()
+	{
+
+	}
+
+	void CEqVcrEventStep::setVcrEventReportDev(int nDev)
+	{
+		m_nVcrEventReportDev = nDev;
+	}
+
+	void CEqVcrEventStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CReadStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Dev",
+			("W" + CToolUnits::toHexString(m_nVcrEventReportDev, strTemp)).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("GlassId",
+			m_vcrEventReport.getGlassId().c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CassetteSequenceNo",
+			std::to_string(m_vcrEventReport.getCassetteSequenceNo()).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("JobSequenceNo",
+			std::to_string(m_vcrEventReport.getJobSequenceNo()).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("UnitNo",
+			std::to_string(m_vcrEventReport.getUnitNo()).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("VCR No",
+			std::to_string(m_vcrEventReport.getVcrNo()).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("VCR Result",
+			m_vcrEventReport.getVcrResultDescription(strTemp).c_str(), ""));
+	}
+
+	int CEqVcrEventStep::onReadData()
+	{
+		CReadStep::onReadData();
+
+
+		char szBuffer[64];
+		int nRet = m_pCclink->ReadData2(m_station, DeviceType::W, m_nVcrEventReportDev,
+			30, szBuffer);
+		if (0 != nRet) {
+			return -1;
+		}
+
+		m_vcrEventReport.unserialize(szBuffer, 60);
+		LOGI("<CEqVcrEventStep-%s>Read VCR Event Report\n", m_strName.c_str());
+
+		return 0;
+	}
+
+	int CEqVcrEventStep::onComplete()
+	{
+		CReadStep::onComplete();
+		LOGI("<CEqVcrEventStep> onComplete.");
+
+		return 0;
+	}
+
+	int CEqVcrEventStep::onTimeout()
+	{
+		CReadStep::onTimeout();
+		LOGI("<CEqVcrEventStep> onTimeout.");
+
+		return 0;
+	}
+
+	CVcrEventReport* CEqVcrEventStep::getVcrEventReport()
+	{
+		return &m_vcrEventReport;
+	}
+
+	int CEqVcrEventStep::setReturnCode(short code)
+	{
+		memcpy(m_szReturnBuf, &code, sizeof(short));
+		m_nReturnDataSize = sizeof(short);
+
+		return 0;
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CEqVcrEventStep.h b/SourceCode/Bond/Servo/CEqVcrEventStep.h
new file mode 100644
index 0000000..b7b64a4
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqVcrEventStep.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "CReadStep.h"
+#include "CVcrEventReport.h"
+
+
+namespace SERVO {
+	class CEqVcrEventStep : public CReadStep
+	{
+	public:
+		CEqVcrEventStep();
+		~CEqVcrEventStep();
+
+	public:
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		virtual int onReadData();
+		virtual int onComplete();
+		virtual int onTimeout();
+		void setVcrEventReportDev(int nDev);
+		CVcrEventReport* getVcrEventReport();
+		int setReturnCode(short code);
+
+	private:
+		int m_nVcrEventReportDev;
+		CVcrEventReport m_vcrEventReport;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqWriteStep.cpp b/SourceCode/Bond/Servo/CEqWriteStep.cpp
new file mode 100644
index 0000000..da4a0cc
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqWriteStep.cpp
@@ -0,0 +1,66 @@
+#include "stdafx.h"
+#include "CEqWriteStep.h"
+
+
+namespace SERVO {
+	CEqWriteStep::CEqWriteStep() : CWriteStep()
+	{
+		m_nDataDev = 0;
+		m_onWritedBlock = nullptr;
+	}
+
+	CEqWriteStep::~CEqWriteStep()
+	{
+
+	}
+
+	void CEqWriteStep::setDataDev(int nDev)
+	{
+		m_nDataDev = nDev;
+	}
+
+	int CEqWriteStep::writeShort(short value, ONWRITED onWritedBlock/* = nullptr*/)
+	{
+		m_onWritedBlock = onWritedBlock;
+		return writeData(m_nDataDev, (const char*)&value, sizeof(short));
+	}
+
+	int CEqWriteStep::writeInt(int value, ONWRITED onWritedBlock/* = nullptr*/)
+	{
+		m_onWritedBlock = onWritedBlock;
+		return writeData(m_nDataDev, (const char*)&value, sizeof(int));
+	}
+
+	int CEqWriteStep::writeDataEx(const char* pszData, int size, ONWRITED onWritedBlock/* = nullptr*/)
+	{
+		m_onWritedBlock = onWritedBlock;
+		return writeData(m_nDataDev, pszData, size);
+	}
+
+	void CEqWriteStep::getAttributeVector(CAttributeVector& attrubutes)
+	{
+		CWriteStep::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Data Dev",
+			("W" + CToolUnits::toHexString(m_nDataDev, strTemp)).c_str(), ""));
+	}
+
+	int CEqWriteStep::onComplete()
+	{
+		if (m_onWritedBlock != nullptr) {
+			m_onWritedBlock(WOK);
+		}
+
+		return 0;
+	}
+
+	int CEqWriteStep::onTimeout()
+	{
+		if (m_onWritedBlock != nullptr) {
+			m_onWritedBlock(WTIMEOUT);
+		}
+
+		return 0;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CEqWriteStep.h b/SourceCode/Bond/Servo/CEqWriteStep.h
new file mode 100644
index 0000000..602408b
--- /dev/null
+++ b/SourceCode/Bond/Servo/CEqWriteStep.h
@@ -0,0 +1,32 @@
+#pragma once
+#include "CWriteStep.h"
+#include <functional>
+
+
+#define WOK				0
+#define WTIMEOUT		-1
+
+namespace SERVO {
+	typedef std::function<int(int code)> ONWRITED;
+
+	class CEqWriteStep : public CWriteStep
+	{
+	public:
+		CEqWriteStep();
+		~CEqWriteStep();
+
+	public:
+		void setDataDev(int nDev);
+		virtual void getAttributeVector(CAttributeVector& attrubutes);
+		int writeShort(short value, ONWRITED onWritedBlock = nullptr);
+		int writeInt(int value, ONWRITED onWritedBlock = nullptr);
+		int writeDataEx(const char* pszData, int size, ONWRITED onWritedBlock = nullptr);
+		virtual int onComplete();
+		virtual int onTimeout();
+
+	private:
+		int m_nDataDev;
+		ONWRITED m_onWritedBlock;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 85f5a0b..096870f 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -1,6 +1,7 @@
 #include "stdafx.h"
 #include "CEquipment.h"
 #include "ToolUnits.h"
+#include <regex>
 
 
 #define CHECK_READ_STEP_SIGNAL(addr, data, size) {							\
@@ -23,8 +24,8 @@
 
 	CEquipment::CEquipment() : m_nID(0), m_strName(""), m_strDescription(""), m_station(0, 255)
 	{
-		m_listener = { nullptr, nullptr, nullptr, nullptr };
-		m_alive = {FALSE, 0, FALSE};
+		m_listener = { nullptr, nullptr, nullptr, nullptr, nullptr };
+		m_alive = { FALSE, 0, FALSE };
 		m_bCimState = FALSE;
 		m_bUpstreamInline = FALSE;
 		m_bDownstreamInline = FALSE;
@@ -67,6 +68,7 @@
 		m_listener.onCimStateChanged = listener.onCimStateChanged;
 		m_listener.onAlarm = listener.onAlarm;
 		m_listener.onDataChanged = listener.onDataChanged;
+		m_listener.onVcrEventReport = listener.onVcrEventReport;
 	}
 
 	void CEquipment::setCcLink(CCCLinkIEControl* pCcLink)
@@ -121,6 +123,7 @@
 		auto iter = m_mapStep.find(addr);
 		if (iter != m_mapStep.end()) return -1;
 		pStep->setEquipment(this);
+		pStep->setID(addr);
 		pStep->setCcLink(m_pCclink);
 		m_mapStep[addr] = pStep;
 		return 0;
@@ -129,6 +132,7 @@
 	void CEquipment::init()
 	{
 		initPins();
+		initSteps();
 		for (auto item : m_mapStep) {
 			item.second->init();
 		}
@@ -139,6 +143,11 @@
 		for (auto item : m_mapStep) {
 			item.second->term();
 		}
+	}
+
+	void CEquipment::initSteps()
+	{
+
 	}
 
 	void CEquipment::setID(int nID)
@@ -310,7 +319,7 @@
 
 		// 以下解释和处理数据
 		BOOL bFlag;
-		int index = 0x340;
+		int index = 0x840;
 
 
 		// alive
@@ -327,7 +336,7 @@
 				}
 			}
 		}
-	
+
 		// CIM State
 		bFlag = isBitOn(pszData, size, ++index);
 		if (!equalBool(m_bCimState, bFlag)) {
@@ -361,7 +370,7 @@
 			m_bAutoRecipeChange = bFlag;
 		}
 
-		// AutoRecipeChange
+		// VCR Enable
 		bFlag = isBitOn(pszData, size, ++index);
 		if (!equalBool(m_bVCREnable[0], bFlag)) {
 			m_bVCREnable[0] = bFlag;
@@ -369,45 +378,44 @@
 
 
 		// 以下根据信号做流程处理
-		CStep* pStep;
-
-		// Equipment Mode Change Report(0x360)
-		// Equipment Status Change Report(0x361)
-		// Equipment Alarm Change Report(0x362 ~ 0x366)
 		for (int i = 0; i < 7; i++) {
-			CHECK_READ_STEP_SIGNAL(0x360 + i, pszData, size);
+			CHECK_READ_STEP_SIGNAL(STEP_ID_EQMODE_CHANGED + i, pszData, size);
 		}
 
 
 		// CIM Mode
-		CHECK_WRITE_STEP_SIGNAL(0x350, pszData, size);
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIMMODE_CHANGED_CMD_REPLY, pszData, size);
 
+		// CIM Message Set cmd reply
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIM_MSG_SET_CMD_REPLY, 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);
+		// CIM Message Clear cmd reply
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIM_MSG_CLEAR_CMD_REPLY, pszData, size);
+
+		// Datetime set cmd reply
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_DATETIME_SET_CMD_REPLY, pszData, size);
+
+		// vcr enable cmd reply
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_VCR_ENABLE_CMD_REPLY, pszData, size);
+
+		// EQ mode change cmd reply
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_EQMODE_CHANGE_CMD_REPLY, pszData, size);
+
+		// EQ Master recipe request cmd reply
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_MASTER_RECIPE_LIST_CMD_REPLY, pszData, size);
+
+		// CIM Message Confirm
+		CHECK_READ_STEP_SIGNAL(STEP_ID_CIM_MSG_CONFIRM_REPORT, pszData, size);
+
+		// VCR1 Event report
+		CHECK_READ_STEP_SIGNAL(STEP_ID_VCR1_EVENT_REPORT, pszData, size);
+
+		// EQ Job Event
+		CHECK_READ_STEP_SIGNAL(STEP_ID_RECIVE_JOB_UPS1, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_RECIVE_JOB_UPS2, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_SENT_OUT_JOB_DOWNS1, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_SENT_OUT_JOB_DOWNS2, pszData, size);
+
 
 		// CEqCassetteTranserStateStep
 		CHECK_READ_STEP_SIGNAL(STEP_ID_PORT1_CASSETTIE_EMPTY, pszData, size);
@@ -494,11 +502,35 @@
 				int state = pEqAlarmStep->getAlarmState();
 				ASSERT(state == 0 || state == 1);
 				if (m_listener.onAlarm != nullptr) {
-					m_listener.onAlarm(this, state, 
+					m_listener.onAlarm(this, state,
 						pEqAlarmStep->getAlarmId(),
 						pEqAlarmStep->getUnitId(),
 						pEqAlarmStep->getAlarmLevel());
 				}
+
+				return 1;
+			}
+			else if (isCimMessageConfirmStep(pStep)) {
+				SERVO::CEqReadIntStep* pEqReadIntStep = (SERVO::CEqReadIntStep*)pStep;
+				int value = pEqReadIntStep->getValue();
+				// 此处将value按高低位拆分为message id和panel no.
+				// 可能还需要上报到cim
+				short msgId, panelNo;
+				msgId = (value & 0xffff0000 >> 16);
+				panelNo = (value & 0xffff);
+				LOGI("Cim Message Confirm(msgID = %d, panel no.=%d).", msgId, panelNo);
+			}
+			else if (isVcrEventStep(pStep)) {
+				SERVO::CEqVcrEventStep* pEqVcrEventStep = (SERVO::CEqVcrEventStep*)pStep;
+				CVcrEventReport* pVcrEventReport = pEqVcrEventStep->getVcrEventReport();
+				ASSERT(pVcrEventReport);
+				if (m_listener.onVcrEventReport != nullptr) {
+					m_listener.onVcrEventReport(this, pVcrEventReport);
+				}
+
+				// 0426, 先固定返回1(OK)
+				pEqVcrEventStep->setReturnCode(1);		
+				return 1;
 			}
 		}
 
@@ -742,4 +774,138 @@
 		return CToolUnits::startsWith(pStep->getName(), STEP_ALARM_START);
 	}
 
-}
+	bool CEquipment::isPortTypeStep(SERVO::CStep* pStep)
+	{
+		std::regex pattern("^EQPort\\d+Type$");
+		return std::regex_match(pStep->getName(), pattern);
+	}
+
+	bool CEquipment::isPortModeStep(SERVO::CStep* pStep)
+	{
+		std::regex pattern("^EQPort\\d+Mode$");
+		return std::regex_match(pStep->getName(), pattern);
+	}
+
+	bool CEquipment::isPortCassetteTypeStep(SERVO::CStep* pStep)
+	{
+		std::regex pattern("^EQPort\\d+CassetteType$");
+		return std::regex_match(pStep->getName(), pattern);
+	}
+
+	bool CEquipment::isPortTransferModeStep(SERVO::CStep* pStep)
+	{
+		std::regex pattern("^EQPort\\d+TransferMode$");
+		return std::regex_match(pStep->getName(), pattern);
+	}
+
+	bool CEquipment::isPortEnableStep(SERVO::CStep* pStep)
+	{
+		std::regex pattern("^EQPort\\d+Enable$");
+		return std::regex_match(pStep->getName(), pattern);
+	}
+
+	bool CEquipment::isPortTypeAutoChangeEnableStep(SERVO::CStep* pStep)
+	{
+		std::regex pattern("^EQPort\\d+CassetteType$");
+		return std::regex_match(pStep->getName(), pattern);
+	}
+
+	bool CEquipment::isCassetteTransferStateStep(SERVO::CStep* pStep)
+	{
+		std::regex pattern("^EQPort\\d+Cassette.*");
+		return std::regex_match(pStep->getName(), pattern);
+	}
+
+	bool CEquipment::isCimMessageConfirmStep(SERVO::CStep* pStep)
+	{
+		return pStep->getName().compare(STEP_EQ_CIM_MESSAGE_CONFIRM) == 0;
+	}
+
+	bool CEquipment::isVcrEventStep(SERVO::CStep* pStep)
+	{
+		return pStep->getName().compare(STEP_EQ_VCR1_EVENT_REPORT) == 0;
+	}
+
+	int CEquipment::setEqMode(short mode)
+	{
+		SERVO::CEqModeChangeStep* pStep = (SERVO::CEqModeChangeStep*)getStepWithName(STEP_EQ_MODE_CHANGE);
+		if (pStep == nullptr) {
+			return -1;
+		}
+
+		return pStep->setEqMode(mode);
+	}
+
+	int CEquipment::setCimMode(BOOL bOn)
+	{
+		SERVO::CEqCimModeChangeStep* pStep = (SERVO::CEqCimModeChangeStep*)getStepWithName(STEP_CIM_MODE_CHANGE);
+		if (pStep == nullptr) {
+			return -1;
+		}
+
+		if (bOn)
+			return pStep->cimOn();
+		else 
+			return pStep->cimOff();
+	}
+
+	int CEquipment::setCimMessage(const char* pszMessage, short id, short nTouchPanelNo)
+	{
+		SERVO::CEqCimMessageCmdStep* pStep = (SERVO::CEqCimMessageCmdStep*)getStepWithName(STEP_CIM_MESSAGE_CMD);
+		if (pStep == nullptr) {
+			return -1;
+		}
+
+		return pStep->setCimMessage(pszMessage, id, nTouchPanelNo);
+	}
+
+	int CEquipment::clearCimMessage(short id, short nTouchPanelNo)
+	{
+		SERVO::CEqCimMessageClearStep* pStep = (SERVO::CEqCimMessageClearStep*)getStepWithName(STEP_CIM_MESSAGE_CLEAR);
+		if (pStep == nullptr) {
+			return -1;
+		}
+
+		return pStep->clearCimMessage(id, nTouchPanelNo);
+	}
+
+	int CEquipment::setDateTime(short year, short month, short day, short hour, short minute, short second)
+	{
+		SERVO::CEqDateTimeSetCmdStep* pStep = (SERVO::CEqDateTimeSetCmdStep*)getStepWithName(STEP_DATETIME_SET_CMD);
+		if (pStep == nullptr) {
+			return -1;
+		}
+
+		return pStep->setDateTime(year, month, day, hour, minute, second);
+	}
+
+	int CEquipment::masterRecipeListRequest(short unitNo)
+	{
+		SERVO::CEqWriteStep* pStep = (SERVO::CEqWriteStep*)getStepWithName(STEP_EQ_MASTER_RECIPE_LIST_REQ);
+		if (pStep == nullptr) {
+			return -1;
+		}
+
+		LOGI("<CEquipment-%s>正在请求单元<%d>主配方列表", m_strName.c_str(), unitNo);
+		if (m_recipesManager.syncing() != 0) {
+			return -2;
+		}
+		pStep->writeShort(unitNo, [&, unitNo](int code) -> int {
+			if (code == WOK) {
+				LOGI("<CEquipment-%s>请求单元<%d>主配方列表成功,正在等待数据.", m_strName.c_str(), unitNo);
+			}
+			else {
+				m_recipesManager.syncFailed();
+				LOGI("<CEquipment-%s>请求单元<%d>主配方列表失败,code:%d", m_strName.c_str(), unitNo, code);
+			}
+
+			return 0;
+		});
+		return 0;
+	}
+
+	short CEquipment::decodeRecipeListReport(const char* pszData, size_t size)
+	{
+		return m_recipesManager.decodeRecipeListReport(pszData, size);
+	}
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index 407b505..14283bd 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -16,10 +16,17 @@
 #include "CEqPortChangeStep.h"
 #include "CEqReadIntStep.h"
 #include "CEqCassetteTransferStateStep.h"
+#include "CEqCassetteCtrlCmdStep.h"
+#include "CEqJobEventStep.h"
+#include "CEqVcrEventStep.h"
+#include "CEqCurrentRecipeChangeStep.h"
+#include "CEqWriteStep.h"
+#include "CEqReadStep.h"
 #include <vector>
 #include <map>
 #include <list>
 #include "CGlass.h"
+#include "CRecipesManager.h"
 
 
 namespace SERVO {
@@ -30,12 +37,14 @@
 	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 std::function<void(void* pEiuipment, void* pReport)> ONVCREVENTREPORT;
 	typedef struct _EquipmentListener
 	{
 		ONALIVE				onAlive;
 		ONALIVE				onCimStateChanged;
 		ONALARM				onAlarm;
 		ONDATACHANGED		onDataChanged;
+		ONVCREVENTREPORT	onVcrEventReport;
 	} EquipmentListener;
 
 	// Memory Block 结构体定义
@@ -88,6 +97,7 @@
 		virtual void init();
 		virtual void term();
 		virtual void initPins() = 0;
+		virtual void initSteps();
 		virtual void onTimer(UINT nTimerid);
 		virtual void serialize(CArchive& ar);
 		virtual void onReceiveLBData(const char* pszData, size_t size);
@@ -104,6 +114,25 @@
 		CGlass* getFrontGlass();
 		BOOL removeClass(CGlass* pGlass);
 		bool isAlarmStep(SERVO::CStep* pStep);
+		bool isVcrEventStep(SERVO::CStep* pStep);
+		bool isCassetteTransferStateStep(SERVO::CStep* pStep);
+		bool isPortTypeStep(SERVO::CStep* pStep);
+		bool isPortModeStep(SERVO::CStep* pStep);
+		bool isPortCassetteTypeStep(SERVO::CStep* pStep);
+		bool isPortTransferModeStep(SERVO::CStep* pStep);
+		bool isPortEnableStep(SERVO::CStep* pStep);
+		bool isPortTypeAutoChangeEnableStep(SERVO::CStep* pStep);
+		bool isCimMessageConfirmStep(SERVO::CStep* pStep);
+		int setEqMode(short mode);
+		int setCimMode(BOOL bOn);
+		int setCimMessage(const char* pszMessage, short id, short nTouchPanelNo);
+		int clearCimMessage(short id, short nTouchPanelNo);
+		int setDateTime(short year, short month, short day, short hour, short minute, short second);
+		
+		// 请求主配方列表
+		// unitNo: 0:local; Others:unit No
+		int masterRecipeListRequest(short unitNo);
+
 
 	// 以下为从CC-Link读取到的Bit标志位检测函数
 	public:
@@ -115,15 +144,13 @@
 		BOOL isAutoRecipeChange();
 		BOOL isVCREnable(unsigned int index);
 
-
-	private:
-		BOOL isBitOn(const char* pszData, size_t size, int index);
-		inline BOOL equalBool(BOOL b1, BOOL b2);
-
 	protected:
 		inline void Lock() { EnterCriticalSection(&m_criticalSection); }
 		inline void Unlock() { LeaveCriticalSection(&m_criticalSection); }
+		BOOL isBitOn(const char* pszData, size_t size, int index);
+		inline BOOL equalBool(BOOL b1, BOOL b2);
 		void addGlassToList(CGlass* pGlass);
+		short decodeRecipeListReport(const char* pszData, size_t size);
 
 	protected:
 		EquipmentListener m_listener;
@@ -140,7 +167,7 @@
 
 
 		// 以下为从CC-Link读取到的Bit标志位
-	private:
+	protected:
 		ALIVE m_alive;
 		BOOL m_bCimState;			// ON/OFF
 		BOOL m_bUpstreamInline;
@@ -149,10 +176,11 @@
 		BOOL m_bAutoRecipeChange;
 		BOOL m_bVCREnable[VCR_MAX];
 
-	private:
+	protected:
 		CCCLinkIEControl* m_pCclink;
 		std::map<unsigned int, CStep*> m_mapStep;
 		int m_nBaseAlarmId;
+		CRecipesManager m_recipesManager;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CJobDataA.cpp b/SourceCode/Bond/Servo/CJobDataA.cpp
new file mode 100644
index 0000000..4c5e3e4
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataA.cpp
@@ -0,0 +1,157 @@
+#include "stdafx.h"
+#include "CJobDataA.h"
+#include "ToolUnits.h"
+
+
+namespace SERVO {
+	CJobDataA::CJobDataA()
+	{
+
+	}
+
+	CJobDataA::~CJobDataA()
+	{
+
+	}
+
+	short CJobDataA::getPortNo()
+	{
+		return m_nPortNo;
+	}
+
+	std::string& CJobDataA::getCarrierId()
+	{
+		return m_strCarrierId;
+	}
+
+	std::string& CJobDataA::getPruductId()
+	{
+		return m_pruductId;
+	}
+
+	int CJobDataA::serialize(char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 640) return -1;
+
+		int index = 0;
+		memcpy(&pszBuffer[index], &m_nPortNo, sizeof(short));
+		index += sizeof(short);
+
+		int strLen = min(20, m_strCarrierId.size());
+		memcpy(&pszBuffer[index], m_strCarrierId.c_str(), strLen);
+		index += 20;
+
+		strLen = min(20, m_pruductId.size());
+		memcpy(&pszBuffer[index], m_pruductId.c_str(), strLen);
+		index += 20;
+
+		memcpy(&pszBuffer[index], &m_nCarrierState, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nSlotMapping, sizeof(int));
+		index += sizeof(int);
+
+		memcpy(&pszBuffer[index], &m_nSlotSelectedFlag, sizeof(int));
+		index += sizeof(int);
+
+		for (int i = 0; i < min(25, m_glassIds.size()); i++) {
+			std::string& strGlassId = m_glassIds.at(i);
+			strLen = min(20, strGlassId.size());
+			memcpy(&pszBuffer[index], strGlassId.c_str(), strLen);
+			index += 20;
+		}
+
+		return 320 * 2;
+	}
+
+	int CJobDataA::unserialize(char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 640) return -1;
+
+		int index = 0;
+		memcpy(&m_nPortNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		CToolUnits::convertString(&pszBuffer[index], 20, m_strCarrierId);
+		index += 20;
+
+		CToolUnits::convertString(&pszBuffer[index], 20, m_pruductId);
+		index += 20;
+
+		memcpy(&m_nCarrierState, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nSlotMapping, &pszBuffer[index], sizeof(int));
+		index += sizeof(int);
+
+		memcpy(&m_nSlotSelectedFlag, &pszBuffer[index], sizeof(int));
+		index += sizeof(int);
+
+		std::string strGlassId;
+		m_glassIds.clear();
+		for (int i = 0; i < 25; i++) {
+			CToolUnits::convertString(&pszBuffer[index], 20, strGlassId);
+			index += 20;
+			if (!strGlassId.empty()) {
+				m_glassIds.push_back(strGlassId);
+			}
+		}
+
+		return 320 * 2;
+	}
+
+	short CJobDataA::getCarrierState()
+	{
+		return m_nCarrierState;
+	}
+
+	std::string& CJobDataA::getCarrierStateDescription(std::string& strDescription)
+	{
+		static char* pszDescription[20] = {
+			"Bind",
+			"CancelPod",
+			"CancelPodNotification",
+			"CancelPodOut",
+			"CancelPodAtPort",
+			"CancelBind", 
+			"Clamp",
+			"ClosePod",
+			"IndexDown",
+			"IndexUp",
+			"OpenPod",
+			"PodComplete",
+			"PodIn",
+			"PodNotification",
+			"PodOut",
+			"PodRelease",
+			"PodTagReadData",
+			"PodTagWriteData",
+			"Proceed WithPod",
+			"Unclamp"
+		};
+
+		if (0 <= m_nCarrierState && m_nCarrierState < 20) {
+			strDescription = pszDescription[m_nCarrierState];
+		}
+		else {
+			strDescription = "";
+		}
+
+		return strDescription;
+	}
+
+	int CJobDataA::getSlotMapping()
+	{
+		return m_nSlotMapping;
+	}
+
+	int CJobDataA::getSlotSelectedFlag()
+	{
+		return m_nSlotSelectedFlag;
+	}
+
+	std::vector<std::string>& CJobDataA::getGlassIds()
+	{
+		return m_glassIds;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CJobDataA.h b/SourceCode/Bond/Servo/CJobDataA.h
new file mode 100644
index 0000000..86b761a
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataA.h
@@ -0,0 +1,35 @@
+#pragma once
+#include <vector>
+#include <string>
+
+
+namespace SERVO {
+	class CJobDataA
+	{
+	public:
+		CJobDataA();
+		~CJobDataA();
+
+	public:
+		short getPortNo();
+		std::string& getCarrierId();
+		std::string& getPruductId();
+		short getCarrierState();
+		std::string& getCarrierStateDescription(std::string& strDescription);
+		int getSlotMapping();
+		int getSlotSelectedFlag();
+		std::vector<std::string>& getGlassIds();
+		int serialize(char* pszBuffer, int nBufferSize);
+		int unserialize(char* pszBuffer, int nBufferSize);
+
+	private:
+		short m_nPortNo;
+		std::string m_strCarrierId;
+		std::string m_pruductId;
+		short m_nCarrierState;
+		int m_nSlotMapping;
+		int m_nSlotSelectedFlag;
+		std::vector<std::string> m_glassIds;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CJobDataB.cpp b/SourceCode/Bond/Servo/CJobDataB.cpp
new file mode 100644
index 0000000..cf25ff2
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataB.cpp
@@ -0,0 +1,46 @@
+#include "stdafx.h"
+#include "CJobDataB.h"
+
+
+namespace SERVO {
+	CJobDataB::CJobDataB()
+	{
+		m_nCassetteSequenceNo = 0;
+		m_nJobSequenceNo = 0;
+	}
+
+	CJobDataB::~CJobDataB()
+	{
+
+	}
+
+	int CJobDataB::getCassetteSequenceNo()
+	{
+		return m_nCassetteSequenceNo;
+	}
+
+	void CJobDataB::setCassetteSequenceNo(int no)
+	{
+		m_nCassetteSequenceNo = no;
+	}
+
+	int CJobDataB::getJobSequenceNo()
+	{
+		return m_nJobSequenceNo;
+	}
+
+	void CJobDataB::setJobSequenceNo(int no)
+	{
+		m_nJobSequenceNo = no;
+	}
+
+	std::string& CJobDataB::getGlassId()
+	{
+		return m_strGlassId;
+	}
+
+	void CJobDataB::setGlassId(const char* pszGlassId)
+	{
+		m_strGlassId = pszGlassId;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CJobDataB.h b/SourceCode/Bond/Servo/CJobDataB.h
new file mode 100644
index 0000000..589ba72
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataB.h
@@ -0,0 +1,25 @@
+#pragma once
+
+
+namespace SERVO {
+	class CJobDataB
+	{
+	public:
+		CJobDataB();
+		~CJobDataB();
+
+	public:
+		int getCassetteSequenceNo();
+		void setCassetteSequenceNo(int no);
+		int getJobSequenceNo();
+		void setJobSequenceNo(int no);
+		std::string& getGlassId();
+		void setGlassId(const char* pszGlassId);
+
+	private:
+		int m_nCassetteSequenceNo;
+		int m_nJobSequenceNo;
+		std::string m_strGlassId;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CJobDataC.cpp b/SourceCode/Bond/Servo/CJobDataC.cpp
new file mode 100644
index 0000000..4781964
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataC.cpp
@@ -0,0 +1,66 @@
+#include "stdafx.h"
+#include "CJobDataC.h"
+
+
+namespace SERVO {
+	CJobDataC::CJobDataC()
+	{
+		m_nCassetteSequenceNo = 0;
+	}
+
+	CJobDataC::~CJobDataC()
+	{
+		m_nCassetteProcessFlag = 0;
+	}
+
+	int CJobDataC::getCassetteSequenceNo()
+	{
+		return m_nCassetteSequenceNo;
+	}
+
+	void CJobDataC::setCassetteSequenceNo(int no)
+	{
+		m_nCassetteSequenceNo = no;
+	}
+
+	std::string& CJobDataC::getCassetteId()
+	{
+		return m_strCassetteId;
+	}
+
+	void CJobDataC::setCassetteId(const char* pszId)
+	{
+		m_strCassetteId = pszId;
+	}
+
+	std::string& CJobDataC::getCassetteJudge()
+	{
+		return m_strCassetteJudge;
+	}
+
+	void CJobDataC::setCassetteJudge(const char* pszJudge)
+	{
+		m_strCassetteJudge = pszJudge;
+	}
+
+	int CJobDataC::getCassetteProcessFlag()
+	{
+		return m_nCassetteProcessFlag;
+	}
+
+	void CJobDataC::setCassetteProcessFlag(int flag)
+	{
+		m_nCassetteProcessFlag = flag;
+	}
+
+	std::string& CJobDataC::getMasterRecipe()
+	{
+		return m_strMasterRecipe;
+	}
+
+	void CJobDataC::setMasterRecipe(const char* pszRecipe)
+	{
+		m_strMasterRecipe = pszRecipe;
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CJobDataC.h b/SourceCode/Bond/Servo/CJobDataC.h
new file mode 100644
index 0000000..6b8189f
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataC.h
@@ -0,0 +1,31 @@
+#pragma once
+
+
+namespace SERVO {
+	class CJobDataC
+	{
+	public:
+		CJobDataC();
+		~CJobDataC();
+
+	public:
+		int getCassetteSequenceNo();
+		void setCassetteSequenceNo(int no);
+		std::string& getCassetteId();
+		void setCassetteId(const char* pszId);
+		std::string& getCassetteJudge();
+		void setCassetteJudge(const char* pszJudge);
+		int getCassetteProcessFlag();
+		void setCassetteProcessFlag(int flag);
+		std::string& getMasterRecipe();
+		void setMasterRecipe(const char* pszRecipe);
+
+	private:
+		int m_nCassetteSequenceNo;
+		std::string m_strCassetteId;
+		std::string m_strCassetteJudge;
+		int m_nCassetteProcessFlag;
+		std::string m_strMasterRecipe;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CJobDataS.cpp b/SourceCode/Bond/Servo/CJobDataS.cpp
new file mode 100644
index 0000000..f474931
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataS.cpp
@@ -0,0 +1,330 @@
+#include "stdafx.h"
+#include "CJobDataS.h"
+
+
+namespace SERVO {
+	CJobDataS::CJobDataS()
+	{
+		m_nCassetteSequenceNo = 0;
+		m_nJobSequenceNo = 0;
+		m_nJobType = 0;
+		m_nMaterialsType = 0;
+		m_nProductType = 0;
+		m_nDummyType = 0;
+		m_nSkipFlag = 0;
+		m_nProcessFlag = 0;
+		m_nProcessResonCode = 0;
+		m_nLastGlassFlag = 0;
+		m_nFirstGlassFlag = 0;
+		m_nQTime[3] = {0};
+		m_nQTimeOverFlag = 0;
+		m_nMasterRecipe = 0;
+		m_nMode = 0;
+		m_nSlotUnitSelectFlag = 0;
+		m_nSourcePortNo = 0;
+		m_nSourceSlotNo = 0;
+		m_nTargetPortNo = 0;
+		m_nTargetSlotNo = 0;
+	}
+
+	CJobDataS::~CJobDataS()
+	{
+
+	}
+
+	int CJobDataS::getCassetteSequenceNo()
+	{
+		return m_nCassetteSequenceNo;
+	}
+
+	void CJobDataS::setCassetteSequenceNo(int no)
+	{
+		m_nCassetteSequenceNo = no;
+	}
+
+	int CJobDataS::getJobSequenceNo()
+	{
+		return m_nJobSequenceNo;
+	}
+
+	void CJobDataS::setJobSequenceNo(int no)
+	{
+		m_nJobSequenceNo = no;
+	}
+
+	std::string& CJobDataS::getLotId()
+	{
+		return m_strLotId;
+	}
+
+	void CJobDataS::setLotId(const char* pszId)
+	{
+		m_strLotId = pszId;
+	}
+
+	std::string& CJobDataS::getProductId()
+	{
+		return m_strProductId;
+	}
+
+	void CJobDataS::setProductId(const char* pszId)
+	{
+		m_strProductId = pszId;
+	}
+
+	std::string& CJobDataS::getOperationId()
+	{
+		return m_strOperationId;
+	}
+
+	void CJobDataS::setOperationId(const char* pszId)
+	{
+		m_strOperationId = pszId;
+	}
+
+	std::string& CJobDataS::getGlass1Id()
+	{
+		return m_strGlass1Id;
+	}
+
+	void CJobDataS::setGlass1Id(const char* pszId)
+	{
+		m_strGlass1Id = pszId;
+	}
+
+	std::string& CJobDataS::getGlass2Id()
+	{
+		return m_strGlass1Id;
+	}
+
+	void CJobDataS::setGlass2Id(const char* pszId)
+	{
+		m_strGlass2Id = pszId;
+	}
+
+	int CJobDataS::getJobType()
+	{
+		return m_nJobType;
+	}
+
+	void CJobDataS::setJobType(int type)
+	{
+		m_nJobType = type;
+	}
+
+	int CJobDataS::getMaterialsType()
+	{
+		return m_nMaterialsType;
+	}
+
+	void CJobDataS::setMaterialsType(int type)
+	{
+		m_nMaterialsType = type;
+	}
+
+	int CJobDataS::getProductType()
+	{
+		return m_nProductType;
+	}
+
+	void CJobDataS::setProductType(int type)
+	{
+		m_nProductType = type;
+	}
+
+	int CJobDataS::getDummyType()
+	{
+		return m_nDummyType;
+	}
+
+	void CJobDataS::setDummyType(int type)
+	{
+		m_nDummyType = type;
+	}
+
+	int CJobDataS::getSkipFlag()
+	{
+		return m_nSkipFlag;
+	}
+
+	void CJobDataS::setSkipFlag(int flag)
+	{
+		m_nSkipFlag = flag;
+	}
+
+	int CJobDataS::getProcessFlag()
+	{
+		return m_nProcessFlag;
+	}
+
+	void CJobDataS::setProcessFlag(int flag)
+	{
+		m_nProcessFlag = flag;
+	}
+
+	int CJobDataS::getProcessResonCode()
+	{
+		return m_nProcessResonCode;
+	}
+
+	void CJobDataS::setProcessResonCode(int code)
+	{
+		m_nProcessResonCode = code;
+	}
+
+	int CJobDataS::getLastGlassFlag()
+	{
+		return m_nLastGlassFlag;
+	}
+
+	void CJobDataS::setLastGlassFlag(int flag)
+	{
+		m_nLastGlassFlag = flag;
+	}
+
+	int CJobDataS::getFirstGlassFlag()
+	{
+		return m_nFirstGlassFlag;
+	}
+
+	void CJobDataS::setFirstGlassFlag(int flag)
+	{
+		m_nFirstGlassFlag = flag;
+	}
+
+	int CJobDataS::getQTime(int index)
+	{
+		if (0 <= index && index <= 2) {
+			return m_nQTime[index];
+		}
+
+		return 0;
+	}
+
+	void CJobDataS::setQTime(int index, int time)
+	{
+		if (0 <= index && index <= 2) {
+			m_nQTime[index] = time;
+		}
+	}
+
+	int CJobDataS::getQTimeOverFlag()
+	{
+		return m_nQTimeOverFlag;
+	}
+
+	void CJobDataS::setQTimeOverFlag(int flag)
+	{
+		m_nQTimeOverFlag = flag;
+	}
+
+	int CJobDataS::getMasterRecipe()
+	{
+		return m_nMasterRecipe;
+	}
+
+	void CJobDataS::setMasterRecipe(int recipe)
+	{
+		m_nMasterRecipe = recipe;
+	}
+
+	std::string& CJobDataS::getProductRecipeId()
+	{
+		return m_strProductRecipeId;
+	}
+
+	void CJobDataS::setProductRecipeId(const char* pszId)
+	{
+		m_strProductRecipeId = pszId;
+	}
+
+	std::string& CJobDataS::getPCode()
+	{
+		return m_strPCode;
+	}
+
+	void CJobDataS::setPCode(const char* pszCode)
+	{
+		m_strPCode = pszCode;
+	}
+
+	std::string& CJobDataS::getUseType()
+	{
+		return m_strPCode;
+	}
+
+	void CJobDataS::setUseType(const char* pszType)
+	{
+		m_strPCode = pszType;
+	}
+
+	std::string& CJobDataS::getPanelMeasure()
+	{
+		return m_strPanelMeasure;
+	}
+
+	void CJobDataS::setPanelMeasure(const char* pszMeasure)
+	{
+		m_strPanelMeasure = pszMeasure;
+	}
+
+	int CJobDataS::getMode()
+	{
+		return m_nMode;
+	}
+
+	void CJobDataS::setMode(int mode)
+	{
+		m_nMode = mode;
+	}
+
+	int CJobDataS::getSlotUnitSelectFlag()
+	{
+		return m_nSlotUnitSelectFlag;
+	}
+
+	void CJobDataS::setSlotUnitSelectFlag(int flag)
+	{
+		m_nSlotUnitSelectFlag = flag;
+	}
+
+	int CJobDataS::getSourcePortNo()
+	{
+		return m_nSourcePortNo;
+	}
+
+	void CJobDataS::setSourcePortNo(int no)
+	{
+		m_nSourcePortNo = no;
+	}
+
+	int CJobDataS::getSourceSlotNo()
+	{
+		return m_nSourceSlotNo;
+	}
+
+	void CJobDataS::setSourceSlotNo(int no)
+	{
+		m_nSourceSlotNo = no;
+	}
+
+	int CJobDataS::getTargetPortNo()
+	{
+		return m_nTargetPortNo;
+	}
+
+	void CJobDataS::setTargetPortNo(int no)
+	{
+		m_nTargetPortNo = no;
+	}
+
+	int CJobDataS::getTargetSlotNo()
+	{
+		return m_nTargetSlotNo;
+	}
+
+	void CJobDataS::setTargetSlotNo(int no)
+	{
+		m_nTargetSlotNo = no;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CJobDataS.h b/SourceCode/Bond/Servo/CJobDataS.h
new file mode 100644
index 0000000..a2e3964
--- /dev/null
+++ b/SourceCode/Bond/Servo/CJobDataS.h
@@ -0,0 +1,103 @@
+#pragma once
+
+
+namespace SERVO {
+	class CJobDataS
+	{
+	public:
+		CJobDataS();
+		~CJobDataS();
+
+	public:
+		int getCassetteSequenceNo();
+		void setCassetteSequenceNo(int no);
+		int getJobSequenceNo();
+		void setJobSequenceNo(int no);
+		std::string& getLotId();
+		void setLotId(const char* pszId);
+		std::string& getProductId();
+		void setProductId(const char* pszId);
+		std::string& getOperationId();
+		void setOperationId(const char* pszId);
+		std::string& getGlass1Id();
+		void setGlass1Id(const char* pszId);
+		std::string& getGlass2Id();
+		void setGlass2Id(const char* pszId);
+		int getJobType();
+		void setJobType(int type);
+		int getMaterialsType();
+		void setMaterialsType(int type);
+		int getProductType();
+		void setProductType(int type);
+		int getDummyType();
+		void setDummyType(int type);
+		int getSkipFlag();
+		void setSkipFlag(int flag);
+		int getProcessFlag();
+		void setProcessFlag(int flag);
+		int getProcessResonCode();
+		void setProcessResonCode(int code);
+		int getLastGlassFlag();
+		void setLastGlassFlag(int flag);
+		int getFirstGlassFlag();
+		void setFirstGlassFlag(int flag);
+		int getQTime(int index);
+		void setQTime(int index, int time);
+		int getQTimeOverFlag();
+		void setQTimeOverFlag(int flag);
+		int getMasterRecipe();
+		void setMasterRecipe(int recipe);
+		std::string& getProductRecipeId();
+		void setProductRecipeId(const char* pszId);
+		std::string& getPCode();
+		void setPCode(const char* pszCode);
+		std::string& getUseType();
+		void setUseType(const char* pszType);
+		std::string& getPanelMeasure();
+		void setPanelMeasure(const char* pszMeasure);
+		int getMode();
+		void setMode(int mode);
+		int getSlotUnitSelectFlag();
+		void setSlotUnitSelectFlag(int flag);
+		int getSourcePortNo();
+		void setSourcePortNo(int no);
+		int getSourceSlotNo();
+		void setSourceSlotNo(int no);
+		int getTargetPortNo();
+		void setTargetPortNo(int no);
+		int getTargetSlotNo();
+		void setTargetSlotNo(int no);
+
+	private:
+		int m_nCassetteSequenceNo;
+		int m_nJobSequenceNo;
+		std::string m_strLotId;
+		std::string m_strProductId;
+		std::string m_strOperationId;
+		std::string m_strGlass1Id;
+		std::string m_strGlass2Id;
+		int m_nJobType;
+		int m_nMaterialsType;
+		int m_nProductType;
+		int m_nDummyType;
+		int m_nSkipFlag;
+		int m_nProcessFlag;
+		int m_nProcessResonCode;
+		int m_nLastGlassFlag;
+		int m_nFirstGlassFlag;
+		int m_nQTime[3];
+		int m_nQTimeOverFlag;
+		int m_nMasterRecipe;
+		std::string m_strProductRecipeId;
+		std::string m_strPCode;
+		std::string m_strUseType;
+		std::string m_strPanelMeasure;
+		int m_nMode;
+		int m_nSlotUnitSelectFlag;
+		int m_nSourcePortNo;
+		int m_nSourceSlotNo;
+		int m_nTargetPortNo;
+		int m_nTargetSlotNo;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CLoadPort.cpp b/SourceCode/Bond/Servo/CLoadPort.cpp
index b881e5a..32ee535 100644
--- a/SourceCode/Bond/Servo/CLoadPort.cpp
+++ b/SourceCode/Bond/Servo/CLoadPort.cpp
@@ -2,10 +2,24 @@
 #include "CLoadPort.h"
 
 
+#define CHECK_READ_STEP_SIGNAL2(addr, data, size) {							\
+	BOOL bFlag = isBitOn(data, size, addr);									\
+	SERVO::CStep* pStep = getStep(addr);									\
+	if (pStep != nullptr) {													\
+		((CReadStep*)pStep)->onReadSignal(bFlag ? addr : 0);				\
+	}																		\
+}
+
 namespace SERVO {
 	CLoadPort::CLoadPort() : CEquipment()
 	{
-
+		m_nIndex = 0;
+		m_nType = 1;
+		m_nMode = 1;
+		m_nCassetteType = 1;
+		m_nTransferMode = 1;
+		m_bEnable = FALSE;
+		m_bAutoChangeEnable = FALSE;
 	}
 
 	CLoadPort::~CLoadPort()
@@ -39,6 +53,120 @@
 		addPin(SERVO::PinType::OUTPUT, _T("Out2"));
 	}
 
+	void CLoadPort::initSteps()
+	{
+		CEquipment::initSteps();
+
+
+		ASSERT(m_nIndex == 0 || m_nIndex == 1 || m_nIndex == 2 || m_nIndex == 3);
+
+		{
+			// Cassette Ctrl Cmd
+			static char* pszName[] = { STEP_EQ_P1_CASSETTE_CTRL_CMD,	STEP_EQ_P2_CASSETTE_CTRL_CMD, STEP_EQ_P3_CASSETTE_CTRL_CMD,	STEP_EQ_P4_CASSETTE_CTRL_CMD };
+			static int writeSignalDev[] = { 0x120, 0x121, 0x122, 0x123 };
+			static int dev[] = { 0x45, 0x1a5, 0x305, 0x465 };
+			static int addr[] = { 0x480, 0x481, 0x482, 0x483 };
+
+			CEqCassetteCtrlCmdStep* pStep = new CEqCassetteCtrlCmdStep();
+			pStep->setName(pszName[m_nIndex]);
+			pStep->setWriteSignalDev(writeSignalDev[m_nIndex]);
+			pStep->setCtrlCmdDev(dev[m_nIndex]);
+			if (addStep(addr[m_nIndex], pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Type
+			static char* pszName[] = { STEP_EQ_PORT1_TYPE, STEP_EQ_PORT2_TYPE, STEP_EQ_PORT3_TYPE, STEP_EQ_PORT4_TYPE };
+			static int dev[] = { 0x6010 , 0x6020, 0x6030, 0x6040 };
+			static int writeSignalDev[] = { 0xa0, 0xa1, 0xa2, 0xa3 };
+			static int addr[] = { STEP_ID_PORT1_TYPE_CHANGE, STEP_ID_PORT2_TYPE_CHANGE, STEP_ID_PORT3_TYPE_CHANGE, STEP_ID_PORT4_TYPE_CHANGE };
+
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, dev[m_nIndex]);
+			pStep->setName(pszName[m_nIndex]);
+			pStep->setWriteSignalDev(writeSignalDev[m_nIndex]);
+			if (addStep(addr[m_nIndex], pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Mode
+			static char* pszName[] = { STEP_EQ_PORT1_MODE, STEP_EQ_PORT2_MODE, STEP_EQ_PORT3_MODE, STEP_EQ_PORT4_MODE };
+			static int dev[] = { 0x6011, 0x6021, 0x6031, 0x6041 };
+			static int writeSignalDev[] = { 0xa8, 0xa9, 0xaa, 0xab };
+			static int addr[] = { STEP_ID_PORT1_MODE_CHANGE, STEP_ID_PORT2_MODE_CHANGE, STEP_ID_PORT3_MODE_CHANGE, STEP_ID_PORT4_MODE_CHANGE };
+
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, dev[m_nIndex]);
+			pStep->setName(pszName[m_nIndex]);
+			pStep->setWriteSignalDev(writeSignalDev[m_nIndex]);
+			if (addStep(addr[m_nIndex], pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Cassette type
+			static char* pszName[] = { STEP_EQ_PORT1_CASSETTE_TYPE, STEP_EQ_PORT2_CASSETTE_TYPE, STEP_EQ_PORT3_CASSETTE_TYPE, STEP_EQ_PORT4_CASSETTE_TYPE };
+			static int dev[] = { 0x6012, 0x6022, 0x6032, 0x6042 };
+			static int writeSignalDev[] = { 0xb0, 0xb1, 0xb2, 0xb3 };
+			static int addr[] = { STEP_ID_PORT1_CASSETTE_TYPE_CHANGE, STEP_ID_PORT2_CASSETTE_TYPE_CHANGE, STEP_ID_PORT3_CASSETTE_TYPE_CHANGE, STEP_ID_PORT4_CASSETTE_TYPE_CHANGE };
+
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, dev[m_nIndex]);
+			pStep->setName(pszName[m_nIndex]);
+			pStep->setWriteSignalDev(writeSignalDev[m_nIndex]);
+			if (addStep(addr[m_nIndex], pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Transfer type
+			static char* pszName[] = { STEP_EQ_PORT1_TRANSFER_MODE, STEP_EQ_PORT2_TRANSFER_MODE, STEP_EQ_PORT3_TRANSFER_MODE, STEP_EQ_PORT4_TRANSFER_MODE };
+			static int dev[] = { 0x6014, 0x6024, 0x6034, 0x6044 };
+			static int writeSignalDev[] = { 0xb8, 0xb9, 0xba, 0xbb };
+			static int addr[] = { STEP_ID_PORT1_TRANSFER_MODE_CHANGE, STEP_ID_PORT2_TRANSFER_MODE_CHANGE, STEP_ID_PORT3_TRANSFER_MODE_CHANGE, STEP_ID_PORT4_TRANSFER_MODE_CHANGE };
+
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, dev[m_nIndex]);
+			pStep->setName(pszName[m_nIndex]);
+			pStep->setWriteSignalDev(writeSignalDev[m_nIndex]);
+			if (addStep(addr[m_nIndex], pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Port enable
+			static char* pszName[] = { STEP_EQ_PORT1_ENABLE, STEP_EQ_PORT2_ENABLE, STEP_EQ_PORT3_ENABLE, STEP_EQ_PORT4_ENABLE };
+			static int dev[] = { 0x6015, 0x6025, 0x6035, 0x6045 };
+			static int writeSignalDev[] = { 0xc0, 0xc1, 0xc2, 0xc3 };
+			static int addr[] = { STEP_ID_PORT1_ENABLE_MODE_CHANGE, STEP_ID_PORT2_ENABLE_MODE_CHANGE, STEP_ID_PORT3_ENABLE_MODE_CHANGE, STEP_ID_PORT4_ENABLE_MODE_CHANGE };
+
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, dev[m_nIndex]);
+			pStep->setName(pszName[m_nIndex]);
+			pStep->setWriteSignalDev(writeSignalDev[m_nIndex]);
+			if (addStep(addr[m_nIndex], pStep) != 0) {
+				delete pStep;
+			}
+		}
+
+		{
+			// Type auto change
+			char* pszName[] = { STEP_EQ_PORT1_TYPE_ATUO, STEP_EQ_PORT2_TYPE_ATUO, STEP_EQ_PORT3_TYPE_ATUO, STEP_EQ_PORT4_TYPE_ATUO };
+			static int dev[] = { 0x6016, 0x6026, 0x6036, 0x6046 };
+			static int writeSignalDev[] = { 0xc8, 0xc9, 0xca, 0xcb };
+			static int addr[] = { STEP_ID_PORT1_TYPE_AUTO_CHANGE, STEP_ID_PORT2_TYPE_AUTO_CHANGE, STEP_ID_PORT3_TYPE_AUTO_CHANGE, STEP_ID_PORT4_TYPE_AUTO_CHANGE };
+
+			CEqReadIntStep* pStep = new CEqReadIntStep(__INT16, dev[m_nIndex]);
+			pStep->setName(pszName[m_nIndex]);
+			pStep->setWriteSignalDev(writeSignalDev[m_nIndex]);
+			if (addStep(addr[m_nIndex], pStep) != 0) {
+				delete pStep;
+			}
+		}
+	}
+
 	void CLoadPort::onTimer(UINT nTimerid)
 	{
 		CEquipment::onTimer(nTimerid);
@@ -52,6 +180,22 @@
 	void CLoadPort::getAttributeVector(CAttributeVector& attrubutes)
 	{
 		__super::getAttributeVector(attrubutes);
+
+		std::string strTemp;
+		attrubutes.addAttribute(new CAttribute("Index",
+			std::to_string(m_nIndex).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("Type",
+			getPortTypeDescription(m_nType, strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("Mode",
+			getPortModeDescription(m_nMode, strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("CassetteType",
+			getPortCassetteTypeDescription(m_nCassetteType, strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("TransferMode",
+			getPortTransferModeDescription(m_nTransferMode, strTemp).c_str(), ""));
+		attrubutes.addAttribute(new CAttribute("Enable",
+			m_bEnable ? "Eanble" : "Disable", ""));
+		attrubutes.addAttribute(new CAttribute("Auto Change",
+			m_bAutoChangeEnable ? "Eanble" : "Disable", ""));
 	}
 
 	int CLoadPort::recvIntent(CPin* pPin, CIntent* pIntent)
@@ -86,4 +230,288 @@
 
 		return (m_glassList.size() < 8);
 	}
+
+	int CLoadPort::sendCassetteCtrlCmd(short cmd,
+		short* jobExistence,
+		int jobExistenceSize,
+		short slotProcess,
+		short jopCount,
+		CJobDataA* pJobDataA)
+	{
+		int id = getID();
+		if ( !(id == EQ_ID_LOADPORT1 || id == EQ_ID_LOADPORT2) ) {
+			return -1;
+		}
+
+
+		SERVO::CEqCassetteCtrlCmdStep* pStep = (SERVO::CEqCassetteCtrlCmdStep*)getCassetteCtrlCmdStep();
+		ASSERT(pStep);
+		return pStep->sendCtrlCmd(cmd, jobExistence, jobExistenceSize, slotProcess, jopCount, pJobDataA);
+	}
+
+	CStep* CLoadPort::getCassetteCtrlCmdStep()
+	{
+		CStep* pStep = nullptr;
+		Lock();
+		for (auto item : m_mapStep) {
+			if (item.second->getName().find(STEP_EQ_P1_CASSETTE_CTRL_CMD) == 0
+				|| item.second->getName().find(STEP_EQ_P2_CASSETTE_CTRL_CMD) == 0
+				|| item.second->getName().find(STEP_EQ_P3_CASSETTE_CTRL_CMD) == 0
+				|| item.second->getName().find(STEP_EQ_P4_CASSETTE_CTRL_CMD) == 0) {
+				pStep = item.second;
+			}
+		}
+		Unlock();
+
+		return pStep;
+	}
+
+	void CLoadPort::setIndex(unsigned int index)
+	{
+		m_nIndex = index;
+	}
+
+	unsigned int CLoadPort::getIndex()
+	{
+		return m_nIndex;
+	}
+
+	BOOL CLoadPort::isEnable()
+	{
+		return m_bEnable;
+	}
+
+	int CLoadPort::getPortType()
+	{
+		return m_nType;
+	}
+
+	int CLoadPort::getPortMode()
+	{
+		return m_nMode;
+	}
+
+	int CLoadPort::getCessetteType()
+	{
+		return m_nCassetteType;
+	}
+
+	int CLoadPort::getTransferMode()
+	{
+		return m_nTransferMode;
+	}
+
+	BOOL CLoadPort::isAutoChange()
+	{
+		return m_bAutoChangeEnable;
+	}
+
+	/*
+	 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& CLoadPort::getPortTypeDescription(int portType, std::string& strDescription)
+	{
+		switch (portType) {
+		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& CLoadPort::getPortModeDescription(int portMode, std::string& strDescription)
+	{
+		switch (portMode) {
+		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& CLoadPort::getPortCassetteTypeDescription(int casseteType, std::string& strDescription)
+	{
+		switch (casseteType) {
+		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& CLoadPort::getPortTransferModeDescription(int mode, std::string& strDescription)
+	{
+		switch (mode) {
+		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& CLoadPort::getEnableModeDescription(int mode, std::string& strDescription)
+	{
+		switch (mode) {
+		case 1:
+			strDescription = _T("Enable");
+			break;
+		case 2:
+			strDescription = _T("Disable");
+			break;
+		default:
+			strDescription = _T("");
+			break;
+		}
+
+		return strDescription;
+	}
+
+	void CLoadPort::onReceiveLBData(const char* pszData, size_t size)
+	{
+		static int type[] = { STEP_ID_PORT1_TYPE_CHANGE, STEP_ID_PORT2_TYPE_CHANGE,
+			STEP_ID_PORT3_TYPE_CHANGE, STEP_ID_PORT4_TYPE_CHANGE };
+		static int mode[] = { STEP_ID_PORT1_MODE_CHANGE, STEP_ID_PORT2_MODE_CHANGE,
+			STEP_ID_PORT3_MODE_CHANGE, STEP_ID_PORT4_MODE_CHANGE };
+		static int cassetteType[] = { STEP_ID_PORT1_CASSETTE_TYPE_CHANGE, STEP_ID_PORT2_CASSETTE_TYPE_CHANGE,
+			STEP_ID_PORT3_CASSETTE_TYPE_CHANGE, STEP_ID_PORT4_CASSETTE_TYPE_CHANGE };
+		static int transferMode[] = { STEP_ID_PORT1_TRANSFER_MODE_CHANGE, STEP_ID_PORT2_TRANSFER_MODE_CHANGE,
+			STEP_ID_PORT3_TRANSFER_MODE_CHANGE, STEP_ID_PORT4_TRANSFER_MODE_CHANGE };
+		static int enable[] = { STEP_ID_PORT1_ENABLE_MODE_CHANGE, STEP_ID_PORT2_ENABLE_MODE_CHANGE,
+			STEP_ID_PORT3_ENABLE_MODE_CHANGE, STEP_ID_PORT4_ENABLE_MODE_CHANGE };
+		static int autoType[] = { STEP_ID_PORT1_TYPE_AUTO_CHANGE, STEP_ID_PORT2_TYPE_AUTO_CHANGE,
+			STEP_ID_PORT3_TYPE_AUTO_CHANGE, STEP_ID_PORT4_TYPE_AUTO_CHANGE };
+
+		CHECK_READ_STEP_SIGNAL2(type[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL2(mode[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL2(cassetteType[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL2(transferMode[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL2(enable[m_nIndex], pszData, size);
+		CHECK_READ_STEP_SIGNAL2(autoType[m_nIndex], pszData, size);
+	}
+
+	int CLoadPort::onStepEvent(CStep* pStep, int code)
+	{
+		int nRet = CEquipment::onStepEvent(pStep, code);
+		if (nRet > 0) return nRet;
+
+		if (code == STEP_EVENT_READDATA) {
+			if (isPortTypeStep(pStep)) {
+				SERVO::CEqReadIntStep* pReadIntStep = (SERVO::CEqReadIntStep*)pStep;
+				m_nType = pReadIntStep->getValue();
+			}
+			else if(isPortModeStep(pStep)) {
+				SERVO::CEqReadIntStep* pReadIntStep = (SERVO::CEqReadIntStep*)pStep;
+				m_nMode = pReadIntStep->getValue();
+			}
+			else if (isPortCassetteTypeStep(pStep)) {
+				SERVO::CEqReadIntStep* pReadIntStep = (SERVO::CEqReadIntStep*)pStep;
+				m_nCassetteType = pReadIntStep->getValue();
+			}
+			else if (isPortTransferModeStep(pStep)) {
+				SERVO::CEqReadIntStep* pReadIntStep = (SERVO::CEqReadIntStep*)pStep;
+				m_nTransferMode = pReadIntStep->getValue();
+			}
+			else if (isPortEnableStep(pStep)) {
+				SERVO::CEqReadIntStep* pReadIntStep = (SERVO::CEqReadIntStep*)pStep;
+				m_bEnable = pReadIntStep->getValue() == 1;
+			}
+			else if (isPortTypeAutoChangeEnableStep(pStep)) {
+				SERVO::CEqReadIntStep* pReadIntStep = (SERVO::CEqReadIntStep*)pStep;
+				m_bAutoChangeEnable = pReadIntStep->getValue() == 1;
+			}
+		}
+
+
+		return 0;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CLoadPort.h b/SourceCode/Bond/Servo/CLoadPort.h
index 3fa8afd..ae63fe7 100644
--- a/SourceCode/Bond/Servo/CLoadPort.h
+++ b/SourceCode/Bond/Servo/CLoadPort.h
@@ -15,14 +15,50 @@
 		virtual void init();
 		virtual void term();
 		virtual void initPins();
+		virtual void initSteps();
 		virtual void onTimer(UINT nTimerid);
 		virtual void serialize(CArchive& ar);
 		virtual void getAttributeVector(CAttributeVector& attrubutes);
 		virtual int recvIntent(CPin* pPin, CIntent* pIntent);
 		virtual BOOL glassWillArrive(CGlass* pGlass);
+		virtual void onReceiveLBData(const char* pszData, size_t size);
+		virtual int onStepEvent(CStep* pStep, int code);
+
+	public:
+		void setIndex(unsigned int index);
+		unsigned int getIndex();
+		BOOL isEnable();
+		int getPortType();
+		int getPortMode();
+		int getCessetteType();
+		int getTransferMode();
+		BOOL isAutoChange();
+
+	public:
+		static std::string& getPortTypeDescription(int portType, std::string& strDescription);
+		static std::string& getPortModeDescription(int portMode, std::string& strDescription);
+		static std::string& getPortCassetteTypeDescription(int casseteType, std::string& strDescription);
+		static std::string& getPortTransferModeDescription(int mode, std::string& strDescription);
+		static std::string& getEnableModeDescription(int mode, std::string& strDescription);
 
 	public:
 		virtual int outputGlass(int port);
+		int sendCassetteCtrlCmd(short cmd,
+			short* jobExistence,
+			int jobExistenceSize,
+			short slotProcess,
+			short jopCount,
+			CJobDataA* pJobDataA);
+		CStep* getCassetteCtrlCmdStep();
+
+	private:
+		unsigned int m_nIndex;
+		int m_nType;
+		int m_nMode;
+		int m_nCassetteType;
+		int m_nTransferMode;
+		BOOL m_bEnable;
+		BOOL m_bAutoChangeEnable;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index fff1ab0..40f4705 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -3,18 +3,18 @@
 #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;
+
+	unsigned __stdcall ReadBitsThreadFunction(LPVOID lpParam)
+	{
+		if (g_pMaster != NULL) {
+			return g_pMaster->ReadBitsProc();
+		}
+
+		return 0;
+	}
+
 	void CALLBACK MasterTimerProc(HWND hWnd, UINT nMsg, UINT nTimerid, DWORD dwTime)
 	{
 		if (g_pMaster != NULL) {
@@ -24,8 +24,12 @@
 
 	CMaster::CMaster()
 	{
-		m_listener = {nullptr, nullptr, nullptr};
+		m_listener = {nullptr, nullptr, nullptr, nullptr};
 		m_bDataModify = FALSE;
+		m_hEventReadBitsThreadExit[0] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+		m_hEventReadBitsThreadExit[1] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+		m_hReadBitsThreadHandle = nullptr;
+		m_nReadBitsThreadAddr = 0;
 	}
 
 	CMaster::~CMaster()
@@ -34,6 +38,16 @@
 			delete item;
 		}
 		m_listEquipment.clear();
+
+		if (m_hEventReadBitsThreadExit[0] != nullptr) {
+			::CloseHandle(m_hEventReadBitsThreadExit[0]);
+			m_hEventReadBitsThreadExit[0] = nullptr;
+		}
+
+		if (m_hEventReadBitsThreadExit[1] != nullptr) {
+			::CloseHandle(m_hEventReadBitsThreadExit[1]);
+			m_hEventReadBitsThreadExit[1] = nullptr;
+		}
 	}
 
 	void CMaster::setListener(MasterListener listener)
@@ -41,6 +55,7 @@
 		m_listener.onEqAlive = listener.onEqAlive;
 		m_listener.onEqCimStateChanged = listener.onEqCimStateChanged;
 		m_listener.onEqAlarm = listener.onEqAlarm;
+		m_listener.onEqVcrEventReport = listener.onEqVcrEventReport;
 	}
 
 	int CMaster::init()
@@ -75,14 +90,21 @@
 
 
 		// 初始化添加各子设备
-		addLoadPort(0);
-		addLoadPort(1);
-		addLoadPort(2);
-		addLoadPort(3);
+		CLoadPort* pPort1, * pPort2, * pPort3, * pPort4;
+		CEFEM* pEfem;
+		pPort1 = addLoadPort(0);
+		pPort2 = addLoadPort(1);
+		pPort3 = addLoadPort(2);
+		pPort4 = addLoadPort(3);
+		pEfem = addEFEM();
+		pEfem->setPort(0, pPort1);
+		pEfem->setPort(1, pPort1);
+		pEfem->setPort(2, pPort1);
+		pEfem->setPort(3, pPort1);
+
 		addFliper();
 		addVacuumBake();
 		addAligner();
-		addEFEM();
 		addBonder(0);
 		addBonder(1);
 		addBakeCooling();
@@ -98,12 +120,19 @@
 		SetTimer(NULL, 1, 250, (TIMERPROC)MasterTimerProc);
 
 
+		m_hReadBitsThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadBitsThreadFunction, this,
+			0, &m_nReadBitsThreadAddr);
+
+
 		LOGI("<Master>初始化完成.");
 		return 0;
 	}
 
 	int CMaster::term()
 	{
+		SetEvent(m_hEventReadBitsThreadExit[0]);
+		::WaitForSingleObject(m_hEventReadBitsThreadExit[1], INFINITE);
+
 		LOGI("<Master>正在结束程序.");
 		for (auto item : m_listEquipment) {
 			item->term();
@@ -111,6 +140,39 @@
 		saveCache();
 
 
+
+		return 0;
+	}
+
+	unsigned CMaster::ReadBitsProc()
+	{
+		while (1) {
+			// 待退出信号或时间到
+			int nRet = ::WaitForSingleObject(m_hEventReadBitsThreadExit[0], 1000);
+			if (nRet == WAIT_OBJECT_0) {
+				break;
+			}
+
+			for (auto item : m_listEquipment) {
+				if (item->getID() == EQ_ID_Bonder1 ||
+					item->getID() == EQ_ID_Bonder2) {
+					const StationIdentifier& station = item->getStation();
+					MemoryBlock& block = item->getReadBitBlock();
+
+					int nRet = m_cclink.ReadData2(station, (DeviceType)block.type,
+						block.start, block.size, block.buffer);
+					if (0 == nRet) {
+						item->onReceiveLBData(block.buffer, block.size);
+					}
+				}
+			}
+		}
+
+		SetEvent(m_hEventReadBitsThreadExit[1]);
+
+
+		// _endthreadex(0);
+		TRACE("CMaster::ReadBitsProc 线程退出\n");
 		return 0;
 	}
 
@@ -133,6 +195,13 @@
 			CEquipment* p = (CEquipment*)pEquipment;
 			if (m_listener.onEqAlarm != nullptr) {
 				m_listener.onEqAlarm(this, p, state, alarmId, unitId, level);
+			}
+		};
+		listener.onVcrEventReport = [&](void* pEquipment, void* pReport) -> void {
+			CEquipment* p = (CEquipment*)pEquipment;
+			CVcrEventReport* p2 = (CVcrEventReport*)pReport;
+			if (m_listener.onEqVcrEventReport != nullptr) {
+				m_listener.onEqVcrEventReport(this, p, p2);
 			}
 		};
 		listener.onDataChanged = [&](void* pEquipment, int code) -> void {
@@ -160,25 +229,30 @@
 		return nullptr;
 	}
 
-	/* 添加LoadPort1
+	/*
+	 * 添加LoadPort1
 	 * index -- 0~3
 	 */
-	int CMaster::addLoadPort(int index)
+	CLoadPort* CMaster::addLoadPort(int index)
 	{
 		ASSERT(index == 0 || index == 1 || index == 2 || index == 3);
+
+
 		char szName[64];
 		sprintf_s(szName, 64, "LoadPort %d", index + 1);
 		CLoadPort* pEquipment = new CLoadPort();
+		pEquipment->setIndex(index);
 		pEquipment->setID(EQ_ID_LOADPORT1 + index);
 		pEquipment->setName(szName);
 		pEquipment->setDescription(szName);
 		addToEquipmentList(pEquipment);
 
+
 		pEquipment->init();
 		LOGE("已添加“%s”.", pEquipment->getName().c_str());
 
 
-		return 0;
+		return pEquipment;
 	}
 
 	int CMaster::addFliper()
@@ -232,400 +306,22 @@
 		return 0;
 	}
 
-	int CMaster::addEFEM()
+	CEFEM* CMaster::addEFEM()
 	{
 		CEFEM* pEquipment = new CEFEM();
 		pEquipment->setID(EQ_ID_EFEM);
 		pEquipment->setBaseAlarmId(BASE_ALARM_EFEM);
 		pEquipment->setName("EFEM(ROBOT)");
 		pEquipment->setDescription("EFEM(ROBOT).");
-		pEquipment->setReadBitBlock(0x4000, 0x45ff);
+		pEquipment->setReadBitBlock(0x3000, 0x3aff);
 		pEquipment->setStation(0, 255);
 		addToEquipmentList(pEquipment);
 
 
-		// 添加 step
-		{
-			CEqModeStep* pStep = new CEqModeStep();
-			pStep->setName(STEP_MODE);
-			pStep->setWriteSignalDev(0x30);
-			pStep->setModeDev(0x4a8c);
-			if (pEquipment->addStep(0x360, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqStatusStep* pStep = new CEqStatusStep();
-			pStep->setName(STEP_STATUS);
-			pStep->setWriteSignalDev(0x31);
-			pStep->setStatusDev(0x4a68);
-			if (pEquipment->addStep(0x361, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK1);
-			pStep->setWriteSignalDev(0x32);
-			pStep->setAlarmDev(0x4c1d);
-			if (pEquipment->addStep(0x362, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK2);
-			pStep->setWriteSignalDev(0x33);
-			pStep->setAlarmDev(0x4c4a);
-			if (pEquipment->addStep(0x363, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK3);
-			pStep->setWriteSignalDev(0x34);
-			pStep->setAlarmDev(0x4c77);
-			if (pEquipment->addStep(0x364, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK4);
-			pStep->setWriteSignalDev(0x35);
-			pStep->setAlarmDev(0x4ca4);
-			if (pEquipment->addStep(0x365, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK5);
-			pStep->setWriteSignalDev(0x36);
-			pStep->setAlarmDev(0x4cd1);
-			if (pEquipment->addStep(0x366, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqProcessStep* pStep = new CEqProcessStep();
-			pStep->setName(STEP_PROCESS);
-			pStep->setWriteSignalDev(0x37);
-			pStep->setProcessDev(0x5864);
-			if (pEquipment->addStep(0x367, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
-			pStep->setName(STEP_CIM_MODE_CHANGE);
-			pStep->setWriteSignalDev(0x50);
-			pStep->setCimModeDev(0x15);
-			if (pEquipment->addStep(0x350, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
-			pStep->setName(STEP_CIM_MESSAGE_CMD);
-			pStep->setWriteSignalDev(0x51);
-			pStep->setCimMessageDev(0x0);
-			if (pEquipment->addStep(0x351, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqCimMessageClearStep* pStep = new CEqCimMessageClearStep();
-			pStep->setName(STEP_CIM_MESSAGE_CLEAR);
-			pStep->setWriteSignalDev(0x52);
-			pStep->setClearCimMessageDev(0x13);
-			if (pEquipment->addStep(0x352, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqDateTimeSetCmdStep* pStep = new CEqDateTimeSetCmdStep();
-			pStep->setName(STEP_DATETIME_SET_CMD);
-			pStep->setWriteSignalDev(0x53);
-			pStep->setDateTimeDev(0x16);
-			if (pEquipment->addStep(0x353, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqVCREnableStep* pStep = new CEqVCREnableStep();
-			pStep->setName(STEP_EQ_VCR_ENABLE);
-			pStep->setWriteSignalDev(0x54);
-			pStep->setEqVCRModeDev(0x1F);
-			if (pEquipment->addStep(0x354, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqModeChangeStep* pStep = new CEqModeChangeStep();
-			pStep->setName(STEP_EQ_MODE_CHANGE);
-			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)”.");
-		return 0;
+
+		return pEquipment;
 	}
 
 	/* 添加bonder1 或 bonder2 
@@ -639,130 +335,11 @@
 		pEquipment->setID(EQ_ID_Bonder1 + index);
 		pEquipment->setName(index == 0 ? "Bonder 1" : "Bonder 2");
 		pEquipment->setDescription(index == 0 ? "Bonder 1." : "Bonder 2.");
-		pEquipment->setStation(1, index == 0 ? 3 : 4);
-		pEquipment->setReadBitBlock(index == 0 ? 0x4600 : 0x4c00,
-			index == 0 ? 0x4c00 : 0x5200);
+		pEquipment->setStation(0, 255);
+		pEquipment->setReadBitBlock(index == 0 ? 0x3b00 : 0x4600,
+			index == 0 ? 0x5600 : 0x6100);
+		pEquipment->setIndex(index);
 		addToEquipmentList(pEquipment);
-
-
-		// 添加 step
-		{
-			CEqModeStep* pStep = new CEqModeStep();
-			pStep->setName(STEP_MODE);
-			pStep->setWriteSignalDev(index == 0 ? 0x330 : 0x630);
-			pStep->setModeDev(index == 0 ? 0x6a8c : 0x848c);
-			if (pEquipment->addStep(0x360, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqStatusStep* pStep = new CEqStatusStep();
-			pStep->setName(STEP_STATUS);
-			pStep->setWriteSignalDev(index == 0 ? 0x331 : 0x631);
-			pStep->setStatusDev(index == 0 ? 0x6a68 : 0x8a68);
-			if (pEquipment->addStep(0x361, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK1);
-			pStep->setWriteSignalDev(index == 0 ? 0x332 : 0x632);
-			pStep->setAlarmDev(index == 0 ? 0x6c1d : 0x8c1d);
-			if (pEquipment->addStep(0x362, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK2);
-			pStep->setWriteSignalDev(index == 0 ? 0x333 : 0x633);
-			pStep->setAlarmDev(index == 0 ? 0x6c4a : 0x8c4a);
-			if (pEquipment->addStep(0x363, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK3);
-			pStep->setWriteSignalDev(index == 0 ? 0x334 : 0x634);
-			pStep->setAlarmDev(index == 0 ? 0x6c77 : 0x8c77);
-			if (pEquipment->addStep(0x364, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK4);
-			pStep->setWriteSignalDev(index == 0 ? 0x335 : 0x635);
-			pStep->setAlarmDev(index == 0 ? 0x6ca4 : 0x8ca4);
-			if (pEquipment->addStep(0x365, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqAlarmStep* pStep = new CEqAlarmStep();
-			pStep->setName(STEP_ALARM_BLOCK5);
-			pStep->setWriteSignalDev(index == 0 ? 0x336 : 0x636);
-			pStep->setAlarmDev(index == 0 ? 0x6cd1 : 0x8cd1);
-			if (pEquipment->addStep(0x366, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqProcessStep* pStep = new CEqProcessStep();
-			pStep->setName(STEP_PROCESS);
-			pStep->setWriteSignalDev(index == 0 ? 0x337 : 0x637);
-			pStep->setProcessDev(index == 0 ? 0x7864 : 0x9864);
-			if (pEquipment->addStep(0x367, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
-			pStep->setName(STEP_CIM_MODE_CHANGE);
-			pStep->setWriteSignalDev(index == 0 ? 0x350 : 0x650);
-			pStep->setCimModeDev(index == 0 ? 0x965 : 0x12b5);
-			if (pEquipment->addStep(0x350, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqCimMessageCmdStep* pStep = new CEqCimMessageCmdStep();
-			pStep->setName(STEP_CIM_MESSAGE_CMD);
-			pStep->setWriteSignalDev(index == 0 ? 0x351 : 0x651);
-			pStep->setCimMessageDev(index == 0 ? 0x950 : 0x12a0);
-			if (pEquipment->addStep(0x351, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqCimMessageClearStep* pStep = new CEqCimMessageClearStep();
-			pStep->setName(STEP_CIM_MESSAGE_CLEAR);
-			pStep->setWriteSignalDev(index == 0 ? 0x352 : 0x652);
-			pStep->setClearCimMessageDev(index == 0 ? 0x963 : 0x12b3);
-			if (pEquipment->addStep(0x352, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqDateTimeSetCmdStep* pStep = new CEqDateTimeSetCmdStep();
-			pStep->setName(STEP_DATETIME_SET_CMD);
-			pStep->setWriteSignalDev(index == 0 ? 0x353 : 0x653);
-			pStep->setDateTimeDev(index == 0 ? 0x966 : 0x12b6);
-			if (pEquipment->addStep(0x353, pStep) != 0) {
-				delete pStep;
-			}
-		}
-		{
-			CEqModeChangeStep* pStep = new CEqModeChangeStep();
-			pStep->setName(STEP_EQ_MODE_CHANGE);
-			pStep->setWriteSignalDev(index == 0 ? 0x355 : 0x655);
-			pStep->setEqModeDev(index == 0 ? 0x96E : 0x12be);
-			if (pEquipment->addStep(0x355, pStep) != 0) {
-				delete pStep;
-			}
-		}
 
 
 		pEquipment->init();
@@ -799,19 +376,23 @@
 		// 按一定频率扫描LB数据
 		static int i = 0;
 		i++;
+		/*
 		if (i % (4 * 1) == 0) {
 
 			for (auto item : m_listEquipment) {
-				const StationIdentifier& station = item->getStation();
-				MemoryBlock& block = item->getReadBitBlock();
+				if (item->getID() == EQ_ID_Bonder1) {
+					const StationIdentifier& station = item->getStation();
+					MemoryBlock& block = item->getReadBitBlock();
 
-				int nRet = m_cclink.ReadData2(station, (DeviceType)block.type,
-					block.start, block.size, block.buffer);
-				if (0 == nRet) {
-					item->onReceiveLBData(block.buffer, block.size);
+					int nRet = m_cclink.ReadData2(station, (DeviceType)block.type,
+						block.start, block.size, block.buffer);
+					if (0 == nRet) {
+						item->onReceiveLBData(block.buffer, block.size);
+					}
 				}
 			}
 		}
+		*/
 
 
 		// 自动保存缓存
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index c6180cc..913d1c9 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -15,11 +15,13 @@
     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 std::function<void(void* pMaster, CEquipment* pEquipment, CVcrEventReport* pReport)> ONEQVCREVENTREPORT;
     typedef struct _MasterListener
     {
         ONEQALIVE				onEqAlive;
         ONEQALIVE		        onEqCimStateChanged;
         ONEQALARM               onEqAlarm;
+        ONEQVCREVENTREPORT	    onEqVcrEventReport;
     } MasterListener;
 
     class CMaster
@@ -33,6 +35,7 @@
         void setListener(MasterListener listener);
         int init();
         int term();
+        unsigned ReadBitsProc();
         void onTimer(UINT nTimerid);
         std::list<CEquipment*>& getEquipmentList();
         CEquipment* getEquipment(int id);
@@ -40,11 +43,11 @@
 
     private:
         int addToEquipmentList(CEquipment* pEquipment);
-        int addLoadPort(int index);
+        CLoadPort* addLoadPort(int index);
         int addFliper();
         int addVacuumBake();
         int addAligner();
-        int addEFEM();
+        CEFEM* addEFEM();
         int addBonder(int index);
         int addBakeCooling();
         void connectEquipments();
@@ -59,6 +62,11 @@
         std::list<CEquipment*> m_listEquipment;
         std::string m_strFilepath;
         BOOL m_bDataModify;
+
+    private:
+        HANDLE m_hEventReadBitsThreadExit[2];
+        HANDLE m_hReadBitsThreadHandle;
+        unsigned m_nReadBitsThreadAddr;
     };
 }
 
diff --git a/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp b/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp
new file mode 100644
index 0000000..0b36e1e
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp
@@ -0,0 +1,116 @@
+锘�// CPageCassetteCtrlCmd.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CPageCassetteCtrlCmd.h"
+#include "afxdialogex.h"
+
+
+// CPageCassetteCtrlCmd 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CPageCassetteCtrlCmd, CHMPropertyPage)
+
+CPageCassetteCtrlCmd::CPageCassetteCtrlCmd(CWnd* pParent /*=nullptr*/)
+	: CHMPropertyPage(IDD_PAGE_CASSETTE_CTRL_CMD, pParent)
+{
+	m_pEquipment = nullptr;
+}
+
+CPageCassetteCtrlCmd::~CPageCassetteCtrlCmd()
+{
+}
+
+void CPageCassetteCtrlCmd::DoDataExchange(CDataExchange* pDX)
+{
+	CHMPropertyPage::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CPageCassetteCtrlCmd, CHMPropertyPage)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+	ON_BN_CLICKED(IDC_BUTTON_SEND_CMD, &CPageCassetteCtrlCmd::OnBnClickedButtonSendCmd)
+END_MESSAGE_MAP()
+
+
+// CPageCassetteCtrlCmd 娑堟伅澶勭悊绋嬪簭
+void CPageCassetteCtrlCmd::OnApply()
+{
+	__super::OnApply();
+}
+
+void CPageCassetteCtrlCmd::setEquipment(SERVO::CEquipment* pEquipment)
+{
+	m_pEquipment = pEquipment;
+}
+
+BOOL CPageCassetteCtrlCmd::OnInitDialog()
+{
+	CHMPropertyPage::OnInitDialog();
+
+	const char* pszText[] = {"Cassette Map Download", "Clamp", "Unclamp",
+		"Reclamp", "Cassette Process Start", "Cassette Process Start By Count",
+		"Cassette Process Pause", "Cassette Process Resume", "Cassette Process Abort",
+		"Cassette Process Cancel", "Cassette Process End"};
+
+	CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_CASSETTE_CTRL_CMD);
+	for (int i = 0; i < 11; i++) {
+		pComboBox->InsertString(i, pszText[i]);
+	}
+	pComboBox->SetCurSel(0);
+
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+HBRUSH CPageCassetteCtrlCmd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CHMPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	// TODO:  鍦ㄦ鏇存敼 DC 鐨勪换浣曠壒鎬�
+
+	// TODO:  濡傛灉榛樿鐨勪笉鏄墍闇�鐢荤瑪锛屽垯杩斿洖鍙︿竴涓敾绗�
+	return hbr;
+}
+
+void CPageCassetteCtrlCmd::OnDestroy()
+{
+	CHMPropertyPage::OnDestroy();
+}
+
+void CPageCassetteCtrlCmd::OnSize(UINT nType, int cx, int cy)
+{
+	CHMPropertyPage::OnSize(nType, cx, cy);
+}
+
+void CPageCassetteCtrlCmd::OnBnClickedButtonSendCmd()
+{
+	ASSERT(m_pEquipment != nullptr);
+	ASSERT(m_pEquipment->getID() == EQ_ID_LOADPORT1
+		|| m_pEquipment->getID() == EQ_ID_LOADPORT2);
+	SERVO::CLoadPort* pLoadPort = (SERVO::CLoadPort*)m_pEquipment;
+
+	short cmd = 0;
+	short jobExistence[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	int jobExistenceSize = 12;
+	short slotProcess = 0;
+	short jobCount = 0;
+	SERVO::CJobDataA* pJobDataA = new SERVO::CJobDataA();
+
+
+	CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_CASSETTE_CTRL_CMD);
+	cmd = pComboBox->GetCurSel() + 1;
+	for (int i = 0; i < 12; i++) {
+		jobExistence[i] = (short)GetDlgItemInt(IDC_EDIT_EXISTENCE1 + i);
+	}
+
+	slotProcess = (short)GetDlgItemInt(IDC_EDIT_SLOT_TO_PROCESS);
+	jobCount = (short)GetDlgItemInt(IDC_EDIT_JOB_COUNT);
+
+
+	pLoadPort->sendCassetteCtrlCmd(cmd, &jobExistence[0], jobExistenceSize, slotProcess,
+		jobCount, pJobDataA);
+}
diff --git a/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.h b/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.h
new file mode 100644
index 0000000..edec95f
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.h
@@ -0,0 +1,36 @@
+锘�#pragma once
+#include "CHMPropertyPage.h"
+
+
+// CPageCassetteCtrlCmd 瀵硅瘽妗�
+
+class CPageCassetteCtrlCmd : public CHMPropertyPage
+{
+	DECLARE_DYNAMIC(CPageCassetteCtrlCmd)
+
+public:
+	CPageCassetteCtrlCmd(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CPageCassetteCtrlCmd();
+	virtual void OnApply();
+	void setEquipment(SERVO::CEquipment* pEquipment);
+
+private:
+	SERVO::CEquipment* m_pEquipment;
+
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_PAGE_CASSETTE_CTRL_CMD };
+#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 OnBnClickedButtonSendCmd();
+};
diff --git a/SourceCode/Bond/Servo/CPageGraph1.cpp b/SourceCode/Bond/Servo/CPageGraph1.cpp
index d288ba5..9a45e1c 100644
--- a/SourceCode/Bond/Servo/CPageGraph1.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph1.cpp
@@ -86,6 +86,14 @@
 							UpdateDeviceStatus(INDICATE_ROBOT_ARM1, status);
 							UpdateDeviceStatus(INDICATE_ROBOT_ARM2, status);
 						}
+						else if(EQ_ID_Bonder1 == nID) {
+							DeviceStatus status = bAlive ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE;
+							UpdateDeviceStatus(INDICATE_BONDER1, status);
+						}
+						else if (EQ_ID_Bonder2 == nID) {
+							DeviceStatus status = bAlive ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE;
+							UpdateDeviceStatus(INDICATE_BONDER2, status);
+						}
 					}
 				}
 			}
@@ -171,8 +179,6 @@
 	m_pGraph->AddIndicateBox(INDICATE_ROBOT_ARM2, 243, 294, 48, RGB(22, 22, 22),
 		RGB(255, 127, 39), EQ_BOX_OFFLINE);
 	m_pGraph->SetBoxText(INDICATE_ROBOT_ARM2, "6", "Robot");
-
-
 
 
 	// Vacuum bake
@@ -423,6 +429,29 @@
 	if (1 == nIDEvent) {
 		KillTimer(1);
 		InitRxWindows();
+
+		// 鏇存柊鐘舵��
+		{
+			SERVO::CEquipment* pEquipment = (SERVO::CEFEM*)theApp.m_model.m_master.getEquipment(EQ_ID_EFEM);
+			ASSERT(pEquipment);
+			DeviceStatus status = pEquipment->isAlive() ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE;
+			UpdateDeviceStatus(INDICATE_ROBOT_ARM1, status);
+			UpdateDeviceStatus(INDICATE_ROBOT_ARM2, status);
+		}
+
+		{
+			SERVO::CEquipment* pEquipment = theApp.m_model.m_master.getEquipment(EQ_ID_Bonder1);
+			ASSERT(pEquipment);
+			DeviceStatus status = pEquipment->isAlive() ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE;
+			UpdateDeviceStatus(INDICATE_BONDER1, status);
+		}
+
+		{
+			SERVO::CEquipment* pEquipment = theApp.m_model.m_master.getEquipment(EQ_ID_Bonder2);
+			ASSERT(pEquipment);
+			DeviceStatus status = pEquipment->isAlive() ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE;
+			UpdateDeviceStatus(INDICATE_BONDER2, status);
+		}
 	}
 
 	CDialogEx::OnTimer(nIDEvent);
diff --git a/SourceCode/Bond/Servo/CPageGraph2.cpp b/SourceCode/Bond/Servo/CPageGraph2.cpp
index 2a5a00e..ffc169d 100644
--- a/SourceCode/Bond/Servo/CPageGraph2.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph2.cpp
@@ -8,6 +8,8 @@
 #include "CHMPropertyDlg.h"
 #include "CEquipmentPage1.h"
 #include "CEquipmentPage2.h"
+#include "CPagePortProperty.h"
+#include "CPageCassetteCtrlCmd.h"
 
 
 // CPageGraph2 瀵硅瘽妗�
@@ -86,15 +88,26 @@
 		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");
+
+		if (_strcmpi(pEquipment->getClassName(), "CLoadPort") == 0) {
+			CPagePortProperty* pPage1 = new CPagePortProperty();
+			pPage1->setLoadPort((SERVO::CLoadPort*)pEquipment);
+			pPage1->Create(IDD_PAGE_PORT_PROPERTY);
+			dlg.addPage(pPage1, "灞炴��");
+		}
 
 		CEquipmentPage2* pPage2 = new CEquipmentPage2();
 		pPage2->setEquipment(pEquipment);
 		pPage2->Create(IDD_PAGE_EQUIPMENT2);
 		dlg.addPage(pPage2, "Glass");
+
+		if (pEquipment->getID() == EQ_ID_LOADPORT1
+			|| pEquipment->getID() == EQ_ID_LOADPORT2) {
+			CPageCassetteCtrlCmd* pPage = new CPageCassetteCtrlCmd();
+			pPage->setEquipment(pEquipment);
+			pPage->Create(IDD_PAGE_CASSETTE_CTRL_CMD);
+			dlg.addPage(pPage, "Cassette control command");
+		}
 
 		dlg.DoModal();
 		return true;
@@ -149,6 +162,69 @@
 		}
 		else if (nCmd == ID_EQSGRAPHITEM_TEST3) {
 			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
+
+			// 娴嬭瘯涓嬪彂Cim Message
+			/*
+			if (pEquipment->getID() == EQ_ID_Bonder1
+				|| pEquipment->getID() == EQ_ID_Bonder2) {
+				static int msgId = 0; msgId++;
+				if (msgId % 2 == 0) {
+					pEquipment->setCimMessage("Hello!", msgId, 1);
+				}
+				else {
+					pEquipment->setCimMessage("ABC0123456789", msgId, 2);
+				}
+			}
+			*/
+
+
+			// 娴嬭瘯娓呴櫎Cim Message
+			/*
+			if (pEquipment->getID() == EQ_ID_Bonder1
+				|| pEquipment->getID() == EQ_ID_Bonder2) {
+				static int msgId = 0; msgId++;
+				if (msgId % 2 == 0) {
+					pEquipment->clearCimMessage(msgId, 1);
+				}
+				else {
+					pEquipment->clearCimMessage(msgId, 2);
+				}
+			}
+			*/
+
+			// 娴嬭瘯璁剧疆鏃堕棿
+			/*
+			if (pEquipment->getID() == EQ_ID_Bonder1
+				|| pEquipment->getID() == EQ_ID_Bonder2) {
+				CTime time = CTime::GetCurrentTime();
+				pEquipment->setDateTime((short)time.GetYear(),
+					(short)time.GetMonth(),
+					(short)time.GetDay(),
+					(short)time.GetHour(),
+					(short)time.GetMinute(),
+					(short)time.GetSecond());
+			}
+			*/
+
+			
+			// 娴嬭瘯璁剧疆cim mode
+			/*
+			if (pEquipment->getID() == EQ_ID_Bonder1
+				|| pEquipment->getID() == EQ_ID_Bonder2) {
+				static int ii = 0; ii++;
+				pEquipment->setCimMode(ii % 2 == 0);
+			}
+			*/
+			
+			/*
+			if (pEquipment->getID() == EQ_ID_Bonder1
+				|| pEquipment->getID() == EQ_ID_Bonder2) {
+				static int ii = 0; ii++;
+				pEquipment->setEqMode((ii % 5) + 1);
+			}
+			*/
+
+			/*
 			SERVO::CGlass* pGlass = pEquipment->getFrontGlass();
 			if (pGlass != nullptr) {
 				std::string strDescription;
@@ -159,6 +235,13 @@
 					pPath = pPath->getNext();
 				}
 			}
+			*/
+
+
+			// 璇锋眰涓婚厤鏂瑰垪琛�
+			if (pEquipment != nullptr) {
+				pEquipment->masterRecipeListRequest(0);
+			}			
 		}
 
 
diff --git a/SourceCode/Bond/Servo/CPagePortProperty.cpp b/SourceCode/Bond/Servo/CPagePortProperty.cpp
new file mode 100644
index 0000000..88728b5
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPagePortProperty.cpp
@@ -0,0 +1,139 @@
+锘�// CPagePortProperty.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CPagePortProperty.h"
+#include "afxdialogex.h"
+
+
+// CPagePortProperty 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CPagePortProperty, CHMPropertyPage)
+
+CPagePortProperty::CPagePortProperty(CWnd* pParent /*=nullptr*/)
+	: CHMPropertyPage(IDD_PAGE_PORT_PROPERTY, pParent)
+{
+	m_pPort = nullptr;
+}
+
+CPagePortProperty::~CPagePortProperty()
+{
+}
+
+void CPagePortProperty::DoDataExchange(CDataExchange* pDX)
+{
+	CHMPropertyPage::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CPagePortProperty, CHMPropertyPage)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+	ON_BN_CLICKED(IDC_CHECK_ENABLE, &CPagePortProperty::OnBnClickedCheckEnable)
+END_MESSAGE_MAP()
+
+
+// CPagePortProperty 娑堟伅澶勭悊绋嬪簭
+void CPagePortProperty::setLoadPort(SERVO::CLoadPort* pPort)
+{
+	m_pPort = pPort;
+}
+
+BOOL CPagePortProperty::OnInitDialog()
+{
+	CHMPropertyPage::OnInitDialog();
+
+
+	ASSERT(m_pPort);
+	CComboBox* pComboBox;
+	std::string strTemp;
+
+	
+	pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PORT_TYPE);
+	for (int i = 1; i <= 7; i++) {
+		pComboBox->InsertString(i - 1, SERVO::CLoadPort::getPortTypeDescription(i, strTemp).c_str());
+	}
+	int portType = m_pPort->getPortType();
+	if (1 <= portType && portType <= 7) {
+		pComboBox->SetCurSel(portType - 1);
+	}
+
+	pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PORT_MODE);
+	for (int i = 1; i <= 3; i++) {
+		pComboBox->InsertString(i - 1, SERVO::CLoadPort::getPortModeDescription(i, strTemp).c_str());
+	}
+	int portMode = m_pPort->getPortMode();
+	if (1 <= portMode && portMode <= 3) {
+		pComboBox->SetCurSel(portMode - 1);
+	}
+
+	pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PORT_CASSERT_TYPE);
+	for (int i = 1; i <= 3; i++) {
+		pComboBox->InsertString(i - 1, SERVO::CLoadPort::getPortCassetteTypeDescription(i, strTemp).c_str());
+	}
+	int cessetteType = m_pPort->getCessetteType();
+	if (1 <= cessetteType && cessetteType <= 3) {
+		pComboBox->SetCurSel(cessetteType - 1);
+	}
+
+	pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PORT_TRANSFER_MODE);
+	for (int i = 1; i <= 3; i++) {
+		pComboBox->InsertString(i - 1, SERVO::CLoadPort::getPortTransferModeDescription(i, strTemp).c_str());
+	}
+	int transferMode = m_pPort->getTransferMode();
+	if (1 <= transferMode && transferMode <= 3) {
+		pComboBox->SetCurSel(transferMode - 1);
+	}
+
+	((CButton*)GetDlgItem(IDC_CHECK_AUTO_CHANGE))->SetCheck(m_pPort->isAutoChange() ? BST_CHECKED : BST_UNCHECKED);
+	
+	
+	
+	EnableCtrls(m_pPort->isEnable());
+
+
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+HBRUSH CPagePortProperty::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CHMPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	// TODO:  鍦ㄦ鏇存敼 DC 鐨勪换浣曠壒鎬�
+
+	// TODO:  濡傛灉榛樿鐨勪笉鏄墍闇�鐢荤瑪锛屽垯杩斿洖鍙︿竴涓敾绗�
+	return hbr;
+}
+
+void CPagePortProperty::OnDestroy()
+{
+	CHMPropertyPage::OnDestroy();
+
+	// TODO: 鍦ㄦ澶勬坊鍔犳秷鎭鐞嗙▼搴忎唬鐮�
+}
+
+void CPagePortProperty::OnSize(UINT nType, int cx, int cy)
+{
+	CHMPropertyPage::OnSize(nType, cx, cy);
+
+	// TODO: 鍦ㄦ澶勬坊鍔犳秷鎭鐞嗙▼搴忎唬鐮�
+}
+
+void CPagePortProperty::OnBnClickedCheckEnable()
+{
+	BOOL bCheck = ((CButton*)GetDlgItem(IDC_CHECK_ENABLE))->GetCheck() == BST_CHECKED;
+	EnableCtrls(bCheck);
+}
+
+void CPagePortProperty::EnableCtrls(BOOL bEnable)
+{
+	GetDlgItem(IDC_COMBO_PORT_TYPE)->EnableWindow(bEnable);
+	GetDlgItem(IDC_COMBO_PORT_MODE)->EnableWindow(bEnable);
+	GetDlgItem(IDC_COMBO_PORT_CASSERT_TYPE)->EnableWindow(bEnable);
+	GetDlgItem(IDC_COMBO_PORT_TRANSFER_MODE)->EnableWindow(bEnable);
+	GetDlgItem(IDC_CHECK_AUTO_CHANGE)->EnableWindow(bEnable);
+}
diff --git a/SourceCode/Bond/Servo/CPagePortProperty.h b/SourceCode/Bond/Servo/CPagePortProperty.h
new file mode 100644
index 0000000..f7e159c
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPagePortProperty.h
@@ -0,0 +1,40 @@
+锘�#pragma once
+#include "CHMPropertyPage.h"
+
+
+// CPagePortProperty 瀵硅瘽妗�
+
+class CPagePortProperty : public CHMPropertyPage
+{
+	DECLARE_DYNAMIC(CPagePortProperty)
+
+public:
+	CPagePortProperty(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CPagePortProperty();
+
+public:
+	void setLoadPort(SERVO::CLoadPort* pPort);
+
+private:
+	void EnableCtrls(BOOL bEnable);
+
+private:
+	SERVO::CLoadPort* m_pPort;
+
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_PAGE_PORT_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 OnBnClickedCheckEnable();
+};
diff --git a/SourceCode/Bond/Servo/CReadStep.cpp b/SourceCode/Bond/Servo/CReadStep.cpp
index 7e05c00..5fd5dfd 100644
--- a/SourceCode/Bond/Servo/CReadStep.cpp
+++ b/SourceCode/Bond/Servo/CReadStep.cpp
@@ -22,6 +22,9 @@
 		m_hReadSignalOff = ::CreateEvent(NULL, TRUE, FALSE, NULL);
 		m_nSignalType = 0;
 		m_nCurStep = 0;
+		m_szReturnBuf[1024] = {0};
+		m_nReturnDataSize = 0;
+		m_nReturnDevNo = 0;
 	}
 
 	CReadStep::~CReadStep()
@@ -38,6 +41,11 @@
 	void CReadStep::setWriteSignalDev(int dev)
 	{
 		m_nWriteSignalDev = dev;
+	}
+	
+	void CReadStep::setReturnDev(int dev)
+	{
+		m_nReturnDevNo = dev;
 	}
 
 	void CReadStep::onReadSignal(int nSignalType)
@@ -88,16 +96,27 @@
 					m_pEquipment->onStepEvent(this, STEP_EVENT_READDATA);
 				}
 
+				// 0426新增
+				// 1.1,写return code or data
+				if (m_nReturnDataSize > 0) {
+					int nWriteRet = m_pCclink->WriteData(m_station, (short)DeviceType::W,
+						m_nReturnDevNo, m_nReturnDataSize, (short*)m_szReturnBuf);
+					if (0 != nWriteRet) {
+						onTimeout();
+						goto RESET;
+					}
+				}
+
 				// 2.给对方写ON
 				nextStep();
-				m_pCclink->SetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
+				m_pCclink->SetBitDeviceEx(m_station, (long)DeviceType::B, m_nWriteSignalDev);
 
 
 				// 3.等待对方OFF
 				nextStep();
 				int nStep3Ret = ::WaitForSingleObject(m_hReadSignalOff, TIMEOUT * 1000);
 				if (nStep3Ret == WAIT_TIMEOUT) {
-					m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
+					m_pCclink->ResetBitDeviceEx(m_station, (long)DeviceType::B, m_nWriteSignalDev);
 					onTimeout();
 					goto RESET;
 				}
@@ -106,7 +125,7 @@
 
 				// 4.给对方写OFF
 				nextStep();
-				m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
+				m_pCclink->ResetBitDeviceEx(m_station, (long)DeviceType::B, m_nWriteSignalDev);
 
 
 				// 6.完成
@@ -115,6 +134,9 @@
 					ASSERT(m_pEquipment);
 					m_pEquipment->onStepEvent(this, STEP_EVENT_COMPLETE);
 				}
+
+				// 回复数据清空
+				m_nReturnDataSize = 0;
 			}
 		}
 
@@ -187,4 +209,12 @@
 	{
 		return 0;
 	}
+
+	int CReadStep::setReturnCode(short code)
+	{
+		memcpy(m_szReturnBuf, &code, sizeof(short));
+		m_nReturnDataSize = sizeof(short);
+
+		return 0;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CReadStep.h b/SourceCode/Bond/Servo/CReadStep.h
index e5c88d2..c74568e 100644
--- a/SourceCode/Bond/Servo/CReadStep.h
+++ b/SourceCode/Bond/Servo/CReadStep.h
@@ -12,6 +12,7 @@
 	public:
 		unsigned WorkingProc();
 		virtual void setWriteSignalDev(int dev);
+		virtual void setReturnDev(int dev);
 		virtual void onReadSignal(int nSignalType);
 		virtual int onReadData();
 		virtual void init();
@@ -21,6 +22,7 @@
 		virtual int onTimeout();
 		inline void nextStep();
 		inline void resetStep();
+		virtual int setReturnCode(short code);
 
 	protected:
 		HANDLE m_hWorkThreadHandle;
@@ -31,6 +33,12 @@
 		int m_nSignalType;
 		int m_nCurStep;
 		int m_nWriteSignalDev;			// 对方BIT地址
+
+		// return code or data
+	protected:
+		char m_szReturnBuf[1024];
+		int m_nReturnDataSize;
+		int m_nReturnDevNo;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CRecipeList.cpp b/SourceCode/Bond/Servo/CRecipeList.cpp
new file mode 100644
index 0000000..4d8e7d0
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipeList.cpp
@@ -0,0 +1,81 @@
+#include "stdafx.h"
+#include "CRecipeList.h"
+#include "Common.h"
+#include "ToolUnits.h"
+
+
+namespace SERVO {
+	CRecipeList::CRecipeList()
+	{
+		m_nToatlGroupCount = 0;
+		m_nCurrentGroupCount = 0;
+	}
+
+	CRecipeList::CRecipeList(int unitNo)
+	{
+		m_nUnitNo = unitNo;
+	}
+
+	CRecipeList::~CRecipeList()
+	{
+
+	}
+
+	int CRecipeList::getUnitNo()
+	{
+		return m_nUnitNo;
+	}
+
+	int CRecipeList::addRecipePacket(int totalGroup, int currentGroup, const char* pszData, size_t size)
+	{
+		if (m_nToatlGroupCount == 0) m_nToatlGroupCount = totalGroup;
+		if (m_nToatlGroupCount != totalGroup) {
+			reset();
+			return MRLRC_GROUP_COUNT_NG;
+		}
+		if (m_nCurrentGroupCount + 1 > currentGroup) {
+			return MRLRC_DUPLICATION_GROUP_COUNT_NG;
+		}
+		if (m_nCurrentGroupCount + 1 < currentGroup) {
+			return ORDER_BY_GROUP_COUNT_NG;
+		}
+		m_nCurrentGroupCount++;
+		
+		for (int i = 0; i < size; i += 4) {
+			int index = CToolUnits::toInt16(&pszData[i]);
+			short id = CToolUnits::toInt16(&pszData[i + 2]);
+			addRecipe(index, id);
+		}
+
+		if (m_nCurrentGroupCount == m_nToatlGroupCount) {
+			return MRLRC_CURRENT_RECIPE_COMPLETE;
+		}
+
+
+		return MRLRC_CONTINUE;
+	}
+
+	int CRecipeList::addRecipe(int index, short id)
+	{
+		for (auto item : m_ids) {
+			if (item.second == id) {
+				return -1;
+			}
+		}
+
+		m_ids[index] = id;
+		return 0;
+	}
+
+	std::map<int, short>& CRecipeList::getIds()
+	{
+		return m_ids;
+	}
+
+	void CRecipeList::reset()
+	{
+		m_nToatlGroupCount = 0;
+		m_nCurrentGroupCount = 0;
+		m_ids.clear();
+	}
+}
diff --git a/SourceCode/Bond/Servo/CRecipeList.h b/SourceCode/Bond/Servo/CRecipeList.h
new file mode 100644
index 0000000..7cb4577
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipeList.h
@@ -0,0 +1,27 @@
+#pragma once
+#include <map>
+
+
+namespace SERVO {
+	class CRecipeList
+	{
+	public:
+		CRecipeList();
+		CRecipeList(int unitNo);
+		virtual ~CRecipeList();
+
+	public:
+		int getUnitNo();
+		int addRecipePacket(int totalGroup, int currentGroup, const char* pszData, size_t size);
+		int addRecipe(int index, short id);
+		std::map<int, short>& getIds();
+		void reset();
+
+	private:
+		int m_nUnitNo;
+		int m_nToatlGroupCount;
+		int m_nCurrentGroupCount;
+		std::map<int, short> m_ids;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CRecipesManager.cpp b/SourceCode/Bond/Servo/CRecipesManager.cpp
new file mode 100644
index 0000000..e858b42
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipesManager.cpp
@@ -0,0 +1,187 @@
+#include "stdafx.h"
+#include "CRecipesManager.h"
+#include "ToolUnits.h"
+#include "Common.h"
+
+
+namespace SERVO {
+	unsigned __stdcall TimeoutCheckWorkThreadFunction(LPVOID lpParam)
+	{
+		CRecipesManager* pRecipesManager = (CRecipesManager*)lpParam;
+		return pRecipesManager->TimeoutCheckWorkingProc();
+	}
+
+	CRecipesManager::CRecipesManager()
+	{
+		m_nSyncStatus = SS_NONE;
+		m_nTotalMasterRecipeCount = 0;
+		m_nWordThreadAddr = 0;
+		m_hWorkStop = nullptr;
+		m_hWorkThreadHandle = nullptr;
+		m_nTimeoutCount = 0;
+		::InitializeCriticalSection(&m_cs);
+	}
+
+	CRecipesManager::~CRecipesManager()
+	{
+		// 等待超时检测线程退出
+		if (m_hWorkStop != nullptr) {
+			SetEvent(m_hWorkStop);
+			if (m_hWorkThreadHandle != NULL) {
+				WaitForSingleObject(m_hWorkThreadHandle, INFINITE);
+				CloseHandle(m_hWorkThreadHandle);
+				m_hWorkThreadHandle = NULL;
+			}
+			CloseHandle(m_hWorkStop);
+			m_hWorkStop = NULL;
+		}
+
+
+		// 清理数据
+		lock();
+		for (auto item : m_mapRecipes) {
+			delete item.second;
+		}
+		for (auto item : m_mapRecipesTemp) {
+			delete item.second;
+		}
+		unlock();
+		::DeleteCriticalSection(&m_cs);
+	}
+
+	int CRecipesManager::syncing()
+	{
+		lock();
+		if (m_nSyncStatus == SS_SYNCING) {
+			unlock();
+			return -1;
+		}
+
+		m_nSyncStatus = SS_SYNCING;
+		m_nTimeoutCount = 0;
+		unlock();
+
+
+		if (m_hWorkStop == nullptr) {
+			m_hWorkStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+			m_hWorkThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::TimeoutCheckWorkThreadFunction, this,
+				0, &m_nWordThreadAddr);
+		}
+
+		return 0;
+	}
+
+	void CRecipesManager::syncFailed()
+	{
+		lock();
+		m_nSyncStatus = SS_FAILED;
+		m_nTimeoutCount = 0;
+		unlock();
+	}
+
+	short CRecipesManager::decodeRecipeListReport(const char* pszData, size_t size)
+	{
+		int index = 0;
+		int unitNo, reportType, totalMasterRecipeCount;
+		int toatlGroupCount, currentGroupCount;
+		const char* pszIdsData;
+
+		unitNo = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		pszIdsData = &pszData[index];
+		index += (250 * 2);
+
+		reportType = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		totalMasterRecipeCount = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		toatlGroupCount = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		lock();
+		if (m_nTotalMasterRecipeCount == 0) m_nTotalMasterRecipeCount = toatlGroupCount;
+		if (m_nTotalMasterRecipeCount != toatlGroupCount) {
+			return MRLRC_MASTER_RECIPE_LIST_COUNT_NG;
+		}
+		m_nTimeoutCount = 0;
+		unlock();
+
+		currentGroupCount = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+
+		// 找到对应CRecipeList, 找不到则新建
+		lock();
+		CRecipeList* pRecipeList = getRecipeListFromTemp(unitNo);
+		if (pRecipeList == nullptr) {
+			pRecipeList = new CRecipeList(unitNo);
+			m_mapRecipesTemp[unitNo] = pRecipeList;
+		}
+		unlock();
+		ASSERT(pRecipeList);
+
+
+		// 这里暂时只处理reportType=4,即Request from EAS
+		if (reportType == 4) {
+			int nRet = pRecipeList->addRecipePacket(toatlGroupCount, currentGroupCount, pszIdsData, 250 * 2);
+			if (MRLRC_CURRENT_RECIPE_COMPLETE == nRet) {
+				lock();
+				if (m_nTotalMasterRecipeCount == m_mapRecipesTemp.size()) {
+					for (auto item : m_mapRecipes) {
+						delete item.second;
+					}
+					m_mapRecipes = m_mapRecipesTemp;
+					m_mapRecipesTemp.clear();
+					m_nSyncStatus = SS_COMPLETE;
+					unlock();
+					return MRLRC_OK;
+				}
+				unlock();
+			}
+			else if (MRLRC_CONTINUE == nRet) {
+				return MRLRC_CONTINUE;
+			}
+		}
+
+
+		return MRLRC_OK;
+	}
+
+	CRecipeList* CRecipesManager::getRecipeListFromTemp(int unitNo)
+	{
+		auto iter = m_mapRecipesTemp.find(unitNo);
+		if (iter == m_mapRecipesTemp.end()) return nullptr;
+		return iter->second;
+	}
+
+	unsigned CRecipesManager::TimeoutCheckWorkingProc()
+	{
+		while (1) {
+			int nRet = WaitForSingleObject(m_hWorkStop, 1000);
+			if (nRet == WAIT_OBJECT_0) {
+				ResetEvent(m_hWorkStop);
+				break;
+			}
+
+			lock();
+			if (m_nSyncStatus == SS_SYNCING) {
+				m_nTimeoutCount++;
+				if (m_nTimeoutCount > 10) {
+					m_nSyncStatus = SS_TIMEOUT;
+					unlock();
+					TRACE("CRecipesManager::TimeoutCheckWorkingProc 超时退出\n");
+				}
+			}
+
+			unlock();
+		}
+
+		// _endthreadex(0);
+		TRACE("CRecipesManager::TimeoutCheckWorkingProc 线程退出\n");
+		return 0;
+	}
+
+}
diff --git a/SourceCode/Bond/Servo/CRecipesManager.h b/SourceCode/Bond/Servo/CRecipesManager.h
new file mode 100644
index 0000000..d8e01dc
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipesManager.h
@@ -0,0 +1,42 @@
+#pragma once
+#include <map>
+#include "CRecipeList.h"
+
+
+#define SS_NONE					0
+#define SS_SYNCING				1
+#define SS_COMPLETE				2
+#define SS_TIMEOUT				3
+#define SS_FAILED				4
+
+namespace SERVO {
+	class CRecipesManager
+	{
+	public:
+		CRecipesManager();
+		virtual ~CRecipesManager();
+
+	public:
+		unsigned TimeoutCheckWorkingProc();
+		int syncing();
+		void syncFailed();
+		short decodeRecipeListReport(const char* pszData, size_t size);
+		CRecipeList* getRecipeListFromTemp(int unitNo);
+
+	public:
+		inline void lock() { ::EnterCriticalSection(&m_cs); };
+		inline void unlock() { ::LeaveCriticalSection(&m_cs); };
+
+	private:
+		HANDLE m_hWorkThreadHandle;
+		unsigned m_nWordThreadAddr;
+		HANDLE m_hWorkStop;
+		int m_nTimeoutCount;
+		CRITICAL_SECTION m_cs;		// 同步锁
+		int m_nSyncStatus;
+		int m_nTotalMasterRecipeCount;
+		std::map<int, CRecipeList*> m_mapRecipes;
+		std::map<int, CRecipeList*> m_mapRecipesTemp;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CStep.cpp b/SourceCode/Bond/Servo/CStep.cpp
index 0f23732..7ffc65d 100644
--- a/SourceCode/Bond/Servo/CStep.cpp
+++ b/SourceCode/Bond/Servo/CStep.cpp
@@ -6,6 +6,7 @@
 
 	CStep::CStep()
 	{
+		m_nID = 0;
 		m_pCclink = nullptr;
 		InitializeCriticalSection(&m_criticalSection);
 	}
@@ -30,6 +31,16 @@
 		return m_pEquipment;
 	}
 
+	void CStep::setID(int id)
+	{
+		m_nID = id;
+	}
+
+	int CStep::getID()
+	{
+		return m_nID;
+	}
+
 	void CStep::setName(const char* pszName)
 	{
 		m_strName = pszName;
diff --git a/SourceCode/Bond/Servo/CStep.h b/SourceCode/Bond/Servo/CStep.h
index aae469e..866e6f2 100644
--- a/SourceCode/Bond/Servo/CStep.h
+++ b/SourceCode/Bond/Servo/CStep.h
@@ -19,6 +19,8 @@
 		void setCcLink(CCCLinkIEControl* pCcLink);
 		void setEquipment(CEquipment* pEquipment);
 		CEquipment* getEquipment();
+		void setID(int id);
+		int getID();
 		void setName(const char* pszName);
 		std::string& getName();
 		virtual void getAttributeVector(CAttributeVector& attrubutes);
@@ -32,6 +34,7 @@
 		void convertString(const char* pszBuffer, int size, std::string& strOut);
 
 	protected:
+		int m_nID;
 		StationIdentifier m_station;
 		std::string m_strName;
 		CEquipment* m_pEquipment;
diff --git a/SourceCode/Bond/Servo/CVcrEventReport.cpp b/SourceCode/Bond/Servo/CVcrEventReport.cpp
new file mode 100644
index 0000000..914b0d0
--- /dev/null
+++ b/SourceCode/Bond/Servo/CVcrEventReport.cpp
@@ -0,0 +1,119 @@
+#include "stdafx.h"
+#include "CVcrEventReport.h"
+#include "ToolUnits.h"
+
+
+namespace SERVO {
+	CVcrEventReport::CVcrEventReport()
+	{
+
+	}
+
+	CVcrEventReport::~CVcrEventReport()
+	{
+
+	}
+
+	std::string& CVcrEventReport::getGlassId()
+	{
+		return m_strGlassId;
+	}
+
+	short CVcrEventReport::getCassetteSequenceNo()
+	{
+		return m_nCassetteSequenceNo;
+	}
+
+	short CVcrEventReport::getJobSequenceNo()
+	{
+		return m_nJobSequenceNo;
+	}
+
+	short CVcrEventReport::getUnitNo()
+	{
+		return m_nUnitNo;
+	}
+
+	short CVcrEventReport::getVcrNo()
+	{
+		return m_nVcrNo;
+	}
+
+	short CVcrEventReport::getVcrResult()
+	{
+		return m_nVcrResult;
+	}
+
+	int CVcrEventReport::serialize(char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 640) return -1;
+
+		int index = 0;
+		int strLen = min(20, m_strGlassId.size());
+		memcpy(&pszBuffer[index], m_strGlassId.c_str(), strLen);
+		index += 20;
+
+		memcpy(&pszBuffer[index], &m_nCassetteSequenceNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nJobSequenceNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nUnitNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nVcrNo, sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&pszBuffer[index], &m_nVcrResult, sizeof(short));
+		index += sizeof(short);
+
+		return 15 * 2;
+	}
+
+	int CVcrEventReport::unserialize(char* pszBuffer, int nBufferSize)
+	{
+		if (nBufferSize < 640) return -1;
+
+		int index = 0;
+		CToolUnits::convertString(&pszBuffer[index], 20, m_strGlassId);
+		index += 20;
+
+		memcpy(&m_nCassetteSequenceNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nJobSequenceNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nUnitNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nVcrNo, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		memcpy(&m_nVcrResult, &pszBuffer[index], sizeof(short));
+		index += sizeof(short);
+
+		return 15 * 2;
+	}
+
+	std::string& CVcrEventReport::getVcrResultDescription(std::string& strDescription)
+	{
+		static char* pszDescription[4] = {
+			"VCR Reading OK & Match With Job Data Glass ID",
+			"VCR Reading OK & Miss Match With Job Data Glass ID",
+			"VCR Reading Fail & Key In & Match With Job Data Glass ID",
+			"VCR Reading Fail & Key In & Miss Match With Job Data Glass ID"
+		};
+
+		if (1 <= m_nVcrResult && m_nVcrResult <= 4) {
+			strDescription = pszDescription[m_nVcrResult - 1];
+		}
+		else {
+			strDescription = "";
+		}
+
+		return strDescription;
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/CVcrEventReport.h b/SourceCode/Bond/Servo/CVcrEventReport.h
new file mode 100644
index 0000000..275cf30
--- /dev/null
+++ b/SourceCode/Bond/Servo/CVcrEventReport.h
@@ -0,0 +1,32 @@
+#pragma once
+#include <string>
+
+
+namespace SERVO {
+	class CVcrEventReport
+	{
+	public:
+		CVcrEventReport();
+		~CVcrEventReport();
+
+	public:
+		std::string& getGlassId();
+		short getCassetteSequenceNo();
+		short getJobSequenceNo();
+		short getUnitNo();
+		short getVcrNo();
+		short getVcrResult();
+		std::string& getVcrResultDescription(std::string& strDescription);
+		int serialize(char* pszBuffer, int nBufferSize);
+		int unserialize(char* pszBuffer, int nBufferSize);
+
+	private:
+		std::string m_strGlassId;			// Read Data
+		short m_nCassetteSequenceNo;
+		short m_nJobSequenceNo;
+		short m_nUnitNo;
+		short m_nVcrNo;
+		short m_nVcrResult;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CWriteStep.cpp b/SourceCode/Bond/Servo/CWriteStep.cpp
index 6d79f55..ba18a5c 100644
--- a/SourceCode/Bond/Servo/CWriteStep.cpp
+++ b/SourceCode/Bond/Servo/CWriteStep.cpp
@@ -89,9 +89,9 @@
 				// 1.写数据
 				nextStep();
 				ASSERT(m_pCclink);
-				int nRet = m_pCclink->WriteData(m_station, (short)DeviceType::W,
+				int nWriteRet = m_pCclink->WriteData(m_station, (short)DeviceType::W,
 					m_nWriteDevNo, m_nWriteDataSize, (short*)m_szBuffer);
-				if (0 != nRet) {
+				if (0 != nWriteRet) {
 					onTimeout();
 					goto RESET;
 				}
@@ -99,14 +99,14 @@
 
 				// 2.给对方写ON
 				nextStep();
-				m_pCclink->SetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
+				m_pCclink->SetBitDeviceEx(m_station, (long)DeviceType::B, m_nWriteSignalDev);
 
 
 				// 3.等待对方ON
 				nextStep();
 				int nStep3Ret = ::WaitForSingleObject(m_hRecvSignalOn, TIMEOUT * 1000);
 				if (nStep3Ret == WAIT_TIMEOUT) {
-					m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
+					m_pCclink->ResetBitDeviceEx(m_station, (long)DeviceType::B, m_nWriteSignalDev);
 					onTimeout();
 					goto RESET;
 				}
@@ -115,7 +115,7 @@
 
 				// 4.写OFF
 				nextStep();
-				m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
+				m_pCclink->ResetBitDeviceEx(m_station, (long)DeviceType::B, m_nWriteSignalDev);
 
 
 				// 6.完成
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index 84bc43e..34d4258 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/SourceCode/Bond/Servo/Common.h
@@ -128,33 +128,93 @@
 #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")
+#define STEP_EQ_P1_CASSETTE_CTRL_CMD	_T("EQPort1CassetteCtrlCmd")
+#define STEP_EQ_P2_CASSETTE_CTRL_CMD	_T("EQPort2CassetteCtrlCmd")
+#define STEP_EQ_P3_CASSETTE_CTRL_CMD	_T("EQPort3CassetteCtrlCmd")
+#define STEP_EQ_P4_CASSETTE_CTRL_CMD	_T("EQPort4CassetteCtrlCmd")
+#define STEP_EQ_CIM_MESSAGE_CONFIRM		_T("EQCimMessageConfirm")
+#define STEP_EQ_RECEIVED_JOB_UPS1		_T("EQJEReceivedJobUps1")
+#define STEP_EQ_RECEIVED_JOB_UPS2		_T("EQJEReceivedJobUps2")
+#define STEP_EQ_SENT_OUT_JOB_DOWNS1		_T("EQJESentOutJobDowns1")
+#define STEP_EQ_SENT_OUT_JOB_DOWNS2		_T("EQJESentOutJobDowns2")
+#define STEP_EQ_VCR1_EVENT_REPORT		_T("EQVcr1EventReport")
+#define STEP_EQ_RURRENT_RECIPE_CHANGE	_T("EQCurrentRecipeChange")
+#define STEP_EQ_MASTER_RECIPE_LIST_REQ	_T("EQMasterRecipeListReq")
+#define STEP_EQ_MASTER_RECIPE_LIST		_T("EQMasterRecipeListReport")
 
 
 /* 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
+#define STEP_ID_CIMMODE_CHANGED_CMD_REPLY		0x550
+#define STEP_ID_CIM_MSG_SET_CMD_REPLY			0x551
+#define STEP_ID_CIM_MSG_CLEAR_CMD_REPLY			0x552
+#define STEP_ID_DATETIME_SET_CMD_REPLY			0x553
+#define STEP_ID_VCR_ENABLE_CMD_REPLY			0x554
+#define STEP_ID_EQMODE_CHANGE_CMD_REPLY			0x555
+#define STEP_ID_MASTER_RECIPE_LIST_CMD_REPLY	0x556
+#define STEP_ID_EQMODE_CHANGED					0x560
+#define STEP_ID_EQSTATUS_CHANGED				0x561
+#define STEP_ID_EQALARM1						0x562
+#define STEP_ID_EQALARM2						0x563
+#define STEP_ID_EQALARM3						0x564
+#define STEP_ID_EQALARM4						0x565
+#define STEP_ID_EQALARM5						0x566
+#define STEP_ID_PROCESS_DATA_REPORT				0x567
+#define STEP_ID_CURRENT_RECIPE_CHANGE_REPORT	0x568
+#define STEP_ID_CIM_MSG_CONFIRM_REPORT			0x569
+#define STEP_ID_VCR1_EVENT_REPORT				0x56A
+#define STEP_ID_MASTER_RECIPE_LIST_REPORT		0x56B
+#define STEP_ID_RECIVE_JOB_UPS1					0x580
+#define STEP_ID_RECIVE_JOB_UPS2					0x581
+#define STEP_ID_SENT_OUT_JOB_DOWNS1				0x590
+#define STEP_ID_SENT_OUT_JOB_DOWNS2				0x591
+#define STEP_ID_PORT1_TYPE_CHANGE				0x600
+#define STEP_ID_PORT2_TYPE_CHANGE				0x601
+#define STEP_ID_PORT3_TYPE_CHANGE				0x602
+#define STEP_ID_PORT4_TYPE_CHANGE				0x603
+#define STEP_ID_PORT1_MODE_CHANGE				0x608
+#define STEP_ID_PORT2_MODE_CHANGE				0x609
+#define STEP_ID_PORT3_MODE_CHANGE				0x60A
+#define STEP_ID_PORT4_MODE_CHANGE				0x60B
+#define STEP_ID_PORT1_CASSETTE_TYPE_CHANGE		0x610
+#define STEP_ID_PORT2_CASSETTE_TYPE_CHANGE		0x611
+#define STEP_ID_PORT3_CASSETTE_TYPE_CHANGE		0x612
+#define STEP_ID_PORT4_CASSETTE_TYPE_CHANGE		0x613
+#define STEP_ID_PORT1_TRANSFER_MODE_CHANGE		0x618
+#define STEP_ID_PORT2_TRANSFER_MODE_CHANGE		0x619
+#define STEP_ID_PORT3_TRANSFER_MODE_CHANGE		0x61A
+#define STEP_ID_PORT4_TRANSFER_MODE_CHANGE		0x61B
+#define STEP_ID_PORT1_ENABLE_MODE_CHANGE		0x620
+#define STEP_ID_PORT2_ENABLE_MODE_CHANGE		0x621
+#define STEP_ID_PORT3_ENABLE_MODE_CHANGE		0x622
+#define STEP_ID_PORT4_ENABLE_MODE_CHANGE		0x623
+#define STEP_ID_PORT1_TYPE_AUTO_CHANGE			0x628
+#define STEP_ID_PORT2_TYPE_AUTO_CHANGE			0x629
+#define STEP_ID_PORT3_TYPE_AUTO_CHANGE			0x62A
+#define STEP_ID_PORT4_TYPE_AUTO_CHANGE			0x62B
+#define STEP_ID_PORT1_CASSETTIE_EMPTY			0x638
+#define STEP_ID_PORT1_CASSETTIE_LOAD_READY		0x640
+#define STEP_ID_PORT1_CASSETTIE_LOADED			0x648
+#define STEP_ID_PORT1_CASSETTIE_INUSE			0x650
+#define STEP_ID_PORT1_CASSETTIE_UNLOAD_READY	0x658
+#define STEP_ID_PORT1_CASSETTIE_BLOCKED			0x660
+#define STEP_ID_PORT2_CASSETTIE_EMPTY			0x639
+#define STEP_ID_PORT2_CASSETTIE_LOAD_READY		0x641
+#define STEP_ID_PORT2_CASSETTIE_LOADED			0x649
+#define STEP_ID_PORT2_CASSETTIE_INUSE			0x651
+#define STEP_ID_PORT2_CASSETTIE_UNLOAD_READY	0x659
+#define STEP_ID_PORT2_CASSETTIE_BLOCKED			0x661
+#define STEP_ID_PORT3_CASSETTIE_EMPTY			0x63a
+#define STEP_ID_PORT3_CASSETTIE_LOAD_READY		0x642
+#define STEP_ID_PORT3_CASSETTIE_LOADED			0x64a
+#define STEP_ID_PORT3_CASSETTIE_INUSE			0x652
+#define STEP_ID_PORT3_CASSETTIE_UNLOAD_READY	0x65a
+#define STEP_ID_PORT3_CASSETTIE_BLOCKED			0x662
+#define STEP_ID_PORT4_CASSETTIE_EMPTY			0x63b
+#define STEP_ID_PORT4_CASSETTIE_LOAD_READY		0x643
+#define STEP_ID_PORT4_CASSETTIE_LOADED			0x64b
+#define STEP_ID_PORT4_CASSETTIE_INUSE			0x653
+#define STEP_ID_PORT4_CASSETTIE_UNLOAD_READY	0x65b
+#define STEP_ID_PORT4_CASSETTIE_BLOCKED			0x663
 
 
 /* base alarm */
@@ -219,3 +279,22 @@
 #define CASSETTE_PROCCESS_COMPLETED		7
 
 
+/*
+	Master Recipe List Return Code Block	Description
+		1	OK : Recipe List Received Result is all ok
+		2	Continue : Equipment still has to send the master recipe list to EAS because EAS is not yet received all master recipe list.
+		3	Master Recipe list Count NG : Total Group Count is same as Current Group Count but it’s different with Total Master Recipe List Count.
+		4	Group Count NG : Total Group Count is different with Current Group Count but it’s same with Total Master Recipe Count.
+		5	Duplication Group Count NG : Current Group Count is duplicate with previous group count.Equipment has to send the next group count to EAS.
+		6	Order by Group Count NG : Group Count is not sent order by next group count to EAS.Group Count has to send by order the next group count
+*/
+#define MRLRC_CURRENT_RECIPE_COMPLETE		0
+#define MRLRC_OK							1
+#define MRLRC_NG							2
+#define MRLRC_CONTINUE						3
+#define MRLRC_MASTER_RECIPE_LIST_COUNT_NG	4
+#define MRLRC_GROUP_COUNT_NG				5
+#define MRLRC_DUPLICATION_GROUP_COUNT_NG	6
+#define ORDER_BY_GROUP_COUNT_NG				7
+
+
diff --git a/SourceCode/Bond/Servo/LogDlg.cpp b/SourceCode/Bond/Servo/LogDlg.cpp
index 560b5cc..f8fa9b8 100644
--- a/SourceCode/Bond/Servo/LogDlg.cpp
+++ b/SourceCode/Bond/Servo/LogDlg.cpp
@@ -154,7 +154,7 @@
 
 
 	// 内容
-	m_logEdit.SetMaxLineCount(20);
+	m_logEdit.SetMaxLineCount(500);
 	m_logEdit.SetLimitText(-1);
 
 
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 9ef4836..5dab65a 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -149,6 +149,9 @@
 			pEquipment->getBaseAlarmId() + alarmId,
 			strAlarmText.c_str());
 	};
+	masterListener.onEqVcrEventReport = [&](void* pMaster, SERVO::CEquipment* pEquipment, SERVO::CVcrEventReport* pReport) {
+		LOGE("<CModel>onEqVcrEventReport.");
+	};
 	m_master.setListener(masterListener);
 
 
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 56533a9..9569c6b 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 c011bc2..65355a0 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="CEqCassetteCtrlCmdStep.h" />
     <ClInclude Include="CEqCassetteTransferStateStep.h" />
     <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h" />
     <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h" />
@@ -212,33 +213,47 @@
     <ClInclude Include="CEqCimMessageCmdStep.h" />
     <ClInclude Include="CEqCimModeChangeStep.h" />
     <ClInclude Include="CEqDateTimeSetCmdStep.h" />
+    <ClInclude Include="CEqJobEventStep.h" />
     <ClInclude Include="CEqModeChangeStep.h" />
     <ClInclude Include="CEqModeStep.h" />
     <ClInclude Include="CEqPortChangeStep.h" />
     <ClInclude Include="CEqProcessStep.h" />
     <ClInclude Include="CEqReadIntStep.h" />
+    <ClInclude Include="CEqReadStep.h" />
     <ClInclude Include="CEqStatusStep.h" />
     <ClInclude Include="CEquipmentPage1.h" />
     <ClInclude Include="CEquipmentPage2.h" />
     <ClInclude Include="CEqVCREnableStep.h" />
+    <ClInclude Include="CEqVcrEventStep.h" />
+    <ClInclude Include="CEqWriteStep.h" />
     <ClInclude Include="CFliper.h" />
     <ClInclude Include="CGlass.h" />
     <ClInclude Include="CHMPropertyDlg.h" />
     <ClInclude Include="CHMPropertyPage.h" />
+    <ClInclude Include="CJobDataA.h" />
+    <ClInclude Include="CJobDataB.h" />
+    <ClInclude Include="CJobDataC.h" />
+    <ClInclude Include="CJobDataS.h" />
     <ClInclude Include="CLoadPort.h" />
     <ClInclude Include="CMeasurement.h" />
     <ClInclude Include="ColorTransfer.h" />
+    <ClInclude Include="CPageCassetteCtrlCmd.h" />
     <ClInclude Include="CPageGraph1.h" />
     <ClInclude Include="CPageGraph2.h" />
+    <ClInclude Include="CPagePortProperty.h" />
     <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="CEqCurrentRecipeChangeStep.h" />
+    <ClInclude Include="CRecipeList.h" />
+    <ClInclude Include="CRecipesManager.h" />
     <ClInclude Include="CSample.h" />
     <ClInclude Include="CStep.h" />
     <ClInclude Include="CVacuumBake.h" />
+    <ClInclude Include="CVcrEventReport.h" />
     <ClInclude Include="CWriteStep.h" />
     <ClInclude Include="DevicePropertyDlg.h" />
     <ClInclude Include="CEFEM.h" />
@@ -282,6 +297,7 @@
     <ClCompile Include="CAttributeVector.cpp" />
     <ClCompile Include="CBakeCooling.cpp" />
     <ClCompile Include="CBonder.cpp" />
+    <ClCompile Include="CEqCassetteCtrlCmdStep.cpp" />
     <ClCompile Include="CEqCassetteTransferStateStep.cpp" />
     <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp" />
     <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp" />
@@ -290,33 +306,47 @@
     <ClCompile Include="CEqCimMessageCmdStep.cpp" />
     <ClCompile Include="CEqCimModeChangeStep.cpp" />
     <ClCompile Include="CEqDateTimeSetCmdStep.cpp" />
+    <ClCompile Include="CEqJobEventStep.cpp" />
     <ClCompile Include="CEqModeChangeStep.cpp" />
     <ClCompile Include="CEqModeStep.cpp" />
     <ClCompile Include="CEqPortChangeStep.cpp" />
     <ClCompile Include="CEqProcessStep.cpp" />
     <ClCompile Include="CEqReadIntStep.cpp" />
+    <ClCompile Include="CEqReadStep.cpp" />
     <ClCompile Include="CEqStatusStep.cpp" />
     <ClCompile Include="CEquipmentPage1.cpp" />
     <ClCompile Include="CEquipmentPage2.cpp" />
     <ClCompile Include="CEqVCREnableStep.cpp" />
+    <ClCompile Include="CEqVcrEventStep.cpp" />
+    <ClCompile Include="CEqWriteStep.cpp" />
     <ClCompile Include="CFliper.cpp" />
     <ClCompile Include="CGlass.cpp" />
     <ClCompile Include="CHMPropertyDlg.cpp" />
     <ClCompile Include="CHMPropertyPage.cpp" />
+    <ClCompile Include="CJobDataA.cpp" />
+    <ClCompile Include="CJobDataB.cpp" />
+    <ClCompile Include="CJobDataC.cpp" />
+    <ClCompile Include="CJobDataS.cpp" />
     <ClCompile Include="CLoadPort.cpp" />
     <ClCompile Include="CMeasurement.cpp" />
     <ClCompile Include="ColorTransfer.cpp" />
+    <ClCompile Include="CPageCassetteCtrlCmd.cpp" />
     <ClCompile Include="CPageGraph1.cpp" />
     <ClCompile Include="CPageGraph2.cpp" />
+    <ClCompile Include="CPagePortProperty.cpp" />
     <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="CEqCurrentRecipeChangeStep.cpp" />
+    <ClCompile Include="CRecipeList.cpp" />
+    <ClCompile Include="CRecipesManager.cpp" />
     <ClCompile Include="CSample.cpp" />
     <ClCompile Include="CStep.cpp" />
     <ClCompile Include="CVacuumBake.cpp" />
+    <ClCompile Include="CVcrEventReport.cpp" />
     <ClCompile Include="CWriteStep.cpp" />
     <ClCompile Include="DevicePropertyDlg.cpp" />
     <ClCompile Include="CEFEM.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 9bd2400..7e9e760 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -82,8 +82,21 @@
     <ClCompile Include="CEqPortChangeStep.cpp" />
     <ClCompile Include="CEqReadIntStep.cpp" />
     <ClCompile Include="CEqCassetteTransferStateStep.cpp" />
-    <ClCompile Include="ProductionLogManager.cpp" />
-    <ClCompile Include="ProductionLogDlg.cpp" />
+    <ClCompile Include="CEqCassetteCtrlCmdStep.cpp" />
+    <ClCompile Include="CJobDataA.cpp" />
+    <ClCompile Include="CPageCassetteCtrlCmd.cpp" />
+    <ClCompile Include="CEqJobEventStep.cpp" />
+    <ClCompile Include="CJobDataB.cpp" />
+    <ClCompile Include="CJobDataC.cpp" />
+    <ClCompile Include="CJobDataS.cpp" />
+    <ClCompile Include="CVcrEventReport.cpp" />
+    <ClCompile Include="CEqVcrEventStep.cpp" />
+    <ClCompile Include="CPagePortProperty.cpp" />
+    <ClCompile Include="CEqCurrentRecipeChangeStep.cpp" />
+    <ClCompile Include="CEqWriteStep.cpp" />
+    <ClCompile Include="CEqReadStep.cpp" />
+    <ClCompile Include="CRecipesManager.cpp" />
+    <ClCompile Include="CRecipeList.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -164,8 +177,21 @@
     <ClInclude Include="CEqPortChangeStep.h" />
     <ClInclude Include="CEqReadIntStep.h" />
     <ClInclude Include="CEqCassetteTransferStateStep.h" />
-    <ClInclude Include="ProductionLogManager.h" />
-    <ClInclude Include="ProductionLogDlg.h" />
+    <ClInclude Include="CEqCassetteCtrlCmdStep.h" />
+    <ClInclude Include="CJobDataA.h" />
+    <ClInclude Include="CPageCassetteCtrlCmd.h" />
+    <ClInclude Include="CEqJobEventStep.h" />
+    <ClInclude Include="CJobDataB.h" />
+    <ClInclude Include="CJobDataC.h" />
+    <ClInclude Include="CJobDataS.h" />
+    <ClInclude Include="CVcrEventReport.h" />
+    <ClInclude Include="CEqVcrEventStep.h" />
+    <ClInclude Include="CPagePortProperty.h" />
+    <ClInclude Include="CEqCurrentRecipeChangeStep.h" />
+    <ClInclude Include="CEqWriteStep.h" />
+    <ClInclude Include="CEqReadStep.h" />
+    <ClInclude Include="CRecipesManager.h" />
+    <ClInclude Include="CRecipeList.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/ToolUnits.cpp b/SourceCode/Bond/Servo/ToolUnits.cpp
index b32362a..f3a88bc 100644
--- a/SourceCode/Bond/Servo/ToolUnits.cpp
+++ b/SourceCode/Bond/Servo/ToolUnits.cpp
@@ -316,4 +316,17 @@
 	strOut = ss.str();
 
 	return strOut;
+}
+
+void CToolUnits::convertString(const char* pszBuffer, int size, std::string& strOut)
+{
+	strOut.clear();
+	int nLength = 0;
+	for (int i = 0; i < size; i++) {
+		if (pszBuffer[i] == '\0') break;
+		nLength++;
+	}
+	if (nLength > 0) {
+		strOut = std::string(pszBuffer, nLength);
+	}
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/ToolUnits.h b/SourceCode/Bond/Servo/ToolUnits.h
index fddb2e3..feeae08 100644
--- a/SourceCode/Bond/Servo/ToolUnits.h
+++ b/SourceCode/Bond/Servo/ToolUnits.h
@@ -30,5 +30,6 @@
 	static std::string getCurrentTimeString();
 	static bool startsWith(const std::string& str, const std::string& prefix);
 	static std::string& toHexString(int value, std::string& strOut);
+	static void convertString(const char* pszBuffer, int size, std::string& strOut);
 };
 
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index c47a946..b61d88b 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3