已添加2个文件
已修改9个文件
472 ■■■■■ 文件已修改
SourceCode/Bond/Servo/CPageDataVarialbles.cpp 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPageDataVarialbles.h 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.cpp 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/PortConfigurationDlg.cpp 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/DataVariableList.txt 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPageDataVarialbles.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,220 @@
// CPageDataVarialbles.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "Servo.h"
#include "CPageDataVarialbles.h"
#include "afxdialogex.h"
#include "CVariableEditDlg2.h"
IMPLEMENT_DYNAMIC(CPageDataVarialbles, CHMPropertyPage)
CPageDataVarialbles::CPageDataVarialbles(CWnd* pParent /*=nullptr*/)
    : CHMPropertyPage(IDD_PAGE_VARIABLE, pParent)
{
}
CPageDataVarialbles::~CPageDataVarialbles()
{
}
void CPageDataVarialbles::DoDataExchange(CDataExchange* pDX)
{
    CHMPropertyPage::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST1, m_listCtrl);
}
BEGIN_MESSAGE_MAP(CPageDataVarialbles, CHMPropertyPage)
    ON_WM_CTLCOLOR()
    ON_WM_DESTROY()
    ON_WM_SIZE()
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CPageDataVarialbles::OnLvnItemchangedList1)
END_MESSAGE_MAP()
BOOL CPageDataVarialbles::OnInitDialog()
{
    CHMPropertyPage::OnInitDialog();
    // è¯»å‡ºåˆ—宽(独立的 ini åˆ†èŠ‚ï¼Œé¿å…ä¸Ž SVID é¡µé¢å†²çªï¼‰
    CString strIniFile, strItem;
    strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
    int width[8] = { 0, 218, 180, 180, 180, 180, 180, 180 };
    for (int i = 0; i < 8; i++) {
        strItem.Format(_T("Col_%d_Width"), i);
        width[i] = GetPrivateProfileInt("PageDataVariableListCtrl", strItem, width[i], strIniFile);
    }
    DWORD dwStyle = m_listCtrl.GetExtendedStyle();
    dwStyle |= LVS_EX_FULLROWSELECT;
    dwStyle |= LVS_EX_GRIDLINES;
    m_listCtrl.SetExtendedStyle(dwStyle);
    HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1);
    ListView_SetImageList(m_listCtrl.GetSafeHwnd(), imageList, LVSIL_SMALL);
    m_listCtrl.InsertColumn(0, _T(""), LVCFMT_RIGHT, width[0]);
    m_listCtrl.InsertColumn(1, _T("DV ID"), LVCFMT_LEFT, width[1]);
    m_listCtrl.InsertColumn(2, _T("DV Name"), LVCFMT_LEFT, width[2]);
    m_listCtrl.InsertColumn(3, _T("DV Format"), LVCFMT_LEFT, width[3]);
    m_listCtrl.InsertColumn(4, _T("DV Remark"), LVCFMT_LEFT, width[4]);
    loadDataVariables();
    return TRUE;
}
HBRUSH CPageDataVarialbles::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    return CHMPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
}
void CPageDataVarialbles::OnDestroy()
{
    CHMPropertyPage::OnDestroy();
    // ä¿å­˜åˆ—宽
    CString strIniFile, strItem, strTemp;
    strIniFile.Format(_T("%s\\configuration.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
    CHeaderCtrl* pHeader = m_listCtrl.GetHeaderCtrl();
    for (int i = 0; i < pHeader->GetItemCount(); i++) {
        RECT rect;
        pHeader->GetItemRect(i, &rect);
        strItem.Format(_T("Col_%d_Width"), i);
        strTemp.Format(_T("%d"), rect.right - rect.left);
        WritePrivateProfileString("PageDataVariableListCtrl", strItem, strTemp, strIniFile);
    }
}
void CPageDataVarialbles::OnSize(UINT nType, int cx, int cy)
{
    CHMPropertyPage::OnSize(nType, cx, cy);
    if (GetDlgItem(IDC_LIST1) == nullptr) return;
    CRect rcClient;
    GetClientRect(&rcClient);
    m_listCtrl.MoveWindow(12, 12, rcClient.Width() - 24, rcClient.Height() - 24);
}
void CPageDataVarialbles::OnApply()
{
    __super::OnApply();
}
void CPageDataVarialbles::loadDataVariables()
{
    auto& dvars = theApp.m_model.m_hsmsPassive.getDataVariables();
    for (auto item : dvars) {
        int index = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), _T(""));
        m_listCtrl.SetItemData(index, (DWORD_PTR)item);
        m_listCtrl.SetItemText(index, 1, std::to_string(item->getVarialbleId()).c_str());
        m_listCtrl.SetItemText(index, 2, item->getName().c_str());
        m_listCtrl.SetItemText(index, 3, SERVO::CVariable::formatToString(item->getFormat()).c_str());
        m_listCtrl.SetItemText(index, 4, item->getRemark().c_str());
    }
}
void CPageDataVarialbles::OnCreateBtns()
{
    const int BTN_W = 80;
    const int BTN_H = 28;
    CreateBtn(_T("新增"), BTN_W, BTN_H, 1001);
    CreateBtn(_T("删除"), BTN_W, BTN_H, 1002)->EnableWindow(FALSE);
    CreateBtn(_T("编辑"), BTN_W, BTN_H, 1003)->EnableWindow(FALSE);
}
void CPageDataVarialbles::OnLvnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    int nSelCount = m_listCtrl.GetSelectedCount();
    if (CButton* pDel = GetBtnByName("删除")) {
        pDel->EnableWindow(nSelCount > 0);
    }
    if (CButton* pEdit = GetBtnByName("编辑")) {
        pEdit->EnableWindow(nSelCount > 0);
    }
    *pResult = 0;
}
void CPageDataVarialbles::OnClickedBtn(const char* btnName)
{
    ASSERT(btnName);
    if (_strcmpi(btnName, "新增") == 0) {
        int rc = UX_CanExecute(L"addVarialbles");
        if (rc != 1) {
            AfxMessageBox("操作权限不足,请联系管理人员!");
            return;
        }
        unsigned int newId = theApp.m_model.m_hsmsPassive.getMaxDataVariableId();
        int newIdInt = static_cast<int>(newId + 1);
        CVariableEditDlg2 dlg(_T("新增数据变量"), newIdInt, _T("U1"), _T(""), _T(""), this);
        if (dlg.DoModal() != IDOK) return;
        CString name = dlg.GetNameText();
        CString fmt = dlg.GetTypeText();
        CString remark = dlg.GetRemark();
        int ret = theApp.m_model.m_hsmsPassive.addDataVariable(CT2A(name), CT2A(fmt), CT2A(remark), newIdInt);
        if (ret == 0) {
            UX_RecordAction(L"addVarialbles");
            m_listCtrl.DeleteAllItems();
            loadDataVariables();
        }
        else {
            AfxMessageBox(_T("新增数据变量失败,格式是否正确?(U1/U2/I2/A20/A50/L)"));
        }
    }
    else if (_strcmpi(btnName, "删除") == 0) {
        POSITION pos = m_listCtrl.GetFirstSelectedItemPosition();
        if (pos == nullptr) return;
        int nItem = m_listCtrl.GetNextSelectedItem(pos);
        auto pVar = reinterpret_cast<SERVO::CDataVariable*>(m_listCtrl.GetItemData(nItem));
        if (pVar == nullptr) return;
        int rc = UX_CanExecute(L"delVarialbles");
        if (rc != 1) {
            AfxMessageBox("操作权限不足,请联系管理人员!");
            return;
        }
        int ret = theApp.m_model.m_hsmsPassive.deleteDataVariable(static_cast<int>(pVar->getVarialbleId()));
        if (ret == 0) {
            UX_RecordAction(L"delVarialbles");
            m_listCtrl.DeleteAllItems();
            loadDataVariables();
            if (CButton* pDel = GetBtnByName("删除")) pDel->EnableWindow(FALSE);
            if (CButton* pEdit = GetBtnByName("编辑")) pEdit->EnableWindow(FALSE);
        }
    }
    else if (_strcmpi(btnName, "编辑") == 0) {
        POSITION pos = m_listCtrl.GetFirstSelectedItemPosition();
        if (pos == nullptr) return;
        int nItem = m_listCtrl.GetNextSelectedItem(pos);
        auto pVar = reinterpret_cast<SERVO::CDataVariable*>(m_listCtrl.GetItemData(nItem));
        if (pVar == nullptr) return;
        int rc = UX_CanExecute(L"editVarialbles");
        if (rc != 1) {
            AfxMessageBox("操作权限不足,请联系管理人员!");
            return;
        }
        CVariableEditDlg2 dlg(_T("编辑数据变量"),
            pVar->getVarialbleId(),
            CString(CA2T(SERVO::CVariable::formatToString(pVar->getFormat()).c_str())),
            CString(CA2T(pVar->getName().c_str())),
            CString(CA2T(pVar->getRemark().c_str())),
            this);
        if (dlg.DoModal() != IDOK) return;
        CString name = dlg.GetNameText();
        CString fmt = dlg.GetTypeText();
        CString remark = dlg.GetRemark();
        int ret = theApp.m_model.m_hsmsPassive.updateDataVariable(static_cast<int>(pVar->getVarialbleId()), CT2A(name), CT2A(fmt), CT2A(remark));
        if (ret == 0) {
            UX_RecordAction(L"editVarialbles");
            m_listCtrl.DeleteAllItems();
            loadDataVariables();
        }
        else {
            AfxMessageBox(_T("编辑数据变量失败,格式是否正确?(U1/U2/I2/A20/A50/L)"));
        }
    }
}
SourceCode/Bond/Servo/CPageDataVarialbles.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
#pragma once
#include "CHMPropertyPage.h"
#include "ListCtrlEx.h"
// CPageDataVarialbles å¯¹è¯æ¡†ï¼ˆDVID ç¼–辑/查看)
class CPageDataVarialbles : public CHMPropertyPage
{
    DECLARE_DYNAMIC(CPageDataVarialbles)
public:
    CPageDataVarialbles(CWnd* pParent = nullptr);
    virtual ~CPageDataVarialbles();
    virtual void OnApply();
    void loadDataVariables();
    virtual void OnCreateBtns();
private:
    CListCtrlEx m_listCtrl;
protected:
    virtual void OnClickedBtn(const char* btnName) override;
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_PAGE_VARIABLE };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    afx_msg void OnDestroy();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnLvnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult);
};
SourceCode/Bond/Servo/HsmsPassive.cpp
@@ -665,6 +665,27 @@
            maxId = item->getVarialbleId();
        }
    }
    for (auto item : m_dataVariabels) {
        if (item && item->getVarialbleId() > maxId) {
            maxId = item->getVarialbleId();
        }
    }
    return maxId;
}
unsigned int CHsmsPassive::getMaxDataVariableId() const
{
    unsigned int maxId = 0;
    for (auto item : m_variabels) {
        if (item && item->getVarialbleId() > maxId) {
            maxId = item->getVarialbleId();
        }
    }
    for (auto item : m_dataVariabels) {
        if (item && item->getVarialbleId() > maxId) {
            maxId = item->getVarialbleId();
        }
    }
    return maxId;
}
@@ -895,6 +916,75 @@
    if (filepath.empty()) return -3;
    return writeVariablesToFile(filepath);
}
int CHsmsPassive::deleteDataVariable(int dvid)
{
    Lock();
    auto it = std::find_if(m_dataVariabels.begin(), m_dataVariabels.end(), [=](SERVO::CDataVariable* v) {
        return v != nullptr && v->getVarialbleId() == (unsigned int)dvid;
        });
    if (it == m_dataVariabels.end()) {
        Unlock();
        return -1;
    }
    delete *it;
    m_dataVariabels.erase(it);
    auto filepath = m_strDataVariableFilepath;
    Unlock();
    if (filepath.empty()) return -2;
    return writeDataVariablesToFile(filepath);
}
int CHsmsPassive::addDataVariable(const char* pszName, const char* pszFormat, const char* pszRemark, int& outId)
{
    if (pszName == nullptr || pszFormat == nullptr) return -1;
    std::string fmt = pszFormat;
    std::transform(fmt.begin(), fmt.end(), fmt.begin(), ::toupper);
    if (!isValidFormat(fmt)) return -2;
    Lock();
    int maxId = 0;
    for (auto v : m_dataVariabels) {
        if (v != nullptr && static_cast<int>(v->getVarialbleId()) > maxId) {
            maxId = static_cast<int>(v->getVarialbleId());
        }
    }
    outId = maxId + 1;
    SERVO::CDataVariable* pNew = new SERVO::CDataVariable(std::to_string(outId).c_str(), pszName, fmt.c_str(), pszRemark ? pszRemark : "");
    m_dataVariabels.push_back(pNew);
    auto filepath = m_strDataVariableFilepath;
    Unlock();
    if (filepath.empty()) return -3;
    return writeDataVariablesToFile(filepath);
}
int CHsmsPassive::updateDataVariable(int dvid, const char* pszName, const char* pszFormat, const char* pszRemark)
{
    if (pszName == nullptr || pszFormat == nullptr) return -1;
    std::string fmt = pszFormat;
    std::transform(fmt.begin(), fmt.end(), fmt.begin(), ::toupper);
    if (!isValidFormat(fmt)) return -2;
    Lock();
    auto it = std::find_if(m_dataVariabels.begin(), m_dataVariabels.end(), [=](SERVO::CDataVariable* v) {
        return v != nullptr && v->getVarialbleId() == (unsigned int)dvid;
        });
    if (it == m_dataVariabels.end()) {
        Unlock();
        return -4;
    }
    (*it)->setName(pszName);
    (*it)->setFormat(fmt.c_str());
    (*it)->setRemark(pszRemark ? pszRemark : "");
    auto filepath = m_strDataVariableFilepath;
    Unlock();
    if (filepath.empty()) return -3;
    return writeDataVariablesToFile(filepath);
}
int CHsmsPassive::writeVariablesToFile(const std::string& filepath)
@@ -3315,6 +3405,26 @@
    // è§£é‡Šæ•°æ®ï¼Œå¾—到CProcessJob
    // å®¹é‡å‰ç½®æ£€æŸ¥ï¼šå½“前实现仅支持单批 PJ é›†åˆï¼Œå¦‚果已有 PJ/CJ,直接返回 ACKA=false
    if (m_pModel != nullptr && !m_pModel->getMaster().isProcessJobsEmpty()) {
        IMessage* pMessage = NULL;
        HSMS_Create1Message(pMessage, m_nSessionId, 16, 16, ++m_nSystemByte);
        ASSERT(pMessage);
        pMessage->getBody()->addItem(); // PRJOBID list ä¸ºç©º
        ISECS2Item* pItemErrors = pMessage->getBody()->addItem();
        pItemErrors->addBoolItem(false, "ACKA");
        ISECS2Item* pItemErrors2 = pItemErrors->addItem();
        auto err = pItemErrors2->addItem();
        err->addU4Item(1000, "ERRCODE");
        err->addItem("PJobSpace=0 (existing ProcessJob/ControlJob)", "ERRTEXT");
        m_pPassive->sendMessage(pMessage);
        LOGI("<HSMS>[SEND]sessionId:%d, sType:%d systemBytes:%d",
            pMessage->getHeader()->sessionId, pMessage->getHeader()->sType, pMessage->getHeader()->systemBytes);
        LogSecsMessageBrief("<HSMS>[SEND]", pMessage);
        HSMS_Destroy1Message(pMessage);
        return 0;
    }
    ISECS2Item* pItemPjs, * pItemPj,* pItemCarriers, * pItemCarrier, *pItemSlots, *pItemRecipes;
    unsigned short DATAID;
    const char* pszPrjobid, *pszMF, *pszCarrierId, *pszRecipeName;
@@ -3366,7 +3476,11 @@
    }
    // å›žå¤æŠ¥æ–‡
    ASSERT(m_listener.onPRJobMultiCreate != nullptr);
    int nRet = m_listener.onPRJobMultiCreate(this, pjs);
    // å›žå¤æŠ¥æ–‡ï¼ˆåœ¨æ ¡éªŒ/落库后再回复,以便带上真实的 issues)
    IMessage* pMessage = NULL;
    HSMS_Create1Message(pMessage, m_nSessionId, 16, 16, ++m_nSystemByte);
    ASSERT(pMessage);
@@ -3392,15 +3506,15 @@
            }
        }
    }
    else {
        pItemErrors->addBoolItem(true, "ACKA");
        pItemErrors->addItem(); // ç©ºåˆ—表
    }
    m_pPassive->sendMessage(pMessage);
    LOGI("<HSMS>[SEND]sessionId:%d, sType:%d systemBytes:%d",
        pMessage->getHeader()->sessionId, pMessage->getHeader()->sType, pMessage->getHeader()->systemBytes);
    LogSecsMessageBrief("<HSMS>[SEND]", pMessage);
    HSMS_Destroy1Message(pMessage);
    ASSERT(m_listener.onPRJobMultiCreate != nullptr);
    int nRet = m_listener.onPRJobMultiCreate(this, pjs);
    // é‡Šæ”¾æœ‰é—®é¢˜(未添加到master)的内存
SourceCode/Bond/Servo/HsmsPassive.h
@@ -153,6 +153,7 @@
    std::vector<SERVO::CVariable*>& getVariables();
    unsigned int getMaxVariableId() const;
    std::vector<SERVO::CDataVariable*>& getDataVariables();
    unsigned int getMaxDataVariableId() const;
    // å–得指定Variable
    SERVO::CVariable* getVariable(int variableId);
@@ -164,6 +165,9 @@
    int deleteVariable(int variableId);
    int addVariable(const char* pszName, const char* pszFormat, const char* pszRemark, int& outId);
    int updateVariable(int variableId, const char* pszName, const char* pszFormat, const char* pszRemark);
    int deleteDataVariable(int dvid);
    int addDataVariable(const char* pszName, const char* pszFormat, const char* pszRemark, int& outId);
    int updateDataVariable(int dvid, const char* pszName, const char* pszFormat, const char* pszRemark);
    // è®¾ç½®å˜é‡å€¼
    void setVariableValue(const char* pszName, __int64 value);
SourceCode/Bond/Servo/Model.cpp
@@ -233,6 +233,11 @@
                // çœŸæ­£çš„“开始”由 ProceedWithSlotMap å†³ç­–触发。
                // ä»…当未开启 CompareMapsBeforeProceeding æ—¶ï¼Œæ‰æ²¿ç”¨æ—§é€»è¾‘直接 Start。
                LOGI("<CModel>ProceedWithCarrier");
                if (m_master.getControlJob() == nullptr || m_master.isProcessJobsEmpty()) {
                    strErrorTxt = "rejected - ControlJob/ProcessJob not ready";
                    LOGW("<CModel>ProceedWithCarrier rejected: no CJ/PJ, port=%d", portIndex + 1);
                    return CAACK_5;
                }
                if (pLoadPort == nullptr || !pLoadPort->isCompareMapsBeforeProceeding()) {
                    m_master.proceedWithCarrier(portIndex);
                }
SourceCode/Bond/Servo/PortConfigurationDlg.cpp
@@ -438,14 +438,68 @@
{
    int selPort = (0 <= m_nCurSelPort && m_nCurSelPort <= 3) ? m_nCurSelPort
        : m_comboPort.GetCurSel();
    if (selPort < 0 || selPort >= 4) return;
    m_pPort[selPort]->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
    if (selPort < 0 || selPort >= 4) {
        LOGE("ProcessStart invalid port index: %d", selPort);
        return;
    }
    SERVO::CLoadPort* pPort = m_pPort[selPort];
    if (pPort == nullptr) {
        LOGE("ProcessStart port pointer is null, index: %d", selPort);
        return;
    }
    constexpr short cmd = CCC_PROCESS_START;
    LOGI("ProcessStart request: port=%d, cmd=%d", selPort + 1, cmd);
    int ret = pPort->sendCassetteCtrlCmd(cmd, nullptr, 0, 0, 0, nullptr,
        [selPort](int code) -> int {
            if (code == WOK) {
                LOGI("ProcessStart write complete: port=%d, code=WOK", selPort + 1);
            }
            else {
                LOGE("ProcessStart write failed: port=%d, code=%d", selPort + 1, code);
            }
            return 0;
        });
    if (ret != 0) {
        LOGE("ProcessStart sendCassetteCtrlCmd immediate failure: port=%d, ret=%d", selPort + 1, ret);
    }
    else {
        LOGI("ProcessStart sendCassetteCtrlCmd dispatched: port=%d", selPort + 1);
    }
}
void CPortConfigurationDlg::OnBnClickedButtonProcessCancel()
{
    int selPort = (0 <= m_nCurSelPort && m_nCurSelPort <= 3) ? m_nCurSelPort
        : m_comboPort.GetCurSel();
    if (selPort < 0 || selPort >= 4) return;
    m_pPort[selPort]->sendCassetteCtrlCmd(CCC_PROCESS_CANCEL, nullptr, 0, 0, 0, nullptr, nullptr);
    if (selPort < 0 || selPort >= 4) {
        LOGE("ProcessCancel invalid port index: %d", selPort);
        return;
    }
    SERVO::CLoadPort* pPort = m_pPort[selPort];
    if (pPort == nullptr) {
        LOGE("ProcessCancel port pointer is null, index: %d", selPort);
        return;
    }
    constexpr short cmd = CCC_PROCESS_CANCEL;
    LOGI("ProcessCancel request: port=%d, cmd=%d", selPort + 1, cmd);
    int ret = pPort->sendCassetteCtrlCmd(cmd, nullptr, 0, 0, 0, nullptr,
        [selPort](int code) -> int {
            if (code == WOK) {
                LOGI("ProcessCancel write complete: port=%d, code=WOK", selPort + 1);
            }
            else {
                LOGE("ProcessCancel write failed: port=%d, code=%d", selPort + 1, code);
            }
            return 0;
        });
    if (ret != 0) {
        LOGE("ProcessCancel sendCassetteCtrlCmd immediate failure: port=%d, ret=%d", selPort + 1, ret);
    }
    else {
        LOGI("ProcessCancel sendCassetteCtrlCmd dispatched: port=%d", selPort + 1);
    }
}
SourceCode/Bond/Servo/Servo.vcxproj
@@ -248,6 +248,7 @@
    <ClInclude Include="CPageProdOverview.h" />
    <ClInclude Include="CPageReport.h" />
    <ClInclude Include="CPageVarialbles.h" />
    <ClInclude Include="CPageDataVarialbles.h" />
    <ClInclude Include="CPanelProduction.h" />
    <ClInclude Include="HmLabel.h" />
    <ClInclude Include="ProductionStats.h" />
@@ -475,6 +476,7 @@
    <ClCompile Include="CPageProdOverview.cpp" />
    <ClCompile Include="CPageReport.cpp" />
    <ClCompile Include="CPageVarialbles.cpp" />
    <ClCompile Include="CPageDataVarialbles.cpp" />
    <ClCompile Include="ConfigurationProduction.cpp" />
    <ClCompile Include="CPanelProduction.cpp" />
    <ClCompile Include="HmLabel.cpp" />
@@ -670,4 +672,4 @@
    <Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
    <Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
  </Target>
</Project>
</Project>
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -174,6 +174,7 @@
    <ClCompile Include="CReport.cpp" />
    <ClCompile Include="CVariable.cpp" />
    <ClCompile Include="CPageVarialbles.cpp" />
    <ClCompile Include="CPageDataVarialbles.cpp" />
    <ClCompile Include="CPageReport.cpp" />
    <ClCompile Include="CPageCollectionEvent.cpp" />
    <ClCompile Include="ProcessJob.cpp" />
@@ -423,6 +424,7 @@
    <ClInclude Include="CReport.h" />
    <ClInclude Include="CVariable.h" />
    <ClInclude Include="CPageVarialbles.h" />
    <ClInclude Include="CPageDataVarialbles.h" />
    <ClInclude Include="CPageReport.h" />
    <ClInclude Include="CPageCollectionEvent.h" />
    <ClInclude Include="ProcessJob.h" />
@@ -571,4 +573,4 @@
      <UniqueIdentifier>{885738f6-3122-4bb9-8308-46b7f692fb13}</UniqueIdentifier>
    </Filter>
  </ItemGroup>
</Project>
</Project>
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -653,6 +653,10 @@
    pPage3->Create(IDD_PAGE_VARIABLE);
    dlg.addPage(pPage3, "Variable");
    CPageDataVarialbles* pPage4 = new CPageDataVarialbles();
    pPage4->Create(IDD_PAGE_VARIABLE);
    dlg.addPage(pPage4, "DataVariable");
    dlg.DoModal();
}
SourceCode/Bond/Servo/ServoDlg.h
@@ -19,6 +19,8 @@
#include "CMyStatusbar.h"
#include "CRobotTaskDlg.h"
#include "CPageGlassList.h"
#include "CPageVarialbles.h"
#include "CPageDataVarialbles.h"
// CServoDlg å¯¹è¯æ¡†
SourceCode/Bond/x64/Debug/DataVariableList.txt
@@ -93,6 +93,6 @@
6701,Measurement_PD_Time,A20,Measurement PD: æ—¶é—´
6702,Measurement_PD_Value1,A20,Measurement PD: æµ‹é‡å€¼1
6703,Measurement_PD_Value2,A20,Measurement PD: æµ‹é‡å€¼2
10200,SlotMap,U2,SlotMap(Scan)
10201,SlotMapScan,U2,SlotMap(Scan)
10202,SlotMapDownload,U2,SlotMap(Download)
10200,SlotMap,U1,SlotMap(Scan)
10201,SlotMapScan,U1,SlotMap(Scan)
10202,SlotMapDownload,U1,SlotMap(Download)