From 1efb832676e8ad27e7a495dba6ffc19479e0c76f Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期四, 04 九月 2025 15:51:33 +0800
Subject: [PATCH] 1.机器配方参数的获取;

---
 SourceCode/Bond/Servo/CVacuumBake.cpp     |   25 +-
 SourceCode/Bond/Servo/RecipeManager.h     |   19 --
 SourceCode/Bond/Servo/CBakeCooling.cpp    |   21 +-
 SourceCode/Bond/Servo/CRecipeList.h       |    9 +
 SourceCode/Bond/Servo/CRecipesManager.h   |    2 
 SourceCode/Bond/Servo/PageRecipe.cpp      |   68 ++++++++-
 Document/EO2860AVA-101工艺参数(1).xlsx        |    0 
 /dev/null                                 |    0 
 SourceCode/Bond/Servo/CMeasurement.cpp    |   15 +
 SourceCode/Bond/Servo/CRecipesManager.cpp |   24 +++
 SourceCode/Bond/Servo/CEquipment.cpp      |   36 +++++
 SourceCode/Bond/Servo/CRecipeList.cpp     |   96 +++++++++++++
 SourceCode/Bond/Servo/PageRecipe.h        |    2 
 SourceCode/Bond/Servo/CEquipment.h        |    5 
 SourceCode/Bond/Servo/CBonder.cpp         |   57 ++++----
 15 files changed, 288 insertions(+), 91 deletions(-)

diff --git "a/Document/EO2860AVA-101\345\267\245\350\211\272\345\217\202\346\225\260\0501\051.xlsx" "b/Document/EO2860AVA-101\345\267\245\350\211\272\345\217\202\346\225\260\0501\051.xlsx"
new file mode 100644
index 0000000..679a879
--- /dev/null
+++ "b/Document/EO2860AVA-101\345\267\245\350\211\272\345\217\202\346\225\260\0501\051.xlsx"
Binary files differ
diff --git "a/Document/\351\205\215\346\226\271\345\217\202\346\225\260.xlsx" "b/Document/\351\205\215\346\226\271\345\217\202\346\225\260.xlsx"
deleted file mode 100644
index d0923fa..0000000
--- "a/Document/\351\205\215\346\226\271\345\217\202\346\225\260.xlsx"
+++ /dev/null
Binary files differ
diff --git a/SourceCode/Bond/Servo/CBakeCooling.cpp b/SourceCode/Bond/Servo/CBakeCooling.cpp
index 6523764..59228f5 100644
--- a/SourceCode/Bond/Servo/CBakeCooling.cpp
+++ b/SourceCode/Bond/Servo/CBakeCooling.cpp
@@ -220,12 +220,13 @@
 			// recipe parameter report
 			CEqReadStep* pStep = new CEqReadStep(0x12a54, 257 * 2,
 				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
+					CEqReadStep* pTmpStep = (CEqReadStep*)pFrom;
 					if (code == ROK && pszData != nullptr && size > 0) {
 						// 此处解释配方数据
 						short ret = decodeRecipeParameterReport(pszData, size);
-						pStep->setReturnCode(ret);
+						pTmpStep->setReturnCode(ret);
 					}
-					pStep->setReturnCode(MRLRC_OK);
+					pTmpStep->setReturnCode(MRLRC_OK);
 					return -1;
 				});
 			pStep->setName(STEP_EQ_RECIPE_PARAMETER);
@@ -423,7 +424,7 @@
 		return pGlass->isProcessed(m_nID, getSlotUnit(slot));
 	}
 
-	int CBakeCooling::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
+	int CBakeCooling::parsingParams(const char* pszData, size_t size, std::vector<CParam>& params)
 	{
 		ASSERT(pszData);
 		if (size < 250) return 0;
@@ -432,36 +433,36 @@
 
 		// 1.A_腔烘烤时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("A_腔烘烤时间", 0, "", v * 0.01f));
+		params.push_back(CParam("A_腔烘烤时间", "", "", v * 0.01f));
 		i += 2;
 
 		// 2.A_腔冷却时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("A_腔冷却时间", 0, "", v * 0.01f));
+		params.push_back(CParam("A_腔冷却时间", "", "", v * 0.01f));
 		i += 2;
 
 		// 3.B_腔烘烤时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("B_腔烘烤时间", 0, "", v * 0.01f));
+		params.push_back(CParam("B_腔烘烤时间", "", "", v * 0.01f));
 		i += 2;
 
 		// 4.BB_腔冷却时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("B_腔冷却时间", 0, "", v * 0.01f));
+		params.push_back(CParam("B_腔冷却时间", "", "", v * 0.01f));
 		i += 2;
 
 		// 5.A_烘烤温度设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("A_烘烤温度设定", 0, "", v * 0.1f));
+		params.push_back(CParam("A_烘烤温度设定", "", "", v * 0.1f));
 		i += 2;
 
 		// 6.B_烘烤温度设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("B_烘烤温度设定", 0, "", v * 0.1f));
+		params.push_back(CParam("B_烘烤温度设定", "", "", v * 0.1f));
 		i += 2;
 
 
-		return (int)parsms.size();
+		return (int)params.size();
 	}
 
 }
diff --git a/SourceCode/Bond/Servo/CBonder.cpp b/SourceCode/Bond/Servo/CBonder.cpp
index 3b49a81..46108dc 100644
--- a/SourceCode/Bond/Servo/CBonder.cpp
+++ b/SourceCode/Bond/Servo/CBonder.cpp
@@ -224,13 +224,14 @@
 		{
 			// recipe parameter report
 			CEqReadStep* pStep = new CEqReadStep(m_nIndex == 0 ? 0xaa54 : 0xea54, 257 * 2,
-				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
+				[&, pStep](void* pFrom, int code, const char* pszData, size_t size) -> int {
+					CEqReadStep* pTmpStep = (CEqReadStep*)pFrom;
+					short ret = MRLRC_OK;
 					if (code == ROK && pszData != nullptr && size > 0) {
 						// 此处解释配方数据
-						short ret = decodeRecipeParameterReport(pszData, size);
-						pStep->setReturnCode(ret);
+						ret = decodeRecipeParameterReport(pszData, size);
 					}
-					pStep->setReturnCode(MRLRC_OK);
+					pTmpStep->setReturnCode(ret);
 					return -1;
 				});
 			pStep->setName(STEP_EQ_RECIPE_PARAMETER);
@@ -523,7 +524,7 @@
 		return m_nIndex == 0 ? 15000 : 20000;
 	}
 
-	int CBonder::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
+	int CBonder::parsingParams(const char* pszData, size_t size, std::vector<CParam>& params)
 	{
 		ASSERT(pszData);
 		if (size < 250) return 0;
@@ -532,113 +533,113 @@
 
 		// 1.校正对位延时
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("校正对位延时", 0, "", v * 0.01f));
+		params.push_back(CParam("校正对位延时", "", "", v * 0.01f));
 		i += 2;
 
 		// 2.保压时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("保压时间", 0, "", v * 0.01f));
+		params.push_back(CParam("保压时间", "", "", v * 0.01f));
 		i += 2;
 
 		// 3.腔体破真空延时
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("腔体破真空延时", 0, "", v * 0.01f));
+		params.push_back(CParam("腔体破真空延时", "", "", v * 0.01f));
 		i += 2;
 
 		// 4.腔体分子泵启动延时
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("腔体分子泵启动延时", 0, "", v * 0.1f));
+		params.push_back(CParam("腔体分子泵启动延时", "", "", v * 0.1f));
 		i += 2;
 
 		// 5.腔体贴附抽真空延时
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("腔体贴附抽真空延时", 0, "", v * 0.1f));
+		params.push_back(CParam("腔体贴附抽真空延时", "", "", v * 0.1f));
 		i += 2;
 
 		// 6.加热等待延时
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("加热等待延时", 0, "", v * 0.1f));
+		params.push_back(CParam("加热等待延时", "", "", v * 0.1f));
 		i += 2;
 
 		// 7.气囊压力设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("气囊压力设定", 0, "", v * 0.1f));
+		params.push_back(CParam("气囊压力设定", "", "", v * 0.001f));
 		i += 4;
 
 		// 8.气囊加压速率
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("气囊加压速率", 0, "", v * 0.1f));
+		params.push_back(CParam("气囊加压速率", "", "", v * 0.001f));
 		i += 4;
 
 		// 9.气囊泄压速率
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("气囊泄压速率", 0, "", v * 0.1f));
+		params.push_back(CParam("气囊泄压速率", "", "", v * 0.001f));
 		i += 4;
 
 		// 10.贴附压力上限
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("贴附压力上限", 0, "", v * 0.1f));
+		params.push_back(CParam("贴附压力上限", "", "", v * 0.1f));
 		i += 4;
 
 		// 11.Z轴转矩速度设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("上腔Z轴转矩速度设定", 0, "", v * 0.001f));
+		params.push_back(CParam("上腔Z轴转矩速度设定", "", "", v * 0.001f));
 		i += 4;
 
 		// 12.上腔温度设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("上腔温度设定", 0, "", v * 0.1f));
+		params.push_back(CParam("上腔温度设定", "", "", v * 0.1f));
 		i += 2;
 
 		// 13.下腔温度设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("下腔温度设定", 0, "", v * 0.1f));
+		params.push_back(CParam("下腔温度设定", "", "", v * 0.1f));
 		i += 2;
 
 		// 14.上腔Z轴预贴合位速度
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("上腔Z轴预贴合位速度", 0, "", v * 0.001f));
+		params.push_back(CParam("上腔Z轴预贴合位速度", "", "", v * 0.001f));
 		i += 4;
 
 		// 15.上腔Z轴贴附位速度
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("上腔Z轴贴附位速度", 0, "", v * 0.001f));
+		params.push_back(CParam("上腔Z轴贴附位速度", "", "", v * 0.001f));
 		i += 4;
 
 		// 16.上腔Z上腔加热位间距
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("上腔Z上腔加热位间距", 0, "", v * 0.001f));
+		params.push_back(CParam("上腔Z上腔加热位间距", "", "", v * 0.001f));
 		i += 4;
 
 		// 17.上腔贴附位压入量
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("上腔贴附位压入量", 0, "", v * 0.001f));
+		params.push_back(CParam("上腔贴附位压入量", "", "", v * 0.001f));
 		i += 4;
 
 		// 18.上腔Z轴破真空距离
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("上腔Z轴破真空距离", 0, "", v * 0.001f));
+		params.push_back(CParam("上腔Z轴破真空距离", "", "", v * 0.001f));
 		i += 4;
 
 		// 19.下顶Pin破真空距离
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("下顶Pin破真空距离", 0, "", v * 0.001f));
+		params.push_back(CParam("下顶Pin破真空距离", "", "", v * 0.001f));
 		i += 4;
 
 		// 20.下顶Pin加热位间距
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("下顶Pin加热位间距", 0, "", v * 0.001f));
+		params.push_back(CParam("下顶Pin加热位间距", "", "", v * 0.001f));
 		i += 4;
 
 		// 21.腔体真空泵真空规设定值
-		parsms.push_back(CParam("腔体真空泵真空规设定值", 0, "", (double)toFloat(&pszData[i])));
+		params.push_back(CParam("腔体真空泵真空规设定值", "", "", (double)toFloat(&pszData[i])));
 		i += 4;
 
 		// 22.腔体分子泵到达设定值
-		parsms.push_back(CParam("腔体分子泵到达设定值", 0, "", (double)toFloat(&pszData[i])));
+		params.push_back(CParam("腔体分子泵到达设定值", "", "", (double)toFloat(&pszData[i])));
 		i += 4;
 
 
-		return (int)parsms.size();
+		return (int)params.size();
 	}
 }
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 30cdedb..c4c19a8 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -496,6 +496,11 @@
 		// 主配方上报
 		CHECK_READ_STEP_SIGNAL(STEP_ID_MASTER_RECIPE_LIST_REPORT, pszData, size);
 
+		// 配方参数
+		CHECK_WRITE_STEP_SIGNAL(STEP_ID_RECIPE_PARAMETER_CMD_REPLY, pszData, size);
+		CHECK_READ_STEP_SIGNAL(STEP_ID_RECIPE_PARAMETER_REPORT, pszData, size);
+		
+
 		// CIM Mode
 		CHECK_WRITE_STEP_SIGNAL(STEP_ID_CIMMODE_CHANGED_CMD_REPLY, pszData, size);
 
@@ -811,6 +816,16 @@
 	CRecipeList* CEquipment::getRecipeList(int unitNo)
 	{
 		return m_recipesManager.getRecipeList(unitNo);
+	}
+
+	bool CEquipment::saveRecipeList(int unitNo, std::string& strFilepath)
+	{
+		return m_recipesManager.saveRecipeList(unitNo, strFilepath);
+	}
+
+	bool CEquipment::readRecipeList(int unitNo, std::string& strFilepath)
+	{
+		return m_recipesManager.readRecipeList(unitNo, strFilepath);
 	}
 
 	int CEquipment::recvIntent(CPin* pPin, CIntent* pIntent)
@@ -2099,4 +2114,25 @@
 
 		return f;
 	}
+
+	int CEquipment::parsingParams(const char* pszData, size_t size, std::string& strOut)
+	{
+		std::vector<CParam> params;
+		int nRet = parsingParams(pszData, size, params);
+		if (nRet <= 0) return nRet;
+
+		char szBuffer[256];
+		for (auto p : params) {
+			if(!strOut.empty()) strOut.append(",");
+			if (p.getValueType() == PVT_INT) {
+				sprintf_s(szBuffer, 256, "%s:%d", p.getName().c_str(), p.getIntValue());
+			}
+			else if (p.getValueType() == PVT_DOUBLE) {
+				sprintf_s(szBuffer, 256, "%s:%f", p.getName().c_str(), p.getDoubleValue());
+			}
+			strOut.append(szBuffer);
+		}
+
+		return 0; 
+	};
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index d7892e4..635c7a8 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -123,6 +123,8 @@
 		std::vector<CPin*>& CEquipment::getInputPins();
 		std::vector<CPin*>& CEquipment::getOutputPins();
 		CRecipeList* getRecipeList(int unitNo);
+		bool saveRecipeList(int unitNo, std::string& strFilepath);
+		bool readRecipeList(int unitNo, std::string& strFilepath);
 		virtual int recvIntent(CPin* pPin, CIntent* pIntent);
 		virtual int fetchedOutJob(int port, CJobDataB* pJobDataB);
 		virtual int storedJob(int port, CJobDataB* pJobDataB, short putSlot);
@@ -169,7 +171,8 @@
 		int recipeParameterRequest(short masterRecipeId, short localRecipeId, short unitNo, ONSYNCINGSTATECHANGED block);
 
 		// 解析配方参数列表
-		virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms) { return 0;  };
+		virtual int parsingParams(const char* pszData, size_t size, std::vector<CParam>& params) { return 0;  };
+		virtual int parsingParams(const char* pszData, size_t size, std::string& strOut);
 
 		// 获取指定的Slot
 		CSlot* getSlot(int index);
diff --git a/SourceCode/Bond/Servo/CMeasurement.cpp b/SourceCode/Bond/Servo/CMeasurement.cpp
index 53ffb9c..207b427 100644
--- a/SourceCode/Bond/Servo/CMeasurement.cpp
+++ b/SourceCode/Bond/Servo/CMeasurement.cpp
@@ -220,12 +220,13 @@
 			// recipe parameter report
 			CEqReadStep* pStep = new CEqReadStep(0x1aa54, 257 * 2,
 				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
+					CEqReadStep* pTmpStep = (CEqReadStep*)pFrom;
 					if (code == ROK && pszData != nullptr && size > 0) {
 						// 此处解释配方数据
 						short ret = decodeRecipeParameterReport(pszData, size);
-						pStep->setReturnCode(ret);
+						pTmpStep->setReturnCode(ret);
 					}
-					pStep->setReturnCode(MRLRC_OK);
+					pTmpStep->setReturnCode(MRLRC_OK);
 					return -1;
 				});
 			pStep->setName(STEP_EQ_RECIPE_PARAMETER);
@@ -417,7 +418,7 @@
 		return 35000;
 	}
 
-	int CMeasurement::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
+	int CMeasurement::parsingParams(const char* pszData, size_t size, std::vector<CParam>& params)
 	{
 		ASSERT(pszData);
 		if (size < 250) return 0;
@@ -426,10 +427,14 @@
 
 		// 1.检测功能启用/禁用
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("检测功能启用/禁用", 0, "", v));
+		params.push_back(CParam("检测功能启用/禁用", "", "", v));
 		i += 2;
 
+		// 2.检测速度
+		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
+		params.push_back(CParam("检测速度", "", "", v * 0.001));
+		i += 4;
 
-		return (int)parsms.size();
+		return (int)params.size();
 	}
 }
diff --git a/SourceCode/Bond/Servo/CRecipeList.cpp b/SourceCode/Bond/Servo/CRecipeList.cpp
index 5f1fbd1..1bbe31c 100644
--- a/SourceCode/Bond/Servo/CRecipeList.cpp
+++ b/SourceCode/Bond/Servo/CRecipeList.cpp
@@ -2,6 +2,7 @@
 #include "CRecipeList.h"
 #include "Common.h"
 #include "ToolUnits.h"
+#include <fstream>
 
 
 namespace SERVO {
@@ -53,6 +54,8 @@
 		}
 
 		if (m_nCurrentGroupCount == m_nToatlGroupCount) {
+			m_nToatlGroupCount = 0;
+			m_nCurrentGroupCount = 0;
 			return MRLRC_CURRENT_RECIPE_COMPLETE;
 		}
 
@@ -90,17 +93,23 @@
 		m_paramsRawData.clear();
 	}
 
+	void CRecipeList::reset2()
+	{
+		m_nToatlGroupCount = 0;
+		m_nCurrentGroupCount = 0;
+	}
+
 	int CRecipeList::addParamsPacket(int totalCount, int totalGroup, int currentGroup,
 		short unitId, short recipeId,
 		const char* pszData, size_t size)
 	{
 		if (m_nToatlGroupCount == 0) m_nToatlGroupCount = totalGroup;
 		if (m_nToatlGroupCount != totalGroup) {
-			reset();
+			reset2();
 			return MRLRC_GROUP_COUNT_NG;
 		}
 		if (currentGroup == 0) {
-			reset();
+			reset2();
 		}
 		if (m_nCurrentGroupCount + 1 > currentGroup) {
 			return MRLRC_DUPLICATION_GROUP_COUNT_NG;
@@ -113,6 +122,8 @@
 		m_paramsRawData[recipeId].insert(m_paramsRawData[recipeId].end(), (uint8_t*)(pszData), (uint8_t*)(pszData) + size);
 		if (m_nCurrentGroupCount == m_nToatlGroupCount) {
 			// 解释数据就交给应用层吧
+			reset2();
+
 			return MRLRC_CURRENT_RECIPE_COMPLETE;
 		}
 
@@ -120,4 +131,85 @@
 		return MRLRC_CONTINUE;
 	}
 
+	// 序列化
+	bool CRecipeList::serialize(const std::string& filename) const
+	{
+		std::ofstream ofs(filename, std::ios::binary);
+		if (!ofs) return false;
+
+		// 写基本成员
+		ofs.write(reinterpret_cast<const char*>(&m_nUnitNo), sizeof(m_nUnitNo));
+		ofs.write(reinterpret_cast<const char*>(&m_nToatlGroupCount), sizeof(m_nToatlGroupCount));
+		ofs.write(reinterpret_cast<const char*>(&m_nCurrentGroupCount), sizeof(m_nCurrentGroupCount));
+
+		// 写 m_ids
+		size_t idsSize = m_ids.size();
+		ofs.write(reinterpret_cast<const char*>(&idsSize), sizeof(idsSize));
+		for (auto& kv : m_ids) {
+			ofs.write(reinterpret_cast<const char*>(&kv.first), sizeof(kv.first));
+			ofs.write(reinterpret_cast<const char*>(&kv.second), sizeof(kv.second));
+		}
+
+		// 写 m_paramsRawData
+		size_t paramsSize = m_paramsRawData.size();
+		ofs.write(reinterpret_cast<const char*>(&paramsSize), sizeof(paramsSize));
+		for (auto& kv : m_paramsRawData) {
+			// 写 key
+			ofs.write(reinterpret_cast<const char*>(&kv.first), sizeof(kv.first));
+
+			// 写 vector 大小
+			size_t vecSize = kv.second.size();
+			ofs.write(reinterpret_cast<const char*>(&vecSize), sizeof(vecSize));
+
+			// 写 vector 内容
+			if (!kv.second.empty()) {
+				ofs.write(reinterpret_cast<const char*>(kv.second.data()), vecSize);
+			}
+		}
+
+		return true;
+	}
+
+	// 反序列化
+	bool CRecipeList::deserialize(const std::string& filename)
+	{
+		std::ifstream ifs(filename, std::ios::binary);
+		if (!ifs) return false;
+
+		reset(); // 清空旧数据
+
+		// 读基本成员
+		ifs.read(reinterpret_cast<char*>(&m_nUnitNo), sizeof(m_nUnitNo));
+		ifs.read(reinterpret_cast<char*>(&m_nToatlGroupCount), sizeof(m_nToatlGroupCount));
+		ifs.read(reinterpret_cast<char*>(&m_nCurrentGroupCount), sizeof(m_nCurrentGroupCount));
+
+		// 读 m_ids
+		size_t idsSize = 0;
+		ifs.read(reinterpret_cast<char*>(&idsSize), sizeof(idsSize));
+		for (size_t i = 0; i < idsSize; ++i) {
+			int key;
+			short value;
+			ifs.read(reinterpret_cast<char*>(&key), sizeof(key));
+			ifs.read(reinterpret_cast<char*>(&value), sizeof(value));
+			m_ids[key] = value;
+		}
+
+		// 读 m_paramsRawData
+		size_t paramsSize = 0;
+		ifs.read(reinterpret_cast<char*>(&paramsSize), sizeof(paramsSize));
+		for (size_t i = 0; i < paramsSize; ++i) {
+			short key;
+			size_t vecSize = 0;
+			ifs.read(reinterpret_cast<char*>(&key), sizeof(key));
+			ifs.read(reinterpret_cast<char*>(&vecSize), sizeof(vecSize));
+
+			std::vector<uint8_t> buffer(vecSize);
+			if (vecSize > 0) {
+				ifs.read(reinterpret_cast<char*>(buffer.data()), vecSize);
+			}
+			m_paramsRawData[key] = std::move(buffer);
+		}
+
+		return true;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CRecipeList.h b/SourceCode/Bond/Servo/CRecipeList.h
index 7038c70..6b1ac0d 100644
--- a/SourceCode/Bond/Servo/CRecipeList.h
+++ b/SourceCode/Bond/Servo/CRecipeList.h
@@ -1,4 +1,4 @@
-#pragma once
+锘�#pragma once
 #include <map>
 
 
@@ -17,12 +17,17 @@
 		std::map<int, short>& getIds();
 		std::unordered_map<short, std::vector<uint8_t>>& getParamsRawData();
 		void reset();
+		void reset2();
 
-		// 添加参数包
+		// 娣诲姞鍙傛暟鍖�
 		int addParamsPacket(int totalCount, int totalGroup, int currentGroup,
 			short unitId, short recipeId,
 			const char* pszData, size_t size);
 
+		// 猸� 鏂板搴忓垪鍖栧拰鍙嶅簭鍒楀寲鍑芥暟
+		bool serialize(const std::string& filename) const;
+		bool deserialize(const std::string& filename);
+
 	private:
 		int m_nUnitNo;
 		int m_nToatlGroupCount;
diff --git a/SourceCode/Bond/Servo/CRecipesManager.cpp b/SourceCode/Bond/Servo/CRecipesManager.cpp
index 48ba9d1..98a17a2 100644
--- a/SourceCode/Bond/Servo/CRecipesManager.cpp
+++ b/SourceCode/Bond/Servo/CRecipesManager.cpp
@@ -232,7 +232,7 @@
 
 		// 找到对应CRecipeList, 找不到则返回NG
 		lock();
-		CRecipeList* pRecipeList = getRecipeListFromTemp(unitNo);
+		CRecipeList* pRecipeList = getRecipeList(unitNo);
 		if (pRecipeList == nullptr) {
 			unlock();
 			return MRLRC_NG;
@@ -262,6 +262,11 @@
 				lock();
 				m_nSyncStatus = SS_PARAMS_COMPLETE;
 				unlock();
+
+				if (m_onSyncingStateChanged != nullptr) {
+					m_onSyncingStateChanged(m_nSyncStatus);
+				}
+
 				return MRLRC_OK;
 			}
 
@@ -286,6 +291,23 @@
 		return iter->second;
 	}
 
+	bool CRecipesManager::saveRecipeList(int unitNo, std::string& strFilepath)
+	{
+		CRecipeList* pRecipeList = getRecipeList(unitNo);
+		if (pRecipeList == nullptr) return false;
+		return pRecipeList->serialize(strFilepath);
+	}
+
+	bool CRecipesManager::readRecipeList(int unitNo, std::string& strFilepath)
+	{
+		CRecipeList* pRecipeList = getRecipeList(unitNo);
+		if (pRecipeList == nullptr) {
+			pRecipeList = new CRecipeList();
+			m_mapRecipes[unitNo] = pRecipeList;
+		}
+		return pRecipeList->deserialize(strFilepath);
+	}
+
 	void CRecipesManager::setOnSyncingStateChanged(ONSYNCINGSTATECHANGED block)
 	{
 		m_onSyncingStateChanged = block;
diff --git a/SourceCode/Bond/Servo/CRecipesManager.h b/SourceCode/Bond/Servo/CRecipesManager.h
index 450d2dd..e61df75 100644
--- a/SourceCode/Bond/Servo/CRecipesManager.h
+++ b/SourceCode/Bond/Servo/CRecipesManager.h
@@ -30,6 +30,8 @@
 		short decodeRecipeParameterReport(const char* pszData, size_t size);
 		CRecipeList* getRecipeListFromTemp(int unitNo);
 		CRecipeList* getRecipeList(int unitNo);
+		bool saveRecipeList(int unitNo, std::string& strFilepath);
+		bool readRecipeList(int unitNo, std::string& strFilepath);
 
 	public:
 		inline void lock() { ::EnterCriticalSection(&m_cs); };
diff --git a/SourceCode/Bond/Servo/CVacuumBake.cpp b/SourceCode/Bond/Servo/CVacuumBake.cpp
index e409204..c14c201 100644
--- a/SourceCode/Bond/Servo/CVacuumBake.cpp
+++ b/SourceCode/Bond/Servo/CVacuumBake.cpp
@@ -220,12 +220,13 @@
 			// recipe parameter report
 			CEqReadStep* pStep = new CEqReadStep(0x16a54, 257 * 2,
 				[&](void* pFrom, int code, const char* pszData, size_t size) -> int {
+					CEqReadStep* pTmpStep = (CEqReadStep*)pFrom;
 					if (code == ROK && pszData != nullptr && size > 0) {
 						// 此处解释配方数据
 						short ret = decodeRecipeParameterReport(pszData, size);
-						pStep->setReturnCode(ret);
+						pTmpStep->setReturnCode(ret);
 					}
-					pStep->setReturnCode(MRLRC_OK);
+					pTmpStep->setReturnCode(MRLRC_OK);
 					return -1;
 				});
 			pStep->setName(STEP_EQ_RECIPE_PARAMETER);
@@ -410,7 +411,7 @@
 		return 30000;
 	}
 
-	int CVacuumBake::parsingParams(const char* pszData, size_t size, std::vector<CParam>& parsms)
+	int CVacuumBake::parsingParams(const char* pszData, size_t size, std::vector<CParam>& params)
 	{
 		ASSERT(pszData);
 		if (size < 250) return 0;
@@ -419,43 +420,43 @@
 
 		// 1.A_腔加热时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("A_腔加热时间", 0, "", v * 0.1f));
+		params.push_back(CParam("A_腔加热时间", "", "", v * 0.1f));
 		i += 2;
 
 		// 2.B_腔加热时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("B_腔加热时间", 0, "", v * 0.1f));
+		params.push_back(CParam("B_腔加热时间", "", "", v * 0.1f));
 		i += 2;
 
 		// 3.A_腔破真空时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("A_腔破真空时间", 0, "", v * 0.01f));
+		params.push_back(CParam("A_腔破真空时间", "", "", v * 0.01f));
 		i += 2;
 
 		// 4.B_腔破真空时间
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8;
-		parsms.push_back(CParam("B_腔破真空时间", 0, "", v * 0.01f));
+		params.push_back(CParam("B_腔破真空时间", "", "", v * 0.01f));
 		i += 2;
 
 		// 5.A_腔真空到达值
-		parsms.push_back(CParam("A_腔真空到达值", 0, "", (double)toFloat(&pszData[i])));
+		params.push_back(CParam("A_腔真空到达值", "", "", (double)toFloat(&pszData[i])));
 		i += 4;
 
 		// 6.B_腔真空到达值
-		parsms.push_back(CParam("B_腔真空到达值", 0, "", (double)toFloat(&pszData[i])));
+		params.push_back(CParam("B_腔真空到达值", "", "", (double)toFloat(&pszData[i])));
 		i += 4;
 
 		// 7.A_腔温控表主控温度设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("A_腔温控表主控温度设定", 0, "", v * 0.1f));
+		params.push_back(CParam("A_腔温控表主控温度设定", "", "", v * 0.1f));
 		i += 4;
 
 		// 8.B_腔温控表主控温度设定
 		v = (pszData[i] & 0xff) | (pszData[i + 1] & 0xff) << 8 | (pszData[i + 2] & 0xff) << 16 | (pszData[i + 3] & 0xff) << 24;
-		parsms.push_back(CParam("B_腔温控表主控温度设定", 0, "", v * 0.1f));
+		params.push_back(CParam("B_腔温控表主控温度设定", "", "", v * 0.1f));
 		i += 4;
 
 
-		return (int)parsms.size();
+		return (int)params.size();
 	}
 }
diff --git a/SourceCode/Bond/Servo/PageRecipe.cpp b/SourceCode/Bond/Servo/PageRecipe.cpp
index 3cadbe0..891f274 100644
--- a/SourceCode/Bond/Servo/PageRecipe.cpp
+++ b/SourceCode/Bond/Servo/PageRecipe.cpp
@@ -160,8 +160,9 @@
 	m_listPPID.SetColumnWidth(nColCount - 1, LVSCW_AUTOSIZE_USEHEADER);
 }
 
-void CPageRecipe::FillRecipeListToListCtrl(SERVO::CRecipeList* pList)
+void CPageRecipe::FillRecipeListToListCtrl(SERVO::CEquipment* pEq)
 {
+	SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
 	CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID);
 	if (pListCtrl == nullptr || !::IsWindow(pListCtrl->m_hWnd)) {
 		return;
@@ -169,16 +170,23 @@
 
 	// 娓呯┖褰撳墠CListCtrl涓殑鎵�鏈夐」
 	pListCtrl->DeleteAllItems();
-	if (pList == nullptr) {
+	if (pRecipeList == nullptr) {
 		return;
 	}
 
 	// 閬嶅巻鏁版嵁骞舵彃鍏ュ埌CListCtrl涓�
-	std::map<int, short>& ids = pList->getIds();
+	std::map<int, short>& ids = pRecipeList->getIds();
+	auto rawDatas = pRecipeList->getParamsRawData();
 	for (auto item : ids) {
 		int index = m_listPPID.InsertItem(m_listPPID.GetItemCount(), _T(""));
 		m_listPPID.SetItemText(index, 1, std::to_string(item.first).c_str());
 		m_listPPID.SetItemText(index, 2, std::to_string(item.second).c_str());
+
+		auto iter = rawDatas.find(item.second);
+		if (iter != rawDatas.end()) {
+			std::string strDescription;
+			pEq->parsingParams((const char*)iter->second.data(), iter->second.size(), strDescription);
+		}
 	}
 
 	// 鑾峰彇鍒楁暟
@@ -338,8 +346,12 @@
 					pEq[i] == nullptr ? _T("Master") : pEq[i]->getName().c_str());
 				pComboBox->SetItemDataPtr(i, pEq[i]);
 
+				// 璇诲彇鍥炴潵
+				char szBuffer[_MAX_PATH];
 				if (pEq[i]) {
-					pEq[i]->masterRecipeListRequest(0, nullptr);
+					sprintf_s(szBuffer, _MAX_PATH, "%s\\Recipe\\EQ%d_Unit0.recipelist", (LPTSTR)(LPCTSTR)theApp.m_strAppDir, pEq[i]->getID());
+					std::string strFilepath(szBuffer);
+					pEq[i]->readRecipeList(0, strFilepath);
 				}
 			}
 			pComboBox->SetCurSel(0);
@@ -531,8 +543,7 @@
 	}
 	else {
 		InitListCtrlHeaderForDevice();
-		SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
-		FillRecipeListToListCtrl(pRecipeList);
+		FillRecipeListToListCtrl(pEq);
 	}
 }
 
@@ -548,6 +559,12 @@
 	SERVO::CEquipment* pEq = (SERVO::CEquipment*)pMsgDlg->GetDataEx();
 	HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
 	int nStep = 0;
+
+	// 鍑嗗閰嶆柟璺緞
+	char szBuffer[_MAX_PATH];
+	sprintf_s(szBuffer, _MAX_PATH, "%s\\Recipe\\EQ%d_Unit0.recipelist", (LPTSTR)(LPCTSTR)theApp.m_strAppDir, pEq->getID());
+	std::string strFilepath(szBuffer);
+
 	pEq->masterRecipeListRequest(0, [&, pEq, pMsgDlg, hEvent](int status) -> void {
 		Sleep(300);
 		if (status == SS_FAILED || status == SS_TIMEOUT) {
@@ -572,6 +589,7 @@
 	});
 	::WaitForSingleObject(hEvent, INFINITE);
 	if (nStep != 1) {
+		pEq->saveRecipeList(0, strFilepath);
 		pMsgDlg->SetIcon(MSG_BOX_SUCCEED);
 		pMsgDlg->SetMarquee(FALSE, 0);
 		pMsgDlg->SetCompleteCode(-1);
@@ -587,17 +605,18 @@
 		auto& ids = pRecipeList->getIds();
 		pMsgDlg->SetTitle(_T("姝e湪鑾峰彇鍙傛暟"));
 		for (auto item : ids) {
+			int recipeId = item.second;
 			CString strMsg;
 			strMsg.Format(_T("姝e湪鑾峰彇閰嶆柟 %d 鍙傛暟..."), item.second);
 			pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
-			pEq->recipeParameterRequest(0, item.second, 0, [&, pEq, pMsgDlg](int status) -> void {
+			pEq->recipeParameterRequest(0, recipeId, 0, [&, pEq, pMsgDlg, recipeId, hEvent](int status) -> void {
 				Sleep(500);
 				if (status == SS_FAILED || status == SS_TIMEOUT) {
 					CString strMsg;
-					strMsg.Format(status == SS_FAILED ? _T("鑾峰彇閰嶆柟 %d 鍙傛暟澶辫触锛�") : _T("鑾峰彇閰嶆柟 %d 鍙傛暟瓒呮椂锛�"), item.second);
+					strMsg.Format(status == SS_FAILED ? _T("鑾峰彇閰嶆柟 %d 鍙傛暟澶辫触锛�") : _T("鑾峰彇閰嶆柟 %d 鍙傛暟瓒呮椂锛�"), recipeId);
 					pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
 
-					Sleep(300);
+					Sleep(30);
 					SetEvent(hEvent);
 				}
 				else if (status == SS_PARAMS_COMPLETE) {
@@ -605,7 +624,7 @@
 					strMsg.Format(_T("鑾峰彇閰嶆柟 %d 鍙傛暟瀹屾垚锛�"), item.second);
 					pMsgDlg->SetMessage((LPTSTR)(LPCTSTR)strMsg);
 
-					Sleep(300);
+					Sleep(30);
 					SetEvent(hEvent);
 				}
 				});
@@ -613,6 +632,8 @@
 			ResetEvent(hEvent);
 		}
 		
+		
+		pEq->saveRecipeList(0, strFilepath);
 		pMsgDlg->SetIcon(MSG_BOX_SUCCEED);
 		pMsgDlg->SetTitle(_T("鎿嶄綔瀹屾垚"));
 		pMsgDlg->SetCompleteCode(0);
@@ -620,10 +641,33 @@
 		pMsgDlg->DelayClose(3000);
 	};
 
-	SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
-	FillRecipeListToListCtrl(pRecipeList);
+	FillRecipeListToListCtrl(pEq);
 	CloseHandle(hEvent);
 
 
+
+	// 鍦ㄦ鎵撳嵃閰嶆柟鍙傛暟浠ヤ究鏍稿鏁版嵁
+	SERVO::CRecipeList* pRecipeList = pEq->getRecipeList(0);
+	ASSERT(pRecipeList);
+	auto rawDatas = pRecipeList->getParamsRawData();
+	for (auto item : rawDatas) {
+		TRACE("================= 閰嶆柟 %d\n", item.first);
+
+		std::vector<CParam> params;
+		pEq->parsingParams((const char*)item.second.data(), item.second.size(), params);
+		for (auto p : params) {
+			if (p.getValueType() == PVT_INT) {
+				TRACE("%s: %d\n", p.getName().c_str(), p.getIntValue());
+			}
+			else if (p.getValueType() == PVT_DOUBLE) {
+				TRACE("%s: %f\n", p.getName().c_str(), p.getDoubleValue());
+			}
+		}
+
+	}
+
+
+
+
 	return 0;
 }
diff --git a/SourceCode/Bond/Servo/PageRecipe.h b/SourceCode/Bond/Servo/PageRecipe.h
index 842082e..352daed 100644
--- a/SourceCode/Bond/Servo/PageRecipe.h
+++ b/SourceCode/Bond/Servo/PageRecipe.h
@@ -24,7 +24,7 @@
 	void InitListCtrlHeaderForDevice();
 	void UpdateRecipeByPPID(const CString& strPPID);
 	void FillDataToListCtrl(const std::vector<RecipeInfo>& vecRecipe);
-	void FillRecipeListToListCtrl(SERVO::CRecipeList* pList);
+	void FillRecipeListToListCtrl(SERVO::CEquipment* pEq);
 
 // 瀵硅瘽妗嗘暟鎹�
 #ifdef AFX_DESIGN_TIME
diff --git a/SourceCode/Bond/Servo/RecipeManager.h b/SourceCode/Bond/Servo/RecipeManager.h
index 41d8f02..c588bb3 100644
--- a/SourceCode/Bond/Servo/RecipeManager.h
+++ b/SourceCode/Bond/Servo/RecipeManager.h
@@ -15,6 +15,8 @@
     int nRecipeID;               // 子配方ID
 	std::string strRecipeName;   // 子配方名称
     std::string strDeviceName;   // 设备名称 
+    std::vector<uint8_t> paramsRawData;     // 配方原始数据
+    std::vector<CParam*> m_params;			// 出站时记录参数
 };
 
 // 配方信息
@@ -23,23 +25,6 @@
     std::string strDescription;  // 配方描述
     std::string strCreateTime;   // 创建时间
     std::vector<DeviceRecipe> vecDeviceList;  // 关联的设备信息列表
-    std::vector<CParam*> m_params;			// 出站时记录参数
-    void RecipeInfo::addIntParam(const char* pszName, const char* pszId, const char* pszUnit, int value)
-    {
-        CParam* pParam = new CParam(pszName, pszId, pszUnit, value);
-        m_params.push_back(pParam);
-    }
-
-    void RecipeInfo::addDoubleParam(const char* pszName, const char* pszId, const char* pszUnit, double value)
-    {
-        CParam* pParam = new CParam(pszName, pszId, pszUnit, value);
-        m_params.push_back(pParam);
-    }
-
-    std::vector<CParam*>& RecipeInfo::getParams()
-    {
-        return m_params;
-    }
 };
 
 using RecipeMap = std::unordered_map<std::string, RecipeInfo>; // 按 PPID 映射的配方表

--
Gitblit v1.9.3