From 3e0ceaf4e569ea1f57a14de2f6135d1f1a50d080 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期三, 27 八月 2025 13:47:31 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang
---
SourceCode/Bond/Servo/CControlJob.cpp | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 336 insertions(+), 0 deletions(-)
diff --git a/SourceCode/Bond/Servo/CControlJob.cpp b/SourceCode/Bond/Servo/CControlJob.cpp
new file mode 100644
index 0000000..8dc2b18
--- /dev/null
+++ b/SourceCode/Bond/Servo/CControlJob.cpp
@@ -0,0 +1,336 @@
+#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;
+ }
+
+ 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 "";
+ }
+}
--
Gitblit v1.9.3