From b78a202c2933d345e1983de26948dbdae5d72382 Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期四, 12 二月 2026 10:28:06 +0800
Subject: [PATCH] 1.加上限制条件,Port1必须配置Port2, Port3必须配Port4,且是同一ProcessJob

---
 SourceCode/Bond/Servo/CMaster.cpp |  222 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 222 insertions(+), 0 deletions(-)

diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 25433ac..c7703e4 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -707,6 +707,91 @@
 					continue;
 				}
 
+				// 鐢熶骇妯″紡鍥哄畾鏄犲皠锛歅ort1/3 -> G1锛孭ort2/4 -> G2銆�
+				auto isProductionPortTypeMatch = [&](int portIndex, MaterialsType type) -> bool {
+					if (m_schedulingMode != SchedulingMode::Production) return true;
+					const bool isG1Port = (portIndex == 0 || portIndex == 2);
+					if (type == MaterialsType::G1) return isG1Port;
+					if (type == MaterialsType::G2) return !isG1Port;
+					return true;
+				};
+
+				// 鐢熶骇妯″紡锛氭牴鎹嚎涓婃湭閰嶅鐜荤拑鍙嶆帹涓嬩竴鐗囧簲鏉ヨ嚜鍝釜绔彛锛圥ort1<->2, Port3<->4锛夈��
+				auto getPreferredPortForType = [&](MaterialsType targetType) -> int {
+					if (m_schedulingMode != SchedulingMode::Production) return -1;
+
+					auto preferG1ByG2 = [&](CGlass* pG2) -> int {
+						if (pG2 == nullptr || pG2->getType() != MaterialsType::G2 || pG2->getBuddy() != nullptr) return -1;
+						int originPort = -1, originSlot = -1;
+						pG2->getOrginPort(originPort, originSlot);
+						if (originPort == 1) return 0; // Port2 -> Port1
+						if (originPort == 3) return 2; // Port4 -> Port3
+						return -1;
+					};
+					auto preferG2ByG1 = [&](CGlass* pG1) -> int {
+						if (pG1 == nullptr || pG1->getType() != MaterialsType::G1 || pG1->getBuddy() != nullptr) return -1;
+						int originPort = -1, originSlot = -1;
+						pG1->getOrginPort(originPort, originSlot);
+						if (originPort == 0) return 1; // Port1 -> Port2
+						if (originPort == 2) return 3; // Port3 -> Port4
+						return -1;
+					};
+
+					if (targetType == MaterialsType::G1) {
+						int p = preferG1ByG2(pBonder1->getGlassFromSlot(1)); if (p >= 0) return p;
+						p = preferG1ByG2(pBonder2->getGlassFromSlot(1)); if (p >= 0) return p;
+						p = preferG1ByG2(pFliper->getGlassFromSlot(1));   if (p >= 0) return p;
+						p = preferG1ByG2(pAligner->getGlassFromSlot(1));  if (p >= 0) return p;
+					}
+					else if (targetType == MaterialsType::G2) {
+						int p = preferG2ByG1(pBonder1->getGlassFromSlot(2)); if (p >= 0) return p;
+						p = preferG2ByG1(pBonder2->getGlassFromSlot(2)); if (p >= 0) return p;
+						p = preferG2ByG1(pVacuumBake->getGlassFromSlot(1)); if (p >= 0) return p;
+						p = preferG2ByG1(pVacuumBake->getGlassFromSlot(2)); if (p >= 0) return p;
+						p = preferG2ByG1(pAligner->getGlassFromSlot(1)); if (p >= 0) return p;
+					}
+
+					return -1;
+				};
+
+				// Job 妯″紡涓嬭姹� Bonder 鍐呯殑 G1/G2 鏉ヨ嚜鍚屼竴涓� ProcessJob銆�
+				auto validateBonderPairProcessJob = [&](CEquipment* pBonder, const char* bonderName) -> bool {
+					if (m_pActiveRobotTask == nullptr) return false;
+					CGlass* pIncomingG1 = (CGlass*)m_pActiveRobotTask->getContext();
+					CGlass* pExistingG2 = pBonder->getGlassFromSlot(0);
+					if (pIncomingG1 == nullptr || pExistingG2 == nullptr) return true;
+
+					CProcessJob* pjG1 = pIncomingG1->getProcessJob();
+					CProcessJob* pjG2 = pExistingG2->getProcessJob();
+					if (m_bJobMode && (pjG1 == nullptr || pjG2 == nullptr || pjG1 != pjG2)) {
+						std::string pj1 = (pjG1 == nullptr) ? "NULL" : pjG1->id();
+						std::string pj2 = (pjG2 == nullptr) ? "NULL" : pjG2->id();
+						LOGW("<Master>%s閰嶅鎷︽埅锛欸1/G2鏉ヨ嚜涓嶅悓ProcessJob(G1=%s,G2=%s)銆�",
+							bonderName, pj1.c_str(), pj2.c_str());
+						delete m_pActiveRobotTask;
+						m_pActiveRobotTask = nullptr;
+						return false;
+					}
+
+					// 鐢熶骇妯″紡鍥哄畾绔彛瀵癸細Port1<->Port2锛孭ort3<->Port4銆�
+					if (m_schedulingMode == SchedulingMode::Production) {
+						int g1Port = 0, g1Slot = 0, g2Port = 0, g2Slot = 0;
+						pIncomingG1->getOrginPort(g1Port, g1Slot);
+						pExistingG2->getOrginPort(g2Port, g2Slot);
+						const bool pairOk =
+							(g1Port == 0 && g2Port == 1) ||
+							(g1Port == 2 && g2Port == 3);
+						if (!pairOk) {
+							LOGW("<Master>%s閰嶅鎷︽埅锛氱鍙e涓嶅尮閰�(瑕佹眰1<->2鎴�3<->4, 瀹為檯G1Port=%d,G2Port=%d)銆�",
+								bonderName, g1Port + 1, g2Port + 1);
+							delete m_pActiveRobotTask;
+							m_pActiveRobotTask = nullptr;
+							return false;
+						}
+					}
+					return true;
+				};
+
 
 				// Bonder1銆丅onder2銆丗liper銆乂acuumBake銆丄ligner锛岀粺璁2鍜孏1鐨勬暟閲�, 閰嶅缁勬暟, 澶氬嚭鐨勭被鍨�
 				int nG2Count = 0, nG1Count = 0, nGlassGroup, nExtraType;
@@ -837,11 +922,17 @@
 				// VacuumBake(G1) -> Bonder
 				if (!rmd.armState[0] && pBonder1->slotHasGlass(0) && !pBonder1->slotHasGlass(1)) {
 					m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, MaterialsType::G1, MaterialsType::G0);
+					if (m_pActiveRobotTask != nullptr && !validateBonderPairProcessJob(pBonder1, "Bonder1")) {
+						// 鍚� PJ 鏍¢獙澶辫触锛屾湰杞笉涓嬪彂鎼��
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
 				if (!rmd.armState[0] && pBonder2->slotHasGlass(0) && !pBonder2->slotHasGlass(1)) {
 					m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, MaterialsType::G1, MaterialsType::G0);
+					if (m_pActiveRobotTask != nullptr && !validateBonderPairProcessJob(pBonder2, "Bonder2")) {
+						// 鍚� PJ 鏍¢獙澶辫触锛屾湰杞笉涓嬪彂鎼��
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
@@ -880,14 +971,34 @@
 				else {
 					primaryType = MaterialsType::G1;
 				}
+				const int preferredPortForPrimary = getPreferredPortForType(primaryType);
+				{
+					static int s_prevPrimaryType = -1;
+					static int s_prevPreferredPort = -2;
+					const int curPrimaryType = (int)primaryType;
+					if (s_prevPrimaryType != curPrimaryType || s_prevPreferredPort != preferredPortForPrimary) {
+						LOGI("<Master>LoadPort->Aligner瑙勫垯(RUNNING): primaryType=%d, preferredPort=%d",
+							curPrimaryType, preferredPortForPrimary >= 0 ? (preferredPortForPrimary + 1) : 0);
+						s_prevPrimaryType = curPrimaryType;
+						s_prevPreferredPort = preferredPortForPrimary;
+					}
+				}
 
 				for (int s = 0; s < 4; s++) {
 					PortType pt = pLoadPorts[s]->getPortType();
 					if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
 						&& (pt == PortType::Loading || pt == PortType::Both)
 						&& pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
+						if (!isProductionPortTypeMatch(s, primaryType)) {
+							continue;
+						}
+						if (preferredPortForPrimary >= 0 && s != preferredPortForPrimary) {
+							continue;
+						}
 						m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, 1, m_bJobMode);
 						if (m_pActiveRobotTask != nullptr) {
+							LOGI("<Master>LoadPort->Aligner鍛戒腑(RUNNING): port=%d, primaryType=%d, preferredPort=%d",
+								s + 1, (int)primaryType, preferredPortForPrimary >= 0 ? (preferredPortForPrimary + 1) : 0);
 							CGlass* pGlass = (CGlass*)m_pActiveRobotTask->getContext();
 							if (pGlass->getBuddy() != nullptr) {
 								delete m_pActiveRobotTask;
@@ -969,6 +1080,91 @@
 					unlock(); // 绛夊綋鍓嶄换鍔″畬鎴愭垨涓鍚庣户缁�
 					continue;
 				}
+
+				// 鐢熶骇妯″紡鍥哄畾鏄犲皠锛歅ort1/3 -> G1锛孭ort2/4 -> G2銆�
+				auto isProductionPortTypeMatch = [&](int portIndex, MaterialsType type) -> bool {
+					if (m_schedulingMode != SchedulingMode::Production) return true;
+					const bool isG1Port = (portIndex == 0 || portIndex == 2);
+					if (type == MaterialsType::G1) return isG1Port;
+					if (type == MaterialsType::G2) return !isG1Port;
+					return true;
+				};
+
+				// 鐢熶骇妯″紡锛氭牴鎹嚎涓婃湭閰嶅鐜荤拑鍙嶆帹涓嬩竴鐗囧簲鏉ヨ嚜鍝釜绔彛锛圥ort1<->2, Port3<->4锛夈��
+				auto getPreferredPortForType = [&](MaterialsType targetType) -> int {
+					if (m_schedulingMode != SchedulingMode::Production) return -1;
+
+					auto preferG1ByG2 = [&](CGlass* pG2) -> int {
+						if (pG2 == nullptr || pG2->getType() != MaterialsType::G2 || pG2->getBuddy() != nullptr) return -1;
+						int originPort = -1, originSlot = -1;
+						pG2->getOrginPort(originPort, originSlot);
+						if (originPort == 1) return 0; // Port2 -> Port1
+						if (originPort == 3) return 2; // Port4 -> Port3
+						return -1;
+					};
+					auto preferG2ByG1 = [&](CGlass* pG1) -> int {
+						if (pG1 == nullptr || pG1->getType() != MaterialsType::G1 || pG1->getBuddy() != nullptr) return -1;
+						int originPort = -1, originSlot = -1;
+						pG1->getOrginPort(originPort, originSlot);
+						if (originPort == 0) return 1; // Port1 -> Port2
+						if (originPort == 2) return 3; // Port3 -> Port4
+						return -1;
+					};
+
+					if (targetType == MaterialsType::G1) {
+						int p = preferG1ByG2(pBonder1->getGlassFromSlot(1)); if (p >= 0) return p;
+						p = preferG1ByG2(pBonder2->getGlassFromSlot(1)); if (p >= 0) return p;
+						p = preferG1ByG2(pFliper->getGlassFromSlot(1));   if (p >= 0) return p;
+						p = preferG1ByG2(pAligner->getGlassFromSlot(1));  if (p >= 0) return p;
+					}
+					else if (targetType == MaterialsType::G2) {
+						int p = preferG2ByG1(pBonder1->getGlassFromSlot(2)); if (p >= 0) return p;
+						p = preferG2ByG1(pBonder2->getGlassFromSlot(2)); if (p >= 0) return p;
+						p = preferG2ByG1(pVacuumBake->getGlassFromSlot(1)); if (p >= 0) return p;
+						p = preferG2ByG1(pVacuumBake->getGlassFromSlot(2)); if (p >= 0) return p;
+						p = preferG2ByG1(pAligner->getGlassFromSlot(1)); if (p >= 0) return p;
+					}
+
+					return -1;
+				};
+
+				// Job 妯″紡涓嬭姹� Bonder 鍐呯殑 G1/G2 鏉ヨ嚜鍚屼竴涓� ProcessJob銆�
+				auto validateBonderPairProcessJob = [&](CEquipment* pBonder, const char* bonderName) -> bool {
+					if (m_pActiveRobotTask == nullptr) return false;
+					CGlass* pIncomingG1 = (CGlass*)m_pActiveRobotTask->getContext();
+					CGlass* pExistingG2 = pBonder->getGlassFromSlot(0);
+					if (pIncomingG1 == nullptr || pExistingG2 == nullptr) return true;
+
+					CProcessJob* pjG1 = pIncomingG1->getProcessJob();
+					CProcessJob* pjG2 = pExistingG2->getProcessJob();
+					if (m_bJobMode && (pjG1 == nullptr || pjG2 == nullptr || pjG1 != pjG2)) {
+						std::string pj1 = (pjG1 == nullptr) ? "NULL" : pjG1->id();
+						std::string pj2 = (pjG2 == nullptr) ? "NULL" : pjG2->id();
+						LOGW("<Master>%s閰嶅鎷︽埅锛欸1/G2鏉ヨ嚜涓嶅悓ProcessJob(G1=%s,G2=%s)銆�",
+							bonderName, pj1.c_str(), pj2.c_str());
+						delete m_pActiveRobotTask;
+						m_pActiveRobotTask = nullptr;
+						return false;
+					}
+
+					// 鐢熶骇妯″紡鍥哄畾绔彛瀵癸細Port1<->Port2锛孭ort3<->Port4銆�
+					if (m_schedulingMode == SchedulingMode::Production) {
+						int g1Port = 0, g1Slot = 0, g2Port = 0, g2Slot = 0;
+						pIncomingG1->getOrginPort(g1Port, g1Slot);
+						pExistingG2->getOrginPort(g2Port, g2Slot);
+						const bool pairOk =
+							(g1Port == 0 && g2Port == 1) ||
+							(g1Port == 2 && g2Port == 3);
+						if (!pairOk) {
+							LOGW("<Master>%s閰嶅鎷︽埅锛氱鍙e涓嶅尮閰�(瑕佹眰1<->2鎴�3<->4, 瀹為檯G1Port=%d,G2Port=%d)銆�",
+								bonderName, g1Port + 1, g2Port + 1);
+							delete m_pActiveRobotTask;
+							m_pActiveRobotTask = nullptr;
+							return false;
+						}
+					}
+					return true;
+				};
 
 				// 5.5) 鏆傚仠鐘舵�佹鏌ワ細鑻� CJ 鎴栧湪鍒� PJ 澶勪簬 Paused锛屾殏缂撹皟搴︽柊鐨勬惉閫�
 				bool pausedByEvent = false;
@@ -1098,10 +1294,16 @@
 				// 13) VacuumBake(G1) -> Bonder锛堟Ы绾у垽瀹氾細slot0(G2) 宸叉湁涓� slot1(G1) 涓虹┖锛�
 				if (!rmd.armState[0] && pBonder1->slotHasGlass(0) && !pBonder1->slotHasGlass(1)) {
 					m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder1, MaterialsType::G1, MaterialsType::G0);
+					if (m_pActiveRobotTask != nullptr && !validateBonderPairProcessJob(pBonder1, "Bonder1")) {
+						// 鍚� PJ 鏍¢獙澶辫触锛屾湰杞笉涓嬪彂鎼��
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 				if (!rmd.armState[0] && pBonder2->slotHasGlass(0) && !pBonder2->slotHasGlass(1)) {
 					m_pActiveRobotTask = createTransferTask(pVacuumBake, pBonder2, MaterialsType::G1, MaterialsType::G0);
+					if (m_pActiveRobotTask != nullptr && !validateBonderPairProcessJob(pBonder2, "Bonder2")) {
+						// 鍚� PJ 鏍¢獙澶辫触锛屾湰杞笉涓嬪彂鎼��
+					}
 					CHECK_RUN_ACTIVE_ROBOT_TASK(m_pActiveRobotTask);
 				}
 
@@ -1123,15 +1325,35 @@
 
 				// 16) LoadPort -> Aligner锛堝彈缁勬暟闂ㄩ檺鎺у埗锛涚粺涓� buddy/鐘舵�佹椂搴忥級
 				if (blockLoadFromLP) { unlock(); continue; }
+				const int preferredPortForPrimary = getPreferredPortForType(primaryType);
+				{
+					static int s_prevPrimaryType = -1;
+					static int s_prevPreferredPort = -2;
+					const int curPrimaryType = (int)primaryType;
+					if (s_prevPrimaryType != curPrimaryType || s_prevPreferredPort != preferredPortForPrimary) {
+						LOGI("<Master>LoadPort->Aligner瑙勫垯(RUNNING_BATCH): primaryType=%d, preferredPort=%d",
+							curPrimaryType, preferredPortForPrimary >= 0 ? (preferredPortForPrimary + 1) : 0);
+						s_prevPrimaryType = curPrimaryType;
+						s_prevPreferredPort = preferredPortForPrimary;
+					}
+				}
 
 				for (int s = 0; s < 4; s++) {
 					PortType pt = pLoadPorts[s]->getPortType();
 					if (!rmd.armState[0] && pLoadPorts[s]->isEnable()
 						&& (pt == PortType::Loading || pt == PortType::Both)
 						&& pLoadPorts[s]->getPortStatus() == PORT_INUSE) {
+						if (!isProductionPortTypeMatch(s, primaryType)) {
+							continue;
+						}
+						if (preferredPortForPrimary >= 0 && s != preferredPortForPrimary) {
+							continue;
+						}
 
 						m_pActiveRobotTask = createTransferTask(pLoadPorts[s], pAligner, primaryType, secondaryType, 1, m_bJobMode);
 						if (m_pActiveRobotTask != nullptr) {
+							LOGI("<Master>LoadPort->Aligner鍛戒腑(RUNNING_BATCH): port=%d, primaryType=%d, preferredPort=%d",
+								s + 1, (int)primaryType, preferredPortForPrimary >= 0 ? (preferredPortForPrimary + 1) : 0);
 							auto* pGlass = static_cast<CGlass*>(m_pActiveRobotTask->getContext());
 							if (pGlass->getBuddy() != nullptr) {
 								delete m_pActiveRobotTask; m_pActiveRobotTask = nullptr;

--
Gitblit v1.9.3