From d14420e7f85b5fe7289aafe6bef0c053dede3657 Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期五, 16 一月 2026 11:20:39 +0800
Subject: [PATCH] 1.修复以下问题: CEID 校验恒通过:ceidDefined 返回 true,PauseEvent ID 不做有效性检查。Host 若下发无效 CEID,将被接受但运行时无法触发暂停,风险难以察觉。 建议的上线前防护 / 改进(无需真机也可先改) 2.软件侧警告id上抛;
---
SourceCode/Bond/Servo/ToolUnits.cpp | 25 ++++
SourceCode/Bond/Servo/Model.h | 10 ++
SourceCode/Bond/x64/Release/AlarmList.txt | 1
SourceCode/Bond/Servo/CMaster.cpp | 107 +++++++++++++++++++++
SourceCode/Bond/Servo/CMaster.h | 12 ++
SourceCode/Bond/Servo/Model.cpp | 78 +++++++++++++++
SourceCode/Bond/Servo/ServoDlg.cpp | 21 ++++
SourceCode/Bond/Servo/ToolUnits.h | 4
SourceCode/Bond/Servo/Common.h | 6 +
SourceCode/Bond/x64/Debug/AlarmList.txt | 1
10 files changed, 260 insertions(+), 5 deletions(-)
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index d9a0e67..90b4d23 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -8,6 +8,9 @@
#include <fstream>
#include "SerializeUtil.h"
#include "CServoUtilsTool.h"
+#include "AlarmManager.h"
+#include "ToolUnits.h"
+#include "Model.h"
namespace SERVO {
@@ -72,6 +75,8 @@
m_nContinuousWorkingPort = 0;
m_nContinuousWorkingSlot = 0;
m_pControlJob = nullptr;
+ m_bPauseAlarmRaised = false;
+ m_pModelCtx = nullptr;
m_nTestFlag = 0;
InitializeCriticalSection(&m_criticalSection);
}
@@ -119,6 +124,11 @@
void CMaster::setListener(MasterListener listener)
{
m_listener = listener;
+ }
+
+ void CMaster::setModelCtx(CModel* pModel)
+ {
+ m_pModelCtx = pModel;
}
CRobotTask* CMaster::getActiveRobotTask()
@@ -879,6 +889,33 @@
m_pActiveRobotTask->place();
}
unlock(); // 绛夊綋鍓嶄换鍔″畬鎴愭垨涓鍚庣户缁�
+ continue;
+ }
+
+ // 5.5) 鏆傚仠鐘舵�佹鏌ワ細鑻� CJ 鎴栧湪鍒� PJ 澶勪簬 Paused锛屾殏缂撹皟搴︽柊鐨勬惉閫�
+ bool pausedByEvent = false;
+ if (m_pControlJob != nullptr && m_pControlJob->state() == CJState::Paused) {
+ pausedByEvent = true;
+ }
+ for (auto pj : m_inProcesJobs) {
+ if (pj != nullptr && pj->state() == PJState::Paused) {
+ pausedByEvent = true;
+ break;
+ }
+ }
+ if (!pausedByEvent && m_bPauseAlarmRaised) {
+ if (m_pModelCtx != nullptr) {
+ m_pModelCtx->clearSoftAlarm(ALID_SOFTWARE_PAUSE_EVENT, 0, 0);
+ }
+ else {
+ AlarmManager& alarmManager = AlarmManager::getInstance();
+ alarmManager.clearAlarmByAttributes(ALID_SOFTWARE_PAUSE_EVENT, 0, 0, CToolUnits::getCurrentTimeString());
+ }
+ m_bPauseAlarmRaised = false;
+ }
+ if (pausedByEvent) {
+ LOGI("<Master>璋冨害鏆傚仠锛欳ontrolJob/ProcessJob 澶勪簬 Paused 鐘舵�侊紙鍙兘鐢� PauseEvent 瑙﹀彂锛�");
+ unlock();
continue;
}
@@ -2977,15 +3014,83 @@
return m_allowedCeids.find(ceid) != m_allowedCeids.end();
}
+ bool CMaster::raiseSoftAlarm(int alarmId,
+ const std::string& desc,
+ int level/* = -1*/,
+ int deviceId/* = 0*/,
+ int unitId/* = 0*/,
+ const char* deviceName/* = "Software"*/,
+ const char* unitName/* = "App"*/)
+ {
+ AlarmManager& alarmManager = AlarmManager::getInstance();
+ const AlarmInfo* info = alarmManager.getAlarmInfoByID(alarmId);
+
+ int severity = level;
+ if (severity < 0 && info != nullptr) {
+ severity = info->nAlarmLevel;
+ }
+ if (severity < 0) severity = 0; // fallback
+
+ std::string descText = desc;
+ if (descText.empty() && info != nullptr) {
+ descText = !info->strDescription.empty() ? info->strDescription : info->strAlarmText;
+ }
+ if (descText.empty()) {
+ descText = CToolUnits::formatString("Alarm %d", alarmId);
+ }
+
+ AlarmData alarmData;
+ alarmData.nId = alarmId;
+ alarmData.nSeverityLevel = severity;
+ alarmData.nDeviceId = deviceId;
+ alarmData.nUnitId = unitId;
+ alarmData.strDeviceName = deviceName;
+ alarmData.strUnitName = unitName;
+ alarmData.strStartTime = CToolUnits::timeToString2(CToolUnits::getTimestamp());
+ alarmData.strEndTime = "";
+ alarmData.strDescription = descText;
+
+ int nAlarmEventId = 0;
+ return alarmManager.addAlarm(alarmData, nAlarmEventId);
+ }
+
void CMaster::handleCollectionEvent(uint32_t ceid)
{
// 閬嶅巻褰撳墠 PJ锛屽懡涓� pauseEvents 鏃跺彲鍦ㄦ鎵╁睍鏆傚仠鍔ㄤ綔
+ bool pausedAny = false;
for (auto pj : m_processJobs) {
if (pj == nullptr) continue;
const auto& pauseList = pj->pauseEvents();
if (std::find(pauseList.begin(), pauseList.end(), ceid) != pauseList.end()) {
LOGW("<Master>PauseEvent hit: CEID=%u, PJ=%s, state=%d", ceid, pj->id().c_str(), (int)pj->state());
- // TODO: 琛旀帴鍏蜂綋鏆傚仠绛栫暐锛堝鏆傚仠 PJ/CJ銆佸仠姝㈣皟搴�/鎼�侊級锛屾澶勪粎鐣欐々浣�
+ if (pj->pause()) {
+ LOGI("<Master>PJ paused by CEID=%u", ceid);
+ pausedAny = true;
+ }
+ if (m_pControlJob != nullptr && m_pControlJob->state() == CJState::Executing) {
+ if (m_pControlJob->pause()) {
+ LOGI("<Master>ControlJob paused by CEID=%u", ceid);
+ pausedAny = true;
+ }
+ }
+ }
+ }
+ if (pausedAny && m_listener.onControlJobChanged) {
+ // 閫氱煡搴旂敤灞傚埛鏂� UI/鎸夐挳鐘舵��
+ m_listener.onControlJobChanged(this);
+ }
+ if (pausedAny && !m_bPauseAlarmRaised) {
+ std::string desc = CToolUnits::formatString("<PauseEvent CEID=%u>", ceid);
+ bool raised = false;
+ if (m_pModelCtx != nullptr) {
+ raised = m_pModelCtx->raiseSoftAlarm(ALID_SOFTWARE_PAUSE_EVENT, desc);
+ }
+ else {
+ raised = raiseSoftAlarm(ALID_SOFTWARE_PAUSE_EVENT, desc);
+ }
+ if (raised) {
+ LOGI("<Master>PauseEvent soft alarm raised, CEID=%u", ceid);
+ m_bPauseAlarmRaised = true;
}
}
}
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index acd3065..c1f1755 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -19,6 +19,8 @@
#include "../DAQBridge/core/Collector.h"
#include "CJobDataS.h"
+class CModel;
+
#define CTStep_Unknow 0
#define CTStep_LoadPort_Aligner 1
@@ -99,6 +101,7 @@
public:
+ void setModelCtx(CModel* pModel);
void setListener(MasterListener listener);
CRobotTask* getActiveRobotTask();
int init();
@@ -192,6 +195,13 @@
bool ceidDefined(uint32_t ceid) const override;
void setAllowedCeids(const std::vector<unsigned int>& ceids);
void handleCollectionEvent(uint32_t ceid);
+ bool raiseSoftAlarm(int alarmId,
+ const std::string& desc,
+ int level = -1,
+ int deviceId = 0,
+ int unitId = 0,
+ const char* deviceName = "Software",
+ const char* unitName = "App");
public:
int getLastError();
@@ -273,9 +283,11 @@
private:
bool m_bEnableEventReport;
bool m_bEnableAlarmReport;
+ bool m_bPauseAlarmRaised;
SERVO::CControlJob* m_pControlJob;
std::vector<SERVO::CProcessJob*> m_processJobs;
std::string m_strStatePath;
+ CModel* m_pModelCtx;
int m_nTestFlag;
std::list<CGlass*> m_bufGlass;
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index 4969d57..b207bfd 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/SourceCode/Bond/Servo/Common.h
@@ -20,7 +20,10 @@
#define RX_CODE_EQ_ROBOT_TASK 1012
#define RX_CODE_LOADPORT_STATUS_CHANGED 1014
#define RX_CODE_CONTROL_STATE_CHANGED 1015
+#define RX_CODE_CONTROLJOB_CHANGED 1016
+/* 软件侧 ALID */
+#define ALID_SOFTWARE_PAUSE_EVENT 9000
/* Channel Name */
#define MC_CHANNEL1_NAME "McChannel1"
@@ -556,4 +559,5 @@
/* PPID名字最大长度 */
-#define PPID_NAME_MAX 80
\ No newline at end of file
+#define PPID_NAME_MAX 80
+
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 3bc322e..61f3a80 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -37,6 +37,79 @@
m_hsmsPassive.setVariableValue("PJobSpace", (__int64)(m_master.isProcessJobsEmpty() ? 1 : 0));
}
+void CModel::notifyControlJobChanged()
+{
+ // 1) 鍒锋柊娲剧敓 SV
+ refreshDerivedSVs();
+ // 2) 閫氱煡涓婂眰 UI锛圧X_CODE_CONTROLJOB_CHANGED锛�
+ notify(RX_CODE_CONTROLJOB_CHANGED);
+}
+
+bool CModel::raiseSoftAlarm(int alarmId,
+ const std::string& desc,
+ int level /*= -1*/,
+ int deviceId /*= 0*/,
+ int unitId /*= 0*/,
+ const char* deviceName /*= "Software"*/,
+ const char* unitName /*= "App"*/)
+{
+ AlarmManager& alarmManager = AlarmManager::getInstance();
+ const AlarmInfo* info = alarmManager.getAlarmInfoByID(alarmId);
+
+ int severity = level;
+ if (severity < 0 && info != nullptr) severity = info->nAlarmLevel;
+ if (severity < 0) severity = 0;
+
+ std::string descText = desc;
+ if (descText.empty() && info != nullptr) {
+ descText = !info->strDescription.empty() ? info->strDescription : info->strAlarmText;
+ }
+ if (descText.empty()) {
+ descText = CToolUnits::formatString("Alarm %d", alarmId);
+ }
+
+ AlarmData alarmData;
+ alarmData.nId = alarmId;
+ alarmData.nSeverityLevel = severity;
+ alarmData.nDeviceId = deviceId;
+ alarmData.nUnitId = unitId;
+ alarmData.strDeviceName = deviceName;
+ alarmData.strUnitName = unitName;
+ // 鑻ユ湭鏄惧紡鎻愪緵璁惧/鍗曞厓鍚嶇О锛屽皾璇曢�氳繃 deviceId/unitId 瑙f瀽锛坰oft alarm 榛樿鍧囦负 0锛�
+ if (alarmData.strDeviceName.empty()) {
+ alarmData.strDeviceName = alarmManager.getDeviceNameById(deviceId);
+ }
+ if (alarmData.strUnitName.empty()) {
+ alarmData.strUnitName = alarmManager.getUnitNameById(deviceId, unitId);
+ }
+ alarmData.strStartTime = CToolUnits::timeToString2(CToolUnits::getTimestamp());
+ alarmData.strEndTime = "";
+ alarmData.strDescription = descText;
+
+ int nAlarmEventId = 0;
+ bool result = alarmManager.addAlarm(alarmData, nAlarmEventId);
+ if (result) {
+ notify(RX_CODE_ALARM_SET);
+ if (m_master.isAlarmReportEnable()) {
+ m_hsmsPassive.requestAlarmReport(1, alarmId, descText.c_str());
+ }
+ }
+ return result;
+}
+
+void CModel::clearSoftAlarm(int alarmId, int deviceId, int unitId)
+{
+ AlarmManager& alarmManager = AlarmManager::getInstance();
+ alarmManager.clearAlarmByAttributes(alarmId, deviceId, unitId, CToolUnits::getCurrentTimeString());
+ notify(RX_CODE_ALARM_CLEAR);
+ if (m_master.isAlarmReportEnable()) {
+ const AlarmInfo* info = alarmManager.getAlarmInfoByID(alarmId);
+ std::string descText;
+ if (info != nullptr) descText = info->strAlarmText;
+ m_hsmsPassive.requestAlarmReport(0, alarmId, descText.c_str());
+ }
+}
+
void CModel::setControlState(ControlState newState)
{
const auto prev = m_currentControlState;
@@ -124,6 +197,9 @@
// CGlassPool
m_glassPool.initPool();
+
+ // 灏� Model 涓婁笅鏂囦紶閫掔粰 Master锛屼究浜� Master 瑙﹀彂杞欢绾ф姤璀︾瓑璺ㄥ眰鎿嶄綔
+ m_master.setModelCtx(this);
// Log
@@ -341,7 +417,7 @@
};
masterListener.onControlJobChanged = [this](void* pMaster) {
(void)pMaster;
- this->refreshDerivedSVs();
+ this->notifyControlJobChanged();
};
masterListener.onEqAlive = [&](void* pMaster, SERVO::CEquipment* pEquipment, BOOL bAlive) -> void {
LOGI("<CModel>Equipment onAlive:%s(%s).", pEquipment->getName().c_str(),
diff --git a/SourceCode/Bond/Servo/Model.h b/SourceCode/Bond/Servo/Model.h
index 839e949..51a5427 100644
--- a/SourceCode/Bond/Servo/Model.h
+++ b/SourceCode/Bond/Servo/Model.h
@@ -4,6 +4,7 @@
#include "CMaster.h"
#include "CGlassPool.h"
#include <cstdint>
+#include <string>
enum class ControlState : uint8_t {
OfflineEquipment = 0,
@@ -33,9 +34,18 @@
ControlState getControlState() const noexcept { return m_currentControlState; }
void setControlState(ControlState newState);
+ bool raiseSoftAlarm(int alarmId,
+ const std::string& desc = "",
+ int level = -1,
+ int deviceId = 0,
+ int unitId = 0,
+ const char* deviceName = "Software",
+ const char* unitName = "App");
+ void clearSoftAlarm(int alarmId, int deviceId = 0, int unitId = 0);
private:
void refreshDerivedSVs();
+ void notifyControlJobChanged();
public:
int notify(int code);
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index cdc423f..77e626f 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -259,6 +259,27 @@
SetTimer(TIMER_ID_UPDATE_RUMTIME, 500, nullptr);
}
}
+ else if (RX_CODE_CONTROLJOB_CHANGED == code) {
+ auto* cj = theApp.m_model.getMaster().getControlJob();
+ CString text;
+ if (cj != nullptr) {
+ std::string st = cj->getStateText();
+ text.Format(_T("ControlJob: %S (%S)"), cj->id().c_str(), st.c_str());
+ if (cj->state() == SERVO::CJState::Paused) {
+ text += _T(" [Paused]");
+ }
+ }
+ else {
+ text = _T("ControlJob: None");
+ }
+ if (m_pMyStatusbar != nullptr) {
+ m_pMyStatusbar->setRunTimeText((LPTSTR)(LPCTSTR)text);
+ if (cj != nullptr && cj->state() == SERVO::CJState::Paused) {
+ m_pMyStatusbar->setBackgroundColor(STATUSBAR_BK_ALARM);
+ m_pMyStatusbar->setForegroundColor(RGB(0, 0, 0));
+ }
+ }
+ }
else if (RX_CODE_EQ_ROBOT_TASK == code) {
int exCode;
if (pAny->getIntValue("exCode", exCode)) {
diff --git a/SourceCode/Bond/Servo/ToolUnits.cpp b/SourceCode/Bond/Servo/ToolUnits.cpp
index 974121c..e3e1dca 100644
--- a/SourceCode/Bond/Servo/ToolUnits.cpp
+++ b/SourceCode/Bond/Servo/ToolUnits.cpp
@@ -7,6 +7,8 @@
#include <ctime>
#include <iomanip>
#include <sstream>
+#include <vector>
+#include <cstdarg>
CToolUnits::CToolUnits()
{
@@ -614,4 +616,25 @@
nullptr, nullptr);
return str;
-}
\ No newline at end of file
+}
+std::string CToolUnits::formatString(const char* fmt, ...)
+{
+ if (fmt == nullptr) return std::string();
+
+ char buf[512] = {0};
+ va_list args;
+ va_start(args, fmt);
+ int n = _vsnprintf_s(buf, sizeof(buf), _TRUNCATE, fmt, args);
+ va_end(args);
+
+ if (n >= 0 && n < (int)sizeof(buf)) {
+ return std::string(buf);
+ }
+
+ // ?????????????????
+ std::vector<char> tmp((n > 0 ? n + 2 : 1024), 0);
+ va_start(args, fmt);
+ _vsnprintf_s(tmp.data(), tmp.size(), _TRUNCATE, fmt, args);
+ va_end(args);
+ return std::string(tmp.data());
+}
diff --git a/SourceCode/Bond/Servo/ToolUnits.h b/SourceCode/Bond/Servo/ToolUnits.h
index 7314ea8..0d171c7 100644
--- a/SourceCode/Bond/Servo/ToolUnits.h
+++ b/SourceCode/Bond/Servo/ToolUnits.h
@@ -3,6 +3,8 @@
#include <chrono>
#include <optional>
#include <utility>
+#include <vector>
+#include <cstdarg>
enum class QuickRange { Today, Last7Days, ThisMonth, ThisYear };
using TP = std::chrono::system_clock::time_point;
@@ -62,5 +64,5 @@
static std::string NowStrSec();
static std::wstring AnsiToWString(const std::string& str);
static std::string WStringToAnsi(const std::wstring& wstr);
+ static std::string formatString(const char* fmt, ...);
};
-
diff --git a/SourceCode/Bond/x64/Debug/AlarmList.txt b/SourceCode/Bond/x64/Debug/AlarmList.txt
index 69473c8..59dab8f 100644
--- a/SourceCode/Bond/x64/Debug/AlarmList.txt
+++ b/SourceCode/Bond/x64/Debug/AlarmList.txt
@@ -225,3 +225,4 @@
+9000,0,PauseEvent触发
diff --git a/SourceCode/Bond/x64/Release/AlarmList.txt b/SourceCode/Bond/x64/Release/AlarmList.txt
index 34ad3a9..40bca15 100644
--- a/SourceCode/Bond/x64/Release/AlarmList.txt
+++ b/SourceCode/Bond/x64/Release/AlarmList.txt
@@ -225,3 +225,4 @@
+9000,0,PauseEvent触发
--
Gitblit v1.9.3