From a8fb417ef1fb696723c8b8d5a340e8ca2e0312ae Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期六, 09 八月 2025 10:43:17 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/Servo/CPagePortProperty.cpp            |    3 
 SourceCode/Bond/Servo/CVariable.h                      |    5 
 SourceCode/Bond/EAPSimulator/CHsmsActive.h             |   14 +
 SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h         |    2 
 SourceCode/Bond/Servo/HsmsPassive.cpp                  |  120 ++++++++++++
 SourceCode/Bond/Servo/PageLog.cpp                      |    9 
 SourceCode/Bond/Servo/Configuration.cpp                |   11 +
 SourceCode/Bond/Servo/CMaster.h                        |   14 +
 SourceCode/Bond/Servo/CCollectionEvent.cpp             |    8 
 SourceCode/Bond/Servo/Configuration.h                  |    2 
 SourceCode/Bond/EAPSimulator/CHsmsActive.cpp           |   32 +++
 SourceCode/Bond/EAPSimulator/Resource.h                |    6 
 SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp       |   15 +
 SourceCode/Bond/Servo/CEquipment.cpp                   |    4 
 SourceCode/Bond/Servo/CPortStatusReport.h              |    1 
 SourceCode/Bond/Servo/Servo.rc                         |    0 
 SourceCode/Bond/Servo/CMaster.cpp                      |  138 +++++++++++++-
 SourceCode/Bond/x64/Debug/ReportList.txt               |    2 
 SourceCode/Bond/Servo/HsmsPassive.h                    |   28 +++
 SourceCode/Bond/EAPSimulator/EAPSimulator.rc           |    0 
 SourceCode/Bond/Servo/Model.cpp                        |   35 +++
 SourceCode/Bond/Servo/CLoadPort.cpp                    |   26 ++
 SourceCode/Bond/Servo/ServoDlg.cpp                     |   10 +
 SourceCode/Bond/x64/Debug/VariableList.txt             |    1 
 SourceCode/Bond/Servo/CPortStatusReport.cpp            |    5 
 SourceCode/Bond/Servo/CCollectionEvent.h               |    4 
 SourceCode/Bond/x64/Debug/CollectionEventList.txt      |    1 
 SourceCode/Bond/Servo/CVariable.cpp                    |   38 ++++
 Document/Panel Bonder八零联合 SecsTest CheckList_v3.0.xlsx |    0 
 29 files changed, 491 insertions(+), 43 deletions(-)

diff --git "a/Document/Panel Bonder\345\205\253\351\233\266\350\201\224\345\220\210 SecsTest CheckList_v3.0.xlsx" "b/Document/Panel Bonder\345\205\253\351\233\266\350\201\224\345\220\210 SecsTest CheckList_v3.0.xlsx"
index 48e2a37..e062180 100644
--- "a/Document/Panel Bonder\345\205\253\351\233\266\350\201\224\345\220\210 SecsTest CheckList_v3.0.xlsx"
+++ "b/Document/Panel Bonder\345\205\253\351\233\266\350\201\224\345\220\210 SecsTest CheckList_v3.0.xlsx"
Binary files differ
diff --git a/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp b/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
index 1605306..2dc424f 100644
--- a/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
+++ b/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
@@ -299,6 +299,38 @@
 	return 0;
 }
 
+int CHsmsActive::hsmsCarrierActionRequest(unsigned int DATAID, 
+	const char* pszCarrierAction, 
+	const char* pszCarrierId,
+	unsigned char PTN)
+{
+	IMessage* pMessage = nullptr;
+	int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 3 | REPLY, 17, ++m_nSystemByte);
+	pMessage->getBody()->addU4Item(DATAID, "DATAID");
+	pMessage->getBody()->addItem(pszCarrierAction, "CARRIERACTION");
+	pMessage->getBody()->addItem(pszCarrierId, "CARRIERID");
+	pMessage->getBody()->addU1Item(PTN, "PTN");
+	pMessage->getBody()->addItem();
+	m_pActive->sendMessage(pMessage);
+	HSMS_Destroy1Message(pMessage);
+
+	return 0;
+}
+
+int CHsmsActive::hsmsProceedWithCarrier(unsigned int DATAID,
+	const char* pszCarrierId,
+	unsigned char PTN)
+{
+	return hsmsCarrierActionRequest(DATAID, "ProceedWithCarrier", pszCarrierId, PTN);
+}
+
+int CHsmsActive::hsmsCarrierRelease(unsigned int DATAID,
+	const char* pszCarrierId,
+	unsigned char PTN)
+{
+	return hsmsCarrierActionRequest(DATAID, "CarrierRelease", pszCarrierId, PTN);
+}
+
 int CHsmsActive::replyAck0(IMessage* pMessage)
 {
 	return 0;
diff --git a/SourceCode/Bond/EAPSimulator/CHsmsActive.h b/SourceCode/Bond/EAPSimulator/CHsmsActive.h
index d6ff5b6..b814d4b 100644
--- a/SourceCode/Bond/EAPSimulator/CHsmsActive.h
+++ b/SourceCode/Bond/EAPSimulator/CHsmsActive.h
@@ -64,6 +64,20 @@
 	// 查询PPID List
 	int hsmsQueryPPIDList();
 
+	// S3F17
+	// 卡匣动作请求
+	int hsmsCarrierActionRequest(unsigned int DATAID, 
+		const char* pszCarrierAction,
+		const char* pszCarrierId,
+		unsigned char PTN);
+	int hsmsProceedWithCarrier(unsigned int DATAID,
+		const char* pszCarrierId,
+		unsigned char PTN);
+	int CHsmsActive::hsmsCarrierRelease(unsigned int DATAID,
+		const char* pszCarrierId,
+		unsigned char PTN);
+
+
 	// 通过的reply函数
 	void replyAck(int s, int f, unsigned int systemBytes, BYTE ack, const char* pszAckName);
 
diff --git a/SourceCode/Bond/EAPSimulator/EAPSimulator.rc b/SourceCode/Bond/EAPSimulator/EAPSimulator.rc
index a7c343f..f489bd8 100644
--- a/SourceCode/Bond/EAPSimulator/EAPSimulator.rc
+++ b/SourceCode/Bond/EAPSimulator/EAPSimulator.rc
Binary files differ
diff --git a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
index f95c6ee..3af62af 100644
--- a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
+++ b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
@@ -88,6 +88,8 @@
 	ON_BN_CLICKED(IDC_BUTTON_TRANSMIT_SPOOLED_DATA, &CEAPSimulatorDlg::OnBnClickedButtonTransmitSpooledData)
 	ON_BN_CLICKED(IDC_BUTTON_PURGE_SPOOLED_DATA, &CEAPSimulatorDlg::OnBnClickedButtonPurgeSpooledData)
 	ON_BN_CLICKED(IDC_BUTTON_QUERY_PPID_LIST, &CEAPSimulatorDlg::OnBnClickedButtonQueryPpidList)
+	ON_BN_CLICKED(IDC_BUTTON_PROCEED_WITH_CARRIER, &CEAPSimulatorDlg::OnBnClickedButtonProceedWithCarrier)
+	ON_BN_CLICKED(IDC_BUTTON_CARRIER_RELEASE, &CEAPSimulatorDlg::OnBnClickedButtonCarrierRelease)
 END_MESSAGE_MAP()
 
 
@@ -275,6 +277,8 @@
 	GetDlgItem(IDC_BUTTON_TRANSMIT_SPOOLED_DATA)->EnableWindow(enabled);
 	GetDlgItem(IDC_BUTTON_PURGE_SPOOLED_DATA)->EnableWindow(enabled);
 	GetDlgItem(IDC_BUTTON_QUERY_PPID_LIST)->EnableWindow(enabled);	
+	GetDlgItem(IDC_BUTTON_PROCEED_WITH_CARRIER)->EnableWindow(enabled);	
+	GetDlgItem(IDC_BUTTON_CARRIER_RELEASE)->EnableWindow(enabled);
 }
 
 void CEAPSimulatorDlg::OnBnClickedButtonConnect()
@@ -376,3 +380,14 @@
 {
 	theApp.m_model.m_pHsmsActive->hsmsQueryPPIDList();
 }
+
+static int DATAID = 1;
+void CEAPSimulatorDlg::OnBnClickedButtonProceedWithCarrier()
+{
+	theApp.m_model.m_pHsmsActive->hsmsProceedWithCarrier(DATAID++, "CSX 52078", 1);
+}
+
+void CEAPSimulatorDlg::OnBnClickedButtonCarrierRelease()
+{
+	theApp.m_model.m_pHsmsActive->hsmsCarrierRelease(DATAID++, "CSX 52078", 2);
+}
diff --git a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
index c243873..c19a88e 100644
--- a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
+++ b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
@@ -57,4 +57,6 @@
 	afx_msg void OnBnClickedButtonTransmitSpooledData();
 	afx_msg void OnBnClickedButtonPurgeSpooledData();
 	afx_msg void OnBnClickedButtonQueryPpidList();
+	afx_msg void OnBnClickedButtonProceedWithCarrier();
+	afx_msg void OnBnClickedButtonCarrierRelease();
 };
diff --git a/SourceCode/Bond/EAPSimulator/Resource.h b/SourceCode/Bond/EAPSimulator/Resource.h
index f3daccf..b39967c 100644
--- a/SourceCode/Bond/EAPSimulator/Resource.h
+++ b/SourceCode/Bond/EAPSimulator/Resource.h
@@ -44,10 +44,12 @@
 #define IDC_BUTTON_CONFIGURE_SPOOLING   1029
 #define IDC_BUTTON_PURGE_SPOOLED_DATA   1030
 #define IDC_EDIT_CE_NAME                1031
-#define IDC_BUTTON_QUERY_PPID_LIST		1032
+#define IDC_BUTTON_QUERY_PPID_LIST      1032
 #define IDC_EDIT_CE_RPTID               1033
+#define IDC_BUTTON_PROCEED_WITH_CARRIER 1033
 #define IDC_BUTTON_TRANSMIT_SPOOLED_DATA 1034
-
+#define IDC_BUTTON_PROCEED_WITH_CARRIER2 1035
+#define IDC_BUTTON_CARRIER_RELEASE      1035
 
 // Next default values for new objects
 // 
diff --git a/SourceCode/Bond/Servo/CCollectionEvent.cpp b/SourceCode/Bond/Servo/CCollectionEvent.cpp
index a0b7773..ce5d1a2 100644
--- a/SourceCode/Bond/Servo/CCollectionEvent.cpp
+++ b/SourceCode/Bond/Servo/CCollectionEvent.cpp
@@ -59,7 +59,7 @@
 		}
 	}
 
-	unsigned int CCollectionEvent::getPortID()
+	unsigned int CCollectionEvent::getFirstPortID()
 	{
 		if (m_reports.empty()) return -1;
 		return m_reports.front()->getReportId();
@@ -90,6 +90,12 @@
 		return nullptr;
 	}
 
+	CReport* CCollectionEvent::getFirstReport()
+	{
+		if (m_reports.empty()) return nullptr;
+		return m_reports.front();
+	}
+
 	std::vector<CReport*>& CCollectionEvent::getReports()
 	{
 		return m_reports;
diff --git a/SourceCode/Bond/Servo/CCollectionEvent.h b/SourceCode/Bond/Servo/CCollectionEvent.h
index bfad5fb..a0b023d 100644
--- a/SourceCode/Bond/Servo/CCollectionEvent.h
+++ b/SourceCode/Bond/Servo/CCollectionEvent.h
@@ -23,7 +23,9 @@
 
 		/* 如果一个CEID只有一个Report的场景,调用此函数设置或取消 */
 		void setReport(CReport* pReport);
-		unsigned int getPortID();
+		unsigned int getFirstPortID();
+		CReport* getFirstReport();
+
 	private:
 		unsigned int m_nCEID;
 		std::string m_strName;
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 322923d..7560957 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -1990,14 +1990,14 @@
 	 */
 	int CEquipment::onSendAble(int port)
 	{
-		LOGI("<CEquipment-%s>onSendAble.port:%d", m_strName.c_str(), port);
+		// LOGI("<CEquipment-%s>onSendAble.port:%d", m_strName.c_str(), port);
 
 		return 0;
 	}
 
 	int CEquipment::onReceiveAble(int port)
 	{
-		LOGI("<CEquipment-%s>onReceiveAble.port:%d", m_strName.c_str(), port);
+		// LOGI("<CEquipment-%s>onReceiveAble.port:%d", m_strName.c_str(), port);
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CLoadPort.cpp b/SourceCode/Bond/Servo/CLoadPort.cpp
index 29b9050..f603990 100644
--- a/SourceCode/Bond/Servo/CLoadPort.cpp
+++ b/SourceCode/Bond/Servo/CLoadPort.cpp
@@ -350,17 +350,30 @@
 	{
 		CEquipment::onTimer(nTimerid);
 
+
+		// 从配置读出的enable,初始化时写给efem
+		static int i_enable[4] = { 0 };
+		if ((++i_enable[m_nIndex]) == 10 + m_nIndex) {
+			eablePort(m_bEnable, [&](int code) -> int {
+				LOGI("<LoadPort-%d>eablePort:code=%d", m_nIndex, code);
+				return 0;
+				});
+		}
+
+
+
 		// 模拟测试
 		/*
 		if (m_nIndex == 0) {
 			static int ii = 0;
 			ii++;
-			if (ii == 20) {
+			if (ii == 50) {
 				char szBuffer[64] = {0};
 				CStep* pStep = getStepWithName(STEP_EQ_PORT1_INUSE);
 				CPortStatusReport portStatusReport;
-				portStatusReport.setPortStatus(PORT_UNLOAD_READY);
+				portStatusReport.setPortStatus(PORT_INUSE);
 				portStatusReport.setJobExistenceSlot(0xf);
+				portStatusReport.setCassetteId("CID1984113");
 				int nRet = portStatusReport.serialize(szBuffer, 64);
 				decodePortStatusReport(pStep, szBuffer, 64);
 			}
@@ -913,13 +926,12 @@
 			else {
 				// 抛出到应用层做选择要加工的片子
 				generateGlassList(getScanCassetteMap());
-				if (m_listener.onPortStatusChanged != nullptr) {
-					m_listener.onPortStatusChanged(this, portStatusReport.getPortStatus(),
-						getScanCassetteMap());
-				}
 			}
 		}
-
+		if (m_listener.onPortStatusChanged != nullptr) {
+			m_listener.onPortStatusChanged(this, portStatusReport.getPortStatus(),
+				getScanCassetteMap());
+		}
 
 
 		// 缓存Attribute,用于调试时显示信息
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 6714999..455804a 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -55,6 +55,8 @@
 		m_bEnableEventReport = true;
 		m_bEnableAlarmReport = true;
 		m_bContinuousTransfer = false;
+		m_nContinuousTransferCount = 0;
+		m_nContinuousTransferStep = CTStep_begin;
 		InitializeCriticalSection(&m_criticalSection);
 	}
 
@@ -294,7 +296,7 @@
 
 	ULONGLONG CMaster::getRunTime()
 	{
-		if (m_state == MASTERSTATE::RUNNING)
+		if (m_state == MASTERSTATE::RUNNING || m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER)
 			return m_ullRunTime + (GetTickCount64() - m_ullStartTime);
 		else
 			return m_ullRunTime;
@@ -345,7 +347,7 @@
 		while (1) {
 			// 待退出信号或时间到
 			HANDLE hEvents[] = { m_hEventDispatchThreadExit[0], m_hDispatchEvent };
-			int nRet = WaitForMultipleObjects(2, hEvents, FALSE, 1000);
+			int nRet = WaitForMultipleObjects(2, hEvents, FALSE, 500);
 			if (nRet == WAIT_OBJECT_0) {
 				break;
 			}
@@ -713,6 +715,7 @@
 							m_pActiveRobotTask = createTransferTask_continuous_transfer(pMeasurement,
 								0, pLoadPorts[s], slot);
 							if (m_pActiveRobotTask != nullptr) {
+								m_nContinuousTransferStep = CTStep_end;
 								goto CT_PORT_PUT;
 							}
 						}
@@ -727,6 +730,9 @@
 				if (!rmd.armState[0]) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
 						3, pMeasurement, 0);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(BakeCooling -> Measurement)...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
@@ -735,44 +741,75 @@
 				if (!rmd.armState[0]) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
 						2, pBakeCooling, 3);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(BakeCooling-2 -> BakeCooling-3)...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 				if (!rmd.armState[0]) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
 						1, pBakeCooling, 2);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(BakeCooling-1 -> BakeCooling-2)...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 				if (!rmd.armState[0]) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pBakeCooling,
 						0, pBakeCooling, 1);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(BakeCooling-0 -> BakeCooling-1)...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
-				// Bonder2 -> BakeCooling
+				// VacuumBake(G1) -> BakeCooling
+				if (!rmd.armState[0]) {
+					m_pActiveRobotTask = createTransferTask_continuous_transfer(pVacuumBake,
+						1, pBakeCooling, 0);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(VacuumBake(G1) -> BakeCooling)...");
+					}
+					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+				}
+
+				// VacuumBake(G1) -> VacuumBake(G1)
+				if (!rmd.armState[0]) {
+					m_pActiveRobotTask = createTransferTask_continuous_transfer(pVacuumBake,
+						0, pVacuumBake, 1);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(VacuumBake(G1-0) -> VacuumBake(G1-1))...");
+					}
+					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
+				}
+
+				// Bonder2 -> VacuumBake(G1)
 				if (!rmd.armState[0]) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pBonder2,
-						0, pBakeCooling, 0);
+						1, pVacuumBake, 0);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(Bonder2 -> VacuumBake(G1))...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
-
+				
 				// Bonder1 -> Bonder2
 				if (!rmd.armState[0] && !pBonder2->hasBondClass()) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pBonder1,
-						0, pBonder2, 0);
+						1, pBonder2, 1);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(Bonder1 -> Bonder2)...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
-				// VacuumBake(G1) -> Bonder1
+				// Fliper(G2) -> Bonder1
 				if (!rmd.armState[0] && !pBonder1->hasBondClass()) {
-					m_pActiveRobotTask = createTransferTask_continuous_transfer(pVacuumBake,
-						0, pBonder1, 0);
-					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
-				}
-
-				// Fliper(G2) -> VacuumBake(G1)
-				if (!rmd.armState[0]) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pFliper,
-						0, pVacuumBake, 0);
+						0, pBonder1, 1, 2);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(Fliper(G2) -> Bonder1)...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
@@ -780,6 +817,9 @@
 				if (!rmd.armState[1]) {
 					m_pActiveRobotTask = createTransferTask_continuous_transfer(pAligner,
 						0, pFliper, 0);
+					if (m_pActiveRobotTask != nullptr) {
+						LOGI("<ContinuousTransfer>千传测试,开始搬送任务(Aligner -> Fliper(G2))...");
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
@@ -793,6 +833,7 @@
 							m_pActiveRobotTask = createTransferTask_continuous_transfer(pLoadPorts[s], 
 								slot, pAligner, 0);
 							if (m_pActiveRobotTask != nullptr) {
+								LOGI("<ContinuousTransfer>千传测试,开始搬送任务(LoadPort -> Aligner)...");
 								pEFEM->setContext(m_pActiveRobotTask->getContext());
 								goto CT_PORT_GET;
 							}
@@ -801,6 +842,10 @@
 				}
 
 			CT_PORT_GET:
+				if (m_pActiveRobotTask != nullptr) {
+					m_nContinuousTransferStep = CTStep_begin;
+					LOGI("<ContinuousTransfer>千传测试,开始第 %d 轮", m_nContinuousTransferCount + 1);
+				}
 				CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 
 
@@ -822,6 +867,16 @@
 
 	unsigned CMaster::ReadBitsProc()
 	{
+		// 标志位清0复位		
+		{
+			StationIdentifier station;
+			station.nNetNo = 0;
+			station.nStNo = 255;
+			char szBuffer[528] = { 0 };	// 0x0, 0x1087
+			m_cclink.WriteData(station, (long)DeviceType::B, 0, 528, (short*)szBuffer);
+		}
+
+
 		while (1) {
 			// 待退出信号或时间到
 			int nRet = ::WaitForSingleObject(m_hEventReadBitsThreadExit[0], 1000);
@@ -882,6 +937,8 @@
 		listener.onPreFethedOutJob = [&](void* pEquipment, int port, CJobDataB* pJobDataB) -> BOOL {
 			CEquipment* p = (CEquipment*)pEquipment;
 
+			// 可能要加这一句
+			Sleep(750);
 
 			// 取片,更新当前搬送任务
 			BOOL bOk = FALSE;
@@ -915,6 +972,8 @@
 		listener.onPreStoredJob = [&](void* pEquipment, int port, CJobDataB* pJobDataB, short& slot) -> BOOL {
 			CEquipment* p = (CEquipment*)pEquipment;
 
+			// 可能要加这一句
+			Sleep(750);
 
 			// 放片,更新当前搬送任务
 			BOOL bOk = FALSE;
@@ -992,6 +1051,17 @@
 					&& m_pActiveRobotTask->getTarPosition() == p->getID()) {
 					m_pActiveRobotTask->stored();
 					m_pActiveRobotTask->completed();
+
+					if (m_state == MASTERSTATE::RUNNING_CONTINUOUS_TRANSFER) {
+						if (m_nContinuousTransferStep == CTStep_end) {
+							m_nContinuousTransferCount++;
+							LOGI("<ContinuousTransfer>千传测试,第 %d 轮结束", m_nContinuousTransferCount);
+							if (m_listener.onCTRoundEnd != nullptr) {
+								m_listener.onCTRoundEnd(this, m_nContinuousTransferCount);
+							}
+						}
+					}
+
 					LOGI("放片完成...");
 					// 完成此条搬送任务,但要把数据和消息上抛应用层
 					unlock();
@@ -1034,7 +1104,7 @@
 				((CEquipment*)pEquipment)->getName().c_str(), scanMap, downMap);
 		};
 		listener.onPortStatusChanged = [&](void* pEquipment, short status, __int64 data) {
-			LOGE("<Master-%s>Port InUse。status=%d, data=%lld", ((CEquipment*)pEquipment)->getName().c_str(), status);
+			LOGE("<Master-%s>onPortStatusChanged。status=%d, data=%lld", ((CEquipment*)pEquipment)->getName().c_str(), status);
 			if (m_listener.onLoadPortStatusChanged != nullptr) {
 				m_listener.onLoadPortStatusChanged(this, (CEquipment*)pEquipment, status, data);
 			}
@@ -1582,8 +1652,12 @@
 		}
 
 		CRobotTask* pTask = nullptr;
-		CSlot* pTarSlot = pTarEq->isSlotAvailable(nTarSlot);
 		CSlot* pSrcSlot = pSrcEq->getProcessedSlotCt(nSrcSlot);
+		if (pSrcSlot != nullptr && pSrcEq->getID() == EQ_ID_MEASUREMENT
+			&& (pTarEq->getID() == EQ_ID_LOADPORT1 || pTarEq->getID() == EQ_ID_LOADPORT2 || pTarEq->getID() == EQ_ID_LOADPORT3 || pTarEq->getID() == EQ_ID_LOADPORT4)) {
+			pTarEq->removeGlass(1);
+		}
+		CSlot* pTarSlot = pTarEq->isSlotAvailable(nTarSlot);
 		if (pSrcSlot != nullptr && nullptr != pTarSlot) {
 			pTask = new CRobotTask();
 			pTask->setContext(pSrcSlot->getContext());
@@ -1703,4 +1777,34 @@
 	{
 		return m_bEnableAlarmReport;
 	}
+
+	int CMaster::proceedWithCarrier(unsigned int port)
+	{
+		if (port >= 4) return -1;
+
+		static int pid[] = { EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4};
+		CLoadPort* pPort = (CLoadPort*)getEquipment(pid[port]);
+		pPort->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
+		return 0;
+	}
+
+	int CMaster::carrierRelease(unsigned int port)
+	{
+		if (port >= 4) return -1;
+
+		static int pid[] = { EQ_ID_LOADPORT1, EQ_ID_LOADPORT2, EQ_ID_LOADPORT3, EQ_ID_LOADPORT4 };
+		CLoadPort* pPort = (CLoadPort*)getEquipment(pid[port]);
+		pPort->sendCassetteCtrlCmd(CCC_PROCESS_CANCEL, nullptr, 0, 0, 0, nullptr, nullptr);
+		return 0;
+	}
+
+	int CMaster::getContinuousTransferCount()
+	{
+		return m_nContinuousTransferCount;
+	}
+
+	void CMaster::setContinuousTransferCount(int round)
+	{
+		m_nContinuousTransferCount = round;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index 7b16db8..e5f868d 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -15,6 +15,9 @@
 #include "CRobotTask.h"
 
 
+#define CTStep_begin        0
+#define CTStep_end          99
+
 namespace SERVO {
     enum class MASTERSTATE {
         READY = 0,
@@ -33,6 +36,7 @@
     typedef std::function<void(void* pMaster, CEquipment* pEquipment, int code)> ONEQDATACHANGED;
     typedef std::function<void(void* pMaster, CRobotTask* pTask, int code)> ONROBOTTASKEVENT;
     typedef std::function<void(void* pMaster, CEquipment* pEquipment, short status, __int64 data)> ONLOADPORTSTATUSCHANGED;
+    typedef std::function<void(void* pMaster, int round)> ONCTROUNDEND;
     typedef struct _MasterListener
     {
         ONMASTERSTATECHANGED    onMasterStateChanged;
@@ -43,6 +47,7 @@
         ONEQDATACHANGED         onEqDataChanged;
         ONROBOTTASKEVENT        onRobotTaskEvent;
         ONLOADPORTSTATUSCHANGED	onLoadPortStatusChanged;
+        ONCTROUNDEND            onCTRoundEnd;
     } MasterListener;
 
     class CMaster
@@ -81,6 +86,10 @@
         void enableEventReport(bool bEnable);
         void enableAlarmReport(bool bEnable);
         bool isAlarmReportEnable();
+        int proceedWithCarrier(unsigned int port);
+        int carrierRelease(unsigned int port);
+        int getContinuousTransferCount();
+        void setContinuousTransferCount(int round);
 
     private:
         inline void lock() { EnterCriticalSection(&m_criticalSection); }
@@ -148,6 +157,11 @@
 
         // 在开始工艺前是否先需要先比较map
         BOOL m_isCompareMapsBeforeProceeding;
+
+        // 千传圈数计数
+        int m_nContinuousTransferCount;
+        int m_nContinuousTransferStep;
+
     private:
         bool m_bEnableEventReport;
         bool m_bEnableAlarmReport;
diff --git a/SourceCode/Bond/Servo/CPagePortProperty.cpp b/SourceCode/Bond/Servo/CPagePortProperty.cpp
index eadf60f..0c241c9 100644
--- a/SourceCode/Bond/Servo/CPagePortProperty.cpp
+++ b/SourceCode/Bond/Servo/CPagePortProperty.cpp
@@ -290,13 +290,11 @@
 	theApp.m_model.setPortCassetteType(m_pPort->getIndex(), SERVO::CassetteType(index + 1));
 
 
-	/*
 	g_nMsgDlgShow = 0;
 	CMsgDlg msgDlg("璇风瓑寰�", "姝e湪鎿嶄綔锛岃绛夊緟...");
 	msgDlg.SetData((DWORD_PTR)this);
 
 	ASSERT(m_pPort != nullptr);
-	int index = ((CComboBox*)GetDlgItem(IDC_COMBO_PORT_CASSERT_TYPE))->GetCurSel();
 	m_pPort->setCassetteType(SERVO::CassetteType(index + 1), [&](int code) -> int {
 		Sleep(100);
 		CString strMsg;
@@ -333,7 +331,6 @@
 
 	msgDlg.DoModal();
 	g_nMsgDlgShow = 1;
-	*/
 }
 
 void CPagePortProperty::OnCbnSelchangeComboPortTransferMode()
diff --git a/SourceCode/Bond/Servo/CPortStatusReport.cpp b/SourceCode/Bond/Servo/CPortStatusReport.cpp
index 89cf223..0d6fa95 100644
--- a/SourceCode/Bond/Servo/CPortStatusReport.cpp
+++ b/SourceCode/Bond/Servo/CPortStatusReport.cpp
@@ -249,6 +249,11 @@
 		m_nJobExistenceSlot[0] = map;
 	}
 
+	void CPortStatusReport::setCassetteId(const char* pszId)
+	{
+		m_strCassetteID = pszId;
+	}
+
 	void CPortStatusReport::WriteString(CArchive& ar, std::string& string)
 	{
 		CString strTemp = string.c_str();
diff --git a/SourceCode/Bond/Servo/CPortStatusReport.h b/SourceCode/Bond/Servo/CPortStatusReport.h
index 727a7d9..fb73f36 100644
--- a/SourceCode/Bond/Servo/CPortStatusReport.h
+++ b/SourceCode/Bond/Servo/CPortStatusReport.h
@@ -31,6 +31,7 @@
 		bool isJobExistenceSlot();
 		short getJobExistenceSlot();
 		void setJobExistenceSlot(short map);
+		void setCassetteId(const char* pszId);
 
 	private:
 		void WriteString(CArchive& ar, std::string& string);
diff --git a/SourceCode/Bond/Servo/CVariable.cpp b/SourceCode/Bond/Servo/CVariable.cpp
index 21ddb44..e9c5d83 100644
--- a/SourceCode/Bond/Servo/CVariable.cpp
+++ b/SourceCode/Bond/Servo/CVariable.cpp
@@ -7,6 +7,7 @@
 	{
 		m_nVarialbeId = 0;
 		m_format = SVFromat::U1;
+		m_nValue = 0;
 	}
 
 	CVariable::CVariable(const char* pszId, const char* pszName, const char* pszFormat, const char* pszRemark)
@@ -87,4 +88,41 @@
 	{
 		return m_strRemark;
 	}
+
+	void CVariable::setValue(__int64 value)
+	{
+		if (m_format == SVFromat::U1 || m_format == SVFromat::U2 || m_format == SVFromat::I2) {
+			m_nValue = value;
+		}
+	}
+
+	void CVariable::setValue(const char* pszValue)
+	{
+		std::string strTemp = pszValue;
+		if (m_format == SVFromat::A20) {
+			if (strTemp.length() > 20) {
+				strTemp = strTemp.substr(0, 20);
+			}
+		}
+		else if (m_format == SVFromat::A50) {
+			if (strTemp.length() > 50) {
+				strTemp = strTemp.substr(0, 50);
+			}
+		}
+
+		m_strValue = strTemp;
+	}
+
+	std::string CVariable::getValue()
+	{
+		std::string strRet;
+		if (m_format == SVFromat::U1 || m_format == SVFromat::U2 || m_format == SVFromat::I2) {
+			strRet = std::to_string(m_nValue);
+		}
+		else if(m_format == SVFromat::A20 || m_format == SVFromat::A50) {
+			strRet = m_strValue;
+		}
+
+		return strRet;
+	}
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CVariable.h b/SourceCode/Bond/Servo/CVariable.h
index 7bac823..beeadd2 100644
--- a/SourceCode/Bond/Servo/CVariable.h
+++ b/SourceCode/Bond/Servo/CVariable.h
@@ -26,12 +26,17 @@
 		std::string& getName();
 		SVFromat getFormat();
 		std::string& getRemark();
+		void setValue(__int64 value);
+		void setValue(const char* pszValue);
+		std::string getValue();
 
 	private:
 		unsigned int m_nVarialbeId;
 		std::string m_strName;
 		SVFromat m_format;
 		std::string m_strRemark;
+		__int64 m_nValue;
+		std::string m_strValue;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/Configuration.cpp b/SourceCode/Bond/Servo/Configuration.cpp
index 08fd582..18ee806 100644
--- a/SourceCode/Bond/Servo/Configuration.cpp
+++ b/SourceCode/Bond/Servo/Configuration.cpp
@@ -160,3 +160,14 @@
 	return GetPrivateProfileInt(_T("Master"), _T("CompareMapsBeforeProceeding"), 0, m_strFilepath);
 }
 
+void CConfiguration::setContinuousTransferCount(int round)
+{
+	WritePrivateProfileString(_T("Master"), _T("CTRound"),
+		std::to_string(round).c_str(), m_strFilepath);
+}
+
+int CConfiguration::getContinuousTransferCount()
+{
+	return GetPrivateProfileInt(_T("Master"), _T("CTRound"), 0, m_strFilepath);
+}
+
diff --git a/SourceCode/Bond/Servo/Configuration.h b/SourceCode/Bond/Servo/Configuration.h
index 8e0d569..96f0e7f 100644
--- a/SourceCode/Bond/Servo/Configuration.h
+++ b/SourceCode/Bond/Servo/Configuration.h
@@ -27,6 +27,8 @@
 	BOOL setPortCassetteType(unsigned int index, int cassetteType);
 	BOOL setPortEnable(unsigned int index, BOOL bEnable);
 	BOOL isCompareMapsBeforeProceeding();
+	void setContinuousTransferCount(int round);
+	int getContinuousTransferCount();
 
 public:
 	void setP2RemoteEqReconnectInterval(int second);
diff --git a/SourceCode/Bond/Servo/HsmsPassive.cpp b/SourceCode/Bond/Servo/HsmsPassive.cpp
index 9dca68a..7a80fd5 100644
--- a/SourceCode/Bond/Servo/HsmsPassive.cpp
+++ b/SourceCode/Bond/Servo/HsmsPassive.cpp
@@ -256,12 +256,39 @@
 	return nullptr;
 }
 
+SERVO::CVariable* CHsmsPassive::getVariable(const char* pszName)
+{
+	for (auto item : m_variabels) {
+		if (item->getName().compare(pszName) == 0) {
+			return item;
+		}
+	}
+
+	return nullptr;
+}
+
 void CHsmsPassive::clearAllVariabel()
 {
 	for (auto item : m_variabels) {
 		delete item;
 	}
 	m_variabels.clear();
+}
+
+void CHsmsPassive::setVariableValue(const char* pszName, __int64 value)
+{
+	auto v = getVariable(pszName);
+	if (v != nullptr) {
+		v->setValue(value);
+	}
+}
+
+void CHsmsPassive::setVariableValue(const char* pszName, const char* value)
+{
+	auto v = getVariable(pszName);
+	if (v != nullptr) {
+		v->setValue(value);
+	}
 }
 
 int CHsmsPassive::loadReports(const char* pszFilepath)
@@ -541,6 +568,9 @@
 		}
 		else if (nStream == 2 && pHeader->function == 43) {
 			replyConfigureSpooling(pMessage);
+		}
+		else if (nStream == 3 && pHeader->function == 17) {
+			replyCarrierAction(pMessage);
 		}
 		else if (nStream == 5 && pHeader->function == 3) {
 			replyEanbleDisableAlarmReport(pMessage);
@@ -1092,7 +1122,7 @@
 
 	// 妫�楠岀粨鏋滄槸鍚︽纭�
 	for (auto item : m_collectionEvents) {
-		LOGE("=== ceid:%d, prtid:%d", item->getEventId(), item->getPortID());
+		LOGE("=== ceid:%d, prtid:%d", item->getEventId(), item->getFirstPortID());
 	}
 	
 MYREPLY:
@@ -1231,6 +1261,57 @@
 	}
 MYREPLY:
 	replyAck(2, 42, pRecv->getHeader()->systemBytes, BYTE(0), "ERACK");
+	return 0;
+}
+
+// S3F17
+int CHsmsPassive::replyCarrierAction(IMessage* pRecv)
+{
+	if (m_pPassive == NULL || STATE::SELECTED != m_pPassive->getState()) {
+		return ER_NOTSELECT;
+	}
+
+	unsigned char CAACK = CAACK_0;
+	unsigned int ERRCODE = 0;
+	std::string strError = "no error";
+	if (m_listener.onCarrierAction == nullptr) {
+		CAACK = 5;
+		ERRCODE = CAACK_5;
+		strError = "Not supported";
+		goto MYREPLY;
+	}
+
+
+	ISECS2Item* pBody = pRecv->getBody();
+	if (pBody == nullptr || pBody->getType() != SITYPE::L) ER_PARAM_ERROR;
+
+	unsigned int DATAID;
+	unsigned char PTN;
+	const char* pszCarrierAction, *pszCarrierId;
+	pBody->getSubItemU4(0, DATAID);
+	pBody->getSubItemString(1, pszCarrierAction);
+	pBody->getSubItemString(2, pszCarrierId);
+	pBody->getSubItemU1(3, PTN);
+	ERRCODE = m_listener.onCarrierAction(this,
+		DATAID, 
+		pszCarrierAction,
+		pszCarrierId, 
+		PTN,
+		strError);
+	CAACK = ERRCODE;
+
+	// 鍥炲
+MYREPLY:
+	IMessage* pMessage = NULL;
+	HSMS_Create1Message(pMessage, m_nSessionId, 3, 18, pRecv->getHeader()->systemBytes);
+	pMessage->getBody()->addU1Item(CAACK, "CAACK");
+	ISECS2Item* pErrItem = pMessage->getBody()->addItem();
+	pErrItem->addU4Item(ERRCODE, "ERRCODE");
+	pErrItem->addItem(strError.c_str(), "ERRTEXT");
+	m_pPassive->sendMessage(pMessage);
+	LOGI("<HSMS>[SECS Msg SEND]S3F18 (SysByte=%u)", pMessage->getHeader()->systemBytes);
+	HSMS_Destroy1Message(pMessage);
+	
 	return 0;
 }
 
@@ -1396,15 +1477,19 @@
 }
 
 // S6F11
-int CHsmsPassive::requestEventReportSend(unsigned int DATAID, unsigned int CEID, const std::vector<std::string>& values)
+static unsigned int DATAID = 1;
+int CHsmsPassive::requestEventReportSend(unsigned int CEID)
 {
 	SERVO::CCollectionEvent* pEvent = getEvent(CEID);
 	if (pEvent == nullptr) {
 		return ER_NO_EVENT;
 	}
-	if (pEvent == nullptr) {
+
+	SERVO::CReport* pReport = pEvent->getFirstReport();
+	if (pReport == nullptr) {
 		return ER_UNLINK_EVENT_REPORT;
 	}
+
 
 	Lock();
 	CHsmsAction* pAction = new CHsmsAction(ACTION_EVENT_REPORT, TRUE, m_nActionTimeout);
@@ -1412,14 +1497,16 @@
 	HSMS_Create1Message(pMessage, m_nSessionId, 6 | REPLY, 11, ++m_nSystemByte);
 	ASSERT(pMessage);
 	ISECS2Item* pItem = pMessage->getBody();
-	pItem->addU4Item(DATAID, "DATAID");
+	pItem->addU4Item(++DATAID, "DATAID");
 	pItem->addU4Item(CEID, "CEID");
 	ISECS2Item* pItemList1 = pItem->addItem();
 	ISECS2Item* pItemList2 = pItemList1->addItem();
-	pItemList2->addU4Item(pEvent->getPortID(), "RPTID");
+	pItemList2->addU4Item(pReport->getReportId(), "RPTID");
 	ISECS2Item* pItemList3 = pItemList2->addItem();
+
+	auto values = pReport->getVariables();
 	for (auto item : values) {
-		pItemList3->addItem(item.c_str(), "V");
+		pItemList3->addItem(item->getValue().c_str(), "V");
 	}
 	pAction->setSendMessage(pMessage);
 	if (m_pPassive == NULL || STATE::SELECTED != m_pPassive->getState()) {
@@ -1434,5 +1521,26 @@
 	return ER_NOERROR;
 }
 
+int CHsmsPassive::requestEventReportSend(const char* pszEventName)
+{
+	SERVO::CCollectionEvent* pEvent = nullptr;
+	for (auto e : m_collectionEvents) {
+		if (e->getName().compare(pszEventName) == 0) {
+			pEvent = e;
+			break;
+		}
+	}
+	if (pEvent == nullptr) {
+		return ER_NO_EVENT;
+	}
+	return requestEventReportSend(pEvent->getEventId());
+}
+
+int CHsmsPassive::requestEventReportSend_CarrierID_Readed()
+{
+	return requestEventReportSend("CarrierID_Readed");
+}
+
+
 
 
diff --git a/SourceCode/Bond/Servo/HsmsPassive.h b/SourceCode/Bond/Servo/HsmsPassive.h
index 64bccc0..f542cf7 100644
--- a/SourceCode/Bond/Servo/HsmsPassive.h
+++ b/SourceCode/Bond/Servo/HsmsPassive.h
@@ -23,7 +23,18 @@
 #define ER_NO_EVENT				-4
 #define ER_UNLINK_EVENT_REPORT	-5
 #define ER_NO_PPID_LIST			-6
+#define ER_NOT_SUPPORTED		-7
 
+
+/* CAACK */
+
+#define CAACK_0					0		/* ok */
+#define CAACK_1					1		/* invalid command */
+#define CAACK_2					2		/* cannot perform now */
+#define CAACK_3					3		/* invalid data or argument */
+#define CAACK_4					4		/* initiated for asynchronous completion */
+#define CAACK_5					5		/* rejected - invalid state */
+#define CAACK_6					6		/* command performed with errors */
 
 /*
  * 常量数据结构
@@ -69,6 +80,12 @@
 typedef std::function<void(void* pFrom, bool bEnable, std::vector<unsigned int>& ids)> EDEVENTREPORT;
 typedef std::function<void(void* pFrom, bool bEnable, unsigned int id)> EDALARMREPORT;
 typedef std::function<std::vector<std::string> (void* pFrom)> QUERYPPIDLIST;
+typedef std::function<unsigned int (void* pFrom,
+	unsigned int DATAID,
+	const char* pszCarrierAction,
+	const char* pszCarrierId,
+	unsigned char PTN, 
+	std::string& strErrorTxt)> CARRIERACTION;
 typedef struct _SECSListener
 {
 	SECSEQOFFLINE				onEQOffLine;
@@ -80,6 +97,7 @@
 	EDEVENTREPORT				onEnableDisableEventReport;
 	EDALARMREPORT				onEnableDisableAlarmReport;
 	QUERYPPIDLIST				onQueryPPIDList;
+	CARRIERACTION				onCarrierAction;
 } SECSListener;
 
 
@@ -118,6 +136,11 @@
 
 	// 取得指定Variable
 	SERVO::CVariable* getVariable(int variableId);
+	SERVO::CVariable* getVariable(const char* pszName);
+
+	// 设置变量值
+	void setVariableValue(const char* pszName, __int64 value);
+	void setVariableValue(const char* pszName, const char* value);
 
 	// 从文件中加载CReport列表
 	int loadReports(const char* pszFilepath);
@@ -155,7 +178,9 @@
 	/* request开头的函数为主动发送数据的函数 */
 	int requestAreYouThere();
 	int requestAlarmReport(int ALCD, int ALID, const char* ALTX);
-	int requestEventReportSend(unsigned int DATAID, unsigned int CEID, const std::vector<std::string>& values);
+	int requestEventReportSend(unsigned int CEID);
+	int requestEventReportSend(const char* pszEventName);
+	int requestEventReportSend_CarrierID_Readed();
 
 private:
 	void replyAck(int s, int f, unsigned int systemBytes, BYTE ack, const char* pszAckName);
@@ -173,6 +198,7 @@
 	int replyEanbleDisableEventReport(IMessage* pRecv);
 	int replyCommand(IMessage* pRecv);
 	int replyConfigureSpooling(IMessage* pRecv);
+	int replyCarrierAction(IMessage* pRecv);
 	int replyEanbleDisableAlarmReport(IMessage* pRecv);
 	int replyPurgeSpooledData(IMessage* pRecv);
 	int replyQueryPPIDList(IMessage* pRecv);
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 70685aa..a6299e5 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -151,6 +151,30 @@
 		}
 		return ppids;
 	};
+	listener.onCarrierAction = [&](void* pFrom, 
+		unsigned int DATAID, 
+		const char* pszCarrierAction,
+		const char* pszCarrierId,
+		unsigned char PTN,
+		std::string& strErrorTxt) -> unsigned int {
+			if (PTN < 1 || 4 < PTN) {
+				strErrorTxt = "invalid data or argument";
+				return CAACK_3;
+			}
+
+			if (_strcmpi(pszCarrierAction, "ProceedWithCarrier") == 0) {
+				m_master.proceedWithCarrier(PTN);
+				return CAACK_0;
+			}
+			else if (_strcmpi(pszCarrierAction, "CarrierRelease") == 0) {
+				m_master.carrierRelease(PTN);
+				return CAACK_0;
+			}
+
+			strErrorTxt = "rejected - invalid state";
+			return CAACK_5;
+			LOGI("<Model>onCarrierAction %d, %s, %d, %d", DATAID, pszCarrierAction, pszCarrierId, PTN);
+	};
 	m_hsmsPassive.setListener(listener);
 	m_hsmsPassive.setEquipmentModelType((LPTSTR)(LPCTSTR)strModeType);
 	m_hsmsPassive.setSoftRev((LPTSTR)(LPCTSTR)strSoftRev);
@@ -329,9 +353,20 @@
 	};
 	masterListener.onLoadPortStatusChanged = [&] (void* pMaster, SERVO::CEquipment* pEquipment, short status, __int64 data) {
 		LOGE("<CModel>onLoadPortStatusChanged. status = %d", status);
+		if (status == PORT_INUSE) {
+			SERVO::CLoadPort* pLoadPort = dynamic_cast<SERVO::CLoadPort*>(pEquipment);
+			if (pLoadPort != nullptr) {
+				m_hsmsPassive.setVariableValue("CarrierID", pLoadPort->getCassetteId().c_str());
+			}
+			m_hsmsPassive.requestEventReportSend_CarrierID_Readed();
+		}
 		notifyPtr(RX_CODE_LOADPORT_STATUS_CHANGED, pEquipment);
 	};
+	masterListener.onCTRoundEnd = [&](void* pMaster, int round) {
+		m_configuration.setContinuousTransferCount(round);
+	};
 	m_master.setListener(masterListener);
+	m_master.setContinuousTransferCount(m_configuration.getContinuousTransferCount());
 
 
 	// master 设置缓存文件
diff --git a/SourceCode/Bond/Servo/PageLog.cpp b/SourceCode/Bond/Servo/PageLog.cpp
index 7fe626a..c5cd4a9 100644
--- a/SourceCode/Bond/Servo/PageLog.cpp
+++ b/SourceCode/Bond/Servo/PageLog.cpp
@@ -79,8 +79,13 @@
 							else {
 								CString strTemp = strText;
 								strTemp.TrimRight();
-								bMatch = std::regex_match((LPTSTR)(LPCTSTR)strTemp,
-									std::regex((LPTSTR)(LPCTSTR)m_strFilterText));
+								try {
+									bMatch = std::regex_match((LPTSTR)(LPCTSTR)strTemp,
+										std::regex((LPTSTR)(LPCTSTR)m_strFilterText));
+								}
+								catch (const std::regex_error& e) {
+
+								}
 							}
 							if (m_filterMode == FilterMode::Exclude) {
 								bMatch = !bMatch;
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 552795b..c1df135 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index 84b1f21..746549b 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -235,7 +235,15 @@
 						pEq2 = theApp.m_model.getMaster().getEquipment(pTask->getTarPosition());
 						if (pEq1 != nullptr && pEq2 != nullptr) {
 							CString strText;
-							strText.Format(_T("%s --> %s"), pEq1->getName().c_str(), pEq2->getName().c_str());
+							if (theApp.m_model.getMaster().getContinuousTransferCount() > 0) {
+								strText.Format(_T("[%d]%s --> %s"),
+									theApp.m_model.getMaster().getContinuousTransferCount(),
+									pEq1->getName().c_str(), pEq2->getName().c_str());
+							}
+							else {
+								strText.Format(_T("%s --> %s"),
+									pEq1->getName().c_str(), pEq2->getName().c_str());
+							}
 							m_pMyStatusbar->setCurTaskBtnText((LPTSTR)(LPCTSTR)strText);
 						}
 					}
diff --git a/SourceCode/Bond/x64/Debug/CollectionEventList.txt b/SourceCode/Bond/x64/Debug/CollectionEventList.txt
index 48df026..8732aaf 100644
--- a/SourceCode/Bond/x64/Debug/CollectionEventList.txt
+++ b/SourceCode/Bond/x64/Debug/CollectionEventList.txt
@@ -37,3 +37,4 @@
 31032,CJobResume,,(31000)
 40000,E90_SPSM_NoState_To_NeedsProcessing,,(40000)
 40001,E90_SPSM_InProcess_To_ProcessCompleted,,(40000)
+50000,CarrierID_Readed,,(50000)
diff --git a/SourceCode/Bond/x64/Debug/ReportList.txt b/SourceCode/Bond/x64/Debug/ReportList.txt
index f614e93..fe7fc97 100644
--- a/SourceCode/Bond/x64/Debug/ReportList.txt
+++ b/SourceCode/Bond/x64/Debug/ReportList.txt
@@ -15,3 +15,5 @@
 30000,(1,30000,30001)
 31000,(1,31000,31001)
 40000,(1,10203,20000)
+50000,(5000)
+
diff --git a/SourceCode/Bond/x64/Debug/VariableList.txt b/SourceCode/Bond/x64/Debug/VariableList.txt
index 5bb7d38..1a93f88 100644
--- a/SourceCode/Bond/x64/Debug/VariableList.txt
+++ b/SourceCode/Bond/x64/Debug/VariableList.txt
@@ -35,3 +35,4 @@
 2023,OCREnable,U2,"OCR使能:O:开启 1:屏蔽"
 2024,CCDEnable,U2,"CCD使能:O:开启 1:屏蔽"
 2025,FFUParameter,U2,FFU设定值
+5000,CarrierID,A20,卡匣ID

--
Gitblit v1.9.3