1.修复以下问题:
CEID 校验恒通过:ceidDefined 返回 true,PauseEvent ID 不做有效性检查。Host 若下发无效 CEID,将被接受但运行时无法触发暂停,风险难以察觉。
建议的上线前防护 / 改进(无需真机也可先改)
2.软件侧警告id上抛;
已修改10个文件
265 ■■■■■ 文件已修改
SourceCode/Bond/Servo/CMaster.cpp 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Common.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ToolUnits.cpp 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ToolUnits.h 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/AlarmList.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Release/AlarmList.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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>调度暂停:ControlJob/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;
            }
        }
    }
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;
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
#define PPID_NAME_MAX            80
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(RX_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 解析(soft 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(),
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);
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)) {
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;
}
}
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());
}
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, ...);
};
SourceCode/Bond/x64/Debug/AlarmList.txt
@@ -225,3 +225,4 @@
9000,0,PauseEvent触发
SourceCode/Bond/x64/Release/AlarmList.txt
@@ -225,3 +225,4 @@
9000,0,PauseEvent触发