From 90c8673e4edaf2e68931470b4d480e02d4634fd0 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期六, 21 六月 2025 13:53:29 +0800
Subject: [PATCH] 1. 动态生成设备配方绑定界面的控件 2. 完善本地测试界面
---
SourceCode/Bond/Servo/PortConfigurationDlg.cpp | 145 +++++++++++++++++++++++++---
SourceCode/Bond/Servo/RecipeManager.cpp | 19 +++
SourceCode/Bond/Servo/resource.h | 0
SourceCode/Bond/Servo/RecipeDeviceBindDlg.h | 11 ++
SourceCode/Bond/Servo/CLoadPort.h | 1
SourceCode/Bond/Servo/RecipeManager.h | 3
SourceCode/Bond/Servo/Servo.rc | 0
SourceCode/Bond/Servo/CLoadPort.cpp | 40 ++++++++
SourceCode/Bond/Servo/PortConfigurationDlg.h | 9 +
SourceCode/Bond/Servo/ServoCommo.h | 19 +++
SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp | 39 +++++++
11 files changed, 265 insertions(+), 21 deletions(-)
diff --git a/SourceCode/Bond/Servo/CLoadPort.cpp b/SourceCode/Bond/Servo/CLoadPort.cpp
index 0ba62ba..5ac81cb 100644
--- a/SourceCode/Bond/Servo/CLoadPort.cpp
+++ b/SourceCode/Bond/Servo/CLoadPort.cpp
@@ -1140,4 +1140,44 @@
return 0;
}
+ int CLoadPort::testGenerateGlassListFromConfig(const SERVO::PortConfig& config)
+ {
+ char szBuffer[64];
+ for (const auto& slot : config.vecSlot) {
+ if (!slot.isEnabled) continue;
+
+ int nSlotIndex = slot.nSlotID - 1;
+ if (nSlotIndex < 0 || nSlotIndex >= SLOT_MAX) {
+ continue;
+ }
+
+ m_slot[nSlotIndex].enable();
+
+ if (!m_slot[nSlotIndex].isEnable()) continue;
+
+ CJobDataS js;
+ js.setCassetteSequenceNo(getNextCassetteSequenceNo());
+ js.setJobSequenceNo(m_slot[nSlotIndex].getNo());
+
+ sprintf_s(szBuffer, 64, "%05d%05d", js.getCassetteSequenceNo(), js.getJobSequenceNo());
+ js.setJobType(1);
+ js.setMaterialsType(config.nMaterialType);
+
+ js.setLotId(config.strLotID.c_str());
+ js.setProductId(config.strProductID.c_str());
+ js.setOperationId(config.strOperationID.c_str());
+ js.setGlass1Id(szBuffer);
+
+ CGlass* pGlass = theApp.m_model.m_glassPool.allocaGlass();
+ pGlass->addPath(m_nID, 0);
+ pGlass->processEnd(m_nID, 0);
+ pGlass->setID(szBuffer);
+ pGlass->setType(static_cast<SERVO::MaterialsType>(config.nMaterialType));
+ pGlass->setJobDataS(&js);
+
+ m_slot[nSlotIndex].setContext(pGlass);
+ }
+
+ return 0;
+ }
}
diff --git a/SourceCode/Bond/Servo/CLoadPort.h b/SourceCode/Bond/Servo/CLoadPort.h
index 0910af3..bc91232 100644
--- a/SourceCode/Bond/Servo/CLoadPort.h
+++ b/SourceCode/Bond/Servo/CLoadPort.h
@@ -56,6 +56,7 @@
int getCassetteMappingState();
int getCassetteStatus();
int testGenerateGlassList(MaterialsType type);
+ int testGenerateGlassListFromConfig(const SERVO::PortConfig& config);
public:
static std::string& getPortTypeDescription(PortType portType, std::string& strDescription);
diff --git a/SourceCode/Bond/Servo/PortConfigurationDlg.cpp b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
index 79a1e11..895648a 100644
--- a/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
+++ b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
@@ -8,6 +8,8 @@
#include "NewCellTypes/GridCellCheck.h"
#include "NewCellTypes/GridCellCombo.h"
#include "NewCellTypes/GridCellNumeric.h"
+#include "RecipeManager.h"
+#include "ServoCommo.h"
// CPortConfigurationDlg 瀵硅瘽妗�
@@ -24,13 +26,22 @@
{
}
+int CPortConfigurationDlg::GetLoadPortEqID(const std::string& strPortName)
+{
+ if (strPortName == "Port 1") return EQ_ID_LOADPORT1;
+ if (strPortName == "Port 2") return EQ_ID_LOADPORT2;
+ if (strPortName == "Port 3") return EQ_ID_LOADPORT3;
+ if (strPortName == "Port 4") return EQ_ID_LOADPORT4;
+ return -1; // 鏈煡绔彛
+}
+
void CPortConfigurationDlg::InitGrid()
{
if (m_wndGrid.GetSafeHwnd() == NULL) {
return;
}
- const int nCols = 3;
+ const int nCols = 2;
const int nFixRows = 1;
const int nRows = 9;
@@ -53,8 +64,6 @@
// 璁剧疆鍒楀
m_wndGrid.SetColumnWidth(nColIdx, 50);
m_wndGrid.SetItemText(0, nColIdx++, _T("Slot ID"));
- m_wndGrid.SetColumnWidth(nColIdx, 150);
- m_wndGrid.SetItemText(0, nColIdx++, _T("EQ Recipe"));
m_wndGrid.SetColumnWidth(nColIdx, 150);
m_wndGrid.SetItemText(0, nColIdx++, _T("Panel ID"));
m_wndGrid.SetColumnWidth(nColIdx, 60);
@@ -98,20 +107,9 @@
m_wndGrid.SetItemText(i, 0, strIndex);
m_wndGrid.SetItemState(i, 0, GVIS_READONLY);
- // EQ Recipe - ComboBox
- //if (m_wndGrid.SetCellType(i, 1, RUNTIME_CLASS(CGridCellCombo))) {
- // CGridCellCombo* pCell = static_cast<CGridCellCombo*>(m_wndGrid.GetCell(i, 1));
- // pCell->SetOptions(recipeOptions);
- // pCell->SetStyle(CBS_DROPDOWNLIST);
- //}
- //m_wndGrid.SetItemText(i, 1, recipeOptions[0]);
-
- // Panel ID - 鍙紪杈�
- m_wndGrid.SetItemText(i, 1, _T(""));
-
// Checkbox
- m_wndGrid.SetCellType(i, 2, RUNTIME_CLASS(CGridCellCheck));
- CGridCellCheck* pCheck = static_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 2));
+ m_wndGrid.SetCellType(i, 1, RUNTIME_CLASS(CGridCellCheck));
+ CGridCellCheck* pCheck = static_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 1));
if (pCheck) {
pCheck->SetCheck(FALSE);
}
@@ -123,12 +121,16 @@
void CPortConfigurationDlg::DoDataExchange(CDataExchange* pDX)
{
+ CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_GRID_PANEL_RECIPE, m_wndGrid);
- CDialogEx::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_COMBO_PORT, m_comboPort);
+ DDX_Control(pDX, IDC_COMBO_RECIPE, m_comboRecipe);
+ DDX_Control(pDX, IDC_COMBO_MATERIALS_TYPE, m_comboMaterialsType);
}
BEGIN_MESSAGE_MAP(CPortConfigurationDlg, CDialogEx)
+ ON_BN_CLICKED(IDC_BUTTON_APPLY, &CPortConfigurationDlg::OnBnClickedButtonApply)
END_MESSAGE_MAP()
@@ -139,8 +141,117 @@
CDialogEx::OnInitDialog();
// TODO: 鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+ // 鍒濆鍖栫鍙d笅鎷夋鍐呭
+ CString ports[] = { _T("Port 1"), _T("Port 2"), _T("Port 3"), _T("Port 4") };
+ for (const auto& item : ports) {
+ m_comboPort.AddString(item);
+ }
+ m_comboPort.SetCurSel(0); // 榛樿閫夋嫨绗竴涓鍙�
+
+ // 鍒濆鍖栭厤鏂逛笅鎷夋鍐呭
+ std::vector<std::string> vecRecipe = RecipeManager::getInstance().getAllPPID();
+ for (const auto& recipe : vecRecipe) {
+ m_comboRecipe.AddString(CString(recipe.c_str()));
+ }
+ m_comboRecipe.SetCurSel(0); // 榛樿閫夋嫨绗竴涓厤鏂�
+
+ // 鍒濆鍖栫墿鏂欑被鍨嬩笅鎷夋鍐呭
+ CString materialTypes[] = { _T("G1"), _T("G2"), _T("G1+G2") };
+ for (const auto& item : materialTypes) {
+ m_comboMaterialsType.AddString(item);
+ }
+ m_comboMaterialsType.SetCurSel(0); // 榛樿閫夋嫨绗竴涓墿鏂欑被鍨�
+
InitGrid();
return TRUE; // return TRUE unless you set the focus to a control
// 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
}
+
+void CPortConfigurationDlg::OnBnClickedButtonApply()
+{
+ // TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
+ SERVO::PortConfig config;
+
+ // 鑾峰彇 Port 鍚嶇О
+ int selPort = m_comboPort.GetCurSel();
+ if (selPort != CB_ERR) {
+ CString str;
+ m_comboPort.GetLBText(selPort, str);
+ config.strPortName = CT2A(str.GetString());
+ }
+
+ // 鑾峰彇 Recipe 鍚嶇О
+ int selRecipe = m_comboRecipe.GetCurSel();
+ if (selRecipe != CB_ERR) {
+ CString str;
+ m_comboRecipe.GetLBText(selRecipe, str);
+ config.strRecipe = CT2A(str.GetString());
+ }
+
+ // 鑾峰彇 Material Type 绱㈠紩锛堢储寮曚粠 0 寮�濮嬶紝瀵瑰簲鏋氫妇浠� 1 寮�濮嬶級
+ int selMaterial = m_comboMaterialsType.GetCurSel();
+ if (selMaterial != CB_ERR) {
+ config.nMaterialType = selMaterial + 1;
+ }
+ else {
+ AfxMessageBox(_T("Please select a material type!"));
+ return;
+ }
+
+ // 鑾峰彇 Lot ID / Product ID / Operation ID
+ CString strText;
+ GetDlgItemText(IDC_EDIT_LOTID, strText);
+ config.strLotID = CT2A(strText.GetString());
+ if (config.strLotID.empty()) {
+ AfxMessageBox(_T("Lot ID cannot be empty!"));
+ return;
+ }
+
+ GetDlgItemText(IDC_EDIT_PRODUCTID, strText);
+ config.strProductID = CT2A(strText.GetString());
+ if (config.strProductID.empty()) {
+ AfxMessageBox(_T("Product ID cannot be empty!"));
+ return;
+ }
+
+ GetDlgItemText(IDC_EDIT_OPERATIONID, strText);
+ config.strOperationID = CT2A(strText.GetString());
+ if (config.strOperationID.empty()) {
+ AfxMessageBox(_T("Operation ID cannot be empty!"));
+ return;
+ }
+
+ // 鑾峰彇 Grid 琛ㄦ牸涓� Slot 鐘舵�侊紙绗�1~8琛岋級
+ for (int i = 1; i <= 8; ++i) {
+ SERVO::SlotConfig slot;
+ slot.nSlotID = i;
+
+ CGridCellCheck* pCheck = static_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 1));
+ if (pCheck) {
+ slot.isEnabled = pCheck->GetCheck();
+ }
+
+ config.vecSlot.push_back(slot);
+ }
+
+ int nEqID = GetLoadPortEqID(config.strPortName);
+ if (nEqID < 0) {
+ AfxMessageBox(_T("鏈煡鐨勭鍙e悕绉帮紒"));
+ return;
+ }
+
+ SERVO::CLoadPort* pPort = dynamic_cast<SERVO::CLoadPort*>(theApp.m_model.m_master.getEquipment(nEqID));
+ if (!pPort) {
+ AfxMessageBox(_T("鎵句笉鍒板搴旂殑 LoadPort 璁惧锛�"));
+ return;
+ }
+
+ // 搴旂敤閰嶇疆锛堜緥濡傛祴璇曠敓鎴愮幓鐠冿級
+ if (pPort->testGenerateGlassListFromConfig(config) < 0) {
+ AfxMessageBox(_T("Failed to generate glass list from configuration!"));
+ return;
+ }
+
+ OnOK();
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/PortConfigurationDlg.h b/SourceCode/Bond/Servo/PortConfigurationDlg.h
index ac7a710..dc33c95 100644
--- a/SourceCode/Bond/Servo/PortConfigurationDlg.h
+++ b/SourceCode/Bond/Servo/PortConfigurationDlg.h
@@ -20,11 +20,16 @@
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 鏀寔
virtual BOOL OnInitDialog();
+ afx_msg void OnBnClickedButtonApply();
DECLARE_MESSAGE_MAP()
private:
- CGridCtrl m_wndGrid;
-
+ int GetLoadPortEqID(const std::string& strPortName);
void InitGrid();
void FillGrid();
+
+ CGridCtrl m_wndGrid;
+ CComboBox m_comboPort;
+ CComboBox m_comboRecipe;
+ CComboBox m_comboMaterialsType;
};
diff --git a/SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp b/SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp
index fec07da..4098135 100644
--- a/SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp
+++ b/SourceCode/Bond/Servo/RecipeDeviceBindDlg.cpp
@@ -6,6 +6,9 @@
#include "afxdialogex.h"
#include "RecipeDeviceBindDlg.h"
+#define IDC_EDIT_DEVICEID_BASE 3000
+#define IDC_EDIT_DEVICENAME_BASE 3050
+#define IDC_COMBO_RECIPEID_BASE 3100
// CRecipeDeviceBindDlg 瀵硅瘽妗�
@@ -32,3 +35,39 @@
// CRecipeDeviceBindDlg 娑堟伅澶勭悊绋嬪簭
+
+BOOL CRecipeDeviceBindDlg::OnInitDialog()
+{
+ CDialogEx::OnInitDialog();
+
+ // TODO: 鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+ // 璁剧疆鍥哄畾澶у皬锛堜緥濡� 600x400锛�
+ SetWindowPos(nullptr, 0, 0, 600, 400, SWP_NOMOVE | SWP_NOZORDER);
+
+ // 鍒涘缓鎺т欢
+ const int totalControlWidth = 340;
+ CRect clientRect;
+ GetClientRect(&clientRect);
+ int xStart = (clientRect.Width() - totalControlWidth) / 2;
+
+ const int nRowCount = 8;
+ const int nRowHeight = 30;
+ const int yStart = 30; // 椤堕儴璧峰楂樺害
+
+ for (int i = 0; i < nRowCount; ++i)
+ {
+ int y = yStart + i * nRowHeight;
+
+ CEdit* pEditID = new CEdit();
+ pEditID->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(xStart, y, xStart + 100, y + 25), this, IDC_EDIT_DEVICEID_BASE + i);
+
+ CEdit* pEditName = new CEdit();
+ pEditName->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(xStart + 110, y, xStart + 210, y + 25), this, IDC_EDIT_DEVICENAME_BASE + i);
+
+ CComboBox* pCombo = new CComboBox();
+ pCombo->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(xStart + 220, y, xStart + 340, y + 300), this, IDC_COMBO_RECIPEID_BASE + i);
+ }
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/RecipeDeviceBindDlg.h b/SourceCode/Bond/Servo/RecipeDeviceBindDlg.h
index c6634bf..d65c49a 100644
--- a/SourceCode/Bond/Servo/RecipeDeviceBindDlg.h
+++ b/SourceCode/Bond/Servo/RecipeDeviceBindDlg.h
@@ -19,6 +19,15 @@
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 鏀寔
-
+ virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
+
+private:
+ struct DeviceWidget {
+ CEdit editDeviceID;
+ CEdit editDeviceName;
+ CComboBox comboRecipeID;
+ };
+
+ std::vector<DeviceWidget> m_vecDevices;
};
diff --git a/SourceCode/Bond/Servo/RecipeManager.cpp b/SourceCode/Bond/Servo/RecipeManager.cpp
index 6e58418..465c1af 100644
--- a/SourceCode/Bond/Servo/RecipeManager.cpp
+++ b/SourceCode/Bond/Servo/RecipeManager.cpp
@@ -238,6 +238,25 @@
return recipes;
}
+std::vector<std::string> RecipeManager::getAllPPID() const {
+ std::vector<std::string> vecPPID;
+
+ if (!m_pDB) {
+ return vecPPID;
+ }
+
+ const std::string query = "SELECT ppid FROM recipes ORDER BY ppid;";
+ auto result = m_pDB->fetchResults(query);
+
+ for (const auto& row : result) {
+ if (!row.empty()) {
+ vecPPID.push_back(row[0]);
+ }
+ }
+
+ return vecPPID;
+}
+
RecipeInfo RecipeManager::getRecipeByPPID(const std::string& ppid) {
RecipeInfo info;
auto rows = m_pDB->fetchResults("SELECT ppid, description, create_time FROM recipes WHERE ppid = '" + ppid + "';");
diff --git a/SourceCode/Bond/Servo/RecipeManager.h b/SourceCode/Bond/Servo/RecipeManager.h
index a51e14d..f13bc50 100644
--- a/SourceCode/Bond/Servo/RecipeManager.h
+++ b/SourceCode/Bond/Servo/RecipeManager.h
@@ -58,6 +58,9 @@
// 查询所有配方
std::vector<RecipeInfo> getAllRecipes();
+ // 获取所有 PPID
+ std::vector<std::string> getAllPPID() const;
+
// 按 PPID 查询配方
RecipeInfo getRecipeByPPID(const std::string& ppid);
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 3440b75..e8c771b 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/ServoCommo.h b/SourceCode/Bond/Servo/ServoCommo.h
index c8b3ae1..1e63c8e 100644
--- a/SourceCode/Bond/Servo/ServoCommo.h
+++ b/SourceCode/Bond/Servo/ServoCommo.h
@@ -1,5 +1,6 @@
#pragma once
-
+#include <string>
+#include <vector>
namespace SERVO {
#define BLOCK_BUFFER_MAX 1024
@@ -165,6 +166,22 @@
Error
};
+ /* Port Status */
+ struct SlotConfig {
+ int nSlotID = 0;
+ bool isEnabled = false;
+ };
+
+ struct PortConfig {
+ int nMaterialType; // 物料类型,1: G1, 2: G2, 3: G1+G2
+ std::string strPortName; // 例如 "Port 1"
+ std::string strRecipe; // 例如 "P1001"
+ std::string strLotID;
+ std::string strProductID;
+ std::string strOperationID;
+ std::vector<SlotConfig> vecSlot;
+ };
+
/* EQ Data changed code */
#define EDCC_FETCHOUT_JOB 1000 /* 取片 */
#define EDCC_STORED_JOB 1001 /* 放片 */
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index e2b5983..2c3b3b4 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ
--
Gitblit v1.9.3