| 2025-08-22 | LAPTOP-SNT8I5JK\Boounion | ![]() |
| 2025-08-21 | LAPTOP-SNT8I5JK\Boounion | ![]() |
| SourceCode/Bond/Servo/CControlJob.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CControlJob.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CControlJobDlg.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CControlJobDlg.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CGlass.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CGlass.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CLoadPort.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CMaster.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/CMaster.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/ProcessJob.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/ProcessJob.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/Servo.rc | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/ServoDlg.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| SourceCode/Bond/Servo/resource.h | 补丁 | 查看 | 原始文档 | blame | 历史 |
SourceCode/Bond/Servo/CControlJob.cpp
@@ -301,4 +301,36 @@ return true; } std::string CControlJob::getStateText() { switch (m_state) { case SERVO::CJState::NoState: return "NoState"; break; case SERVO::CJState::Queued: return "Queued"; break; case SERVO::CJState::Executing: return "Executing"; break; case SERVO::CJState::Paused: return "Paused"; break; case SERVO::CJState::Completed: return "Completed"; break; case SERVO::CJState::Aborted: return "Aborted"; break; case SERVO::CJState::Failed: return "Failed"; break; default: break; } return ""; } } SourceCode/Bond/Servo/CControlJob.h
@@ -45,6 +45,7 @@ CJState state() const noexcept { return m_state; } uint8_t priority() const noexcept { return m_priority; } void setPriority(uint8_t p) noexcept { m_priority = p; } std::string getStateText(); // —— PJ 列表维护(去重)—— // bool addPJ(const std::string& pjId); // 已存在则不重复添加 @@ -54,6 +55,7 @@ const std::vector<std::string>& pjIds() const noexcept { return m_pjIds; } bool setPJs(const std::vector<CProcessJob*>& pjs); void clearPJs() { m_pjIds.clear(); } const std::vector<CProcessJob*>& getPjs() { return m_pjs; }; // —— 校验 —— // struct ValidationIssue { uint32_t code; std::string text; }; SourceCode/Bond/Servo/CControlJobDlg.cpp
@@ -14,7 +14,7 @@ CControlJobDlg::CControlJobDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_DIALOG_CONTROL_JOB, pParent) { m_pControlJob = nullptr; } CControlJobDlg::~CControlJobDlg() @@ -29,40 +29,141 @@ BEGIN_MESSAGE_MAP(CControlJobDlg, CDialogEx) ON_WM_SIZE() END_MESSAGE_MAP() void CControlJobDlg::SetControlJob(SERVO::CControlJob* pControlJob) { m_pControlJob = pControlJob; } // CControlJobDlg 消息处理程序 BOOL CControlJobDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // label字体 LOGFONT lf{}; GetFont()->GetLogFont(&lf); lf.lfHeight = -20; lf.lfWeight = FW_BOLD; _tcscpy_s(lf.lfFaceName, _T("Arial")); m_fontNoJob.CreateFontIndirect(&lf); GetDlgItem(IDC_LABEL_NO_JOB)->SetFont(&m_fontNoJob); // 列表控件 HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1); ListView_SetImageList(m_listCtrl.GetSafeHwnd(), imageList, LVSIL_SMALL); // m_list 已经是对话框上的 CExpandableListCtrl 成员(拖控件改类) m_listCtrl.ModifyStyle(0, LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS); m_listCtrl.InsertColumn(0, _T("名称"), LVCFMT_LEFT, 260); m_listCtrl.InsertColumn(1, _T("状态"), LVCFMT_LEFT, 120); m_listCtrl.InsertColumn(2, _T("描述"), LVCFMT_LEFT, 260); m_listCtrl.InsertColumn(0, _T("ID"), LVCFMT_LEFT, 180); m_listCtrl.InsertColumn(1, _T("类型"), LVCFMT_LEFT, 120); m_listCtrl.InsertColumn(2, _T("状态"), LVCFMT_LEFT, 120); m_listCtrl.InsertColumn(3, _T("配方"), LVCFMT_LEFT, 120); m_listCtrl.InsertColumn(4, _T("Port / Carrier / Slot"), LVCFMT_LEFT, 180); m_listCtrl.InsertColumn(5, _T("描述"), LVCFMT_LEFT, 220); auto* root1 = m_listCtrl.InsertRoot({ _T("EFEM"), _T("Ready"), _T("Front End Module") }); m_listCtrl.InsertChild(root1, { _T("Slot #1"), _T("OK"), _T("150mm wafer") }); m_listCtrl.InsertChild(root1, { _T("Slot #2"), _T("Empty"), _T("") }); auto* root2 = m_listCtrl.InsertRoot({ _T("Bonder"), _T("Run"), _T("G1+G2 Process") }); auto* ch21 = m_listCtrl.InsertChild(root2, { _T("Job A"), _T("Proc"), _T("Step 1") }); m_listCtrl.InsertChild(ch21, { _T("SubStep A1"), _T("Done"), _T("Align") }); m_listCtrl.InsertChild(ch21, { _T("SubStep A2"), _T("Run"), _T("Bond") }); // 初始让顶层展开 root1->expanded = true; root2->expanded = true; m_listCtrl.RebuildVisible(); // 控件状态 Resize(); ShowGroup1(m_pControlJob == nullptr); ShowGroup2(m_pControlJob != nullptr); LoadData(); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CControlJobDlg::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); if (GetDlgItem(IDC_LIST1) == nullptr) return; Resize(); } void CControlJobDlg::Resize() { CRect rcClient, rcItem; CWnd* pItem; GetClientRect(rcClient); // 关闭按钮 int y = rcClient.bottom - 12; pItem = GetDlgItem(IDCANCEL); pItem->GetClientRect(&rcItem); pItem->MoveWindow(rcClient.right - 12 - rcItem.Width(), y - rcItem.Height(), rcItem.Width(), rcItem.Height()); y -= rcItem.Height(); y -= 12; // 线 pItem = GetDlgItem(IDC_LINE1); pItem->MoveWindow(12, y, rcClient.Width() - 24, 2); y -= 2; // Label pItem = GetDlgItem(IDC_LABEL_NO_JOB); pItem->GetClientRect(&rcItem); pItem->MoveWindow((rcClient.Width() - rcItem.Width()) / 2, (y - rcItem.Height()) / 2, rcItem.Width(), rcItem.Height()); // ListCtrl pItem = GetDlgItem(IDC_LIST1); pItem->MoveWindow(12, 12, rcClient.Width() - 24, y - 12); } void CControlJobDlg::ShowGroup1(BOOL bShow) { GetDlgItem(IDC_LABEL_NO_JOB)->ShowWindow(bShow ? SW_SHOW : SW_HIDE); GetDlgItem(IDC_LINE1)->ShowWindow(bShow ? SW_SHOW : SW_HIDE); } void CControlJobDlg::ShowGroup2(BOOL bShow) { GetDlgItem(IDC_LIST1)->ShowWindow(bShow ? SW_SHOW : SW_HIDE); } void CControlJobDlg::LoadData() { m_listCtrl.DeleteAllItems(); if (m_pControlJob != nullptr) { auto* root1 = m_listCtrl.InsertRoot({ m_pControlJob->id().c_str(), _T("ControlJob"), m_pControlJob->getStateText().c_str(), _T("") }); auto pjs = m_pControlJob->getPjs(); for (auto pj : pjs) { auto* root2 = m_listCtrl.InsertChild(root1, {pj->id().c_str(), _T("ProcessJob"), pj->getStateText().c_str(), pj->recipeSpec().c_str(), _T(""), _T(""), _T("") }); auto cs = pj->carriers(); for (auto c : cs) { for (auto g : c.contexts) { SERVO::CGlass* pGlass = (SERVO::CGlass*)g; if (pGlass != nullptr) { int port, slot; pGlass->getOrginPort(port, slot); std::string carrier = c.carrierId + " / Port" + std::to_string(port + 1) + " / Slot" + std::to_string(slot + 1); m_listCtrl.InsertChild(root2, { pGlass->getID().c_str(), _T("Glass"), pGlass->getStateText().c_str(), _T(""), carrier.c_str(), _T("") }); } else { m_listCtrl.InsertChild(root2, { "Null", _T("Glass"), _T(""), _T(""), c.carrierId.c_str(), _T("") }); } } } root2->expanded = true; } root1->expanded = true; m_listCtrl.RebuildVisible(); } } SourceCode/Bond/Servo/CControlJobDlg.h
@@ -1,5 +1,6 @@ #pragma once #include "CExpandableListCtrl.h" #include "CControlJob.h" // CControlJobDlg 对话框 @@ -11,6 +12,19 @@ public: CControlJobDlg(CWnd* pParent = nullptr); // 标准构造函数 virtual ~CControlJobDlg(); public: void SetControlJob(SERVO::CControlJob* pControlJob); private: void Resize(); void ShowGroup1(BOOL bShow); void ShowGroup2(BOOL bShow); void LoadData(); private: SERVO::CControlJob* m_pControlJob; CFont m_fontNoJob; protected: CExpandableListCtrl m_listCtrl; @@ -27,4 +41,5 @@ DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnSize(UINT nType, int cx, int cy); }; SourceCode/Bond/Servo/CGlass.cpp
@@ -11,6 +11,7 @@ m_nOriginPort = 0; m_nOriginSlot = 0; m_bScheduledForProcessing = FALSE; m_pProcessJob = nullptr; } CGlass::~CGlass() @@ -89,6 +90,16 @@ void CGlass::setScheduledForProcessing(BOOL bProcessing) { m_bScheduledForProcessing = bProcessing; } CProcessJob* CGlass::getProcessJob() { return m_pProcessJob; } void CGlass::setProcessJob(CProcessJob* pProcessJob) { m_pProcessJob = pProcessJob; } CPath* CGlass::getPath() @@ -246,4 +257,116 @@ return pPath->getInspResult(); } std::string CGlass::getStateText() { switch (m_state) { case SERVO::GlsState::NoState: return "NoState"; break; case SERVO::GlsState::Queued: return "Queued"; break; case SERVO::GlsState::InProcess: return "InProcess"; break; case SERVO::GlsState::Paused: return "Queued"; break; case SERVO::GlsState::Completed: return "Queued"; break; case SERVO::GlsState::Aborted: return "Aborted"; break; case SERVO::GlsState::Failed: return "Failed"; break; default: break; } return ""; } bool CGlass::queue() { if (m_state != GlsState::NoState) return false; markQueued(); return true; } bool CGlass::start() { if (m_state != GlsState::Queued && m_state != GlsState::Paused) return false; if (!m_tStart.has_value()) markStart(); m_state = GlsState::InProcess; return true; } bool CGlass::pause() { if (m_state != GlsState::InProcess) return false; m_state = GlsState::Paused; return true; } bool CGlass::resume() { if (m_state != GlsState::Paused) return false; m_state = GlsState::InProcess; return true; } bool CGlass::complete() { if (m_state != GlsState::InProcess && m_state != GlsState::Paused) return false; m_state = GlsState::Completed; markEnd(); return true; } bool CGlass::abort() { if (m_state == GlsState::Completed || m_state == GlsState::Aborted || m_state == GlsState::Failed) return false; m_state = GlsState::Aborted; markEnd(); return true; } bool CGlass::fail(std::string reason) { m_failReason = trimCopy(reason); clampString(m_failReason, 128); m_state = GlsState::Failed; markEnd(); return true; } std::string CGlass::trimCopy(std::string s) { auto notspace = [](int ch) { return !std::isspace(ch); }; s.erase(s.begin(), std::find_if(s.begin(), s.end(), notspace)); s.erase(std::find_if(s.rbegin(), s.rend(), notspace).base(), s.end()); return s; } void CGlass::clampString(std::string& s, size_t maxLen) { if (s.size() > maxLen) s.resize(maxLen); } // —— 时间戳 & 工具 —— void CGlass::markQueued() { m_state = GlsState::Queued; m_tQueued = std::chrono::system_clock::now(); } void CGlass::markStart() { m_tStart = std::chrono::system_clock::now(); } void CGlass::markEnd() { m_tEnd = std::chrono::system_clock::now(); } } SourceCode/Bond/Servo/CGlass.h
@@ -7,9 +7,21 @@ #include "CJobDataC.h" #include "CJobDataS.h" #include "ServoCommo.h" #include "ProcessJob.h" namespace SERVO { /// PJ 生命周期(贴近 E40 常见状态) enum class GlsState : uint8_t { NoState = 0, Queued, InProcess, Paused, Completed, Aborted, Failed }; class CGlass : public CContext { public: @@ -28,6 +40,8 @@ void getOrginPort(int& port, int& slot); BOOL isScheduledForProcessing(); void setScheduledForProcessing(BOOL bProcessing); CProcessJob* getProcessJob(); void setProcessJob(CProcessJob* pProcessJob); CPath* getPathWithEq(unsigned int nEqId, unsigned int nUnit); CPath* getPath(); void addPath(unsigned int nEqId, unsigned int nUnit); @@ -44,6 +58,37 @@ int setInspResult(unsigned int nEqId, unsigned int nUnit, InspResult result); InspResult getInspResult(unsigned int nEqId, unsigned int nUnit); public: // 新增状态 GlsState state() const noexcept { return m_state; } std::string getStateText(); GlsState m_state{ GlsState::NoState }; static void clampString(std::string& s, size_t maxLen); static std::string trimCopy(std::string s); std::string m_failReason; // —— 状态机(带守卫)—— bool queue(); // NoState -> Queued bool start(); // Queued -> InProcess bool pause(); // InProcess -> Paused bool resume(); // Paused -> InProcess bool complete(); // InProcess -> Completed bool abort(); // Any (未终态) -> Aborted bool fail(std::string reason); // 任意态 -> Failed(记录失败原因) // 时间戳 std::optional<std::chrono::system_clock::time_point> m_tQueued; std::optional<std::chrono::system_clock::time_point> m_tStart; std::optional<std::chrono::system_clock::time_point> m_tEnd; // 时间戳(可用于报表/追溯) std::optional<std::chrono::system_clock::time_point> tQueued() const { return m_tQueued; } std::optional<std::chrono::system_clock::time_point> tStart() const { return m_tStart; } std::optional<std::chrono::system_clock::time_point> tEnd() const { return m_tEnd; } void markQueued(); void markStart(); void markEnd(); private: MaterialsType m_type; std::string m_strID; @@ -54,6 +99,7 @@ int m_nOriginPort; int m_nOriginSlot; BOOL m_bScheduledForProcessing; /* 是否将加工处理 */ CProcessJob* m_pProcessJob; }; } SourceCode/Bond/Servo/CLoadPort.cpp
@@ -385,7 +385,7 @@ CStep* pStep = getStepWithName(STEP_EQ_PORT2_INUSE); CPortStatusReport portStatusReport; portStatusReport.setPortStatus(PORT_INUSE); portStatusReport.setJobExistenceSlot(0xf); portStatusReport.setJobExistenceSlot(0xff ); portStatusReport.setCassetteId("CID1004"); int nRet = portStatusReport.serialize(szBuffer, 64); decodePortStatusReport(pStep, szBuffer, 64); SourceCode/Bond/Servo/CMaster.cpp
@@ -1143,6 +1143,25 @@ }; listener.onPortStatusChanged = [&](void* pEquipment, short status, __int64 data) { LOGE("<Master-%s>onPortStatusChanged。status=%d, data=%lld", ((CEquipment*)pEquipment)->getName().c_str(), status); if (status == PORT_INUSE && m_pControlJob != nullptr) { CLoadPort* pPort = (CLoadPort*)pEquipment; auto pjs = m_pControlJob->getPjs(); for (auto pj : pjs) { auto carrier = pj->getCarrier(pPort->getCassetteId()); if (carrier != nullptr) { for (auto slot : carrier->slots) { CGlass* pGlass = pPort->getGlassFromSlot(slot); carrier->contexts.push_back((void*)pGlass); if (pGlass != nullptr) { pGlass->setProcessJob(pj); } } } } } if (m_listener.onLoadPortStatusChanged != nullptr) { m_listener.onLoadPortStatusChanged(this, (CEquipment*)pEquipment, status, data); } @@ -1868,7 +1887,7 @@ m_processJobs = temp; this->saveState(); return m_processJobs.size(); return (int)m_processJobs.size(); } std::vector<CProcessJob*>& CMaster::getProcessJobs() @@ -1927,6 +1946,11 @@ return 0; } CControlJob* CMaster::getControlJob() { return m_pControlJob; } CLoadPort* CMaster::getPortWithCarrierId(const std::string& carrierId) const @@ -2047,6 +2071,19 @@ m_processJobs.push_back(pProcessJob); } // 找到CProcessJob指针加入列表中 std::vector<CProcessJob*> tempPjs; auto ids = m_pControlJob->pjIds(); for (auto id : ids) { auto pj = getProcessJob(id); if (pj != nullptr) { tempPjs.push_back(pj); } } m_pControlJob->setPJs(tempPjs); // 如果版本升级,可在这里判断 version 来加载新字段 SourceCode/Bond/Servo/CMaster.h
@@ -110,6 +110,7 @@ std::vector<CProcessJob*>& getProcessJobs(); CProcessJob* getProcessJob(const std::string& id); int setControlJob(CControlJob& controlJob); CControlJob* getControlJob(); CLoadPort* getPortWithCarrierId(const std::string& carrierId) const; bool saveState() const; bool loadState(const std::string& path); SourceCode/Bond/Servo/ProcessJob.cpp
@@ -381,4 +381,53 @@ return true; } std::string CProcessJob::getStateText() { switch (m_state) { case SERVO::PJState::NoState: return "NoState"; break; case SERVO::PJState::Queued: return "Queued"; break; case SERVO::PJState::SettingUp: return "SettingUp"; break; case SERVO::PJState::InProcess: return "InProcess"; break; case SERVO::PJState::Paused: return "Queued"; break; case SERVO::PJState::Aborting: return "Aborting"; break; case SERVO::PJState::Completed: return "Queued"; break; case SERVO::PJState::Aborted: return "Aborted"; break; case SERVO::PJState::Failed: return "Failed"; break; default: break; } return ""; } CarrierSlotInfo* CProcessJob::getCarrier(std::string& strId) { for (auto& item : m_carriers) { if (item.carrierId.compare(strId) == 0) { return &item; } } return nullptr; } } SourceCode/Bond/Servo/ProcessJob.h
@@ -49,8 +49,9 @@ } */ struct CarrierSlotInfo { std::string carrierId; // CARRIERID std::vector<uint8_t> slots; // SLOTID[] std::string carrierId; // CARRIERID std::vector<uint8_t> slots; // SLOTID[] std::vector<void*> contexts; // Glass }; /// 简单资源视图接口:供 Validate() 查询(由设备端实现者在外部提供) @@ -94,6 +95,7 @@ StartPolicy startPolicy() const noexcept { return m_startPolicy; } RecipeMethod recipeMethod() const noexcept { return m_recipeMethod; } const std::string& recipeSpec() const noexcept { return m_recipeSpec; } // PPID 或 Spec std::string getStateText(); // 绑定父 CJ void setParentCjId(std::string cjId); @@ -153,6 +155,7 @@ // 访问器 const std::vector<CarrierSlotInfo>& carriers() const noexcept { return m_carriers; } CarrierSlotInfo* getCarrier(std::string& strId); // 判定是否“按载具/卡位”方式 bool usesCarrierSlots() const noexcept { return !m_carriers.empty(); } SourceCode/Bond/Servo/Servo.rcBinary files differ
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -981,6 +981,7 @@ } else if (id == IDC_BUTTON_JOBS) { CControlJobDlg dlg; dlg.SetControlJob(theApp.m_model.m_master.getControlJob()); dlg.DoModal(); } else if (id == IDC_BUTTON_PORT_CONFIG) { SourceCode/Bond/Servo/resource.hBinary files differ