From 0a0b065a898ea5d87ae82bf39a745e76337fc8f5 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期三, 10 九月 2025 15:19:16 +0800
Subject: [PATCH] 1.一些输出日志信息,更新等级; 2.CPath增加Slot信息; 3.WIP数据显示到列表控件; 4.调整Glass的Path信息文本输出;

---
 SourceCode/Bond/Servo/CEqPortChangeStep.cpp    |    2 
 SourceCode/Bond/Servo/resource.h               |    0 
 SourceCode/Bond/Servo/CServoUtilsTool.h        |    1 
 SourceCode/Bond/Servo/CFliper.cpp              |    2 
 SourceCode/Bond/Servo/CGlass.h                 |    2 
 SourceCode/Bond/Servo/CRobotTask.cpp           |    8 
 SourceCode/Bond/Servo/CMaster.h                |    1 
 SourceCode/Bond/Servo/GlassJson.cpp            |    4 
 SourceCode/Bond/Servo/CBakeCooling.cpp         |    2 
 SourceCode/Bond/Servo/ListCtrlEx.cpp           |   11 
 SourceCode/Bond/Servo/CPageGlassList.h         |    8 
 SourceCode/Bond/Servo/CPath.h                  |    4 
 SourceCode/Bond/Servo/ToolUnits.cpp            |   66 +++++++
 SourceCode/Bond/Servo/CEquipment.cpp           |   48 +++-
 SourceCode/Bond/Servo/CMaster.cpp              |   61 ++++--
 SourceCode/Bond/Servo/CEqReadStep.cpp          |    8 
 SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp |    2 
 SourceCode/Bond/Servo/CEqReadIntStep.cpp       |    2 
 SourceCode/Bond/Servo/ToolUnits.h              |   13 +
 SourceCode/Bond/Servo/CEqVcrEventStep.cpp      |    2 
 SourceCode/Bond/Servo/CEquipmentPage3.cpp      |    2 
 SourceCode/Bond/Servo/CGlass.cpp               |   12 
 SourceCode/Bond/Servo/CEqAlarmStep.cpp         |    6 
 SourceCode/Bond/Servo/CPath.cpp                |   12 +
 SourceCode/Bond/Servo/Model.cpp                |   10 
 SourceCode/Bond/Servo/CLoadPort.cpp            |   20 +-
 SourceCode/Bond/Servo/CEqProcessStep.cpp       |    2 
 SourceCode/Bond/Servo/CPageGlassList.cpp       |  118 +++++++++++++
 SourceCode/Bond/Servo/DevicePropertyDlg.cpp    |    2 
 SourceCode/Bond/Servo/CEqJobEventStep.cpp      |    2 
 SourceCode/Bond/Servo/CAligner.cpp             |    2 
 SourceCode/Bond/Servo/CEqStatusStep.cpp        |    2 
 SourceCode/Bond/Servo/CServoUtilsTool.cpp      |   74 ++++++++
 SourceCode/Bond/Servo/CEFEM.cpp                |    6 
 SourceCode/Bond/Servo/CEquipment.h             |    1 
 35 files changed, 416 insertions(+), 102 deletions(-)

diff --git a/SourceCode/Bond/Servo/CAligner.cpp b/SourceCode/Bond/Servo/CAligner.cpp
index b48d48d..e15bfe0 100644
--- a/SourceCode/Bond/Servo/CAligner.cpp
+++ b/SourceCode/Bond/Servo/CAligner.cpp
@@ -32,7 +32,7 @@
 	void CAligner::initPins()
 	{
 		// 加入Pin初始化代码
-		LOGI("<CAligner>initPins");
+		LOGD("<CAligner>initPins");
 		addPin(SERVO::PinType::INPUT, _T("In1"));
 		addPin(SERVO::PinType::INPUT, _T("In2"));
 		addPin(SERVO::PinType::OUTPUT, _T("Out1"));
diff --git a/SourceCode/Bond/Servo/CBakeCooling.cpp b/SourceCode/Bond/Servo/CBakeCooling.cpp
index dedf8a4..166dedf 100644
--- a/SourceCode/Bond/Servo/CBakeCooling.cpp
+++ b/SourceCode/Bond/Servo/CBakeCooling.cpp
@@ -32,7 +32,7 @@
 	void CBakeCooling::initPins()
 	{
 		// 加入Pin初始化代码
-		LOGI("<CBakeCooling>initPins");
+		LOGD("<CBakeCooling>initPins");
 		addPin(SERVO::PinType::INPUT, _T("In1"));
 		addPin(SERVO::PinType::INPUT, _T("In2"));
 		addPin(SERVO::PinType::OUTPUT, _T("Out"));
diff --git a/SourceCode/Bond/Servo/CEFEM.cpp b/SourceCode/Bond/Servo/CEFEM.cpp
index 7715750..d882c9b 100644
--- a/SourceCode/Bond/Servo/CEFEM.cpp
+++ b/SourceCode/Bond/Servo/CEFEM.cpp
@@ -133,7 +133,7 @@
 					LOGI("<CEquipment-%s>发送RobotCmdS成功.", m_strName.c_str());
 				}
 				else {
-					LOGI("<CEquipment-%s>发送RobotCmds失败,code:%d", m_strName.c_str(), code);
+					LOGE("<CEquipment-%s>发送RobotCmds失败,code:%d", m_strName.c_str(), code);
 				}
 
 				return 0;
@@ -367,7 +367,7 @@
 	void CEFEM::initPins()
 	{
 		// 加入Pin初始化代码
-		LOGI("<CEFEM>initPins");
+		LOGD("<CEFEM>initPins");
 	}
 
 	void CEFEM::initSteps()
@@ -874,7 +874,7 @@
 
 	void CEFEM::printDebugRobotState()
 	{
-		LOGI("<CEFEM>Robot status:%d, ARM1:%s, ARM2:%s",
+		LOGD("<CEFEM>Robot status:%d, ARM1:%s, ARM2:%s",
 			m_robotData.status,
 			m_robotData.armState[0] ? _T("ON") : _T("OFF"),
 			m_robotData.armState[1] ? _T("ON") : _T("OFF"));
diff --git a/SourceCode/Bond/Servo/CEqAlarmStep.cpp b/SourceCode/Bond/Servo/CEqAlarmStep.cpp
index dcbd9b7..63adada 100644
--- a/SourceCode/Bond/Servo/CEqAlarmStep.cpp
+++ b/SourceCode/Bond/Servo/CEqAlarmStep.cpp
@@ -58,7 +58,7 @@
 		m_nAlarmCode = (unsigned int)CToolUnits::toInt16(&szBuffer[6]);
 		m_nAlarmLevel = (unsigned int)CToolUnits::toInt16(&szBuffer[8]);
 
-		LOGI("<CEqAlarmStep> Equipment Alarm state Changed<State:%d, Unit:%d, Level:%d, Code:%d, ID:%d>",
+		LOGE("<CEqAlarmStep> Equipment Alarm state Changed<State:%d, Unit:%d, Level:%d, Code:%d, ID:%d>",
 			m_nAlarmState, m_nUnitId, m_nAlarmLevel, m_nAlarmCode, m_nAlarmId,
 			m_strText.c_str(), m_strDescription.c_str());
 
@@ -68,7 +68,7 @@
 	int CEqAlarmStep::onComplete()
 	{
 		CReadStep::onComplete();
-		LOGI("<CEqAlarmStep> onComplete.");
+		LOGD("<CEqAlarmStep> onComplete.");
 
 		return 0;
 	}
@@ -76,7 +76,7 @@
 	int CEqAlarmStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEqAlarmStep> onTimeout.");
+		LOGE("<CEqAlarmStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEqJobEventStep.cpp b/SourceCode/Bond/Servo/CEqJobEventStep.cpp
index 7a084fe..b8f998c 100644
--- a/SourceCode/Bond/Servo/CEqJobEventStep.cpp
+++ b/SourceCode/Bond/Servo/CEqJobEventStep.cpp
@@ -57,7 +57,7 @@
 	int CEqJobEventStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEqJobEventStep> onTimeout.");
+		LOGE("<CEqJobEventStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEqPortChangeStep.cpp b/SourceCode/Bond/Servo/CEqPortChangeStep.cpp
index 5d85b6c..92fe57e 100644
--- a/SourceCode/Bond/Servo/CEqPortChangeStep.cpp
+++ b/SourceCode/Bond/Servo/CEqPortChangeStep.cpp
@@ -80,7 +80,7 @@
 	int CEqPortChangeStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEQPortChangeStep> onTimeout.");
+		LOGE("<CEQPortChangeStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEqProcessStep.cpp b/SourceCode/Bond/Servo/CEqProcessStep.cpp
index 8c607bc..b7d4b85 100644
--- a/SourceCode/Bond/Servo/CEqProcessStep.cpp
+++ b/SourceCode/Bond/Servo/CEqProcessStep.cpp
@@ -119,7 +119,7 @@
 	int CEqProcessStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEqProcessStep> onTimeout.");
+		LOGE("<CEqProcessStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEqReadIntStep.cpp b/SourceCode/Bond/Servo/CEqReadIntStep.cpp
index c6bb18e..4625674 100644
--- a/SourceCode/Bond/Servo/CEqReadIntStep.cpp
+++ b/SourceCode/Bond/Servo/CEqReadIntStep.cpp
@@ -71,7 +71,7 @@
 	int CEqReadIntStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEqReadIntStep> onTimeout.");
+		LOGE("<CEqReadIntStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEqReadStep.cpp b/SourceCode/Bond/Servo/CEqReadStep.cpp
index ce4f078..f4fe44f 100644
--- a/SourceCode/Bond/Servo/CEqReadStep.cpp
+++ b/SourceCode/Bond/Servo/CEqReadStep.cpp
@@ -53,14 +53,14 @@
 		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.");
+			LOGE("<CEqReadStep>Read data error.");
 			if (m_onReadBlock != nullptr) {
 				m_onReadBlock(this, RERROR, nullptr, 0);
 			}
 			return -1;
 		}
 
-		LOGI("<CEqReadStep>read data succeed.");
+		LOGD("<CEqReadStep>read data succeed.");
 		if (m_onReadBlock != nullptr) {
 			m_onReadBlock(this, ROK, szBuffer, m_nReadSize);
 		}
@@ -72,7 +72,7 @@
 	int CEqReadStep::onComplete()
 	{
 		CReadStep::onComplete();
-		LOGI("<CEqReadStep> onComplete.");
+		LOGD("<CEqReadStep> onComplete.");
 		if (m_onReadBlock != nullptr) {
 			m_onReadBlock(this, RCOMPLETE, nullptr, 0);
 		}
@@ -83,7 +83,7 @@
 	int CEqReadStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEqReadStep> onTimeout.");
+		LOGE("<CEqReadStep> onTimeout.");
 		if (m_onReadBlock != nullptr) {
 			m_onReadBlock(this, RTIMEOUT, nullptr, 0);
 		}
diff --git a/SourceCode/Bond/Servo/CEqStatusStep.cpp b/SourceCode/Bond/Servo/CEqStatusStep.cpp
index 6108c58..3f8195a 100644
--- a/SourceCode/Bond/Servo/CEqStatusStep.cpp
+++ b/SourceCode/Bond/Servo/CEqStatusStep.cpp
@@ -93,7 +93,7 @@
 	int CEqStatusStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEqStatusStep> onTimeout.");
+		LOGE("<CEqStatusStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEqVcrEventStep.cpp b/SourceCode/Bond/Servo/CEqVcrEventStep.cpp
index dbe4fc9..0d88dac 100644
--- a/SourceCode/Bond/Servo/CEqVcrEventStep.cpp
+++ b/SourceCode/Bond/Servo/CEqVcrEventStep.cpp
@@ -70,7 +70,7 @@
 	int CEqVcrEventStep::onTimeout()
 	{
 		CReadStep::onTimeout();
-		LOGI("<CEqVcrEventStep> onTimeout.");
+		LOGE("<CEqVcrEventStep> onTimeout.");
 
 		return 0;
 	}
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 2cbf62f..e390343 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -839,7 +839,7 @@
 		CEquipment* pFromEq = pFromPin->getEquipment();
 		ASSERT(pFromEq);
 
-		LOGI("<CEquipment><%s-%s>收到来自<%s.%s>的Intent<%d,%s,0x%x>",
+		LOGD("<CEquipment><%s-%s>收到来自<%s.%s>的Intent<%d,%s,0x%x>",
 			this->getName().c_str(),
 			pPin->getName().c_str(),
 			pFromEq->getName().c_str(),
@@ -916,7 +916,7 @@
 
 		ASSERT(pGlass);
 		Lock();
-		pGlass->addPath(m_nID, getSlotUnit(putSlot));
+		pGlass->addPath(m_nID, getSlotUnit(putSlot), putSlot);
 		m_slot[putSlot - 1].setContext(pGlass);
 		pGlass->release();				// tempFetchOut需要调用一次release
 		Unlock();
@@ -990,6 +990,22 @@
 
 
 		return nullptr;
+	}
+
+	int CEquipment::getAllGlass(std::vector<CGlass*>& glasses)
+	{
+		Lock();
+		for (int i = 0; i < SLOT_MAX; i++) {
+			if (!m_slot[i].isEnable()) continue;
+			CGlass* pGlass = (CGlass*)m_slot[i].getContext();
+			if (pGlass != nullptr) {
+				pGlass->addRef();
+				glasses.push_back(pGlass);
+			}
+		}
+		Unlock();
+
+		return (int)glasses.size();
 	}
 
 	CJobDataS* CEquipment::getJobDataSWithCassette(int cassetteSequenceNo, int jobSequenceNo)
@@ -1138,7 +1154,7 @@
 					LOGI("<CEquipment-%s>设置DispatchingMode成功.", m_strName.c_str());
 				}
 				else {
-					LOGI("<CEquipment-%s>设置DispatchingMode失败,code:%d", m_strName.c_str(), code);
+					LOGE("<CEquipment-%s>设置DispatchingMode失败,code:%d", m_strName.c_str(), code);
 				}
 
 				return 0;
@@ -1168,7 +1184,7 @@
 				LOGI("<CEquipment-%s>返回值: %d", m_strName.c_str(), retCode);
 			}
 			else {
-				LOGI("<CEquipment-%s>设置indexerOperationMode失败,code:%d", m_strName.c_str(), code);
+				LOGE("<CEquipment-%s>设置indexerOperationMode失败,code:%d", m_strName.c_str(), code);
 			}
 
 			if (onWritedRetBlock != nullptr) {
@@ -1199,7 +1215,7 @@
 			}
 			else {
 				m_recipesManager.syncFailed();
-				LOGI("<CEquipment-%s>请求单元<%d>主配方列表失败,code:%d", m_strName.c_str(), unitNo, code);
+				LOGE("<CEquipment-%s>请求单元<%d>主配方列表失败,code:%d", m_strName.c_str(), unitNo, code);
 			}
 
 			return 0;
@@ -1234,7 +1250,7 @@
 			}
 			else {
 				m_recipesManager.syncFailed();
-				LOGI("<CEquipment-%s>请求单元<%d>主配方参数列表失败,code:%d", m_strName.c_str(), unitNo, code);
+				LOGE("<CEquipment-%s>请求单元<%d>主配方参数列表失败,code:%d", m_strName.c_str(), unitNo, code);
 			}
 
 			return 0;
@@ -1358,32 +1374,32 @@
 	CSlot* CEquipment::getProcessedSlot(MaterialsType putSlotType, BOOL bJobMode/* = FALSE*/)
 	{
 		for (int i = 0; i < SLOT_MAX; i++) {
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 001");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 001");
 			if (!m_slot[i].isEnable()) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 002");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 002");
 			if (m_slot[i].isLock()) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 003");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 003");
 			CGlass* pGlass = (CGlass*)m_slot[i].getContext();
 			if (!isSlotProcessed(i)) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 004");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 004");
 			if (pGlass == nullptr) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 005");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 005");
 			if (!pGlass->isScheduledForProcessing()) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 006");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 006");
 			if (bJobMode && pGlass->getProcessJob() == nullptr) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 007");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 007");
 			if(pGlass->getInspResult(m_nID, 0) == InspResult::Fail) continue;
 			int lsPath = m_slot[i].getLinkSignalPath();
 			if(!m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_INLINE]
 				|| m_bLinkSignalToUpstream[lsPath][SIGNAL_UPSTREAM_TROUBLE]
 				|| !m_bLinkSignalToUpstream[lsPath][SIGNAL_INTERLOCK]
 				|| !m_bLinkSignalToUpstream[lsPath][SIGNAL_SEND_ABLE] ) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 008");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 008");
 			MaterialsType glassType = pGlass->getType();
 			if (glassType == MaterialsType::G1 && putSlotType == MaterialsType::G2) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 009");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 009");
 			if (glassType == MaterialsType::G2 && putSlotType == MaterialsType::G1) continue;
-			if (m_nTestFlag == 1) LOGI("getProcessedSlot 00a");
+			if (m_nTestFlag == 1) LOGD("getProcessedSlot 00a");
 			return &m_slot[i];
 		}
 
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index ffb7ea9..bf1808b 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -206,6 +206,7 @@
 		CGlass* getGlassWithCassette(int cassetteSequenceNo, int jobSequenceNo);
 		CGlass* getAnyGlass();
 		CGlass* getGlass(const char* pszGlassId);
+		int getAllGlass(std::vector<CGlass*>& glasses);
 		CJobDataS* getJobDataSWithCassette(int cassetteSequenceNo, int jobSequenceNo);
 
 		// 验证玻璃和槽是否匹配
diff --git a/SourceCode/Bond/Servo/CEquipmentPage3.cpp b/SourceCode/Bond/Servo/CEquipmentPage3.cpp
index 00fe069..4f4e440 100644
--- a/SourceCode/Bond/Servo/CEquipmentPage3.cpp
+++ b/SourceCode/Bond/Servo/CEquipmentPage3.cpp
@@ -91,7 +91,7 @@
 				AfxMessageBox("璁剧疆EAS妯″紡鎴愬姛锛�");
 			}
 			else {
-				LOGI("<CEquipment-%s>璁剧疆DispatchingMode澶辫触锛宑ode:%d", m_pEquipment->getName().c_str(), code);
+				LOGE("<CEquipment-%s>璁剧疆DispatchingMode澶辫触锛宑ode:%d", m_pEquipment->getName().c_str(), code);
 				AfxMessageBox("璁剧疆EAS妯″紡澶辫触锛�");
 			}
 
diff --git a/SourceCode/Bond/Servo/CFliper.cpp b/SourceCode/Bond/Servo/CFliper.cpp
index aed1fc6..d0f5f9c 100644
--- a/SourceCode/Bond/Servo/CFliper.cpp
+++ b/SourceCode/Bond/Servo/CFliper.cpp
@@ -32,7 +32,7 @@
 	void CFliper::initPins()
 	{
 		// 加入Pin初始化代码
-		LOGI("<CFliper>initPins");
+		LOGD("<CFliper>initPins");
 		addPin(SERVO::PinType::INPUT, _T("In"));
 		addPin(SERVO::PinType::OUTPUT, _T("Out1"));
 		addPin(SERVO::PinType::OUTPUT, _T("Out2"));
diff --git a/SourceCode/Bond/Servo/CGlass.cpp b/SourceCode/Bond/Servo/CGlass.cpp
index b249b79..b5ad3db 100644
--- a/SourceCode/Bond/Servo/CGlass.cpp
+++ b/SourceCode/Bond/Servo/CGlass.cpp
@@ -115,12 +115,12 @@
 		CPath* pTemp = m_pPath;
 		while (pTemp != nullptr) {
 			pTemp->getSimpleDescription(strPath);
-			strOut.append(strPath);
+			if (strPath.compare("ARM1") != 0 && strPath.compare("ARM2") != 0) {
+				if (!strOut.empty()) strOut.append(" -> ");
+				strOut.append(strPath);
+			}
 
 			pTemp = pTemp->getNext();
-			if (pTemp != nullptr) {
-				strOut.append(" -> ");
-			}
 		}
 
 		return strOut;
@@ -140,9 +140,9 @@
 		return nullptr;
 	}
 
-	void CGlass::addPath(unsigned int nEqId, unsigned int nUnit)
+	void CGlass::addPath(unsigned int nEqId, unsigned int nUnit, unsigned int slot)
 	{
-		CPath* pPath = new CPath(nEqId, nUnit);
+		CPath* pPath = new CPath(nEqId, nUnit, slot);
 		if (m_pPath == nullptr) {
 			m_pPath = pPath;
 		}
diff --git a/SourceCode/Bond/Servo/CGlass.h b/SourceCode/Bond/Servo/CGlass.h
index 708e629..72f304b 100644
--- a/SourceCode/Bond/Servo/CGlass.h
+++ b/SourceCode/Bond/Servo/CGlass.h
@@ -47,7 +47,7 @@
 		void setProcessJob(CProcessJob* pProcessJob);
 		CPath* getPathWithEq(unsigned int nEqId, unsigned int nUnit) const;
 		CPath* getPath();
-		void addPath(unsigned int nEqId, unsigned int nUnit);
+		void addPath(unsigned int nEqId, unsigned int nUnit, unsigned int slot);
 		std::string getPathDescription() const;
 		std::string getParamsDescription() const;
 		void serialize(CArchive& ar);
diff --git a/SourceCode/Bond/Servo/CLoadPort.cpp b/SourceCode/Bond/Servo/CLoadPort.cpp
index 9fe24b5..e7725f2 100644
--- a/SourceCode/Bond/Servo/CLoadPort.cpp
+++ b/SourceCode/Bond/Servo/CLoadPort.cpp
@@ -44,7 +44,7 @@
 	void CLoadPort::initPins()
 	{
 		// 加入Pin初始化代码
-		LOGI("<CLoadPort>initPins");
+		LOGD("<CLoadPort>initPins");
 		addPin(SERVO::PinType::INPUT, _T("In"));
 		addPin(SERVO::PinType::OUTPUT, _T("Out"));
 	}
@@ -983,7 +983,7 @@
 				LOGI("<CLoadPort-%d>设置Port type成功.", m_nIndex);
 			}
 			else {
-				LOGI("<CLoadPort-%d>设置Port type失败,code:%d", m_nIndex, code);
+				LOGE("<CLoadPort-%d>设置Port type失败,code:%d", m_nIndex, code);
 			}
 			if (onWritedBlock != nullptr) {
 				return onWritedBlock(code);
@@ -1013,7 +1013,7 @@
 				LOGI("<CLoadPort-%d>%s Port成功.", m_nIndex, bEnable ? _T("启用") : _T("禁用"));
 			}
 			else {
-				LOGI("<CLoadPort-%d>%s  Port失败,code:%d", m_nIndex, bEnable ? _T("启用") : _T("禁用"), code);
+				LOGE("<CLoadPort-%d>%s  Port失败,code:%d", m_nIndex, bEnable ? _T("启用") : _T("禁用"), code);
 			}
 			if (onWritedBlock != nullptr) {
 				return onWritedBlock(code);
@@ -1042,7 +1042,7 @@
 				LOGI("<CLoadPort-%d>设置Port mode成功.", m_nIndex);
 			}
 			else {
-				LOGI("<CLoadPort-%d>设置Port mode失败,code:%d", m_nIndex, code);
+				LOGE("<CLoadPort-%d>设置Port mode失败,code:%d", m_nIndex, code);
 			}
 			if (onWritedBlock != nullptr) {
 				return onWritedBlock(code);
@@ -1071,7 +1071,7 @@
 				LOGI("<CLoadPort-%d>设置Cassette Type成功.", m_nIndex);
 			}
 			else {
-				LOGI("<CLoadPort-%d>设置Cassette Type失败,code:%d", m_nIndex, code);
+				LOGE("<CLoadPort-%d>设置Cassette Type失败,code:%d", m_nIndex, code);
 			}
 			if (onWritedBlock != nullptr) {
 				return onWritedBlock(code);
@@ -1100,7 +1100,7 @@
 				LOGI("<CLoadPort-%d>设置Transfer mode成功.", m_nIndex + 1);
 			}
 			else {
-				LOGI("<CLoadPort-%d>设置Transfer mode失败,code:%d", m_nIndex + 1, code);
+				LOGE("<CLoadPort-%d>设置Transfer mode失败,code:%d", m_nIndex + 1, code);
 			}
 			if (onWritedBlock != nullptr) {
 				return onWritedBlock(code);
@@ -1129,7 +1129,7 @@
 				LOGI("<CLoadPort-%d>%s Auto Change成功.", m_nIndex, bEnable ? _T("启用") : _T("禁用"));
 			}
 			else {
-				LOGI("<CLoadPort-%d>%s  Auto Change失败,code:%d", m_nIndex, bEnable ? _T("启用") : _T("禁用"), code);
+				LOGE("<CLoadPort-%d>%s  Auto Change失败,code:%d", m_nIndex, bEnable ? _T("启用") : _T("禁用"), code);
 			}
 			if (onWritedBlock != nullptr) {
 				return onWritedBlock(code);
@@ -1209,7 +1209,7 @@
 
 			CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
 			pGlass->setOriginPort(m_nIndex, i);
-			pGlass->addPath(m_nID, 0);
+			pGlass->addPath(m_nID, 0, i + 1);
 			pGlass->processEnd(m_nID, 0);
 			pGlass->setID(szBuffer);
 			pGlass->setType(type);
@@ -1249,7 +1249,7 @@
 			CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
 			pGlass->setOriginPort(m_nIndex, i);
 			pGlass->setScheduledForProcessing(i % 2 == 1);
-			pGlass->addPath(m_nID, 0);
+			pGlass->addPath(m_nID, 0, i + 1);
 			pGlass->processEnd(m_nID, 0);
 			pGlass->setID(szBuffer);
 			pGlass->setType(m_cassetteType);
@@ -1289,7 +1289,7 @@
 
 			CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
 			pGlass->setOriginPort(m_nIndex, nSlotIndex);
-			pGlass->addPath(m_nID, 0);
+			pGlass->addPath(m_nID, 0, slot.nSlotID);
 			pGlass->processEnd(m_nID, 0);
 			pGlass->setID(szBuffer);
 			pGlass->setType(static_cast<SERVO::MaterialsType>(config.nMaterialType));
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 425ac92..9c22433 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -131,7 +131,7 @@
 			BoardVersion version{};
 			int nRet = m_cclink.GetBoardVersion(version);
 			if (nRet == 0) {
-				LOGI("版本信息:%s.", version.toString().c_str());
+				LOGD("版本信息:%s.", version.toString().c_str());
 			}
 			else {
 				LOGE("获取CC-Link版本信息失败.");
@@ -140,7 +140,7 @@
 			BoardStatus status;
 			nRet = m_cclink.GetBoardStatus(status);
 			if (nRet == 0) {
-				LOGI("状态:%s.", status.toString().c_str());
+				LOGD("状态:%s.", status.toString().c_str());
 			}
 			else {
 				LOGE("获取CC-Link状态失败.");
@@ -422,7 +422,7 @@
 						TRACE("a0001\n", writeCode, retCode);
 					});
 				if (nRet != 0) {
-					LOGI("<Master>EFEM切换Start状态失败");
+					LOGE("<Master>EFEM切换Start状态失败");
 					m_strLastError = "EFEM切换Start状态失败.";
 					goto WAIT;
 				}
@@ -435,7 +435,7 @@
 						TRACE("a0002\n");
 					});
 				if (nRet != 0) {
-					LOGI("<Master>Bonder1切换Start状态失败");
+					LOGE("<Master>Bonder1切换Start状态失败");
 					m_strLastError = "Bonder1切换Start状态失败.";
 					goto WAIT;
 				}
@@ -448,7 +448,7 @@
 						TRACE("a0003\n");
 					});
 				if (nRet != 0) {
-					LOGI("<Master>Bonder2切换Start状态失败");
+					LOGE("<Master>Bonder2切换Start状态失败");
 					m_strLastError = "Bonder2切换Start状态失败.";
 					goto WAIT;
 				}
@@ -461,7 +461,7 @@
 						TRACE("a0004\n");
 					});
 				if (nRet != 0) {
-					LOGI("<Master>BakeCooling切换Start状态失败");
+					LOGE("<Master>BakeCooling切换Start状态失败");
 					m_strLastError = "BakeCooling切换Start状态失败.";
 					goto WAIT;
 				}
@@ -474,7 +474,7 @@
 						TRACE("a0005\n");
 					});
 				if (nRet != 0) {
-					LOGI("<Master>VacuumBake切换Start状态失败");
+					LOGE("<Master>VacuumBake切换Start状态失败");
 					m_strLastError = "VacuumBake切换Start状态失败.";
 					goto WAIT;
 				}
@@ -487,7 +487,7 @@
 						TRACE("a0006\n");
 					});
 				if (nRet != 0) {
-					LOGI("<Master>Measurement切换Start状态失败");
+					LOGE("<Master>Measurement切换Start状态失败");
 					m_strLastError = "Measurement切换Start状态失败.";
 					goto WAIT;
 				}
@@ -501,7 +501,7 @@
 				for (int i = 0; i < 6; i++) {
 					if (!bIomcOk[i]) {
 						bIomcOk[6] = FALSE;
-						LOGI("<Master>%s切换Start状态失败", pEq[i]->getName().c_str());
+						LOGE("<Master>%s切换Start状态失败", pEq[i]->getName().c_str());
 					}
 				}
 				
@@ -545,7 +545,7 @@
 							TRACE("s000%d: ret=%d\n", i + 1, retCode);
 						});
 					if (nRet != 0) {
-						LOGI("<Master>%s切换Stop状态发送失败", pEq[i]->getName().c_str());
+						LOGE("<Master>%s切换Stop状态发送失败", pEq[i]->getName().c_str());
 						m_strLastError = pEq[i]->getName() + "切换Stop状态发送失败.";
 						bIomcOk[i] = FALSE;
 						promises[i].set_value(); // 避免 wait 阻塞
@@ -560,7 +560,7 @@
 				for (int i = 0; i < 6; ++i) {
 					if (!bIomcOk[i]) {
 						bIomcOk[6] = FALSE;
-						LOGI("<Master>%s切换Stop状态失败", pEq[i]->getName().c_str());
+						LOGE("<Master>%s切换Stop状态失败", pEq[i]->getName().c_str());
 					}
 				}
 
@@ -734,7 +734,7 @@
 
 				if (!rmd.armState[0]) {
 					// m_nTestFlag = 1;
-					if (m_nTestFlag == 1) LOGI("createTransferTask 004df %d, %d", MaterialsType::G1, secondaryType);
+					if (m_nTestFlag == 1) LOGD("createTransferTask 004df %d, %d", MaterialsType::G1, secondaryType);
 					m_pActiveRobotTask = createTransferTask(pAligner, pVacuumBake, MaterialsType::G1, secondaryType);
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 					m_nTestFlag = 0;
@@ -798,7 +798,7 @@
 				CJState state = m_pControlJob->state();
 				if (state == CJState::Completed || state == CJState::Aborted || state == CJState::Failed) {
 					// ConrolJpb已完成
-					LOGI("<Master>ControlJob已经完成或失败中断");
+					LOGE("<Master>ControlJob已经完成或失败中断");
 					unlock();
 					continue;
 				}
@@ -835,7 +835,7 @@
 					}
 				}
 				if (m_inProcesJobs.empty()) {
-					LOGI("<Master>选择当前ProcessJob失败!");
+					LOGE("<Master>选择当前ProcessJob失败!");
 					unlock();
 					continue;
 				}
@@ -887,7 +887,7 @@
 
 				// Measurement -> LoadPort
 				if (rmd.armState[0] || rmd.armState[1]) {
-					LOGI("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
+					LOGD("Arm1 %s, Arm2 %s.", rmd.armState[0] ? _T("不可用") : _T("可用"),
 						rmd.armState[1] ? _T("不可用") : _T("可用"));
 				}
 				for (int s = 0; s < 4; s++) {
@@ -1312,22 +1312,22 @@
 			BOOL bOk = FALSE;
 			lock();
 			if (m_pActiveRobotTask != nullptr) {
-				LOGI("<CMaster>onPreFethedOutJob 0001.");
+				LOGD("<CMaster>onPreFethedOutJob 0001.");
 				if (m_pActiveRobotTask->getSrcPosition() == p->getID()) {
-					LOGI("<CMaster>onPreFethedOutJob 0002.");
+					LOGD("<CMaster>onPreFethedOutJob 0002.");
 					CGlass* pGlass = p->getGlassFromSlot(m_pActiveRobotTask->getSrcSlot());
 					if (pGlass != nullptr) {
-						LOGI("<CMaster>onPreFethedOutJob 0003.");
+						LOGD("<CMaster>onPreFethedOutJob 0003.");
 						CJobDataS* pJobDataS = pGlass->getJobDataS();
 						if (pJobDataS != nullptr
 							&& pJobDataS->getCassetteSequenceNo() == pJobDataB->getCassetteSequenceNo()
 							&& pJobDataS->getJobSequenceNo() == pJobDataB->getJobSequenceNo()) {
 							bOk = TRUE;
-							LOGI("<CMaster>onPreFethedOutJob, 已校验数据一致性.");
+							LOGD("<CMaster>onPreFethedOutJob, 已校验数据一致性.");
 						}
-						LOGI("<CMaster>onPreFethedOutJob 0004.");
+						LOGD("<CMaster>onPreFethedOutJob 0004.");
 						if (pJobDataS != nullptr) {
-							LOGI("<CMaster>onPreFethedOutJob 0005. %d,%d,%d,%d", 
+							LOGD("<CMaster>onPreFethedOutJob 0005. %d,%d,%d,%d", 
 								pJobDataS->getCassetteSequenceNo(),
 								pJobDataB->getCassetteSequenceNo(),
 								pJobDataS->getJobSequenceNo(),
@@ -1570,7 +1570,7 @@
 				}
 				strOut.append(szBuffer);
 			}
-			LOGI("<CMaster-%s>SVDataReport:%s", ((CEquipment*)pEquipment)->getName().c_str(), strOut.c_str());
+			LOGD("<CMaster-%s>SVDataReport:%s", ((CEquipment*)pEquipment)->getName().c_str(), strOut.c_str());
 		};
 		pEquipment->setListener(listener);
 		pEquipment->setCcLink(&m_cclink);
@@ -2038,12 +2038,12 @@
 		pSrcEq->m_nTestFlag = m_nTestFlag;
 		pTarSlot = pTarEq->getAvailableSlotForGlass(primaryType);
 		pSrcSlot = pSrcEq->getProcessedSlot(primaryType, bJobMode);
-		if (m_nTestFlag == 1) LOGI("createTransferTask 003 %x, %x", pTarSlot, pSrcSlot);
+		if (m_nTestFlag == 1) LOGD("createTransferTask 003 %x, %x", pTarSlot, pSrcSlot);
 		if (pSrcSlot == nullptr || nullptr == pTarSlot && secondaryType != SERVO::MaterialsType::G0) {
 			pTarSlot = pTarEq->getAvailableSlotForGlass(secondaryType);
 			pSrcSlot = pSrcEq->getProcessedSlot(secondaryType, bJobMode);
 		}
-		if (m_nTestFlag == 1) LOGI("createTransferTask 004 %x, %x", pTarSlot, pSrcSlot);
+		if (m_nTestFlag == 1) LOGD("createTransferTask 004 %x, %x", pTarSlot, pSrcSlot);
 
 		if (pSrcSlot != nullptr && nullptr != pTarSlot) {
 			pTask = new CRobotTask();
@@ -2698,4 +2698,17 @@
 
 		return nullptr;
 	}
+
+	int CMaster::getWipGlasses(std::vector<CGlass*>& glasses)
+	{
+		for (auto eq : m_listEquipment) {
+			auto p = dynamic_cast<CLoadPort*>(eq);
+			if (p == nullptr) {
+				eq->getAllGlass(glasses);
+			}
+
+		}
+
+		return (int)glasses.size();
+	}
 }
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index 2d4d697..e79589d 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -124,6 +124,7 @@
         CLoadPort* getPortWithCarrierId(const std::string& carrierId) const;
         bool saveState() const;
         bool loadState(const std::string& path);
+        int getWipGlasses(std::vector<CGlass*>& glasses);
 
     private:
         inline void lock() { EnterCriticalSection(&m_criticalSection); }
diff --git a/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp b/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp
index 324e975..e39bd05 100644
--- a/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp
+++ b/SourceCode/Bond/Servo/CPageCassetteCtrlCmd.cpp
@@ -119,7 +119,7 @@
 				LOGI("sendCassetteCtrlCmd 鎴愬姛.");
 			}
 			else {
-				LOGI("sendCassetteCtrlCmd 澶辫触.");
+				LOGE("sendCassetteCtrlCmd 澶辫触.");
 			}
 
 			return 0;
diff --git a/SourceCode/Bond/Servo/CPageGlassList.cpp b/SourceCode/Bond/Servo/CPageGlassList.cpp
index b5fb2f8..f858794 100644
--- a/SourceCode/Bond/Servo/CPageGlassList.cpp
+++ b/SourceCode/Bond/Servo/CPageGlassList.cpp
@@ -8,6 +8,7 @@
 #include "GlassJson.h"
 #include "CServoUtilsTool.h"
 #include "ToolUnits.h"
+#include <optional>
 
 
 #define PAGE_SIZE						10
@@ -207,10 +208,14 @@
 
 void CPageGlassList::UpdatePageData()
 {
+	// 濡傛灉涓虹1椤�, 鍙栧嚭缂撳瓨Glass, 绗﹀悎鏉′欢鍒欐樉绀猴紱
+	m_listCtrl.DeleteAllItems();
+	UpdateWipData();
+
+
 	// 鏌ヨ
 	auto& db = GlassLogDb::Instance();
 	auto page = db.queryPaged(m_filters, PAGE_SIZE, PAGE_SIZE * (m_nCurPage - 1));
-	m_listCtrl.DeleteAllItems();
 	for (const auto& r : page.items) {
 		int index = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), std::to_string(r.id).c_str());
 		m_listCtrl.SetItemText(index, 1, std::to_string(r.cassetteSeqNo).c_str());
@@ -224,6 +229,7 @@
 		m_listCtrl.SetItemText(index, 9, SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)r.aoiResult).c_str());
 		m_listCtrl.SetItemText(index, 10, r.path.c_str());
 		m_listCtrl.SetItemText(index, 11, r.params.c_str());
+		m_listCtrl.SetItemColor(index, RGB(0, 0, 0), RGB(255, 255, 0));
 
 		// 娴嬭瘯鍙嶅簭鍒楀寲
 		/*
@@ -237,6 +243,42 @@
 
 	// 涓婁竴椤� / 涓嬩竴椤�
 	UpdatePageControls();
+}
+
+void CPageGlassList::UpdateWipData()
+{
+	if (m_nCurPage != 1) return;
+
+	// 鍙栧嚭缂撳瓨Glass, 绗﹀悎鏉′欢鍒欐樉绀猴紱
+	// 浣嗚鍒犻櫎鏃х殑鏁版嵁
+	std::vector<SERVO::CGlass*> wipGlasses;
+	theApp.m_model.m_master.getWipGlasses(wipGlasses);
+	std::vector<SERVO::CGlass*> tempGlasses = wipGlasses;
+	int count = m_listCtrl.GetItemCount();
+	if (count > 0) {
+		for (int i = count - 1; i >= 0; i--) {
+			SERVO::CGlass* pGlass = (SERVO::CGlass*)m_listCtrl.GetItemData(i);
+			if (eraseGlassInVector(pGlass, wipGlasses)
+				&& GlassMatchesFilters(*pGlass, m_filters)) {
+				// 鏇存柊
+				UpdateWipRow(i, pGlass);
+			}
+			else {
+				// 鍒犻櫎
+				m_listCtrl.DeleteItem(i);
+			}
+		}
+	}
+
+	// 鍓╀笅鐨勫绗﹀彿鎻掑叆
+	for (auto* item : wipGlasses) {
+		if (GlassMatchesFilters(*item, m_filters)) {
+			InsertWipRow(item);
+		}
+	}
+	for (auto* item : tempGlasses) {
+		item->release();
+	}
 }
 
 void CPageGlassList::UpdatePageControls()
@@ -256,6 +298,7 @@
 
 	// TODO:  鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
 	SetTimer(1, 3000, nullptr);
+	SetTimer(2, 2000, nullptr);
 
 	// 涓嬫媺妗嗘帶浠�
 	InitStatusCombo();
@@ -354,6 +397,11 @@
 		KillTimer(1);
 		InitRxWindow();
 	}
+
+	else if (nIDEvent == 2) {
+		UpdateWipData();
+	}
+
 	CDialogEx::OnTimer(nIDEvent);
 }
 
@@ -464,4 +512,72 @@
 		m_nCurPage++;
 		UpdatePageData();
 	}
+}
+
+// 鏍稿績锛歐IP 鐨� CGlass 鏄惁鍛戒腑褰撳墠 Filters
+// useEndTime=true 鏃剁敤 tEnd 鍒ゆ椂闂达紙姣斿鈥滃畬鎴愬垪琛ㄢ�濈敤 t_end锛夛紝榛樿鎸� tStart銆�
+bool CPageGlassList::GlassMatchesFilters(const SERVO::CGlass& g,
+	const GlassLogDb::Filters& f,
+	bool useEndTime/* = false*/)
+{
+	// 1) 绮剧‘瀛楁
+	if (f.classId && g.getID() != *f.classId)      return false;
+	if (f.cassetteSeqNo && g.getCassetteSequenceNo() != *f.cassetteSeqNo)return false;
+	if (f.jobSeqNo && g.getJobSequenceNo() != *f.jobSeqNo)     return false;
+
+	// 2) 鍏抽敭瀛楋紙涓� DB 淇濇寔涓�鑷达細class_id / buddy_id / path / params / pretty锛�
+	if (f.keyword) {
+		const std::string& kw = *f.keyword;
+		if (!(CToolUnits::containsCI(g.getID(), kw)
+			|| CToolUnits::containsCI(g.getBuddyId(), kw)
+			|| CToolUnits::containsCI(g.getPathDescription(), kw)
+			|| CToolUnits::containsCI(g.getParamsDescription(), kw)))
+			return false;
+	}
+
+	// 3) 鏃堕棿锛堜笌 DB 淇濇寔涓�鑷达細榛樿鎸� t_start 杩囨护锛涢渶瑕佸彲鍒囧埌 t_end锛�
+	if (f.tStartFrom || f.tStartTo) {
+		std::optional<std::chrono::system_clock::time_point> tp = useEndTime ? g.tEnd() : g.tStart();
+		// 绾﹀畾锛氳嫢娌℃湁瀵瑰簲鏃堕棿鎴筹紝鍒欒涓轰笉鍛戒腑锛堜笌 DB 鐩稿悓锛歂ULL 涓嶄細鍛戒腑鑼冨洿锛�
+		if (!tp) return false;
+		if (f.tStartFrom && *tp < *f.tStartFrom) return false;
+		if (f.tStartTo && *tp > *f.tStartTo)   return false;
+	}
+
+	return true;
+}
+
+void CPageGlassList::InsertWipRow(SERVO::CGlass* pGlass)
+{
+	int index = m_listCtrl.InsertItem(0, "");
+	UpdateWipRow(index, pGlass);
+}
+
+void CPageGlassList::UpdateWipRow(unsigned int index, SERVO::CGlass* pGlass)
+{
+	ASSERT(index < m_listCtrl.GetItemCount());
+	m_listCtrl.SetItemData(index, (DWORD_PTR)pGlass);
+	m_listCtrl.SetItemColor(index, RGB(0, 0, 0), RGB(255, 255, 255));
+	m_listCtrl.SetItemText(index, 1, std::to_string(pGlass->getCassetteSequenceNo()).c_str());
+	m_listCtrl.SetItemText(index, 2, std::to_string(pGlass->getJobSequenceNo()).c_str());
+	m_listCtrl.SetItemText(index, 3, pGlass->getID().c_str());
+	m_listCtrl.SetItemText(index, 4, SERVO::CServoUtilsTool::getMaterialsTypeText(pGlass->getType()).c_str());
+	m_listCtrl.SetItemText(index, 5, SERVO::CServoUtilsTool::getGlassStateText(pGlass->state()).c_str());
+	m_listCtrl.SetItemText(index, 6, CToolUnits::TimePointToLocalString(pGlass->tStart()).c_str());
+	m_listCtrl.SetItemText(index, 7, CToolUnits::TimePointToLocalString(pGlass->tEnd()).c_str());
+	m_listCtrl.SetItemText(index, 8, pGlass->getBuddyId().c_str());
+	m_listCtrl.SetItemText(index, 9, SERVO::CServoUtilsTool::getInspResultText((SERVO::InspResult)pGlass->getAOIInspResult()).c_str());
+	m_listCtrl.SetItemText(index, 10, pGlass->getPathDescription().c_str());
+	m_listCtrl.SetItemText(index, 11, pGlass->getParamsDescription().c_str());
+}
+
+bool CPageGlassList::eraseGlassInVector(SERVO::CGlass* pGlass, std::vector<SERVO::CGlass*>& glasses)
+{
+	auto iter = std::find(glasses.begin(), glasses.end(), pGlass);
+	if (iter != glasses.end()) {
+		glasses.erase(iter);
+		return true;
+	}
+
+	return false;
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CPageGlassList.h b/SourceCode/Bond/Servo/CPageGlassList.h
index 7d702c7..5d110a4 100644
--- a/SourceCode/Bond/Servo/CPageGlassList.h
+++ b/SourceCode/Bond/Servo/CPageGlassList.h
@@ -44,7 +44,13 @@
 	void LoadData();
 	void UpdatePageData();
 	void UpdatePageControls();
-
+	void InsertWipRow(SERVO::CGlass* pGlass);
+	static bool GlassMatchesFilters(const SERVO::CGlass& g,
+		const GlassLogDb::Filters& f,
+		bool useEndTime = false);
+	void UpdateWipData();
+	bool eraseGlassInVector(SERVO::CGlass* pGlass, std::vector<SERVO::CGlass*>& glasses);
+	void UpdateWipRow(unsigned int index, SERVO::CGlass* pGlass);
 
 // 瀵硅瘽妗嗘暟鎹�
 #ifdef AFX_DESIGN_TIME
diff --git a/SourceCode/Bond/Servo/CPath.cpp b/SourceCode/Bond/Servo/CPath.cpp
index 1731ee9..5898b5b 100644
--- a/SourceCode/Bond/Servo/CPath.cpp
+++ b/SourceCode/Bond/Servo/CPath.cpp
@@ -16,10 +16,11 @@
 		m_pNext = nullptr;
 	}
 
-	CPath::CPath(unsigned int nEqId, unsigned int nUnit)
+	CPath::CPath(unsigned int nEqId, unsigned int nUnit, unsigned int nSlot)
 	{
 		m_nEqID = nEqId;
 		m_nUnit = nUnit;
+		m_nSlot = nSlot;
 		m_timeOut = 0;
 		m_timeIn = CToolUnits::getTimestamp();
 		m_bProcessed = FALSE;
@@ -49,7 +50,7 @@
 
 	void CPath::getSimpleDescription(std::string& strOut)
 	{
-		strOut = CServoUtilsTool::getEqUnitName(m_nEqID, m_nUnit);
+		strOut = CServoUtilsTool::getEqUnitName(m_nEqID, m_nUnit, m_nSlot);
 	}
 
 	void CPath::serialize(CArchive& ar)
@@ -57,6 +58,7 @@
 		if (ar.IsStoring()) {
 			ar << m_nEqID;
 			ar << m_nUnit;
+			ar << m_nSlot;
 			ar << m_timeIn;
 			ar << m_timeOut;
 			ar << m_bProcessed;
@@ -71,6 +73,7 @@
 
 			ar >> m_nEqID;
 			ar >> m_nUnit;
+			ar >> m_nSlot;
 			ar >> m_timeIn;
 			ar >> m_timeOut;
 			ar >> m_bProcessed;
@@ -96,6 +99,11 @@
 		return m_nUnit;
 	}
 
+	unsigned int CPath::getSlot()
+	{
+		return m_nSlot;
+	}
+
 	void CPath::setInTime(ULONGLONG time)
 	{
 		m_timeIn = time;
diff --git a/SourceCode/Bond/Servo/CPath.h b/SourceCode/Bond/Servo/CPath.h
index ed17d8e..61f8955 100644
--- a/SourceCode/Bond/Servo/CPath.h
+++ b/SourceCode/Bond/Servo/CPath.h
@@ -7,7 +7,7 @@
 	{
 	public:
 		CPath();
-		CPath(unsigned int nEqId, unsigned int nUnit);
+		CPath(unsigned int nEqId, unsigned int nUnit, unsigned int nSlot);
 		virtual ~CPath();
 
 	public:
@@ -21,6 +21,7 @@
 		CPath* getHeadPath();
 		unsigned int getEqID();
 		unsigned int getUnit();
+		unsigned int getSlot();
 		void setInTime(ULONGLONG time);
 		ULONGLONG getInTime();
 		void setOutTime(ULONGLONG time);
@@ -33,6 +34,7 @@
 	private:	
 		unsigned int m_nEqID;
 		unsigned int m_nUnit;
+		unsigned int m_nSlot;
 		ULONGLONG m_timeIn;
 		ULONGLONG m_timeOut;
 		BOOL m_bProcessed;
diff --git a/SourceCode/Bond/Servo/CRobotTask.cpp b/SourceCode/Bond/Servo/CRobotTask.cpp
index 1b4a1aa..f0e9596 100644
--- a/SourceCode/Bond/Servo/CRobotTask.cpp
+++ b/SourceCode/Bond/Servo/CRobotTask.cpp
@@ -220,7 +220,7 @@
 					LOGI(_T("RobotTask已下发到EFEM"));
 				}
 				else {
-					LOGI(_T("RobotTask下发失败"));
+					LOGE(_T("RobotTask下发失败"));
 				}
 
 				return 0;
@@ -238,7 +238,7 @@
 					LOGI(_T("RobotTask/get已下发到EFEM"));
 				}
 				else {
-					LOGI(_T("RobotTask/get已下发失败"));
+					LOGE(_T("RobotTask/get已下发失败"));
 				}
 
 				return 0;
@@ -261,7 +261,7 @@
 					LOGI(_T("RobotTask/put已下发到EFEM"));
 				}
 				else {
-					LOGI(_T("RobotTask/put已下发失败"));
+					LOGE(_T("RobotTask/put已下发失败"));
 				}
 
 				return 0;
@@ -279,7 +279,7 @@
 					LOGI(_T("RobotTask/restore-put已下发到EFEM"));
 				}
 				else {
-					LOGI(_T("RobotTask/restore-put已下发失败"));
+					LOGE(_T("RobotTask/restore-put已下发失败"));
 				}
 
 				return 0;
diff --git a/SourceCode/Bond/Servo/CServoUtilsTool.cpp b/SourceCode/Bond/Servo/CServoUtilsTool.cpp
index bfa0a43..8c29031 100644
--- a/SourceCode/Bond/Servo/CServoUtilsTool.cpp
+++ b/SourceCode/Bond/Servo/CServoUtilsTool.cpp
@@ -64,6 +64,80 @@
 			return "AOI";
 		}
 
+
+		if (eqid == EQ_ID_ARM_TRAY1) {
+			return "ARM1";
+		}
+
+		if (eqid == EQ_ID_ARM_TRAY2) {
+			return "ARM2";
+		}
+
+		return "";
+	}
+
+	std::string CServoUtilsTool::getEqUnitName(int eqid, int unit, int slot)
+	{
+		char szBuffer[256];
+		if (eqid == EQ_ID_LOADPORT1
+			|| eqid == EQ_ID_LOADPORT2
+			|| eqid == EQ_ID_LOADPORT3
+			|| eqid == EQ_ID_LOADPORT4
+			) {
+			sprintf_s(szBuffer, 256, "Port%d(Slot%d)", eqid - EQ_ID_LOADPORT1 + 1, slot);
+			return std::string(szBuffer);
+		}
+
+		if (eqid == EQ_ID_ALIGNER) {
+			return "Aligner";
+		}
+
+		if (eqid == EQ_ID_FLIPER) {
+			return "Fliper";
+		}
+
+		if (eqid == EQ_ID_VACUUMBAKE) {
+			if (unit == 0) {
+				sprintf_s(szBuffer, 256, "烘烤A腔(Slot%d)", slot);
+				return std::string(szBuffer);
+			}
+			if (unit == 1) {
+				sprintf_s(szBuffer, 256, "烘烤B腔(Slot%d)", slot);
+				return std::string(szBuffer);
+			}
+		}
+
+		if (eqid == EQ_ID_Bonder1) {
+			sprintf_s(szBuffer, 256, "Bonder1(Slot%d)", slot);
+			return std::string(szBuffer);
+		}
+
+		if (eqid == EQ_ID_Bonder2) {
+			sprintf_s(szBuffer, 256, "Bonder2(Slot%d)", slot);
+			return std::string(szBuffer);
+		}
+
+		if (eqid == EQ_ID_BAKE_COOLING) {
+
+			if (slot == 0) return "后烘烤A腔";
+			if (slot == 1) return "冷却A";
+			if (slot == 0) return "后烘烤B腔";
+			if (slot == 1) return "冷却B";
+		}
+
+		if (eqid == EQ_ID_MEASUREMENT) {
+			return "AOI";
+		}
+
+
+		if (eqid == EQ_ID_ARM_TRAY1) {
+			return "ARM1";
+		}
+
+		if (eqid == EQ_ID_ARM_TRAY2) {
+			return "ARM2";
+		}
+
 		return "";
 	}
 
diff --git a/SourceCode/Bond/Servo/CServoUtilsTool.h b/SourceCode/Bond/Servo/CServoUtilsTool.h
index 10d3038..945d717 100644
--- a/SourceCode/Bond/Servo/CServoUtilsTool.h
+++ b/SourceCode/Bond/Servo/CServoUtilsTool.h
@@ -12,6 +12,7 @@
 
 	public:
 		static std::string getEqUnitName(int eqid, int unit);
+		static std::string getEqUnitName(int eqid, int unit, int slot);
 		static std::string getMaterialsTypeText(MaterialsType type);
 		static std::string getGlassStateText(SERVO::GlsState state);
 		static std::string getInspResultText(SERVO::InspResult result);
diff --git a/SourceCode/Bond/Servo/DevicePropertyDlg.cpp b/SourceCode/Bond/Servo/DevicePropertyDlg.cpp
index 82f4c6f..c666f66 100644
--- a/SourceCode/Bond/Servo/DevicePropertyDlg.cpp
+++ b/SourceCode/Bond/Servo/DevicePropertyDlg.cpp
@@ -41,7 +41,7 @@
 	// TODO:  鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
 	SERVO::CEquipment* pEquipment = theApp.m_model.m_master.getEquipment(m_nDeviceID);
 	if (nullptr == pEquipment) {
-		LOGI("<璁惧ID锛�%d>鑾峰彇璁惧灞炴�уけ璐ャ��", m_nDeviceID);
+		LOGE("<璁惧ID锛�%d>鑾峰彇璁惧灞炴�уけ璐ャ��", m_nDeviceID);
 		return FALSE;
 	}
 
diff --git a/SourceCode/Bond/Servo/GlassJson.cpp b/SourceCode/Bond/Servo/GlassJson.cpp
index e9c54fb..91e7bed 100644
--- a/SourceCode/Bond/Servo/GlassJson.cpp
+++ b/SourceCode/Bond/Servo/GlassJson.cpp
@@ -178,6 +178,7 @@
                 Json::Value n(Json::objectValue);
                 n["eq_id"] = p->getEqID();
                 n["unit"] = p->getUnit();
+                n["slot"] = p->getUnit();
                 put_ull_as_str(n, "time_in", static_cast<unsigned long long>(p->getInTime()));
                 put_ull_as_str(n, "time_out", static_cast<unsigned long long>(p->getOutTime()));
                 n["processed"] = p->isProcessEnd() ? true : false;
@@ -293,7 +294,8 @@
         for (const auto& n : root["path"]) {
             unsigned eq = JUInt(n, "eq_id", 0);
             unsigned unit = JUInt(n, "unit", 0);
-            g.addPath(eq, unit);
+            unsigned slot = JUInt(n, "slot", 0);
+            g.addPath(eq, unit, slot);
 
             CPath* tail = nullptr;
             if (auto head = g.getPath()) tail = head->getTailPath();
diff --git a/SourceCode/Bond/Servo/ListCtrlEx.cpp b/SourceCode/Bond/Servo/ListCtrlEx.cpp
index d302c4c..ff94bd7 100644
--- a/SourceCode/Bond/Servo/ListCtrlEx.cpp
+++ b/SourceCode/Bond/Servo/ListCtrlEx.cpp
@@ -34,11 +34,12 @@
 	{
 		// 根据在 SetItemColor(DWORD iItem, COLORREF color) 设置的   
 		// ITEM号和COLORREF 在摸板中查找,然后进行颜色赋值。
-		//LISTITEMEX_9& itemex = m_listItemColor.GetAt(m_listItemColor.FindIndex(nmcd.dwItemSpec));
-		//lplvdr->clrText = itemex.colText;
-		//lplvdr->clrTextBk = itemex.colTextBk;
-		//*pResult = CDRF_DODEFAULT;
+		LISTITEMEX_9& itemex = m_listItemColor.GetAt(m_listItemColor.FindIndex(nmcd.dwItemSpec));
+		lplvdr->clrText = itemex.colText;
+		lplvdr->clrTextBk = itemex.colTextBk;
+		*pResult = CDRF_DODEFAULT;
 
+		/*
 		if (nmcd.dwItemSpec % 2 == 0) {
 			lplvdr->clrText = RGB(0, 0, 0);
 			lplvdr->clrTextBk = RGB(235, 235, 235);
@@ -49,7 +50,7 @@
 			lplvdr->clrTextBk = RGB(255, 255, 255);
 			*pResult = CDRF_DODEFAULT;
 		}
-
+		*/
 
 		break;
 	}
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 47ea454..6f2111e 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -428,13 +428,15 @@
 		m_hsmsPassive.setVariableValue("PJEndID", ((SERVO::CProcessJob*)pj)->id().c_str());
 		m_hsmsPassive.requestEventReportSend_PJ_End();
 	};
-	masterListener.onPanelStart = [&](void* pMaster, void* pj) {
-		m_hsmsPassive.setVariableValue("PanelStartID", ((SERVO::CGlass*)pj)->getID().c_str());
+	masterListener.onPanelStart = [&](void* pMaster, void* pPanel) {
+		m_hsmsPassive.setVariableValue("PanelStartID", ((SERVO::CGlass*)pPanel)->getID().c_str());
 		m_hsmsPassive.requestEventReportSend_Panel_Start();
 	};
-	masterListener.onPanelEnd = [&](void* pMaster, void* pj) {
-		m_hsmsPassive.setVariableValue("PanelEndID", ((SERVO::CGlass*)pj)->getID().c_str());
+	masterListener.onPanelEnd = [&](void* pMaster, void* pPanel) {
+		m_hsmsPassive.setVariableValue("PanelEndID", ((SERVO::CGlass*)pPanel)->getID().c_str());
 		m_hsmsPassive.requestEventReportSend_Panel_End();
+		auto& db = GlassLogDb::Instance();
+		db.insertFromCGlass((*(SERVO::CGlass*)pPanel));
 	};
 	m_master.setListener(masterListener);
 	m_master.setContinuousTransferCount(m_configuration.getContinuousTransferCount());
diff --git a/SourceCode/Bond/Servo/ToolUnits.cpp b/SourceCode/Bond/Servo/ToolUnits.cpp
index 68f9937..cc9a1bf 100644
--- a/SourceCode/Bond/Servo/ToolUnits.cpp
+++ b/SourceCode/Bond/Servo/ToolUnits.cpp
@@ -3,6 +3,7 @@
 #include <chrono>
 #include <memory>
 #include <sstream>
+#include <algorithm>
 
 
 CToolUnits::CToolUnits()
@@ -491,3 +492,68 @@
 	auto toUtc = LocalSTtoUtcTP(stToLocal);
 	return { fromUtc, toUtc };
 }
+
+// 小工具:ASCII 不区分大小写包含(中文等非 ASCII 不受影响,但也不需要大小写转换)
+bool CToolUnits::containsCI(const std::string& hay, const std::string& needle) {
+	if (needle.empty()) return true;
+	auto toLower = [](std::string s) { std::transform(s.begin(), s.end(), s.begin(),
+		[](unsigned char c) { return (char)std::tolower(c); }); return s; };
+	std::string h = toLower(hay), n = toLower(needle);
+	return h.find(n) != std::string::npos;
+}
+
+// ------- 本地时间 -------
+std::string CToolUnits::TimePointToLocalString(const std::optional<TP>& tp,
+	const char* fmt/* = "%Y-%m-%d %H:%M:%S"*/)
+{
+	if (!tp) return {};
+	std::time_t t = std::chrono::system_clock::to_time_t(*tp);
+	std::tm tm{};
+#if defined(_WIN32)
+	localtime_s(&tm, &t);
+#else
+	localtime_r(&t, &tm);
+#endif
+	char buf[64]{};
+	std::strftime(buf, sizeof(buf), fmt, &tm);
+	return buf;
+}
+
+// ------- UTC 时间 -------
+std::string CToolUnits::TimePointToUtcString(const std::optional<TP>& tp,
+	const char* fmt/* = "%Y-%m-%d %H:%M:%S"*/)
+{
+	if (!tp) return {};
+	std::time_t t = std::chrono::system_clock::to_time_t(*tp);
+	std::tm tm{};
+#if defined(_WIN32)
+	gmtime_s(&tm, &t);
+#else
+	gmtime_r(&t, &tm);
+#endif
+	char buf[64]{};
+	std::strftime(buf, sizeof(buf), fmt, &tm);
+	return buf;
+}
+
+std::string CToolUnits::TimePointToLocalStringMs(const std::optional<TP>& tp)
+{
+	if (!tp) return {};
+	using namespace std::chrono;
+	auto ms_since_epoch = duration_cast<milliseconds>(tp->time_since_epoch());
+	auto ms = static_cast<int>(ms_since_epoch.count() % 1000);
+
+	std::time_t t = system_clock::to_time_t(*tp);
+	std::tm tm{};
+#if defined(_WIN32)
+	localtime_s(&tm, &t);
+#else
+	localtime_r(&t, &tm);
+#endif
+	char date[32]{};
+	std::strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &tm);
+
+	char out[40]{};
+	std::snprintf(out, sizeof(out), "%s.%03d", date, ms);
+	return out;
+}
diff --git a/SourceCode/Bond/Servo/ToolUnits.h b/SourceCode/Bond/Servo/ToolUnits.h
index d369213..b5f8430 100644
--- a/SourceCode/Bond/Servo/ToolUnits.h
+++ b/SourceCode/Bond/Servo/ToolUnits.h
@@ -5,7 +5,7 @@
 #include <utility>
 
 enum class QuickRange { Today, Last7Days, ThisMonth, ThisYear };
-
+using TP = std::chrono::system_clock::time_point;
 class CToolUnits
 {
 public:
@@ -49,10 +49,15 @@
 	static bool IsLeap(int y);
 	static int DaysInMonth(int y, int m);
 	static void GetTodayYMD_Local(int& y, int& m, int& d);
-	static void CToolUnits::LocalCalendarMinusDays(int& y, int& m, int& d, int nDays);
+	static void LocalCalendarMinusDays(int& y, int& m, int& d, int nDays);
 	static std::pair<std::chrono::system_clock::time_point,
 		std::chrono::system_clock::time_point>
-		CToolUnits::CalcQuickRangeUtc(QuickRange r);
-
+		CalcQuickRangeUtc(QuickRange r);
+	static bool containsCI(const std::string& hay, const std::string& needle);
+	static std::string TimePointToLocalString(const std::optional<TP>& tp,
+		const char* fmt = "%Y-%m-%d %H:%M:%S");
+	static std::string TimePointToUtcString(const std::optional<TP>& tp,
+		const char* fmt = "%Y-%m-%d %H:%M:%S");
+	static std::string TimePointToLocalStringMs(const std::optional<TP>& tp);
 };
 
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index ad5b964..c5bbd31 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3