From 19261d011387ec57d646decc945aadaf8913eeab Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期一, 10 三月 2025 09:05:54 +0800
Subject: [PATCH] Merge branch 'clh'

---
 SourceCode/Bond/Servo/CReadStep.h                             |   35 
 SourceCode/Bond/Servo/CPanelEquipment.cpp                     |  175 ++
 SourceCode/Bond/Servo/CPanelAttributes.cpp                    |  192 ++
 SourceCode/Bond/Servo/ServoGraph.cpp                          |   18 
 SourceCode/Bond/Servo/ToolUnits.cpp                           |    5 
 SourceCode/Bond/Servo/Servo.rc                                |    0 
 SourceCode/Bond/Servo/ApredTreeCtrl2.h                        |   53 
 SourceCode/Bond/Servo/ServoDlg.h                              |   10 
 SourceCode/Bond/Servo/AlarmDlg.h                              |    1 
 SourceCode/Bond/Servo/CEqStatusStep.h                         |    6 
 SourceCode/Bond/Servo/HorizontalLine.cpp                      |  209 ++
 SourceCode/Bond/Servo/CPanelMaster.h                          |   47 
 SourceCode/Bond/Servo/CWriteStep.cpp                          |  197 ++
 SourceCode/Bond/Servo/CEqCimModeChangeStep.h                  |   23 
 SourceCode/Bond/Servo/CPanelAttributes.h                      |   41 
 SourceCode/Bond/Servo/CAttribute.cpp                          |   36 
 SourceCode/Bond/Servo/ApredTreeCtrl2.cpp                      |  379 +++++
 SourceCode/Bond/Servo/CEqModeStep.cpp                         |   24 
 SourceCode/Bond/Servo/Servo.vcxproj.filters                   |   22 
 SourceCode/Bond/Servo/CEqStatusStep.cpp                       |   34 
 SourceCode/Bond/Servo/CEquipment.h                            |    6 
 SourceCode/Bond/Servo/Servo.vcxproj                           |   22 
 .gitignore                                                    |    1 
 SourceCode/Bond/Servo/resource.h                              |    0 
 SourceCode/Bond/Servo/Servo.vcxproj.user                      |    2 
 SourceCode/Bond/Servo/HorizontalLine.h                        |   87 +
 SourceCode/Bond/Servo/Servo.cpp                               |    3 
 SourceCode/Bond/Servo/CPanelMaster.cpp                        |  207 ++
 SourceCode/Bond/Servo/CEqModeStep.h                           |    6 
 SourceCode/Bond/Servo/CMaster.h                               |    1 
 SourceCode/Bond/Servo/VerticalLine.h                          |   95 +
 SourceCode/Bond/Servo/CEqAlarmStep.h                          |   37 
 SourceCode/Bond/Servo/CStep.h                                 |   22 
 SourceCode/Bond/Servo/AlarmDlg.cpp                            |   16 
 SourceCode/Bond/Servo/AlarmManager.h                          |   28 
 SourceCode/Bond/Servo/CEquipment.cpp                          |   25 
 SourceCode/Bond/Servo/Model.h                                 |    1 
 SourceCode/Bond/Servo/CMaster.cpp                             |   44 
 SourceCode/Bond/x64/Debug/Res/panel_close_24_b.ico            |    0 
 SourceCode/Bond/Servo/CEqCimModeChangeStep.cpp                |   45 
 SourceCode/Bond/Servo/CStep.cpp                               |  166 --
 SourceCode/Bond/Servo/ToolUnits.h                             |    1 
 SourceCode/Bond/Servo/CReadStep.cpp                           |  187 ++
 SourceCode/Bond/Servo/CWriteStep.h                            |   38 
 SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h   |  412 ++--
 SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp |  442 +++---
 SourceCode/Bond/Servo/CEqAlarmStep.cpp                        |   55 
 SourceCode/Bond/x64/Debug/Res/panel_close_24_a.ico            |    0 
 SourceCode/Bond/Servo/CPanelEquipment.h                       |   42 
 SourceCode/Bond/Servo/Model.cpp                               |   52 
 SourceCode/Bond/Servo/ServoDlg.cpp                            |  141 +
 SourceCode/Bond/Servo/VerticalLine.cpp                        |  316 ++++
 SourceCode/Bond/Servo/CEqProcessStep.cpp                      |  160 ++
 SourceCode/Bond/Servo/CAttributeVector.h                      |   24 
 SourceCode/Bond/Servo/CAttribute.h                            |   23 
 SourceCode/Bond/Servo/CAttributeVector.cpp                    |   47 
 SourceCode/Bond/Servo/ServoGraph.h                            |    4 
 SourceCode/Bond/Servo/CEqProcessStep.h                        |   37 
 SourceCode/Bond/Servo/Common.h                                |   39 
 59 files changed, 3,658 insertions(+), 683 deletions(-)

diff --git a/.gitignore b/.gitignore
index 1277413..99779f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,3 +48,4 @@
 *.iom
 SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.user
 SourceCode/Bond/x64/Debug/ServoConfiguration.ini
+*.iobj
diff --git a/SourceCode/Bond/Servo/AlarmDlg.cpp b/SourceCode/Bond/Servo/AlarmDlg.cpp
index 6fc3e88..66c14dd 100644
--- a/SourceCode/Bond/Servo/AlarmDlg.cpp
+++ b/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();  // 璋冪敤鍒嗛〉鏇存柊鍑芥暟
-}
\ No newline at end of file
+}
diff --git a/SourceCode/Bond/Servo/AlarmDlg.h b/SourceCode/Bond/Servo/AlarmDlg.h
index 3fbf26d..6755277 100644
--- a/SourceCode/Bond/Servo/AlarmDlg.h
+++ b/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();
diff --git a/SourceCode/Bond/Servo/AlarmManager.h b/SourceCode/Bond/Servo/AlarmManager.h
index f99aafe..1c41797 100644
--- a/SourceCode/Bond/Servo/AlarmManager.h
+++ b/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();
diff --git a/SourceCode/Bond/Servo/ApredTreeCtrl2.cpp b/SourceCode/Bond/Servo/ApredTreeCtrl2.cpp
new file mode 100644
index 0000000..92956c6
--- /dev/null
+++ b/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);
+	}
+}
diff --git a/SourceCode/Bond/Servo/ApredTreeCtrl2.h b/SourceCode/Bond/Servo/ApredTreeCtrl2.h
new file mode 100644
index 0000000..68f5310
--- /dev/null
+++ b/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();
+};
+
diff --git a/SourceCode/Bond/Servo/CAttribute.cpp b/SourceCode/Bond/Servo/CAttribute.cpp
new file mode 100644
index 0000000..468ebf2
--- /dev/null
+++ b/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;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CAttribute.h b/SourceCode/Bond/Servo/CAttribute.h
new file mode 100644
index 0000000..5c96b72
--- /dev/null
+++ b/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;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CAttributeVector.cpp b/SourceCode/Bond/Servo/CAttributeVector.cpp
new file mode 100644
index 0000000..6d9213a
--- /dev/null
+++ b/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];
+	}
+}
diff --git a/SourceCode/Bond/Servo/CAttributeVector.h b/SourceCode/Bond/Servo/CAttributeVector.h
new file mode 100644
index 0000000..c3b9b34
--- /dev/null
+++ b/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;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
index 61f9245..141634c 100644
--- a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
+++ b/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;
 
-        // 浣跨敤鍒嗛殧绗� "|" 瑙f瀽姣忎竴琛�
+        // 使用分隔符 "|" 解析每一行
         if (std::getline(iss, strToken, '|')) {
             nCode = std::stoi(strToken);
         }
@@ -200,7 +200,7 @@
     return true;
 }
 
-// 杩炴帴鍒癙LC
+// 连接到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;
 }
 
-// 鏉縇ED璇诲彇
+// 板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();
 
-        // 灏嗗瓧鏁版嵁瑙f瀽涓轰綅鏁版嵁
+        // 将字数据解析为位数据
         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;
 }
 
-// 杩滅▼绔欑殑缂撳啿瀛樺偍鍣ㄨ鍙� 瀵硅薄绔橧P鍦板潃鎸囧畾
+// 远程站的缓冲存储器读取 对象站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;
 }
 
-// 杩滅▼绔欑殑缂撳啿瀛樺偍鍣ㄥ啓鍏� 瀵硅薄绔橧P鍦板潃鎸囧畾
+// 远程站的缓冲存储器写入 对象站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;
 }
 
-//============================================闈欐�佽緟鍔╁嚱鏁�====================================================
-// 寤舵椂锛屽苟涓旇浆鍙戠獥鍙f秷鎭�
+//============================================静态辅助函数====================================================
+// 延时,并且转发窗口消息
 void CPerformanceMelsec::Delay(const unsigned int nDelayMs) {
     MSG message;
-    // 濡傛灉寤惰繜鏃堕棿涓� 0锛屼粎澶勭悊涓�娆℃秷鎭槦鍒�
+    // 如果延迟时间为 0,仅处理一次消息队列
     if (nDelayMs == 0) {
-        // 闈為樆濉炵殑妫�鏌ユ秷鎭槦鍒�
+        // 非阻塞的检查消息队列
         if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
-            TranslateMessage(&message);  // 灏嗘秷鎭浆鍖栦负鏈夋晥鐨勭獥鍙f秷鎭�
-            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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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));
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
index 07a4b32..a6020c4 100644
--- a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
+++ b/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銆丩X銆丩Y銆丩B銆丩W銆丩SB銆丩SW鍜孲PG杞厓浠堕兘鏄寖鍥村瀷
-	 * ER锛欴evER0锝�256
-	 * LX锛欴evLX1锝�255锛孌evLX(x)	(DevX*1000+(x))
-	 * LY锛欴evLY1锝�255锛孌evLY(x)	(DevY*1000+(x))
-	 * LB锛欴evLB1锝�255锛孌evLB(x)	(DevB*1000+(x))
-	 * LW锛欴evLW1锝�255锛孌evLW(x)	(DevW*1000+(x))
-	 * LSB锛欴evLSB1锝�255锛孌evLSB(x) (DevQSB*1000+(x))
-	 * LSW锛欴evLSW1锝�255锛孌evLSW(x) (DevQSW*1000+(x))
-	 * SPG锛欴evSPG0锝�255锛孌evSPG(x) (29*1000+(x))
-	 * 鎵╁睍鏂囦欢瀵勫瓨鍣ㄤ唬鐮佹寚瀹�(10杩涘埗鏁�)鐨勫悗3浣嶆暟鍙婅蒋鍏冧欢鍚嶆寚瀹氱殑鏁板�间腑锛屽簲鎸囧畾鍧桸o.(0锝�256)
-	 * 閾炬帴鐩存帴杞厓浠朵唬鐮佹寚瀹�(10杩涘埗鏁�)鐨勫悗3浣嶆暟鍙婅蒋鍏冧欢鍚嶆寚瀹氱殑鏁板�间腑锛屽簲鎸囧畾缃戠粶No.(1锝�255)
-	 * 鏅鸿兘鍔熻兘妯″潡杞厓浠朵唬鐮佹寚瀹�(10杩涘埗鏁�)鐨勫悗3浣嶆暟鍙婅蒋鍏冧欢鍚嶆寚瀹氱殑鏁板�间腑锛屽簲鎸囧畾(璧峰I/ONo.梅16)鐨勫��
-	 * 鎵╁睍鏂囦欢瀵勫瓨鍣ㄥ拰閾炬帴鐩存帴杞厓浠跺湪闅忔満璇诲彇(mdRandR銆乵dRandREx)鍑芥暟涓紝鍗充娇鎸囧畾瀹為檯涓嶅瓨鍦ㄧ殑杞厓浠朵篃鏈夊彲鑳芥甯哥粨鏉�
-	 * MAIL鍜孧AILMC鍦⊿END鍔熻兘鍙奟ECV鍔熻兘涓紝涓庤蒋鍏冧欢璁块棶涓�鏍凤紝鎸囧畾鍚勫姛鑳藉搴旂殑杞厓浠剁被鍨嬶紝杩涜鏁版嵁鐨勫彂閫�(mdSend銆乵dSendEx)鎴栨暟鎹殑璇诲彇(mdReceive銆乵dReceiveEx)
+	 * 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銆乵dRandREx)鍑芥暟涓紝鍗充娇鎸囧畾瀹為檯涓嶅瓨鍦ㄧ殑杞厓浠朵篃鏈夊彲鑳芥甯哥粨鏉熴��(璇诲彇鏁版嵁涓嶆纭��))
-	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位)
 };
 
-// 鎺у埗浠g爜
+// 控制代码
 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];    // 涓ょ鍙e瓨鍌ㄥ櫒鍗犵敤瀹归噺
-	char twoPortAttribute[2]; // 涓ょ鍙e睘鎬�
-	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;    // 缃戠粶缂栧彿锛歅LC鎵�杩炴帴鐨勭綉缁滅紪鍙凤紝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; 		// 存储事件详情信息
 
-	// 瑙f瀽浜嬩欢璇︽儏锛岃繑鍥炴牸寮忓寲瀛楃涓�
+	// 解析事件详情,返回格式化字符串
 	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;
 
-		// 浣跨敤鍒嗛殧绗� "|" 瑙f瀽瀛楃涓�
+		// 使用分隔符 "|" 解析字符串
 		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 绫诲0鏄�
+// 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();
 
-	// 鏉縇ED璇诲彇
+	// 板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);
 
-	// 浜嬩欢绛夊緟锛寁ecEventNumbers[0, 64]锛宯TimeoutMs[-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);						// 寤舵椂锛屽苟涓旇浆鍙戠獥鍙f秷鎭�
-	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
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CEqAlarmStep.cpp b/SourceCode/Bond/Servo/CEqAlarmStep.cpp
index 0b42394..67247eb 100644
--- a/SourceCode/Bond/Servo/CEqAlarmStep.cpp
+++ b/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;
 	}
 }
diff --git a/SourceCode/Bond/Servo/CEqAlarmStep.h b/SourceCode/Bond/Servo/CEqAlarmStep.h
index 98cc3bc..7c33958 100644
--- a/SourceCode/Bond/Servo/CEqAlarmStep.h
+++ b/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;
diff --git a/SourceCode/Bond/Servo/CEqCimModeChangeStep.cpp b/SourceCode/Bond/Servo/CEqCimModeChangeStep.cpp
new file mode 100644
index 0000000..9e2d40c
--- /dev/null
+++ b/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(), ""));
+	}
+}
diff --git a/SourceCode/Bond/Servo/CEqCimModeChangeStep.h b/SourceCode/Bond/Servo/CEqCimModeChangeStep.h
new file mode 100644
index 0000000..22afc6a
--- /dev/null
+++ b/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;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqModeStep.cpp b/SourceCode/Bond/Servo/CEqModeStep.cpp
index 888117b..3b416b2 100644
--- a/SourceCode/Bond/Servo/CEqModeStep.cpp
+++ b/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
diff --git a/SourceCode/Bond/Servo/CEqModeStep.h b/SourceCode/Bond/Servo/CEqModeStep.h
index c91c5fa..1bc611d 100644
--- a/SourceCode/Bond/Servo/CEqModeStep.h
+++ b/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:
diff --git a/SourceCode/Bond/Servo/CEqProcessStep.cpp b/SourceCode/Bond/Servo/CEqProcessStep.cpp
new file mode 100644
index 0000000..f566e43
--- /dev/null
+++ b/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();
+	}
+}
diff --git a/SourceCode/Bond/Servo/CEqProcessStep.h b/SourceCode/Bond/Servo/CEqProcessStep.h
new file mode 100644
index 0000000..d16a5a0
--- /dev/null
+++ b/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;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CEqStatusStep.cpp b/SourceCode/Bond/Servo/CEqStatusStep.cpp
index 9df8a03..b525e6f 100644
--- a/SourceCode/Bond/Servo/CEqStatusStep.cpp
+++ b/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;
diff --git a/SourceCode/Bond/Servo/CEqStatusStep.h b/SourceCode/Bond/Servo/CEqStatusStep.h
index 09fc8f4..f99e813 100644
--- a/SourceCode/Bond/Servo/CEqStatusStep.h
+++ b/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:
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 2c6b8e6..3fa85bb 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/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)
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index 2bdbc4d..c13e71e 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/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;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 82d77ca..7040c70 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/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();
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index 73ae99b..0fefda3 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/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:
diff --git a/SourceCode/Bond/Servo/CPanelAttributes.cpp b/SourceCode/Bond/Servo/CPanelAttributes.cpp
new file mode 100644
index 0000000..fb2200b
--- /dev/null
+++ b/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);
+}
diff --git a/SourceCode/Bond/Servo/CPanelAttributes.h b/SourceCode/Bond/Servo/CPanelAttributes.h
new file mode 100644
index 0000000..5c00465
--- /dev/null
+++ b/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();
+};
diff --git a/SourceCode/Bond/Servo/CPanelEquipment.cpp b/SourceCode/Bond/Servo/CPanelEquipment.cpp
new file mode 100644
index 0000000..533e77f
--- /dev/null
+++ b/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);
+}
diff --git a/SourceCode/Bond/Servo/CPanelEquipment.h b/SourceCode/Bond/Servo/CPanelEquipment.h
new file mode 100644
index 0000000..460e858
--- /dev/null
+++ b/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();
+};
diff --git a/SourceCode/Bond/Servo/CPanelMaster.cpp b/SourceCode/Bond/Servo/CPanelMaster.cpp
new file mode 100644
index 0000000..014819d
--- /dev/null
+++ b/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;
+}
diff --git a/SourceCode/Bond/Servo/CPanelMaster.h b/SourceCode/Bond/Servo/CPanelMaster.h
new file mode 100644
index 0000000..bea8068
--- /dev/null
+++ b/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);
+};
diff --git a/SourceCode/Bond/Servo/CReadStep.cpp b/SourceCode/Bond/Servo/CReadStep.cpp
new file mode 100644
index 0000000..0a2474f
--- /dev/null
+++ b/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;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CReadStep.h b/SourceCode/Bond/Servo/CReadStep.h
new file mode 100644
index 0000000..2b0df3b
--- /dev/null
+++ b/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地址
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/CStep.cpp b/SourceCode/Bond/Servo/CStep.cpp
index 2e43de3..dbbf161 100644
--- a/SourceCode/Bond/Servo/CStep.cpp
+++ b/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();
 	}
 }
 
diff --git a/SourceCode/Bond/Servo/CStep.h b/SourceCode/Bond/Servo/CStep.h
index 628f116..04aa2c1 100644
--- a/SourceCode/Bond/Servo/CStep.h
+++ b/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地址
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CWriteStep.cpp b/SourceCode/Bond/Servo/CWriteStep.cpp
new file mode 100644
index 0000000..15f6a2a
--- /dev/null
+++ b/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;
+	}
+}
diff --git a/SourceCode/Bond/Servo/CWriteStep.h b/SourceCode/Bond/Servo/CWriteStep.h
new file mode 100644
index 0000000..6bb6b30
--- /dev/null
+++ b/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;
+	};
+}
+
diff --git a/SourceCode/Bond/Servo/Common.h b/SourceCode/Bond/Servo/Common.h
index 7aeb6aa..92d40c2 100644
--- a/SourceCode/Bond/Servo/Common.h
+++ b/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
\ No newline at end of file
+#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
diff --git a/SourceCode/Bond/Servo/HorizontalLine.cpp b/SourceCode/Bond/Servo/HorizontalLine.cpp
new file mode 100644
index 0000000..fc48b76
--- /dev/null
+++ b/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;
+}
+
+
diff --git a/SourceCode/Bond/Servo/HorizontalLine.h b/SourceCode/Bond/Servo/HorizontalLine.h
new file mode 100644
index 0000000..f5b3647
--- /dev/null
+++ b/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_)
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 38ad39f..729bf8d 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/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);
+}
diff --git a/SourceCode/Bond/Servo/Model.h b/SourceCode/Bond/Servo/Model.h
index 6e2655c..3b92364 100644
--- a/SourceCode/Bond/Servo/Model.h
+++ b/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);
diff --git a/SourceCode/Bond/Servo/Servo.cpp b/SourceCode/Bond/Servo/Servo.cpp
index 4b49603..4a492c8 100644
--- a/SourceCode/Bond/Servo/Servo.cpp
+++ b/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库
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 228ffdd..d4dd065 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 1e7a588..15c767a 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/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" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 06cd13e..c1113c1 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/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" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.user b/SourceCode/Bond/Servo/Servo.vcxproj.user
index 3980fd1..86e9faf 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.user
+++ b/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>
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index bb7deba..90ee383 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/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;
+}
+
diff --git a/SourceCode/Bond/Servo/ServoDlg.h b/SourceCode/Bond/Servo/ServoDlg.h
index dc5314e..39ae6d7 100644
--- a/SourceCode/Bond/Servo/ServoDlg.h
+++ b/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);
 };
diff --git a/SourceCode/Bond/Servo/ServoGraph.cpp b/SourceCode/Bond/Servo/ServoGraph.cpp
index daf274a..63bfab7 100644
--- a/SourceCode/Bond/Servo/ServoGraph.cpp
+++ b/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;
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/ServoGraph.h b/SourceCode/Bond/Servo/ServoGraph.h
index d409660..3dc0518 100644
--- a/SourceCode/Bond/Servo/ServoGraph.h
+++ b/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);
diff --git a/SourceCode/Bond/Servo/ToolUnits.cpp b/SourceCode/Bond/Servo/ToolUnits.cpp
index 664f802..a3e1725 100644
--- a/SourceCode/Bond/Servo/ToolUnits.cpp
+++ b/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;
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/ToolUnits.h b/SourceCode/Bond/Servo/ToolUnits.h
index 9e8fdfb..d010744 100644
--- a/SourceCode/Bond/Servo/ToolUnits.h
+++ b/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);
 };
 
diff --git a/SourceCode/Bond/Servo/VerticalLine.cpp b/SourceCode/Bond/Servo/VerticalLine.cpp
new file mode 100644
index 0000000..319e508
--- /dev/null
+++ b/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;
+}
+
diff --git a/SourceCode/Bond/Servo/VerticalLine.h b/SourceCode/Bond/Servo/VerticalLine.h
new file mode 100644
index 0000000..d27f7b6
--- /dev/null
+++ b/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_)
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 2afa563..f5ef8b0 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ
diff --git a/SourceCode/Bond/x64/Debug/Res/panel_close_24_a.ico b/SourceCode/Bond/x64/Debug/Res/panel_close_24_a.ico
new file mode 100644
index 0000000..8950fff
--- /dev/null
+++ b/SourceCode/Bond/x64/Debug/Res/panel_close_24_a.ico
Binary files differ
diff --git a/SourceCode/Bond/x64/Debug/Res/panel_close_24_b.ico b/SourceCode/Bond/x64/Debug/Res/panel_close_24_b.ico
new file mode 100644
index 0000000..5df3daa
--- /dev/null
+++ b/SourceCode/Bond/x64/Debug/Res/panel_close_24_b.ico
Binary files differ

--
Gitblit v1.9.3