From 8908f3613d5ca848249179d8c361576078f9781f Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期一, 18 八月 2025 17:12:10 +0800
Subject: [PATCH] 1.实现Create CJ功能和模拟测试;
---
SourceCode/Bond/Servo/Servo.vcxproj | 2
SourceCode/Bond/Servo/HsmsPassive.h | 4
SourceCode/Bond/Servo/ProcessJob.h | 2
SourceCode/Bond/Servo/ProcessJob.cpp | 2
SourceCode/Bond/Servo/CControlJob.cpp | 224 ++++++++++++++++++
SourceCode/Bond/Servo/CControlJob.h | 144 ++++++++++++
SourceCode/Bond/EAPSimulator/CHsmsActive.h | 3
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h | 1
SourceCode/Bond/Servo/HsmsPassive.cpp | 147 +++++++++++
SourceCode/Bond/EAPSimulator/EAPSimulator.rc | 0
SourceCode/Bond/Servo/CMaster.h | 8
SourceCode/Bond/Servo/Model.cpp | 13
SourceCode/Bond/EAPSimulator/CHsmsActive.cpp | 44 +++
SourceCode/Bond/EAPSimulator/Resource.h | 2
SourceCode/Bond/HSMSSDK/Include/ISECS2Item.h | 1
SourceCode/Bond/Servo/Servo.vcxproj.filters | 2
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp | 8
SourceCode/Bond/Servo/CMaster.cpp | 61 ++++
18 files changed, 653 insertions(+), 15 deletions(-)
diff --git a/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp b/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
index 7969e15..b334708 100644
--- a/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
+++ b/SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
@@ -385,6 +385,50 @@
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;
diff --git a/SourceCode/Bond/EAPSimulator/CHsmsActive.h b/SourceCode/Bond/EAPSimulator/CHsmsActive.h
index 4ea6387..29abeb5 100644
--- a/SourceCode/Bond/EAPSimulator/CHsmsActive.h
+++ b/SourceCode/Bond/EAPSimulator/CHsmsActive.h
@@ -89,6 +89,9 @@
// 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);
diff --git a/SourceCode/Bond/EAPSimulator/EAPSimulator.rc b/SourceCode/Bond/EAPSimulator/EAPSimulator.rc
index 245a5d1..53eb764 100644
--- a/SourceCode/Bond/EAPSimulator/EAPSimulator.rc
+++ b/SourceCode/Bond/EAPSimulator/EAPSimulator.rc
Binary files differ
diff --git a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
index 13bb28c..e15ff68 100644
--- a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
+++ b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
@@ -94,6 +94,7 @@
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()
@@ -286,6 +287,7 @@
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()
@@ -414,3 +416,9 @@
CPJsDlg dlg;
dlg.DoModal();
}
+
+void CEAPSimulatorDlg::OnBnClickedButtonCreateCj()
+{
+ std::vector<std::string> processJobIds = {"PJ0001", "PJ0003"};
+ theApp.m_model.m_pHsmsActive->hsmsCreateControlJob("CJ5007", processJobIds);
+}
diff --git a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
index e289190..e10cf1a 100644
--- a/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
+++ b/SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
@@ -62,4 +62,5 @@
afx_msg void OnBnClickedButtonQueryCjSpace();
afx_msg void OnBnClickedButtonQueryPjSpace();
afx_msg void OnBnClickedButtonCreatePj();
+ afx_msg void OnBnClickedButtonCreateCj();
};
diff --git a/SourceCode/Bond/EAPSimulator/Resource.h b/SourceCode/Bond/EAPSimulator/Resource.h
index 6f261c8..96c191e 100644
--- a/SourceCode/Bond/EAPSimulator/Resource.h
+++ b/SourceCode/Bond/EAPSimulator/Resource.h
@@ -54,6 +54,8 @@
#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
diff --git a/SourceCode/Bond/HSMSSDK/Include/ISECS2Item.h b/SourceCode/Bond/HSMSSDK/Include/ISECS2Item.h
index b3bfa28..09b9ed0 100644
--- a/SourceCode/Bond/HSMSSDK/Include/ISECS2Item.h
+++ b/SourceCode/Bond/HSMSSDK/Include/ISECS2Item.h
@@ -70,5 +70,6 @@
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;
};
diff --git a/SourceCode/Bond/Servo/CControlJob.cpp b/SourceCode/Bond/Servo/CControlJob.cpp
new file mode 100644
index 0000000..3f0237b
--- /dev/null
+++ b/SourceCode/Bond/Servo/CControlJob.cpp
@@ -0,0 +1,224 @@
+#include "stdafx.h"
+#include "CControlJob.h"
+#include <cctype>
+
+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(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;
+ });
+ }
+}
diff --git a/SourceCode/Bond/Servo/CControlJob.h b/SourceCode/Bond/Servo/CControlJob.h
new file mode 100644
index 0000000..a9611a4
--- /dev/null
+++ b/SourceCode/Bond/Servo/CControlJob.h
@@ -0,0 +1,144 @@
+#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:
+ 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);
+
+ private:
+ void markQueued();
+ void markStart();
+ void markEnd();
+
+ private:
+ // —— 标识 & 配置 —— //
+ 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;
+ };
+}
+
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index ccd1f5d..81a0115 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -58,15 +58,21 @@
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]);
@@ -1847,11 +1853,12 @@
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);
}
}
@@ -1860,11 +1867,61 @@
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);
+ return 0;
+ }
+
CLoadPort* CMaster::getPortWithCarrierId(const std::string& carrierId) const
{
CLoadPort* pPort;
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index 6cb2965..d43642d 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -14,6 +14,7 @@
#include "CCLinkIEControl.h"
#include "CRobotTask.h"
#include "ProcessJob.h"
+#include "CControlJob.h"
#define CTStep_Unknow 0
@@ -105,8 +106,10 @@
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;
private:
@@ -191,6 +194,7 @@
private:
bool m_bEnableEventReport;
bool m_bEnableAlarmReport;
+ SERVO::CControlJob* m_pControlJob;
std::vector<SERVO::CProcessJob*> m_processJobs;
};
}
diff --git a/SourceCode/Bond/Servo/HsmsPassive.cpp b/SourceCode/Bond/Servo/HsmsPassive.cpp
index b71785e..689920b 100644
--- a/SourceCode/Bond/Servo/HsmsPassive.cpp
+++ b/SourceCode/Bond/Servo/HsmsPassive.cpp
@@ -632,6 +632,9 @@
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);
}
@@ -1538,6 +1541,140 @@
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);
+
+
+
+ // 瑙i噴鏁版嵁锛屽緱鍒癈ontrolJob
+ 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) {
+
+ // 绫籭d
+ 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("鍙傛暟鎴栨姤鏂囦笉姝g‘", "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];
+
+ // 鍒涘缓绫籆ControlJob
+ 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)
{
@@ -1611,7 +1748,7 @@
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 {
@@ -1622,10 +1759,10 @@
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");
}
}
}
@@ -1636,7 +1773,7 @@
// 閲婃斁鏈夐棶棰�(鏈坊鍔犲埌master)鐨勫唴瀛�
for (auto p : pjs) {
- if(!p->issue().empty()) delete p;
+ if(!p->issues().empty()) delete p;
}
pjs.clear();
diff --git a/SourceCode/Bond/Servo/HsmsPassive.h b/SourceCode/Bond/Servo/HsmsPassive.h
index f229e93..0f5a636 100644
--- a/SourceCode/Bond/Servo/HsmsPassive.h
+++ b/SourceCode/Bond/Servo/HsmsPassive.h
@@ -8,6 +8,7 @@
#include <set>
#include "CCollectionEvent.h"
#include "ProcessJob.h"
+#include "CControlJob.h"
#define EQCONSTANT_VALUE_MAX 64
@@ -88,6 +89,7 @@
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;
@@ -101,6 +103,7 @@
QUERYPPIDLIST onQueryPPIDList;
CARRIERACTION onCarrierAction;
PRJOBMULTICREATE onPRJobMultiCreate;
+ CONTROLJOBCREATE onControlJobCreate;
} SECSListener;
@@ -212,6 +215,7 @@
int replyPurgeSpooledData(IMessage* pRecv);
int replyQueryPPIDList(IMessage* pRecv);
int replyTerminalDisplay(IMessage* pRecv);
+ int replyCreateObj(IMessage* pRecv);
int replyPRJobMultiCreate(IMessage* pRecv);
private:
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 71d4eef..6ce35c5 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -88,7 +88,7 @@
::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);
@@ -112,7 +112,7 @@
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 {
@@ -151,8 +151,8 @@
}
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,
@@ -192,6 +192,11 @@
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_hsmsPassive.setEquipmentModelType((LPTSTR)(LPCTSTR)strModeType);
m_hsmsPassive.setSoftRev((LPTSTR)(LPCTSTR)strSoftRev);
diff --git a/SourceCode/Bond/Servo/ProcessJob.cpp b/SourceCode/Bond/Servo/ProcessJob.cpp
index 2ca265a..16bfbb0 100644
--- a/SourceCode/Bond/Servo/ProcessJob.cpp
+++ b/SourceCode/Bond/Servo/ProcessJob.cpp
@@ -53,7 +53,7 @@
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;
}
diff --git a/SourceCode/Bond/Servo/ProcessJob.h b/SourceCode/Bond/Servo/ProcessJob.h
index 9cf2fc5..da5db9b 100644
--- a/SourceCode/Bond/Servo/ProcessJob.h
+++ b/SourceCode/Bond/Servo/ProcessJob.h
@@ -118,7 +118,7 @@
};
// 返回问题清单(空=通过)
bool validate(const IResourceView& rv);
- const std::vector<ValidationIssue>& issue();
+ const std::vector<ValidationIssue>& issues();
// —— 状态机(带守卫)——
bool queue(); // NoState -> Queued
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 8246915..7bf97d3 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -201,6 +201,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="CBaseDlg.h" />
+ <ClInclude Include="CControlJob.h" />
<ClInclude Include="CCustomCheckBox.h" />
<ClInclude Include="CCollectionEvent.h" />
<ClInclude Include="CEquipmentPage3.h" />
@@ -351,6 +352,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="CBaseDlg.cpp" />
+ <ClCompile Include="CControlJob.cpp" />
<ClCompile Include="CCustomCheckBox.cpp" />
<ClCompile Include="CCollectionEvent.cpp" />
<ClCompile Include="CEquipmentPage3.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 230f6df..f96e572 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -177,6 +177,7 @@
<ClCompile Include="CPageReport.cpp" />
<ClCompile Include="CPageCollectionEvent.cpp" />
<ClCompile Include="ProcessJob.cpp" />
+ <ClCompile Include="CControlJob.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlarmManager.h" />
@@ -359,6 +360,7 @@
<ClInclude Include="CPageReport.h" />
<ClInclude Include="CPageCollectionEvent.h" />
<ClInclude Include="ProcessJob.h" />
+ <ClInclude Include="CControlJob.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Servo.rc" />
--
Gitblit v1.9.3