1.PorcessJob和Glass关系绑定;
2.对话框显示ProcessJob、Glass等数据;
| | |
| | | HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1); |
| | | ListView_SetImageList(m_listCtrl.GetSafeHwnd(), imageList, LVSIL_SMALL); |
| | | m_listCtrl.ModifyStyle(0, LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS); |
| | | m_listCtrl.InsertColumn(0, _T("名称"), LVCFMT_LEFT, 180); |
| | | m_listCtrl.InsertColumn(1, _T("状态"), LVCFMT_LEFT, 120); |
| | | m_listCtrl.InsertColumn(2, _T("描述"), LVCFMT_LEFT, 260); |
| | | m_listCtrl.InsertColumn(3, _T("配方"), LVCFMT_LEFT, 180); |
| | | 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); |
| | | |
| | | |
| | | // 控件状态 |
| | |
| | | m_listCtrl.DeleteAllItems(); |
| | | |
| | | if (m_pControlJob != nullptr) { |
| | | auto* root1 = m_listCtrl.InsertRoot({ m_pControlJob->id().c_str(), |
| | | 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(), |
| | | pj->getStateText().c_str(), _T(""), pj->recipeSpec().c_str()}); |
| | | 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) { |
| | | m_listCtrl.InsertChild(root2, {c.carrierId.c_str(), _T(""), _T("") }); |
| | | 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; |
| | | } |
| | |
| | | m_nOriginPort = 0; |
| | | m_nOriginSlot = 0; |
| | | m_bScheduledForProcessing = FALSE; |
| | | m_pProcessJob = nullptr; |
| | | } |
| | | |
| | | CGlass::~CGlass() |
| | |
| | | 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() |
| | |
| | | |
| | | 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(); |
| | | } |
| | | } |
| | |
| | | #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: |
| | |
| | | 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); |
| | |
| | | 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; |
| | |
| | | int m_nOriginPort; |
| | | int m_nOriginSlot; |
| | | BOOL m_bScheduledForProcessing; /* 是否将加工处理 */ |
| | | CProcessJob* m_pProcessJob; |
| | | }; |
| | | } |
| | | |
| | |
| | | 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); |
| | |
| | | }; |
| | | 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); |
| | | } |
| | |
| | | m_processJobs = temp; |
| | | this->saveState(); |
| | | |
| | | return m_processJobs.size(); |
| | | return (int)m_processJobs.size(); |
| | | } |
| | | |
| | | std::vector<CProcessJob*>& CMaster::getProcessJobs() |
| | |
| | | |
| | | return ""; |
| | | } |
| | | |
| | | CarrierSlotInfo* CProcessJob::getCarrier(std::string& strId) |
| | | { |
| | | for (auto& item : m_carriers) { |
| | | if (item.carrierId.compare(strId) == 0) { |
| | | return &item; |
| | | } |
| | | } |
| | | |
| | | return nullptr; |
| | | } |
| | | } |
| | |
| | | struct CarrierSlotInfo { |
| | | std::string carrierId; // CARRIERID |
| | | std::vector<uint8_t> slots; // SLOTID[] |
| | | std::vector<void*> contexts; // Glass |
| | | }; |
| | | |
| | | /// 简单资源视图接口:供 Validate() 查询(由设备端实现者在外部提供) |
| | |
| | | |
| | | // 访问器 |
| | | const std::vector<CarrierSlotInfo>& carriers() const noexcept { return m_carriers; } |
| | | CarrierSlotInfo* getCarrier(std::string& strId); |
| | | |
| | | // 判定是否“按载具/卡位”方式 |
| | | bool usesCarrierSlots() const noexcept { return !m_carriers.empty(); } |