| | |
| | | return 0; |
| | | } |
| | | |
| | | int CHsmsActive::hsmsCreateControlJob(const char* pszControlJobId, std::vector<std::string>& processJobIds) |
| | | { |
| | | char szBuffer[256]; |
| | | sprintf_s(szBuffer, 256, "ControlJob:%s>", pszControlJobId); |
| | | |
| | | IMessage* pMessage = nullptr; |
| | | int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 14 | REPLY, 9, ++m_nSystemByte); |
| | | pMessage->getBody()->addItem(szBuffer, "OBJSPEC"); |
| | | pMessage->getBody()->addItem("ControlJob", "OBJTYPE"); |
| | | auto itemAttrs = pMessage->getBody()->addItem(); |
| | | |
| | | { |
| | | auto itemAttr = itemAttrs->addItem(); |
| | | itemAttr->addItem("Priority", "ATTRID"); |
| | | itemAttr->addU1Item(8, "ATTRDATA"); |
| | | } |
| | | |
| | | { |
| | | auto itemAttr = itemAttrs->addItem(); |
| | | itemAttr->addItem("weight", "ATTRID"); |
| | | itemAttr->addF4Item(60.5, "ATTRDATA"); |
| | | } |
| | | |
| | | { |
| | | auto itemAttr = itemAttrs->addItem(); |
| | | itemAttr->addItem("tel", "ATTRID"); |
| | | itemAttr->addItem("15919875007", "ATTRDATA"); |
| | | } |
| | | |
| | | { |
| | | auto itemAttr = itemAttrs->addItem(); |
| | | itemAttr->addItem("PRJOBLIST", "ATTRID"); |
| | | auto itemProcessJobs = itemAttr->addItem(); |
| | | for (auto& item : processJobIds) { |
| | | itemProcessJobs->addItem(item.c_str(), ""); |
| | | } |
| | | } |
| | | |
| | | m_pActive->sendMessage(pMessage); |
| | | HSMS_Destroy1Message(pMessage); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int CHsmsActive::replyAck0(IMessage* pMessage) |
| | | { |
| | | return 0; |
| | |
| | | // S16F15 |
| | | int hsmsPRJobMultiCreate(std::vector<SERVO::CProcessJob*>& pjs); |
| | | |
| | | // S14F9 |
| | | int hsmsCreateControlJob(const char* pszControlJobId, std::vector<std::string>& processJobIds); |
| | | |
| | | // éè¿çreply彿° |
| | | void replyAck(int s, int f, unsigned int systemBytes, BYTE ack, const char* pszAckName); |
| | | |
| | |
| | | ON_BN_CLICKED(IDC_BUTTON_QUERY_CJ_SPACE, &CEAPSimulatorDlg::OnBnClickedButtonQueryCjSpace) |
| | | ON_BN_CLICKED(IDC_BUTTON_QUERY_PJ_SPACE, &CEAPSimulatorDlg::OnBnClickedButtonQueryPjSpace) |
| | | ON_BN_CLICKED(IDC_BUTTON_CREATE_PJ, &CEAPSimulatorDlg::OnBnClickedButtonCreatePj) |
| | | ON_BN_CLICKED(IDC_BUTTON_CREATE_CJ, &CEAPSimulatorDlg::OnBnClickedButtonCreateCj) |
| | | END_MESSAGE_MAP() |
| | | |
| | | |
| | |
| | | GetDlgItem(IDC_BUTTON_QUERY_CJ_SPACE)->EnableWindow(enabled); |
| | | GetDlgItem(IDC_BUTTON_QUERY_PJ_SPACE)->EnableWindow(enabled); |
| | | GetDlgItem(IDC_BUTTON_CREATE_PJ)->EnableWindow(enabled); |
| | | GetDlgItem(IDC_BUTTON_CREATE_CJ)->EnableWindow(enabled); |
| | | } |
| | | |
| | | void CEAPSimulatorDlg::OnBnClickedButtonConnect() |
| | |
| | | CPJsDlg dlg; |
| | | dlg.DoModal(); |
| | | } |
| | | |
| | | void CEAPSimulatorDlg::OnBnClickedButtonCreateCj() |
| | | { |
| | | std::vector<std::string> processJobIds = {"PJ0001", "PJ0003"}; |
| | | theApp.m_model.m_pHsmsActive->hsmsCreateControlJob("CJ5007", processJobIds); |
| | | } |
| | |
| | | afx_msg void OnBnClickedButtonQueryCjSpace(); |
| | | afx_msg void OnBnClickedButtonQueryPjSpace(); |
| | | afx_msg void OnBnClickedButtonCreatePj(); |
| | | afx_msg void OnBnClickedButtonCreateCj(); |
| | | }; |
| | |
| | | #define IDC_BUTTON_QUERY_PJ_SPACE 1038 |
| | | #define IDC_BUTTON_CREATE_PJ 1039 |
| | | #define IDC_BUTTON_ADD 1040 |
| | | #define IDC_BUTTON_CREATE_PJ2 1040 |
| | | #define IDC_BUTTON_CREATE_CJ 1040 |
| | | #define IDC_BUTTON_DELETE 1041 |
| | | |
| | | // Next default values for new objects |
| | |
| | | virtual void setBinary(const char* pszData, unsigned int len, const char* pszNote) = 0; |
| | | virtual void setString(const char* pszText, const char* pszNote) = 0; |
| | | virtual void setU1(unsigned char value, const char* pszNote) = 0; |
| | | virtual void setBool(bool value, const char* pszNote) = 0; |
| | | virtual ISECS2Item* addItem() = 0; |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #include "stdafx.h" |
| | | #include "CControlJob.h" |
| | | #include <cctype> |
| | | #include "SerializeUtil.h" |
| | | |
| | | static inline std::string 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; |
| | | } |
| | | |
| | | namespace SERVO { |
| | | CControlJob::CControlJob() |
| | | { |
| | | |
| | | } |
| | | |
| | | CControlJob::CControlJob(std::string cjId) |
| | | : m_cjId(trimCopy(std::move(cjId))) |
| | | { |
| | | clampString(m_cjId, MAX_ID_LEN); |
| | | } |
| | | |
| | | CControlJob::CControlJob(CControlJob& src) |
| | | { |
| | | m_cjId = src.m_cjId; |
| | | clampString(m_cjId, MAX_ID_LEN); |
| | | m_priority = src.m_priority; |
| | | m_pjIds = src.m_pjIds; |
| | | m_state = src.m_state; |
| | | m_failReason = src.m_failReason; |
| | | m_tQueued = src.m_tQueued; |
| | | m_tStart = src.m_tStart; |
| | | m_tEnd = src.m_tEnd; |
| | | } |
| | | |
| | | bool CControlJob::addPJ(const std::string& pjId) { |
| | | if (pjId.empty()) return false; |
| | | auto id = pjId; |
| | | auto it = std::find(m_pjIds.begin(), m_pjIds.end(), id); |
| | | if (it != m_pjIds.end()) return false; |
| | | clampString(id, MAX_ID_LEN); |
| | | m_pjIds.push_back(std::move(id)); |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::addPJs(const std::vector<std::string>& ids) { |
| | | bool added = false; |
| | | for (auto& s : ids) added |= addPJ(s); |
| | | return added; |
| | | } |
| | | |
| | | bool CControlJob::setPJs(const std::vector<CProcessJob*>& pjs) |
| | | { |
| | | m_pjs = pjs; |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::removePJ(const std::string& pjId) { |
| | | auto it = std::find(m_pjIds.begin(), m_pjIds.end(), pjId); |
| | | if (it == m_pjIds.end()) return false; |
| | | m_pjIds.erase(it); |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::containsPJ(const std::string& pjId) const { |
| | | return std::find(m_pjIds.begin(), m_pjIds.end(), pjId) != m_pjIds.end(); |
| | | } |
| | | |
| | | const std::vector<CControlJob::ValidationIssue>& CControlJob::issues() |
| | | { |
| | | return m_issues; |
| | | } |
| | | |
| | | bool CControlJob::validateForCreate( |
| | | const std::function<bool(uint32_t& code, std::string& msg)>& canCreateCjFn, |
| | | const std::function<bool(const std::string&)>& getPjExistsFn, |
| | | const std::function<bool(const std::string&)>& canJoinFn |
| | | ) |
| | | { |
| | | m_issues.clear(); |
| | | |
| | | auto add = [&](uint32_t code, std::string msg) { m_issues.push_back({ code, std::move(msg) }); }; |
| | | |
| | | // æ¯å¦è½å建CJ, ç±ä¸å±æ ¹æ®å½åä»»å¡ï¼æºå¨ç¶æçæ£éª |
| | | uint32_t cc; |
| | | std::string mm; |
| | | if (!canCreateCjFn(cc, mm)) { |
| | | add(cc, mm); |
| | | } |
| | | |
| | | |
| | | // CJID åºç¡æ ¡éª |
| | | if (m_cjId.empty()) add(1101, "CJID empty"); |
| | | if (!asciiPrintable(m_cjId)) add(1102, "CJID has non-printable chars"); |
| | | |
| | | // PJ åè¡¨æ ¡éª |
| | | if (m_pjIds.empty()) add(1110, "PRJOBLIST empty"); |
| | | for (const auto& pj : m_pjIds) { |
| | | if (!getPjExistsFn(pj)) add(1111, "PJ not found: " + pj); |
| | | else if (!canJoinFn(pj)) add(1112, "PJ not joinable: " + pj); |
| | | } |
| | | |
| | | return m_issues.empty(); |
| | | } |
| | | |
| | | // åºç¨å建/æ´æ°ï¼ç¨äº S14F9 â S14F10 è·¯å¾ï¼ |
| | | CControlJob::CreateResult |
| | | CControlJob::applyCreate( |
| | | const CreateRequest& req, |
| | | const std::function<bool(const std::string&)>& getPjExistsFn, |
| | | const std::function<bool(const std::string&)>& canJoinFn |
| | | ) |
| | | { |
| | | CreateResult r; |
| | | |
| | | // è¦çä¼å
级ï¼å¦æä¾ï¼ |
| | | if (req.priority.has_value()) { |
| | | m_priority = *req.priority; |
| | | } |
| | | |
| | | // é PJ å¤å® |
| | | for (const auto& pjIdRaw : req.requestedPjIds) { |
| | | std::string pjId = trimCopy(pjIdRaw); |
| | | clampString(pjId, MAX_ID_LEN); |
| | | |
| | | if (!getPjExistsFn(pjId)) { |
| | | r.errors.push_back({ 2001, "PRJOBLIST: " + pjId + " not found" }); |
| | | continue; |
| | | } |
| | | if (!canJoinFn(pjId)) { |
| | | r.errors.push_back({ 2002, "PRJOBLIST: " + pjId + " not joinable (state)" }); |
| | | continue; |
| | | } |
| | | if (containsPJ(pjId)) { |
| | | // å·²å¨å表ï¼è§ä½æåï¼å¹çï¼ |
| | | r.acceptedPjIds.push_back(pjId); |
| | | continue; |
| | | } |
| | | // å å
¥ CJ |
| | | m_pjIds.push_back(pjId); |
| | | r.acceptedPjIds.push_back(std::move(pjId)); |
| | | } |
| | | |
| | | // å½å¹¶ ACK |
| | | if (r.errors.empty()) r.objack = 0; // å
¨æå |
| | | else if (!r.acceptedPjIds.empty()) r.objack = 1; // é¨åæå |
| | | else r.objack = 2; // å
¨å¤±è´¥ |
| | | |
| | | return r; |
| | | } |
| | | |
| | | // ââ ç¶ææº ââ // |
| | | bool CControlJob::queue() { |
| | | if (m_state != CJState::NoState) return false; |
| | | markQueued(); |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::start() { |
| | | if (m_state != CJState::Queued) return false; |
| | | m_state = CJState::Executing; |
| | | if (!m_tStart.has_value()) markStart(); |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::pause() { |
| | | if (m_state != CJState::Executing) return false; |
| | | m_state = CJState::Paused; |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::resume() { |
| | | if (m_state != CJState::Paused) return false; |
| | | m_state = CJState::Executing; |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::complete() { |
| | | if (m_state != CJState::Executing && m_state != CJState::Paused) return false; |
| | | m_state = CJState::Completed; |
| | | markEnd(); |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::abort() { |
| | | if (m_state == CJState::Completed || m_state == CJState::Aborted || m_state == CJState::Failed) |
| | | return false; |
| | | m_state = CJState::Aborted; |
| | | markEnd(); |
| | | return true; |
| | | } |
| | | |
| | | bool CControlJob::fail(std::string reason) { |
| | | m_failReason = trimCopy(reason); |
| | | clampString(m_failReason, 128); |
| | | m_state = CJState::Failed; |
| | | markEnd(); |
| | | return true; |
| | | } |
| | | |
| | | // ââ èå宿夿 ââ // |
| | | bool CControlJob::tryAggregateComplete( |
| | | const std::function<bool(const std::string&)>& isPjCompletedFn |
| | | ) { |
| | | if (m_pjIds.empty()) return false; |
| | | for (const auto& pj : m_pjIds) { |
| | | if (!isPjCompletedFn(pj)) return false; |
| | | } |
| | | // ææ PJ 已宿 â CJ 宿 |
| | | return complete(); |
| | | } |
| | | |
| | | // ââ æ¶é´æ³ ââ // |
| | | void CControlJob::markQueued() { m_state = CJState::Queued; m_tQueued = std::chrono::system_clock::now(); } |
| | | void CControlJob::markStart() { m_tStart = std::chrono::system_clock::now(); } |
| | | void CControlJob::markEnd() { m_tEnd = std::chrono::system_clock::now(); } |
| | | |
| | | // ââ å·¥å
· ââ // |
| | | void CControlJob::clampString(std::string& s, size_t maxLen) { |
| | | if (s.size() > maxLen) s.resize(maxLen); |
| | | } |
| | | |
| | | bool CControlJob::asciiPrintable(const std::string& s) { |
| | | return std::all_of(s.begin(), s.end(), [](unsigned char c) { |
| | | return c >= 0x20 && c <= 0x7E; |
| | | }); |
| | | } |
| | | |
| | | void CControlJob::serialize(std::ostream& os) const { |
| | | write_pod(os, CJ_MAGIC); |
| | | write_pod(os, CJ_VERSION); |
| | | |
| | | // æ è¯/ä¼å
级/ç¶æ/失败åå |
| | | write_string(os, id()); // æ m_cjId |
| | | write_pod<uint8_t>(os, priority()); // æ m_priority |
| | | write_pod<uint8_t>(os, static_cast<uint8_t>(state())); // æ m_state |
| | | write_string(os, failReason()); // æ m_failReason |
| | | |
| | | // æ¶é´æ³ |
| | | write_opt_time(os, tQueued()); |
| | | write_opt_time(os, tStart()); |
| | | write_opt_time(os, tEnd()); |
| | | |
| | | // å
³è PJ å表 |
| | | write_vec_str(os, pjIds()); // æ m_pjIds |
| | | } |
| | | |
| | | bool CControlJob::deserialize(std::istream& is, CControlJob& out, std::string* err) { |
| | | auto fail = [&](const char* msg) { if (err) *err = msg; return false; }; |
| | | |
| | | uint32_t magic = 0; if (!read_pod(is, magic)) return fail("read CJ magic"); |
| | | if (magic != CJ_MAGIC) return fail("bad CJ magic"); |
| | | |
| | | uint16_t ver = 0; if (!read_pod(is, ver)) return fail("read CJ version"); |
| | | if (ver != CJ_VERSION) return fail("unsupported CJ version"); |
| | | |
| | | std::string cjId; |
| | | if (!read_string(is, cjId)) return fail("read CJID"); |
| | | |
| | | uint8_t prio = 0; |
| | | if (!read_pod(is, prio)) return fail("read Priority"); |
| | | |
| | | uint8_t st = 0; |
| | | if (!read_pod(is, st)) return fail("read State"); |
| | | |
| | | std::string failText; |
| | | if (!read_string(is, failText)) return fail("read failReason"); |
| | | |
| | | std::optional<std::chrono::system_clock::time_point> tQ, tS, tE; |
| | | if (!read_opt_time(is, tQ)) return fail("read tQueued"); |
| | | if (!read_opt_time(is, tS)) return fail("read tStart"); |
| | | if (!read_opt_time(is, tE)) return fail("read tEnd"); |
| | | |
| | | std::vector<std::string> pjIds; |
| | | if (!read_vec_str(is, pjIds)) return fail("read PJIDs"); |
| | | |
| | | // ââ åå对象ï¼ç´æ¥æ¹æåï¼æéè¿ setterï¼ââ |
| | | // è¥ä½ æ setterï¼out.setId(...)/setPriority(...)/setState(...)/setFailReason(...) |
| | | out = CControlJob(cjId); |
| | | out.setPriority(prio); |
| | | |
| | | // ç´æ¥æ¢å¤å
é¨ç¶æï¼è¥ä½ è¦æ±èµ°ç¶ææºï¼å¯å¨è¿éæåæ³è¿æ¸¡è°ç¨ queue()/start()/...ï¼ |
| | | // ç®åï¼ç´æ¥èµå¼ï¼ä½ å¨ CControlJob.cpp å
é¨ï¼å¯è®¿é®ç§ææåï¼ |
| | | struct Access : CControlJob { |
| | | using CControlJob::m_state; |
| | | using CControlJob::m_failReason; |
| | | using CControlJob::m_tQueued; |
| | | using CControlJob::m_tStart; |
| | | using CControlJob::m_tEnd; |
| | | using CControlJob::m_pjIds; |
| | | }; |
| | | auto& a = reinterpret_cast<Access&>(out); |
| | | a.m_state = static_cast<CJState>(st); |
| | | a.m_failReason = std::move(failText); |
| | | a.m_tQueued = std::move(tQ); |
| | | a.m_tStart = std::move(tS); |
| | | a.m_tEnd = std::move(tE); |
| | | a.m_pjIds = std::move(pjIds); |
| | | |
| | | return true; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include <string> |
| | | #include <vector> |
| | | #include <algorithm> |
| | | #include <cstdint> |
| | | #include <optional> |
| | | #include <chrono> |
| | | #include <functional> |
| | | #include "ProcessJob.h" |
| | | |
| | | |
| | | // ââ æ å/项ç®å
约å®ç屿§åï¼A:40ï¼ââ |
| | | // 说æï¼ä¸ä»¥ç©ºæ ¼å¼å¤´/ç»å°¾ï¼å符èå´ 0x20-0x7Eï¼ä¸ä¸è½å
å« > : ? * ~ |
| | | inline constexpr const char* CJ_ATTR_CJID = "CJID"; // A:n |
| | | inline constexpr const char* CJ_ATTR_PRIORITY = "Priority"; // U1 |
| | | inline constexpr const char* CJ_ATTR_PRJOBLIST = "PRJOBLIST"; // L:n of A:n (PJID[]) |
| | | |
| | | namespace SERVO { |
| | | /// CJ ç¶æï¼è´´è¿ E40 è¯ä¹ï¼ |
| | | enum class CJState : uint8_t { |
| | | NoState = 0, |
| | | Queued, |
| | | Executing, |
| | | Paused, |
| | | Completed, |
| | | Aborted, |
| | | Failed |
| | | }; |
| | | |
| | | /// å建/ä¿®æ¹ç»æä¸çé误项 |
| | | struct CJError { |
| | | uint16_t code; // èªå®ä¹é误ç ï¼ä¾ï¼2001=PJ_NOT_FOUND, 2002=NOT_JOINABLEï¼ |
| | | std::string text; // 建议å
å«å®ä½ä¿¡æ¯ï¼ATTRID/PJIDï¼ |
| | | }; |
| | | |
| | | /// CControlJobï¼Control Job 管çç±» |
| | | class CControlJob { |
| | | public: |
| | | CControlJob(); |
| | | explicit CControlJob(std::string cjId); |
| | | explicit CControlJob(CControlJob& src); |
| | | |
| | | // ââ åºæ¬å±æ§ ââ // |
| | | const std::string& id() const noexcept { return m_cjId; } |
| | | CJState state() const noexcept { return m_state; } |
| | | uint8_t priority() const noexcept { return m_priority; } |
| | | void setPriority(uint8_t p) noexcept { m_priority = p; } |
| | | |
| | | // ââ PJ å表维æ¤ï¼å»éï¼ââ // |
| | | bool addPJ(const std::string& pjId); // å·²åå¨åä¸é夿·»å |
| | | bool addPJs(const std::vector<std::string>& ids); // è¿åæ¯å¦ææ°å¢ |
| | | bool removePJ(const std::string& pjId); // åå¨åç§»é¤ |
| | | bool containsPJ(const std::string& pjId) const; |
| | | const std::vector<std::string>& pjIds() const noexcept { return m_pjIds; } |
| | | bool setPJs(const std::vector<CProcessJob*>& pjs); |
| | | void clearPJs() { m_pjIds.clear(); } |
| | | |
| | | // ââ æ ¡éª ââ // |
| | | struct ValidationIssue { uint32_t code; std::string text; }; |
| | | |
| | | // æ ¡éª CJ æ¯å¦å¯å建/æ´æ°ï¼ä¾å¦ï¼PJ æ¯å¦åå¨ãæ¯å¦å¯å å
¥ï¼ |
| | | // getPjExistsFn(pjId)->boolï¼PJ æ¯å¦åå¨ |
| | | // canJoinFn(pjId)->bool ï¼PJ å½åæ¯å¦å
许å å
¥ CJï¼å¦ PJ ç¶æä¸º Queued çï¼ |
| | | bool validateForCreate( |
| | | const std::function<bool(uint32_t& code, std::string& msg)>& canCreateCjFn, |
| | | const std::function<bool(const std::string&)>& getPjExistsFn, |
| | | const std::function<bool(const std::string&)>& canJoinFn |
| | | ); |
| | | const std::vector<CControlJob::ValidationIssue>& CControlJob::issues(); |
| | | |
| | | // ââ S14F9 â S14F10 çâåºç¨ç»æâ模å ââ // |
| | | struct CreateRequest { |
| | | std::optional<uint8_t> priority; // è¥æåè¦ç |
| | | std::vector<std::string> requestedPjIds;// æ³è¦ç»å®ç PJ å表 |
| | | }; |
| | | struct CreateResult { |
| | | std::vector<std::string> acceptedPjIds; // æåç»å®ç PJï¼ç¨äºåæ¾ PRJOBLISTï¼ |
| | | std::vector<CJError> errors; // 失败项ï¼å« PJID 说æï¼ |
| | | uint8_t objack{ 0 }; // 0=å
¨æå, 1=é¨åæå, 2=å
¨å¤±è´¥ |
| | | }; |
| | | |
| | | // åºç¨å建/æ´æ°è¯·æ±ï¼åªç»å®å
许ç PJï¼å¹¶çæ OBJACK/é误æ¸
å |
| | | // getPjExistsFn / canJoinFn åä¸ |
| | | CreateResult applyCreate( |
| | | const CreateRequest& req, |
| | | const std::function<bool(const std::string&)>& getPjExistsFn, |
| | | const std::function<bool(const std::string&)>& canJoinFn |
| | | ); |
| | | |
| | | // ââ ç¶ææº ââ // |
| | | bool queue(); // NoState -> Queued |
| | | bool start(); // Queued -> Executing |
| | | bool pause(); // Executing -> Paused |
| | | bool resume(); // Paused -> Executing |
| | | bool complete(); // Executing/Paused -> Completed |
| | | bool abort(); // éç»æ -> Aborted |
| | | bool fail(std::string reason); // ä»»æ -> Failed |
| | | |
| | | const std::string& failReason() const noexcept { return m_failReason; } |
| | | |
| | | // ââ æ¶é´æ³ ââ // |
| | | 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; } |
| | | |
| | | // ââ æ±æ»ç¶æè¾
å©ï¼å¯éï¼ââ // |
| | | // æ ¹æ®å¤é¨æä¾çâPJ æ¯å¦å·²å®æâ夿ï¼å°è¯æ CJ èå置为 Completedã |
| | | // isPjCompletedFn(pjId)->bool |
| | | bool tryAggregateComplete(const std::function<bool(const std::string&)>& isPjCompletedFn); |
| | | |
| | | // å·¥å
·ï¼ç»ä¸å符串éå¶ |
| | | static void clampString(std::string& s, size_t maxLen); |
| | | static bool asciiPrintable(const std::string& s); |
| | | |
| | | static constexpr uint32_t CJ_MAGIC = 0x434A5031; // "CJP1" |
| | | static constexpr uint16_t CJ_VERSION = 0x0001; |
| | | |
| | | void serialize(std::ostream& os) const; |
| | | static bool deserialize(std::istream& is, CControlJob& out, std::string* err = nullptr); |
| | | |
| | | private: |
| | | void markQueued(); |
| | | void markStart(); |
| | | void markEnd(); |
| | | |
| | | protected: |
| | | // ââ æ è¯ & é
ç½® ââ // |
| | | std::string m_cjId; |
| | | uint8_t m_priority{ 5 }; // 缺çä¼å
级ï¼èªå®ï¼ |
| | | |
| | | // ââ ç»æ ââ // |
| | | std::vector<std::string> m_pjIds; |
| | | std::vector<CProcessJob*> m_pjs; |
| | | |
| | | // ââ ç¶æ / ææ¬ ââ // |
| | | CJState m_state{ CJState::NoState }; |
| | | std::string m_failReason; |
| | | |
| | | // ââ æ¶é´æ³ ââ // |
| | | 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; |
| | | |
| | | // ââ ç»ä¸çº¦æ ââ // |
| | | static constexpr size_t MAX_ID_LEN = 64; // CJID / PJID ç |
| | | |
| | | // é误å表 |
| | | std::vector<ValidationIssue> m_issues; |
| | | }; |
| | | } |
| | | |
| | |
| | | #include <future> |
| | | #include <vector> |
| | | #include "RecipeManager.h" |
| | | #include <fstream> |
| | | #include "SerializeUtil.h" |
| | | |
| | | |
| | | namespace SERVO { |
| | |
| | | m_bContinuousTransfer = false; |
| | | m_nContinuousTransferCount = 0; |
| | | m_nContinuousTransferStep = CTStep_Unknow; |
| | | m_pControlJob = nullptr; |
| | | InitializeCriticalSection(&m_criticalSection); |
| | | } |
| | | |
| | | CMaster::~CMaster() |
| | | { |
| | | // éæ¾Jobç¸å
³ |
| | | for (auto item : m_processJobs) { |
| | | delete item; |
| | | } |
| | | m_processJobs.clear(); |
| | | if (m_pControlJob != nullptr) { |
| | | delete m_pControlJob; |
| | | m_pControlJob = nullptr; |
| | | } |
| | | |
| | | if (m_hEventReadBitsThreadExit[0] != nullptr) { |
| | | ::CloseHandle(m_hEventReadBitsThreadExit[0]); |
| | |
| | | m_nContinuousTransferCount = round; |
| | | } |
| | | |
| | | int CMaster::setProcessJobs(std::vector<SERVO::CProcessJob*>& pjs) |
| | | int CMaster::setProcessJobs(std::vector<CProcessJob*>& pjs) |
| | | { |
| | | std::vector<SERVO::CProcessJob*> temp; |
| | | for (auto p : pjs) { |
| | | if (p->validate(*this)) { |
| | | p->queue(); |
| | | temp.push_back(p); |
| | | } |
| | | } |
| | | |
| | | m_processJobs = temp; |
| | | this->saveState(); |
| | | |
| | | return m_processJobs.size(); |
| | | } |
| | | |
| | | std::vector<SERVO::CProcessJob*>& CMaster::getProcessJobs() |
| | | std::vector<CProcessJob*>& CMaster::getProcessJobs() |
| | | { |
| | | return m_processJobs; |
| | | } |
| | | |
| | | CProcessJob* CMaster::getProcessJob(const std::string& id) |
| | | { |
| | | for (auto item : m_processJobs) { |
| | | if (item->id().compare(id) == 0) return item; |
| | | } |
| | | |
| | | return nullptr; |
| | | } |
| | | |
| | | int CMaster::setControlJob(CControlJob& controlJob) |
| | | { |
| | | // åè°ï¼æ¯å¦åå建ControlJob |
| | | auto canCreateCjFn = [&](uint32_t& cc, std::string& mm) -> bool { |
| | | if (m_pControlJob != nullptr) { |
| | | cc = 1100; |
| | | mm = "å½åControlJobæªç»æ¹ï¼ä¸è½å建æ°çControlJob"; |
| | | return false; |
| | | } |
| | | return true; |
| | | }; |
| | | |
| | | |
| | | // åè°ï¼æ¯å¦åå¨ |
| | | auto pjExists = [&](const std::string& id) -> bool { |
| | | return getProcessJob(id) != nullptr; |
| | | }; |
| | | |
| | | // åè°ï¼æ¯å¦å¯å å
¥ CJï¼è¿éå®ä¹ï¼å¿
é¡»æ¯ Queuedï¼ |
| | | auto pjJoinable = [&](const std::string& id) -> bool { |
| | | auto pj = getProcessJob(id); |
| | | if (pj == nullptr) return false; |
| | | return pj->state() == PJState::Queued; |
| | | }; |
| | | |
| | | bool bRet = controlJob.validateForCreate(canCreateCjFn, pjExists, pjJoinable); |
| | | if (!bRet) return -1; |
| | | |
| | | std::vector<CProcessJob*> temps; |
| | | m_pControlJob = new CControlJob(controlJob); |
| | | auto pjIds = controlJob.pjIds(); |
| | | for (auto id : pjIds) { |
| | | auto pj = getProcessJob(id); |
| | | if (pj != nullptr) { |
| | | temps.push_back(pj); |
| | | } |
| | | } |
| | | m_pControlJob->setPJs(temps); |
| | | this->saveState(); |
| | | |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | CLoadPort* CMaster::getPortWithCarrierId(const std::string& carrierId) const |
| | |
| | | return true; |
| | | } |
| | | |
| | | bool CMaster::saveState() const |
| | | { |
| | | std::ofstream ofs(m_strStatePath, std::ios::binary); |
| | | if (!ofs) return false; |
| | | |
| | | // æä»¶å¤´ |
| | | uint32_t magic = 0x4D415354; // 'MAST' |
| | | uint16_t version = 1; |
| | | ofs.write(reinterpret_cast<const char*>(&magic), sizeof(magic)); |
| | | ofs.write(reinterpret_cast<const char*>(&version), sizeof(version)); |
| | | |
| | | // ä¿å ControlJob |
| | | bool hasCJ = (m_pControlJob != nullptr); |
| | | ofs.write(reinterpret_cast<const char*>(&hasCJ), sizeof(hasCJ)); |
| | | if (hasCJ) { |
| | | m_pControlJob->serialize(ofs); |
| | | } |
| | | |
| | | // ä¿å ProcessJob å表 |
| | | uint32_t count = static_cast<uint32_t>(m_processJobs.size()); |
| | | ofs.write(reinterpret_cast<const char*>(&count), sizeof(count)); |
| | | for (const auto& job : m_processJobs) { |
| | | job->serialize(ofs); |
| | | } |
| | | |
| | | // 以åå¯ä»¥å¨è¿éè¿½å æ°å段 |
| | | return true; |
| | | } |
| | | |
| | | bool CMaster::loadState(const std::string& path) |
| | | { |
| | | // ä¿åæä»¶è·¯å¾ |
| | | m_strStatePath = path; |
| | | |
| | | |
| | | std::ifstream ifs(path, std::ios::binary); |
| | | if (!ifs) return false; |
| | | |
| | | // æä»¶å¤´ |
| | | uint32_t magic = 0; |
| | | uint16_t version = 0; |
| | | ifs.read(reinterpret_cast<char*>(&magic), sizeof(magic)); |
| | | ifs.read(reinterpret_cast<char*>(&version), sizeof(version)); |
| | | |
| | | if (magic != 0x4D415354) { |
| | | // æä»¶ä¸åæ³ |
| | | return false; |
| | | } |
| | | |
| | | if (m_pControlJob != nullptr) { |
| | | delete m_pControlJob; |
| | | m_pControlJob = nullptr; |
| | | } |
| | | |
| | | // 读å ControlJob |
| | | bool hasCJ = false; |
| | | ifs.read(reinterpret_cast<char*>(&hasCJ), sizeof(hasCJ)); |
| | | if (hasCJ) { |
| | | m_pControlJob = new CControlJob(); |
| | | if (!CControlJob::deserialize(ifs, *m_pControlJob)) return false; |
| | | } |
| | | |
| | | |
| | | // 读å ProcessJob å表 |
| | | uint32_t count = 0; |
| | | ifs.read(reinterpret_cast<char*>(&count), sizeof(count)); |
| | | m_processJobs.clear(); |
| | | for (uint32_t i = 0; i < count; i++) { |
| | | CProcessJob* pProcessJob = new CProcessJob(); |
| | | if (!CProcessJob::deserialize(ifs, *pProcessJob)) return false; |
| | | m_processJobs.push_back(pProcessJob); |
| | | } |
| | | |
| | | // å¦æçæ¬å级ï¼å¯å¨è¿é夿 version æ¥å è½½æ°å段 |
| | | |
| | | |
| | | return true; |
| | | } |
| | | } |
| | |
| | | #include "CCLinkIEControl.h" |
| | | #include "CRobotTask.h" |
| | | #include "ProcessJob.h" |
| | | #include "CControlJob.h" |
| | | |
| | | |
| | | #define CTStep_Unknow 0 |
| | |
| | | int carrierRelease(unsigned int port); |
| | | int getContinuousTransferCount(); |
| | | void setContinuousTransferCount(int round); |
| | | int setProcessJobs(std::vector<SERVO::CProcessJob*>& pjs); |
| | | std::vector<SERVO::CProcessJob*>& getProcessJobs(); |
| | | int setProcessJobs(std::vector<CProcessJob*>& pjs); |
| | | std::vector<CProcessJob*>& getProcessJobs(); |
| | | CProcessJob* getProcessJob(const std::string& id); |
| | | int setControlJob(CControlJob& controlJob); |
| | | CLoadPort* getPortWithCarrierId(const std::string& carrierId) const; |
| | | bool saveState() const; |
| | | bool loadState(const std::string& path); |
| | | |
| | | private: |
| | | inline void lock() { EnterCriticalSection(&m_criticalSection); } |
| | |
| | | private: |
| | | bool m_bEnableEventReport; |
| | | bool m_bEnableAlarmReport; |
| | | SERVO::CControlJob* m_pControlJob; |
| | | std::vector<SERVO::CProcessJob*> m_processJobs; |
| | | std::string m_strStatePath; |
| | | }; |
| | | } |
| | | |
| | |
| | | else if (nStream == 10 && pHeader->function == 3) { |
| | | replyTerminalDisplay(pMessage); |
| | | } |
| | | else if (nStream == 14 && pHeader->function == 9) { |
| | | replyCreateObj(pMessage); |
| | | } |
| | | else if (nStream == 16 && pHeader->function == 15) { |
| | | replyPRJobMultiCreate(pMessage); |
| | | } |
| | |
| | | return 0; |
| | | } |
| | | |
| | | // S14F9 |
| | | int CHsmsPassive::replyCreateObj(IMessage* pRecv) |
| | | { |
| | | if (m_pPassive == NULL || STATE::SELECTED != m_pPassive->getState()) { |
| | | return ER_NOTSELECT; |
| | | } |
| | | ISECS2Item* pBody = pRecv->getBody(); |
| | | if (pBody == nullptr || pBody->getType() != SITYPE::L) ER_PARAM_ERROR; |
| | | |
| | | |
| | | // æ¯å¦å建æåå¹¶åå¤å夿¥æ |
| | | bool bCreateOk = false; |
| | | IMessage* pReply = NULL; |
| | | HSMS_Create1Message(pReply, m_nSessionId, 14, 10, ++m_nSystemByte); |
| | | ASSERT(pReply); |
| | | |
| | | |
| | | |
| | | // è§£éæ°æ®ï¼å¾å°ControlJob |
| | | ISECS2Item* pItemAttrs, * pItemAttr, *pItemAttrData; |
| | | const char* pszObjSpec, *pszObjType, *pszAttrId, *pszProcessJobId; |
| | | std::string strObjName, strObjId; |
| | | if (!pBody->getSubItemString(0, pszObjSpec)) return ER_PARAM_ERROR; |
| | | if (!pBody->getSubItemString(1, pszObjType)) return ER_PARAM_ERROR; |
| | | |
| | | pReply->getBody()->addItem(pszObjSpec, "OBJSPEC"); |
| | | ISECS2Item* pReplyItemAttrs = pReply->getBody()->addItem(); |
| | | ISECS2Item* pReplyItemAcks = pReply->getBody()->addItem(); |
| | | ISECS2Item* pReplyItemAck = pReplyItemAcks->addU1Item(0, "OBJACK"); |
| | | ISECS2Item* pReplyItemErrs = pReplyItemAcks->addItem(); |
| | | |
| | | // å½ååªå¤çç±»å为ControlJob |
| | | if (_strcmpi(pszObjType, "ControlJob") == 0) { |
| | | |
| | | // ç±»id |
| | | std::regex re("^([^:]+):([^>]+)>"); |
| | | std::smatch match; |
| | | std::string strObjSpec(pszObjSpec); |
| | | if (!std::regex_search(strObjSpec, match, re)) { |
| | | ISECS2Item* pItemError = pReplyItemErrs->addItem(); |
| | | pItemError->addU4Item(2001, "ERRCODE"); |
| | | pItemError->addItem("åæ°ææ¥æä¸æ£ç¡®", "ERRTEXT"); |
| | | goto MYREPLY; |
| | | } |
| | | |
| | | if (match[1].compare("ControlJob") != 0) { |
| | | ISECS2Item* pItemError = pReplyItemErrs->addItem(); |
| | | pItemError->addU4Item(2001, "ERRCODE"); |
| | | pItemError->addItem("䏿¯æçOBJ", "ERRTEXT"); |
| | | goto MYREPLY; |
| | | } |
| | | strObjId = match[2]; |
| | | |
| | | // å建类CControlJob |
| | | SERVO::CControlJob controlJob(strObjId); |
| | | |
| | | // ç±»å±æ§ |
| | | pItemAttrs = pBody->getSubItem(2); |
| | | if (pItemAttrs == nullptr) return ER_PARAM_ERROR; |
| | | for (int i = 0; i < pItemAttrs->getSubItemSize(); i++) { |
| | | pItemAttr = pItemAttrs->getSubItem(i); |
| | | if (pItemAttr == nullptr) continue; |
| | | if (!pItemAttr->getSubItemString(0, pszAttrId)) continue; |
| | | if (_strcmpi(pszAttrId, CJ_ATTR_PRIORITY) == 0) { |
| | | uint8_t priority; |
| | | if (pItemAttr->getSubItemU1(1, priority)) { |
| | | controlJob.setPriority(priority); |
| | | } |
| | | } |
| | | else if (_strcmpi(pszAttrId, CJ_ATTR_PRJOBLIST) == 0) { |
| | | pItemAttrData = pItemAttr->getSubItem(1); |
| | | if (pItemAttrData != nullptr && pItemAttrData->getType() == SITYPE::L) { |
| | | for (int i = 0; i < pItemAttrData->getSubItemSize(); i++) { |
| | | if (pItemAttrData->getSubItemString(i, pszProcessJobId)) { |
| | | std::string strProcessJobId(pszProcessJobId); |
| | | controlJob.addPJ(strProcessJobId); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | ASSERT(m_listener.onControlJobCreate != nullptr); |
| | | int nRet = m_listener.onControlJobCreate(this, controlJob); |
| | | bCreateOk = nRet == 0; |
| | | |
| | | // æ·»å æ°å»ºç±»çåç§å±æ§å°å夿¥æä¸ |
| | | if(bCreateOk) { |
| | | { |
| | | ISECS2Item* pReplyItemAttr = pReplyItemAttrs->addItem(); |
| | | pReplyItemAttr->addItem(CJ_ATTR_PRIORITY, "ATTRID"); |
| | | pReplyItemAttr->addU1Item(controlJob.priority(), "ATTRDATA"); |
| | | } |
| | | |
| | | { |
| | | ISECS2Item* pReplyItemAttr = pReplyItemAttrs->addItem(); |
| | | pReplyItemAttr->addItem(CJ_ATTR_PRJOBLIST, "ATTRID"); |
| | | ISECS2Item* pItemPjs = pReplyItemAttr->addItem(); |
| | | auto pjIds = controlJob.pjIds(); |
| | | for (auto id : pjIds) { |
| | | pItemPjs->addItem(id.c_str(), "PRJOBID"); |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | auto issues = controlJob.issues(); |
| | | for (auto i : issues) { |
| | | ISECS2Item* pItemError = pReplyItemErrs->addItem(); |
| | | pItemError->addU4Item(i.code, "ERRCODE"); |
| | | pItemError->addItem(i.text.c_str(), "ERRTEXT"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | else { |
| | | ISECS2Item* pItemError = pReplyItemErrs->addItem(); |
| | | pItemError->addU4Item(2001, "ERRCODE"); |
| | | pItemError->addItem("䏿¯æçOBJ", "ERRTEXT"); |
| | | } |
| | | |
| | | |
| | | // å®åæ¥æå¹¶åå¤ |
| | | MYREPLY: |
| | | pReplyItemAck->setU1(bCreateOk ? 0 : 1, "OBJACK"); |
| | | m_pPassive->sendMessage(pReply); |
| | | LOGI("<HSMS>[SECS Msg SEND]S14F10 (SysByte=%u)", pReply->getHeader()->systemBytes); |
| | | HSMS_Destroy1Message(pReply); |
| | | |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | // S16F15 |
| | | int CHsmsPassive::replyPRJobMultiCreate(IMessage* pRecv) |
| | | { |
| | |
| | | ISECS2Item* pItemErrors = pMessage->getBody()->addItem(); |
| | | bool bHasError = false; |
| | | for (auto p : pjs) { |
| | | if (p->issue().empty()) { |
| | | if (p->issues().empty()) { |
| | | pItemPrjobIds->addItem(p->id().c_str(), "PRJOBID"); |
| | | } |
| | | else { |
| | |
| | | pItemErrors->addBoolItem(false, "ACKA"); |
| | | ISECS2Item* pItemErrors2 = pItemErrors->addItem(); |
| | | for (auto p : pjs) { |
| | | if (!p->issue().empty()) { |
| | | if (!p->issues().empty()) { |
| | | ISECS2Item* pItemErr = pItemErrors2->addItem(); |
| | | pItemErr->addU4Item(p->issue()[0].code, "ERRCODE"); |
| | | pItemErr->addItem(("<" + p->id() + ">" + p->issue()[0].text).c_str(), "ERRTEXT"); |
| | | pItemErr->addU4Item(p->issues()[0].code, "ERRCODE"); |
| | | pItemErr->addItem(("<" + p->id() + ">" + p->issues()[0].text).c_str(), "ERRTEXT"); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | // éæ¾æé®é¢(æªæ·»å å°master)çå
å |
| | | for (auto p : pjs) { |
| | | if(!p->issue().empty()) delete p; |
| | | if(!p->issues().empty()) delete p; |
| | | } |
| | | pjs.clear(); |
| | | |
| | |
| | | #include <set> |
| | | #include "CCollectionEvent.h" |
| | | #include "ProcessJob.h" |
| | | #include "CControlJob.h" |
| | | |
| | | |
| | | #define EQCONSTANT_VALUE_MAX 64 |
| | |
| | | unsigned char PTN, |
| | | std::string& strErrorTxt)> CARRIERACTION; |
| | | typedef std::function<int(void* pFrom, std::vector<SERVO::CProcessJob*>& pjs)> PRJOBMULTICREATE; |
| | | typedef std::function<int(void* pFrom, SERVO::CControlJob& controlJob)> CONTROLJOBCREATE; |
| | | typedef struct _SECSListener |
| | | { |
| | | SECSEQOFFLINE onEQOffLine; |
| | |
| | | QUERYPPIDLIST onQueryPPIDList; |
| | | CARRIERACTION onCarrierAction; |
| | | PRJOBMULTICREATE onPRJobMultiCreate; |
| | | CONTROLJOBCREATE onControlJobCreate; |
| | | } SECSListener; |
| | | |
| | | |
| | |
| | | int replyPurgeSpooledData(IMessage* pRecv); |
| | | int replyQueryPPIDList(IMessage* pRecv); |
| | | int replyTerminalDisplay(IMessage* pRecv); |
| | | int replyCreateObj(IMessage* pRecv); |
| | | int replyPRJobMultiCreate(IMessage* pRecv); |
| | | |
| | | private: |
| | |
| | | ::CreateDirectory(strLogDir, NULL); |
| | | CLog::GetLog()->SetOnLogCallback([&](int level, const char* pszMessage) -> void { |
| | | notifyTextAndInt(RX_CODE_LOG, pszMessage, level); |
| | | }); |
| | | }); |
| | | CLog::GetLog()->SetAutoAppendTimeString(TRUE); |
| | | CLog::GetLog()->SetOutputTarget(OT_FILE); |
| | | CLog::GetLog()->SetLogsDir(strLogDir); |
| | |
| | | listener.onEQConstantRequest = [&](void* pFrom, std::vector<EQConstant>& eqcs) -> void { |
| | | // 卿¤å¡«å
常éå¼ï¼ç®åä»
æ¯å 1åè¿å |
| | | for (auto& item : eqcs) { |
| | | sprintf_s(item.szValue, 256, "Test%d", item.id+1); |
| | | sprintf_s(item.szValue, 256, "Test%d", item.id + 1); |
| | | } |
| | | }; |
| | | listener.onEQConstantSend = [&](void* pFrom, std::vector<EQConstant>& eqcs) -> void { |
| | |
| | | } |
| | | return ppids; |
| | | }; |
| | | listener.onCarrierAction = [&](void* pFrom, |
| | | unsigned int DATAID, |
| | | listener.onCarrierAction = [&](void* pFrom, |
| | | unsigned int DATAID, |
| | | const char* pszCarrierAction, |
| | | const char* pszCarrierId, |
| | | unsigned char PTN, |
| | |
| | | |
| | | m_hsmsPassive.setVariableValue("PJQueued", vars); |
| | | m_hsmsPassive.requestEventReportSend_PJ_Queued(); |
| | | return nRet; |
| | | }; |
| | | listener.onControlJobCreate = [&](void* pFrom, SERVO::CControlJob& controlJob) -> int { |
| | | LOGI("<Model>onControlJobCreate %s %d", controlJob.id().c_str(), controlJob.priority()); |
| | | int nRet = m_master.setControlJob(controlJob); |
| | | return nRet; |
| | | }; |
| | | m_hsmsPassive.setListener(listener); |
| | |
| | | m_master.setCacheFilepath((LPTSTR)(LPCTSTR)strMasterDataFile); |
| | | m_master.setCompareMapsBeforeProceeding(m_configuration.isCompareMapsBeforeProceeding()); |
| | | |
| | | // å æªJob |
| | | strMasterDataFile.Format(_T("%s\\MasterState.dat"), (LPTSTR)(LPCTSTR)m_strWorkDir); |
| | | std::string strPath = std::string((LPTSTR)(LPCTSTR)strMasterDataFile); |
| | | if (!m_master.loadState(strPath)) { |
| | | LOGE("<Master>å è½½MasterState.datæä»¶å¤±è´¥."); |
| | | } |
| | | |
| | | |
| | | // å è½½è¦åä¿¡æ¯ |
| | | AlarmManager& alarmManager = AlarmManager::getInstance(); |
| | | char szBuffer[MAX_PATH]; |
| | |
| | | #include "stdafx.h" |
| | | #include "ProcessJob.h" |
| | | #include <cctype> |
| | | #include <fstream> |
| | | #include "SerializeUtil.h" |
| | | |
| | | |
| | | namespace SERVO { |
| | | static inline std::string trimCopy(std::string s) { |
| | |
| | | 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; |
| | | } |
| | | |
| | | CProcessJob::CProcessJob() |
| | | { |
| | | |
| | | } |
| | | |
| | | CProcessJob::CProcessJob(std::string pjId) |
| | |
| | | m_pauseEvents.erase(std::unique(m_pauseEvents.begin(), m_pauseEvents.end()), m_pauseEvents.end()); |
| | | } |
| | | |
| | | const std::vector<CProcessJob::ValidationIssue>& CProcessJob::issue() |
| | | const std::vector<CProcessJob::ValidationIssue>& CProcessJob::issues() |
| | | { |
| | | return m_issues; |
| | | } |
| | |
| | | m_carriers.emplace_back(std::move(cs)); |
| | | } |
| | | } |
| | | |
| | | // --------- æ ¸å¿ï¼serialize/deserialize --------- |
| | | void CProcessJob::serialize(std::ostream& os) const { |
| | | // Í· |
| | | write_pod(os, PJ_FILE_MAGIC); |
| | | write_pod(os, PJ_FILE_VERSION); |
| | | |
| | | // åºæ¬ |
| | | write_string(os, m_pjId); |
| | | write_string(os, m_parentCjId); |
| | | |
| | | // é
æ¹ |
| | | uint8_t recipeType = static_cast<uint8_t>(m_recipeMethod); |
| | | write_pod(os, m_recipeMethod); |
| | | write_string(os, m_recipeSpec); |
| | | |
| | | // ç©æï¼å¤ Carrier & Slotï¼ |
| | | { |
| | | uint32_t n = static_cast<uint32_t>(m_carriers.size()); |
| | | write_pod(os, n); |
| | | for (const auto& cs : m_carriers) { |
| | | write_string(os, cs.carrierId); |
| | | write_vec<uint8_t>(os, cs.slots); |
| | | } |
| | | } |
| | | |
| | | // åæ° |
| | | { |
| | | uint32_t n = static_cast<uint32_t>(m_params.size()); |
| | | write_pod(os, n); |
| | | for (const auto& p : m_params) { |
| | | write_string(os, p.name); |
| | | write_string(os, p.value); |
| | | } |
| | | } |
| | | |
| | | // æåäºä»¶ |
| | | write_vec<uint32_t>(os, m_pauseEvents); |
| | | |
| | | // å¯å¨çç¥ & ç¶æ |
| | | uint8_t startPolicy = static_cast<uint8_t>(m_startPolicy); |
| | | uint8_t st = static_cast<uint8_t>(m_state); |
| | | write_pod(os, startPolicy); |
| | | write_pod(os, st); |
| | | |
| | | // 失败åå |
| | | write_string(os, m_failReason); |
| | | |
| | | // æ¶é´æ³ |
| | | write_opt_time(os, m_tQueued); |
| | | write_opt_time(os, m_tStart); |
| | | write_opt_time(os, m_tEnd); |
| | | } |
| | | |
| | | bool CProcessJob::deserialize(std::istream& is, CProcessJob& out, std::string* err) { |
| | | auto fail = [&](const char* msg) { if (err) *err = msg; return false; }; |
| | | |
| | | uint32_t magic = 0; if (!read_pod(is, magic)) return fail("read magic failed"); |
| | | if (magic != PJ_FILE_MAGIC) return fail("bad magic"); |
| | | |
| | | uint16_t ver = 0; if (!read_pod(is, ver)) return fail("read version failed"); |
| | | if (ver != PJ_FILE_VERSION) return fail("unsupported version"); |
| | | |
| | | // åºæ¬ |
| | | if (!read_string(is, out.m_pjId)) return fail("read pjId"); |
| | | if (!read_string(is, out.m_parentCjId)) return fail("read parentCjId"); |
| | | |
| | | // é
æ¹ |
| | | uint8_t recipeType = 0; if (!read_pod(is, recipeType)) return fail("read recipeType"); |
| | | out.m_recipeMethod = static_cast<RecipeMethod>(recipeType); |
| | | if (!read_string(is, out.m_recipeSpec)) return fail("read recipeSpec"); |
| | | |
| | | // ç©æ |
| | | { |
| | | uint32_t n = 0; if (!read_pod(is, n)) return fail("read carriers count"); |
| | | out.m_carriers.clear(); out.m_carriers.reserve(n); |
| | | for (uint32_t i = 0; i < n; ++i) { |
| | | CarrierSlotInfo cs; |
| | | if (!read_string(is, cs.carrierId)) return fail("read carrierId"); |
| | | if (!read_vec<uint8_t>(is, cs.slots)) return fail("read slots"); |
| | | out.m_carriers.emplace_back(std::move(cs)); |
| | | } |
| | | } |
| | | |
| | | // åæ° |
| | | { |
| | | uint32_t n = 0; if (!read_pod(is, n)) return fail("read params count"); |
| | | out.m_params.clear(); out.m_params.reserve(n); |
| | | for (uint32_t i = 0; i < n; ++i) { |
| | | PJParam p; |
| | | if (!read_string(is, p.name)) return fail("read param name"); |
| | | if (!read_string(is, p.value)) return fail("read param value"); |
| | | out.m_params.emplace_back(std::move(p)); |
| | | } |
| | | } |
| | | |
| | | // æåäºä»¶ |
| | | if (!read_vec<uint32_t>(is, out.m_pauseEvents)) return fail("read pauseEvents"); |
| | | |
| | | // å¯å¨çç¥ & ç¶æ |
| | | uint8_t startPolicy = 0, st = 0; |
| | | if (!read_pod(is, startPolicy)) return fail("read startPolicy"); |
| | | if (!read_pod(is, st)) return fail("read state"); |
| | | out.m_startPolicy = static_cast<StartPolicy>(startPolicy); |
| | | out.m_state = static_cast<PJState>(st); |
| | | |
| | | // 失败åå |
| | | if (!read_string(is, out.m_failReason)) return fail("read failReason"); |
| | | |
| | | // æ¶é´æ³ |
| | | if (!read_opt_time(is, out.m_tQueued)) return fail("read tQueued"); |
| | | if (!read_opt_time(is, out.m_tStart)) return fail("read tStart"); |
| | | if (!read_opt_time(is, out.m_tEnd)) return fail("read tEnd"); |
| | | |
| | | return true; |
| | | } |
| | | } |
| | |
| | | class CProcessJob { |
| | | public: |
| | | // ââ æé / åºæ¬è®¾ç½® ââ |
| | | CProcessJob(); |
| | | explicit CProcessJob(std::string pjId); |
| | | |
| | | const std::string& id() const noexcept { return m_pjId; } |
| | |
| | | }; |
| | | // è¿åé®é¢æ¸
åï¼ç©º=éè¿ï¼ |
| | | bool validate(const IResourceView& rv); |
| | | const std::vector<ValidationIssue>& issue(); |
| | | const std::vector<ValidationIssue>& issues(); |
| | | |
| | | // ââ ç¶ææºï¼å¸¦å®å«ï¼ââ |
| | | bool queue(); // NoState -> Queued |
| | |
| | | bool usesCarrierSlots() const noexcept { return !m_carriers.empty(); } |
| | | |
| | | |
| | | public: |
| | | // ====== çæ¬å¤´å¸¸éï¼å»ºè®®ä¿çï¼ä¾¿äºå
¼å®¹ï¼====== |
| | | static constexpr uint32_t PJ_FILE_MAGIC = 0x504A4A31; // "PJJ1" |
| | | static constexpr uint16_t PJ_FILE_VERSION = 0x0001; |
| | | |
| | | // ====== æµå¼åºååæ¥å£ ====== |
| | | void serialize(std::ostream& os) const; |
| | | static bool deserialize(std::istream& is, CProcessJob& out, std::string* err = nullptr); |
| | | |
| | | private: |
| | | // å
é¨ç¶æè½¬ç§»å¸®å© |
| | | void markQueued(); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | #pragma once |
| | | #include <fstream> |
| | | |
| | | |
| | | // --------- ç§æ/å
é¨ï¼è¯»åå·¥å
· --------- |
| | | namespace SERVO { |
| | | template<typename T> |
| | | inline void write_pod(std::ostream& os, const T& v) { |
| | | os.write(reinterpret_cast<const char*>(&v), sizeof(T)); |
| | | } |
| | | template<typename T> |
| | | inline bool read_pod(std::istream& is, T& v) { |
| | | return bool(is.read(reinterpret_cast<char*>(&v), sizeof(T))); |
| | | } |
| | | |
| | | inline void write_string(std::ostream& os, const std::string& s) { |
| | | uint32_t n = static_cast<uint32_t>(s.size()); |
| | | write_pod(os, n); |
| | | if (n) os.write(s.data(), n); |
| | | } |
| | | inline bool read_string(std::istream& is, std::string& s) { |
| | | uint32_t n = 0; if (!read_pod(is, n)) return false; |
| | | s.resize(n); |
| | | if (n) return bool(is.read(&s[0], n)); |
| | | return true; |
| | | } |
| | | |
| | | template<typename T> |
| | | inline void write_vec(std::ostream& os, const std::vector<T>& v) { |
| | | uint32_t n = static_cast<uint32_t>(v.size()); |
| | | write_pod(os, n); |
| | | if (n) os.write(reinterpret_cast<const char*>(v.data()), sizeof(T) * n); |
| | | } |
| | | template<typename T> |
| | | inline bool read_vec(std::istream& is, std::vector<T>& v) { |
| | | uint32_t n = 0; if (!read_pod(is, n)) return false; |
| | | v.resize(n); |
| | | if (n) return bool(is.read(reinterpret_cast<char*>(v.data()), sizeof(T) * n)); |
| | | return true; |
| | | } |
| | | |
| | | // vector<string> ç¹åå读 |
| | | inline void write_vec_str(std::ostream& os, const std::vector<std::string>& v) { |
| | | uint32_t n = static_cast<uint32_t>(v.size()); |
| | | write_pod(os, n); |
| | | for (const auto& s : v) write_string(os, s); |
| | | } |
| | | inline bool read_vec_str(std::istream& is, std::vector<std::string>& v) { |
| | | uint32_t n = 0; if (!read_pod(is, n)) return false; |
| | | v.clear(); v.reserve(n); |
| | | for (uint32_t i = 0; i < n; ++i) { std::string s; if (!read_string(is, s)) return false; v.emplace_back(std::move(s)); } |
| | | return true; |
| | | } |
| | | |
| | | // optional<time_point> â bool + int64 (ms since epoch) |
| | | inline void write_opt_time(std::ostream& os, const std::optional<std::chrono::system_clock::time_point>& tp) { |
| | | uint8_t has = tp.has_value() ? 1 : 0; |
| | | write_pod(os, has); |
| | | if (has) { |
| | | auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(tp->time_since_epoch()).count(); |
| | | int64_t v = static_cast<int64_t>(ms); |
| | | write_pod(os, v); |
| | | } |
| | | } |
| | | inline bool read_opt_time(std::istream& is, std::optional<std::chrono::system_clock::time_point>& tp) { |
| | | uint8_t has = 0; if (!read_pod(is, has)) return false; |
| | | if (!has) { tp.reset(); return true; } |
| | | int64_t v = 0; if (!read_pod(is, v)) return false; |
| | | tp = std::chrono::system_clock::time_point(std::chrono::milliseconds(v)); |
| | | return true; |
| | | } |
| | | } |
| | |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ClInclude Include="CBaseDlg.h" /> |
| | | <ClInclude Include="CControlJob.h" /> |
| | | <ClInclude Include="CCustomCheckBox.h" /> |
| | | <ClInclude Include="CCollectionEvent.h" /> |
| | | <ClInclude Include="CEquipmentPage3.h" /> |
| | |
| | | <ClInclude Include="Resource.h" /> |
| | | <ClInclude Include="SECSRuntimeManager.h" /> |
| | | <ClInclude Include="SecsTestDlg.h" /> |
| | | <ClInclude Include="SerializeUtil.h" /> |
| | | <ClInclude Include="Servo.h" /> |
| | | <ClInclude Include="ServoCommo.h" /> |
| | | <ClInclude Include="ServoDlg.h" /> |
| | |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ClCompile Include="CBaseDlg.cpp" /> |
| | | <ClCompile Include="CControlJob.cpp" /> |
| | | <ClCompile Include="CCustomCheckBox.cpp" /> |
| | | <ClCompile Include="CCollectionEvent.cpp" /> |
| | | <ClCompile Include="CEquipmentPage3.cpp" /> |
| | |
| | | <ClCompile Include="CPageReport.cpp" /> |
| | | <ClCompile Include="CPageCollectionEvent.cpp" /> |
| | | <ClCompile Include="ProcessJob.cpp" /> |
| | | <ClCompile Include="CControlJob.cpp" /> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ClInclude Include="AlarmManager.h" /> |
| | |
| | | <ClInclude Include="CPageReport.h" /> |
| | | <ClInclude Include="CPageCollectionEvent.h" /> |
| | | <ClInclude Include="ProcessJob.h" /> |
| | | <ClInclude Include="CControlJob.h" /> |
| | | <ClInclude Include="SerializeUtil.h" /> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ResourceCompile Include="Servo.rc" /> |