已添加2个文件
已修改17个文件
536 ■■■■■ 文件已修改
SourceCode/Bond/EAPSimulator/CHsmsActive.cpp 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/CHsmsActive.h 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/EAPSimulator.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/Resource.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPageCtrlState.cpp 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPageCtrlState.h 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelProduction.cpp 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelProduction.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Common.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.cpp 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HsmsPassive.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/EAPSimulator/CHsmsActive.cpp
@@ -143,6 +143,48 @@
    return 0;
}
int CHsmsActive::hsmsRequestOnline()
{
    IMessage* pMessage = nullptr;
    int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 1 | REPLY, 17, ++m_nSystemByte);
    m_pActive->sendMessage(pMessage);
    HSMS_Destroy1Message(pMessage);
    return 0;
}
int CHsmsActive::hsmsRequestOffline()
{
    IMessage* pMessage = nullptr;
    int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 1 | REPLY, 15, ++m_nSystemByte);
    m_pActive->sendMessage(pMessage);
    HSMS_Destroy1Message(pMessage);
    return 0;
}
int CHsmsActive::hsmsGoLocal()
{
    IMessage* pMessage = nullptr;
    int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 2 | REPLY, 41, ++m_nSystemByte);
    ISECS2Item* pBody = pMessage->getBody();
    pBody->addItem("GoLocal", "RCMD");
    pBody->addItem(); // L: empty params
    m_pActive->sendMessage(pMessage);
    HSMS_Destroy1Message(pMessage);
    return 0;
}
int CHsmsActive::hsmsGoRemote()
{
    IMessage* pMessage = nullptr;
    int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 2 | REPLY, 41, ++m_nSystemByte);
    ISECS2Item* pBody = pMessage->getBody();
    pBody->addItem("GoRemote", "RCMD");
    pBody->addItem(); // L: empty params
    m_pActive->sendMessage(pMessage);
    HSMS_Destroy1Message(pMessage);
    return 0;
}
int CHsmsActive::hsmsDatetimeSync()
{
    CTime time = CTime::GetCurrentTime();
@@ -300,7 +342,7 @@
    IMessage* pMessage = nullptr;
    int nRet = HSMS_Create1Message(pMessage, m_nSessionId, 1 | REPLY, 3, ++m_nSystemByte);
    pMessage->getBody()->addU4Item(SVID, "SVID");
    pMessage->getBody()->addU2Item(static_cast<unsigned short>(SVID), "SVID");
    m_pActive->sendMessage(pMessage);
    HSMS_Destroy1Message(pMessage);
SourceCode/Bond/EAPSimulator/CHsmsActive.h
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <string>
#include <vector>
#include <map>
@@ -7,7 +7,8 @@
#include "ProcessJob.h"
#define SVID_CJobSpace                5001
#define SVID_ControlState           600
#define SVID_CJobSpace            5001
#define SVID_PJobSpace                5002
#define SVID_PJobQueued                5003
@@ -36,11 +37,19 @@
    // Deselect Request
    int hsmsDeselectRequest();
    // å»ºç«‹é€šè®¯(S1F13)
    // å»ºç«‹é€šè®¯(S1F13)
    int hsmsEstablishCommunications();
    // Are You There
    int hsmsAreYouThere();
    // ControlState: Request Online/Offline (S1F17 / S1F15)
    int hsmsRequestOnline();
    int hsmsRequestOffline();
    // ControlState: GoLocal/GoRemote (S2F41)
    int hsmsGoLocal();
    int hsmsGoRemote();
    // Date time sync
    int hsmsDatetimeSync();
@@ -63,18 +72,18 @@
    // Configure Spooling
    int hsmsConfigureSpooling(std::map<unsigned int, std::set<unsigned int>>& spoolingConfig);
    // å‘送或清空缓存的消息
    // å‘送或清空缓存的消息
    int hsmsTransmitSpooledData();
    int hsmsPurgeSpooledData();
    // æŸ¥è¯¢å˜é‡
    // æŸ¥è¯¢å˜é‡
    int hsmsSelectedEquipmentStatusRequest(unsigned int SVID);
    // æŸ¥è¯¢PPID List
    // æŸ¥è¯¢PPID List
    int hsmsQueryPPIDList();
    // S3F17
    // å¡åŒ£åŠ¨ä½œè¯·æ±‚
    // å¡åŒ£åŠ¨ä½œè¯·æ±‚
    int hsmsCarrierActionRequest(unsigned int DATAID, 
        const char* pszCarrierAction,
        const char* pszCarrierId,
@@ -98,7 +107,7 @@
    // S14F9
    int hsmsCreateControlJob(const char* pszControlJobId, std::vector<std::string>& processJobIds);
    // é€šè¿‡çš„reply函数
    // é€šè¿‡çš„reply函数
    void replyAck(int s, int f, unsigned int systemBytes, BYTE ack, const char* pszAckName);
    // reply ack0
SourceCode/Bond/EAPSimulator/EAPSimulator.rc
Binary files differ
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.cpp
@@ -98,6 +98,10 @@
    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)
    ON_BN_CLICKED(IDC_BUTTON_CTRL_OFFLINE, &CEAPSimulatorDlg::OnBnClickedButtonCtrlOffline)
    ON_BN_CLICKED(IDC_BUTTON_CTRL_ONLINE_LOCAL, &CEAPSimulatorDlg::OnBnClickedButtonCtrlOnlineLocal)
    ON_BN_CLICKED(IDC_BUTTON_CTRL_ONLINE_REMOTE, &CEAPSimulatorDlg::OnBnClickedButtonCtrlOnlineRemote)
    ON_BN_CLICKED(IDC_BUTTON_QUERY_CONTROL_STATE, &CEAPSimulatorDlg::OnBnClickedButtonQueryControlState)
END_MESSAGE_MAP()
@@ -189,6 +193,45 @@
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            rc.left, rc.top, rc.Width(), rc.Height(),
            m_hWnd, (HMENU)IDC_BUTTON_PROCEED_WITH_SLOTMAP, AfxGetInstanceHandle(), nullptr);
        if (hBtn != nullptr) {
            ::SendMessage(hBtn, WM_SETFONT, (WPARAM)GetFont()->GetSafeHandle(), TRUE);
        }
    }
    // ControlState test buttons at runtime (resource file is UTF-16, keep it unchanged)
    {
        const int y = 120;
        const int w = 70;
        const int h = 14;
        const int gap = 3;
        struct BtnDef { int x; int id; const TCHAR* text; };
        BtnDef defs[] = {
            { 238, IDC_BUTTON_CTRL_OFFLINE, _T("Ctrl Offline") },
            { 238 + (w + gap), IDC_BUTTON_CTRL_ONLINE_LOCAL, _T("Ctrl Local") },
            { 238 + 2 * (w + gap), IDC_BUTTON_CTRL_ONLINE_REMOTE, _T("Ctrl Remote") },
        };
        for (const auto& d : defs) {
            CRect rc(d.x, y, d.x + w, y + h); // dialog units
            MapDialogRect(&rc);
            HWND hBtn = ::CreateWindow(_T("BUTTON"), d.text,
                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                rc.left, rc.top, rc.Width(), rc.Height(),
                m_hWnd, (HMENU)d.id, AfxGetInstanceHandle(), nullptr);
            if (hBtn != nullptr) {
                ::SendMessage(hBtn, WM_SETFONT, (WPARAM)GetFont()->GetSafeHandle(), TRUE);
            }
        }
    }
    // S1F3 Query ControlState (SVID=600) button (runtime add to avoid touching UTF-16 RC)
    {
        // Place on its own row to avoid overlapping with control-mode buttons.
        CRect rc(14, 136, 14 + 140, 136 + 14); // dialog units
        MapDialogRect(&rc);
        HWND hBtn = ::CreateWindow(_T("BUTTON"), _T("S1F3_QueryControlState"),
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            rc.left, rc.top, rc.Width(), rc.Height(),
            m_hWnd, (HMENU)IDC_BUTTON_QUERY_CONTROL_STATE, AfxGetInstanceHandle(), nullptr);
        if (hBtn != nullptr) {
            ::SendMessage(hBtn, WM_SETFONT, (WPARAM)GetFont()->GetSafeHandle(), TRUE);
        }
@@ -307,6 +350,18 @@
    GetDlgItem(IDC_BUTTON_QUERY_PJ_SPACE)->EnableWindow(enabled);
    GetDlgItem(IDC_BUTTON_CREATE_PJ)->EnableWindow(enabled);    
    GetDlgItem(IDC_BUTTON_CREATE_CJ)->EnableWindow(enabled);    
    if (GetDlgItem(IDC_BUTTON_CTRL_OFFLINE) != nullptr) {
        GetDlgItem(IDC_BUTTON_CTRL_OFFLINE)->EnableWindow(enabled);
    }
    if (GetDlgItem(IDC_BUTTON_CTRL_ONLINE_LOCAL) != nullptr) {
        GetDlgItem(IDC_BUTTON_CTRL_ONLINE_LOCAL)->EnableWindow(enabled);
    }
    if (GetDlgItem(IDC_BUTTON_CTRL_ONLINE_REMOTE) != nullptr) {
        GetDlgItem(IDC_BUTTON_CTRL_ONLINE_REMOTE)->EnableWindow(enabled);
    }
    if (GetDlgItem(IDC_BUTTON_QUERY_CONTROL_STATE) != nullptr) {
        GetDlgItem(IDC_BUTTON_QUERY_CONTROL_STATE)->EnableWindow(enabled);
    }
}
void CEAPSimulatorDlg::OnBnClickedButtonConnect()
@@ -454,3 +509,25 @@
    std::vector<std::string> processJobIds = {"PJ0001"};
    theApp.m_model.m_pHsmsActive->hsmsCreateControlJob("CJ5007", processJobIds);
}
void CEAPSimulatorDlg::OnBnClickedButtonCtrlOffline()
{
    theApp.m_model.m_pHsmsActive->hsmsRequestOffline();
}
void CEAPSimulatorDlg::OnBnClickedButtonCtrlOnlineLocal()
{
    theApp.m_model.m_pHsmsActive->hsmsRequestOnline();
    theApp.m_model.m_pHsmsActive->hsmsGoLocal();
}
void CEAPSimulatorDlg::OnBnClickedButtonCtrlOnlineRemote()
{
    theApp.m_model.m_pHsmsActive->hsmsRequestOnline();
    theApp.m_model.m_pHsmsActive->hsmsGoRemote();
}
void CEAPSimulatorDlg::OnBnClickedButtonQueryControlState()
{
    theApp.m_model.m_pHsmsActive->hsmsSelectedEquipmentStatusRequest(SVID_ControlState);
}
SourceCode/Bond/EAPSimulator/EAPSimulatorDlg.h
@@ -64,4 +64,8 @@
    afx_msg void OnBnClickedButtonQueryPjSpace();
    afx_msg void OnBnClickedButtonCreatePj();
    afx_msg void OnBnClickedButtonCreateCj();
    afx_msg void OnBnClickedButtonCtrlOffline();
    afx_msg void OnBnClickedButtonCtrlOnlineLocal();
    afx_msg void OnBnClickedButtonCtrlOnlineRemote();
    afx_msg void OnBnClickedButtonQueryControlState();
};
SourceCode/Bond/EAPSimulator/Resource.h
@@ -58,6 +58,10 @@
#define IDC_BUTTON_CREATE_CJ            1040
#define IDC_BUTTON_DELETE               1041
#define IDC_BUTTON_PROCEED_WITH_SLOTMAP 1042
#define IDC_BUTTON_CTRL_OFFLINE         1043
#define IDC_BUTTON_CTRL_ONLINE_LOCAL    1044
#define IDC_BUTTON_CTRL_ONLINE_REMOTE   1045
#define IDC_BUTTON_QUERY_CONTROL_STATE  1046
// Next default values for new objects
// 
@@ -65,7 +69,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        143
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1043
#define _APS_NEXT_CONTROL_VALUE         1047
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif
SourceCode/Bond/Servo/CPageCtrlState.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,157 @@
// CPageCtrlState.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "Servo.h"
#include "CPageCtrlState.h"
#include "afxdialogex.h"
#include "Common.h"
#include "Model.h"
#include "ColorTransfer.h"
// CPageCtrlState å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CPageCtrlState, CDialogEx)
CPageCtrlState::CPageCtrlState(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_PROD_CTRL_STATE, pParent)
{
}
CPageCtrlState::~CPageCtrlState()
{
}
void CPageCtrlState::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BUTTON_OFFLINE, m_btnOffline);
    DDX_Control(pDX, IDC_BUTTON_ONLINE_LOCAL, m_btnOnlineLocal);
    DDX_Control(pDX, IDC_BUTTON_ONLINE_REMOTE, m_btnOnlineRemote);
}
BEGIN_MESSAGE_MAP(CPageCtrlState, CDialogEx)
    ON_WM_CTLCOLOR()
    ON_WM_SIZE()
    ON_WM_DESTROY()
    ON_BN_CLICKED(IDC_BUTTON_OFFLINE, &CPageCtrlState::OnBnClickedOffline)
    ON_BN_CLICKED(IDC_BUTTON_ONLINE_LOCAL, &CPageCtrlState::OnBnClickedOnlineLocal)
    ON_BN_CLICKED(IDC_BUTTON_ONLINE_REMOTE, &CPageCtrlState::OnBnClickedOnlineRemote)
END_MESSAGE_MAP()
// CPageCtrlState æ¶ˆæ¯å¤„理程序
void CPageCtrlState::InitRxWindows()
{
    IRxWindows* pRxWindows = RX_GetRxWindows();
    if (m_pObserver == nullptr) {
        m_pObserver = pRxWindows->allocObserver([this](IAny* pAny) -> void {
            pAny->addRef();
            const int code = pAny->getCode();
            if (code == RX_CODE_CONTROL_STATE_CHANGED && ::IsWindow(m_hWnd)) {
                UpdateButtonStyles();
            }
            pAny->release();
            }, [&]() -> void {
                // onComplete
            }, [&](IThrowable* pThrowable) -> void {
                // onError
                pThrowable->printf();
            });
        theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
            ->subscribe(m_pObserver);
    }
}
void CPageCtrlState::ApplyButtonTheme(CBlButton& btn, bool active)
{
    const COLORREF text = active ? RGB(255, 255, 255) : RGB(0, 0, 0);
    const COLORREF normal = active ? RGB(34, 177, 76) : RGB(222, 222, 222);
    const COLORREF hover = CColorTransfer::ApproximateColor(normal, active ? 0.08 : 0.05);
    const COLORREF press = CColorTransfer::ApproximateColor(normal, active ? -0.10 : -0.12);
    const COLORREF frame = active ? CColorTransfer::ApproximateColor(normal, -0.18) : RGB(168, 168, 168);
    btn.SetRoundWidth(6);
    btn.SetTextColor(BS_NORMAL, text);
    btn.SetTextColor(BS_HOVER, text);
    btn.SetTextColor(BS_PRESS, text);
    btn.SetTextColor(BS_DISABLE, RGB(120, 120, 120));
    btn.SetBkgndColor(BS_NORMAL, normal);
    btn.SetBkgndColor(BS_HOVER, hover);
    btn.SetBkgndColor(BS_PRESS, press);
    btn.SetBkgndColor(BS_DISABLE, RGB(210, 210, 210));
    btn.SetFrameColor(BS_NORMAL, frame);
    btn.SetFrameColor(BS_HOVER, frame);
    btn.SetFrameColor(BS_PRESS, frame);
    btn.SetFrameColor(BS_DISABLE, RGB(180, 180, 180));
}
void CPageCtrlState::UpdateButtonStyles()
{
    const auto state = theApp.m_model.getControlState();
    ApplyButtonTheme(m_btnOffline, state == ControlState::OfflineEquipment || state == ControlState::OfflineHost);
    ApplyButtonTheme(m_btnOnlineLocal, state == ControlState::OnlineLocal);
    ApplyButtonTheme(m_btnOnlineRemote, state == ControlState::OnlineRemote);
    Invalidate();
    UpdateWindow();
}
BOOL CPageCtrlState::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  åœ¨æ­¤æ·»åŠ é¢å¤–çš„åˆå§‹åŒ–
    InitRxWindows();
    UpdateButtonStyles();
    return TRUE;  // return TRUE unless you set the focus to a control
                  // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
HBRUSH CPageCtrlState::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    // TODO:  åœ¨æ­¤æ›´æ”¹ DC çš„任何特性
    // TODO:  å¦‚果默认的不是所需画笔,则返回另一个画笔
    return hbr;
}
void CPageCtrlState::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    // TODO: åœ¨æ­¤å¤„添加消息处理程序代码
}
void CPageCtrlState::OnDestroy()
{
    CDialogEx::OnDestroy();
    // TODO: åœ¨æ­¤å¤„添加消息处理程序代码
}
void CPageCtrlState::OnBnClickedOffline()
{
    theApp.m_model.setControlState(ControlState::OfflineEquipment);
}
void CPageCtrlState::OnBnClickedOnlineLocal()
{
    theApp.m_model.setControlState(ControlState::OnlineLocal);
}
void CPageCtrlState::OnBnClickedOnlineRemote()
{
    theApp.m_model.setControlState(ControlState::OnlineRemote);
}
SourceCode/Bond/Servo/CPageCtrlState.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
#pragma once
#include "BlButton.h"
// CPageCtrlState å¯¹è¯æ¡†
class CPageCtrlState : public CDialogEx
{
    DECLARE_DYNAMIC(CPageCtrlState)
public:
    CPageCtrlState(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CPageCtrlState();
private:
    void InitRxWindows();
    void UpdateButtonStyles();
    void ApplyButtonTheme(CBlButton& btn, bool active);
    CBlButton m_btnOffline;
    CBlButton m_btnOnlineLocal;
    CBlButton m_btnOnlineRemote;
    IObserver* m_pObserver{ nullptr };
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_PROD_CTRL_STATE };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnDestroy();
    afx_msg void OnBnClickedOffline();
    afx_msg void OnBnClickedOnlineLocal();
    afx_msg void OnBnClickedOnlineRemote();
};
SourceCode/Bond/Servo/CPanelProduction.cpp
@@ -24,6 +24,7 @@
    m_pStatsThread = nullptr;
    m_pAccordionWnd = nullptr;
    m_pPageProdOverview = nullptr;
    m_pPageCtrlState = nullptr;
}
CPanelProduction::~CPanelProduction()
@@ -77,6 +78,12 @@
    m_pAccordionWnd->Setpadding(PADDING_BOTTOM, 2);
    m_pAccordionWnd->LoadExpandIcon(strExpandIcon, strCloseIcon);
    m_pPageCtrlState = new CPageCtrlState();
    m_pPageCtrlState->SetBackgroundColor(m_crBkgnd);
    m_pPageCtrlState->Create(IDD_PROD_CTRL_STATE, GetDlgItem(IDC_ACCORDION_WND1));
    m_pPageCtrlState->ShowWindow(SW_HIDE);
    m_pAccordionWnd->AddItem("状态", m_pPageCtrlState, 120, TRUE, TRUE);
    m_pPageProdOverview = new CPageProdOverview();
    m_pPageProdOverview->SetBackgroundColor(m_crBkgnd);
    m_pPageProdOverview->Create(IDD_PROD_OVERVIEW, GetDlgItem(IDC_ACCORDION_WND1));
@@ -112,6 +119,17 @@
    CDialogEx::OnDestroy();
    if (m_pPageCtrlState != nullptr) {
        m_pPageCtrlState->DestroyWindow();
        delete m_pPageCtrlState;
        m_pPageCtrlState = nullptr;
    }
    if (m_pPageProdOverview != nullptr) {
        m_pPageProdOverview->DestroyWindow();
        delete m_pPageProdOverview;
        m_pPageProdOverview = nullptr;
    }
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
SourceCode/Bond/Servo/CPanelProduction.h
@@ -4,6 +4,7 @@
#include "AccordionWnd.h"
#include "ProductionStats.h"
#include "CPageProdOverview.h"
#include "CPageCtrlState.h"
// CPanelProduction dialog
class CPanelProduction : public CDialogEx
@@ -32,6 +33,7 @@
    CWinThread* m_pStatsThread;
    CEvent m_evStopStats;
    CPageProdOverview* m_pPageProdOverview;
    CPageCtrlState* m_pPageCtrlState;
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
SourceCode/Bond/Servo/Common.h
@@ -19,6 +19,7 @@
#define RX_CODE_MASTER_STATE_CHANGED    1011
#define RX_CODE_EQ_ROBOT_TASK            1012
#define RX_CODE_LOADPORT_STATUS_CHANGED    1014
#define RX_CODE_CONTROL_STATE_CHANGED    1015
/* Channel Name */
SourceCode/Bond/Servo/HsmsPassive.cpp
@@ -12,6 +12,9 @@
#include <set>
#include <regex>
// ControlState values (keep in sync with Model::ControlState / VariableList.txt)
static constexpr uint8_t kControlStateOnlineRemote = 5;
const char ACK[2] = {0, 1};
const char* ACK0 = &ACK[0];
@@ -442,6 +445,21 @@
    }
    return nullptr;
}
int CHsmsPassive::getCurrentControlState()
{
    auto v = getVariable("CurrentControlState");
    if (v != nullptr) {
        return static_cast<int>(v->getIntValue());
    }
    return 0;
}
bool CHsmsPassive::isHostCommandAllowed()
{
    // Only allow host control commands in OnlineRemote.
    return getCurrentControlState() == kControlStateOnlineRemote;
}
void CHsmsPassive::clearAllVariabel()
@@ -1784,9 +1802,14 @@
        goto MYREPLY;
    }
    if (!pBody->getSubItemU2(0, SVID)) {
        // also accept I2 or U4 to be tolerant with host implementations
        if (!pBody->getSubItemI2(0, (short&)SVID)) {
            pMessage->getBody()->addU1Item(SVU1, "SV");
            goto MYREPLY;
            unsigned int svidU4 = 0;
            if (!pBody->getSubItemU4(0, svidU4)) {
                pMessage->getBody()->addU1Item(SVU1, "SV");
                goto MYREPLY;
            }
            SVID = static_cast<unsigned short>(svidU4);
        }
    }
@@ -2216,6 +2239,13 @@
        goto MYREPLY;
    }
    if (!isHostCommandAllowed()) {
        CAACK = CAACK_5;
        ERRCODE = CAACK_5;
        strError = "rejected - ControlState not OnlineRemote";
        goto MYREPLY;
    }
    ISECS2Item* pBody = pRecv->getBody();
    if (pBody == nullptr || pBody->getType() != SITYPE::L) ER_PARAM_ERROR;
@@ -2419,6 +2449,13 @@
    ISECS2Item* pReplyItemAck = pReplyItemAcks->addU1Item(0, "OBJACK");
    ISECS2Item* pReplyItemErrs = pReplyItemAcks->addItem();
    if (!isHostCommandAllowed()) {
        ISECS2Item* pItemError = pReplyItemErrs->addItem();
        pItemError->addU4Item(2001, "ERRCODE");
        pItemError->addItem("rejected - ControlState not OnlineRemote", "ERRTEXT");
        goto MYREPLY;
    }
    // å½“前只处理类各为ControlJob
    if (_strcmpi(pszObjType, "ControlJob") == 0) {
@@ -2533,6 +2570,25 @@
    ISECS2Item* pBody = pRecv->getBody();
    if (pBody == nullptr || pBody->getType() != SITYPE::L) ER_PARAM_ERROR;
    if (!isHostCommandAllowed()) {
        IMessage* pMessage = NULL;
        HSMS_Create1Message(pMessage, m_nSessionId, 16, 16, ++m_nSystemByte);
        ASSERT(pMessage);
        ISECS2Item* pItemPrjobIds = pMessage->getBody()->addItem();
        ISECS2Item* pItemErrors = pMessage->getBody()->addItem();
        pItemErrors->addBoolItem(false, "ACKA");
        ISECS2Item* pItemErrors2 = pItemErrors->addItem();
        auto err = pItemErrors2->addItem();
        err->addU4Item(2001, "ERRCODE");
        err->addItem("rejected - ControlState not OnlineRemote", "ERRTEXT");
        m_pPassive->sendMessage(pMessage);
        LOGI("<HSMS>[SEND]sessionId:%d, sType:%d systemBytes:%d",
            pMessage->getHeader()->sessionId, pMessage->getHeader()->sType, pMessage->getHeader()->systemBytes);
        LOGI("<HSMS>[SEND]%s", pMessage->toString());
        HSMS_Destroy1Message(pMessage);
        return 0;
    }
    // è§£é‡Šæ•°æ®ï¼Œå¾—到CProcessJob
    ISECS2Item* pItemPjs, * pItemPj,* pItemCarriers, * pItemCarrier, *pItemSlots, *pItemRecipes;
SourceCode/Bond/Servo/HsmsPassive.h
@@ -150,6 +150,8 @@
    // å–得指定Variable
    SERVO::CVariable* getVariable(int variableId);
    SERVO::CVariable* getVariable(const char* pszName);
    int getCurrentControlState();
    bool isHostCommandAllowed();
    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);
SourceCode/Bond/Servo/Model.cpp
@@ -31,6 +31,24 @@
    m_hsmsPassive.setVariableValue("PJobSpace", (__int64)(m_master.isProcessJobsEmpty() ? 1 : 0));
}
void CModel::setControlState(ControlState newState)
{
    const auto prev = m_currentControlState;
    if (newState != m_currentControlState) {
        m_hsmsPassive.setVariableValue("PreviousControlState", (__int64)static_cast<uint8_t>(prev));
        m_currentControlState = newState;
    }
    // Always keep SV in sync (even if state didn't change or variables were just loaded).
    m_hsmsPassive.setVariableValue("CurrentControlState", (__int64)static_cast<uint8_t>(m_currentControlState));
    if (newState != prev) {
        // S6F11 (CEID=600): ControlStateChanged
        m_hsmsPassive.requestEventReportSend("ControlStateChanged");
        notifyInt(RX_CODE_CONTROL_STATE_CHANGED, static_cast<int>(m_currentControlState));
    }
}
IObservable* CModel::getObservable()
{
    if (m_pObservable == nullptr) {
@@ -117,16 +135,31 @@
    SECSListener listener;
    listener.onEQOffLine = [&](void* pFrom) -> void {
    listener.onEQOffLine = [this](void* pFrom) -> void {
        LOGI("远程请求OffLine");
        (void)pFrom;
        setControlState(ControlState::OfflineHost);
    };
    listener.onEQOnLine = [&](void* pFrom) -> void {
    listener.onEQOnLine = [this](void* pFrom) -> void {
        LOGI("远程请求OnLine");
        (void)pFrom;
        // Customer flow: S1F17 RequestOnline defaults to OnlineRemote.
        setControlState(ControlState::OnlineRemote);
    };
    listener.onCommand = [&](void* pFrom, const char* pszName, std::vector<CommandParameter>& params) -> void {
    listener.onCommand = [this](void* pFrom, const char* pszName, std::vector<CommandParameter>& params) -> void {
        LOGI("onCommand:%s", pszName);
        (void)pFrom;
        for (auto& item : params) {
            LOGI("param:%s,%s", item.szName, item.szValue);
        }
        if (pszName == nullptr) return;
        // S2F41 GoLocal / GoRemote (RCMD)
        if (_strcmpi(pszName, "GoLocal") == 0 || _strcmpi(pszName, "LOCAL") == 0 || _strcmpi(pszName, "GoLOCAL") == 0) {
            setControlState(ControlState::OnlineLocal);
        }
        else if (_strcmpi(pszName, "GoRemote") == 0 || _strcmpi(pszName, "REMOTE") == 0 || _strcmpi(pszName, "GoREMOTE") == 0) {
            setControlState(ControlState::OnlineRemote);
        }
    };
    listener.onEQConstantRequest = [&](void* pFrom, std::vector<EQConstant>& eqcs) -> void {
@@ -253,6 +286,7 @@
    CString strVarialbleFile;
    strVarialbleFile.Format(_T("%s\\VariableList.txt"), (LPTSTR)(LPCTSTR)m_strWorkDir);
    m_hsmsPassive.loadVarialbles((LPTSTR)(LPCTSTR)strVarialbleFile);
    setControlState(m_currentControlState);
    refreshDerivedSVs();
    m_hsmsPassive.init(this, "APP", 7000);
    strVarialbleFile.Format(_T("%s\\ReportList.txt"), (LPTSTR)(LPCTSTR)m_strWorkDir);
SourceCode/Bond/Servo/Model.h
@@ -3,6 +3,16 @@
#include "HsmsPassive.h"
#include "CMaster.h"
#include "CGlassPool.h"
#include <cstdint>
enum class ControlState : uint8_t {
    OfflineEquipment = 0,
    OfflineAttempt = 1,
    Online = 2,
    OfflineHost = 3,
    OnlineLocal = 4,
    OnlineRemote = 5,
};
class CModel
{
@@ -20,6 +30,9 @@
    void setPortEnable(unsigned int index, BOOL bEnable);
    int init();
    int term();
    ControlState getControlState() const noexcept { return m_currentControlState; }
    void setControlState(ControlState newState);
private:
    void refreshDerivedSVs();
@@ -49,5 +62,7 @@
    IObservableEmitter* m_pObservableEmitter;
    CString m_strWorkDir;
    CString m_strDataDir;
};
private:
    ControlState m_currentControlState{ ControlState::OfflineEquipment };
};
SourceCode/Bond/Servo/Servo.rc
@@ -826,6 +826,15 @@
    CTEXT           "-",IDC_PROD_NIGHT_TAKT,126,82,68,45,SS_CENTERIMAGE
END
IDD_PROD_CTRL_STATE DIALOGEX 0, 0, 216, 97
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    PUSHBUTTON      "Offline",IDC_BUTTON_OFFLINE,9,15,58,27
    PUSHBUTTON      "Online Local",IDC_BUTTON_ONLINE_LOCAL,74,15,58,27
    PUSHBUTTON      "Online Remote",IDC_BUTTON_ONLINE_REMOTE,138,15,58,27
END
/////////////////////////////////////////////////////////////////////////////
//
@@ -1271,6 +1280,14 @@
        TOPMARGIN, 7
        BOTTOMMARGIN, 152
    END
    IDD_PROD_CTRL_STATE, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 209
        TOPMARGIN, 7
        BOTTOMMARGIN, 90
    END
END
#endif    // APSTUDIO_INVOKED
@@ -1530,6 +1547,11 @@
    0
END
IDD_PROD_CTRL_STATE AFX_DIALOG_LAYOUT
BEGIN
    0
END
/////////////////////////////////////////////////////////////////////////////
//
SourceCode/Bond/Servo/Servo.vcxproj
@@ -242,6 +242,7 @@
    <ClInclude Include="ClientListDlg.h" />
    <ClInclude Include="CMyStatusbar.h" />
    <ClInclude Include="CPageCollectionEvent.h" />
    <ClInclude Include="CPageCtrlState.h" />
    <ClInclude Include="CPageGlassList.h" />
    <ClInclude Include="CPageLinkSignal.h" />
    <ClInclude Include="CPageProdOverview.h" />
@@ -468,6 +469,7 @@
    <ClCompile Include="ClientListDlg.cpp" />
    <ClCompile Include="CMyStatusbar.cpp" />
    <ClCompile Include="CPageCollectionEvent.cpp" />
    <ClCompile Include="CPageCtrlState.cpp" />
    <ClCompile Include="CPageGlassList.cpp" />
    <ClCompile Include="CPageLinkSignal.cpp" />
    <ClCompile Include="CPageProdOverview.cpp" />
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -242,6 +242,7 @@
    <ClCompile Include="AccordionWnd.cpp" />
    <ClCompile Include="CPageProdOverview.cpp" />
    <ClCompile Include="HmLabel.cpp" />
    <ClCompile Include="CPageCtrlState.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AlarmManager.h" />
@@ -526,6 +527,7 @@
    <ClInclude Include="AccordionWnd.h" />
    <ClInclude Include="CPageProdOverview.h" />
    <ClInclude Include="HmLabel.h" />
    <ClInclude Include="CPageCtrlState.h" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc" />
SourceCode/Bond/Servo/resource.h
@@ -61,12 +61,13 @@
#define IDD_CJ_PAGE3                    180
#define IDD_DIALOG_USER_MANAGER2        181
#define IDD_DIALOG_USER_EDIT2           182
#define IDD_PROD_OVERVIEW                183
#define IDD_PROD_OVERVIEW               183
#define IDD_DIALOG_USERX_LOG            184
#define IDD_DIALOG_VARIABLE_EDIT2       186
#define IDD_DIALOG_REPORT_EDIT          187
#define IDD_DIALOG_EVENT_EDIT           188
#define IDD_PANEL_PRODUCTION            189
#define IDD_PROD_CTRL_STATE             190
#define IDC_SERVO_GRAPH1                1001
#define IDC_BUTTON_LOG                  1002
#define IDC_EDIT_LOG                    1003
@@ -324,10 +325,13 @@
#define IDC_EDIT_EVT_DESC               1245
#define IDC_LIST_EVT_RPTS               1246
#define IDC_ACCORDION_WND1              1247
#define IDC_PROD_DAY_OUTPUT                1248
#define IDC_PROD_NIGHT_OUTPUT            1249
#define IDC_PROD_DAY_TAKT                1250
#define IDC_PROD_NIGHT_TAKT                1251
#define IDC_PROD_DAY_OUTPUT             1248
#define IDC_PROD_NIGHT_OUTPUT           1249
#define IDC_PROD_DAY_TAKT               1250
#define IDC_PROD_NIGHT_TAKT             1251
#define IDC_BUTTON_OFFLINE              1252
#define IDC_BUTTON_ONLINE_LOCAL         1253
#define IDC_BUTTON_ONLINE_REMOTE        1254
#define ID_MENU_HELP_ABOUT              32771
#define ID_MENU_FILE_EXIT               32772
#define ID_MENU_FILE_SECSTEST           32773
@@ -367,7 +371,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        191
#define _APS_NEXT_COMMAND_VALUE         32804
#define _APS_NEXT_CONTROL_VALUE         1252
#define _APS_NEXT_CONTROL_VALUE         1255
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif