6e0341c6356cdb6e527fbd89d1dc876f4e47ce46..ded981a2ac5dbb456bafce5468d7289bc45e313b
2026-01-10 chenluhua1980
1.S7F5查询PPID
ded981 对比 | 目录
2026-01-10 chenluhua1980
1.S1F3_CurrentRecipe,S6F11_RecipeChange实现。
9198ac 对比 | 目录
2026-01-10 chenluhua1980
1.实现远程删除配方功能;
6d140a 对比 | 目录
已修改15个文件
345 ■■■■■ 文件已修改
SourceCode/Bond/EAPSimulator/CHsmsActive.cpp 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/CHsmsActive.h 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/EAPSimulator.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/Resource.h 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.cpp 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PageRecipe.cpp 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/VariableList.txt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
@@ -394,6 +394,33 @@
    return 0;
}
int CHsmsActive::hsmsDeletePPID(const std::vector<std::string>& ppids)
{
    IMessage* pMessage = nullptr;
    int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 7 | REPLY, 17, ++m_nSystemByte);
    if (nRet != 0 || pMessage == nullptr) return -1;
    ISECS2Item* pBody = pMessage->getBody();
    for (const auto& ppid : ppids) {
        pBody->addItem(ppid.c_str(), "PPID");
    }
    m_pActive->sendMessage(pMessage);
    HSMS_Destroy1Message(pMessage);
    return 0;
}
int CHsmsActive::hsmsProcessProgramRequest(const char* pszPPID)
{
    if (pszPPID == nullptr || strlen(pszPPID) == 0) return -1;
    IMessage* pMessage = nullptr;
    if (HSMS_Create1Message(pMessage, m_nSessionId, 7 | REPLY, 5, ++m_nSystemByte) != 0 || pMessage == nullptr) {
        return -1;
    }
    pMessage->getBody()->setString(pszPPID, "PPID");
    m_pActive->sendMessage(pMessage);
    HSMS_Destroy1Message(pMessage);
    return 0;
}
int CHsmsActive::hsmsCarrierActionRequest(unsigned int DATAID, 
    const char* pszCarrierAction, 
    const char* pszCarrierId,
SourceCode/Bond/EAPSimulator/CHsmsActive.h
@@ -12,6 +12,13 @@
#define SVID_CJobSpace            5001
#define SVID_PJobSpace                5002
#define SVID_PJobQueued                5003
#define SVID_EQPPExecName           801
#define SVID_Bonder1CurrentRecipe   8100
#define SVID_Bonder2CurrentRecipe   8101
#define SVID_VacuumBakeCurrentRecipe 8102
#define SVID_BakeCoolingCurrentRecipe 8103
#define SVID_MeasurementCurrentRecipe 8104
#define SVID_EFEMCurrentRecipe      8105
typedef std::function<void(void* pFrom, ACTIVESTATE state)> STATECHANGED;
@@ -84,6 +91,8 @@
    // 查询PPID List
    int hsmsQueryPPIDList();
    int hsmsDeletePPID(const std::vector<std::string>& ppids); // S7F17
    int hsmsProcessProgramRequest(const char* pszPPID); // S7F5
    // S3F17
    // 卡匣动作请求
SourceCode/Bond/EAPSimulator/EAPSimulator.rc
Binary files differ
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
@@ -91,6 +91,7 @@
    ON_BN_CLICKED(IDC_BUTTON_TRANSMIT_SPOOLED_DATA, &CEAPSimulatorDlg::OnBnClickedButtonTransmitSpooledData)
    ON_BN_CLICKED(IDC_BUTTON_PURGE_SPOOLED_DATA, &CEAPSimulatorDlg::OnBnClickedButtonPurgeSpooledData)
    ON_BN_CLICKED(IDC_BUTTON_QUERY_PPID_LIST, &CEAPSimulatorDlg::OnBnClickedButtonQueryPpidList)
    ON_BN_CLICKED(IDC_BUTTON_DELETE_PPID, &CEAPSimulatorDlg::OnBnClickedButtonDeletePpid)
    ON_BN_CLICKED(IDC_BUTTON_PROCEED_WITH_CARRIER, &CEAPSimulatorDlg::OnBnClickedButtonProceedWithCarrier)
    ON_BN_CLICKED(IDC_BUTTON_PROCEED_WITH_SLOTMAP, &CEAPSimulatorDlg::OnBnClickedButtonProceedWithSlotMap)
    ON_BN_CLICKED(IDC_BUTTON_CARRIER_RELEASE, &CEAPSimulatorDlg::OnBnClickedButtonCarrierRelease)
@@ -105,6 +106,8 @@
    ON_BN_CLICKED(IDC_BUTTON_QUERY_PROCESS_STATE, &CEAPSimulatorDlg::OnBnClickedButtonQueryProcessState)
    ON_BN_CLICKED(IDC_BUTTON_QUERY_ALL_SVID, &CEAPSimulatorDlg::OnBnClickedButtonQueryAllSvid)
    ON_BN_CLICKED(IDC_BUTTON_QUERY_ALL_CEID, &CEAPSimulatorDlg::OnBnClickedButtonQueryAllCeid)
    ON_BN_CLICKED(IDC_BUTTON_QUERY_CURRENT_RECIPE, &CEAPSimulatorDlg::OnBnClickedButtonQueryCurrentRecipe)
    ON_BN_CLICKED(IDC_BUTTON_PP_REQUEST, &CEAPSimulatorDlg::OnBnClickedButtonPpRequest)
END_MESSAGE_MAP()
@@ -275,6 +278,34 @@
            ::SendMessage(hBtn, WM_SETFONT, (WPARAM)GetFont()->GetSafeHandle(), TRUE);
        }
    }
    // S1F3 CurrentRecipe (EQ specific) combo + button
    {
        CRect rcCombo(14, 168, 14 + 120, 168 + 120); // dropdown height arbitrary
        MapDialogRect(&rcCombo);
        HWND hCombo = ::CreateWindow(_T("COMBOBOX"), _T(""),
            WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,
            rcCombo.left, rcCombo.top, rcCombo.Width(), rcCombo.Height(),
            m_hWnd, (HMENU)IDC_COMBO_EQ_FOR_RECIPE, AfxGetInstanceHandle(), nullptr);
        if (hCombo != nullptr) {
            ::SendMessage(hCombo, WM_SETFONT, (WPARAM)GetFont()->GetSafeHandle(), TRUE);
            // 简单填充设备列表(可按需调整)
            std::vector<CString> eqs = { _T("Bonder1"), _T("Bonder2"), _T("EFEM"), _T("VacuumBake"), _T("BakeCooling"), _T("Measurement") };
            for (const auto& eq : eqs) {
                ::SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)eq);
            }
            ::SendMessage(hCombo, CB_SETCURSEL, 0, 0);
        }
        CRect rcBtn(140, 168, 14 + 140 + 118, 168 + 14);
        MapDialogRect(&rcBtn);
        HWND hBtn = ::CreateWindow(_T("BUTTON"), _T("S1F3_CurrentRecipe"),
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            rcBtn.left, rcBtn.top, rcBtn.Width(), rcBtn.Height(),
            m_hWnd, (HMENU)IDC_BUTTON_QUERY_CURRENT_RECIPE, AfxGetInstanceHandle(), nullptr);
        if (hBtn != nullptr) {
            ::SendMessage(hBtn, WM_SETFONT, (WPARAM)GetFont()->GetSafeHandle(), TRUE);
        }
    }
    SetDlgItemText(IDC_EDIT_IP, _T("127.0.0.1"));
    SetDlgItemInt(IDC_EDIT_PORT, 7000);
@@ -380,6 +411,12 @@
    GetDlgItem(IDC_BUTTON_TRANSMIT_SPOOLED_DATA)->EnableWindow(enabled);
    GetDlgItem(IDC_BUTTON_PURGE_SPOOLED_DATA)->EnableWindow(enabled);
    GetDlgItem(IDC_BUTTON_QUERY_PPID_LIST)->EnableWindow(enabled);    
    if (GetDlgItem(IDC_BUTTON_DELETE_PPID) != nullptr) {
        GetDlgItem(IDC_BUTTON_DELETE_PPID)->EnableWindow(enabled);
    }
    if (GetDlgItem(IDC_EDIT_DELETE_PPID) != nullptr) {
        GetDlgItem(IDC_EDIT_DELETE_PPID)->EnableWindow(enabled);
    }
    GetDlgItem(IDC_BUTTON_PROCEED_WITH_CARRIER)->EnableWindow(enabled);    
    if (GetDlgItem(IDC_BUTTON_PROCEED_WITH_SLOTMAP) != nullptr) {
        GetDlgItem(IDC_BUTTON_PROCEED_WITH_SLOTMAP)->EnableWindow(enabled);
@@ -522,6 +559,31 @@
    theApp.m_model.m_pHsmsActive->hsmsQueryPPIDList();
}
void CEAPSimulatorDlg::OnBnClickedButtonDeletePpid()
{
    CString strPPID;
    GetDlgItemText(IDC_EDIT_DELETE_PPID, strPPID);
    strPPID.Trim();
    std::vector<std::string> ppids;
    if (!strPPID.IsEmpty()) {
        CString upper = strPPID;
        upper.MakeUpper();
        if (upper != _T("ALL")) {
            int start = 0;
            CString token = strPPID.Tokenize(_T(","), start);
            while (!token.IsEmpty()) {
                token.Trim();
                if (!token.IsEmpty()) {
                    ppids.push_back(std::string((LPTSTR)(LPCTSTR)token));
                }
                token = strPPID.Tokenize(_T(","), start);
            }
        }
    }
    // L:0 if ppids empty -> delete all
    theApp.m_model.m_pHsmsActive->hsmsDeletePPID(ppids);
}
static int DATAID = 1;
void CEAPSimulatorDlg::OnBnClickedButtonProceedWithCarrier()
{
@@ -594,3 +656,39 @@
{
    theApp.m_model.m_pHsmsActive->hsmsQueryAllCollectionEvents();
}
void CEAPSimulatorDlg::OnBnClickedButtonQueryCurrentRecipe()
{
    CString sel;
    CComboBox* pCombo = (CComboBox*)GetDlgItem(IDC_COMBO_EQ_FOR_RECIPE);
    if (pCombo != nullptr) {
        int idx = pCombo->GetCurSel();
        if (idx != CB_ERR) {
            pCombo->GetLBText(idx, sel);
        }
    }
    unsigned int svid = SVID_EQPPExecName; // 默认全局
    CString upper = sel;
    upper.MakeUpper();
    if (upper.Find(_T("BONDER1")) != -1) svid = SVID_Bonder1CurrentRecipe;
    else if (upper.Find(_T("BONDER2")) != -1) svid = SVID_Bonder2CurrentRecipe;
    else if (upper.Find(_T("VACUUMBAKE")) != -1) svid = SVID_VacuumBakeCurrentRecipe;
    else if (upper.Find(_T("BAKECOOLING")) != -1) svid = SVID_BakeCoolingCurrentRecipe;
    else if (upper.Find(_T("MEASUREMENT")) != -1) svid = SVID_MeasurementCurrentRecipe;
    else if (upper.Find(_T("EFEM")) != -1) svid = SVID_EFEMCurrentRecipe;
    theApp.m_model.m_pHsmsActive->hsmsSelectedEquipmentStatusRequest(svid);
}
void CEAPSimulatorDlg::OnBnClickedButtonPpRequest()
{
    CString strPPID;
    GetDlgItemText(IDC_EDIT_PPID_REQ, strPPID);
    strPPID.Trim();
    std::string ppid = CT2A(strPPID);
    if (ppid.empty()) {
        AfxMessageBox(_T("请输入 PPID"));
        return;
    }
    theApp.m_model.m_pHsmsActive->hsmsProcessProgramRequest(ppid.c_str());
}
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
@@ -57,6 +57,7 @@
    afx_msg void OnBnClickedButtonTransmitSpooledData();
    afx_msg void OnBnClickedButtonPurgeSpooledData();
    afx_msg void OnBnClickedButtonQueryPpidList();
    afx_msg void OnBnClickedButtonDeletePpid();
    afx_msg void OnBnClickedButtonProceedWithCarrier();
    afx_msg void OnBnClickedButtonProceedWithSlotMap();
    afx_msg void OnBnClickedButtonCarrierRelease();
@@ -71,4 +72,6 @@
    afx_msg void OnBnClickedButtonQueryProcessState();
    afx_msg void OnBnClickedButtonQueryAllSvid();
    afx_msg void OnBnClickedButtonQueryAllCeid();
    afx_msg void OnBnClickedButtonQueryCurrentRecipe();
    afx_msg void OnBnClickedButtonPpRequest();
};
SourceCode/Bond/EAPSimulator/Resource.h
@@ -65,14 +65,20 @@
#define IDC_BUTTON_QUERY_PROCESS_STATE  1047
#define IDC_BUTTON_QUERY_ALL_SVID       1048
#define IDC_BUTTON_QUERY_ALL_CEID       1049
#define IDC_EDIT_DELETE_PPID            1050
#define IDC_BUTTON_DELETE_PPID          1051
#define IDC_COMBO_EQ_FOR_RECIPE         1052
#define IDC_BUTTON_QUERY_CURRENT_RECIPE 1053
#define IDC_EDIT_PPID_REQ               1054
#define IDC_BUTTON_PP_REQUEST           1055
// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        143
#define _APS_NEXT_RESOURCE_VALUE        146
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1050
#define _APS_NEXT_CONTROL_VALUE         1056
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif
SourceCode/Bond/Servo/CEquipment.cpp
@@ -208,6 +208,21 @@
        return m_strDescription;
    }
    void CEquipment::setCurrentRecipe(const std::string& recipe)
    {
        Lock();
        m_currentRecipe = recipe;
        Unlock();
    }
    std::string CEquipment::getCurrentRecipe()
    {
        Lock();
        std::string out = m_currentRecipe;
        Unlock();
        return out;
    }
    void CEquipment::setStation(int network, int station)
    {
        m_station.nNetNo = network;
@@ -1655,6 +1670,10 @@
                m_strName.c_str(), nRet);
        }
        if (m_listener.onReceivedJob != nullptr) {
            m_listener.onReceivedJob(this, port, pJobDataS);
        }
        return nRet;
    }
SourceCode/Bond/Servo/CEquipment.h
@@ -59,6 +59,7 @@
    typedef std::function<void(void* pEiuipment, short scanMap, short downMap)> ONMAPMISMATCH;
    typedef std::function<void(void* pEiuipment, short status, __int64 data)> ONPORTSTATUSCHANGED;
    typedef std::function<void(void* pEiuipment, const std::vector<CParam>& params)> ONPROCESSDATAREPORT;
    typedef std::function<void(void* pEiuipment, int port, CJobDataS* pJobDataS)> ONRECEIVEDJOB;
    
    typedef struct _EquipmentListener
    {
@@ -75,6 +76,7 @@
        ONVCREVENTREPORT    onSVDataReport;
        ONVCREVENTREPORT    onPanelDataReport;
        ONPROCESSDATAREPORT    onProcessDataReport;
        ONRECEIVEDJOB        onReceivedJob;
    } EquipmentListener;
@@ -101,6 +103,8 @@
        std::string& getName();
        void setDescription(const char* pszDescription);
        std::string& getDescription();
        void setCurrentRecipe(const std::string& recipe);
        std::string getCurrentRecipe();
        void setStation(int network, int station);
        const StationIdentifier& getStation();
        virtual void getAttributeVector(CAttributeVector& attrubutes);
@@ -284,6 +288,7 @@
        int m_nID;
        std::string m_strName;
        std::string m_strDescription;
        std::string m_currentRecipe;
        CRITICAL_SECTION m_criticalSection;
        StationIdentifier m_station;
        MemoryBlock m_blockReadBit;
SourceCode/Bond/Servo/CMaster.cpp
@@ -1810,6 +1810,11 @@
            }
        };
        listener.onReceivedJob = [&](void* pEquipment, int port, CJobDataS* pJobDataS) {
            if (m_listener.onJobReceived != nullptr) {
                m_listener.onJobReceived(this, (CEquipment*)pEquipment, port, pJobDataS);
            }
        };
        pEquipment->setListener(listener);
        pEquipment->setCcLink(&m_cclink);
        m_listEquipment.push_back(pEquipment);
SourceCode/Bond/Servo/CMaster.h
@@ -16,6 +16,7 @@
#include "ProcessJob.h"
#include "CControlJob.h"
#include "../DAQBridge/core/Collector.h"
#include "CJobDataS.h"
#define CTStep_Unknow                   0
@@ -61,6 +62,7 @@
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int slotNo, PROCESS_STATE prevState, PROCESS_STATE state)> ONPROCESSSTATECHANGED;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, const std::vector<CParam>& params)> ONPROCESSDATAREPORTEX;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, const std::vector<CParam>& params)> ONSVDATAREPORT;
    typedef std::function<void(void* pMaster, CEquipment* pEquipment, int port, CJobDataS* pJobDataS)> ONJOBRECEIVED;
    typedef std::function<void(void* pMaster, int round)> ONCTROUNDEND;
    typedef std::function<void(void* pMaster, void* pj)> ONPJSTART;
    typedef std::function<void(void* pMaster)> ONCONTROLJOBCHANGED;
@@ -77,6 +79,7 @@
        ONPROCESSSTATECHANGED   onProcessStateChanged;
        ONSVDATAREPORT          onSVDataReport;
        ONPROCESSDATAREPORTEX   onProcessDataReport;
        ONJOBRECEIVED           onJobReceived;
        ONCTROUNDEND            onCTRoundEnd;
        ONPJSTART               onCjStart;
        ONPJSTART               onCjEnd;
SourceCode/Bond/Servo/HsmsPassive.cpp
@@ -3,6 +3,7 @@
#include "Log.h"
#include "Model.h"
#include "Common.h"
#include "RecipeManager.h"
#include <time.h>
#include <iostream>  
#include <time.h>  
@@ -11,6 +12,7 @@
#include <algorithm>
#include <set>
#include <regex>
#include <sstream>
// ControlState values (keep in sync with Model::ControlState / VariableList.txt)
static constexpr uint8_t kControlStateOnlineRemote = 5;
@@ -587,8 +589,8 @@
    Lock();
    int maxId = 0;
    for (auto v : m_variabels) {
        if (v != nullptr && v->getVarialbleId() > maxId) {
            maxId = v->getVarialbleId();
        if (v != nullptr && static_cast<int>(v->getVarialbleId()) > maxId) {
            maxId = static_cast<int>(v->getVarialbleId());
        }
    }
    outId = maxId + 1;
@@ -1370,6 +1372,12 @@
        else if (nStream == 7 && pHeader->function == 19) {
            replyQueryPPIDList(pMessage);
        }
        else if (nStream == 7 && pHeader->function == 17) {
            replyDeletePPID(pMessage);
        }
        else if (nStream == 7 && pHeader->function == 5) {
            replyProcessProgramRequest(pMessage);
        }
        else if (nStream == 10 && pHeader->function == 3) {
            replyTerminalDisplay(pMessage);
        }
@@ -1409,7 +1417,12 @@
        return -1;
    }
    int nBufSize = file.GetLength();
    ULONGLONG len = file.GetLength();
    if (len > INT_MAX) {
        file.Close();
        return -1;
    }
    int nBufSize = static_cast<int>(len);
    char* pszBuffer = new char[nBufSize];
    file.Read(pszBuffer, nBufSize);
    file.Close();
@@ -2544,6 +2557,86 @@
    return 0;
}
// S7F17 Delete Process Program (PPID list) / S7F18
int CHsmsPassive::replyDeletePPID(IMessage* pRecv)
{
    if (m_pPassive == NULL || STATE::SELECTED != m_pPassive->getState()) {
        return ER_NOTSELECT;
    }
    bool allOk = true;
    const bool deleteAll = (pRecv->getBody() == nullptr || pRecv->getBody()->getSubItemSize() == 0);
    std::vector<std::string> ppids;
    ISECS2Item* pBody = pRecv->getBody();
    const int nCount = pBody ? pBody->getSubItemSize() : 0;
    for (int i = 0; i < nCount; ++i) {
        const char* pszPPID = nullptr;
        if (pBody->getSubItemString(i, pszPPID) && pszPPID != nullptr) {
            ppids.emplace_back(pszPPID);
        }
        else {
            allOk = false;
        }
    }
    if (deleteAll || !ppids.empty()) {
        if (m_listener.onDeletePPID != nullptr) {
            allOk = m_listener.onDeletePPID(this, ppids);
        }
        else {
            // no handler provided; treat as failure
            allOk = false;
            LOGW("<HSMS>DeletePPID request ignored: no onDeletePPID listener");
        }
    }
    replyAck(7, 18, pRecv->getHeader()->systemBytes, allOk ? BYTE(0) : BYTE(1), "ACKC7");
    return 0;
}
// S7F5 Process Program Request -> reply S7F6 with PPID + PPBODY
int CHsmsPassive::replyProcessProgramRequest(IMessage* pRecv)
{
    if (m_pPassive == NULL || STATE::SELECTED != m_pPassive->getState()) {
        return ER_NOTSELECT;
    }
    ISECS2Item* pBody = pRecv->getBody();
    const char* pszPPID = nullptr;
    if (pBody == nullptr || !pBody->getString(pszPPID) || pszPPID == nullptr) {
        return ER_PARAM_ERROR;
    }
    std::string ppid(pszPPID);
    std::string ppbody;
    // 简单聚合:从 RecipeManager 取设备配方,拼成文本
    auto recipeInfo = RecipeManager::getInstance().getRecipeByPPID(ppid);
    if (!recipeInfo.strPPID.empty()) {
        for (const auto& dev : recipeInfo.vecDeviceList) {
            if (!ppbody.empty()) ppbody.append("\n");
            ppbody.append(dev.strDeviceName);
            ppbody.append(",");
            ppbody.append(std::to_string(dev.nRecipeID));
            ppbody.append(",");
            ppbody.append(dev.strRecipeName);
            // 附加参数大小信息(目前缺少具体参数列表)
            ppbody.append(",paramsSize=");
            ppbody.append(std::to_string(dev.paramsRawData.size()));
        }
    }
    IMessage* pMessage = nullptr;
    if (HSMS_Create1Message(pMessage, m_nSessionId, 7, 6, pRecv->getHeader()->systemBytes) != 0 || pMessage == nullptr) {
        return ER_CREATED_MESSAGE;
    }
    ISECS2Item* pRspBody = pMessage->getBody(); // top-level L:2
    pRspBody->addItem(ppid.c_str(), "PPID");
    pRspBody->addItem(ppbody.c_str(), "PPBODY");
    m_pPassive->sendMessage(pMessage);
    LogSecsMessageBrief("<HSMS>[SEND]", pMessage);
    HSMS_Destroy1Message(pMessage);
    return 0;
}
// S7F19
int CHsmsPassive::replyQueryPPIDList(IMessage* pRecv)
{
SourceCode/Bond/Servo/HsmsPassive.h
@@ -26,6 +26,8 @@
#define ER_UNLINK_EVENT_REPORT    -5
#define ER_NO_PPID_LIST            -6
#define ER_NOT_SUPPORTED        -7
#define ER_CREATED_MESSAGE        -8
/* CAACK */
@@ -90,6 +92,7 @@
    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 std::function<bool(void* pFrom, const std::vector<std::string>& ppids)> DELETEPPID;
typedef struct _SECSListener
{
    SECSEQOFFLINE                onEQOffLine;
@@ -101,6 +104,7 @@
    EDEVENTREPORT                onEnableDisableEventReport;
    EDALARMREPORT                onEnableDisableAlarmReport;
    QUERYPPIDLIST                onQueryPPIDList;
    DELETEPPID                    onDeletePPID;
    CARRIERACTION                onCarrierAction;
    PRJOBMULTICREATE            onPRJobMultiCreate;
    CONTROLJOBCREATE            onControlJobCreate;
@@ -250,6 +254,8 @@
    int replyEanbleDisableAlarmReport(IMessage* pRecv);
    int replyPurgeSpooledData(IMessage* pRecv);
    int replyQueryPPIDList(IMessage* pRecv);
    int replyDeletePPID(IMessage* pRecv); // S7F17/S7F18
    int replyProcessProgramRequest(IMessage* pRecv); // S7F5/S7F6
    int replyTerminalDisplay(IMessage* pRecv);
    int replyCreateObj(IMessage* pRecv);
    int replyPRJobMultiCreate(IMessage* pRecv);
SourceCode/Bond/Servo/Model.cpp
@@ -10,6 +10,7 @@
#include "RecipeManager.h"
#include "GlassLogDb.h"
#include "CParam.h"
#include "CJobDataS.h"
#include <algorithm>
#include <iomanip>
#include <sstream>
@@ -189,6 +190,21 @@
        if (ids.empty()) {
            m_master.enableEventReport(bEnable);
        }
    };
    listener.onDeletePPID = [&](void* pFrom, const std::vector<std::string>& ppids) -> bool {
        (void)pFrom;
        bool allOk = true;
        std::vector<std::string> targets = ppids;
        if (targets.empty()) {
            // L:0 => delete all PPIDs
            targets = RecipeManager::getInstance().getAllPPID();
        }
        for (auto& ppid : targets) {
            bool ok = RecipeManager::getInstance().deleteRecipeByPPID(ppid);
            allOk = allOk && ok;
            LOGI("<CModel>DeletePPID: %s, result=%s", ppid.c_str(), ok ? "OK" : "FAIL");
        }
        return allOk;
    };
    listener.onEnableDisableAlarmReport = [&](void* pFrom, bool bEnable, unsigned int id) -> void {
        LOGI("onEnableDisableAlarmReport bEnable:%s, id:%d", bEnable ? _T("YES") : _T("NO"), id);
@@ -495,6 +511,42 @@
        notifyPtrAndInt(RX_CODE_EQ_ROBOT_TASK, pTask, nullptr, code);
    };
    masterListener.onJobReceived = [&](void* pMaster, SERVO::CEquipment* pEquipment, int port, SERVO::CJobDataS* pJobDataS) {
        (void)pMaster;
        (void)port;
        if (pEquipment == nullptr || pJobDataS == nullptr) return;
        const int eqId = pEquipment->getID();
        const int recipeId = pJobDataS->getMasterRecipe();
        std::string recipe = RecipeManager::getInstance().getPPIDById(recipeId);
        if (recipe.empty()) {
            recipe = std::to_string(recipeId);
        }
        const std::string prev = pEquipment->getCurrentRecipe();
        if (recipe.empty() || recipe == prev) {
            pEquipment->setCurrentRecipe(recipe);
            return;
        }
        pEquipment->setCurrentRecipe(recipe);
        m_hsmsPassive.withVariableLock([&] {
            m_hsmsPassive.setVariableValue("Clock", CToolUnits::getCurrentTimeString().c_str());
            m_hsmsPassive.setVariableValue("EQPPExecName", recipe.c_str());
            m_hsmsPassive.setVariableValue("SubEqpName", pEquipment->getName().c_str());
            const char* recipeVid = nullptr;
            switch (eqId) {
            case EQ_ID_Bonder1: recipeVid = "Bonder1CurrentRecipe"; break;
            case EQ_ID_Bonder2: recipeVid = "Bonder2CurrentRecipe"; break;
            case EQ_ID_VACUUMBAKE: recipeVid = "VacuumBakeCurrentRecipe"; break;
            case EQ_ID_BAKE_COOLING: recipeVid = "BakeCoolingCurrentRecipe"; break;
            case EQ_ID_MEASUREMENT: recipeVid = "MeasurementCurrentRecipe"; break;
            case EQ_ID_EFEM: recipeVid = "EFEMCurrentRecipe"; break;
            default: break;
            }
            if (recipeVid != nullptr) {
                m_hsmsPassive.setVariableValue(recipeVid, recipe.c_str());
            }
            m_hsmsPassive.requestEventReportSend("RecipeChanged");
        });
    };
    masterListener.onLoadPortStatusChanged = [&] (void* pMaster, SERVO::CEquipment* pEquipment, short status, __int64 data) {
        LOGE("<CModel>onLoadPortStatusChanged. status = %d", status);
        static std::map<int, short> s_prevPortStatus;
SourceCode/Bond/Servo/PageRecipe.cpp
@@ -138,9 +138,12 @@
    // 遍历数据并插入到CListCtrl中
    for (int i = 0; i < static_cast<int>(vecRecipe.size()); ++i) {
        const RecipeInfo& recipe = vecRecipe[i];
        // 原程序要求PPID有子配方,先注释
        /*
        if (recipe.vecDeviceList.empty() || recipe.vecDeviceList.size() > 6){
            continue;
        }
        */
        m_listPPID.InsertItem(i, _T("")); // 第0列空白
SourceCode/Bond/x64/Debug/VariableList.txt
@@ -8,6 +8,12 @@
701,PreviousProcessState,U1,
800,EFEMPPExecName,A20,
801,EQPPExecName,A20,
8100,Bonder1CurrentRecipe,A50,
8101,Bonder2CurrentRecipe,A50,
8102,VacuumBakeCurrentRecipe,A50,
8103,BakeCoolingCurrentRecipe,A50,
8104,MeasurementCurrentRecipe,A50,
8105,EFEMCurrentRecipe,A50,
2000,RbRAxisTorque,I2,机器人R轴扭矩
2001,RbLAxisTorque,U1,机器人L轴扭矩
2002,RbZAxisTorque,U1,机器人Z轴扭矩