LAPTOP-SNT8I5JK\Boounion
2025-03-10 19261d011387ec57d646decc945aadaf8913eeab
Merge branch 'clh'

# Conflicts:
# SourceCode/Bond/Servo/AlarmDlg.cpp
# SourceCode/Bond/Servo/AlarmDlg.h
# SourceCode/Bond/Servo/AlarmManager.cpp
# SourceCode/Bond/Servo/AlarmManager.h
# SourceCode/Bond/Servo/CEqAlarmStep.cpp
# SourceCode/Bond/Servo/CEqAlarmStep.h
# SourceCode/Bond/Servo/CMaster.cpp
# SourceCode/Bond/Servo/CStep.cpp
# SourceCode/Bond/Servo/CStep.h
# SourceCode/Bond/Servo/Common.h
# SourceCode/Bond/Servo/Model.cpp
# SourceCode/Bond/Servo/Servo.cpp
# SourceCode/Bond/Servo/Servo.rc
# SourceCode/Bond/Servo/Servo.vcxproj.filters
# SourceCode/Bond/Servo/ServoDlg.cpp
# SourceCode/Bond/Servo/ServoDlg.h
# SourceCode/Bond/Servo/resource.h
已添加26个文件
已修改33个文件
4341 ■■■■ 文件已修改
.gitignore 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmDlg.cpp 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmDlg.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/AlarmManager.h 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ApredTreeCtrl2.cpp 379 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ApredTreeCtrl2.h 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CAttribute.cpp 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CAttribute.h 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CAttributeVector.cpp 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CAttributeVector.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp 442 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h 412 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqAlarmStep.cpp 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqAlarmStep.h 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqCimModeChangeStep.cpp 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqCimModeChangeStep.h 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqModeStep.cpp 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqModeStep.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqProcessStep.cpp 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqProcessStep.h 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqStatusStep.cpp 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEqStatusStep.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.cpp 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CEquipment.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.cpp 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CMaster.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelAttributes.cpp 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelAttributes.h 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelEquipment.cpp 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelEquipment.h 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelMaster.cpp 207 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CPanelMaster.h 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CReadStep.cpp 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CReadStep.h 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CStep.cpp 166 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CStep.h 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CWriteStep.cpp 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/CWriteStep.h 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Common.h 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HorizontalLine.cpp 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/HorizontalLine.h 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.cpp 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.user 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 141 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoGraph.cpp 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoGraph.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ToolUnits.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ToolUnits.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/VerticalLine.cpp 316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/VerticalLine.h 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/Res/panel_close_24_a.ico 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/x64/Debug/Res/panel_close_24_b.ico 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -48,3 +48,4 @@
*.iom
SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.user
SourceCode/Bond/x64/Debug/ServoConfiguration.ini
*.iobj
SourceCode/Bond/Servo/AlarmDlg.cpp
@@ -5,6 +5,7 @@
#include "Servo.h"
#include "afxdialogex.h"
#include "AlarmDlg.h"
#include "AlarmManager.h"
#include "Common.h"
#include <iomanip>
@@ -84,13 +85,14 @@
                        bool result = alarmManager.addAlarm(alarmData, alarmEventId);
                        if (result) {
                            LOGI("<CAlarmDlg> Alarm added successfully!");
                        }
                    }
                        else {
                            LOGI("<CAlarmDlg> Failed to add alarm.");
                        }
                    }
                }
            }
                }
            }
        pAny->release();
        }, [&]() -> void {
@@ -277,7 +279,6 @@
    pListCtrl->SetColumnWidth(7, LVSCW_AUTOSIZE_USEHEADER);
    // è®¡ç®—总页数
    int totalRecords = AlarmManager::getInstance().getTotalAlarmCount("", "", m_strDeviceName, m_strUnitName, m_strKeyword, m_szTimeStart, m_szTimeEnd);
    m_nTotalPages = (totalRecords + PAGE_SIZE - 1) / PAGE_SIZE;
    m_nCurPage = 1;
@@ -286,6 +287,11 @@
    return TRUE;  // return TRUE unless you set the focus to a control
    // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
BOOL CAlarmDlg::DestroyWindow()
{
    return CDialogEx::DestroyWindow();
}
HBRUSH CAlarmDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
@@ -471,4 +477,4 @@
    // ç‚¹å‡»ä¸‹ä¸€é¡µ
    m_nCurPage++;
    UpdatePageData();  // è°ƒç”¨åˆ†é¡µæ›´æ–°å‡½æ•°
}
}
SourceCode/Bond/Servo/AlarmDlg.h
@@ -57,6 +57,7 @@
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    virtual BOOL OnInitDialog();
    virtual BOOL DestroyWindow();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    afx_msg void OnDestroy();
    afx_msg void OnClose();
SourceCode/Bond/Servo/AlarmManager.h
@@ -262,6 +262,34 @@
    */
    std::vector<AlarmInfo> getAlarmsInfoByIDs(const std::vector<int>& alarmIDs) const;
    /**
     * è¯»å–报警文件
     * @param filename æ–‡ä»¶å
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool readAlarmFile(const std::string& filename);
    /**
     * ä¿å­˜æŠ¥è­¦æ–‡ä»¶
     * @param filename æ–‡ä»¶å
     * @return æˆåŠŸè¿”å›žtrue,失败返回false
     */
    bool saveAlarmFile(const std::string& filename);
    /**
     * é€šè¿‡æŠ¥è­¦ID查询报警信息
     * @param nAlarmID æŠ¥è­¦ID
     * @return æŠ¥è­¦ä¿¡æ¯çš„æŒ‡é’ˆ
     */
    const AlarmInfo* getAlarmInfoByID(int nAlarmID) const;
    /**
    * é€šè¿‡å¤šä¸ªæŠ¥è­¦ID查询对应的报警信息
    * @param alarmIDs å¤šä¸ªæŠ¥è­¦ID
    * @return è¿”回多个报警信息
    */
    std::vector<AlarmInfo> getAlarmsInfoByIDs(const std::vector<int>& alarmIDs) const;
private:
    AlarmManager();
    ~AlarmManager();
SourceCode/Bond/Servo/ApredTreeCtrl2.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,379 @@
#include "stdafx.h"
#include "ApredTreeCtrl2.h"
#define ROFFSET 7
#define WIDE    10
#define WIDE2    5
#define EXPANDED_WIDE    8
#define BADGE_HIDE                  0
#define BADGE_DOT                   1
#define BADGE_NUMBER                2
#define BADGE_DOT_WIDTH             12
#define BADGE_NUMBER_WIDTH          20
IMPLEMENT_DYNAMIC(CApredTreeCtrl2, CTreeCtrl)
CApredTreeCtrl2::CApredTreeCtrl2()
{
    m_hBrushItem[0] = NULL;
    m_hBrushItem[1] = NULL;
    m_hBrushItem[2] = NULL;
    m_crItemBk[0] = GetSysColor(COLOR_WINDOW);
    m_crItemBk[1] = GetSysColor(COLOR_HIGHLIGHT);
    m_crItemBk[2] = RGB(204, 206, 219);
    m_crItemBtn[0] = RGB(30, 30, 30);
    m_crItemBtn[1] = RGB(255, 255, 255);
    m_crItemBtn[2] = RGB(255, 255, 255);
}
CApredTreeCtrl2::~CApredTreeCtrl2()
{
    if (m_hBrushItem[0] != NULL) {
        ::DeleteObject(m_hBrushItem[0]);
    }
    if (m_hBrushItem[1] != NULL) {
        ::DeleteObject(m_hBrushItem[1]);
    }
    if (m_hBrushItem[2] != NULL) {
        ::DeleteObject(m_hBrushItem[2]);
    }
}
BEGIN_MESSAGE_MAP(CApredTreeCtrl2, CTreeCtrl)
    ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CApredTreeCtrl2::OnNMCustomdraw)
END_MESSAGE_MAP()
void CApredTreeCtrl2::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
    LPNMTVCUSTOMDRAW lpnmcd = (LPNMTVCUSTOMDRAW)pNMCD;
    HTREEITEM hItem;
    UINT unt;
    *pResult = 0;
    switch (lpnmcd->nmcd.dwDrawStage)
    {
    case CDDS_PREPAINT:
        *pResult = CDRF_NOTIFYITEMDRAW;
        m_items.clear();
        break;
    case CDDS_ITEMPREPAINT:
        m_items[(HTREEITEM)lpnmcd->nmcd.dwItemSpec] = lpnmcd->iLevel;
        hItem = (HTREEITEM)lpnmcd->nmcd.dwItemSpec;
        if (hItem != NULL) {
            if ( (GetItemState(hItem, TVIS_SELECTED) & TVIS_SELECTED)== TVIS_SELECTED) {
                if (GetFocus() != this) {
                    lpnmcd->clrTextBk = RGB(204, 206, 219);
                }
            }
        }
        *pResult = CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT;   // è®¢é˜…绘制结束通知
        break;
    case CDDS_ITEMPOSTPAINT: // é¡¹ç»˜åˆ¶ç»“束通知
        unt = GetIndent();
        hItem = (HTREEITEM)lpnmcd->nmcd.dwItemSpec;
        auto iter = m_items.find(hItem);
        if (iter != m_items.end()) {
            CRect button_rect = pNMCD->rc;
            button_rect.right = button_rect.left + unt + 5;
            int off = unt * iter->second;
            button_rect.OffsetRect(off, 0);
            DrawItemButton(hItem, pNMCD->hdc, &button_rect);
            // æ˜¯å¦æœ‰å°åœ†ç‚¹
            CRect rcItem = pNMCD->rc;
            Gdiplus::Graphics graphics(pNMCD->hdc);
            graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
            if (m_badges.find(hItem) != m_badges.end()) {
                BADGE& badge = m_badges[hItem];
                if (badge.type == BADGE_DOT) {
                    Gdiplus::SolidBrush brush(Gdiplus::Color(GetRValue(badge.badgeBackground), GetGValue(badge.badgeBackground), GetBValue(badge.badgeBackground)));
                    int x = rcItem.right - 18 - BADGE_DOT_WIDTH;
                    int y = rcItem.top + (rcItem.Height() - BADGE_DOT_WIDTH) / 2;
                    graphics.FillEllipse(&brush, x, y, BADGE_DOT_WIDTH, BADGE_DOT_WIDTH);
                }
                else if (badge.type == BADGE_NUMBER) {
                    Gdiplus::SolidBrush brush(Gdiplus::Color(GetRValue(badge.badgeBackground), GetGValue(badge.badgeBackground), GetBValue(badge.badgeBackground)));
                    int x = rcItem.right - 18 - BADGE_NUMBER_WIDTH;
                    int y = rcItem.top + (rcItem.Height() - BADGE_NUMBER_WIDTH) / 2;
                    graphics.FillEllipse(&brush, x, y, BADGE_NUMBER_WIDTH, BADGE_NUMBER_WIDTH);
                    RECT rcBadge;
                    rcBadge.left = x;
                    rcBadge.right = rcBadge.left + BADGE_NUMBER_WIDTH;
                    rcBadge.top = y;
                    rcBadge.bottom = rcBadge.top + BADGE_NUMBER_WIDTH;
                    ::SetTextColor(pNMCD->hdc, badge.badgeForeground);
                    char szBuffer[32];
                    sprintf_s(szBuffer, 32, "%d%s", min(badge.number, 9), badge.number > 9 ? "+" : "");
                    DrawText(pNMCD->hdc, szBuffer, (int)strlen(szBuffer), &rcBadge, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
                }
            }
            *pResult = CDRF_SKIPDEFAULT;
        }
        break;
    }
}
void CApredTreeCtrl2::DrawItemButton(HTREEITEM hItem, HDC hDC, CRect* pRect)
{
    if (!ItemHasChildren(hItem)) {
        return;
    }
    // æŒ‰é’®è¦åˆ·ä¸€ä¸‹
    ::FillRect(hDC, pRect, GetItemBkBrush(hItem));
    if ((GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED) == TVIS_EXPANDED) {
        int nBottomOffset = (pRect->Height() - EXPANDED_WIDE) / 2;
        POINT pt[3];
        pt[0].x = pRect->right - ROFFSET - EXPANDED_WIDE;
        pt[0].y = pRect->bottom - nBottomOffset;
        pt[1].x = pRect->right - ROFFSET;
        pt[1].y = pRect->bottom - nBottomOffset;
        pt[2].x = pRect->right - ROFFSET;
        pt[2].y = pRect->bottom - nBottomOffset - EXPANDED_WIDE;
        HBRUSH hBrush = GetItemBtnBrush(hItem);
        HPEN hPen = GetItemBtnPen(hItem);
        HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC, hBrush);
        HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
        ::Polygon(hDC, pt, 3);
        ::SelectObject(hDC, hOldBrush);
        ::SelectObject(hDC, hOldPen);
        ::DeleteObject(hBrush);
        ::DeleteObject(hPen);
    }
    else {
        int nBottomOffset = (pRect->Height() - WIDE) / 2;
        POINT pt[3];
        pt[0].x = pRect->right - ROFFSET - WIDE2;
        pt[0].y = pRect->bottom - nBottomOffset - WIDE;
        pt[1].x = pRect->right - ROFFSET - WIDE2;
        pt[1].y = pRect->bottom - nBottomOffset;
        pt[2].x = pRect->right - ROFFSET;
        pt[2].y = pRect->bottom - nBottomOffset - WIDE2;
        HBRUSH hBrush = GetItemBtnBrush(hItem);
        HPEN hPen = GetItemBtnPen(hItem);
        HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC, hBrush);
        HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
        ::Polygon(hDC, pt, 3);
        ::SelectObject(hDC, hOldBrush);
        ::SelectObject(hDC, hOldPen);
        ::DeleteObject(hBrush);
        ::DeleteObject(hPen);
    }
}
COLORREF CApredTreeCtrl2::SetBkColor(COLORREF crColor)
{
    if (m_hBrushItem[0] != NULL) {
        ::DeleteObject(m_hBrushItem[0]);
    }
    m_hBrushItem[0] = CreateSolidBrush(crColor);
    return CTreeCtrl::SetBkColor(crColor);
}
int CApredTreeCtrl2::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CTreeCtrl::OnCreate(lpCreateStruct) == -1)
        return -1;
    m_crItemBk[0] = GetBkColor();
    m_crItemBk[1] = GetSysColor(COLOR_HIGHLIGHT);
    m_hBrushItem[0] = CreateSolidBrush(m_crItemBk[0]);
    m_hBrushItem[1] = CreateSolidBrush(m_crItemBk[1]);
    m_hBrushItem[2] = CreateSolidBrush(m_crItemBk[2]);
    return 0;
}
HBRUSH CApredTreeCtrl2::GetItemBkBrush(HTREEITEM hItem)
{
    BOOL bSelected = (GetItemState(hItem, TVIS_SELECTED) & TVIS_SELECTED) == TVIS_SELECTED;
    BOOL bHilited = (GetItemState(hItem, TVIS_DROPHILITED) & TVIS_DROPHILITED) == TVIS_DROPHILITED;;
    HTREEITEM hClickedItem = GetDropHilightItem();
    if (bHilited) {
        return m_hBrushItem[1];
    }
    if (!bSelected) {
        return m_hBrushItem[0];
    }
    if (GetFocus() == this) {
        if (hClickedItem == NULL) {
            return m_hBrushItem[1];
        }
        else {
            return m_hBrushItem[0];
        }
    }
    return m_hBrushItem[2];
}
HBRUSH CApredTreeCtrl2::GetItemBtnBrush(HTREEITEM hItem)
{
    BOOL bExpanded = (GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED) == TVIS_EXPANDED;
    BOOL bSelected = (GetItemState(hItem, TVIS_SELECTED) & TVIS_SELECTED) == TVIS_SELECTED;
    BOOL bHilited = (GetItemState(hItem, TVIS_DROPHILITED) & TVIS_DROPHILITED) == TVIS_DROPHILITED;;
    HTREEITEM hClickedItem = GetDropHilightItem();
    // å±•开时实心三角
    if (bExpanded) {
        if (bHilited) {
            return CreateSolidBrush(m_crItemBtn[1]);
        }
        if (!bSelected) {
            return CreateSolidBrush(m_crItemBtn[0]);
        }
        if (GetFocus() == this && hClickedItem == NULL) {
            return CreateSolidBrush(m_crItemBtn[1]);
        }
        return CreateSolidBrush(m_crItemBtn[0]);
    }
    else {
        // æ”¶èµ·æ—¶ç©ºå¿ƒä¸‰è§’
        if (bHilited) {
            return CreateSolidBrush(m_crItemBk[1]);
        }
        if (!bSelected) {
            return CreateSolidBrush(m_crItemBk[0]);
        }
        if (GetFocus() == this && hClickedItem == NULL) {
            return CreateSolidBrush(m_crItemBk[1]);
        }
        return CreateSolidBrush(m_crItemBk[2]);
    }
}
HPEN CApredTreeCtrl2::GetItemBtnPen(HTREEITEM hItem)
{
    BOOL bExpanded = (GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED) == TVIS_EXPANDED;
    BOOL bSelected = (GetItemState(hItem, TVIS_SELECTED) & TVIS_SELECTED) == TVIS_SELECTED;
    BOOL bHilited = (GetItemState(hItem, TVIS_DROPHILITED) & TVIS_DROPHILITED) == TVIS_DROPHILITED;;
    HTREEITEM hClickedItem = GetDropHilightItem();
    // å±•开时实心三角
    if (bExpanded) {
        if (bHilited) {
            return CreatePen(PS_SOLID, 1, m_crItemBtn[1]);
        }
        if (!bSelected) {
            return CreatePen(PS_SOLID, 1, m_crItemBtn[0]);
        }
        if (GetFocus() == this && hClickedItem == NULL) {
            return CreatePen(PS_SOLID, 1, m_crItemBtn[1]);
        }
        return CreatePen(PS_SOLID, 1, m_crItemBtn[0]);
    }
    else {
        // æ”¶èµ·æ—¶ç©ºå¿ƒä¸‰è§’
        if (bHilited) {
            return CreatePen(PS_SOLID, 1, m_crItemBtn[1]);
        }
        if (!bSelected) {
            return CreatePen(PS_SOLID, 1, m_crItemBtn[0]);
        }
        if (GetFocus() == this && hClickedItem == NULL) {
            return CreatePen(PS_SOLID, 1, m_crItemBtn[1]);
        }
        return CreatePen(PS_SOLID, 1, m_crItemBtn[0]);
    }
}
void CApredTreeCtrl2::PreSubclassWindow()
{
    m_crItemBk[0] = GetBkColor();
    m_crItemBk[1] = GetSysColor(COLOR_HIGHLIGHT);
    m_hBrushItem[0] = CreateSolidBrush(m_crItemBk[0]);
    m_hBrushItem[1] = CreateSolidBrush(m_crItemBk[1]);
    m_hBrushItem[2] = CreateSolidBrush(m_crItemBk[2]);
    CTreeCtrl::PreSubclassWindow();
}
void CApredTreeCtrl2::SetItemBadge(HTREEITEM hItem, COLORREF badgeBackground, COLORREF badgeForeground)
{
    if (m_badges.find(hItem) == m_badges.end()) {
        BADGE badge;
        badge.badgeBackground = badgeBackground;
        badge.badgeForeground = badgeForeground;
        badge.type = BADGE_HIDE;
        m_badges[hItem] = badge;
    }
    else {
        BADGE& badge = m_badges[hItem];
        badge.badgeBackground = badgeBackground;
        badge.badgeForeground = badgeForeground;
        badge.type = BADGE_HIDE;
    }
}
void CApredTreeCtrl2::ShowItemBadgeNumber(HTREEITEM hItem, int number)
{
    if (m_badges.find(hItem) == m_badges.end()) {
        return;
    }
    BADGE& badge = m_badges[hItem];
    badge.type = BADGE_NUMBER;
    badge.number = number;
    InvalidateRect(NULL, TRUE);
}
void CApredTreeCtrl2::ShowItemBadgeDotMode(HTREEITEM hItem)
{
    if (m_badges.find(hItem) == m_badges.end()) {
        return;
    }
    BADGE& badge = m_badges[hItem];
    if (badge.type != BADGE_DOT) {
        badge.type = BADGE_DOT;
        InvalidateRect(NULL, TRUE);
    }
}
void CApredTreeCtrl2::HideItemBadge(HTREEITEM hItem)
{
    if (m_badges.find(hItem) == m_badges.end()) {
        return;
    }
    BADGE& badge = m_badges[hItem];
    if (badge.type != BADGE_HIDE) {
        badge.type = BADGE_HIDE;
        InvalidateRect(NULL, TRUE);
    }
}
SourceCode/Bond/Servo/ApredTreeCtrl2.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
#pragma once
#include <afxcmn.h>
#include <map>
class CApredTreeCtrl2 :
    public CTreeCtrl
{
public:
    typedef struct tagBADGE
    {
        HTREEITEM hTreeItem;
        COLORREF badgeBackground;
        COLORREF badgeForeground;
        int type;                       /* 0: æ— ,不显示*/
        int number;
    } BADGE;
    DECLARE_DYNAMIC(CApredTreeCtrl2)
public:
    CApredTreeCtrl2();
    virtual ~CApredTreeCtrl2();
public:
    virtual COLORREF SetBkColor(COLORREF crColor);
    void SetItemBadge(HTREEITEM hItem, COLORREF badgeBackground, COLORREF badgeForeground);
    void ShowItemBadgeNumber(HTREEITEM hItem, int number);
    void ShowItemBadgeDotMode(HTREEITEM hItem);
    void HideItemBadge(HTREEITEM hItem);
private:
    HBRUSH GetItemBkBrush(HTREEITEM hItem);
    HBRUSH GetItemBtnBrush(HTREEITEM hItem);
    HPEN GetItemBtnPen(HTREEITEM hItem);
    void DrawItemButton(HTREEITEM hItem, HDC hDC, CRect* pRect);
private:
    std::map<HTREEITEM, BADGE> m_badges;
    std::map<HTREEITEM, int> m_items;
    HBRUSH m_hBrushItem[3];
    COLORREF m_crItemBk[3];
    COLORREF m_crItemBtn[3];
public:
    DECLARE_MESSAGE_MAP()
    afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    virtual void PreSubclassWindow();
};
SourceCode/Bond/Servo/CAttribute.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
#include "stdafx.h"
#include "CAttribute.h"
namespace SERVO {
    CAttribute::CAttribute()
    {
    }
    CAttribute::CAttribute(const char* pszName, const char* pszValue, const char* pszDescription)
    {
        m_strName = pszName;
        m_strValue = pszValue;
        m_strDescription = pszDescription;
    }
    CAttribute::~CAttribute()
    {
    }
    std::string& CAttribute::getName()
    {
        return m_strName;
    }
    std::string& CAttribute::getValue()
    {
        return m_strValue;
    }
    std::string& CAttribute::getDescription()
    {
        return m_strDescription;
    }
}
SourceCode/Bond/Servo/CAttribute.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
#pragma once
namespace SERVO {
    class CAttribute
    {
    public:
        CAttribute();
        CAttribute(const char* pszName, const char* pszValue, const char* pszDescription);
        ~CAttribute();
    public:
        std::string& getName();
        std::string& getValue();
        std::string& getDescription();
    private:
        std::string m_strName;
        std::string m_strValue;
        std::string m_strDescription;
    };
}
SourceCode/Bond/Servo/CAttributeVector.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
#include "stdafx.h"
#include "CAttributeVector.h"
namespace SERVO {
    CAttributeVector::CAttributeVector()
    {
    }
    CAttributeVector::~CAttributeVector()
    {
        for (auto item : m_attributes) {
            delete item;
        }
        m_attributes.clear();
    }
    void CAttributeVector::addAttribute(CAttribute* pAttribute)
    {
        m_attributes.push_back(pAttribute);
    }
    unsigned int CAttributeVector::size()
    {
        return m_attributes.size();
    }
    void CAttributeVector::clear()
    {
        for (auto item : m_attributes) {
            delete item;
        }
        m_attributes.clear();
    }
    bool CAttributeVector::empty()
    {
        return m_attributes.empty();
    }
    CAttribute* CAttributeVector::getAttribute(unsigned int index)
    {
        ASSERT(index < m_attributes.size());
        return m_attributes[index];
    }
}
SourceCode/Bond/Servo/CAttributeVector.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
#pragma once
#include <vector>
#include "CAttribute.h"
namespace SERVO {
    class CAttributeVector
    {
    public:
        CAttributeVector();
        ~CAttributeVector();
    public:
        void addAttribute(CAttribute* pAttribute);
        void clear();
        unsigned int size();
        bool empty();
        CAttribute* getAttribute(unsigned int index);
    private:
        std::vector<CAttribute*> m_attributes;
    };
}
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
@@ -23,9 +23,9 @@
#define LOG_DEBUG(msg)
#endif
// åˆå§‹åŒ–静态成员变量
// åˆå§‹åŒ–静态成员变量
std::unordered_map<int, std::string> CPerformanceMelsec::m_mapError = {
    // æ¿å—SDK错误码
    // æ¿å—SDK错误码
    {0, "No error, communication successful."},
    {1, "Driver not started. The driver is not running."},
    {2, "Timeout error (board response error). Request not completed within timeout."},
@@ -118,7 +118,7 @@
    {-28634, "Hardware self-diagnosis error."},
    {-28636, "Hardware self-diagnosis error."},
    // è‡ªå®šä¹‰é”™è¯¯ç 
    // è‡ªå®šä¹‰é”™è¯¯ç 
    {ERROR_CODE_UNKNOWN, "Error: Unknown error code."},
    {ERROR_CODE_NOT_CONNECTED, "Error: Not connected to the device."},
    {ERROR_CODE_INVALID_PARAM, "Error: Invalid parameter."},
@@ -137,26 +137,26 @@
    m_bConnected.store(false);
}
// æžæž„函数
// æžæž„函数
CPerformanceMelsec::~CPerformanceMelsec() {
    Disconnect();
}
// èŽ·å–æœ€è¿‘çš„é”™è¯¯ä¿¡æ¯
// èŽ·å–æœ€è¿‘çš„é”™è¯¯ä¿¡æ¯
std::string CPerformanceMelsec::GetLastError() const {
    return m_strLastError;
}
// ä¿å­˜é”™è¯¯ä¿¡æ¯
// ä¿å­˜é”™è¯¯ä¿¡æ¯
bool CPerformanceMelsec::SaveErrorInfoToFile(const std::string& filename) {
    // æ‰“开文件
    // æ‰“开文件
    std::ofstream file(filename);
    if (!file.is_open()) {
        std::cerr << "Failed to open file for saving: " << filename << std::endl;
        return false;
    }
    // éåŽ†é™æ€æˆå‘˜å˜é‡ m_mapError å¹¶å°†æ¯ä¸ªé”™è¯¯ä¿¡æ¯å†™å…¥æ–‡ä»¶
    // éåŽ†é™æ€æˆå‘˜å˜é‡ m_mapError å¹¶å°†æ¯ä¸ªé”™è¯¯ä¿¡æ¯å†™å…¥æ–‡ä»¶
    for (const auto& entry : m_mapError) {
        const int nCode = entry.first;
        const std::string& strMessage = entry.second;
@@ -167,7 +167,7 @@
    return true;
}
// åŠ è½½é”™è¯¯ä¿¡æ¯
// åŠ è½½é”™è¯¯ä¿¡æ¯
bool CPerformanceMelsec::LoadErrorInfoFromFile(const std::string& filename) {
    std::ifstream inFile(filename);
    if (!inFile.is_open()) {
@@ -183,7 +183,7 @@
        std::string strToken;
        std::string strMessage;
        // ä½¿ç”¨åˆ†éš”符 "|" è§£æžæ¯ä¸€è¡Œ
        // ä½¿ç”¨åˆ†éš”符 "|" è§£æžæ¯ä¸€è¡Œ
        if (std::getline(iss, strToken, '|')) {
            nCode = std::stoi(strToken);
        }
@@ -200,7 +200,7 @@
    return true;
}
// è¿žæŽ¥åˆ°PLC
// è¿žæŽ¥åˆ°PLC
int CPerformanceMelsec::Connect(const short nChannel, const short nMode) {
    std::lock_guard<std::mutex> lock(m_mtx);
@@ -214,7 +214,7 @@
        return ERROR_CODE_INVALID_PARAM;
    }
    // è¿žæŽ¥PLC,显式类型转换以匹配 mdOpen çš„签名
    // è¿žæŽ¥PLC,显式类型转换以匹配 mdOpen çš„签名
    const short nRet = mdOpen(nChannel, nMode, &m_nPath);
    if (nRet == 0) {
        m_bConnected.store(true);
@@ -228,7 +228,7 @@
    return nRet;
}
// æ–­å¼€è¿žæŽ¥
// æ–­å¼€è¿žæŽ¥
int CPerformanceMelsec::Disconnect() {
    std::lock_guard<std::mutex> lock(m_mtx);
@@ -245,7 +245,7 @@
    return nRet;
}
// å¯ç¼–程控制器软元件信息表的初始化
// å¯ç¼–程控制器软元件信息表的初始化
int CPerformanceMelsec::InitializeController() {
    std::lock_guard<std::mutex> lock(m_mtx);
@@ -263,14 +263,14 @@
    return nRet;
}
// èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
// èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
int CPerformanceMelsec::GetBoardVersion(BoardVersion& version) {
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    // èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
    // èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
    short buf[32] = { 0 };
    const short nRet = mdBdVerRead(m_nPath, buf);
    if (nRet != 0) {
@@ -279,7 +279,7 @@
        return nRet;
    }
    // å¡«å……版本信息到结构体
    // å¡«å……版本信息到结构体
    version.fixedValue[0] = static_cast<char>(buf[0] & 0xFF);
    version.fixedValue[1] = static_cast<char>((buf[0] >> 8) & 0xFF);
@@ -310,16 +310,16 @@
    return nRet;
}
// è¯»å–目标站点CPU类型
// è¯»å–目标站点CPU类型
int CPerformanceMelsec::ReadCPUCode(const StationIdentifier& station, short& nCPUCode) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        nCPUCode = 0;
        std::lock_guard<std::mutex> lock(m_mtx);
@@ -334,15 +334,15 @@
    return nRet;
}
// æ¿æ¨¡å¼è®¾ç½®
// æ¿æ¨¡å¼è®¾ç½®
int CPerformanceMelsec::SetBoardMode(const short nMode) {
    // æ£€æŸ¥æ˜¯å¦å·²ç»è¿žæŽ¥
    // æ£€æŸ¥æ˜¯å¦å·²ç»è¿žæŽ¥
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    short nRet = 0;
    {
        std::lock_guard<std::mutex> lock(m_mtx);
@@ -357,9 +357,9 @@
    return nRet;
}
// èŽ·å–æ¿æ¨¡å¼
// èŽ·å–æ¿æ¨¡å¼
int CPerformanceMelsec::GetBoardMode(short& nMode) {
    // æ£€æŸ¥æ˜¯å¦å·²ç»è¿žæŽ¥
    // æ£€æŸ¥æ˜¯å¦å·²ç»è¿žæŽ¥
    if (!m_bConnected.load()) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
        return ERROR_CODE_NOT_CONNECTED;
@@ -381,7 +381,7 @@
    return 0;
}
// æ¿å¤ä½
// æ¿å¤ä½
int CPerformanceMelsec::BoardReset() {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected.load()) {
@@ -398,7 +398,7 @@
    return nRet;
}
// æ¿LED读取
// æ¿LED读取
int CPerformanceMelsec::ReadBoardLed(std::vector<short>& vecLedBuffer) {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected.load()) {
@@ -406,11 +406,11 @@
        return ERROR_CODE_NOT_CONNECTED;
    }
    // æ¸…空 LED ç¼“冲区
    // æ¸…空 LED ç¼“冲区
    vecLedBuffer.clear();
    vecLedBuffer.resize(16, 0);
    // è°ƒç”¨ SDK å‡½æ•°è¯»å– LED æ•°æ®
    // è°ƒç”¨ SDK å‡½æ•°è¯»å– LED æ•°æ®
    const short nRet = mdBdLedRead(m_nPath, vecLedBuffer.data());
    if (nRet != 0) {
        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
@@ -421,7 +421,7 @@
    return nRet;
}
// èŽ·å–æ¿çŠ¶æ€
// èŽ·å–æ¿çŠ¶æ€
int CPerformanceMelsec::GetBoardStatus(BoardStatus& status) {
    std::lock_guard<std::mutex> lock(m_mtx);
    if (!m_bConnected) {
@@ -436,25 +436,25 @@
        LOG_ERROR(m_strLastError);
    }
    // å°† buf æ˜ å°„到结构体
    // å°† buf æ˜ å°„到结构体
    status = BoardStatus::fromBuffer(buf);
    return 0;
}
// é€šç”¨è¯»æ•°æ®
// é€šç”¨è¯»æ•°æ®
int CPerformanceMelsec::ReadData(const StationIdentifier& station, const short nDevType, const short nDevNo, short nSize, std::vector<short>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nSize);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // åˆå§‹åŒ–读取缓冲区
    // åˆå§‹åŒ–读取缓冲区
    vecData.clear();
    vecData.resize(nSize, 0);
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        short* pData = vecData.data();
@@ -468,15 +468,15 @@
    }
    if (nRet != 0) {
        vecData.clear(); // å¦‚果读取失败,清空缓冲区
        vecData.clear(); // å¦‚果读取失败,清空缓冲区
    }
    return nRet;
}
// è¯»å–位数据
// è¯»å–位数据
int CPerformanceMelsec::ReadBitData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nBitCount, BitContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nBitCount);
    if (nRet != 0) {
        UpdateLastError(nRet);
@@ -490,7 +490,7 @@
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>((static_cast<int>(nBitCount) + 15) / 16);  // è®¡ç®—需要读取的字数量(向上取整)
    const auto nSize = static_cast<short>((static_cast<int>(nBitCount) + 15) / 16);  // è®¡ç®—需要读取的字数量(向上取整)
    std::vector<short> vecTempBuffer(nSize, 0);
    nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
@@ -498,15 +498,15 @@
    if (nRet == 0) {
        vecData.clear();
        // å°†å­—数据解析为位数据
        // å°†å­—数据解析为位数据
        for (short nIdx = 0; nIdx < nSize; ++nIdx) {
            const short nCurrentValue = vecTempBuffer[nIdx];
            // éåŽ†å½“å‰ short ä¸­çš„æ¯ä¸€ä½
            // éåŽ†å½“å‰ short ä¸­çš„æ¯ä¸€ä½
            for (int bitIdx = 0; bitIdx < 16; ++bitIdx) {
                bool bBit = (nCurrentValue & (1 << bitIdx)) != 0;
                vecData.push_back(bBit);
                if (vecData.size() >= nBitCount) {
                    return nRet;  // å¦‚果已经读取完所需的位数,提前退出
                    return nRet;  // å¦‚果已经读取完所需的位数,提前退出
                }
            }
        }
@@ -515,9 +515,9 @@
    return nRet;
}
// è¯»å–字数据
// è¯»å–字数据
int CPerformanceMelsec::ReadWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nWordCount, WordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nWordCount);
    if (nRet != 0) {
        UpdateLastError(nRet);
@@ -536,44 +536,44 @@
    return nRet;
}
// è¯»å–双字数据
// è¯»å–双字数据
int CPerformanceMelsec::ReadDWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nDWordCount, DWordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndSize(station, nDWordCount);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    const auto nSize = static_cast<short>(nDWordCount * 2); // æ¯ä¸ªåŒå­—占两个字(每个双字占 4 å­—节)
    const auto nSize = static_cast<short>(nDWordCount * 2); // æ¯ä¸ªåŒå­—占两个字(每个双字占 4 å­—节)
    const short nDevType = CalculateDeviceType(station, enDevType);
    std::vector<short> vecTempBuffer(nSize, 0);
    nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
    if (nRet == 0) {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertShortToUint32(vecTempBuffer, vecData);
    }
    return nRet;
}
// é€šç”¨å†™æ•°æ®
// é€šç”¨å†™æ•°æ®
int CPerformanceMelsec::WriteData(const StationIdentifier& station, const short nDevType, const short nDevNo, short nSize, short* pData) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    // éªŒè¯ç«™ç‚¹å‚æ•°
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // æ•°æ®æœ‰æ•ˆæ€§
    // æ•°æ®æœ‰æ•ˆæ€§
    if (nSize < 0 || pData == nullptr) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM);
        return ERROR_CODE_INVALID_PARAM;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        nSize *= sizeof(short);
@@ -588,9 +588,9 @@
    return nRet;
}
// å†™ä½æ•°æ®
// å†™ä½æ•°æ®
int CPerformanceMelsec::WriteBitData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const BitContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
@@ -604,16 +604,16 @@
    }
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>((static_cast<int>(vecData.size()) + 15) / 16);  // è®¡ç®—需要写入的字数量(向上取整)
    const auto nSize = static_cast<short>((static_cast<int>(vecData.size()) + 15) / 16);  // è®¡ç®—需要写入的字数量(向上取整)
    // å‡†å¤‡ä¸´æ—¶ç¼“冲区来存储转换后的 16 ä½æ•°æ®
    // å‡†å¤‡ä¸´æ—¶ç¼“冲区来存储转换后的 16 ä½æ•°æ®
    std::vector<short> vecTempBuffer(nSize, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        // å°†ä½æ•°æ®æŒ‰å­—打包到临时缓冲区
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        // å°†ä½æ•°æ®æŒ‰å­—打包到临时缓冲区
        for (int i = 0; i < vecData.size(); ++i) {
            if (vecData[i]) {
                // ä½¿ç”¨ & 0xFFFF ä¿è¯ä¸ä¼šè¶…过 16 ä½ï¼Œé˜²æ­¢æº¢å‡º
                // ä½¿ç”¨ & 0xFFFF ä¿è¯ä¸ä¼šè¶…过 16 ä½ï¼Œé˜²æ­¢æº¢å‡º
                vecTempBuffer[i / 16] |= static_cast<short>((1 << (i % 16)) & 0xFFFF);
            }
        }
@@ -622,16 +622,16 @@
    return WriteData(station, nDevType, nDevNo, nSize, vecTempBuffer.data());
}
// å†™å­—数据
// å†™å­—数据
int CPerformanceMelsec::WriteWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const WordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    const int nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // è®¡ç®—需要写入的字节数(每个字占 2 å­—节)
    // è®¡ç®—需要写入的字节数(每个字占 2 å­—节)
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>(vecData.size());
    const auto pData = const_cast<short*>(reinterpret_cast<const short*>(vecData.data()));
@@ -639,30 +639,30 @@
    return WriteData(station, nDevType, nDevNo, nSize, pData);
}
// å†™åŒå­—数据
// å†™åŒå­—数据
int CPerformanceMelsec::WriteDWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const DWordContainer& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    const int nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // è®¡ç®—需要写入的字节数(每个双字占 4 å­—节)
    // è®¡ç®—需要写入的字节数(每个双字占 4 å­—节)
    const short nDevType = CalculateDeviceType(station, enDevType);
    const auto nSize = static_cast<short>(vecData.size() * sizeof(short));
    std::vector<short> vecBuffer(nSize, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertUint32ToShort(vecData, vecBuffer);
    }
    return WriteData(station, nDevType, nDevNo, nSize, vecBuffer.data());
}
// æ‰©å±•读数据
// æ‰©å±•读数据
long CPerformanceMelsec::ReadDataEx(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和读取大小是否有效
    // éªŒè¯ç«™ç‚¹å‚数和读取大小是否有效
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
@@ -678,7 +678,7 @@
    std::vector<short> vecBuffer(nSize / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, vecBuffer.data());
    }
@@ -687,7 +687,7 @@
        LOG_ERROR(m_strLastError);
    }
    else {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        vecData.resize(nSize);
        ConvertShortToChar(vecBuffer, vecData);
    }
@@ -695,27 +695,27 @@
    return 0;
}
// æ‰©å±•写数据
// æ‰©å±•写数据
long CPerformanceMelsec::WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    long nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // å°† vecData è½¬æ¢ä¸º short ç±»åž‹çš„缓冲区
    // å°† vecData è½¬æ¢ä¸º short ç±»åž‹çš„缓冲区
    long nSize = static_cast<long>(vecData.size());
    nSize = nSize % 2 != 0 ? nSize + 1 : nSize;
    std::vector<short> vecBuffer(nSize / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdSendEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, vecBuffer.data());
    }
    // é”™è¯¯å¤„理和日志记录
    // é”™è¯¯å¤„理和日志记录
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
@@ -724,7 +724,7 @@
    return nRet;
}
// æ‰©å±•软元件随机读取
// æ‰©å±•软元件随机读取
long CPerformanceMelsec::ReadRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, std::vector<char>& vecData) {
    if (vecSoftElements.empty()) {
        UpdateLastError(ERROR_INVALID_PARAMETER);
@@ -732,48 +732,48 @@
        return ERROR_INVALID_PARAMETER;
    }
    // å‡†å¤‡ dev æ•°æ®
    std::vector<short> devBuffer(vecSoftElements.size() * 3 + 1, 0); // æ¯ä¸ªè½¯å…ƒä»¶éœ€è¦ 3 ä¸ª short,外加一个计数器
    devBuffer[0] = static_cast<short>(vecSoftElements.size());                 // ç¬¬ä¸€ä¸ªå…ƒç´ æ˜¯è½¯å…ƒä»¶æ•°é‡
    // å‡†å¤‡ dev æ•°æ®
    std::vector<short> devBuffer(vecSoftElements.size() * 3 + 1, 0); // æ¯ä¸ªè½¯å…ƒä»¶éœ€è¦ 3 ä¸ª short,外加一个计数器
    devBuffer[0] = static_cast<short>(vecSoftElements.size());                 // ç¬¬ä¸€ä¸ªå…ƒç´ æ˜¯è½¯å…ƒä»¶æ•°é‡
    for (size_t i = 0; i < vecSoftElements.size(); ++i) {
        const SoftElement& element = vecSoftElements[i];
        devBuffer[i * 3 + 1] = element.nType;                        // è½¯å…ƒä»¶ç±»åž‹
        devBuffer[i * 3 + 2] = static_cast<short>(element.nStartNo); // èµ·å§‹è½¯å…ƒä»¶ç¼–号
        devBuffer[i * 3 + 3] = element.nElementCount;                // ç‚¹æ•°
        devBuffer[i * 3 + 1] = element.nType;                        // è½¯å…ƒä»¶ç±»åž‹
        devBuffer[i * 3 + 2] = static_cast<short>(element.nStartNo); // èµ·å§‹è½¯å…ƒä»¶ç¼–号
        devBuffer[i * 3 + 3] = element.nElementCount;                // ç‚¹æ•°
    }
    // è®¡ç®—读取数据所需缓冲区大小
    // è®¡ç®—读取数据所需缓冲区大小
    long nBufferSize = 0;
    for (const auto& element : vecSoftElements) {
        nBufferSize += element.nElementCount * 2; // æ¯ä¸ªç‚¹å ç”¨ 2 ä¸ªå­—节
        nBufferSize += element.nElementCount * 2; // æ¯ä¸ªç‚¹å ç”¨ 2 ä¸ªå­—节
    }
    // é”ä¿æŠ¤åŠè°ƒç”¨ mdRandREx
    // é”ä¿æŠ¤åŠè°ƒç”¨ mdRandREx
    long nRet = 0;
    std::vector<short> vecBuffer(nBufferSize / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // ç¡®ä¿çº¿ç¨‹å®‰å…¨
        std::lock_guard<std::mutex> lock(m_mtx); // ç¡®ä¿çº¿ç¨‹å®‰å…¨
        nRet = mdRandREx(m_nPath, station.nNetNo, station.nStNo, devBuffer.data(), vecBuffer.data(), nBufferSize);
    }
    // é”™è¯¯å¤„理和日志记录
    // é”™è¯¯å¤„理和日志记录
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
        return nRet;
    }
    // å°†è¯»å–到的 short æ•°æ®è½¬æ¢ä¸º char æ•°æ®
    // å°†è¯»å–到的 short æ•°æ®è½¬æ¢ä¸º char æ•°æ®
    vecData.resize(nBufferSize);
    for (size_t i = 0; i < vecBuffer.size(); ++i) {
        vecData[i * 2] = static_cast<char>(vecBuffer[i] & 0xFF);            // ä½Žå­—节
        vecData[i * 2 + 1] = static_cast<char>((vecBuffer[i] >> 8) & 0xFF); // é«˜å­—节
        vecData[i * 2] = static_cast<char>(vecBuffer[i] & 0xFF);            // ä½Žå­—节
        vecData[i * 2 + 1] = static_cast<char>((vecBuffer[i] >> 8) & 0xFF); // é«˜å­—节
    }
    return nRet;
}
// æ‰©å±•软元件随机写入(支持多个软元件)
// æ‰©å±•软元件随机写入(支持多个软元件)
long CPerformanceMelsec::WriteRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, const std::vector<char>& vecData) {
    if (vecSoftElements.empty() || vecData.empty()) {
        UpdateLastError(ERROR_INVALID_PARAMETER);
@@ -781,26 +781,26 @@
        return ERROR_INVALID_PARAMETER;
    }
    // å‡†å¤‡ dev æ•°æ®
    std::vector<long> devBuffer(vecSoftElements.size() * 3 + 1, 0); // æ¯ä¸ªè½¯å…ƒä»¶éœ€è¦ 3 ä¸ª long,外加一个计数器
    devBuffer[0] = static_cast<long>(vecSoftElements.size());                 // ç¬¬ä¸€ä¸ªå…ƒç´ æ˜¯è½¯å…ƒä»¶æ•°é‡
    // å‡†å¤‡ dev æ•°æ®
    std::vector<long> devBuffer(vecSoftElements.size() * 3 + 1, 0); // æ¯ä¸ªè½¯å…ƒä»¶éœ€è¦ 3 ä¸ª long,外加一个计数器
    devBuffer[0] = static_cast<long>(vecSoftElements.size());                 // ç¬¬ä¸€ä¸ªå…ƒç´ æ˜¯è½¯å…ƒä»¶æ•°é‡
    for (size_t i = 0; i < vecSoftElements.size(); ++i) {
        const SoftElement& element = vecSoftElements[i];
        devBuffer[i * 3 + 1] = static_cast<long>(element.nType);    // è½¯å…ƒä»¶ç±»åž‹
        devBuffer[i * 3 + 2] = element.nStartNo;                    // èµ·å§‹è½¯å…ƒä»¶ç¼–号(已经是 long ç±»åž‹ï¼Œæ— éœ€è½¬æ¢ï¼‰
        devBuffer[i * 3 + 3] = static_cast<long>(element.nElementCount); // ç‚¹æ•°
        devBuffer[i * 3 + 1] = static_cast<long>(element.nType);    // è½¯å…ƒä»¶ç±»åž‹
        devBuffer[i * 3 + 2] = element.nStartNo;                    // èµ·å§‹è½¯å…ƒä»¶ç¼–号(已经是 long ç±»åž‹ï¼Œæ— éœ€è½¬æ¢ï¼‰
        devBuffer[i * 3 + 3] = static_cast<long>(element.nElementCount); // ç‚¹æ•°
    }
    // é”ä¿æŠ¤åŠè°ƒç”¨ mdRandWEx
    // é”ä¿æŠ¤åŠè°ƒç”¨ mdRandWEx
    long nRet = 0;
    std::vector<short> vecBuffer(vecData.size() / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // ç¡®ä¿çº¿ç¨‹å®‰å…¨
        std::lock_guard<std::mutex> lock(m_mtx); // ç¡®ä¿çº¿ç¨‹å®‰å…¨
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdRandWEx(m_nPath, station.nNetNo, station.nStNo, devBuffer.data(), vecBuffer.data(), static_cast<long>(vecBuffer.size()));
    }
    // é”™è¯¯å¤„理和日志记录
    // é”™è¯¯å¤„理和日志记录
    if (nRet != 0) {
        UpdateLastError(nRet);
        LOG_ERROR(m_strLastError);
@@ -809,9 +809,9 @@
    return nRet;
}
// è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器读取
// è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器读取
long CPerformanceMelsec::ReadRemoteBuffer(const StationIdentifier& station, long nOffset, long nSize, std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
@@ -826,37 +826,37 @@
    long nActualSize = (nSize + 1) / 2;
    std::vector<short> vecBuffer(nActualSize, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        nRet = mdRemBufReadEx(m_nPath, station.nNetNo, station.nStNo, nOffset, &nActualSize, vecBuffer.data());
    }
    if (nRet != 0) {
        UpdateLastError(nRet); // æ›´æ–°é”™è¯¯ç 
        UpdateLastError(nRet); // æ›´æ–°é”™è¯¯ç 
        LOG_ERROR(m_strLastError);
    }
    else {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertShortToChar(vecBuffer, vecData);
    }
    return nRet;
}
// è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器写入
// è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器写入
long CPerformanceMelsec::WriteRemoteBuffer(const StationIdentifier& station, long nOffset, const std::vector<char>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    long nRet = ValidateStationAndData(station, vecData);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // å°† vecData è½¬æ¢ä¸º short ç±»åž‹çš„缓冲区
    // å°† vecData è½¬æ¢ä¸º short ç±»åž‹çš„缓冲区
    long nSize = static_cast<long>(vecData.size());
    std::vector<short> vecBuffer((nSize + 1) / 2, 0);
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdRemBufWriteEx(m_nPath, station.nNetNo, station.nStNo, nOffset, &nSize, vecBuffer.data());
    }
@@ -869,7 +869,7 @@
    return nRet;
}
// è¿œç¨‹ç«™çš„缓冲存储器读取 å¯¹è±¡ç«™IP地址指定
// è¿œç¨‹ç«™çš„缓冲存储器读取 å¯¹è±¡ç«™IP地址指定
long CPerformanceMelsec::ReadRemoteBufferByIp(const std::string& strIP, long nOffset, long nSize, std::vector<char>& vecData) {
    uint32_t nAddress = 0;
    if (nSize < 0 || !ConvertIpStringToUint32(strIP, nAddress)) {
@@ -877,14 +877,14 @@
        return ERROR_CODE_INVALID_PARAM;
    }
    // å°†ç¼“冲区大小调整为 nSize
    // å°†ç¼“冲区大小调整为 nSize
    vecData.resize(nSize, 0);
    std::vector<short> vecBuffer((nSize + 1) / 2, 0); // è½¬æ¢ä¸º short ç±»åž‹
    std::vector<short> vecBuffer((nSize + 1) / 2, 0); // è½¬æ¢ä¸º short ç±»åž‹
    // è°ƒç”¨åº•层 SDK
    // è°ƒç”¨åº•层 SDK
    long nRet = 0;
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        nRet = mdRemBufReadIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
    }
@@ -893,14 +893,14 @@
        LOG_ERROR(m_strLastError);
    }
    else {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨ä¿æŠ¤
        ConvertShortToChar(vecBuffer, vecData);
    }
    return nRet;
}
// è¿œç¨‹ç«™çš„缓冲存储器写入 å¯¹è±¡ç«™IP地址指定
// è¿œç¨‹ç«™çš„缓冲存储器写入 å¯¹è±¡ç«™IP地址指定
long CPerformanceMelsec::WriteRemoteBufferByIp(const std::string& strIP, long nOffset, const std::vector<char>& vecData) {
    uint32_t nAddress = 0;
    if (vecData.empty() || !ConvertIpStringToUint32(strIP, nAddress)) {
@@ -908,13 +908,13 @@
        return ERROR_CODE_INVALID_PARAM;
    }
    // è½¬æ¢ vecData ä¸º short ç±»åž‹çš„缓冲区
    // è½¬æ¢ vecData ä¸º short ç±»åž‹çš„缓冲区
    long nSize = static_cast<long>(vecData.size());
    std::vector<short> vecBuffer((nSize + 1) / 2, 0);
    long nRet = 0;
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨
        ConvertCharToShort(vecData, vecBuffer);
        nRet = mdRemBufWriteIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
    }
@@ -927,18 +927,18 @@
    return nRet;
}
// è®¾ç½®(ON)对象站的指定位软元件
// è®¾ç½®(ON)对象站的指定位软元件
int CPerformanceMelsec::SetBitDevice(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    // éªŒè¯ç«™ç‚¹å‚æ•°
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨
        std::lock_guard<std::mutex> lock(m_mtx); // çº¿ç¨‹å®‰å…¨
        const short nDevType = CalculateDeviceType(station, enDevType);
        nRet = mdDevSet(m_nPath, CombineStation(station), nDevType, nDevNo);
    }
@@ -951,16 +951,16 @@
    return nRet;
}
// å¤ä½(OFF)对象站的指定位软元件
// å¤ä½(OFF)对象站的指定位软元件
int CPerformanceMelsec::ResetBitDevice(const StationIdentifier& station, const DeviceType enDevType, const short enDevNo) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    // éªŒè¯ç«™ç‚¹å‚æ•°
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        const short nDevType = CalculateDeviceType(station, enDevType);
@@ -975,11 +975,11 @@
    return nRet;
}
// æ‰©å±•位软元件设置
// æ‰©å±•位软元件设置
long CPerformanceMelsec::SetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo) {
    std::lock_guard<std::mutex> lock(m_mtx);
    // æ£€æŸ¥å‚数有效性
    // æ£€æŸ¥å‚数有效性
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
@@ -995,11 +995,11 @@
    return nRet;
}
// æ‰©å±•位软元件复位
// æ‰©å±•位软元件复位
long CPerformanceMelsec::ResetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo) {
    std::lock_guard<std::mutex> lock(m_mtx);
    // æ£€æŸ¥å‚数有效性
    // æ£€æŸ¥å‚数有效性
    long nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
@@ -1015,23 +1015,23 @@
    return nRet;
}
// æ‰§è¡Œå¯¹è±¡ç«™çš„CPU
// æ‰§è¡Œå¯¹è±¡ç«™çš„CPU
int CPerformanceMelsec::ControlCPU(const StationIdentifier& station, ControlCode enControlCode) {
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    // éªŒè¯ç«™ç‚¹å‚数和数据有效性
    int nRet = ValidateStation(station);
    if (nRet != 0) {
        UpdateLastError(nRet);
        return nRet;
    }
    // éªŒè¯æŽ§åˆ¶ç æ˜¯å¦åˆæ³•
    // éªŒè¯æŽ§åˆ¶ç æ˜¯å¦åˆæ³•
    const auto nControlCode = static_cast<short>(enControlCode);
    if (nControlCode < 0 || nControlCode > 2) {
        UpdateLastError(ERROR_CODE_INVALID_PARAM); // å‚数错误
        UpdateLastError(ERROR_CODE_INVALID_PARAM); // å‚数错误
        return ERROR_CODE_INVALID_PARAM;
    }
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    // ç¡®ä¿çº¿ç¨‹å®‰å…¨çš„æœ€å°é”å®šèŒƒå›´
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        nRet = mdControl(m_nPath, CombineStation(station), nControlCode);
@@ -1045,7 +1045,7 @@
    return nRet;
}
// äº‹ä»¶ç­‰å¾…
// äº‹ä»¶ç­‰å¾…
int CPerformanceMelsec::WaitForBoardEvent(std::vector<short> vecEventNumbers, const int nTimeoutMs, EventDetails& details) {
    std::lock_guard<std::mutex> lock(m_mtx);
@@ -1059,12 +1059,12 @@
        return ERROR_CODE_INVALID_PARAM;
    }
    // ç¬¬ 0 ä¸ªå…ƒç´ å­˜å‚¨æ•°é‡ï¼Œæœ€å¤§æ”¯æŒ 64 ä¸ªäº‹ä»¶
    // ç¬¬ 0 ä¸ªå…ƒç´ å­˜å‚¨æ•°é‡ï¼Œæœ€å¤§æ”¯æŒ 64 ä¸ªäº‹ä»¶
    std::array<short, 65> eventno = { 0 };
    eventno[0] = static_cast<short>(vecEventNumbers.size());
    std::copy(vecEventNumbers.begin(), vecEventNumbers.end(), eventno.begin() + 1);
    // åˆå§‹åŒ–输出参数
    // åˆå§‹åŒ–输出参数
    details.nEventNo = 0;
    details.details.fill(0);
@@ -1077,100 +1077,100 @@
    return nRet;
}
//============================================辅助函数=======================================================
// æ›´æ–°æœ€è¿‘的错误信息
//============================================辅助函数=======================================================
// æ›´æ–°æœ€è¿‘的错误信息
void CPerformanceMelsec::UpdateLastError(const int nCode) {
    if (nCode == 0) {
        return;
    }
    // æ£€æŸ¥é”™è¯¯ç æ˜¯å¦å­˜åœ¨äºŽæ˜ å°„表中
    // æ£€æŸ¥é”™è¯¯ç æ˜¯å¦å­˜åœ¨äºŽæ˜ å°„表中
    const auto it = m_mapError.find(nCode);
    if (it != m_mapError.end()) {
        // å¦‚果找到,直接返回对应语言的错误信息
        // å¦‚果找到,直接返回对应语言的错误信息
        m_strLastError = it->second;
    }
    else {
        // å¦‚果未找到,处理特殊范围
        // å¦‚果未找到,处理特殊范围
        m_strLastError = "Unknown error.";
        if (nCode == -28611 || nCode == -28612) {
            // ç³»ç»Ÿå‡ºé”™
            // ç³»ç»Ÿå‡ºé”™
            m_strLastError = "System error.";
        }
        if (nCode >= -20480 && nCode <= -16384) {
            // CC-Link ç³»ç»Ÿæ£€æµ‹å‡ºçš„错误
            // CC-Link ç³»ç»Ÿæ£€æµ‹å‡ºçš„错误
            m_strLastError = "Error detected in the CC-Link system.";
        }
        if (nCode >= -12288 && nCode <= -8193) {
            // CC-Link IE TSN ç³»ç»Ÿæ£€æµ‹å‡ºçš„错误
            // CC-Link IE TSN ç³»ç»Ÿæ£€æµ‹å‡ºçš„错误
            m_strLastError = "Error detected in the CC-Link IE TSN system.";
        }
        if (nCode >= -8192 && nCode <= -4097) {
            // CC-Link IE æŽ§åˆ¶ç½‘络系统检测出的错误
            // CC-Link IE æŽ§åˆ¶ç½‘络系统检测出的错误
            m_strLastError = "Error detected in the CC-Link IE control network system.";
        }
        if (nCode >= -4096 && nCode <= -257) {
            // MELSECNET/10 æˆ– MELSECNET/网络系统错误范围
            // MELSECNET/10 æˆ– MELSECNET/网络系统错误范围
            m_strLastError = "Errors detected in MELSECNET/10 or MELSECNET/network system.";
        }
        if (nCode >= 4096 && nCode <= 16383) {
            // MELSEC æ•°æ®é“¾æŽ¥åº“范围
            // MELSEC æ•°æ®é“¾æŽ¥åº“范围
            m_strLastError = "Internal error detected by MELSEC Data Link Library.";
        }
        if (nCode == 18944 || nCode == 18945) {
            // é“¾æŽ¥å…³è”出错
            // é“¾æŽ¥å…³è”出错
            m_strLastError = "Link association error: Network does not exist, unsupported CPU, or incorrect network No./station number.";
        }
        if (nCode >= 16384 && nCode <= 20479) {
            // PLC CPU æ£€æµ‹èŒƒå›´
            // PLC CPU æ£€æµ‹èŒƒå›´
            m_strLastError = "Errors detected by the programmable controller CPU in the target station.";
        }
        if (nCode >= 28416 && nCode <= 28671) {
            // å†—余功能模块范围
            // å†—余功能模块范围
            m_strLastError = "Error detected in the redundancy module of the target station.";
        }
    }
}
// æ£€æŸ¥è¿žæŽ¥çŠ¶æ€å’Œç«™ç‚¹å‚æ•°æœ‰æ•ˆæ€§
// æ£€æŸ¥è¿žæŽ¥çŠ¶æ€å’Œç«™ç‚¹å‚æ•°æœ‰æ•ˆæ€§
int CPerformanceMelsec::ValidateStation(const StationIdentifier& station) const {
    // æ£€æŸ¥æ˜¯å¦å·²è¿žæŽ¥
    // æ£€æŸ¥æ˜¯å¦å·²è¿žæŽ¥
    if (!m_bConnected.load()) {
        return ERROR_CODE_NOT_CONNECTED;
    }
    // æ£€æŸ¥ç½‘络号和站点号范围
    // æ£€æŸ¥ç½‘络号和站点号范围
    if (station.nNetNo < 0 || station.nNetNo > 239 || station.nStNo < 0 || station.nStNo > 255) {
        return ERROR_CODE_INVALID_PARAM;
    }
    return 0; // å‚数有效
    return 0; // å‚数有效
}
// éªŒè¯ç«™ç‚¹å‚数和数据有效性
// éªŒè¯ç«™ç‚¹å‚数和数据有效性
int CPerformanceMelsec::ValidateStationAndSize(const StationIdentifier& station, const short nCount) const {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    // éªŒè¯ç«™ç‚¹å‚æ•°
    const int nRet = ValidateStation(station);
    if (nRet != 0) {
        return nRet; // å¦‚果站点验证失败,返回对应错误码
        return nRet; // å¦‚果站点验证失败,返回对应错误码
    }
    if (nCount <= 0) {
        return ERROR_CODE_INVALID_PARAM;
    }
    return 0; // éªŒè¯é€šè¿‡
    return 0; // éªŒè¯é€šè¿‡
}
// IP字符串转uint32_t
// IP字符串转uint32_t
bool CPerformanceMelsec::ConvertIpStringToUint32(const std::string& strIP, uint32_t& nIP) {
    nIP = 0;
    std::stringstream ss(strIP);
@@ -1189,30 +1189,30 @@
    return true;
}
//============================================静态辅助函数====================================================
// å»¶æ—¶ï¼Œå¹¶ä¸”转发窗口消息
//============================================静态辅助函数====================================================
// å»¶æ—¶ï¼Œå¹¶ä¸”转发窗口消息
void CPerformanceMelsec::Delay(const unsigned int nDelayMs) {
    MSG message;
    // å¦‚果延迟时间为 0,仅处理一次消息队列
    // å¦‚果延迟时间为 0,仅处理一次消息队列
    if (nDelayMs == 0) {
        // éžé˜»å¡žçš„æ£€æŸ¥æ¶ˆæ¯é˜Ÿåˆ—
        // éžé˜»å¡žçš„æ£€æŸ¥æ¶ˆæ¯é˜Ÿåˆ—
        if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
            TranslateMessage(&message);  // å°†æ¶ˆæ¯è½¬åŒ–为有效的窗口消息
            DispatchMessage(&message);   // æ´¾å‘消息给相应的窗口过程
            TranslateMessage(&message);  // å°†æ¶ˆæ¯è½¬åŒ–为有效的窗口消息
            DispatchMessage(&message);   // æ´¾å‘消息给相应的窗口过程
        }
        return;
    }
    DWORD finish;
    const DWORD start = GetTickCount();  // èŽ·å–å½“å‰çš„æ—¶é—´æˆ³ï¼ˆä»Žç³»ç»Ÿå¯åŠ¨ä»¥æ¥çš„æ¯«ç§’æ•°ï¼‰
    const DWORD start = GetTickCount();  // èŽ·å–å½“å‰çš„æ—¶é—´æˆ³ï¼ˆä»Žç³»ç»Ÿå¯åŠ¨ä»¥æ¥çš„æ¯«ç§’æ•°ï¼‰
    do {
        if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
            TranslateMessage(&message);  // è½¬æ¢æ¶ˆæ¯
            DispatchMessage(&message);   // å¤„理消息
            TranslateMessage(&message);  // è½¬æ¢æ¶ˆæ¯
            DispatchMessage(&message);   // å¤„理消息
        }
        Sleep(1);   // æš‚停 1 æ¯«ç§’,防止过度占用 CPU
        finish = GetTickCount(); // èŽ·å–å½“å‰çš„æ—¶é—´æˆ³
    } while ((finish - start) < nDelayMs);  // å¾ªçŽ¯ç›´åˆ°ç»è¿‡çš„æ—¶é—´å¤§äºŽæŒ‡å®šçš„å»¶è¿Ÿæ—¶é—´
        Sleep(1);   // æš‚停 1 æ¯«ç§’,防止过度占用 CPU
        finish = GetTickCount(); // èŽ·å–å½“å‰çš„æ—¶é—´æˆ³
    } while ((finish - start) < nDelayMs);  // å¾ªçŽ¯ç›´åˆ°ç»è¿‡çš„æ—¶é—´å¤§äºŽæŒ‡å®šçš„å»¶è¿Ÿæ—¶é—´
}
BoardType CPerformanceMelsec::FindBoardTypeByChannel(const int nChannel) {
@@ -1234,136 +1234,136 @@
    return BoardType::UNKNOWN;
}
// åˆå¹¶ç½‘络号和站点号
// åˆå¹¶ç½‘络号和站点号
short CPerformanceMelsec::CombineStation(const StationIdentifier& station) {
    return static_cast<short>(station.nStNo | ((station.nNetNo << 8) & 0xFF00));
}
// è®¡ç®—软元件类型
// è®¡ç®—软元件类型
short CPerformanceMelsec::CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType) {
    int nDevType = static_cast<int>(enDevType);
    // æ ¹æ®è½¯å…ƒä»¶ç±»åž‹çš„特定规则进行计算
    // æ ¹æ®è½¯å…ƒä»¶ç±»åž‹çš„特定规则进行计算
    if (enDevType == DeviceType::LX || enDevType == DeviceType::LY ||
        enDevType == DeviceType::LB || enDevType == DeviceType::LW ||
        enDevType == DeviceType::LSB || enDevType == DeviceType::LSW) {
        // ç½‘络号加偏移
        // ç½‘络号加偏移
        nDevType += station.nNetNo;
    }
    else if (enDevType == DeviceType::ER) {
        // æ–‡ä»¶å¯„存器的块号加偏移
        // æ–‡ä»¶å¯„存器的块号加偏移
        nDevType += 0;
    }
    else if (enDevType == DeviceType::SPG) {
        // èµ·å§‹ I/O No. Ã· 16 çš„值
        // èµ·å§‹ I/O No. Ã· 16 çš„值
        nDevType += 0 / 16;
    }
    return static_cast<short>(nDevType);
}
// std::vector<char>转换为std::vector<short>
// std::vector<char>转换为std::vector<short>
void CPerformanceMelsec::ConvertCharToShort(const std::vector<char>& vecChar, std::vector<short>& vecShort) {
    vecShort.resize((vecChar.size() + 1) / 2, 0); // è°ƒæ•´ short å®¹å™¨å¤§å°
    vecShort.resize((vecChar.size() + 1) / 2, 0); // è°ƒæ•´ short å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecChar.size(); i++) {
        if (i % 2 == 0) {
            vecShort[i / 2] = static_cast<unsigned char>(vecChar[i]);       // ä½Žå­—节
            vecShort[i / 2] = static_cast<unsigned char>(vecChar[i]);       // ä½Žå­—节
        }
        else {
            vecShort[i / 2] |= static_cast<unsigned char>(vecChar[i]) << 8; // é«˜å­—节
            vecShort[i / 2] |= static_cast<unsigned char>(vecChar[i]) << 8; // é«˜å­—节
        }
    }
}
// std::vector<short>转换为std::vector<char>
// std::vector<short>转换为std::vector<char>
void CPerformanceMelsec::ConvertShortToChar(const std::vector<short>& vecShort, std::vector<char>& vecChar) {
    vecChar.resize(vecShort.size() * 2); // è°ƒæ•´ char å®¹å™¨å¤§å°
    vecChar.resize(vecShort.size() * 2); // è°ƒæ•´ char å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecShort.size(); i++) {
        vecChar[i * 2] = static_cast<char>(vecShort[i] & 0xFF);             // ä½Žå­—节
        vecChar[i * 2 + 1] = static_cast<char>((vecShort[i] >> 8) & 0xFF);  // é«˜å­—节
        vecChar[i * 2] = static_cast<char>(vecShort[i] & 0xFF);             // ä½Žå­—节
        vecChar[i * 2 + 1] = static_cast<char>((vecShort[i] >> 8) & 0xFF);  // é«˜å­—节
    }
}
// std::vector<uint8_t>转换为std::vector<short>
// std::vector<uint8_t>转换为std::vector<short>
void CPerformanceMelsec::ConvertUint8ToShort(const std::vector<uint8_t>& vecUint8, std::vector<short>& vecShort) {
    vecShort.resize((vecUint8.size() + 1) / 2, 0); // è°ƒæ•´ short å®¹å™¨å¤§å°
    vecShort.resize((vecUint8.size() + 1) / 2, 0); // è°ƒæ•´ short å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecUint8.size(); i++) {
        if (i % 2 == 0) {
            vecShort[i / 2] = static_cast<short>(vecUint8[i]);          // ä½Žå­—节
            vecShort[i / 2] = static_cast<short>(vecUint8[i]);          // ä½Žå­—节
        }
        else {
            vecShort[i / 2] |= static_cast<short>(vecUint8[i] << 8);    // é«˜å­—节
            vecShort[i / 2] |= static_cast<short>(vecUint8[i] << 8);    // é«˜å­—节
        }
    }
}
// std::vector<short>转换为std::vector<uint8_t>
// std::vector<short>转换为std::vector<uint8_t>
void CPerformanceMelsec::ConvertShortToUint8(const std::vector<short>& vecShort, std::vector<uint8_t>& vecUint8) {
    vecUint8.resize(vecShort.size() * 2); // è°ƒæ•´ uint8_t å®¹å™¨å¤§å°
    vecUint8.resize(vecShort.size() * 2); // è°ƒæ•´ uint8_t å®¹å™¨å¤§å°
    for (size_t i = 0; i < vecShort.size(); i++) {
        vecUint8[i * 2] = static_cast<uint8_t>(vecShort[i] & 0xFF);             // ä½Žå­—节
        vecUint8[i * 2 + 1] = static_cast<uint8_t>((vecShort[i] >> 8) & 0xFF);  // é«˜å­—节
        vecUint8[i * 2] = static_cast<uint8_t>(vecShort[i] & 0xFF);             // ä½Žå­—节
        vecUint8[i * 2 + 1] = static_cast<uint8_t>((vecShort[i] >> 8) & 0xFF);  // é«˜å­—节
    }
}
// std::vector<uint32_t>转换为std::vector<short>
// std::vector<uint32_t>转换为std::vector<short>
void CPerformanceMelsec::ConvertUint32ToShort(const std::vector<uint32_t>& vecUint32, std::vector<short>& vecShort) {
    vecShort.resize(vecUint32.size() * 2); // æ¯ä¸ª uint32_t è½¬æ¢ä¸ºä¸¤ä¸ª short
    vecShort.resize(vecUint32.size() * 2); // æ¯ä¸ª uint32_t è½¬æ¢ä¸ºä¸¤ä¸ª short
    for (size_t i = 0; i < vecUint32.size(); i++) {
        vecShort[i * 2] = static_cast<short>(vecUint32[i] & 0xFFFF);             // ä½Ž16位
        vecShort[i * 2 + 1] = static_cast<short>((vecUint32[i] >> 16) & 0xFFFF); // é«˜16位
        vecShort[i * 2] = static_cast<short>(vecUint32[i] & 0xFFFF);             // ä½Ž16位
        vecShort[i * 2 + 1] = static_cast<short>((vecUint32[i] >> 16) & 0xFFFF); // é«˜16位
    }
}
// std::vector<short>转换为std::vector<uint32_t>
// std::vector<short>转换为std::vector<uint32_t>
void CPerformanceMelsec::ConvertShortToUint32(const std::vector<short>& vecShort, std::vector<uint32_t>& vecUint32) {
    vecUint32.resize((vecShort.size() + 1) / 2, 0); // æ¯ä¸¤ä¸ª short åˆå¹¶ä¸ºä¸€ä¸ª uint32_t
    vecUint32.resize((vecShort.size() + 1) / 2, 0); // æ¯ä¸¤ä¸ª short åˆå¹¶ä¸ºä¸€ä¸ª uint32_t
    for (size_t i = 0; i < vecUint32.size(); i++) {
        vecUint32[i] = (static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2 + 1])) << 16) | // é«˜16位
            static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2]));              // ä½Ž16位
        vecUint32[i] = (static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2 + 1])) << 16) | // é«˜16位
            static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2]));              // ä½Ž16位
    }
}
//============================================模板辅助函数====================================================
// éªŒè¯ç«™ç‚¹å‚数和数据有效性
//============================================模板辅助函数====================================================
// éªŒè¯ç«™ç‚¹å‚数和数据有效性
template <typename T>
int CPerformanceMelsec::ValidateStationAndData(const StationIdentifier& station, const std::vector<T>& vecData) {
    // éªŒè¯ç«™ç‚¹å‚æ•°
    // éªŒè¯ç«™ç‚¹å‚æ•°
    const int nRet = ValidateStation(station);
    if (nRet != 0) {
        return nRet; // å¦‚果站点验证失败,返回对应错误码
        return nRet; // å¦‚果站点验证失败,返回对应错误码
    }
    // éªŒè¯æ•°æ®æ˜¯å¦ä¸ºç©º
    // éªŒè¯æ•°æ®æ˜¯å¦ä¸ºç©º
    if (vecData.empty()) {
        return ERROR_CODE_INVALID_PARAM;
    }
    return 0; // éªŒè¯é€šè¿‡
    return 0; // éªŒè¯é€šè¿‡
}
// ç”±ä½Žè½¬é«˜å®¹å™¨çš„æ¨¡æ¿ï¼ˆæ•´åž‹ï¼‰
// ç”±ä½Žè½¬é«˜å®¹å™¨çš„æ¨¡æ¿ï¼ˆæ•´åž‹ï¼‰
template <typename T, typename U>
void CPerformanceMelsec::ConvertLowToHigh(const std::vector<T>& vecLow, std::vector<U>& vecHigh) {
    static_assert(std::is_integral<T>::value && std::is_integral<U>::value, "T and U must be integral types");
    // è‡ªåŠ¨è®¡ç®— nGroupSize
    // è‡ªåŠ¨è®¡ç®— nGroupSize
    constexpr size_t nGroupSize = sizeof(U) / sizeof(T);
    // å¦‚æžœ T å’Œ U çš„大小相等,直接转换
    // å¦‚æžœ T å’Œ U çš„大小相等,直接转换
    if (sizeof(T) == sizeof(U)) {
        vecHigh.assign(vecLow.begin(), vecLow.end());
        return;
    }
    // å¦‚æžœ U çš„大小是 T çš„倍数,正常组合
    // å¦‚æžœ U çš„大小是 T çš„倍数,正常组合
    static_assert(sizeof(U) > sizeof(T), "Size of U must be greater than or equal to size of T");
    // è®¡ç®—完整组的数量
    size_t nHighSize = (vecLow.size() + nGroupSize - 1) / nGroupSize; // å‘上取整
    // è®¡ç®—完整组的数量
    size_t nHighSize = (vecLow.size() + nGroupSize - 1) / nGroupSize; // å‘上取整
    vecHigh.resize(nHighSize, 0);
    // åˆå¹¶ä½Žä½æ•°æ®åˆ°é«˜ä½æ•°æ®
    // åˆå¹¶ä½Žä½æ•°æ®åˆ°é«˜ä½æ•°æ®
    for (size_t i = 0; i < vecLow.size(); i++) {
        vecHigh[i / nGroupSize] |= (static_cast<U>(vecLow[i]) << ((i % nGroupSize) * CHAR_BIT * sizeof(T)));
    }
@@ -1371,27 +1371,27 @@
    return vecHigh;
}
// ç”±é«˜è½¬ä½Žå®¹å™¨çš„æ¨¡æ¿ï¼ˆæ•´åž‹ï¼‰
// ç”±é«˜è½¬ä½Žå®¹å™¨çš„æ¨¡æ¿ï¼ˆæ•´åž‹ï¼‰
template <typename T, typename U>
void CPerformanceMelsec::ConvertHighToLow(const std::vector<T>& vecHigh, std::vector<U>& vecLow) {
    static_assert(std::is_integral<T>::value && std::is_integral<U>::value, "T and U must be integral types");
    // è‡ªåŠ¨è®¡ç®— nGroupSize
    // è‡ªåŠ¨è®¡ç®— nGroupSize
    constexpr size_t nGroupSize = sizeof(T) / sizeof(U);
    // å¦‚æžœ T å’Œ U çš„大小相等,直接转换
    // å¦‚æžœ T å’Œ U çš„大小相等,直接转换
    if (sizeof(T) == sizeof(U)) {
        vecLow.assign(vecHigh.begin(), vecHigh.end());
        return;
    }
    // å¦‚æžœ T çš„大小是 U çš„倍数,正常分解
    // å¦‚æžœ T çš„大小是 U çš„倍数,正常分解
    static_assert(sizeof(T) > sizeof(U), "Size of T must be greater than or equal to size of U");
    size_t nLowSize = vecHigh.size() * nGroupSize; // ä½Žå®¹å™¨çš„大小
    size_t nLowSize = vecHigh.size() * nGroupSize; // ä½Žå®¹å™¨çš„大小
    vecLow.resize(nLowSize, 0);
    // åˆ†è§£é«˜ä½æ•°æ®åˆ°ä½Žä½æ•°æ®
    // åˆ†è§£é«˜ä½æ•°æ®åˆ°ä½Žä½æ•°æ®
    for (size_t i = 0; i < vecHigh.size(); i++) {
        for (size_t j = 0; j < nGroupSize; j++) {
            vecLow[i * nGroupSize + j] = static_cast<U>((vecHigh[i] >> (j * CHAR_BIT * sizeof(U))) & ((1ULL << (CHAR_BIT * sizeof(U))) - 1));
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
@@ -10,151 +10,151 @@
#include <sstream>
#include <unordered_map>
// è¿žæŽ¥å‚æ•°
#define PLC_MAX_RETRY 3        // æœ€å¤§é‡è¯•次数:在与PLC通信时,如果发生通信错误,将最多重试3次
#define PLC_TIMEOUT 500        // è¶…时时间(毫秒):每次通信操作的超时等待时间为500毫秒
// è¿žæŽ¥å‚æ•°
#define PLC_MAX_RETRY 3        // æœ€å¤§é‡è¯•次数:在与PLC通信时,如果发生通信错误,将最多重试3次
#define PLC_TIMEOUT 500        // è¶…时时间(毫秒):每次通信操作的超时等待时间为500毫秒
/*
 * ç½‘络通道:指定通信所使用的网络通道号,通常在多通道通信中设置
 * 51 åˆ° 54 æ˜¯ MELSECNET/H çš„ 1-4 é€šé“
 * 81 åˆ° 84 æ˜¯ CC-Link çš„ 1-4 é€šé“
 * 151 åˆ° 154 æ˜¯ CC-Link IE æŽ§åˆ¶å™¨ç½‘络的 1-4 é€šé“
 * 181 åˆ° 184 æ˜¯ CC-Link IE çŽ°åœºç½‘ç»œçš„ 1-4 é€šé“
 * 281 åˆ° 284 æ˜¯ CC-Link IE TSN ç½‘络的 1-4 é€šé“
 * ç½‘络通道:指定通信所使用的网络通道号,通常在多通道通信中设置
 * 51 åˆ° 54 æ˜¯ MELSECNET/H çš„ 1-4 é€šé“
 * 81 åˆ° 84 æ˜¯ CC-Link çš„ 1-4 é€šé“
 * 151 åˆ° 154 æ˜¯ CC-Link IE æŽ§åˆ¶å™¨ç½‘络的 1-4 é€šé“
 * 181 åˆ° 184 æ˜¯ CC-Link IE çŽ°åœºç½‘ç»œçš„ 1-4 é€šé“
 * 281 åˆ° 284 æ˜¯ CC-Link IE TSN ç½‘络的 1-4 é€šé“
 **/
#define MELSECNET_CHANNEL(x) (50 + (x))           // x èŒƒå›´ï¼š1~4
#define CC_LINK_CHANNEL(x) (80 + (x))              // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_CONTROL_CHANNEL(x) (150 + (x)) // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_FIELD_CHANNEL(x) (180 + (x))   // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_TSN_CHANNEL(x) (280 + (x))     // x èŒƒå›´ï¼š1~4
#define MELSECNET_CHANNEL(x) (50 + (x))           // x èŒƒå›´ï¼š1~4
#define CC_LINK_CHANNEL(x) (80 + (x))              // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_CONTROL_CHANNEL(x) (150 + (x)) // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_FIELD_CHANNEL(x) (180 + (x))   // x èŒƒå›´ï¼š1~4
#define CC_LINK_IE_TSN_CHANNEL(x) (280 + (x))     // x èŒƒå›´ï¼š1~4
 // è‡ªå®šä¹‰é”™è¯¯ç 
#define ERROR_CODE_UNKNOWN                0x00010000 // æœªçŸ¥
#define ERROR_CODE_NOT_CONNECTED        0x00020000 // æœªè¿žæŽ¥
#define ERROR_CODE_INVALID_PARAM        0x00030000 // å‚数无效
#define ERROR_CODE_INVALID_DATA            0x00040000 // æ•°æ®æ— æ•ˆ
#define ERROR_CODE_STATION_OUT_OF_RANGE 0x00050000 // ç«™å·è¶…出范围
#define ERROR_CODE_GROUP_OUT_OF_RANGE   0x00060000 // ç»„号超出范围
#define ERROR_CODE_NETWORK_OUT_OF_RANGE 0x00070000 // ç½‘络号超出范围
 // è‡ªå®šä¹‰é”™è¯¯ç 
#define ERROR_CODE_UNKNOWN                0x00010000 // Î´Öª
#define ERROR_CODE_NOT_CONNECTED        0x00020000 // æœªè¿žæŽ¥
#define ERROR_CODE_INVALID_PARAM        0x00030000 // å‚数无效
#define ERROR_CODE_INVALID_DATA            0x00040000 // æ•°æ®æ— æ•ˆ
#define ERROR_CODE_STATION_OUT_OF_RANGE 0x00050000 // ç«™å·è¶…出范围
#define ERROR_CODE_GROUP_OUT_OF_RANGE   0x00060000 // ç»„号超出范围
#define ERROR_CODE_NETWORK_OUT_OF_RANGE 0x00070000 // ç½‘络号超出范围
// æ¿å—类型
// æ¿å—类型
enum class BoardType {
    UNKNOWN = -1,                                        // æœªçŸ¥ç±»åž‹
    UNKNOWN = -1,                                        // æœªçŸ¥ç±»åž‹
    MELSECNET_H = MELSECNET_CHANNEL(1),                    // MELSECNET/H
    CC_LINK_VER_2 = CC_LINK_CHANNEL(1),                    // CC-Link Ver. 2
    CC_LINK_IE_CONTROL = CC_LINK_IE_CONTROL_CHANNEL(1),    // CC-Link IE æŽ§åˆ¶ç½‘络
    CC_LINK_IE_FIELD = CC_LINK_IE_FIELD_CHANNEL(1),     // CC-Link IE çŽ°åœºç½‘ç»œ
    CC_LINK_IE_CONTROL = CC_LINK_IE_CONTROL_CHANNEL(1),    // CC-Link IE æŽ§åˆ¶ç½‘络
    CC_LINK_IE_FIELD = CC_LINK_IE_FIELD_CHANNEL(1),     // CC-Link IE çŽ°åœºç½‘ç»œ
    CC_LINK_IE_TSN = CC_LINK_IE_TSN_CHANNEL(1)          // CC-Link IE TSN
};
// è½¯å…ƒä»¶ç±»åž‹æžšä¸¾
// è½¯å…ƒä»¶ç±»åž‹æžšä¸¾
enum class DeviceType {
    /*
     * ER、LX、LY、LB、LW、LSB、LSW和SPG软元件都是范围型
     * ER:DevER0~256
     * LX:DevLX1~255,DevLX(x)    (DevX*1000+(x))
     * LY:DevLY1~255,DevLY(x)    (DevY*1000+(x))
     * LB:DevLB1~255,DevLB(x)    (DevB*1000+(x))
     * LW:DevLW1~255,DevLW(x)    (DevW*1000+(x))
     * LSB:DevLSB1~255,DevLSB(x) (DevQSB*1000+(x))
     * LSW:DevLSW1~255,DevLSW(x) (DevQSW*1000+(x))
     * SPG:DevSPG0~255,DevSPG(x) (29*1000+(x))
     * æ‰©å±•文件寄存器代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定块No.(0~256)
     * é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ä»£ç æŒ‡å®š(10进制数)的后3位数及软元件名指定的数值中,应指定网络No.(1~255)
     * æ™ºèƒ½åŠŸèƒ½æ¨¡å—è½¯å…ƒä»¶ä»£ç æŒ‡å®š(10进制数)的后3位数及软元件名指定的数值中,应指定(起始I/ONo.÷16)的值
     * æ‰©å±•文件寄存器和链接直接软元件在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束
     * MAIL和MAILMC在SEND功能及RECV功能中,与软元件访问一样,指定各功能对应的软元件类型,进行数据的发送(mdSend、mdSendEx)或数据的读取(mdReceive、mdReceiveEx)
     * ER、LX、LY、LB、LW、LSB、LSW和SPG软元件都是范围型
     * ER:DevER0~256
     * LX:DevLX1~255,DevLX(x)    (DevX*1000+(x))
     * LY:DevLY1~255,DevLY(x)    (DevY*1000+(x))
     * LB:DevLB1~255,DevLB(x)    (DevB*1000+(x))
     * LW:DevLW1~255,DevLW(x)    (DevW*1000+(x))
     * LSB:DevLSB1~255,DevLSB(x) (DevQSB*1000+(x))
     * LSW:DevLSW1~255,DevLSW(x) (DevQSW*1000+(x))
     * SPG:DevSPG0~255,DevSPG(x) (29*1000+(x))
     * æ‰©å±•文件寄存器代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定块No.(0~256)
     * é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ä»£ç æŒ‡å®š(10进制数)的后3位数及软元件名指定的数值中,应指定网络No.(1~255)
     * æ™ºèƒ½åŠŸèƒ½æ¨¡å—è½¯å…ƒä»¶ä»£ç æŒ‡å®š(10进制数)的后3位数及软元件名指定的数值中,应指定(起始I/ONo.÷16)的值
     * æ‰©å±•文件寄存器和链接直接软元件在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束
     * MAIL和MAILMC在SEND功能及RECV功能中,与软元件访问一样,指定各功能对应的软元件类型,进行数据的发送(mdSend、mdSendEx)或数据的读取(mdReceive、mdReceiveEx)
     **/
    X = 0x0001,      // è¾“å…¥ (位)
    Y = 0x0002,      // è¾“出 (位)
    L = 0x0003,      // é”å­˜ç»§ç”µå™¨ (位)
    M = 0x0004,      // å†…部继电器 (位)
    SM = 0x0005,     // ç‰¹æ®Šç»§ç”µå™¨ (位)
    F = 0x0006,      // æŠ¥è­¦å™¨ (位)
    TT = 0x0007,     // å®šæ—¶å™¨ (触点) (位)
    TC = 0x0008,     // è®¡æ•°å™¨ (线圈) (位)
    CT = 0x0009,     // è®¡æ•°å™¨ (触点) (位)
    CC = 0x000A,     // è®¡æ•°å™¨ (线圈) (字)
    TN = 0x000B,     // å®šæ—¶å™¨ (当前值) (字)
    CN = 0x000C,     // è®¡æ•°å™¨ (当前值) (字)
    D = 0x000D,      // æ•°æ®å¯„存器 (字)
    SD = 0x000E,     // ç‰¹æ®Šå¯„存器 (字)
    TM = 0x000F,     // å®šæ—¶å™¨ (设置值主) (字)
    TS = 0x0010,     // å®šæ—¶å™¨ (设置值主1) (字)
    TS2 = 0x3E82,    // å®šæ—¶å™¨ (设置值主2) (字)
    TS3 = 0x3E83,    // å®šæ—¶å™¨ (设置值主3) (字)
    CM = 0x0011,     // è®¡æ•°å™¨ (设置值主) (字)
    CS = 0x0012,     // è®¡æ•°å™¨ (设置值主1) (字)
    CS2 = 0x4652,    // è®¡æ•°å™¨ (设置值主2) (字)
    CS3 = 0x4653,    // è®¡æ•°å™¨ (设置值主3) (字)
    A = 0x0013,      // ç´¯åР噍 (字)
    Z = 0x0014,      // å˜å€å¯„存器 (字)
    V = 0x0015,      // å˜å€å¯„存器 (字)
    R = 0x0016,      // æ–‡ä»¶å¯„存器 (块切换方式) (字)
    ER = 0x55F0,     // æ‰©å±•文件寄存器 (块切换方式) (0x55F0~0x56F0) (字) (在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束。(读取数据不正确。))
    ZR = 0x00DC,     // æ–‡ä»¶å¯„存器 (连号访问方式) (字)
    B = 0x0017,      // é“¾æŽ¥ç»§ç”µå™¨ (位)
    W = 0x0018,      // é“¾æŽ¥å¯„存器 (字)
    QSB = 0x0019,    // é“¾æŽ¥ç‰¹æ®Šç»§ç”µå™¨ (位)
    STT = 0x001A,    // ç´¯è®¡å®šæ—¶å™¨ (触点) (位)
    STC = 0x001B,    // ç´¯è®¡å®šæ—¶å™¨ (线圈) (位)
    QSW = 0x001C,    // é“¾æŽ¥ç‰¹æ®Šå¯„存器 (字)
    QV = 0x001E,     // å˜å€ç»§ç”µå™¨ (位)
    MRB = 0x0021,     // éšæœºè®¿é—®ç¼“冲 (字)
    STN = 0x0023,    // ç´¯è®¡å®šæ—¶å™¨ (当前值) (字)
    LZ = 0x0026,     // è¶…长变址寄存器 (双字)
    RD = 0x0027,     // åˆ·æ–°æ•°æ®å¯„存器 (字)
    LTT = 0x0029,    // è¶…长定时器 (触点) (位)
    LTC = 0x002A,    // è¶…长定时器 (线圈) (位)
    LTN = 0x002B,    // è¶…长定时器 (当前值) (双字)
    LCT = 0x002C,    // è¶…长计数器 (触点) (位)
    LCC = 0x002D,    // è¶…长计数器 (线圈) (位)
    LCN = 0x002E,    // è¶…长计数器 (当前值) (双字)
    LSTT = 0x002F,   // è¶…长累计定时器 (触点) (位)
    LSTC = 0x0030,   // è¶…长累计定时器 (线圈) (位)
    LSTN = 0x0031,   // è¶…长累计定时器 (当前值) (双字)
    SPB = 0x0032,     // ç¼“冲存储器 (字)
    MAIL = 0x0065,   // ç‰¹æ®Šè½¯å…ƒä»¶ç±»åž‹ï¼šé‚®ä»¶ç±»åž‹ (10进制 101)
    MAILMC = 0x0066, // ç‰¹æ®Šè½¯å…ƒä»¶ç±»åž‹ï¼šæ— ç¡®è®¤é‚®ä»¶ (10进制 102)
    LX = 0x03E8,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输入) (0x03E9~0x04E7) (位)
    LY = 0x07D0,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输出) (0x07D1~0x08CF) (位)
    LB = 0x59D8,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接继电器) (0x59D9~0x5AD7) (位)
    LW = 0x5DC0,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接寄存器) (0x5DC1~0x5EBF) (字)
    LSB = 0x61A8,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊继电器) (0x61A9~0x62A7) (位)
    LSW = 0x6D60,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊寄存器) (0x6D61~0x6E5F) (字)
    SPG = 0x7147,    // æ™ºèƒ½åŠŸèƒ½æ¨¡å—è½¯å…ƒä»¶ (0x7148~0x7247) (字)
    X = 0x0001,      // è¾“å…¥ (位)
    Y = 0x0002,      // è¾“出 (位)
    L = 0x0003,      // é”å­˜ç»§ç”µå™¨ (位)
    M = 0x0004,      // å†…部继电器 (位)
    SM = 0x0005,     // ç‰¹æ®Šç»§ç”µå™¨ (位)
    F = 0x0006,      // æŠ¥è­¦å™¨ (位)
    TT = 0x0007,     // å®šæ—¶å™¨ (触点) (位)
    TC = 0x0008,     // è®¡æ•°å™¨ (线圈) (位)
    CT = 0x0009,     // è®¡æ•°å™¨ (触点) (位)
    CC = 0x000A,     // è®¡æ•°å™¨ (线圈) (字)
    TN = 0x000B,     // å®šæ—¶å™¨ (当前值) (字)
    CN = 0x000C,     // è®¡æ•°å™¨ (当前值) (字)
    D = 0x000D,      // æ•°æ®å¯„存器 (字)
    SD = 0x000E,     // ç‰¹æ®Šå¯„存器 (字)
    TM = 0x000F,     // å®šæ—¶å™¨ (设置值主) (字)
    TS = 0x0010,     // å®šæ—¶å™¨ (设置值主1) (字)
    TS2 = 0x3E82,    // å®šæ—¶å™¨ (设置值主2) (字)
    TS3 = 0x3E83,    // å®šæ—¶å™¨ (设置值主3) (字)
    CM = 0x0011,     // è®¡æ•°å™¨ (设置值主) (字)
    CS = 0x0012,     // è®¡æ•°å™¨ (设置值主1) (字)
    CS2 = 0x4652,    // è®¡æ•°å™¨ (设置值主2) (字)
    CS3 = 0x4653,    // è®¡æ•°å™¨ (设置值主3) (字)
    A = 0x0013,      // ç´¯åР噍 (字)
    Z = 0x0014,      // å˜å€å¯„存器 (字)
    V = 0x0015,      // å˜å€å¯„存器 (字)
    R = 0x0016,      // æ–‡ä»¶å¯„存器 (块切换方式) (字)
    ER = 0x55F0,     // æ‰©å±•文件寄存器 (块切换方式) (0x55F0~0x56F0) (字) (在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束。(读取数据不正确。))
    ZR = 0x00DC,     // æ–‡ä»¶å¯„存器 (连号访问方式) (字)
    B = 0x0017,      // é“¾æŽ¥ç»§ç”µå™¨ (位)
    W = 0x0018,      // é“¾æŽ¥å¯„存器 (字)
    QSB = 0x0019,    // é“¾æŽ¥ç‰¹æ®Šç»§ç”µå™¨ (位)
    STT = 0x001A,    // ç´¯è®¡å®šæ—¶å™¨ (触点) (位)
    STC = 0x001B,    // ç´¯è®¡å®šæ—¶å™¨ (线圈) (位)
    QSW = 0x001C,    // é“¾æŽ¥ç‰¹æ®Šå¯„存器 (字)
    QV = 0x001E,     // å˜å€ç»§ç”µå™¨ (位)
    MRB = 0x0021,     // éšæœºè®¿é—®ç¼“冲 (字)
    STN = 0x0023,    // ç´¯è®¡å®šæ—¶å™¨ (当前值) (字)
    LZ = 0x0026,     // è¶…长变址寄存器 (双字)
    RD = 0x0027,     // åˆ·æ–°æ•°æ®å¯„存器 (字)
    LTT = 0x0029,    // è¶…长定时器 (触点) (位)
    LTC = 0x002A,    // è¶…长定时器 (线圈) (位)
    LTN = 0x002B,    // è¶…长定时器 (当前值) (双字)
    LCT = 0x002C,    // è¶…长计数器 (触点) (位)
    LCC = 0x002D,    // è¶…长计数器 (线圈) (位)
    LCN = 0x002E,    // è¶…长计数器 (当前值) (双字)
    LSTT = 0x002F,   // è¶…长累计定时器 (触点) (位)
    LSTC = 0x0030,   // è¶…长累计定时器 (线圈) (位)
    LSTN = 0x0031,   // è¶…长累计定时器 (当前值) (双字)
    SPB = 0x0032,     // ç¼“冲存储器 (字)
    MAIL = 0x0065,   // ç‰¹æ®Šè½¯å…ƒä»¶ç±»åž‹ï¼šé‚®ä»¶ç±»åž‹ (10进制 101)
    MAILMC = 0x0066, // ç‰¹æ®Šè½¯å…ƒä»¶ç±»åž‹ï¼šæ— ç¡®è®¤é‚®ä»¶ (10进制 102)
    LX = 0x03E8,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输入) (0x03E9~0x04E7) (位)
    LY = 0x07D0,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接输出) (0x07D1~0x08CF) (位)
    LB = 0x59D8,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接继电器) (0x59D9~0x5AD7) (位)
    LW = 0x5DC0,     // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接寄存器) (0x5DC1~0x5EBF) (字)
    LSB = 0x61A8,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊继电器) (0x61A9~0x62A7) (位)
    LSW = 0x6D60,    // é“¾æŽ¥ç›´æŽ¥è½¯å…ƒä»¶ (链接特殊寄存器) (0x6D61~0x6E5F) (字)
    SPG = 0x7147,    // æ™ºèƒ½åŠŸèƒ½æ¨¡å—è½¯å…ƒä»¶ (0x7148~0x7247) (字)
};
// æ•°æ®ç±»åž‹
// æ•°æ®ç±»åž‹
enum class DataType {
    BIT = 1,   // ä½ (1位)
    WORD = 2,  // å­— (16位)
    DWORD = 4  // åŒå­— (32位)
    BIT = 1,   // Î» (1λ)
    WORD = 2,  // å­— (16位)
    DWORD = 4  // åŒå­— (32位)
};
// æŽ§åˆ¶ä»£ç 
// æŽ§åˆ¶ä»£ç 
enum class ControlCode {
    RUN = 0,   // è¿œç¨‹ RUN
    STOP = 1,  // è¿œç¨‹ STOP
    PAUSE = 2  // è¿œç¨‹ PAUSE
    RUN = 0,   // è¿œç¨‹ RUN
    STOP = 1,  // è¿œç¨‹ STOP
    PAUSE = 2  // è¿œç¨‹ PAUSE
};
// ç‰ˆæœ¬ä¿¡æ¯
// ç‰ˆæœ¬ä¿¡æ¯
struct BoardVersion {
    char fixedValue[2];       // å›ºå®šå€¼
    char checksum[2];         // æ ¡éªŒå’Œ
    char swVersion[2];        // è½¯ä»¶ç‰ˆæœ¬
    char date[6];             // æ—¥æœŸ (格式 YYMMDD)
    uint32_t reserved;        // ä¿ç•™åŒºåŸŸ (4 å­—节)
    char swModel[16];         // è½¯ä»¶åž‹å·
    char hwModel[16];         // ç¡¬ä»¶åž‹å·
    char twoPortMemory[2];    // ä¸¤ç«¯å£å­˜å‚¨å™¨å ç”¨å®¹é‡
    char twoPortAttribute[2]; // ä¸¤ç«¯å£å±žæ€§
    char availableBias[2];    // å¯ä½¿ç”¨åç½®
    char moduleType[10];      // æœºåž‹ç±»åž‹
    char fixedValue[2];       // å›ºå®šå€¼
    char checksum[2];         // æ ¡éªŒå’Œ
    char swVersion[2];        // è½¯ä»¶ç‰ˆæœ¬
    char date[6];             // æ—¥æœŸ (格式 YYMMDD)
    uint32_t reserved;        // ä¿ç•™åŒºåŸŸ (4 å­—节)
    char swModel[16];         // è½¯ä»¶åž‹å·
    char hwModel[16];         // ç¡¬ä»¶åž‹å·
    char twoPortMemory[2];    // ä¸¤ç«¯å£å­˜å‚¨å™¨å ç”¨å®¹é‡
    char twoPortAttribute[2]; // ä¸¤ç«¯å£å±žæ€§
    char availableBias[2];    // å¯ä½¿ç”¨åç½®
    char moduleType[10];      // æœºåž‹ç±»åž‹
    // è¾“出结构体内容为字符串 (便于调试)
    // è¾“出结构体内容为字符串 (便于调试)
    std::string toString() const {
        std::ostringstream oss;
        oss << "Fixed Value: " << fixedValue[0] << fixedValue[1] << "\n"
@@ -172,18 +172,18 @@
    }
};
// ç«™ç‚¹æ ‡è¯†ç¬¦ï¼Œé»˜è®¤ä½¿ç”¨æœ¬ç«™
// ç«™ç‚¹æ ‡è¯†ç¬¦ï¼Œé»˜è®¤ä½¿ç”¨æœ¬ç«™
struct StationIdentifier {
    /*
     * [Network No.]
     * 0 è¡¨ç¤ºæœ¬ç«™
     * 1~239 è¡¨ç¤ºæ™®é€šç½‘络号
     * 0 è¡¨ç¤ºæœ¬ç«™
     * 1~239 è¡¨ç¤ºæ™®é€šç½‘络号
     **/
     /*
      * [Station No.]
      * MELSECNET/H:1~64 è¡¨ç¤ºå…¶ä»–站点,255 è¡¨ç¤ºæœ¬ç«™
      * CC-Link ç³»åˆ—网络的范围类似,区别在于站号的取值范围
      * MELSECNET/H:1~64 è¡¨ç¤ºå…¶ä»–站点,255 è¡¨ç¤ºæœ¬ç«™
      * CC-Link ç³»åˆ—网络的范围类似,区别在于站号的取值范围
      * MELSECNET/H             : 1~64(Other stations),255(Own station)
      * CC-Link                 : 0~63(Other stations),255(Own station)
      * CC-Link IE Controller   : 1~120(Other stations),255(Own station)
@@ -192,15 +192,15 @@
      **/
      /*
       * é«˜ 8 ä½ï¼ˆç½‘络号): æŒ‡å®šè®¾å¤‡æ‰€å±žçš„网络
       * ä½Ž 8 ä½ï¼ˆç«™ç‚¹å·ï¼‰ï¼š æŒ‡å®šè®¾å¤‡åœ¨ç½‘络中的编号
       * ç”¨ä¸€ä¸ªå‚数传递设备的网络号和站点号时: nSt = station.nStNo | ((station.nNetNo << 8) & 0xFF00);
       * é«˜ 8 ä½ï¼ˆç½‘络号): æŒ‡å®šè®¾å¤‡æ‰€å±žçš„网络
       * ä½Ž 8 ä½ï¼ˆç«™ç‚¹å·ï¼‰ï¼š æŒ‡å®šè®¾å¤‡åœ¨ç½‘络中的编号
       * ç”¨ä¸€ä¸ªå‚数传递设备的网络号和站点号时: nSt = station.nStNo | ((station.nNetNo << 8) & 0xFF00);
       **/
    short nNetNo = 0;    // ç½‘络编号:PLC所连接的网络编号,0表示默认网络
    short nStNo = 255;   // ç«™ç‚¹ç¼–号:指定与PLC连接的站点编号,255通常表示广播或所有站点
    short nNetNo = 0;    // ç½‘络编号:PLC所连接的网络编号,0表示默认网络
    short nStNo = 255;   // ç«™ç‚¹ç¼–号:指定与PLC连接的站点编号,255通常表示广播或所有站点
    // è‡ªå®šä¹‰æž„造函数,覆盖默认值
    // è‡ªå®šä¹‰æž„造函数,覆盖默认值
    explicit StationIdentifier(const short net, const short st) : nNetNo(net), nStNo(st) {}
    StationIdentifier() 
@@ -209,24 +209,24 @@
        nStNo = 255;
    }
    // å°†â€œç½‘络号”和“站点号”组合成一个最终编码
    // å°†â€œç½‘络号”和“站点号”组合成一个最终编码
    short StationIdentifier::toNetworkStationCode() const {
        return static_cast<short>(nStNo | ((nNetNo << 8) & 0xFF00));
    }
    // é‡è½½ < è¿ç®—符(用于排序或比较,通常用于 map æˆ– set ä¸­ä½œä¸º key)
    // é‡è½½ < è¿ç®—符(用于排序或比较,通常用于 map æˆ– set ä¸­ä½œä¸º key)
    bool operator<(const StationIdentifier& other) const {
        return std::tie(nNetNo, nStNo) <
            std::tie(other.nNetNo, other.nStNo);
    }
    // é‡è½½ == è¿ç®—符(用于相等比较)
    // é‡è½½ == è¿ç®—符(用于相等比较)
    bool operator==(const StationIdentifier& other) const {
        return std::tie(nNetNo, nStNo) ==
            std::tie(other.nNetNo, other.nStNo);
    }
    // é‡è½½ = è¿ç®—符(用于赋值)
    // é‡è½½ = è¿ç®—符(用于赋值)
    StationIdentifier& operator=(const StationIdentifier& other) {
        if (this != &other) {
            nNetNo = other.nNetNo;
@@ -236,16 +236,16 @@
    }
};
// æ¿çŠ¶æ€
// æ¿çŠ¶æ€
struct BoardStatus {
    short nStationValue = 0;    // ç«™å·çš„设备值 (buf[0])
    short nGroupValue = 0;      // ç»„ No. çš„设备值 (buf[1])
    short nNetworkValue = 0;    // ç½‘络 No. çš„设备值 (buf[2])
    short nReserved1 = 0;       // ä¿ç•™å­—段 (buf[3])
    short nReserved2 = 0;       // ä¿ç•™å­—段 (buf[4])
    short nReserved3 = 0;       // ä¿ç•™å­—段 (buf[5])
    short nStationValue = 0;    // ç«™å·çš„设备值 (buf[0])
    short nGroupValue = 0;      // ç»„ No. çš„设备值 (buf[1])
    short nNetworkValue = 0;    // ç½‘络 No. çš„设备值 (buf[2])
    short nReserved1 = 0;       // ä¿ç•™å­—段 (buf[3])
    short nReserved2 = 0;       // ä¿ç•™å­—段 (buf[4])
    short nReserved3 = 0;       // ä¿ç•™å­—段 (buf[5])
    // å°†æ•°ç»„映射到结构体
    // å°†æ•°ç»„映射到结构体
    static BoardStatus fromBuffer(const short buf[6]) {
        return {
            buf[0],
@@ -257,7 +257,7 @@
        };
    }
    // å°†ç»“构体内容映射到数组
    // å°†ç»“构体内容映射到数组
    void toBuffer(short buf[6]) const {
        buf[0] = nStationValue;
        buf[1] = nGroupValue;
@@ -267,7 +267,7 @@
        buf[5] = nReserved3;
    }
    // è°ƒè¯•输出
    // è°ƒè¯•输出
    std::string toString() const {
        std::ostringstream oss;
        oss << "Station Value: " << nStationValue << "\n"
@@ -280,12 +280,12 @@
    }
};
// äº‹ä»¶è¯¦æƒ…
// äº‹ä»¶è¯¦æƒ…
struct EventDetails {
    short nEventNo;                      // å‘生的事件号
    std::array<short, 4> details;         // å­˜å‚¨äº‹ä»¶è¯¦æƒ…信息
    short nEventNo;                      // å‘生的事件号
    std::array<short, 4> details;         // å­˜å‚¨äº‹ä»¶è¯¦æƒ…信息
    // è§£æžäº‹ä»¶è¯¦æƒ…,返回格式化字符串
    // è§£æžäº‹ä»¶è¯¦æƒ…,返回格式化字符串
    std::string toString() const {
        std::ostringstream oss;
        oss << "Details[0]: " << details[0] << ", "
@@ -296,33 +296,33 @@
    }
};
// SoftElement ç»“构体定义
// SoftElement ç»“构体定义
struct SoftElement {
    short nType;         // è½¯å…ƒä»¶ç±»åž‹
    short nElementCount; // ç‚¹æ•°
    long nStartNo;       // èµ·å§‹è½¯å…ƒä»¶ç¼–号
    short nType;         // è½¯å…ƒä»¶ç±»åž‹
    short nElementCount; // ç‚¹æ•°
    long nStartNo;       // èµ·å§‹è½¯å…ƒä»¶ç¼–号
};
// é”™è¯¯ä¿¡æ¯
// é”™è¯¯ä¿¡æ¯
struct ErrorInfo {
    int nErrorCode = 0;              // é”™è¯¯ç 
    std::string strErrorMessageCn;   // ä¸­æ–‡æè¿°
    std::string strErrorMessageEn;   // è‹±æ–‡æè¿°
    int nErrorCode = 0;              // é”™è¯¯ç 
    std::string strErrorMessageCn;   // ä¸­æ–‡æè¿°
    std::string strErrorMessageEn;   // è‹±æ–‡æè¿°
    // å°†ç»“构体序列化为字符串
    // å°†ç»“构体序列化为字符串
    std::string toString() const {
        std::ostringstream oss;
        oss << nErrorCode << "|" << strErrorMessageCn << "|" << strErrorMessageEn;
        return oss.str();
    }
    // ä»Žå­—符串反序列化为结构体
    // ä»Žå­—符串反序列化为结构体
    static ErrorInfo fromString(const std::string& line) {
        ErrorInfo info;
        std::istringstream iss(line);
        std::string token;
        // ä½¿ç”¨åˆ†éš”符 "|" è§£æžå­—符串
        // ä½¿ç”¨åˆ†éš”符 "|" è§£æžå­—符串
        std::getline(iss, token, '|');
        info.nErrorCode = std::stoi(token);
@@ -336,47 +336,47 @@
    }
};
using BitContainer = std::vector<bool>;            // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 1  ä½
using WordContainer = std::vector<uint16_t>;    // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 16 ä½
using DWordContainer = std::vector<uint32_t>;    // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 32 ä½
using BitContainer = std::vector<bool>;            // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 1  ä½
using WordContainer = std::vector<uint16_t>;    // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 16 ä½
using DWordContainer = std::vector<uint32_t>;    // æ¯ä¸ªå…ƒç´ å­˜å‚¨ 32 ä½
// CPerformanceMelsec ç±»å£°æ˜Ž
// CPerformanceMelsec ç±»å£°æ˜Ž
class CPerformanceMelsec {
public:
    // èŽ·å–æœ€è¿‘çš„é”™è¯¯ä¿¡æ¯
    // èŽ·å–æœ€è¿‘çš„é”™è¯¯ä¿¡æ¯
    std::string GetLastError() const;
    // é”™è¯¯ä¿¡æ¯åŠ è½½ä¸Žä¿å­˜æŽ¥å£
    static bool LoadErrorInfoFromFile(const std::string& filename);  // ä»Žæ–‡ä»¶åŠ è½½é”™è¯¯ä¿¡æ¯
    static bool SaveErrorInfoToFile(const std::string& filename);    // ä¿å­˜é”™è¯¯ä¿¡æ¯åˆ°æ–‡ä»¶
    // é”™è¯¯ä¿¡æ¯åŠ è½½ä¸Žä¿å­˜æŽ¥å£
    static bool LoadErrorInfoFromFile(const std::string& filename);  // ä»Žæ–‡ä»¶åŠ è½½é”™è¯¯ä¿¡æ¯
    static bool SaveErrorInfoToFile(const std::string& filename);    // ä¿å­˜é”™è¯¯ä¿¡æ¯åˆ°æ–‡ä»¶
    // è¿žæŽ¥/断开
    // è¿žæŽ¥/断开
    int Connect(short nChannel, short nMode = -1);
    int Disconnect();
    // åˆå§‹åŒ–可编程控制器软元件信息表
    // åˆå§‹åŒ–可编程控制器软元件信息表
    int InitializeController();
    //    èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
    //    èŽ·å–ç‰ˆæœ¬ä¿¡æ¯
    int GetBoardVersion(BoardVersion& version);
    // æ¿å¤ä½
    // æ¿å¤ä½
    int BoardReset();
    // æ¿LED读取
    // æ¿LED读取
    int ReadBoardLed(std::vector<short>& vecLedBuffer);
    // è¯»å–目标站点CPU类型
    // è¯»å–目标站点CPU类型
    int ReadCPUCode(const StationIdentifier& station, short& nCPUCode);
    // æ¿æ¨¡å¼èŽ·å–/设置
    // æ¿æ¨¡å¼èŽ·å–/设置
    int SetBoardMode(short nMode);
    int GetBoardMode(short& nMode);
    // èŽ·å–æ¿çŠ¶æ€
    // èŽ·å–æ¿çŠ¶æ€
    int GetBoardStatus(BoardStatus& status);
    // è¯»å†™æ•°æ®
    // è¯»å†™æ•°æ®
    int ReadData(const StationIdentifier& station, short nDevType, short nDevNo, short nSize, std::vector<short>& vecData);
    int ReadBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nBitCount, BitContainer& vecData);
    int ReadWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nWordCount, WordContainer& vecData);
@@ -386,60 +386,60 @@
    int WriteWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const WordContainer& vecData);
    int WriteDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const DWordContainer& vecData);
    // æ‰©å±•读写数据
    // æ‰©å±•读写数据
    long ReadDataEx(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<char>& vecData);
    long WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& vecData);
    // æ‰©å±•软元件随机读写(支持多个软元件)
    // æ‰©å±•软元件随机读写(支持多个软元件)
    long ReadRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, std::vector<char>& vecData);
    long WriteRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, const std::vector<char>& vecData);
    // è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器读写
    // è¿œç¨‹è®¾å¤‡ç«™/远程站的缓冲存储器读写
    long ReadRemoteBuffer(const StationIdentifier& station, long nOffset, long nSize, std::vector<char>& vecData);
    long WriteRemoteBuffer(const StationIdentifier& station, long nOffset, const std::vector<char>& vecData);
    long ReadRemoteBufferByIp(const std::string& strIP, long nOffset, long nSize, std::vector<char>& vecData);
    long WriteRemoteBufferByIp(const std::string& strIP, long nOffset, const std::vector<char>& vecData);
    // è®¾ç½®/复位对象站的指定位软元件
    // è®¾ç½®/复位对象站的指定位软元件
    int SetBitDevice(const StationIdentifier& station, DeviceType enDevType, short nDevNo);
    int ResetBitDevice(const StationIdentifier& station, DeviceType enDevType, short enDevNo);
    // æ‰©å±•设置/复位对象站的指定位软元件
    // æ‰©å±•设置/复位对象站的指定位软元件
    long SetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo);
    long ResetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo);
    // æ‰§è¡Œå¯¹è±¡ç«™çš„CPU
    // æ‰§è¡Œå¯¹è±¡ç«™çš„CPU
    int ControlCPU(const StationIdentifier& station, ControlCode enControlCode);
    // äº‹ä»¶ç­‰å¾…,vecEventNumbers[0, 64],nTimeoutMs[-1, 2147483647]
    // åŒæ—¶å‘生了多个事件的情况下,首先检测出其中一个事件。 å†æ¬¡æ‰§è¡Œäº†æœ¬å‡½æ•°çš„æƒ…况下检测出其它事件。
    // äº‹ä»¶ç­‰å¾…,vecEventNumbers[0, 64],nTimeoutMs[-1, 2147483647]
    // åŒæ—¶å‘生了多个事件的情况下,首先检测出其中一个事件。 å†æ¬¡æ‰§è¡Œäº†æœ¬å‡½æ•°çš„æƒ…况下检测出其它事件。
    int WaitForBoardEvent(std::vector<short> vecEventNumbers, int nTimeoutMs, EventDetails& details);
private:
    // é”å®šä¸Žè§£é”ï¼ˆå¤šçº¿ç¨‹åŒæ­¥ä¿æŠ¤ï¼‰
    // é”å®šä¸Žè§£é”ï¼ˆå¤šçº¿ç¨‹åŒæ­¥ä¿æŠ¤ï¼‰
    void Lock() { m_mtx.lock(); }
    void Unlock() { m_mtx.unlock(); }
protected:
    // æž„造函数/析构函数
    // æž„造函数/析构函数
    explicit CPerformanceMelsec(BoardType enBoardType);
    virtual ~CPerformanceMelsec();
    // è¾…助函数
    void UpdateLastError(int nCode);                                 // æ›´æ–°æœ€è¿‘的错误信息
    int ValidateStation(const StationIdentifier& station) const;     // æ£€æŸ¥è¿žæŽ¥çŠ¶æ€å’Œç«™ç‚¹å‚æ•°æœ‰æ•ˆæ€§
    // è¾…助函数
    void UpdateLastError(int nCode);                                 // æ›´æ–°æœ€è¿‘的错误信息
    int ValidateStation(const StationIdentifier& station) const;     // æ£€æŸ¥è¿žæŽ¥çŠ¶æ€å’Œç«™ç‚¹å‚æ•°æœ‰æ•ˆæ€§
    int ValidateStationAndSize(const StationIdentifier& station, short nCount) const;
    // é™æ€è¾…助函数
    static void Delay(unsigned int nDelayMs);                        // å»¶æ—¶ï¼Œå¹¶ä¸”转发窗口消息
    static BoardType FindBoardTypeByChannel(int nChannel);            // æŸ¥æ‰¾æ¿å—类型
    static short CombineStation(const StationIdentifier& station);  // åˆå¹¶ç½‘络号和站点号
    static short CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType); // è®¡ç®—软元件类型
    // é™æ€è¾…助函数
    static void Delay(unsigned int nDelayMs);                        // å»¶æ—¶ï¼Œå¹¶ä¸”转发窗口消息
    static BoardType FindBoardTypeByChannel(int nChannel);            // æŸ¥æ‰¾æ¿å—类型
    static short CombineStation(const StationIdentifier& station);  // åˆå¹¶ç½‘络号和站点号
    static short CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType); // è®¡ç®—软元件类型
    // IP转换
    // IP转换
    static bool ConvertIpStringToUint32(const std::string& strIP, uint32_t& nIP);
    // å®¹å™¨è½¬æ¢
    // å®¹å™¨è½¬æ¢
    static void ConvertCharToShort(const std::vector<char>& vecChar, std::vector<short>& vecShort);
    static void ConvertShortToChar(const std::vector<short>& vecShort, std::vector<char>& vecChar);
    static void ConvertUint8ToShort(const std::vector<uint8_t>& vecUint8, std::vector<short>& vecShort);
@@ -447,7 +447,7 @@
    static void ConvertUint32ToShort(const std::vector<uint32_t>& vecUint32, std::vector<short>& vecShort);
    static void ConvertShortToUint32(const std::vector<short>& vecShort, std::vector<uint32_t>& vecUint32);
    // æ¨¡æ¿è¾…助函数
    // æ¨¡æ¿è¾…助函数
    template <typename T>
    int ValidateStationAndData(const StationIdentifier& station, const std::vector<T>& vecData);
@@ -457,15 +457,15 @@
    template <typename T, typename U>
    void ConvertHighToLow(const std::vector<T>& vecHigh, std::vector<U>& vecLow);
    // æˆå‘˜å˜é‡
    std::mutex m_mtx;                       // äº’斥锁保护
    BoardType m_enBoardType;                // æ¿å—类型
    long m_nPath;                           // é€šä¿¡è·¯å¾„
    std::atomic<bool> m_bConnected;         // æ˜¯å¦å·²è¿žæŽ¥
    std::string m_strLastError;             // æœ€è¿‘一次错误信息
    // æˆå‘˜å˜é‡
    std::mutex m_mtx;                       // äº’斥锁保护
    BoardType m_enBoardType;                // æ¿å—类型
    long m_nPath;                           // é€šä¿¡è·¯å¾„
    std::atomic<bool> m_bConnected;         // æ˜¯å¦å·²è¿žæŽ¥
    std::string m_strLastError;             // æœ€è¿‘一次错误信息
    // é™æ€æˆå‘˜å˜é‡
    static std::unordered_map<int, std::string> m_mapError; // é”™è¯¯ç æ˜ å°„表
    // é™æ€æˆå‘˜å˜é‡
    static std::unordered_map<int, std::string> m_mapError; // é”™è¯¯ç æ˜ å°„表
};
#endif // PERFORMANCE_MELSEC_H
SourceCode/Bond/Servo/CEqAlarmStep.cpp
@@ -5,7 +5,7 @@
namespace SERVO {
    CEqAlarmStep::CEqAlarmStep() : CStep()
    CEqAlarmStep::CEqAlarmStep() : CReadStep()
    {
        m_nAlarmDev = 0;
        m_nAlarmState = 0;
@@ -19,9 +19,30 @@
    {
    }
    void CEqAlarmStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        CReadStep::getAttributeVector(attrubutes);
        attrubutes.addAttribute(new CAttribute("Alarm State",
            std::to_string(m_nAlarmState).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Unit ID",
            std::to_string(m_nUnitId).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Alarm Level",
            std::to_string(m_nAlarmLevel).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Alarm Code",
            std::to_string(m_nAlarmCode).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Alarm ID",
            std::to_string(m_nAlarmId).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Text",
            m_strText.c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Description",
            m_strDescription.c_str(), ""));
    }
    int CEqAlarmStep::onReadData()
    {
        CStep::onReadData();
        CReadStep::onReadData();
        char szBuffer[64];
        int nRet = m_pCclink->ReadData2(m_station, DeviceType::W,
@@ -45,7 +66,7 @@
    int CEqAlarmStep::onComplete()
    {
        CStep::onComplete();
        CReadStep::onComplete();
        LOGI("<CEqAlarmStep> onComplete.");
        return 0;
@@ -53,7 +74,7 @@
    int CEqAlarmStep::onTimeout()
    {
        CStep::onTimeout();
        CReadStep::onTimeout();
        LOGI("<CEqAlarmStep> onTimeout.");
        return 0;
@@ -122,12 +143,28 @@
        m_strText = strText;
    }
    // èŽ·å–å’Œè®¾ç½® Description
    std::string CEqAlarmStep::getDescription() const {
        return m_strDescription;
    int CEqAlarmStep::getAlarmState()
    {
        return m_nAlarmState;
    }
    void CEqAlarmStep::setDescription(const std::string& strDescription) {
        m_strDescription = strDescription;
    int CEqAlarmStep::getUnitId()
    {
        return m_nUnitId;
    }
    int CEqAlarmStep::getAlarmLevel()
    {
        return m_nAlarmLevel;
    }
    int CEqAlarmStep::getAlarmCode()
    {
        return m_nAlarmCode;
    }
    int CEqAlarmStep::getAlarmId()
    {
        return m_nAlarmId;
    }
}
SourceCode/Bond/Servo/CEqAlarmStep.h
@@ -1,44 +1,25 @@
#pragma once
#include "CStep.h"
#include "CReadStep.h"
namespace SERVO {
    class CEqAlarmStep : public CStep
    class CEqAlarmStep : public CReadStep
    {
    public:
        CEqAlarmStep();
        ~CEqAlarmStep();
    public:
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int onReadData();
        virtual int onComplete();
        virtual int onTimeout();
        // Getter å’Œ Setter å£°æ˜Ž
        int getAlarmDev() const;
        void setAlarmDev(int nAlarmDev);
        int getAlarmState() const;
        void setAlarmState(int nAlarmState);
        int getUnitId() const;
        void setUnitId(int nUnitId);
        int getAlarmLevel() const;
        void setAlarmLevel(int nAlarmLevel);
        int getAlarmCode() const;
        void setAlarmCode(int nAlarmCode);
        int getAlarmId() const;
        void setAlarmId(int nAlarmId);
        std::string getText() const;
        void setText(const std::string& strText);
        std::string getDescription() const;
        void setDescription(const std::string& strDescription);
        void setAlarmDev(int nDev);
        int getAlarmState();
        int getUnitId();
        int getAlarmLevel();
        int getAlarmCode();
        int getAlarmId();
    private:
        int m_nAlarmDev;
SourceCode/Bond/Servo/CEqCimModeChangeStep.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
#include "stdafx.h"
#include "CEqCimModeChangeStep.h"
namespace SERVO {
    CEqCimModeChangeStep::CEqCimModeChangeStep() : CWriteStep()
    {
        m_nCimModeDev = 0;
    }
    CEqCimModeChangeStep::~CEqCimModeChangeStep()
    {
    }
    void CEqCimModeChangeStep::setCimModeDev(int nDev)
    {
        m_nCimModeDev = nDev;
    }
    int CEqCimModeChangeStep::cimOn()
    {
        short mode = 1;
        return writeData(m_nCimModeDev, (const char*)&mode, sizeof(short));
    }
    int CEqCimModeChangeStep::cimOff()
    {
        short mode = 2;
        return writeData(m_nCimModeDev, (const char*)&mode, sizeof(short));
    }
    int CEqCimModeChangeStep::setCimMode(short mode)
    {
        return writeData(m_nCimModeDev, (const char*)&mode, sizeof(short));
    }
    void CEqCimModeChangeStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        CWriteStep::getAttributeVector(attrubutes);
        attrubutes.addAttribute(new CAttribute("Cim Mode Dev",
            std::to_string(m_nCimModeDev).c_str(), ""));
    }
}
SourceCode/Bond/Servo/CEqCimModeChangeStep.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
#pragma once
#include "CWriteStep.h"
namespace SERVO {
    class CEqCimModeChangeStep : public CWriteStep
    {
    public:
        CEqCimModeChangeStep();
        ~CEqCimModeChangeStep();
    public:
        void setCimModeDev(int nDev);
        int cimOn();
        int cimOff();
        int setCimMode(short mode);
        void getAttributeVector(CAttributeVector& attrubutes);
    private:
        int m_nCimModeDev;
    };
}
SourceCode/Bond/Servo/CEqModeStep.cpp
@@ -4,7 +4,7 @@
namespace SERVO {
    CEqModeStep::CEqModeStep() : CStep()
    CEqModeStep::CEqModeStep() : CReadStep()
    {
        m_nModeDev = 0;
        m_nMode = 0;
@@ -15,9 +15,20 @@
    }
    void CEqModeStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        CReadStep::getAttributeVector(attrubutes);
        std::string strTemp;
        attrubutes.addAttribute(new CAttribute("Mode",
            std::to_string(m_nMode).c_str(), getModeDescription(strTemp).c_str()));
        attrubutes.addAttribute(new CAttribute("Mode Dev",
            std::to_string(m_nModeDev).c_str(), ""));
    }
    int CEqModeStep::onReadData()
    {
        CStep::onReadData();
        CReadStep::onReadData();
        DWordContainer dc;
        if (0 != m_pCclink->ReadDWordData(m_station, DeviceType::W, m_nModeDev, 1, dc)) {
@@ -37,7 +48,7 @@
    int CEqModeStep::onComplete()
    {
        CStep::onComplete();
        CReadStep::onComplete();
        LOGI("<CEqModeStep> onComplete.");
        return 0;
@@ -45,7 +56,7 @@
    int CEqModeStep::onTimeout()
    {
        CStep::onTimeout();
        CReadStep::onTimeout();
        LOGI("<CEqModeStep> onTimeout.");
        return 0;
@@ -56,6 +67,11 @@
        m_nModeDev = nDev;
    }
    int CEqModeStep::getMode()
    {
        return m_nMode;
    }
    /*
    0: No Equipment Mode exist
        1: Normal Mode
SourceCode/Bond/Servo/CEqModeStep.h
@@ -1,19 +1,21 @@
#pragma once
#include "CStep.h"
#include "CReadStep.h"
namespace SERVO {
    class CEqModeStep : public CStep
    class CEqModeStep : public CReadStep
    {
    public:
        CEqModeStep();
        ~CEqModeStep();
    public:
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int onReadData();
        virtual int onComplete();
        virtual int onTimeout();
        void setModeDev(int nDev);
        int getMode();
        std::string& getModeDescription(std::string& strDescription);
    private:
SourceCode/Bond/Servo/CEqProcessStep.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,160 @@
#include "stdafx.h"
#include "Common.h"
#include "CEqProcessStep.h"
#include "Log.h"
#include "ToolUnits.h"
namespace SERVO {
    CEqProcessStep::CEqProcessStep() : CReadStep()
    {
        m_nProcessDev = 0;
        m_nTotalParameter = 0;
    }
    CEqProcessStep::~CEqProcessStep()
    {
    }
    void CEqProcessStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        CReadStep::getAttributeVector(attrubutes);
        attrubutes.addAttribute(new CAttribute("Glass ID",
            m_strGlassId.c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Start Time",
            m_strStartTime.c_str(), ""));
        attrubutes.addAttribute(new CAttribute("End Time",
            m_strEndTime.c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Total Parameter",
            std::to_string(m_nTotalParameter).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Total Group",
            std::to_string(m_nTotalGroup).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Current Group",
            std::to_string(m_nCurrentGroup).c_str(), ""));
        char szName[256];
        int index = 0;
        for (auto item : m_params) {
            sprintf_s(szName, 256, "Parameter %d", ++index);
            attrubutes.addAttribute(new CAttribute(szName,
                item.c_str(), ""));
        }
    }
#define PROGRESS_BUF_SIZE        (1024 + 64)
    int CEqProcessStep::onReadData()
    {
        CReadStep::onReadData();
        // W1864 ~ W1A74, 529个word, 1058 bytes
        char szBuffer[PROGRESS_BUF_SIZE];
        int nRet = m_pCclink->ReadData2(m_station, DeviceType::W,
            m_nProcessDev, PROGRESS_BUF_SIZE, szBuffer);
        if (0 != nRet) {
            return -1;
        }
        // è§£é‡Šæ•°æ®
        // Glass ID(1864~186D)
        int index = 0;
        convertString(&szBuffer[index], (0x186d - 0x1864 + 1) * 2, m_strStartTime);
        index += (0x186d - 0x1864 + 1) * 2;
        // Process Start Time(186e~1875)
        convertString(&szBuffer[index], (0x1875 - 0x186e + 1) * 2, m_strStartTime);
        index += (0x1875 - 0x186e + 1) * 2;
        // Process End Time(1876~187d)
        convertString(&szBuffer[index], (0x187d - 0x1876 + 1) * 2, m_strEndTime);
        index += (0x187d - 0x1876 + 1) * 2;
        // parameter count
        m_nTotalParameter = (unsigned int)CToolUnits::toInt16(&szBuffer[index]);
        index += 2;
        // total group
        m_nTotalGroup = (unsigned int)CToolUnits::toInt16(&szBuffer[index]);
        index += 2;
        // current group
        m_nCurrentGroup = (unsigned int)CToolUnits::toInt16(&szBuffer[index]);
        index += 2;
        // param list(0x1881~0x1a74), å…±1000 bytes, 20个字符为一个参数, 50组
        // æœ€åŽä¸€group可能不满足50, ä»¥m_nTotalParameter为依据
        int size = (m_nCurrentGroup == m_nTotalGroup) ? m_nTotalParameter % 50 : 50;
        for (int i = 0; i < size; i++) {
            std::string strParam;
            convertString(&szBuffer[index], 20, strParam);
            if (!strParam.empty()) {
                m_params.push_back(strParam);
            }
            index += 20;
        }
        if (m_nCurrentGroup == m_nTotalGroup && m_listener.onEvent != nullptr) {
            m_listener.onEvent(this, STEP_EVENT_PROCESS_DATA, nullptr);
        }
        LOGI("<CEqProcessStep> Process Data<GlassId:%s>\n",
            m_strGlassId.c_str());
        return 0;
    }
    int CEqProcessStep::onComplete()
    {
        CReadStep::onComplete();
        LOGI("<CEqProcessStep> onComplete.");
        return 0;
    }
    int CEqProcessStep::onTimeout()
    {
        CReadStep::onTimeout();
        LOGI("<CEqProcessStep> onTimeout.");
        return 0;
    }
    void CEqProcessStep::setProcessDev(int nDev)
    {
        m_nProcessDev = nDev;
    }
    std::string& CEqProcessStep::getGlassId()
    {
        return m_strGlassId;
    }
    std::string& CEqProcessStep::getStartTime()
    {
        return m_strStartTime;
    }
    std::string& CEqProcessStep::getEndTime()
    {
        return m_strEndTime;
    }
    unsigned int CEqProcessStep::getTotalParameter()
    {
        return m_nTotalParameter;
    }
    const std::list<std::string> CEqProcessStep::getParameters()
    {
        return m_params;
    }
    void CEqProcessStep::getParameters(std::list<std::string>& list)
    {
        Lock();
        std::copy(m_params.begin(), m_params.end(), std::back_inserter(list));
        Unlock();
    }
}
SourceCode/Bond/Servo/CEqProcessStep.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
#pragma once
#include "CReadStep.h"
#include <list>
namespace SERVO {
    class CEqProcessStep : public CReadStep
    {
    public:
        CEqProcessStep();
        ~CEqProcessStep();
    public:
        void getAttributeVector(CAttributeVector& attrubutes);
        virtual int onReadData();
        virtual int onComplete();
        virtual int onTimeout();
        void setProcessDev(int nDev);
        std::string& getGlassId();
        std::string& getStartTime();
        std::string& getEndTime();
        unsigned int getTotalParameter();
        const std::list<std::string> getParameters();
        void getParameters(std::list<std::string>& list);
    private:
        int m_nProcessDev;
        std::string m_strGlassId;
        std::string m_strStartTime;
        std::string m_strEndTime;
        unsigned int m_nTotalParameter;
        unsigned int m_nTotalGroup;
        unsigned int m_nCurrentGroup;
        std::list<std::string> m_params;
    };
}
SourceCode/Bond/Servo/CEqStatusStep.cpp
@@ -5,7 +5,7 @@
namespace SERVO {
    CEqStatusStep::CEqStatusStep() : CStep()
    CEqStatusStep::CEqStatusStep() : CReadStep()
    {
        m_nStatusDev = 0;
        for (int i = 0; i < STATUS_MAX; i++) {
@@ -21,9 +21,35 @@
    }
    void CEqStatusStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        CReadStep::getAttributeVector(attrubutes);
        char szName[256];
        for (int i = 0; i < STATUS_MAX; i++) {
            sprintf_s(szName, 256, "Status %d", i + 1);
            attrubutes.addAttribute(new CAttribute(szName,
                std::to_string(m_nStatus[i]).c_str(), ""));
            sprintf_s(szName, 256, "Reason Code %d", i + 1);
            attrubutes.addAttribute(new CAttribute(szName,
                std::to_string(m_nReasonCode[i]).c_str(), ""));
        }
        attrubutes.addAttribute(new CAttribute("Status Dev",
            std::to_string(m_nStatusDev).c_str(), ""));
    }
    int CEqStatusStep::getStatus(unsigned int uint)
    {
        if (uint < STATUS_MAX) {
            return m_nStatus[uint];
        }
        return -1;
    }
    int CEqStatusStep::onReadData()
    {
        CStep::onReadData();
        CReadStep::onReadData();
        char szBuffer[64];
        int nRet = m_pCclink->ReadData2(m_station, DeviceType::W,
@@ -56,7 +82,7 @@
    int CEqStatusStep::onComplete()
    {
        CStep::onComplete();
        CReadStep::onComplete();
        LOGI("<CEqStatusStep> onComplete.");
        return 0;
@@ -64,7 +90,7 @@
    int CEqStatusStep::onTimeout()
    {
        CStep::onTimeout();
        CReadStep::onTimeout();
        LOGI("<CEqStatusStep> onTimeout.");
        return 0;
SourceCode/Bond/Servo/CEqStatusStep.h
@@ -1,22 +1,24 @@
#pragma once
#include "CStep.h"
#include "CReadStep.h"
namespace SERVO {
#define UNIT_MAX        6
#define STATUS_MAX        (UNIT_MAX + 1)
    class CEqStatusStep : public CStep
    class CEqStatusStep : public CReadStep
    {
    public:
        CEqStatusStep();
        ~CEqStatusStep();
    public:
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int onReadData();
        virtual int onComplete();
        virtual int onTimeout();
        void setStatusDev(int nDev);
        int getStatus(unsigned int uint);
        std::string& getStatusDescription(unsigned int unid, std::string& strDescription);
    private:
SourceCode/Bond/Servo/CEquipment.cpp
@@ -16,6 +16,7 @@
        m_bAutoRecipeChange = FALSE;
        m_bVCREnable[0] = FALSE;
        m_pCclink = nullptr;
        m_nBaseAlarmId = 0;
        InitializeCriticalSection(&m_criticalSection);
    }
@@ -40,6 +41,16 @@
        m_pCclink = pCcLink;
    }
    void CEquipment::setBaseAlarmId(int nBaseId)
    {
        m_nBaseAlarmId = nBaseId;
    }
    int CEquipment::getBaseAlarmId()
    {
        return m_nBaseAlarmId;
    }
    void CEquipment::getProperties(std::vector<std::pair<std::string, std::string>>& container)
    {
        container.clear();
@@ -47,6 +58,11 @@
        container.push_back(std::make_pair("DeviceName", "ServoMotor"));
        container.push_back(std::make_pair("SerialNumber", "123456789"));
        container.push_back(std::make_pair("Version", "1.0"));
    }
    std::map<unsigned int, CStep*>& CEquipment::getSteps()
    {
        return m_mapStep;
    }
    CStep* CEquipment::getStep(unsigned int addr)
@@ -251,9 +267,16 @@
            bFlag = isBitOn(pszData, size, index);
            pStep = getStep(index);
            if (pStep != nullptr) {
                pStep->onSignal(bFlag);
                ((CReadStep*)pStep)->onReadSignal(bFlag);
            }
        }
        index = 0x350;
        bFlag = isBitOn(pszData, size, index);
        pStep = getStep(index);
        if (pStep != nullptr) {
            ((CWriteStep*)pStep)->onRecvSignal(bFlag);
        }
    }
    BOOL CEquipment::isBitOn(const char* pszData, size_t size, int index)
SourceCode/Bond/Servo/CEquipment.h
@@ -4,6 +4,8 @@
#include "CEqModeStep.h"
#include "CEqStatusStep.h"
#include "CEqAlarmStep.h"
#include "CEqProcessStep.h"
#include "CEqCimModeChangeStep.h"
#include <map>
@@ -46,6 +48,8 @@
        virtual const char* getClassName() = 0;
        virtual void setListener(EquipmentListener listener);
        void setCcLink(CCCLinkIEControl* pCcLink);
        void setBaseAlarmId(int nBaseId);
        int getBaseAlarmId();
        void setID(int nID);
        int getID();
        void setName(const char* pszName);
@@ -61,6 +65,7 @@
        void getProperties(std::vector<std::pair<std::string, std::string>>& container);
        int addStep(unsigned int addr, CStep* pStep);
        CStep* getStep(unsigned int addr);
        std::map<unsigned int, CStep*>& getSteps();
        virtual void init();
        virtual void term();
        virtual void onTimer(UINT nTimerid);
@@ -110,6 +115,7 @@
    private:
        CCCLinkIEControl* m_pCclink;
        std::map<unsigned int, CStep*> m_mapStep;
        int m_nBaseAlarmId;
    };
}
SourceCode/Bond/Servo/CMaster.cpp
@@ -74,7 +74,7 @@
        // åˆå§‹åŒ–添加各子设备
        addEFEM(listener);
        /*
        {
            CBonder* pBonder = new CBonder();
            pBonder->setName("Bonder 1");
@@ -84,7 +84,7 @@
            addEquipment(pBonder);
            LOGE("已添加“Bonder 1”.");
        }
        */
        // å®šæ—¶å™¨
        g_pMaster = this;
@@ -127,6 +127,11 @@
        return 0;
    }
    std::list<CEquipment*>& CMaster::getEquipmentList()
    {
        return m_listEquipment;
    }
    CEquipment* CMaster::getEquipment(int id)
    {
        for (auto item : m_listEquipment) {
@@ -140,6 +145,7 @@
    {
        CEFEM* pEquipment = new CEFEM();
        pEquipment->setID(EQ_ID_EFEM);
        pEquipment->setBaseAlarmId(BASE_ALARM_EFEM);
        pEquipment->setName("EFEM(ROBOT)");
        pEquipment->setDescription("EFEM(ROBOT).");
        pEquipment->setReadBitBlock(0x4000, 0x45ff);
@@ -150,7 +156,7 @@
        // æ·»åŠ  step
        {
            CEqModeStep* pStep = new CEqModeStep();
            pStep->setName("EQMode");
            pStep->setName(STEP_MODE);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x30);
            pStep->setModeDev(0x4a8c);
@@ -160,7 +166,7 @@
        }
        {
            CEqStatusStep* pStep = new CEqStatusStep();
            pStep->setName("EQStatus");
            pStep->setName(STEP_STATUS);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x31);
            pStep->setStatusDev(0x4a68);
@@ -170,7 +176,7 @@
        }
        {
            CEqAlarmStep* pStep = new CEqAlarmStep();
            pStep->setName("EQAlarm1");
            pStep->setName(STEP_ALARM_BLOCK1);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x32);
            pStep->setAlarmDev(0x4c1d);
@@ -180,7 +186,7 @@
        }
        {
            CEqAlarmStep* pStep = new CEqAlarmStep();
            pStep->setName("EQAlarm2");
            pStep->setName(STEP_ALARM_BLOCK2);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x33);
            pStep->setAlarmDev(0x4c4a);
@@ -190,7 +196,7 @@
        }
        {
            CEqAlarmStep* pStep = new CEqAlarmStep();
            pStep->setName("EQAlarm3");
            pStep->setName(STEP_ALARM_BLOCK3);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x34);
            pStep->setAlarmDev(0x4c77);
@@ -200,7 +206,7 @@
        }
        {
            CEqAlarmStep* pStep = new CEqAlarmStep();
            pStep->setName("EQAlarm4");
            pStep->setName(STEP_ALARM_BLOCK4);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x35);
            pStep->setAlarmDev(0x4ca4);
@@ -210,7 +216,7 @@
        }
        {
            CEqAlarmStep* pStep = new CEqAlarmStep();
            pStep->setName("EQAlarm5");
            pStep->setName(STEP_ALARM_BLOCK5);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x36);
            pStep->setAlarmDev(0x4cd1);
@@ -218,6 +224,26 @@
                delete pStep;
            }
        }
        {
            CEqProcessStep* pStep = new CEqProcessStep();
            pStep->setName(STEP_PROCESS);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x37);
            pStep->setProcessDev(0x1864);
            if (pEquipment->addStep(0x367, pStep) != 0) {
                delete pStep;
            }
        }
        {
            CEqCimModeChangeStep* pStep = new CEqCimModeChangeStep();
            pStep->setName(STEP_CIM_MODE_CHANGE);
            pStep->setListener(listener);
            pStep->setWriteSignalDev(0x50);
            pStep->setCimModeDev(0x15);
            if (pEquipment->addStep(0x350, pStep) != 0) {
                delete pStep;
            }
        }
        pEquipment->init();
SourceCode/Bond/Servo/CMaster.h
@@ -28,6 +28,7 @@
        int init();
        int term();
        void onTimer(UINT nTimerid);
        std::list<CEquipment*>& getEquipmentList();
        CEquipment* getEquipment(int id);
    private:
SourceCode/Bond/Servo/CPanelAttributes.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,192 @@
// CPanelAttributes.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "Servo.h"
#include "CPanelAttributes.h"
#include "afxdialogex.h"
#include "common.h"
#include "VerticalLine.h"
// CPanelAttributes å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CPanelAttributes, CDialogEx)
CPanelAttributes::CPanelAttributes(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_PANEL_ATTRIBUTES, pParent)
{
    m_crBkgnd = PANEL_ATTRIBUTES_BACKGROUND_COLOR;
    m_hbrBkgnd = nullptr;
    m_nPanelWidth = 188;
}
CPanelAttributes::~CPanelAttributes()
{
}
void CPanelAttributes::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_MFCPROPERTYGRID1, m_gridCtrl);
}
BEGIN_MESSAGE_MAP(CPanelAttributes, CDialogEx)
    ON_WM_CTLCOLOR()
    ON_WM_DESTROY()
    ON_WM_SIZE()
    ON_NOTIFY(BYVERTICALLINE_MOVEX, IDC_LINE1, &CPanelAttributes::OnVLineMoveX)
    ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CPanelAttributes::OnBnClickedButtonClose)
END_MESSAGE_MAP()
// CPanelAttributes æ¶ˆæ¯å¤„理程序
int CPanelAttributes::getPanelWidth()
{
    return m_nPanelWidth;
}
void CPanelAttributes::loadDataFromStep(SERVO::CStep* pStep)
{
    // å…ˆæ¸…空所有
    m_gridCtrl.RemoveAll();
    // åŠ è½½æ•°æ®
    SetDlgItemText(IDC_LABEL_TITLE, pStep->getName().c_str());
    SERVO::CAttributeVector attrubutes;
    pStep->getAttributeVector(attrubutes);
    unsigned int nSize = attrubutes.size();
    for (unsigned int i = 0; i < nSize; i++) {
        SERVO::CAttribute* pAttribute = attrubutes.getAttribute(i);
        CMFCPropertyGridProperty* pProperty = new CMFCPropertyGridProperty(
            pAttribute->getName().c_str(),
            pAttribute->getValue().c_str(),
            pAttribute->getDescription().c_str());
        pProperty->AllowEdit(TRUE);
        m_gridCtrl.AddProperty(pProperty);
    }
}
BOOL CPanelAttributes::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // å…³é—­æŒ‰é’®
    CString strIcon1;
    strIcon1.Format(_T("%s\\Res\\panel_close_24_b.ico"), theApp.m_strAppDir);
    HICON hIcon1 = (HICON)::LoadImage(AfxGetInstanceHandle(),
        strIcon1, IMAGE_ICON, 24, 24,
        LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
    m_btnClose.SubclassDlgItem(IDC_BUTTON_CLOSE, this);
    m_btnClose.SetIcon(hIcon1, hIcon1, 24);
    m_btnClose.SetFaceColor(m_crBkgnd);
    m_btnClose.SetFrameColor(m_crBkgnd);
    m_btnClose.SetFrameColor(BS_HOVER, RGB(218, 218, 218));
    m_btnClose.SetFrameColor(BS_PRESS, RGB(168, 168, 168));
    CVerticalLine* pLine1 = CVerticalLine::Hook(GetDlgItem(IDC_LINE1)->GetSafeHwnd());
    pLine1->SetBkgndColor(RGB(225, 225, 225));
    pLine1->SetLineColor(RGB(198, 198, 198));
    pLine1->EnableResize();
    // è¯»å–面板宽
    CString strIniFile;
    strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
    m_nPanelWidth = GetPrivateProfileInt(_T("App"), _T("AttributesPanelWidth"),
        int((double)GetSystemMetrics(SM_CXSCREEN) * 0.25), (LPTSTR)(LPCTSTR)strIniFile);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
HBRUSH CPanelAttributes::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    if (nCtlColor == CTLCOLOR_STATIC) {
        pDC->SetBkColor(m_crBkgnd);
        pDC->SetTextColor(RGB(0, 0, 0));
    }
    if (m_hbrBkgnd == nullptr) {
        m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
    }
    return m_hbrBkgnd;
}
void CPanelAttributes::OnDestroy()
{
    CDialogEx::OnDestroy();
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
}
void CPanelAttributes::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    if (GetDlgItem(IDC_LINE1) == nullptr) return;
    CWnd* pItem;
    CRect rcClient, rcItem;
    GetClientRect(&rcClient);
    pItem = GetDlgItem(IDC_LINE1);
    pItem->MoveWindow(rcClient.right - 3, 0, 3, rcClient.Height());
    int x2 = rcClient.right - 6;
    int y = 3;
    pItem = GetDlgItem(IDC_BUTTON_CLOSE);
    pItem->GetWindowRect(&rcItem);
    pItem->MoveWindow(x2 - rcItem.Width(), y, rcItem.Width(), rcItem.Height());
    x2 -= rcItem.Width();
    x2 -= 3;
    pItem = GetDlgItem(IDC_LABEL_TITLE);
    pItem->GetWindowRect(&rcItem);
    pItem->MoveWindow(5, y, x2 - 5, rcItem.Height());
    y += rcItem.Height();
    y += 8;
    GetDlgItem(IDC_MFCPROPERTYGRID1)->MoveWindow(5, y, rcClient.Width() - 13, rcClient.Height() - 3 - y);
}
#define ATTRIBUTES_PANEL_MIN_WIDTH        88
#define ATTRIBUTES_PANEL_MAX_WIDTH        588
void CPanelAttributes::OnVLineMoveX(NMHDR* nmhdr, LRESULT* result)
{
    BYVERTICALLINE_NMHDR* pNmhdrex = (BYVERTICALLINE_NMHDR*)nmhdr;
    int x = pNmhdrex->dwData;
    m_nPanelWidth += x;
    m_nPanelWidth = max(m_nPanelWidth, ATTRIBUTES_PANEL_MIN_WIDTH);
    m_nPanelWidth = min(m_nPanelWidth, ATTRIBUTES_PANEL_MAX_WIDTH);
    GetParent()->SendMessage(ID_MSG_PANEL_RESIZE, m_nPanelWidth, 0);
    CString strIniFile, strValue;
    strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
    strValue.Format(_T("%d"), m_nPanelWidth);
    WritePrivateProfileString(_T("App"), _T("AttributesPanelWidth"),
        (LPTSTR)(LPCTSTR)strValue, (LPTSTR)(LPCTSTR)strIniFile);
    OnSize(0, 0, 0);
    *result = 0;
}
void CPanelAttributes::OnBnClickedButtonClose()
{
    ShowWindow(SW_HIDE);
    GetParent()->SendMessage(ID_MSG_PANEL_RESIZE, m_nPanelWidth, 0);
}
SourceCode/Bond/Servo/CPanelAttributes.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
#pragma once
#include "BlButton.h"
// CPanelAttributes å¯¹è¯æ¡†
class CPanelAttributes : public CDialogEx
{
    DECLARE_DYNAMIC(CPanelAttributes)
public:
    CPanelAttributes(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CPanelAttributes();
    int getPanelWidth();
    void loadDataFromStep(SERVO::CStep* pStep);
private:
    COLORREF m_crBkgnd;
    HBRUSH m_hbrBkgnd;
    int m_nPanelWidth;
    CMFCPropertyGridCtrl m_gridCtrl;
    CBlButton m_btnClose;
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_PANEL_ATTRIBUTES };
#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 OnDestroy();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnVLineMoveX(NMHDR* nmhdr, LRESULT* result);
    afx_msg void OnBnClickedButtonClose();
};
SourceCode/Bond/Servo/CPanelEquipment.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,175 @@
// CPanelEquipment.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "Servo.h"
#include "CPanelEquipment.h"
#include "afxdialogex.h"
#include "Common.h"
#include "VerticalLine.h"
// CPanelEquipment å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CPanelEquipment, CDialogEx)
CPanelEquipment::CPanelEquipment(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_PANEL_EQUIPMENT, pParent)
{
    m_crBkgnd = PANEL_EQUIPMENT_BACKGROUND_COLOR;
    m_hbrBkgnd = nullptr;
    m_nPanelWidth = 188;
    m_pEquipment = nullptr;
}
CPanelEquipment::~CPanelEquipment()
{
}
void CPanelEquipment::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CPanelEquipment, CDialogEx)
    ON_WM_CTLCOLOR()
    ON_WM_DESTROY()
    ON_WM_SIZE()
    ON_NOTIFY(BYVERTICALLINE_MOVEX, IDC_LINE1, &CPanelEquipment::OnVLineMoveX)
    ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CPanelEquipment::OnBnClickedButtonClose)
END_MESSAGE_MAP()
// CPanelEquipment æ¶ˆæ¯å¤„理程序
int CPanelEquipment::getPanelWidth()
{
    return m_nPanelWidth;
}
void CPanelEquipment::SetEquipment(SERVO::CEquipment* pEquipment)
{
    m_pEquipment = pEquipment;
    ASSERT(m_pEquipment);
    if (::IsWindow(m_hWnd)) {
        SetDlgItemText(IDC_LABEL_TITLE, m_pEquipment->getName().c_str());
    }
}
BOOL CPanelEquipment::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // å…³é—­æŒ‰é’®
    CString strIcon1;
    strIcon1.Format(_T("%s\\Res\\panel_close_24_b.ico"), theApp.m_strAppDir);
    HICON hIcon1 = (HICON)::LoadImage(AfxGetInstanceHandle(),
        strIcon1, IMAGE_ICON, 24, 24,
        LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
    m_btnClose.SubclassDlgItem(IDC_BUTTON_CLOSE, this);
    m_btnClose.SetIcon(hIcon1, hIcon1, 24);
    m_btnClose.SetFaceColor(m_crBkgnd);
    m_btnClose.SetFrameColor(m_crBkgnd);
    m_btnClose.SetFrameColor(BS_HOVER, RGB(218, 218, 218));
    m_btnClose.SetFrameColor(BS_PRESS, RGB(168, 168, 168));
    CVerticalLine* pLine1 = CVerticalLine::Hook(GetDlgItem(IDC_LINE1)->GetSafeHwnd());
    pLine1->SetBkgndColor(RGB(225, 225, 225));
    pLine1->SetLineColor(RGB(198, 198, 198));
    pLine1->EnableResize();
    // è¯»å–面板宽
    CString strIniFile;
    strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
    m_nPanelWidth = GetPrivateProfileInt(_T("App"), _T("EquipmentPanelWidth"),
        int((double)GetSystemMetrics(SM_CXSCREEN) * 0.25), (LPTSTR)(LPCTSTR)strIniFile);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
HBRUSH CPanelEquipment::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    if (nCtlColor == CTLCOLOR_STATIC) {
        pDC->SetBkColor(m_crBkgnd);
        pDC->SetTextColor(RGB(0, 0, 0));
    }
    if (m_hbrBkgnd == nullptr) {
        m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
    }
    return m_hbrBkgnd;
}
void CPanelEquipment::OnDestroy()
{
    CDialogEx::OnDestroy();
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
}
void CPanelEquipment::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    if (GetDlgItem(IDC_LINE1) == nullptr) return;
    CWnd* pItem;
    CRect rcClient, rcItem;
    GetClientRect(&rcClient);
    pItem = GetDlgItem(IDC_LINE1);
    pItem->MoveWindow(rcClient.right - 3, 0, 3, rcClient.Height());
    int x2 = rcClient.right - 6;
    int y = 3;
    pItem = GetDlgItem(IDC_BUTTON_CLOSE);
    pItem->GetWindowRect(&rcItem);
    pItem->MoveWindow(x2 - rcItem.Width(), y, rcItem.Width(), rcItem.Height());
    x2 -= rcItem.Width();
    x2 -= 3;
    pItem = GetDlgItem(IDC_LABEL_TITLE);
    pItem->GetWindowRect(&rcItem);
    pItem->MoveWindow(5, y, x2 - 5, rcItem.Height());
    y += rcItem.Height();
    y += 8;
}
#define EQUIPMENT_PANEL_MIN_WIDTH        88
#define EQUIPMENT_PANEL_MAX_WIDTH        588
void CPanelEquipment::OnVLineMoveX(NMHDR* nmhdr, LRESULT* result)
{
    BYVERTICALLINE_NMHDR* pNmhdrex = (BYVERTICALLINE_NMHDR*)nmhdr;
    int x = pNmhdrex->dwData;
    m_nPanelWidth += x;
    m_nPanelWidth = max(m_nPanelWidth, EQUIPMENT_PANEL_MIN_WIDTH);
    m_nPanelWidth = min(m_nPanelWidth, EQUIPMENT_PANEL_MAX_WIDTH);
    GetParent()->SendMessage(ID_MSG_PANEL_RESIZE, m_nPanelWidth, 0);
    CString strIniFile, strValue;
    strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
    strValue.Format(_T("%d"), m_nPanelWidth);
    WritePrivateProfileString(_T("App"), _T("EquipmentPanelWidth"),
        (LPTSTR)(LPCTSTR)strValue, (LPTSTR)(LPCTSTR)strIniFile);
    OnSize(0, 0, 0);
    *result = 0;
}
void CPanelEquipment::OnBnClickedButtonClose()
{
    ShowWindow(SW_HIDE);
    GetParent()->SendMessage(ID_MSG_PANEL_RESIZE, m_nPanelWidth, 0);
}
SourceCode/Bond/Servo/CPanelEquipment.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
#pragma once
#include "BlButton.h"
#include "CEquipment.h"
// CPanelEquipment å¯¹è¯æ¡†
class CPanelEquipment : public CDialogEx
{
    DECLARE_DYNAMIC(CPanelEquipment)
public:
    CPanelEquipment(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CPanelEquipment();
    int getPanelWidth();
    void SetEquipment(SERVO::CEquipment* pEquipment);
private:
    COLORREF m_crBkgnd;
    HBRUSH m_hbrBkgnd;
    int m_nPanelWidth;
    CBlButton m_btnClose;
    SERVO::CEquipment* m_pEquipment;
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_PANEL_EQUIPMENT };
#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 OnDestroy();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnVLineMoveX(NMHDR* nmhdr, LRESULT* result);
    afx_msg void OnBnClickedButtonClose();
};
SourceCode/Bond/Servo/CPanelMaster.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,207 @@
// CPanelMaster.cpp: å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "Servo.h"
#include "CPanelMaster.h"
#include "afxdialogex.h"
#include "Common.h"
#include "VerticalLine.h"
// CPanelMaster å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CPanelMaster, CDialogEx)
CPanelMaster::CPanelMaster(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_PANEL_MASTER, pParent)
{
    m_crBkgnd = PANEL_MASTER_BACKGROUND_COLOR;
    m_hbrBkgnd = nullptr;
    m_nPanelWidth = 388;
}
CPanelMaster::~CPanelMaster()
{
}
void CPanelMaster::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_TREE1, m_treeCtrl);
}
BEGIN_MESSAGE_MAP(CPanelMaster, CDialogEx)
    ON_WM_CTLCOLOR()
    ON_WM_DESTROY()
    ON_WM_SIZE()
    ON_NOTIFY(BYVERTICALLINE_MOVEX, IDC_LINE1, &CPanelMaster::OnVLineMoveX)
    ON_WM_TIMER()
    ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, &CPanelMaster::OnTvnSelchangedTree1)
END_MESSAGE_MAP()
// CPanelMaster æ¶ˆæ¯å¤„理程序
int CPanelMaster::getPanelWidth()
{
    return m_nPanelWidth;
}
BOOL CPanelMaster::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    CVerticalLine* pLine1 = CVerticalLine::Hook(GetDlgItem(IDC_LINE1)->GetSafeHwnd());
    pLine1->SetBkgndColor(RGB(225, 225, 225));
    pLine1->SetLineColor(RGB(198, 198, 198));
    pLine1->EnableResize();
    // è¯»å–面板宽
    CString strIniFile;
    strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
    m_nPanelWidth = GetPrivateProfileInt(_T("App"), _T("MasterPanelWidth"),
        int((double)GetSystemMetrics(SM_CXSCREEN) * 0.25), (LPTSTR)(LPCTSTR)strIniFile);
    // treectrl
    m_treeCtrl.SetBkColor(PANEL_MASTER_BACKGROUND_COLOR);
    m_treeCtrl.SetItemHeight(28);
    SetTimer(1, 2000, nullptr);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
HBRUSH CPanelMaster::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    if (nCtlColor == CTLCOLOR_STATIC) {
        pDC->SetBkColor(m_crBkgnd);
        pDC->SetTextColor(RGB(0, 0, 0));
    }
    if (m_hbrBkgnd == nullptr) {
        m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
    }
    return m_hbrBkgnd;
}
void CPanelMaster::OnDestroy()
{
    CDialogEx::OnDestroy();
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
}
void CPanelMaster::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    if (GetDlgItem(IDC_LINE1) == nullptr) return;
    CWnd* pItem;
    CRect rcClient;
    GetClientRect(&rcClient);
    pItem = GetDlgItem(IDC_LINE1);
    pItem->MoveWindow(rcClient.right - 3, 0, 3, rcClient.Height());
    m_treeCtrl.MoveWindow(5, 5, rcClient.Width() - 13, rcClient.Height() - 10);
}
#define MASTER_PANEL_MIN_WIDTH        88
#define MASTER_PANEL_MAX_WIDTH        588
void CPanelMaster::OnVLineMoveX(NMHDR* nmhdr, LRESULT* result)
{
    BYVERTICALLINE_NMHDR* pNmhdrex = (BYVERTICALLINE_NMHDR*)nmhdr;
    int x = pNmhdrex->dwData;
    m_nPanelWidth += x;
    m_nPanelWidth = max(m_nPanelWidth, MASTER_PANEL_MIN_WIDTH);
    m_nPanelWidth = min(m_nPanelWidth, MASTER_PANEL_MAX_WIDTH);
    GetParent()->SendMessage(ID_MSG_PANEL_RESIZE, m_nPanelWidth, 0);
    CString strIniFile, strValue;
    strIniFile.Format(_T("%s\\%s.ini"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir, (LPTSTR)(LPCTSTR)theApp.m_strAppFile);
    strValue.Format(_T("%d"), m_nPanelWidth);
    WritePrivateProfileString(_T("App"), _T("MasterPanelWidth"),
        (LPTSTR)(LPCTSTR)strValue, (LPTSTR)(LPCTSTR)strIniFile);
    OnSize(0, 0, 0);
    * result = 0;
}
void CPanelMaster::OnTimer(UINT_PTR nIDEvent)
{
    if (1 == nIDEvent) {
        KillTimer(1);
        loadEquipmentList();
    }
    CDialogEx::OnTimer(nIDEvent);
}
void CPanelMaster::loadEquipmentList()
{
    HTREEITEM hItemMaster = m_treeCtrl.InsertItem("Master");
    std::list<SERVO::CEquipment*>& eqs = theApp.m_model.m_master.getEquipmentList();
    for (auto item : eqs) {
        HTREEITEM hItemEq = m_treeCtrl.InsertItem(item->getName().c_str(), hItemMaster);
        m_treeCtrl.SetItemData(hItemEq, (DWORD_PTR)item);
        loadSteps(item, hItemEq);
        m_treeCtrl.Expand(hItemEq, TVE_EXPAND);
    }
    m_treeCtrl.Expand(hItemMaster, TVE_EXPAND);
}
void CPanelMaster::loadSteps(SERVO::CEquipment* pEquipment, HTREEITEM hItemEq)
{
    std::map<unsigned int, SERVO::CStep*>& steps = pEquipment->getSteps();
    for (auto item : steps) {
        HTREEITEM hStep = m_treeCtrl.InsertItem(item.second->getName().c_str(), hItemEq);
        m_treeCtrl.SetItemData(hStep, (DWORD_PTR)item.second);
    }
}
void CPanelMaster::OnTvnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    HTREEITEM hItem = pNMTreeView->itemNew.hItem;
    int nLevel = GetTreeItemLevel(hItem);
    if (nLevel == 2) {
        SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)m_treeCtrl.GetItemData(hItem);
        theApp.m_model.notifyPtr(RX_CODE_SELECT_EQUIPMENT, pEquipment);
    }
    else if (nLevel == 3) {
        SERVO::CStep* pStep = (SERVO::CStep*)m_treeCtrl.GetItemData(hItem);
        theApp.m_model.notifyPtr(RX_CODE_SELECT_STEP, pStep);
    }
    *pResult = 0;
}
int CPanelMaster::GetTreeItemLevel(HTREEITEM hItem)
{
    int nLevel = 0;
    HTREEITEM hTemp = hItem;
    while (hTemp != nullptr) {
        hTemp = m_treeCtrl.GetParentItem(hTemp);
        nLevel++;
    }
    return nLevel;
}
SourceCode/Bond/Servo/CPanelMaster.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
#pragma once
#include "ApredTreeCtrl2.h"
// CPanelMaster å¯¹è¯æ¡†
class CPanelMaster : public CDialogEx
{
    DECLARE_DYNAMIC(CPanelMaster)
public:
    CPanelMaster(CWnd* pParent = nullptr);   // æ ‡å‡†æž„造函数
    virtual ~CPanelMaster();
    int getPanelWidth();
    void loadEquipmentList();
    void loadSteps(SERVO::CEquipment* pEquipment, HTREEITEM hItemEq);
private:
    int GetTreeItemLevel(HTREEITEM hItem);
private:
    COLORREF m_crBkgnd;
    HBRUSH m_hbrBkgnd;
    CApredTreeCtrl2 m_treeCtrl;
    int m_nPanelWidth;
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_PANEL_MASTER };
#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 OnDestroy();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnVLineMoveX(NMHDR* nmhdr, LRESULT* result);
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg void OnTvnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult);
};
SourceCode/Bond/Servo/CReadStep.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,187 @@
#include "stdafx.h"
#include "CReadStep.h"
#include "Common.h"
namespace SERVO {
#define TIMEOUT            15
    unsigned __stdcall ReadStepWorkThreadFunction(LPVOID lpParam)
    {
        CReadStep* pStep = (CReadStep*)lpParam;
        return pStep->WorkingProc();
    }
    CReadStep::CReadStep() : CStep()
    {
        m_nWordThreadAddr = 0;
        m_hWorkStop = nullptr;
        m_hWorkThreadHandle = nullptr;
        m_hReadSignalOn = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_hReadSignalOff = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_nCurStep = 0;
    }
    CReadStep::~CReadStep()
    {
        ASSERT(m_hReadSignalOn);
        CloseHandle(m_hReadSignalOn);
        m_hReadSignalOn = nullptr;
        ASSERT(m_hReadSignalOff);
        CloseHandle(m_hReadSignalOff);
        m_hReadSignalOff = nullptr;
    }
    void CReadStep::setWriteSignalDev(int dev)
    {
        m_nWriteSignalDev = dev;
    }
    void CReadStep::onReadSignal(BOOL bSignal)
    {
        Lock();
        if (m_nCurStep == 0 && bSignal) {
            SetEvent(m_hReadSignalOn);
        }
        else if (m_nCurStep == 3 && !bSignal) {
            SetEvent(m_hReadSignalOff);
        }
        Unlock();
    }
    int CReadStep::onReadData()
    {
        return 0;
    }
    unsigned CReadStep::WorkingProc()
    {
        HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        BOOL bReadOk = FALSE;
        int nBeginAddr = 0x0;
        while (1) {
        RESET:
            resetStep();
            // å¾…退出信号或时间到
            HANDLE hEvents[] = { m_hWorkStop, m_hReadSignalOn };
            int nRet = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
            if (nRet == WAIT_OBJECT_0) {
                ResetEvent(m_hWorkStop);
                break;
            }
            else if (nRet == WAIT_OBJECT_0 + 1) {
                ResetEvent(m_hReadSignalOn);
                // 1.读取数据
                nextStep();
                ASSERT(m_pCclink);
                if (0 == onReadData()) {
                    if (m_listener.onEvent != nullptr) {
                        m_listener.onEvent(this, STEP_EVENT_READDATA, nullptr);
                    }
                }
                // 2.给对方写ON
                nextStep();
                m_pCclink->SetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                // 3.等待对方OFF
                nextStep();
                int nStep3Ret = ::WaitForSingleObject(m_hReadSignalOff, TIMEOUT * 1000);
                if (nStep3Ret == WAIT_TIMEOUT) {
                    m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                    onTimeout();
                    goto RESET;
                }
                ResetEvent(m_hReadSignalOff);
                // 4.给对方写OFF
                nextStep();
                m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                // 6.完成
                nextStep();
                if (0 == onComplete()) {
                    if (m_listener.onEvent != nullptr) {
                        m_listener.onEvent(this, STEP_EVENT_COMPLETE, nullptr);
                    }
                }
            }
        }
        if (hEvent != nullptr) {
            CloseHandle(hEvent);
        }
        // _endthreadex(0);
        TRACE("CStep::WorkingProc çº¿ç¨‹é€€å‡º\n");
        return 0;
    }
    void CReadStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        CStep::getAttributeVector(attrubutes);
        attrubutes.addAttribute(new CAttribute("Current Step",
            std::to_string(m_nCurStep).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Signal Dev",
            std::to_string(m_nWriteSignalDev).c_str(), ""));
    }
    void CReadStep::init()
    {
        CStep::init();
        if (m_hWorkStop != nullptr) return;
        m_hWorkStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_hWorkThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::ReadStepWorkThreadFunction, this,
            0, &m_nWordThreadAddr);
    }
    void CReadStep::term()
    {
        CStep::term();
        ASSERT(m_hWorkStop);
        SetEvent(m_hWorkStop);
        if (m_hWorkThreadHandle != NULL) {
            WaitForSingleObject(m_hWorkThreadHandle, INFINITE);
            CloseHandle(m_hWorkThreadHandle);
            m_hWorkThreadHandle = NULL;
        }
        CloseHandle(m_hWorkStop);
        m_hWorkStop = NULL;
    }
    void CReadStep::resetStep()
    {
        Lock();
        m_nCurStep = 0;
        Unlock();
    }
    void CReadStep::nextStep()
    {
        Lock();
        m_nCurStep++;
        Unlock();
    }
    int CReadStep::onComplete()
    {
        return 0;
    }
    int CReadStep::onTimeout()
    {
        return 0;
    }
}
SourceCode/Bond/Servo/CReadStep.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
#pragma once
#include "CStep.h"
namespace SERVO {
    class CReadStep : public CStep
    {
    public:
        CReadStep();
        virtual ~CReadStep();
    public:
        unsigned WorkingProc();
        virtual void setWriteSignalDev(int dev);
        virtual void onReadSignal(BOOL bSignal);
        virtual int onReadData();
        virtual void init();
        virtual void term();
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int onComplete();
        virtual int onTimeout();
        inline void nextStep();
        inline void resetStep();
    protected:
        HANDLE m_hWorkThreadHandle;
        unsigned m_nWordThreadAddr;
        HANDLE m_hWorkStop;
        HANDLE m_hReadSignalOn;
        HANDLE m_hReadSignalOff;
        int m_nCurStep;
        int m_nWriteSignalDev;            // å¯¹æ–¹BIT地址
    };
}
SourceCode/Bond/Servo/CStep.cpp
@@ -3,38 +3,16 @@
namespace SERVO {
#define TIMEOUT            15
    unsigned __stdcall StepWorkThreadFunction(LPVOID lpParam)
    {
        CStep* pStep = (CStep*)lpParam;
        return pStep->WorkingProc();
    }
    CStep::CStep()
    {
        m_listener = {nullptr};
        m_nWordThreadAddr = 0;
        m_hWorkStop = nullptr;
        m_hWorkThreadHandle = nullptr;
        m_hSignalOn = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_hSignalOff = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_nCurStep = 0;
        m_pCclink = nullptr;
        m_nWriteSignalDev = 0;
        InitializeCriticalSection(&m_criticalSection);
    }
    CStep::~CStep()
    {
        ASSERT(m_hSignalOn);
        CloseHandle(m_hSignalOn);
        m_hSignalOn = nullptr;
        ASSERT(m_hSignalOff);
        CloseHandle(m_hSignalOff);
        m_hSignalOff = nullptr;
        DeleteCriticalSection(&m_criticalSection);
    }
@@ -68,142 +46,36 @@
        return m_strName;
    }
    void CStep::setWriteSignalDev(int dev)
    void CStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        m_nWriteSignalDev = dev;
        attrubutes.clear();
        attrubutes.addAttribute(new CAttribute("Network",
            std::to_string(m_station.nNetNo).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Station",
            std::to_string(m_station.nStNo).c_str(), ""));
    }
    void CStep::init()
    {
        if (m_hWorkStop != nullptr) return;
        m_hWorkStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_hWorkThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::StepWorkThreadFunction, this,
            0, &m_nWordThreadAddr);
    }
    void CStep::term()
    {
        ASSERT(m_hWorkStop);
        SetEvent(m_hWorkStop);
        if (m_hWorkThreadHandle != NULL) {
            WaitForSingleObject(m_hWorkThreadHandle, INFINITE);
            CloseHandle(m_hWorkThreadHandle);
            m_hWorkThreadHandle = NULL;
    }
    void CStep::convertString(const char* pszBuffer, int size, std::string& strOut)
    {
        strOut.clear();
        int nLength = 0;
        for (int i = 0; i < size; i++) {
            if (pszBuffer[i] == '\0') break;
            nLength++;
        }
        CloseHandle(m_hWorkStop);
        m_hWorkStop = NULL;
    }
    unsigned CStep::WorkingProc()
    {
        HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        BOOL bReadOk = FALSE;
        int nBeginAddr = 0x0;
        while (1) {
RESET:
            resetStep();
            // å¾…退出信号或时间到
            HANDLE hEvents[] = { m_hWorkStop, m_hSignalOn };
            int nRet = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
            if (nRet == WAIT_OBJECT_0) {
                ResetEvent(m_hWorkStop);
                break;
            }
            else if (nRet == WAIT_OBJECT_0 + 1) {
                ResetEvent(m_hSignalOn);
                // 1.读取数据
                nextStep();
                ASSERT(m_pCclink);
                if (0 == onReadData()) {
                    if (m_listener.onEvent != nullptr) {
                        m_listener.onEvent(this, STEP_EVENT_READDATA, nullptr);
                    }
                }
                // 2.给对方写ON
                nextStep();
                m_pCclink->SetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                // 3.等待对方OFF
                nextStep();
                int nStep3Ret = ::WaitForSingleObject(m_hSignalOff, TIMEOUT * 1000);
                if (nStep3Ret == WAIT_TIMEOUT) {
                    m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                    onTimeout();
                    goto RESET;
                }
                ResetEvent(m_hSignalOff);
                // 4.给对方写OFF
                nextStep();
                m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                // 6.完成
                nextStep();
                if (0 == onComplete()) {
                    if (m_listener.onEvent != nullptr) {
                        m_listener.onEvent(this, STEP_EVENT_COMPLETE, nullptr);
                    }
                }
            }
        if (nLength > 0) {
            strOut = std::string(pszBuffer, nLength);
        }
        if (hEvent != nullptr) {
            CloseHandle(hEvent);
        }
        // _endthreadex(0);
        TRACE("CStep::WorkingProc çº¿ç¨‹é€€å‡º\n");
        return 0;
    }
    void CStep::onSignal(BOOL bSignal)
    {
        Lock();
        if (m_nCurStep == 0 && bSignal) {
            SetEvent(m_hSignalOn);
        }
        else if (m_nCurStep == 3 && !bSignal) {
            SetEvent(m_hSignalOff);
        }
        Unlock();
    }
    int CStep::onReadData()
    {
        return 0;
    }
    int CStep::onComplete()
    {
        return 0;
    }
    int CStep::onTimeout()
    {
        return 0;
    }
    void CStep::resetStep()
    {
        Lock();
        m_nCurStep = 0;
        Unlock();
    }
    void CStep::nextStep()
    {
        Lock();
        m_nCurStep++;
        Unlock();
    }
}
SourceCode/Bond/Servo/CStep.h
@@ -1,5 +1,6 @@
#pragma once
#include "CCLinkIEControl.h"
#include "CAttributeVector.h"
namespace SERVO {
@@ -20,26 +21,21 @@
        virtual ~CStep();
    public:
        unsigned WorkingProc();
        void setListener(StepListener listener);
        void setCcLink(CCCLinkIEControl* pCcLink);
        void setEquipment(CEquipment* pEquipment);
        CEquipment* getEquipment();
        void setName(const char* pszName);
        std::string& getName();
        virtual void setWriteSignalDev(int dev);
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual void init();
        virtual void CStep::term();
        virtual void onSignal(BOOL bSignal);
        virtual int onReadData();
        virtual int onComplete();
        virtual int onTimeout();
        virtual void term();
    protected:
        inline void Lock() { EnterCriticalSection(&m_criticalSection); }
        inline void Unlock() { LeaveCriticalSection(&m_criticalSection); }
        inline void nextStep();
        inline void resetStep();
        void convertString(const char* pszBuffer, int size, std::string& strOut);
    protected:
        StepListener m_listener;
@@ -48,14 +44,6 @@
        CEquipment* m_pEquipment;
        CCCLinkIEControl* m_pCclink;
        CRITICAL_SECTION m_criticalSection;
        std::string strName;
        HANDLE m_hWorkThreadHandle;
        unsigned m_nWordThreadAddr;
        HANDLE m_hWorkStop;
        HANDLE m_hSignalOn;
        HANDLE m_hSignalOff;
        int m_nCurStep;
        int m_nWriteSignalDev;            // å¯¹æ–¹BIT地址
    };
}
SourceCode/Bond/Servo/CWriteStep.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,197 @@
#include "stdafx.h"
#include "CWriteStep.h"
#include "Common.h"
namespace SERVO {
#define TIMEOUT            15
    unsigned __stdcall WriteStepWorkThreadFunction(LPVOID lpParam)
    {
        CWriteStep* pStep = (CWriteStep*)lpParam;
        return pStep->WorkingProc();
    }
    CWriteStep::CWriteStep() : CStep()
    {
        m_nWordThreadAddr = 0;
        m_hWorkStop = nullptr;
        m_hWorkThreadHandle = nullptr;
        m_nCurStep = 0;
        m_nWriteSignalDev = 0;
        m_nWriteDataSize = 0;
        m_nWriteDevNo = 0;
        m_hWriteSignalOn = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_hRecvSignalOn = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    }
    CWriteStep::~CWriteStep()
    {
        ASSERT(m_hWriteSignalOn);
        CloseHandle(m_hWriteSignalOn);
        m_hWriteSignalOn = nullptr;
        ASSERT(m_hRecvSignalOn);
        CloseHandle(m_hRecvSignalOn);
        m_hRecvSignalOn = nullptr;
    }
    int CWriteStep::writeData(short devno, const char* pszData, int size)
    {
        if (size > 1024) return -1;
        if (m_nCurStep != 0) return -2;
        memcpy(m_szBuffer, pszData, size);
        m_nWriteDataSize = size;
        m_nWriteDevNo = devno;
        SetEvent(m_hWriteSignalOn);
        return 0;
    }
    void CWriteStep::setWriteSignalDev(int dev)
    {
        m_nWriteSignalDev = dev;
    }
    void CWriteStep::onRecvSignal(BOOL bSignal)
    {
        Lock();
        if (m_nCurStep == 3 && bSignal) {
            SetEvent(m_hRecvSignalOn);
        }
        Unlock();
    }
    unsigned CWriteStep::WorkingProc()
    {
        HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        BOOL bReadOk = FALSE;
        int nBeginAddr = 0x0;
        while (1) {
        RESET:
            resetStep();
            // å¾…退出信号或时间到
            HANDLE hEvents[] = { m_hWorkStop, m_hWriteSignalOn };
            int nRet = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
            if (nRet == WAIT_OBJECT_0) {
                ResetEvent(m_hWorkStop);
                break;
            }
            else if (nRet == WAIT_OBJECT_0 + 1) {
                ResetEvent(m_hWriteSignalOn);
                // 1.写数据
                nextStep();
                ASSERT(m_pCclink);
                int nRet = m_pCclink->WriteData(m_station, (short)DeviceType::W,
                    m_nWriteDevNo, m_nWriteDataSize, (short*)m_szBuffer);
                if (0 != nRet) {
                    onTimeout();
                    goto RESET;
                }
                // 2.给对方写ON
                nextStep();
                m_pCclink->SetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                // 3.等待对方ON
                nextStep();
                int nStep3Ret = ::WaitForSingleObject(m_hRecvSignalOn, TIMEOUT * 1000);
                if (nStep3Ret == WAIT_TIMEOUT) {
                    m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                    onTimeout();
                    goto RESET;
                }
                ResetEvent(m_hRecvSignalOn);
                // 4.дOFF
                nextStep();
                m_pCclink->ResetBitDevice(m_station, DeviceType::B, m_nWriteSignalDev);
                // 6.完成
                nextStep();
                if (0 == onComplete()) {
                    if (m_listener.onEvent != nullptr) {
                        m_listener.onEvent(this, STEP_EVENT_COMPLETE, nullptr);
                    }
                }
            }
        }
        if (hEvent != nullptr) {
            CloseHandle(hEvent);
        }
        // _endthreadex(0);
        TRACE("CStep::WorkingProc çº¿ç¨‹é€€å‡º\n");
        return 0;
    }
    void CWriteStep::getAttributeVector(CAttributeVector& attrubutes)
    {
        CStep::getAttributeVector(attrubutes);
        attrubutes.addAttribute(new CAttribute("Current Step",
            std::to_string(m_nCurStep).c_str(), ""));
        attrubutes.addAttribute(new CAttribute("Signal Dev",
            std::to_string(m_nWriteSignalDev).c_str(), ""));
    }
    void CWriteStep::init()
    {
        CStep::init();
        if (m_hWorkStop != nullptr) return;
        m_hWorkStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_hWorkThreadHandle = (HANDLE)_beginthreadex(NULL, 0, SERVO::WriteStepWorkThreadFunction, this,
            0, &m_nWordThreadAddr);
    }
    void CWriteStep::term()
    {
        CStep::term();
        ASSERT(m_hWorkStop);
        SetEvent(m_hWorkStop);
        if (m_hWorkThreadHandle != NULL) {
            WaitForSingleObject(m_hWorkThreadHandle, INFINITE);
            CloseHandle(m_hWorkThreadHandle);
            m_hWorkThreadHandle = NULL;
        }
        CloseHandle(m_hWorkStop);
        m_hWorkStop = NULL;
    }
    void CWriteStep::resetStep()
    {
        Lock();
        m_nCurStep = 0;
        Unlock();
    }
    void CWriteStep::nextStep()
    {
        Lock();
        m_nCurStep++;
        Unlock();
    }
    int CWriteStep::onComplete()
    {
        return 0;
    }
    int CWriteStep::onTimeout()
    {
        return 0;
    }
}
SourceCode/Bond/Servo/CWriteStep.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
#pragma once
#include "CStep.h"
namespace SERVO {
    class CWriteStep : public CStep
    {
    public:
        CWriteStep();
        virtual ~CWriteStep();
    public:
        unsigned WorkingProc();
        virtual void setWriteSignalDev(int dev);
        virtual void onRecvSignal(BOOL bSignal);
        int writeData(short devno, const char* pszData, int size);
        virtual void init();
        virtual void term();
        virtual void getAttributeVector(CAttributeVector& attrubutes);
        virtual int onComplete();
        virtual int onTimeout();
        inline void nextStep();
        inline void resetStep();
    protected:
        HANDLE m_hWorkThreadHandle;
        unsigned m_nWordThreadAddr;
        HANDLE m_hWorkStop;
        HANDLE m_hWriteSignalOn;
        HANDLE m_hRecvSignalOn;
        int m_nCurStep;
        int m_nWriteSignalDev;            // å¯¹æ–¹BIT地址
        char m_szBuffer[1024];
        int m_nWriteDataSize;
        int m_nWriteDevNo;
    };
}
SourceCode/Bond/Servo/Common.h
@@ -9,14 +9,19 @@
#define RX_HSMS_TERMINAL_TEXT            1003
#define RX_CODE_EQ_ALIVE                1004
#define RX_CODE_STEP_EVENT_READDATA        1005
#define RX_CODE_SELECT_EQUIPMENT        1006
#define RX_CODE_SELECT_STEP                1007
/* Channel Name */
#define MC_CHANNEL1_NAME        "McChannel1"
/* é¢œè‰² */
#define APPDLG_BACKGROUND_COLOR            RGB(255, 255, 255)
#define LOGDLG_BACKGROUND_COLOR            RGB(255, 255, 255)
#define APPDLG_BACKGROUND_COLOR                RGB(255, 255, 255)
#define LOGDLG_BACKGROUND_COLOR                RGB(255, 255, 255)
#define PANEL_MASTER_BACKGROUND_COLOR        RGB(255, 255, 255)
#define PANEL_ATTRIBUTES_BACKGROUND_COLOR    RGB(255, 255, 255)
#define PANEL_EQUIPMENT_BACKGROUND_COLOR    RGB(255, 255, 255)
/* LOG BTN */
@@ -38,4 +43,32 @@
/* Equipment ID */
#define EQ_ID_EFEM            1
#define EQ_ID_Bonder1        2
#define EQ_ID_Bonder2        3
#define EQ_ID_Bonder2        3
/* step name */
#define STEP_MODE                _T("EQMode")
#define STEP_STATUS                _T("EQStatus")
#define STEP_ALARM_START        _T("EQAlarm")
#define STEP_ALARM_BLOCK1        _T("EQAlarm1")
#define STEP_ALARM_BLOCK2        _T("EQAlarm2")
#define STEP_ALARM_BLOCK3        _T("EQAlarm3")
#define STEP_ALARM_BLOCK4        _T("EQAlarm4")
#define STEP_ALARM_BLOCK5        _T("EQAlarm5")
#define STEP_PROCESS            _T("EQProcess")
#define STEP_CIM_MODE_CHANGE    _T("EQCimModeChange")
#define BASE_ALARM_EFEM        10000
#define BASE_ALARM_BONDER1    20000
#define BASE_ALARM_BONDER2    30000
/* step event */
#define STEP_EVENT_READDATA            0x01
#define STEP_EVENT_COMPLETE            0x02
#define STEP_EVENT_PROCESS_DATA        0x1001
/* è‡ªå®šä¹‰æ¶ˆæ¯ */
#define ID_MSG_PANEL_RESIZE            WM_USER + 1998
SourceCode/Bond/Servo/HorizontalLine.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,209 @@
// HorizontalLine.cpp: implementation of the CHorizontalLine class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "HorizontalLine.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CHorizontalLine::CHorizontalLine()
{
    m_hWnd = NULL;
    m_crBkgnd = RGB(255, 255, 255);
    m_crLineColor = RGB(222, 222, 222);
}
CHorizontalLine::~CHorizontalLine()
{
}
BOOL CHorizontalLine::RegisterWndClass()
{
    WNDCLASS wc;
    wc.lpszClassName = BYHORIZONTALLINE_CLASS;
    wc.hInstance = AfxGetInstanceHandle();
    wc.lpfnWndProc = WindowProc;
    wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = 0;
    wc.lpszMenuName = NULL;
    wc.hbrBackground = NULL;
    wc.style = CS_GLOBALCLASS|CS_DBLCLKS;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    // æ³¨å†Œè‡ªå®šä¹‰ç±»
    return (::RegisterClass(&wc) != 0);
}
CHorizontalLine* CHorizontalLine::Hook(HWND hWnd)
{
    CHorizontalLine* pHorizontalLine = (CHorizontalLine*)GetProp(hWnd, BYSTAG_HORIZONTALLINE);
    if(pHorizontalLine == NULL)
    {
        pHorizontalLine = new CHorizontalLine;
        pHorizontalLine->m_hWnd = hWnd;
        SetProp(hWnd, BYSTAG_HORIZONTALLINE, (HANDLE)pHorizontalLine);
    }
    return pHorizontalLine;
}
void CHorizontalLine::Release()
{
    // delete
    delete this;
}
void CHorizontalLine::Notify(int nCode, int dwData, int dwData1/* = 0*/, int dwData2/* = 0*/)
{
    HWND hParent;
    hParent = GetParent(m_hWnd);
    if(hParent != NULL) {
        BYHORIZONTALLINE_NMHDR iii_nmhdr;
        iii_nmhdr.nmhdr.hwndFrom = m_hWnd;
        iii_nmhdr.nmhdr.idFrom = GetWindowLong(m_hWnd, GWL_ID);
        iii_nmhdr.nmhdr.code = nCode;
        iii_nmhdr.dwData = dwData;
        iii_nmhdr.dwData1 = dwData1;
        iii_nmhdr.dwData2 = dwData2;
        SendMessage(hParent, WM_NOTIFY, (WPARAM)iii_nmhdr.nmhdr.idFrom, (LPARAM)&iii_nmhdr);
    }
}
////////////////////////////////
// æ‹¦æˆªçª—口消息函数
LRESULT CALLBACK CHorizontalLine::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CHorizontalLine* pHorizontalLine = (CHorizontalLine *)GetProp(hWnd, BYSTAG_HORIZONTALLINE);
    if(pHorizontalLine == NULL && uMsg != WM_NCCREATE)
    {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    // å¦‚æžœHook则响应消息
    ASSERT(hWnd);
    switch(uMsg)
    {
    case WM_NCCREATE:
        return OnNcCreate(hWnd, wParam, lParam);
    case WM_DESTROY:
        return pHorizontalLine->OnDestroy(wParam, lParam);
    case WM_PAINT:
        return pHorizontalLine->OnPaint(wParam, lParam);
    case WM_TIMER:
        return pHorizontalLine->OnTimer(wParam, lParam);
    case WM_GETDLGCODE:
        return DLGC_WANTALLKEYS;
    default:
        break;
    }
    return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
///////////////////////////////
// WM_NCCREATE
// çª—口创建前的初始化工作
LRESULT CHorizontalLine::OnNcCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
    CHorizontalLine* pHorizontalLine = (CHorizontalLine *)GetProp(hWnd, BYSTAG_HORIZONTALLINE);
    ASSERT(pHorizontalLine == NULL);
    Hook(hWnd);
    return ::DefWindowProc(hWnd, WM_NCCREATE, wParam, lParam);
}
///////////////////////////////
// WM_DESTROY
LRESULT CHorizontalLine::OnDestroy(WPARAM wParam, LPARAM lParam)
{
    Release();
    return ::DefWindowProc(m_hWnd, WM_DESTROY, wParam, lParam);
}
///////////////////////////////
// WM_TIMER
LRESULT CHorizontalLine::OnTimer(WPARAM wParam, LPARAM lParam)
{
    return ::DefWindowProc(m_hWnd, WM_TIMER, wParam, lParam);
}
///////////////////////////////
// WM_PAINT
LRESULT CHorizontalLine::OnPaint(WPARAM wParam, LPARAM lParam)
{
    HDC hDC, hMemDC;
    HBITMAP hBitmap;
    RECT rcClient;
    CString strText;
    HFONT hFont;
    HBRUSH hBrushBK;
    // BeginPaint
    PAINTSTRUCT ps;
    hDC = BeginPaint(m_hWnd, &ps);
    GetClientRect(m_hWnd, &rcClient);
    hMemDC = ::CreateCompatibleDC(hDC);
    hBitmap = ::CreateCompatibleBitmap(hDC, rcClient.right-rcClient.left,
        rcClient.bottom-rcClient.top);
    ::SelectObject(hMemDC, hBitmap);
    hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    ::SelectObject(hMemDC, hFont);
    // èƒŒæ™¯é¢œè‰²
    hBrushBK = CreateSolidBrush( m_crBkgnd );
    ::FillRect(hMemDC, &rcClient, hBrushBK);
    DeleteObject(hBrushBK);
    // ç”»çº¿
    HPEN hPen = CreatePen(PS_SOLID, 1, m_crLineColor);
    HPEN hOldPen = (HPEN)::SelectObject(hMemDC, hPen);
    ::MoveToEx(hMemDC, 0, 0, NULL);
    LineTo(hMemDC, rcClient.right, 0);
    ::SelectObject(hMemDC, hOldPen);
    // EndPaint
    ::BitBlt(hDC, 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
        hMemDC, 0, 0, SRCCOPY);
    EndPaint(m_hWnd, &ps);
    ::DeleteObject(hBitmap);
    ::DeleteDC(hMemDC);
    return 1;
}
void CHorizontalLine::SetBkgndColor(COLORREF cr)
{
    m_crBkgnd = cr;
}
void CHorizontalLine::SetLineColor(COLORREF cr)
{
    m_crLineColor = cr;
}
SourceCode/Bond/Servo/HorizontalLine.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
// HorizontalLine.h: interface for the CHorizontalLine class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_HORIZONTALLINE_H__FBB8916A_DE77_4EA3_9C21_E51E6B06194C__INCLUDED_)
#define AFX_HORIZONTALLINE_H__FBB8916A_DE77_4EA3_9C21_E51E6B06194C__INCLUDED_
#pragma comment(lib, "Msimg32.lib")            // TransparentBlt
//====== HorizontalLine =====================================================
#ifndef NOHORIZONTALLINE
#ifdef _WIN32
#define BYHORIZONTALLINE_CLASSA       "BYHorizontalLine"
#define BYHORIZONTALLINE_CLASSW       L"BYHorizontalLine"
#ifdef UNICODE
#define  BYHORIZONTALLINE_CLASS       BYHORIZONTALLINE_CLASSW
#else
#define  BYHORIZONTALLINE_CLASS       BYHORIZONTALLINE_CLASSA
#endif
#else
#define BYHORIZONTALLINE_CLASS        "BYHorizontalLine"
#endif
#define BYSTAG_HORIZONTALLINE         _T("ISHORIZONTALLINE")
//====== WM_NOTIFY codes (NMHDR.code values) ==================================
#define BYHORIZONTALLINE_FIRST                 (0U-590U)       //
#define BYHORIZONTALLINE_LAST                 (0U-550U)
#define BYHORIZONTALLINE_                      (BYHORIZONTALLINE_FIRST - 1)
typedef struct tagBYHORIZONTALLINE_NMHDR
{
    NMHDR        nmhdr;
    DWORD        dwData;
    DWORD        dwData1;
    DWORD        dwData2;
} BYHORIZONTALLINE_NMHDR;
#endif
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CHorizontalLine
{
public:
    CHorizontalLine();
    virtual ~CHorizontalLine();
public:
    static BOOL RegisterWndClass();
    static CHorizontalLine* Hook(HWND hWnd);
    void Notify(int nCode, int dwData, int dwData1 = 0, int dwData2 = 0);
    void Release();
    void SetBkgndColor(COLORREF cr);
    void SetLineColor(COLORREF cr);
    static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    static LRESULT OnNcCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
    LRESULT OnDestroy(WPARAM wParam, LPARAM lParam);
    LRESULT OnTimer(WPARAM wParam, LPARAM lParam);
    LRESULT OnPaint(WPARAM wParam, LPARAM lParam);
private:
    HWND        m_hWnd;
    COLORREF m_crBkgnd;
    COLORREF m_crLineColor;
};
#endif // !defined(AFX_HORIZONTALLINE_H__FBB8916A_DE77_4EA3_9C21_E51E6B06194C__INCLUDED_)
SourceCode/Bond/Servo/Model.cpp
@@ -2,6 +2,9 @@
#include "Model.h"
#include "Log.h"
#include "Common.h"
#include "ToolUnits.h"
#include "CEqAlarmStep.h"
#include "AlarmManager.h"
CModel::CModel()
@@ -108,10 +111,54 @@
                pStep->getName().c_str(), pData);
            notifyPtr(RX_CODE_STEP_EVENT_READDATA, pStep);
            
            // å¤„理警告信息
            if (isAlarmStep(pStep)) {
                // ä¿å­˜åˆ°æ•°æ®åº“
                AlarmManager& alarmManager = AlarmManager::getInstance();
                std::string strAlarmText;
                SERVO::CEquipment* pEquipment = pStep->getEquipment();
                SERVO::CEqAlarmStep* pEqAlarmStep = (SERVO::CEqAlarmStep*)pStep;
                const AlarmInfo* pAlarmInfo = alarmManager.getAlarmInfoByID(pEqAlarmStep->getAlarmId());
                if (pAlarmInfo != nullptr) {
                    strAlarmText = pAlarmInfo->strAlarmText;
                }
                int state = pEqAlarmStep->getAlarmState();
                if (state == 1) {
                    LOGE("<CAlarmDlg> å‘生警告");
                    std::string startTime = CToolUnits::timeToString2(CToolUnits::getTimestamp());
                    std::string endTime = "";
                    bool result = alarmManager.addAlarm(std::to_string(pEqAlarmStep->getAlarmId()),
                        pEquipment->getName(), strAlarmText, startTime, endTime);
                    if (result) {
                        LOGI("<CAlarmDlg> Alarm added successfully!");
                    }
                    else {
                        LOGE("<CAlarmDlg> Failed to add alarm.");
                    }
                }
                else {
                    LOGE("<CAlarmDlg> i消除警告");
                    //alarmManager.updateAlarmEndTime(std::to_string(pEqAlarmStep->getAlarmId()),
                    //    pEquipment->getName());
                }
                m_hsmsPassive.requestAlarmReport(pEqAlarmStep->getAlarmState(),
                    pEquipment->getBaseAlarmId() + pEqAlarmStep->getAlarmId(),
                    strAlarmText.c_str());
            }
        }
    };
    m_master.setListener(masterListener);
    // åŠ è½½è­¦å‘Šä¿¡æ¯
    AlarmManager& alarmManager = AlarmManager::getInstance();
    char szBuffer[MAX_PATH];
    sprintf_s(szBuffer, MAX_PATH, "%s\\AlarmList.csv", (LPTSTR)(LPCTSTR)m_strWorkDir);
    alarmManager.readAlarmFile(szBuffer);
    return 0;
}
@@ -329,3 +376,8 @@
    return 0;
}
bool CModel::isAlarmStep(SERVO::CStep* pStep)
{
    return CToolUnits::startsWith(pStep->getName(), STEP_ALARM_START);
}
SourceCode/Bond/Servo/Model.h
@@ -14,6 +14,7 @@
    void setWorkDir(const char* pszWorkDir);
    int init();
    int term();
    bool isAlarmStep(SERVO::CStep* pStep);
public:
    int notify(int code);
SourceCode/Bond/Servo/Servo.cpp
@@ -8,6 +8,8 @@
#include "ServoGraph.h"
#include "AlarmManager.h"
#include "SECSRuntimeManager.h"
#include "VerticalLine.h"
// å£°æ˜Žå…¨å±€å˜é‡ï¼Œç”¨äºŽç®¡ç† GDI+ åˆå§‹åŒ–
ULONG_PTR g_diplusToken;
@@ -92,6 +94,7 @@
    // æ³¨å†ŒæŽ§ä»¶
    CServoGraph::RegisterWndClass();
    CVerticalLine::RegisterWndClass();
    // åˆå§‹åŒ–Rx库
SourceCode/Bond/Servo/Servo.rc
Binary files differ
SourceCode/Bond/Servo/Servo.vcxproj
@@ -197,14 +197,24 @@
  <ItemGroup>
    <ClInclude Include="AlarmDlg.h" />
    <ClInclude Include="AlarmManager.h" />
    <ClInclude Include="ApredTreeCtrl2.h" />
    <ClInclude Include="BlButton.h" />
    <ClInclude Include="CAttribute.h" />
    <ClInclude Include="CAttributeVector.h" />
    <ClInclude Include="CBonder.h" />
    <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h" />
    <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h" />
    <ClInclude Include="CEqAlarmStep.h" />
    <ClInclude Include="CEqCimModeChangeStep.h" />
    <ClInclude Include="CEqModeStep.h" />
    <ClInclude Include="CEqProcessStep.h" />
    <ClInclude Include="CEqStatusStep.h" />
    <ClInclude Include="CPanelAttributes.h" />
    <ClInclude Include="CPanelEquipment.h" />
    <ClInclude Include="CPanelMaster.h" />
    <ClInclude Include="CReadStep.h" />
    <ClInclude Include="CStep.h" />
    <ClInclude Include="CWriteStep.h" />
    <ClInclude Include="DevicePropertyDlg.h" />
    <ClInclude Include="CEFEM.h" />
    <ClInclude Include="CEquipment.h" />
@@ -228,18 +238,29 @@
    <ClInclude Include="targetver.h" />
    <ClInclude Include="TerminalDisplayDlg.h" />
    <ClInclude Include="ToolUnits.h" />
    <ClInclude Include="VerticalLine.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="AlarmDlg.cpp" />
    <ClCompile Include="AlarmManager.cpp" />
    <ClCompile Include="ApredTreeCtrl2.cpp" />
    <ClCompile Include="BlButton.cpp" />
    <ClCompile Include="CAttribute.cpp" />
    <ClCompile Include="CAttributeVector.cpp" />
    <ClCompile Include="CBonder.cpp" />
    <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp" />
    <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp" />
    <ClCompile Include="CEqAlarmStep.cpp" />
    <ClCompile Include="CEqCimModeChangeStep.cpp" />
    <ClCompile Include="CEqModeStep.cpp" />
    <ClCompile Include="CEqProcessStep.cpp" />
    <ClCompile Include="CEqStatusStep.cpp" />
    <ClCompile Include="CPanelAttributes.cpp" />
    <ClCompile Include="CPanelEquipment.cpp" />
    <ClCompile Include="CPanelMaster.cpp" />
    <ClCompile Include="CReadStep.cpp" />
    <ClCompile Include="CStep.cpp" />
    <ClCompile Include="CWriteStep.cpp" />
    <ClCompile Include="DevicePropertyDlg.cpp" />
    <ClCompile Include="CEFEM.cpp" />
    <ClCompile Include="CEquipment.cpp" />
@@ -265,6 +286,7 @@
    </ClCompile>
    <ClCompile Include="TerminalDisplayDlg.cpp" />
    <ClCompile Include="ToolUnits.cpp" />
    <ClCompile Include="VerticalLine.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc" />
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -41,6 +41,17 @@
    <ClCompile Include="CEqStatusStep.cpp" />
    <ClCompile Include="CEqAlarmStep.cpp" />
    <ClCompile Include="AlarmDlg.cpp" />
    <ClCompile Include="CEqProcessStep.cpp" />
    <ClCompile Include="CAttribute.cpp" />
    <ClCompile Include="CAttributeVector.cpp" />
    <ClCompile Include="CPanelMaster.cpp" />
    <ClCompile Include="VerticalLine.cpp" />
    <ClCompile Include="ApredTreeCtrl2.cpp" />
    <ClCompile Include="CPanelAttributes.cpp" />
    <ClCompile Include="CReadStep.cpp" />
    <ClCompile Include="CWriteStep.cpp" />
    <ClCompile Include="CEqCimModeChangeStep.cpp" />
    <ClCompile Include="CPanelEquipment.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AlarmManager.h" />
@@ -80,6 +91,17 @@
    <ClInclude Include="CEqStatusStep.h" />
    <ClInclude Include="CEqAlarmStep.h" />
    <ClInclude Include="AlarmDlg.h" />
    <ClInclude Include="CEqProcessStep.h" />
    <ClInclude Include="CAttribute.h" />
    <ClInclude Include="CAttributeVector.h" />
    <ClInclude Include="CPanelMaster.h" />
    <ClInclude Include="VerticalLine.h" />
    <ClInclude Include="ApredTreeCtrl2.h" />
    <ClInclude Include="CPanelAttributes.h" />
    <ClInclude Include="CReadStep.h" />
    <ClInclude Include="CWriteStep.h" />
    <ClInclude Include="CEqCimModeChangeStep.h" />
    <ClInclude Include="CPanelEquipment.h" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc" />
SourceCode/Bond/Servo/Servo.vcxproj.user
@@ -7,6 +7,6 @@
    <RemoteDebuggerCommand>D:\CLH\Servo\Servo.exe</RemoteDebuggerCommand>
    <RemoteDebuggerWorkingDirectory>D:\CLH\Servo\</RemoteDebuggerWorkingDirectory>
    <RemoteDebuggerServerName>Boounion-0106</RemoteDebuggerServerName>
    <DebuggerFlavor>WindowsRemoteDebugger</DebuggerFlavor>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
  </PropertyGroup>
</Project>
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -9,6 +9,7 @@
#include "Common.h"
#include "Log.h"
#include "SecsTestDlg.h"
#include "AlarmDlg.h"
#include <chrono>
#include <thread>
#include <cmath>
@@ -90,6 +91,9 @@
    m_pAlarmDlg = nullptr;
    m_pTerminalDisplayDlg = nullptr;
    m_pObserver = nullptr;
    m_pPanelMaster = nullptr;
    m_pPanelEquipment = nullptr;
    m_pPanelAttributes = nullptr;
}
void CServoDlg::DoDataExchange(CDataExchange* pDX)
@@ -127,6 +131,9 @@
    ON_WM_TIMER()
    ON_WM_ERASEBKGND()
    ON_BN_CLICKED(IDC_BUTTON_ALARM, &CServoDlg::OnBnClickedButtonAlarm)
    ON_BN_CLICKED(IDC_BUTTON_ALARM, &CServoDlg::OnBnClickedButtonAlarm)
    ON_NOTIFY(BYSERVOGRAPH_ITEM_CLICKED, IDC_SERVO_GRAPH1, &CServoDlg::OnGraphItemClicked)
    ON_MESSAGE(ID_MSG_PANEL_RESIZE, OnPanelResize)
END_MESSAGE_MAP()
@@ -164,6 +171,35 @@
                    }
                }
            }
            else if (RX_CODE_SELECT_EQUIPMENT == code) {
                SERVO::CEquipment* pEquipment = nullptr;
                if (pAny->getPtrValue("ptr", (void*&)pEquipment)) {
                    ASSERT(pEquipment);
                    ASSERT(m_pPanelEquipment);
                    ASSERT(m_pPanelAttributes);
                    m_pPanelEquipment->SetEquipment(pEquipment);
                    m_pPanelAttributes->ShowWindow(SW_HIDE);
                    if (!m_pPanelEquipment->IsWindowVisible()) {
                        m_pPanelEquipment->ShowWindow(SW_SHOW);
                        Resize();
                    }
                }
            }
            else if (RX_CODE_SELECT_STEP == code) {
                SERVO::CStep* pStep = nullptr;
                if (pAny->getPtrValue("ptr", (void*&)pStep)) {
                    ASSERT(pStep);
                    ASSERT(m_pPanelEquipment);
                    ASSERT(m_pPanelAttributes);
                    m_pPanelEquipment->ShowWindow(SW_HIDE);
                    m_pPanelAttributes->loadDataFromStep(pStep);
                    if (!m_pPanelAttributes->IsWindowVisible()) {
                        m_pPanelAttributes->ShowWindow(SW_SHOW);
                        Resize();
                    }
                }
            }
            pAny->release();
        }, [&]() -> void {
            // onComplete
@@ -278,6 +314,8 @@
    m_pGraph->SetBoxText(INDICATE_ROBOT_ARM2, "6", "Robot");
    // Vacuum bake
    m_pGraph->AddIndicateBox(INDICATE_VACUUM_BAKE, 396, 516, 48, RGB(22, 22, 22),
        RGB(255, 127, 39), RGB(0, 176, 80));
@@ -294,6 +332,17 @@
    m_pGraph->AddIndicateBox(INDICATE_MEASUREMENT, 736, 516, 48, RGB(22, 22, 22),
        RGB(255, 127, 39), RGB(0, 176, 80));
    m_pGraph->SetBoxText(INDICATE_MEASUREMENT, "13", "Measurement");
    m_pPanelMaster = new CPanelMaster();
    m_pPanelMaster->Create(IDD_PANEL_MASTER, this);
    m_pPanelMaster->ShowWindow(SW_SHOW);
    m_pPanelEquipment = new CPanelEquipment();
    m_pPanelEquipment->Create(IDD_PANEL_EQUIPMENT, this);
    m_pPanelAttributes = new CPanelAttributes();
    m_pPanelAttributes->Create(IDD_PANEL_ATTRIBUTES, this);
    // è°ƒæ•´åˆå§‹çª—口位置
@@ -318,6 +367,13 @@
    // ç›¸å½“于延时调用master的初始化
    theApp.m_model.m_master.init();
    // ç»‘定数据
    {
        SERVO::CEquipment* pEquipment = theApp.m_model.m_master.getEquipment(EQ_ID_EFEM);
        m_pGraph->SetIndicateBoxData(INDICATE_ROBOT_ARM1, pEquipment);
    }
    return TRUE;  // é™¤éžå°†ç„¦ç‚¹è®¾ç½®åˆ°æŽ§ä»¶ï¼Œå¦åˆ™è¿”回 TRUE
@@ -541,6 +597,24 @@
        m_pTerminalDisplayDlg = nullptr;
    }
    if (m_pPanelMaster != nullptr) {
        m_pPanelMaster->DestroyWindow();
        delete m_pPanelMaster;
        m_pPanelMaster = nullptr;
    }
    if (m_pPanelEquipment != nullptr) {
        m_pPanelEquipment->DestroyWindow();
        delete m_pPanelEquipment;
        m_pPanelEquipment = nullptr;
    }
    if (m_pPanelAttributes != nullptr) {
        m_pPanelAttributes->DestroyWindow();
        delete m_pPanelAttributes;
        m_pPanelAttributes = nullptr;
    }
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
@@ -749,6 +823,25 @@
    x = 0;
    y = 0;
    int nPanelWidth = 0;
    if (m_pPanelMaster != nullptr) {
        nPanelWidth = m_pPanelMaster->getPanelWidth();
        m_pPanelMaster->MoveWindow(x, y, nPanelWidth, rcClient.Height());
        x += nPanelWidth;
    }
    if (m_pPanelEquipment != nullptr && m_pPanelEquipment->IsWindowVisible()) {
        nPanelWidth = m_pPanelEquipment->getPanelWidth();
        m_pPanelEquipment->MoveWindow(x, y, nPanelWidth, rcClient.Height());
        x += nPanelWidth;
    }
    if (m_pPanelAttributes != nullptr && m_pPanelAttributes->IsWindowVisible()) {
        nPanelWidth = m_pPanelAttributes->getPanelWidth();
        m_pPanelAttributes->MoveWindow(x, y, nPanelWidth, rcClient.Height());
        x += nPanelWidth;
    }
    pItem = GetDlgItem(IDC_SERVO_GRAPH1);
    pItem->GetClientRect(&rcItem);
    pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height());
@@ -858,27 +951,29 @@
void CServoDlg::OnBnClickedButtonAlarm()
{
    // TODO: åœ¨æ­¤æ·»åŠ æŽ§ä»¶é€šçŸ¥å¤„ç†ç¨‹åºä»£ç 
    m_bShowAlarmWnd = !m_bShowAlarmWnd;
    // å¦‚果要显示报警窗口,则隐藏日志窗口
    if (m_bShowAlarmWnd) {
        m_bShowLogWnd = false;
        if (m_pLogDlg != nullptr) {
            m_pLogDlg->ShowWindow(SW_HIDE);
            UpdateLogBtn();
        }
    }
    if (m_pAlarmDlg == nullptr) {
        m_pAlarmDlg = new CAlarmDlg();
        m_pAlarmDlg->Create(IDD_DIALOG_ALARM, this);
        CRect rcWnd;
        GetWindowRect(&rcWnd);
        m_pAlarmDlg->MoveWindow(rcWnd.left, rcWnd.bottom - 8, rcWnd.Width(), 200);
    }
    ASSERT(m_pAlarmDlg);
    m_pAlarmDlg->ShowWindow(m_bShowAlarmWnd ? SW_SHOW : SW_HIDE);
    UpdateAlarmBtn();
    CAlarmDlg dlg;
    dlg.DoModal();
}
void CServoDlg::OnGraphItemClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
    BYSERVOGRAPH_NMHDR* pGraphNmhdr = reinterpret_cast<BYSERVOGRAPH_NMHDR*>(pNMHDR);
    CString s; s.Format(_T("OnGraphItemClicked %d"), pGraphNmhdr->dwData);
    SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)m_pGraph->GetIndicateBoxData(pGraphNmhdr->dwData);
    if (pEquipment != nullptr) {
        AfxMessageBox(pEquipment->getName().c_str());
    }
    *pResult = 0;
}
LRESULT CServoDlg::OnPanelResize(WPARAM wParam, LPARAM lParam)
{
    int width = wParam;
    // m_pPanel->SetPanelWidth(width);
    Resize();
    return 0;
}
SourceCode/Bond/Servo/ServoDlg.h
@@ -8,6 +8,10 @@
#include "LogDlg.h"
#include "AlarmDlg.h"
#include "TerminalDisplayDlg.h"
#include "CPanelMaster.h"
#include "CPanelEquipment.h"
#include "CPanelAttributes.h"
enum DeviceStatus {
    ONLINE,       // åœ¨çº¿
@@ -64,7 +68,9 @@
    HBRUSH m_hbrBkgnd;
    CBlButton m_btnLog;
    CBlButton m_btnAlarm;
    CPanelMaster* m_pPanelMaster;
    CPanelEquipment* m_pPanelEquipment;
    CPanelAttributes* m_pPanelAttributes;
    // ç”Ÿæˆçš„æ¶ˆæ¯æ˜ å°„函数
    virtual BOOL OnInitDialog();
@@ -97,4 +103,6 @@
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnBnClickedButtonAlarm();
    afx_msg void OnGraphItemClicked(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg LRESULT OnPanelResize(WPARAM wParam, LPARAM lParam);
};
SourceCode/Bond/Servo/ServoGraph.cpp
@@ -693,4 +693,22 @@
        graphics.DrawImage(&bitmap, item.x, item.y);
        graphics.ResetTransform();
    }
}
void CServoGraph::SetIndicateBoxData(int id, void* pData)
{
    INDICATEBOX* pib = GetIndicateBox(id);
    if (pib != nullptr) {
        pib->m_pData = pData;
    }
}
void* CServoGraph::GetIndicateBoxData(int id)
{
    INDICATEBOX* pib = GetIndicateBox(id);
    if (pib != nullptr) {
        return pib->m_pData;
    }
    return nullptr;
}
SourceCode/Bond/Servo/ServoGraph.h
@@ -94,6 +94,7 @@
            this->box2BackgroundColor = RGB(0, 255, 255);;
            this->box2FrameColor = RGB(255, 255, 0);;
            this->bBox2Visible = FALSE;
            this->m_pData = nullptr;
        };
        ~INDICATEBOX() {};
@@ -110,6 +111,7 @@
        COLORREF box2FrameColor;
        BOOL bBox2Visible;
        std::vector<void*> m_contexts;
        void* m_pData;
    };
    class INDICATEBKGND
@@ -154,6 +156,8 @@
    BOOL RemoveIndicateBoxAllContext(int id);
    const std::vector<void*>& GetIndicateBoxContexts(int id);
    bool IsIndicateBoxContextsEmpty(int id);
    void SetIndicateBoxData(int id, void* pData);
    void* GetIndicateBoxData(int id);
    void ShowIndicateBoxInterior(int id, COLORREF color);
    void HideIndicateBoxInterior(int id);
    CServoGraph::INDICATEBOX* GetIndicateBox(int id);
SourceCode/Bond/Servo/ToolUnits.cpp
@@ -301,4 +301,9 @@
        ltm.tm_hour, ltm.tm_min, ltm.tm_sec);
    return std::string(buffer);
}
bool CToolUnits::startsWith(const std::string& str, const std::string& prefix)
{
    return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0;
}
SourceCode/Bond/Servo/ToolUnits.h
@@ -28,5 +28,6 @@
    static std::vector<CString> GetFileNamesInDirectory(const CString& strFolderPath, const CString& strExtension);
    static std::string getRecipePath();
    static std::string getCurrentTimeString();
    static bool startsWith(const std::string& str, const std::string& prefix);
};
SourceCode/Bond/Servo/VerticalLine.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,316 @@
// VerticalLine.cpp: implementation of the CVerticalLine class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "VerticalLine.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CVerticalLine::CVerticalLine()
{
    m_hWnd = NULL;
    m_crBkgnd = RGB(255, 255, 255);
    m_crLineColor = RGB(222, 222, 222);
    m_bEnableResize = FALSE;
}
CVerticalLine::~CVerticalLine()
{
}
BOOL CVerticalLine::RegisterWndClass()
{
    WNDCLASS wc;
    wc.lpszClassName = BYVERTICALLINE_CLASS;
    wc.hInstance = AfxGetInstanceHandle();
    wc.lpfnWndProc = WindowProc;
    wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = 0;
    wc.lpszMenuName = NULL;
    wc.hbrBackground = NULL;
    wc.style = CS_GLOBALCLASS|CS_DBLCLKS;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    // æ³¨å†Œè‡ªå®šä¹‰ç±»
    return (::RegisterClass(&wc) != 0);
}
CVerticalLine* CVerticalLine::Hook(HWND hWnd)
{
    CVerticalLine* pVerticalLine = (CVerticalLine*)GetProp(hWnd, BYSTAG_VERTICALLINE);
    if(pVerticalLine == NULL)
    {
        pVerticalLine = new CVerticalLine;
        pVerticalLine->m_hWnd = hWnd;
        SetProp(hWnd, BYSTAG_VERTICALLINE, (HANDLE)pVerticalLine);
    }
    return pVerticalLine;
}
void CVerticalLine::Release()
{
    // delete
    delete this;
}
void CVerticalLine::Notify(int nCode, int dwData, int dwData1/* = 0*/, int dwData2/* = 0*/)
{
    HWND hParent;
    hParent = GetParent(m_hWnd);
    if(hParent != NULL) {
        BYVERTICALLINE_NMHDR iii_nmhdr;
        iii_nmhdr.nmhdr.hwndFrom = m_hWnd;
        iii_nmhdr.nmhdr.idFrom = GetWindowLong(m_hWnd, GWL_ID);
        iii_nmhdr.nmhdr.code = nCode;
        iii_nmhdr.dwData = dwData;
        iii_nmhdr.dwData1 = dwData1;
        iii_nmhdr.dwData2 = dwData2;
        SendMessage(hParent, WM_NOTIFY, (WPARAM)iii_nmhdr.nmhdr.idFrom, (LPARAM)&iii_nmhdr);
    }
}
////////////////////////////////
// æ‹¦æˆªçª—口消息函数
LRESULT CALLBACK CVerticalLine::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CVerticalLine* pVerticalLine = (CVerticalLine *)GetProp(hWnd, BYSTAG_VERTICALLINE);
    if(pVerticalLine == NULL && uMsg != WM_NCCREATE)
    {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    // å¦‚æžœHook则响应消息
    ASSERT(hWnd);
    switch(uMsg)
    {
    case WM_NCCREATE:
        return OnNcCreate(hWnd, wParam, lParam);
    case WM_DESTROY:
        return pVerticalLine->OnDestroy(wParam, lParam);
    case WM_PAINT:
        return pVerticalLine->OnPaint(wParam, lParam);
    case WM_TIMER:
        return pVerticalLine->OnTimer(wParam, lParam);
    case WM_SETCURSOR:
        return pVerticalLine->OnSetCursor(wParam, lParam);
    case WM_LBUTTONDOWN:
        return pVerticalLine->OnLButtonDown(wParam, lParam);
    case WM_GETDLGCODE:
        return DLGC_WANTALLKEYS;
    default:
        break;
    }
    return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
///////////////////////////////
// WM_NCCREATE
// çª—口创建前的初始化工作
LRESULT CVerticalLine::OnNcCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
    CVerticalLine* pVerticalLine = (CVerticalLine *)GetProp(hWnd, BYSTAG_VERTICALLINE);
    ASSERT(pVerticalLine == NULL);
    Hook(hWnd);
    return ::DefWindowProc(hWnd, WM_NCCREATE, wParam, lParam);
}
///////////////////////////////
// WM_DESTROY
LRESULT CVerticalLine::OnDestroy(WPARAM wParam, LPARAM lParam)
{
    Release();
    return ::DefWindowProc(m_hWnd, WM_DESTROY, wParam, lParam);
}
///////////////////////////////
// WM_TIMER
LRESULT CVerticalLine::OnTimer(WPARAM wParam, LPARAM lParam)
{
    return ::DefWindowProc(m_hWnd, WM_TIMER, wParam, lParam);
}
///////////////////////////////
// WM_SETCURSOR
LRESULT CVerticalLine::OnSetCursor(WPARAM wParam, LPARAM lParam)
{
    if(m_bEnableResize) {
        SetCursor(::LoadCursor(NULL, IDC_SIZEWE));
        return TRUE;
    }
    return ::DefWindowProc(m_hWnd, WM_SETCURSOR, wParam, lParam);
}
/*
 * WM_LBUTTONDOWN
 * é¼ æ ‡å·¦é”®æŒ‰ä¸‹
 */
LRESULT CVerticalLine::OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
    if (!m_bEnableResize) {
        return ::DefWindowProc(m_hWnd, WM_LBUTTONDOWN, wParam, lParam);
    }
    POINT pt, ptNew;
    pt.x = LOWORD(lParam);
    pt.y = HIWORD(lParam);
    int nMoveX = 0;
    // æ•捉鼠标消息,检测是否拖动
    RECT rcParent, rcWindows;
    GetClientRect(m_hWnd, &rcWindows);
    ::ClientToScreen(m_hWnd, (LPPOINT)&rcWindows);
    ::ClientToScreen(m_hWnd, (LPPOINT)&rcWindows.right);
    GetClientRect(GetParent(m_hWnd), &rcParent);
    ::ClientToScreen(GetParent(m_hWnd), (LPPOINT)&rcParent);
    HDC hDC = GetDC(GetDesktopWindow());
    ::DrawFocusRect(hDC, &rcWindows);
    if (::GetCapture() == NULL) {
        SetCapture(m_hWnd);
        ASSERT(m_hWnd == GetCapture());
        AfxLockTempMaps();
        for (;;) {
            MSG msg;
            VERIFY(::GetMessage(&msg, NULL, 0, 0));
            if (GetCapture() != m_hWnd) break;
            switch (msg.message)
            {
            case WM_MOUSEMOVE:
                ptNew = msg.pt;
                if (ptNew.x < rcParent.left) ptNew.x = rcParent.left;
                ::DrawFocusRect(hDC, &rcWindows);
                rcWindows.left = ptNew.x - 3;
                rcWindows.right = ptNew.x + 3;
                ::DrawFocusRect(hDC, &rcWindows);
                ::ScreenToClient(m_hWnd, &ptNew);
                break;
            case WM_LBUTTONUP:
                ptNew = msg.pt;
                ::ScreenToClient(m_hWnd, &ptNew);
                nMoveX = ptNew.x - pt.x;
                goto ExitLoop;
            case WM_KEYDOWN:
                if (msg.wParam == VK_ESCAPE) {
                    goto ExitLoop;
                }
                break;
            default:
                DispatchMessage(&msg);
                break;
            }
        }
    ExitLoop:
        ::DrawFocusRect(hDC, &rcWindows);
        ReleaseDC(GetDesktopWindow(), hDC);
        ReleaseCapture();
        ::InvalidateRect(m_hWnd, NULL, TRUE);
        Notify((int)BYVERTICALLINE_MOVEX, nMoveX);
        AfxUnlockTempMaps(FALSE);
    }
    return ::DefWindowProc(m_hWnd, WM_LBUTTONDOWN, wParam, lParam);
}
///////////////////////////////
// WM_PAINT
LRESULT CVerticalLine::OnPaint(WPARAM wParam, LPARAM lParam)
{
    HDC hDC, hMemDC;
    HBITMAP hBitmap;
    RECT rcClient;
    CString strText;
    HFONT hFont;
    HBRUSH hBrushBK;
    // BeginPaint
    PAINTSTRUCT ps;
    hDC = BeginPaint(m_hWnd, &ps);
    GetClientRect(m_hWnd, &rcClient);
    hMemDC = ::CreateCompatibleDC(hDC);
    hBitmap = ::CreateCompatibleBitmap(hDC, rcClient.right-rcClient.left,
        rcClient.bottom-rcClient.top);
    ::SelectObject(hMemDC, hBitmap);
    hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    ::SelectObject(hMemDC, hFont);
    // èƒŒæ™¯é¢œè‰²
    hBrushBK = CreateSolidBrush( m_crBkgnd );
    ::FillRect(hMemDC, &rcClient, hBrushBK);
    DeleteObject(hBrushBK);
    // ç”»çº¿
    HPEN hPen = CreatePen(PS_SOLID, 1, m_crLineColor);
    HPEN hOldPen = (HPEN)::SelectObject(hMemDC, hPen);
    ::MoveToEx(hMemDC, rcClient.right-1, 0, NULL);
    LineTo(hMemDC, rcClient.right - 1, rcClient.bottom);
    ::SelectObject(hMemDC, hOldPen);
    // EndPaint
    ::BitBlt(hDC, 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
        hMemDC, 0, 0, SRCCOPY);
    EndPaint(m_hWnd, &ps);
    ::DeleteObject(hBitmap);
    ::DeleteDC(hMemDC);
    return 1;
}
void CVerticalLine::SetBkgndColor(COLORREF cr)
{
    m_crBkgnd = cr;
}
void CVerticalLine::SetLineColor(COLORREF cr)
{
    m_crLineColor = cr;
}
void CVerticalLine::EnableResize()
{
    m_bEnableResize = TRUE;
}
void CVerticalLine::DisableResize()
{
    m_bEnableResize = FALSE;
}
SourceCode/Bond/Servo/VerticalLine.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,95 @@
// VerticalLine.h: interface for the CVerticalLine class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_VERTICALLINE_H__FBB8916A_DE77_4EA3_9C21_E51E6B06194C__INCLUDED_)
#define AFX_VERTICALLINE_H__FBB8916A_DE77_4EA3_9C21_E51E6B06194C__INCLUDED_
#pragma comment(lib, "Msimg32.lib")            // TransparentBlt
//====== VerticalLine =====================================================
#ifndef NOVERTICALLINE
#ifdef _WIN32
#define BYVERTICALLINE_CLASSA       "BYVerticalLine"
#define BYVERTICALLINE_CLASSW       L"BYVerticalLine"
#ifdef UNICODE
#define  BYVERTICALLINE_CLASS       BYVERTICALLINE_CLASSW
#else
#define  BYVERTICALLINE_CLASS       BYVERTICALLINE_CLASSA
#endif
#else
#define BYVERTICALLINE_CLASS        "BYVerticalLine"
#endif
#define BYSTAG_VERTICALLINE         _T("ISVERTICALLINE")
//====== WM_NOTIFY codes (NMHDR.code values) ==================================
#define BYVERTICALLINE_FIRST             (0U-2330U)       //
#define BYVERTICALLINE_LAST                 (0U-2320U)
#define BYVERTICALLINE_MOVEX              (BYVERTICALLINE_FIRST - 1)
typedef struct tagBYVERTICALLINE_NMHDR
{
    NMHDR        nmhdr;
    DWORD        dwData;
    DWORD        dwData1;
    DWORD        dwData2;
} BYVERTICALLINE_NMHDR;
#endif
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CVerticalLine
{
public:
    CVerticalLine();
    virtual ~CVerticalLine();
public:
    void EnableResize();
    void DisableResize();
    static BOOL RegisterWndClass();
    static CVerticalLine* Hook(HWND hWnd);
    void Notify(int nCode, int dwData, int dwData1 = 0, int dwData2 = 0);
    void Release();
    void SetBkgndColor(COLORREF cr);
    void SetLineColor(COLORREF cr);
    static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    static LRESULT OnNcCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
    LRESULT OnDestroy(WPARAM wParam, LPARAM lParam);
    LRESULT OnTimer(WPARAM wParam, LPARAM lParam);
    LRESULT OnSetCursor(WPARAM wParam, LPARAM lParam);
    LRESULT OnPaint(WPARAM wParam, LPARAM lParam);
    LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam);
private:
    HWND        m_hWnd;
    COLORREF m_crBkgnd;
    COLORREF m_crLineColor;
private:
    BOOL m_bEnableResize;
};
#endif // !defined(AFX_VERTICALLINE_H__FBB8916A_DE77_4EA3_9C21_E51E6B06194C__INCLUDED_)
SourceCode/Bond/Servo/resource.h
Binary files differ
SourceCode/Bond/x64/Debug/Res/panel_close_24_a.ico
SourceCode/Bond/x64/Debug/Res/panel_close_24_b.ico