From 38fdd2e7d1d45a3ffed57fde30031a6a8f04d235 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期一, 05 五月 2025 18:02:20 +0800
Subject: [PATCH] 1.获取配方列表,已处理待测试。

---
 SourceCode/Bond/Servo/CPageGraph2.cpp       |   14 +
 SourceCode/Bond/Servo/Servo.vcxproj         |    4 
 SourceCode/Bond/Servo/Servo.vcxproj.filters |    4 
 SourceCode/Bond/Servo/CRecipesManager.cpp   |  187 ++++++++++++++++++++++++++
 SourceCode/Bond/Servo/CEquipment.cpp        |   11 +
 SourceCode/Bond/Servo/CRecipeList.cpp       |   81 +++++++++++
 SourceCode/Bond/Servo/CEquipment.h          |    3 
 SourceCode/Bond/Servo/CBonder.cpp           |    2 
 SourceCode/Bond/Servo/CRecipeList.h         |   27 +++
 SourceCode/Bond/Servo/CRecipesManager.h     |   42 ++++++
 SourceCode/Bond/Servo/Common.h              |   18 ++
 11 files changed, 389 insertions(+), 4 deletions(-)

diff --git a/SourceCode/Bond/Servo/CBonder.cpp b/SourceCode/Bond/Servo/CBonder.cpp
index 5276f30..1652925 100644
--- a/SourceCode/Bond/Servo/CBonder.cpp
+++ b/SourceCode/Bond/Servo/CBonder.cpp
@@ -188,7 +188,9 @@
 				[&](int code, const char* pszData, size_t size) -> int {
 					if (code == ROK && pszData != nullptr && size > 0) {
 						// 此处解释配方数据
+						return decodeRecipeListReport(pszData, size);
 					}
+					return -1;
 				});
 			pStep->setName(STEP_EQ_MASTER_RECIPE_LIST);
 			pStep->setWriteSignalDev(m_nIndex == 0 ? 0x34b : 0x64b);
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index aaf7662..054457f 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -887,11 +887,15 @@
 		}
 
 		LOGI("<CEquipment-%s>正在请求单元<%d>主配方列表", m_strName.c_str(), unitNo);
-		pStep->writeShort(unitNo, [&](int code) -> int {
+		if (m_recipesManager.syncing() != 0) {
+			return -2;
+		}
+		pStep->writeShort(unitNo, [&, unitNo](int code) -> int {
 			if (code == WOK) {
 				LOGI("<CEquipment-%s>请求单元<%d>主配方列表成功,正在等待数据.", m_strName.c_str(), unitNo);
 			}
 			else {
+				//m_recipesManager.syncFailed();
 				LOGI("<CEquipment-%s>请求单元<%d>主配方列表失败,code:%d", m_strName.c_str(), unitNo, code);
 			}
 
@@ -899,4 +903,9 @@
 		});
 		return 0;
 	}
+
+	int CEquipment::decodeRecipeListReport(const char* pszData, size_t size)
+	{
+		return m_recipesManager.decodeRecipeListReport(pszData, size);
+	}
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index e16140a..1e6d326 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -26,6 +26,7 @@
 #include <map>
 #include <list>
 #include "CGlass.h"
+#include "CRecipesManager.h"
 
 
 namespace SERVO {
@@ -149,6 +150,7 @@
 		BOOL isBitOn(const char* pszData, size_t size, int index);
 		inline BOOL equalBool(BOOL b1, BOOL b2);
 		void addGlassToList(CGlass* pGlass);
+		int decodeRecipeListReport(const char* pszData, size_t size);
 
 	protected:
 		EquipmentListener m_listener;
@@ -178,6 +180,7 @@
 		CCCLinkIEControl* m_pCclink;
 		std::map<unsigned int, CStep*> m_mapStep;
 		int m_nBaseAlarmId;
+		CRecipesManager m_recipesManager;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CPageGraph2.cpp b/SourceCode/Bond/Servo/CPageGraph2.cpp
index 4d81345..7ead0b6 100644
--- a/SourceCode/Bond/Servo/CPageGraph2.cpp
+++ b/SourceCode/Bond/Servo/CPageGraph2.cpp
@@ -176,8 +176,10 @@
 				}
 			}
 			*/
+
+
 			// 娴嬭瘯娓呴櫎Cim Message
-			
+			/*
 			if (pEquipment->getID() == EQ_ID_Bonder1
 				|| pEquipment->getID() == EQ_ID_Bonder2) {
 				static int msgId = 0; msgId++;
@@ -188,7 +190,7 @@
 					pEquipment->clearCimMessage(msgId, 2);
 				}
 			}
-			
+			*/
 
 			// 娴嬭瘯璁剧疆鏃堕棿
 			/*
@@ -221,8 +223,8 @@
 				pEquipment->setEqMode((ii % 5) + 1);
 			}
 			*/
+
 			/*
-			SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)pItem->pData;
 			SERVO::CGlass* pGlass = pEquipment->getFrontGlass();
 			if (pGlass != nullptr) {
 				std::string strDescription;
@@ -234,6 +236,12 @@
 				}
 			}
 			*/
+
+
+			// 璇锋眰涓婚厤鏂瑰垪琛�
+			if (pEquipment != nullptr) {
+				pEquipment->masterRecipeListRequest(0);
+			}			
 		}
 
 
diff --git a/SourceCode/Bond/Servo/CRecipeList.cpp b/SourceCode/Bond/Servo/CRecipeList.cpp
new file mode 100644
index 0000000..4d8e7d0
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipeList.cpp
@@ -0,0 +1,81 @@
+#include "stdafx.h"
+#include "CRecipeList.h"
+#include "Common.h"
+#include "ToolUnits.h"
+
+
+namespace SERVO {
+	CRecipeList::CRecipeList()
+	{
+		m_nToatlGroupCount = 0;
+		m_nCurrentGroupCount = 0;
+	}
+
+	CRecipeList::CRecipeList(int unitNo)
+	{
+		m_nUnitNo = unitNo;
+	}
+
+	CRecipeList::~CRecipeList()
+	{
+
+	}
+
+	int CRecipeList::getUnitNo()
+	{
+		return m_nUnitNo;
+	}
+
+	int CRecipeList::addRecipePacket(int totalGroup, int currentGroup, const char* pszData, size_t size)
+	{
+		if (m_nToatlGroupCount == 0) m_nToatlGroupCount = totalGroup;
+		if (m_nToatlGroupCount != totalGroup) {
+			reset();
+			return MRLRC_GROUP_COUNT_NG;
+		}
+		if (m_nCurrentGroupCount + 1 > currentGroup) {
+			return MRLRC_DUPLICATION_GROUP_COUNT_NG;
+		}
+		if (m_nCurrentGroupCount + 1 < currentGroup) {
+			return ORDER_BY_GROUP_COUNT_NG;
+		}
+		m_nCurrentGroupCount++;
+		
+		for (int i = 0; i < size; i += 4) {
+			int index = CToolUnits::toInt16(&pszData[i]);
+			short id = CToolUnits::toInt16(&pszData[i + 2]);
+			addRecipe(index, id);
+		}
+
+		if (m_nCurrentGroupCount == m_nToatlGroupCount) {
+			return MRLRC_CURRENT_RECIPE_COMPLETE;
+		}
+
+
+		return MRLRC_CONTINUE;
+	}
+
+	int CRecipeList::addRecipe(int index, short id)
+	{
+		for (auto item : m_ids) {
+			if (item.second == id) {
+				return -1;
+			}
+		}
+
+		m_ids[index] = id;
+		return 0;
+	}
+
+	std::map<int, short>& CRecipeList::getIds()
+	{
+		return m_ids;
+	}
+
+	void CRecipeList::reset()
+	{
+		m_nToatlGroupCount = 0;
+		m_nCurrentGroupCount = 0;
+		m_ids.clear();
+	}
+}
diff --git a/SourceCode/Bond/Servo/CRecipeList.h b/SourceCode/Bond/Servo/CRecipeList.h
new file mode 100644
index 0000000..7cb4577
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipeList.h
@@ -0,0 +1,27 @@
+#pragma once
+#include <map>
+
+
+namespace SERVO {
+	class CRecipeList
+	{
+	public:
+		CRecipeList();
+		CRecipeList(int unitNo);
+		virtual ~CRecipeList();
+
+	public:
+		int getUnitNo();
+		int addRecipePacket(int totalGroup, int currentGroup, const char* pszData, size_t size);
+		int addRecipe(int index, short id);
+		std::map<int, short>& getIds();
+		void reset();
+
+	private:
+		int m_nUnitNo;
+		int m_nToatlGroupCount;
+		int m_nCurrentGroupCount;
+		std::map<int, short> m_ids;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CRecipesManager.cpp b/SourceCode/Bond/Servo/CRecipesManager.cpp
new file mode 100644
index 0000000..34bac63
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipesManager.cpp
@@ -0,0 +1,187 @@
+#include "stdafx.h"
+#include "CRecipesManager.h"
+#include "ToolUnits.h"
+#include "Common.h"
+
+
+namespace SERVO {
+	unsigned __stdcall TimeoutCheckWorkThreadFunction(LPVOID lpParam)
+	{
+		CRecipesManager* pRecipesManager = (CRecipesManager*)lpParam;
+		return pRecipesManager->TimeoutCheckWorkingProc();
+	}
+
+	CRecipesManager::CRecipesManager()
+	{
+		m_nSyncStatus = SS_NONE;
+		m_nTotalMasterRecipeCount = 0;
+		m_nWordThreadAddr = 0;
+		m_hWorkStop = nullptr;
+		m_hWorkThreadHandle = nullptr;
+		m_nTimeoutCount = 0;
+		::InitializeCriticalSection(&m_cs);
+	}
+
+	CRecipesManager::~CRecipesManager()
+	{
+		// 等待超时检测线程退出
+		if (m_hWorkStop != nullptr) {
+			SetEvent(m_hWorkStop);
+			if (m_hWorkThreadHandle != NULL) {
+				WaitForSingleObject(m_hWorkThreadHandle, INFINITE);
+				CloseHandle(m_hWorkThreadHandle);
+				m_hWorkThreadHandle = NULL;
+			}
+			CloseHandle(m_hWorkStop);
+			m_hWorkStop = NULL;
+		}
+
+
+		// 清理数据
+		lock();
+		for (auto item : m_mapRecipes) {
+			delete item.second;
+		}
+		for (auto item : m_mapRecipesTemp) {
+			delete item.second;
+		}
+		unlock();
+		::DeleteCriticalSection(&m_cs);
+	}
+
+	int CRecipesManager::syncing()
+	{
+		lock();
+		if (m_nSyncStatus == SS_SYNCING) {
+			unlock();
+			return -1;
+		}
+
+		m_nSyncStatus = SS_SYNCING;
+		m_nTimeoutCount = 0;
+		unlock();
+
+
+		if (m_hWorkStop == nullptr) {
+			m_hWorkStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+			m_hWorkThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::TimeoutCheckWorkThreadFunction, this,
+				0, &m_nWordThreadAddr);
+		}
+
+		return 0;
+	}
+
+	void CRecipesManager::syncFailed()
+	{
+		lock();
+		m_nSyncStatus = SS_FAILED;
+		m_nTimeoutCount = 0;
+		unlock();
+	}
+
+	int CRecipesManager::decodeRecipeListReport(const char* pszData, size_t size)
+	{
+		int index = 0;
+		int unitNo, reportType, totalMasterRecipeCount;
+		int toatlGroupCount, currentGroupCount;
+		const char* pszIdsData;
+
+		unitNo = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		pszIdsData = &pszData[index];
+		index += (250 * 2);
+
+		reportType = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		totalMasterRecipeCount = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		toatlGroupCount = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+		lock();
+		if (m_nTotalMasterRecipeCount == 0) m_nTotalMasterRecipeCount = toatlGroupCount;
+		if (m_nTotalMasterRecipeCount != toatlGroupCount) {
+			return MRLRC_MASTER_RECIPE_LIST_COUNT_NG;
+		}
+		m_nTimeoutCount = 0;
+		unlock();
+
+		currentGroupCount = CToolUnits::toInt16(&pszData[index]);
+		index += 2;
+
+
+		// 找到对应CRecipeList, 找不到则新建
+		lock();
+		CRecipeList* pRecipeList = getRecipeListFromTemp(unitNo);
+		if (pRecipeList == nullptr) {
+			pRecipeList = new CRecipeList(unitNo);
+			m_mapRecipesTemp[unitNo] = pRecipeList;
+		}
+		unlock();
+		ASSERT(pRecipeList);
+
+
+		// 这里暂时只处理reportType=4,即Request from EAS
+		if (reportType == 4) {
+			int nRet = pRecipeList->addRecipePacket(toatlGroupCount, currentGroupCount, pszIdsData, 250 * 2);
+			if (MRLRC_CURRENT_RECIPE_COMPLETE == nRet) {
+				lock();
+				if (m_nTotalMasterRecipeCount == m_mapRecipesTemp.size()) {
+					for (auto item : m_mapRecipes) {
+						delete item.second;
+					}
+					m_mapRecipes = m_mapRecipesTemp;
+					m_mapRecipesTemp.clear();
+					m_nSyncStatus = SS_COMPLETE;
+					unlock();
+					return MRLRC_OK;
+				}
+				unlock();
+			}
+			else if (MRLRC_CONTINUE == nRet) {
+				return MRLRC_CONTINUE;
+			}
+		}
+
+
+		return MRLRC_OK;
+	}
+
+	CRecipeList* CRecipesManager::getRecipeListFromTemp(int unitNo)
+	{
+		auto iter = m_mapRecipesTemp.find(unitNo);
+		if (iter == m_mapRecipesTemp.end()) return nullptr;
+		return iter->second;
+	}
+
+	unsigned CRecipesManager::TimeoutCheckWorkingProc()
+	{
+		while (1) {
+			int nRet = WaitForSingleObject(m_hWorkStop, 1000);
+			if (nRet == WAIT_OBJECT_0) {
+				ResetEvent(m_hWorkStop);
+				break;
+			}
+
+			lock();
+			if (m_nSyncStatus == SS_SYNCING) {
+				m_nTimeoutCount++;
+				if (m_nTimeoutCount > 10) {
+					m_nSyncStatus = SS_TIMEOUT;
+					unlock();
+					TRACE("CRecipesManager::TimeoutCheckWorkingProc 超时退出\n");
+				}
+			}
+
+			unlock();
+		}
+
+		// _endthreadex(0);
+		TRACE("CRecipesManager::TimeoutCheckWorkingProc 线程退出\n");
+		return 0;
+	}
+
+}
diff --git a/SourceCode/Bond/Servo/CRecipesManager.h b/SourceCode/Bond/Servo/CRecipesManager.h
new file mode 100644
index 0000000..489e2a5
--- /dev/null
+++ b/SourceCode/Bond/Servo/CRecipesManager.h
@@ -0,0 +1,42 @@
+#pragma once
+#include <map>
+#include "CRecipeList.h"
+
+
+#define SS_NONE					0
+#define SS_SYNCING				1
+#define SS_COMPLETE				2
+#define SS_TIMEOUT				3
+#define SS_FAILED				4
+
+namespace SERVO {
+	class CRecipesManager
+	{
+	public:
+		CRecipesManager();
+		virtual ~CRecipesManager();
+
+	public:
+		unsigned TimeoutCheckWorkingProc();
+		int syncing();
+		void syncFailed();
+		int decodeRecipeListReport(const char* pszData, size_t size);
+		CRecipeList* getRecipeListFromTemp(int unitNo);
+
+	public:
+		inline void lock() { ::EnterCriticalSection(&m_cs); };
+		inline void unlock() { ::LeaveCriticalSection(&m_cs); };
+
+	private:
+		HANDLE m_hWorkThreadHandle;
+		unsigned m_nWordThreadAddr;
+		HANDLE m_hWorkStop;
+		int m_nTimeoutCount;
+		CRITICAL_SECTION m_cs;		// 同步锁
+		int m_nSyncStatus;
+		int m_nTotalMasterRecipeCount;
+		std::map<int, CRecipeList*> m_mapRecipes;
+		std::map<int, CRecipeList*> m_mapRecipesTemp;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index c8ae7ab..5314223 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/SourceCode/Bond/Servo/Common.h
@@ -279,3 +279,21 @@
 #define CASSETTE_PROCCESS_COMPLETED		7
 
 
+/*
+	Master Recipe List Return Code Block	Description
+		1	OK : Recipe List Received Result is all ok
+		2	Continue : Equipment still has to send the master recipe list to EAS because EAS is not yet received all master recipe list.
+		3	Master Recipe list Count NG : Total Group Count is same as Current Group Count but it’s different with Total Master Recipe List Count.
+		4	Group Count NG : Total Group Count is different with Current Group Count but it’s same with Total Master Recipe Count.
+		5	Duplication Group Count NG : Current Group Count is duplicate with previous group count.Equipment has to send the next group count to EAS.
+		6	Order by Group Count NG : Group Count is not sent order by next group count to EAS.Group Count has to send by order the next group count
+*/
+#define MRLRC_CURRENT_RECIPE_COMPLETE		0
+#define MRLRC_OK							1
+#define MRLRC_CONTINUE						2
+#define MRLRC_MASTER_RECIPE_LIST_COUNT_NG	3
+#define MRLRC_GROUP_COUNT_NG				4
+#define MRLRC_DUPLICATION_GROUP_COUNT_NG	5
+#define ORDER_BY_GROUP_COUNT_NG				6
+
+
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index bd2f2f6..1f07ff6 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -248,6 +248,8 @@
     <ClInclude Include="CPin.h" />
     <ClInclude Include="CReadStep.h" />
     <ClInclude Include="CEqCurrentRecipeChangeStep.h" />
+    <ClInclude Include="CRecipeList.h" />
+    <ClInclude Include="CRecipesManager.h" />
     <ClInclude Include="CSample.h" />
     <ClInclude Include="CStep.h" />
     <ClInclude Include="CVacuumBake.h" />
@@ -337,6 +339,8 @@
     <ClCompile Include="CPin.cpp" />
     <ClCompile Include="CReadStep.cpp" />
     <ClCompile Include="CEqCurrentRecipeChangeStep.cpp" />
+    <ClCompile Include="CRecipeList.cpp" />
+    <ClCompile Include="CRecipesManager.cpp" />
     <ClCompile Include="CSample.cpp" />
     <ClCompile Include="CStep.cpp" />
     <ClCompile Include="CVacuumBake.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 339a1a7..7e9e760 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -95,6 +95,8 @@
     <ClCompile Include="CEqCurrentRecipeChangeStep.cpp" />
     <ClCompile Include="CEqWriteStep.cpp" />
     <ClCompile Include="CEqReadStep.cpp" />
+    <ClCompile Include="CRecipesManager.cpp" />
+    <ClCompile Include="CRecipeList.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -188,6 +190,8 @@
     <ClInclude Include="CEqCurrentRecipeChangeStep.h" />
     <ClInclude Include="CEqWriteStep.h" />
     <ClInclude Include="CEqReadStep.h" />
+    <ClInclude Include="CRecipesManager.h" />
+    <ClInclude Include="CRecipeList.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />

--
Gitblit v1.9.3