From a3943d169515d841e70c57703cbd9fcbf5409a5a Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期一, 04 八月 2025 17:59:52 +0800
Subject: [PATCH] 1. SGMeasurement模块添加CC-Link通信 2. SGMeasurement模块添加PLC交互

---
 SourceCode/Bond/SGMeasurement/PLCSignalListener.h                     |   56 +
 SourceCode/Bond/SGMeasurement/SGMeasurementDlg.h                      |   10 
 SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.cpp   |  104 ++
 SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp                    |   52 +
 SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.h     |   70 +
 SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.cpp | 1572 ++++++++++++++++++++++++++++++++++++
 SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp                   |  203 ++++
 SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.h   |  479 +++++++++++
 8 files changed, 2,546 insertions(+), 0 deletions(-)

diff --git a/SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.cpp b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.cpp
new file mode 100644
index 0000000..42b6f63
--- /dev/null
+++ b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.cpp
@@ -0,0 +1,104 @@
+#include "pch.h"
+#include "CCLinkIEControl.h"
+
+CCCLinkIEControl::CCCLinkIEControl() : CPerformanceMelsec(BoardType::CC_LINK_IE_CONTROL) {}
+
+CCCLinkIEControl::~CCCLinkIEControl() = default;
+
+int CCCLinkIEControl::SetBoardModeEx(CCLinkIEControlMode mode) {
+    return SetBoardMode(static_cast<short>(mode));
+}
+
+CCLinkIEControlMode CCCLinkIEControl::GetBoardModeEx() {
+    short nMode = 0;
+    const int nResult = GetBoardMode(nMode);
+    if (nResult != 0) {
+        return CCLinkIEControlMode::UNKNOWN;
+    }
+
+    return ConvertToCCLinkIEControlMode(nMode);
+}
+
+int CCCLinkIEControl::GetBoardStatusEx(BoardStatus& status) {
+    const int nResult = GetBoardStatus(status);
+    if (nResult != 0) {
+        return nResult;
+    }
+
+    return ValidateBoardStatus(status);
+}
+
+int CCCLinkIEControl::ReadLedStatus(LedStatus& outLedStatus) {
+    std::vector<short> vecLedBuffer;
+    const int nRet = ReadBoardLed(vecLedBuffer);
+    if (nRet != 0) {
+        return nRet;
+    }
+
+    if (vecLedBuffer.empty()) {
+        UpdateLastError(ERROR_CODE_INVALID_DATA);
+        return ERROR_CODE_INVALID_DATA;
+    }
+
+    // 解析各位状态
+    const short nBuffer = vecLedBuffer[0];
+    outLedStatus.bExtPw = (nBuffer & (1 << 15)) != 0;
+    outLedStatus.bRd = (nBuffer & (1 << 6)) != 0;
+    outLedStatus.bDLnk = (nBuffer & (1 << 5)) != 0;
+    outLedStatus.bPrm = (nBuffer & (1 << 4)) != 0;
+    outLedStatus.bErr = (nBuffer & (1 << 3)) != 0;
+    outLedStatus.bSd = (nBuffer & (1 << 2)) != 0;
+    outLedStatus.bMode = (nBuffer & (1 << 1)) != 0;
+    outLedStatus.bRun = (nBuffer & (1 << 0)) != 0;
+
+    return 0;
+}
+
+CCLinkIEControlMode CCCLinkIEControl::ConvertToCCLinkIEControlMode(const short nMode) {
+    switch (static_cast<CCLinkIEControlMode>(nMode)) {
+        case CCLinkIEControlMode::ONLINE: return CCLinkIEControlMode::ONLINE;                           // 在线
+        case CCLinkIEControlMode::OFFLINE: return CCLinkIEControlMode::OFFLINE;                         // 离线
+        case CCLinkIEControlMode::INTER_STATION_TEST: return CCLinkIEControlMode::INTER_STATION_TEST;   // 站间测试
+        case CCLinkIEControlMode::LINE_TEST: return CCLinkIEControlMode::LINE_TEST;                     // 线路测试
+        case CCLinkIEControlMode::LOOPBACK_TEST: return CCLinkIEControlMode::LOOPBACK_TEST;             // 自回送测试
+        case CCLinkIEControlMode::HW_TEST: return CCLinkIEControlMode::HW_TEST;                         // H/W测试
+        case CCLinkIEControlMode::BUS_IF_TEST: return CCLinkIEControlMode::BUS_IF_TEST;                 // 总线I/F测试
+        default: return CCLinkIEControlMode::UNKNOWN;
+    }
+}
+
+int CCCLinkIEControl::ValidateBoardStatus(const BoardStatus& status) {
+    if (status.nStationValue < 1 || status.nStationValue > 120) {
+        return ERROR_CODE_STATION_OUT_OF_RANGE; // 站号超出范围
+    }
+    if (status.nGroupValue < 0 || status.nGroupValue > 32) {
+        return ERROR_CODE_GROUP_OUT_OF_RANGE;   // 组超出范围
+    }
+    if (status.nNetworkValue < 1 || status.nNetworkValue > 239) {
+        return ERROR_CODE_NETWORK_OUT_OF_RANGE; // 网络号超出范围
+    }
+    return 0; // 校验通过
+}
+
+int CCCLinkIEControl::ReadDataEx(const StationIdentifier& station, DeviceType enDevType, long devNo, long size, void* pData)
+{
+    // 验证站点参数和数据有效性
+    int nRet = ValidateStationAndSize(station, static_cast<short>(size));
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    // 确保线程安全的最小锁定范围
+    {
+        std::lock_guard<std::mutex> lock(m_mtx);
+        const short nDevType = CalculateDeviceType(station, enDevType);
+        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, devNo, &size, pData);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+    }
+
+    return nRet;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.h b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.h
new file mode 100644
index 0000000..703780b
--- /dev/null
+++ b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/CCLinkIEControl.h
@@ -0,0 +1,70 @@
+#ifndef CCLINKIECONTROL_H
+#define CCLINKIECONTROL_H
+
+#include "PerformanceMelsec.h"
+
+enum class CCLinkIEControlMode : short {
+    UNKNOWN = 0x0194,               // 未知
+    ONLINE = 0x0000,                // 在线
+    OFFLINE = 0x0002,               // 离线
+    INTER_STATION_TEST = 0x0005,    // 站间测试
+    LINE_TEST = 0x0006,             // 线路测试
+    LOOPBACK_TEST = 0x0007,         // 自回送测试
+    HW_TEST = 0x0009,               // H/W测试
+    BUS_IF_TEST = 0x000E            // 总线I/F测试
+};
+
+class CCCLinkIEControl final : public CPerformanceMelsec {
+public:
+    CCCLinkIEControl();
+    ~CCCLinkIEControl() override;
+
+    struct LedStatus {
+        bool bExtPw; // 外部电源状态 (b15)
+        bool bRd;    // 数据接收状态 (b6)
+        bool bDLnk;  // 数据链接状态 (b5)
+        bool bPrm;   // 管理功能状态 (b4)
+        bool bErr;   // 错误状态 (b3)
+        bool bSd;    // 数据发送状态 (b2)
+        bool bMode;  // 动作模式 (b1)
+        bool bRun;   // 运行状态 (b0)
+
+        // 转换为字符串,用于调试
+        std::string ToString() const {
+            std::ostringstream oss;
+            oss << "CC-Link IE Control Network LED Status: {"
+                << "\n  Ext Power: " << (bExtPw ? "ON" : "OFF")
+                << "\n  Receive Data: " << (bRd ? "Receiving" : "Not Receiving")
+                << "\n  Data Link: " << (bDLnk ? "Linked" : "Not Linked")
+                << "\n  Management: " << (bPrm ? "Managing" : "Not Managing")
+                << "\n  Error: " << (bErr ? "Error Detected" : "No Error")
+                << "\n  Send Data: " << (bSd ? "Sending" : "Not Sending")
+                << "\n  Mode: " << (bMode ? "Executing" : "Not Executing")
+                << "\n  Run: " << (bRun ? "Running" : "Stopped")
+                << "\n}";
+            return oss.str();
+        }
+    };
+
+    // 读取目标站点CPU类型
+    // short ReadCPUCodeEx(const StationIdentifier& station, short& nCPUCode);
+
+    // 板模式获取/设置
+    int SetBoardModeEx(CCLinkIEControlMode mode);
+    CCLinkIEControlMode GetBoardModeEx();
+
+    // 获取板状态
+    int GetBoardStatusEx(BoardStatus& status);
+
+    // 读取LED状态
+    int ReadLedStatus(LedStatus& outLedStatus);
+
+    int ReadDataEx(const StationIdentifier& station, DeviceType enDevType, long devNo, long size, void* pData);
+
+private:
+    static CCLinkIEControlMode ConvertToCCLinkIEControlMode(short nMode);
+    static int ValidateBoardStatus(const BoardStatus& status);
+};
+
+
+#endif //CCLINKIECONTROL_H
diff --git a/SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.cpp b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.cpp
new file mode 100644
index 0000000..58b229a
--- /dev/null
+++ b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.cpp
@@ -0,0 +1,1572 @@
+// PerformanceMelsec.cpp: implementation of the CPerformanceMelsec class.
+//
+//////////////////////////////////////////////////////////////////////
+#include "pch.h"
+#include "PerformanceMelsec.h"
+#include <windows.h>
+#include <iostream>
+#include <fstream>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char* THIS_FILE = __FILE__;
+#define new DEBUG_NEW
+#endif
+
+#ifdef _DEBUG
+#define LOG_ERROR(msg) \
+std::cerr << "[ERROR] " << __FILE__ << ":" << __LINE__ << " (" << __FUNCTION__ << ") - " << msg << std::endl;
+#define LOG_DEBUG(msg) \
+std::cout << "[DEBUG] " << __FILE__ << ":" << __LINE__ << " (" << __FUNCTION__ << ") - " << msg << std::endl;
+#else
+#define LOG_ERROR(msg)
+#define LOG_DEBUG(msg)
+#endif
+
+// 初始化静态成员变量
+std::unordered_map<int, std::string> CPerformanceMelsec::m_mapError = {
+    // 板块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."},
+    {66, "Already OPEN error. The specified channel is OPEN."},
+    {68, "Path error. The specified path is invalid."},
+    {69, "Unsupported function execution error."},
+    {70, "Station number error. The specified station number is invalid."},
+    {71, "No received data error (during RECV function)."},
+    {77, "Memory allocation error / insufficient memory resources."},
+    {85, "SEND/RECV channel number error."},
+    {100, "Board H/W resource busy."},
+    {101, "Routing exception."},
+    {102, "Board driver I/F error: Failed to send request data to the board driver."},
+    {103, "Board driver I/F error: Failed to receive response data from the board driver."},
+    {130, "Initial software component No. Error."},
+    {131, "Capacity error."},
+    {133, "Parameter error."},
+    {16385, "Specified target station number does not exist."},
+    {16386, "Received a request that the target station cannot process."},
+    {16418, "Failed to create the event history file."},
+    {16420, "Failed to access the event history file."},
+    {16421, "Another board driver is using the event history file."},
+    {16432, "The specified soft component type does not exist."},
+    {16433, "Soft component specification error: Out of range or invalid start I/O or block number."},
+    {16512, "Request data exception: Invalid data or unsupported module."},
+    {16685, "File association error: Failed to create the event history file."},
+    {16837, "File association error: Event history file does not exist."},
+    {18944, "Link association error: Network does not exist, unsupported CPU, or incorrect network No./station number."},
+    {-1, "Invalid path. The specified function is not supported for this path."},
+    {-2, "Start component No. error. The specified component is out of range."},
+    {-3, "Capacity error. The capacity exceeds the component range."},
+    {-6, "Component type error. The specified type during write is invalid."},
+    {-8, "Channel No. error. The channel specified is invalid."},
+    {-12, "Target path error. The specified path points to an invalid target."},
+    {-13, "Write protection area error. The specified range is protected."},
+    {-16, "Target path conflict. The path conflicts with write protection settings."},
+    {-17, "Device not found or target not responding."},
+    {-18, "Invalid target. The device does not support the operation."},
+    {-19, "Invalid path operation. An unsupported path operation was executed."},
+    {-31, "DLL library call failed or path not initialized."},
+    {-32, "Resource timeout error. Communication timed out or exceeded resource limits."},
+    {-33, "Communication timeout error. The target is not responding or timed out."},
+    {-34, "Unsupported communication target error. The specified network No. or station No. points to an unsupported model."},
+    {-35, "Registry access error."},
+    {-36, "Registry access error."},
+    {-37, "Communication initialization error. The settings for initializing the communication path are invalid."},
+    {-42, "Key information error. Authentication failed."},
+    {-43, "Marking event error. TC waiting event write was executed on the CPU."},
+    {-61, "Marking event error. TC waiting event write was executed on the CPU."},
+    {-62, "Event waiting timeout. The specified external event waiting timed out."},
+    {-63, "Timeout value is out of range."},
+    {-64, "Timeout value is out of range."},
+    {-65, "Event waiting timeout. The specified external event waiting timed out."},
+    {-66, "Timeout-induced resource shortage."},
+    {-67, "Irrelevant file access execution error."},
+    {-69, "Operation executed, but the module does not support the function."},
+    {-70, "The target event processing module returned a rejection."},
+    {-71, "The remote station did not return data correctly."},
+    {-72, "Pointer error. The specified pointer value is invalid."},
+    {-73, "Specified address error."},
+    {-2174, "Buffer data queue exception occurred. Read/write exception to device."},
+    {-7656, "Buffer data queue exception. Read/write exception to the device."},
+    {-7672, "Buffer data queue exception. Read/write exception to the device."},
+    {-11683, "Buffer data transfer error."},
+    {-11717, "Network No. error."},
+    {-11746, "Station No. error."},
+    {-12128, "Buffer data send/response error."},
+    {-18560, "Module mode setting error."},
+    {-18572, "Communication method error."},
+    {-25056, "Processor error."},
+    {-26334, "Duplicate program call or illegal CPU operation."},
+    {-26336, "Routing request error to a station without routing function support."},
+    {-27902, "Event register timeout error."},
+    {-28079, "Communication No. read error."},
+    {-28080, "Communication No. incorrect error."},
+    {-28136, "Unsupported function in fast mode error."},
+    {-28139, "Link disconnection error."},
+    {-28140, "Incorrect mode setting error."},
+    {-28141, "System reboot error."},
+    {-28142, "Mode error."},
+    {-28143, "Hardware self-diagnosis error."},
+    {-28144, "Hardware self-diagnosis error."},
+    {-28150, "Data reception interruption at remote station error."},
+    {-28151, "Data reception interruption at remote station error."},
+    {-28153, "Data reception interruption at remote station error."},
+    {-28154, "Abnormal data reception error."},
+    {-28158, "Driver WDT error."},
+    {-28160, "Hardware resource error."},
+    {-28622, "Dedicated instruction channel in-use error."},
+    {-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."},
+    {ERROR_CODE_INVALID_DATA, "Error: Invalid data provided."},
+    {ERROR_CODE_STATION_OUT_OF_RANGE, "Error: Station number is out of range."},
+    {ERROR_CODE_GROUP_OUT_OF_RANGE, "Error: Group number is out of range."},
+    {ERROR_CODE_NETWORK_OUT_OF_RANGE, "Error: Network number is out of range."}
+};
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+CPerformanceMelsec::CPerformanceMelsec(const BoardType enBoardType) {
+    m_nPath = 0;
+    m_enBoardType = enBoardType;
+    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 并将每个错误信息写入文件
+    for (const auto& entry : m_mapError) {
+        const int nCode = entry.first;
+        const std::string& strMessage = entry.second;
+        file << nCode << "|" << strMessage << "\n";
+    }
+    file.close();
+
+    return true;
+}
+
+// 加载错误信息
+bool CPerformanceMelsec::LoadErrorInfoFromFile(const std::string& filename) {
+    std::ifstream inFile(filename);
+    if (!inFile.is_open()) {
+        std::cerr << "Failed to open file for loading: " << filename << std::endl;
+        return false;
+    }
+
+    m_mapError.clear();
+    std::string line;
+    while (std::getline(inFile, line)) {
+        std::istringstream iss(line);
+        int nCode = 0;
+        std::string strToken;
+        std::string strMessage;
+
+        // 使用分隔符 "|" 解析每一行
+        if (std::getline(iss, strToken, '|')) {
+            nCode = std::stoi(strToken);
+        }
+
+        if (std::getline(iss, strToken)) {
+            strMessage = strToken;
+        }
+
+        if (!strMessage.empty()) {
+            m_mapError[nCode] = strMessage;
+        }
+    }
+
+    return true;
+}
+
+// 连接到PLC
+int CPerformanceMelsec::Connect(const short nChannel, const short nMode) {
+    std::lock_guard<std::mutex> lock(m_mtx);
+
+    if (m_bConnected.load()) {
+        return 0;
+    }
+
+    const BoardType enBoardType = FindBoardTypeByChannel(nChannel);
+    if (enBoardType == BoardType::UNKNOWN || enBoardType != m_enBoardType) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    // 连接PLC,显式类型转换以匹配 mdOpen 的签名
+    const short nRet = mdOpen(nChannel, nMode, &m_nPath);
+    if (nRet == 0) {
+        m_bConnected.store(true);
+        m_enBoardType = enBoardType;
+    }
+    else {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 断开连接
+int CPerformanceMelsec::Disconnect() {
+    std::lock_guard<std::mutex> lock(m_mtx);
+
+    short nRet = 0;
+    if (m_bConnected.load()) {
+        nRet = mdClose(m_nPath);
+        m_bConnected.store(false);
+        m_nPath = 0;
+    }
+
+    UpdateLastError(nRet);
+    LOG_DEBUG("Close connect.");
+
+    return nRet;
+}
+
+// 可编程控制器软元件信息表的初始化
+int CPerformanceMelsec::InitializeController() {
+    std::lock_guard<std::mutex> lock(m_mtx);
+
+    if (!m_bConnected.load()) {
+        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
+        return ERROR_CODE_NOT_CONNECTED;
+    }
+
+    const short nRet = mdInit(m_nPath);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    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) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+        return nRet;
+    }
+
+    // 填充版本信息到结构体
+    version.fixedValue[0] = static_cast<char>(buf[0] & 0xFF);
+    version.fixedValue[1] = static_cast<char>((buf[0] >> 8) & 0xFF);
+
+    version.checksum[0] = static_cast<char>(buf[1] & 0xFF);
+    version.checksum[1] = static_cast<char>((buf[1] >> 8) & 0xFF);
+
+    version.swVersion[0] = static_cast<char>(buf[2] & 0xFF);
+    version.swVersion[1] = static_cast<char>((buf[2] >> 8) & 0xFF);
+
+    std::memcpy(version.date, &buf[3], 6);
+
+    version.reserved = static_cast<uint32_t>(buf[6]) | (static_cast<uint32_t>(buf[7]) << 16);
+
+    std::memcpy(version.swModel, &buf[8], 16);
+    std::memcpy(version.hwModel, &buf[16], 16);
+
+    version.twoPortMemory[0] = static_cast<char>(buf[18] & 0xFF);
+    version.twoPortMemory[1] = static_cast<char>((buf[18] >> 8) & 0xFF);
+
+    version.twoPortAttribute[0] = static_cast<char>(buf[19] & 0xFF);
+    version.twoPortAttribute[1] = static_cast<char>((buf[19] >> 8) & 0xFF);
+
+    version.availableBias[0] = static_cast<char>(buf[20] & 0xFF);
+    version.availableBias[1] = static_cast<char>((buf[20] >> 8) & 0xFF);
+
+    std::memcpy(version.moduleType, &buf[21], 10);
+
+    return nRet;
+}
+
+// 读取目标站点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);
+        nRet = mdTypeRead(m_nPath, CombineStation(station), &nCPUCode);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    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);
+        nRet = mdBdModSet(m_nPath, nMode);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 获取板模式
+int CPerformanceMelsec::GetBoardMode(short& nMode) {
+    // 检查是否已经连接
+    if (!m_bConnected.load()) {
+        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
+        return ERROR_CODE_NOT_CONNECTED;
+    }
+
+    short nRet = 0;
+    {
+        nMode = 0;
+        std::lock_guard<std::mutex> lock(m_mtx);
+        nRet = mdBdModRead(m_nPath, &nMode);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_DEBUG("Raw Mode: " << nMode);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return 0;
+}
+
+// 板复位
+int CPerformanceMelsec::BoardReset() {
+    std::lock_guard<std::mutex> lock(m_mtx);
+    if (!m_bConnected.load()) {
+        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
+        return ERROR_CODE_NOT_CONNECTED;
+    }
+
+    const short nRet = mdBdRst(m_nPath);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 板LED读取
+int CPerformanceMelsec::ReadBoardLed(std::vector<short>& vecLedBuffer) {
+    std::lock_guard<std::mutex> lock(m_mtx);
+    if (!m_bConnected.load()) {
+        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
+        return ERROR_CODE_NOT_CONNECTED;
+    }
+
+    // 清空 LED 缓冲区
+    vecLedBuffer.clear();
+    vecLedBuffer.resize(16, 0);
+
+    // 调用 SDK 函数读取 LED 数据
+    const short nRet = mdBdLedRead(m_nPath, vecLedBuffer.data());
+    if (nRet != 0) {
+        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
+        LOG_ERROR("Error reading board LED, ErrorCode: " << nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 获取板状态
+int CPerformanceMelsec::GetBoardStatus(BoardStatus& status) {
+    std::lock_guard<std::mutex> lock(m_mtx);
+    if (!m_bConnected) {
+        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
+        return ERROR_CODE_NOT_CONNECTED;
+    }
+
+    short buf[6] = { 0 };
+    const short nRet = mdBdSwRead(m_nPath, buf);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    // 将 buf 映射到结构体
+    status = BoardStatus::fromBuffer(buf);
+    return 0;
+}
+
+// 通用读数据
+int CPerformanceMelsec::ReadData(const StationIdentifier& station, const long nDevType, const long nDevNo, long nSize, std::vector<short>& vecData) {
+    // 验证站点参数和数据有效性
+    int nRet = ValidateStationAndSize(station, static_cast<short>(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();
+        nSize *= sizeof(short);
+        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, (long)(unsigned short)nDevNo, &nSize, pData);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    if (nRet != 0) {
+        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);
+        return nRet;
+    }
+
+    if (nDevNo % 8 != 0) {
+        nRet = -2;
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    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);
+
+    if (nRet == 0) {
+        vecData.clear();
+
+        // 将字数据解析为位数据
+        for (short nIdx = 0; nIdx < nSize; ++nIdx) {
+            const short nCurrentValue = vecTempBuffer[nIdx];
+            // 遍历当前 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;
+}
+
+// 读取字数据
+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);
+        return nRet;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    std::vector<short> vecTempBuffer(nWordCount, 0);
+    nRet = ReadData(station, nDevType, nDevNo, nWordCount, vecTempBuffer);
+
+    if (nRet == 0) {
+        vecData.clear();
+        vecData.assign(vecTempBuffer.begin(), vecTempBuffer.end());
+    }
+
+    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 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); // 线程安全保护
+        ConvertShortToUint32(vecTempBuffer, vecData);
+    }
+
+    return nRet;
+}
+
+// 通用写数据
+int CPerformanceMelsec::WriteData(const StationIdentifier& station, const long nDevType, const long nDevNo, long 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);
+        nRet = mdSendEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, pData);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    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);
+        return nRet;
+    }
+
+    if (nDevNo % 8 != 0) {
+        nRet = -2;
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    const auto nSize = static_cast<short>((static_cast<int>(vecData.size()) + 15) / 16);  // 计算需要写入的字数量(向上取整)
+
+    // 准备临时缓冲区来存储转换后的 16 位数据
+    std::vector<short> vecTempBuffer(nSize, 0);
+    {
+        std::lock_guard<std::mutex> lock(m_mtx); // 线程安全保护
+        // 将位数据按字打包到临时缓冲区
+        for (int i = 0; i < vecData.size(); ++i) {
+            if (vecData[i]) {
+                // 使用 & 0xFFFF 保证不会超过 16 位,防止溢出
+                vecTempBuffer[i / 16] |= static_cast<short>((1 << (i % 16)) & 0xFFFF);
+            }
+        }
+    }
+
+    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 字节)
+    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()));
+
+    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 字节)
+    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); // 线程安全保护
+        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);
+        return nRet;
+    }
+
+    if (nSize < 0) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    nSize = nSize % 2 != 0 ? nSize + 1 : nSize;
+    std::vector<short> vecBuffer(nSize / 2, 0);
+
+    {
+        std::lock_guard<std::mutex> lock(m_mtx); // 线程安全保护
+        nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, vecBuffer.data());
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+    else {
+        std::lock_guard<std::mutex> lock(m_mtx); // 线程安全保护
+        vecData.resize(nSize);
+        ConvertShortToChar(vecBuffer, vecData);
+    }
+
+    return 0;
+}
+
+// 扩展读取位数据
+long CPerformanceMelsec::ReadBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nBitCount, BitContainer& vecData) {
+    long nRet = ValidateStationAndSize(station, static_cast<short>(nBitCount));
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    if (nDevNo % 8 != 0) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    const long nWordCount = (nBitCount + 15) / 16;
+    const long nByteSize = nWordCount * sizeof(short);
+
+    std::vector<char> vecRaw;
+    nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
+    if (nRet != 0) {
+        return nRet;
+    }
+
+    vecData.clear();
+    for (long i = 0; i < nWordCount; ++i) {
+        short word = static_cast<unsigned char>(vecRaw[i * 2]) |
+            (static_cast<unsigned char>(vecRaw[i * 2 + 1]) << 8);
+        for (int j = 0; j < 16; ++j) {
+            vecData.push_back((word & (1 << j)) != 0);
+            if (vecData.size() >= static_cast<size_t>(nBitCount)) {
+                return 0;
+            }
+        }
+    }
+
+    return 0;
+}
+
+// 扩展读取字数据
+long CPerformanceMelsec::ReadWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nWordCount, WordContainer& vecData) {
+    long nRet = ValidateStationAndSize(station, static_cast<short>(nWordCount));
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    const long nByteSize = nWordCount * sizeof(short);
+
+    std::vector<char> vecRaw;
+    nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
+    if (nRet != 0) {
+        return nRet;
+    }
+
+    vecData.clear();
+    for (long i = 0; i < nWordCount; ++i) {
+        short value = static_cast<unsigned char>(vecRaw[i * 2]) |
+            (static_cast<unsigned char>(vecRaw[i * 2 + 1]) << 8);
+        vecData.push_back(value);
+    }
+
+    return 0;
+}
+
+// 扩展读取双字数据
+long CPerformanceMelsec::ReadDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nDWordCount, DWordContainer& vecData) {
+    long nRet = ValidateStationAndSize(station, static_cast<short>(nDWordCount));
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    const long nByteSize = nDWordCount * sizeof(uint32_t);
+
+    std::vector<char> vecRaw;
+    nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
+    if (nRet != 0) {
+        return nRet;
+    }
+
+    vecData.clear();
+    for (long i = 0; i < nDWordCount; ++i) {
+        uint32_t val = static_cast<unsigned char>(vecRaw[i * 4 + 0]) |
+            (static_cast<unsigned char>(vecRaw[i * 4 + 1]) << 8) |
+            (static_cast<unsigned char>(vecRaw[i * 4 + 2]) << 16) |
+            (static_cast<unsigned char>(vecRaw[i * 4 + 3]) << 24);
+        vecData.push_back(val);
+    }
+
+    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 类型的缓冲区
+    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); // 线程安全保护
+        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);
+    }
+
+    return nRet;
+}
+
+// 扩展写位数据
+long CPerformanceMelsec::WriteBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const BitContainer& vecData) {
+    long nRet = ValidateStationAndData(station, vecData);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    if (nDevNo % 8 != 0) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    const size_t nWordCount = (vecData.size() + 15) / 16;
+
+    std::vector<short> vecWordBuffer(nWordCount, 0);
+    for (size_t i = 0; i < vecData.size(); ++i) {
+        if (vecData[i]) {
+            vecWordBuffer[i / 16] |= (1 << (i % 16));
+        }
+    }
+
+    // 转换 short -> char
+    std::vector<char> vecByteBuffer;
+    vecByteBuffer.resize(nWordCount * sizeof(short));
+    for (size_t i = 0; i < nWordCount; ++i) {
+        vecByteBuffer[i * 2] = static_cast<char>(vecWordBuffer[i] & 0xFF);
+        vecByteBuffer[i * 2 + 1] = static_cast<char>((vecWordBuffer[i] >> 8) & 0xFF);
+    }
+
+    return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
+}
+
+// 扩展写字数据
+long CPerformanceMelsec::WriteWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const WordContainer& vecData) {
+    long nRet = ValidateStationAndData(station, vecData);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    std::vector<char> vecByteBuffer;
+    vecByteBuffer.resize(vecData.size() * sizeof(short));
+
+    for (size_t i = 0; i < vecData.size(); ++i) {
+        vecByteBuffer[i * 2] = static_cast<char>(vecData[i] & 0xFF);
+        vecByteBuffer[i * 2 + 1] = static_cast<char>((vecData[i] >> 8) & 0xFF);
+    }
+
+    return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
+}
+
+// 扩展写双字数据
+long CPerformanceMelsec::WriteDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const DWordContainer& vecData) {
+    long nRet = ValidateStationAndData(station, vecData);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        return nRet;
+    }
+
+    const short nDevType = CalculateDeviceType(station, enDevType);
+    std::vector<char> vecByteBuffer;
+    vecByteBuffer.resize(vecData.size() * sizeof(uint32_t));
+
+    for (size_t i = 0; i < vecData.size(); ++i) {
+        vecByteBuffer[i * 4] = static_cast<char>(vecData[i] & 0xFF);
+        vecByteBuffer[i * 4 + 1] = static_cast<char>((vecData[i] >> 8) & 0xFF);
+        vecByteBuffer[i * 4 + 2] = static_cast<char>((vecData[i] >> 16) & 0xFF);
+        vecByteBuffer[i * 4 + 3] = static_cast<char>((vecData[i] >> 24) & 0xFF);
+    }
+
+    return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
+}
+
+// 扩展软元件随机读取
+long CPerformanceMelsec::ReadRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, std::vector<char>& vecData) {
+    if (vecSoftElements.empty()) {
+        UpdateLastError(ERROR_INVALID_PARAMETER);
+        LOG_ERROR("Invalid parameters: soft elements are empty.");
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    // 准备 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;                // 点数
+    }
+
+    // 计算读取数据所需缓冲区大小
+    long nBufferSize = 0;
+    for (const auto& element : vecSoftElements) {
+        nBufferSize += element.nElementCount * 2; // 每个点占用 2 个字节
+    }
+
+    // 锁保护及调用 mdRandREx
+    long nRet = 0;
+    std::vector<short> vecBuffer(nBufferSize / 2, 0);
+    {
+        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 数据
+    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); // 高字节
+    }
+
+    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);
+        LOG_ERROR("Invalid parameters: soft elements or data is empty.");
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    // 准备 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); // 点数
+    }
+
+    // 锁保护及调用 mdRandWEx
+    long nRet = 0;
+    std::vector<short> vecBuffer(vecData.size() / 2, 0);
+    {
+        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);
+    }
+
+    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);
+        return nRet;
+    }
+
+    if (nSize < 0) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    long nActualSize = (nSize + 1) / 2;
+    std::vector<short> vecBuffer(nActualSize, 0);
+    {
+        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); // 更新错误码
+        LOG_ERROR(m_strLastError);
+    }
+    else {
+        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 类型的缓冲区
+    long nSize = static_cast<long>(vecData.size());
+    std::vector<short> vecBuffer((nSize + 1) / 2, 0);
+
+    {
+        std::lock_guard<std::mutex> lock(m_mtx); // 线程安全保护
+        ConvertCharToShort(vecData, vecBuffer);
+        nRet = mdRemBufWriteEx(m_nPath, station.nNetNo, station.nStNo, nOffset, &nSize, vecBuffer.data());
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 远程站的缓冲存储器读取 对象站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)) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    // 将缓冲区大小调整为 nSize
+    vecData.resize(nSize, 0);
+    std::vector<short> vecBuffer((nSize + 1) / 2, 0); // 转换为 short 类型
+
+    // 调用底层 SDK
+    long nRet = 0;
+    {
+        std::lock_guard<std::mutex> lock(m_mtx); // 线程安全保护
+        nRet = mdRemBufReadIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+    else {
+        std::lock_guard<std::mutex> lock(m_mtx); // 线程安全保护
+        ConvertShortToChar(vecBuffer, vecData);
+    }
+
+    return nRet;
+}
+
+// 远程站的缓冲存储器写入 对象站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)) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    // 转换 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); // 线程安全
+        ConvertCharToShort(vecData, vecBuffer);
+        nRet = mdRemBufWriteIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 设置(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); // 线程安全
+        const short nDevType = CalculateDeviceType(station, enDevType);
+        nRet = mdDevSet(m_nPath, CombineStation(station), nDevType, nDevNo);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 复位(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);
+        nRet = mdDevRst(m_nPath, CombineStation(station), nDevType, enDevNo);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    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);
+        return nRet;
+    }
+
+    nRet = mdDevSetEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    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);
+        return nRet;
+    }
+
+    nRet = mdDevRstEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo);
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 执行对象站的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); // 参数错误
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    // 确保线程安全的最小锁定范围
+    {
+        std::lock_guard<std::mutex> lock(m_mtx);
+        nRet = mdControl(m_nPath, CombineStation(station), nControlCode);
+    }
+
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    return nRet;
+}
+
+// 事件等待
+int CPerformanceMelsec::WaitForBoardEvent(std::vector<short> vecEventNumbers, const int nTimeoutMs, EventDetails& details) {
+    std::lock_guard<std::mutex> lock(m_mtx);
+
+    if (!m_bConnected.load()) {
+        UpdateLastError(ERROR_CODE_NOT_CONNECTED);
+        return ERROR_CODE_NOT_CONNECTED;
+    }
+
+    if (vecEventNumbers.empty() || vecEventNumbers.size() > 64) {
+        UpdateLastError(ERROR_CODE_INVALID_PARAM);
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    // 第 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);
+
+    const int nRet = mdWaitBdEvent(m_nPath, eventno.data(), nTimeoutMs, &details.nEventNo, details.details.data());
+    if (nRet != 0) {
+        UpdateLastError(nRet);
+        LOG_ERROR(m_strLastError);
+    }
+
+    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 系统检测出的错误
+            m_strLastError = "Error detected in the CC-Link system.";
+        }
+
+        if (nCode >= -12288 && nCode <= -8193) {
+            // CC-Link IE TSN 系统检测出的错误
+            m_strLastError = "Error detected in the CC-Link IE TSN system.";
+        }
+
+        if (nCode >= -8192 && nCode <= -4097) {
+            // CC-Link IE 控制网络系统检测出的错误
+            m_strLastError = "Error detected in the CC-Link IE control network system.";
+        }
+
+        if (nCode >= -4096 && nCode <= -257) {
+            // MELSECNET/10 或 MELSECNET/网络系统错误范围
+            m_strLastError = "Errors detected in MELSECNET/10 or MELSECNET/network system.";
+        }
+
+        if (nCode >= 4096 && nCode <= 16383) {
+            // 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 检测范围
+            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; // 参数有效
+}
+
+// 验证站点参数和数据有效性
+int CPerformanceMelsec::ValidateStationAndSize(const StationIdentifier& station, const short nCount) const {
+    // 验证站点参数
+    const int nRet = ValidateStation(station);
+    if (nRet != 0) {
+        return nRet; // 如果站点验证失败,返回对应错误码
+    }
+
+    if (nCount <= 0) {
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    return 0; // 验证通过
+}
+
+// IP字符串转uint32_t
+bool CPerformanceMelsec::ConvertIpStringToUint32(const std::string& strIP, uint32_t& nIP) {
+    nIP = 0;
+    std::stringstream ss(strIP);
+    std::string strSegment;
+    int nShift = 24;
+
+    while (std::getline(ss, strSegment, '.')) {
+        const auto nByte = static_cast<uint32_t>(std::stoi(strSegment));
+        if (nByte > 255) {
+            return false;
+        }
+        nIP |= (nByte << nShift);
+        nShift -= 8;
+    }
+
+    return true;
+}
+
+//============================================静态辅助函数====================================================
+// 延时,并且转发窗口消息
+void CPerformanceMelsec::Delay(const unsigned int nDelayMs) {
+    MSG message;
+    // 如果延迟时间为 0,仅处理一次消息队列
+    if (nDelayMs == 0) {
+        // 非阻塞的检查消息队列
+        if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
+            TranslateMessage(&message);  // 将消息转化为有效的窗口消息
+            DispatchMessage(&message);   // 派发消息给相应的窗口过程
+        }
+        return;
+    }
+
+    DWORD finish;
+    const DWORD start = GetTickCount();  // 获取当前的时间戳(从系统启动以来的毫秒数)
+    do {
+        if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
+            TranslateMessage(&message);  // 转换消息
+            DispatchMessage(&message);   // 处理消息
+        }
+        Sleep(1);   // 暂停 1 毫秒,防止过度占用 CPU
+        finish = GetTickCount(); // 获取当前的时间戳
+    } while ((finish - start) < nDelayMs);  // 循环直到经过的时间大于指定的延迟时间
+}
+
+BoardType CPerformanceMelsec::FindBoardTypeByChannel(const int nChannel) {
+    if (nChannel >= MELSECNET_CHANNEL(1) && nChannel <= MELSECNET_CHANNEL(4)) {
+        return BoardType::MELSECNET_H;
+    }
+    else if (nChannel >= CC_LINK_CHANNEL(1) && nChannel <= CC_LINK_CHANNEL(4)) {
+        return BoardType::CC_LINK_VER_2;
+    }
+    else if (nChannel >= CC_LINK_IE_CONTROL_CHANNEL(1) && nChannel <= CC_LINK_IE_CONTROL_CHANNEL(4)) {
+        return BoardType::CC_LINK_IE_CONTROL;
+    }
+    else if (nChannel >= CC_LINK_IE_FIELD_CHANNEL(1) && nChannel <= CC_LINK_IE_FIELD_CHANNEL(4)) {
+        return BoardType::CC_LINK_IE_FIELD;
+    }
+    else if (nChannel >= CC_LINK_IE_TSN_CHANNEL(1) && nChannel <= CC_LINK_IE_TSN_CHANNEL(4)) {
+        return BoardType::CC_LINK_IE_TSN;
+    }
+    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 的值
+        nDevType += 0 / 16;
+    }
+
+    return static_cast<short>(nDevType);
+}
+
+// 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 容器大小
+    for (size_t i = 0; i < vecChar.size(); i++) {
+        if (i % 2 == 0) {
+            vecShort[i / 2] = static_cast<unsigned char>(vecChar[i]);       // 低字节
+        }
+        else {
+            vecShort[i / 2] |= static_cast<unsigned char>(vecChar[i]) << 8; // 高字节
+        }
+    }
+}
+
+// std::vector<short>转换为std::vector<char>
+void CPerformanceMelsec::ConvertShortToChar(const std::vector<short>& vecShort, std::vector<char>& vecChar) {
+    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);  // 高字节
+    }
+}
+
+// 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 容器大小
+    for (size_t i = 0; i < vecUint8.size(); i++) {
+        if (i % 2 == 0) {
+            vecShort[i / 2] = static_cast<short>(vecUint8[i]);          // 低字节
+        }
+        else {
+            vecShort[i / 2] |= static_cast<short>(vecUint8[i] << 8);    // 高字节
+        }
+    }
+}
+
+// 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 容器大小
+    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);  // 高字节
+    }
+}
+
+// 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
+    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位
+    }
+}
+
+// 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
+    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位
+    }
+}
+
+//============================================模板辅助函数====================================================
+// 验证站点参数和数据有效性
+template <typename T>
+int CPerformanceMelsec::ValidateStationAndData(const StationIdentifier& station, const std::vector<T>& vecData) {
+    // 验证站点参数
+    const int nRet = ValidateStation(station);
+    if (nRet != 0) {
+        return nRet; // 如果站点验证失败,返回对应错误码
+    }
+
+    // 验证数据是否为空
+    if (vecData.empty()) {
+        return ERROR_CODE_INVALID_PARAM;
+    }
+
+    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
+    constexpr size_t nGroupSize = sizeof(U) / sizeof(T);
+
+    // 如果 T 和 U 的大小相等,直接转换
+    if (sizeof(T) == sizeof(U)) {
+        vecHigh.assign(vecLow.begin(), vecLow.end());
+        return;
+    }
+
+    // 如果 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; // 向上取整
+    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)));
+    }
+
+    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
+    constexpr size_t nGroupSize = sizeof(T) / sizeof(U);
+
+    // 如果 T 和 U 的大小相等,直接转换
+    if (sizeof(T) == sizeof(U)) {
+        vecLow.assign(vecHigh.begin(), vecHigh.end());
+        return;
+    }
+
+    // 如果 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; // 低容器的大小
+    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));
+        }
+    }
+
+    return vecLow;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.h b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.h
new file mode 100644
index 0000000..6ede559
--- /dev/null
+++ b/SourceCode/Bond/SGMeasurement/CCLinkPerformance/PerformanceMelsec.h
@@ -0,0 +1,479 @@
+#ifndef PERFORMANCE_MELSEC_H
+#define PERFORMANCE_MELSEC_H
+
+#include "Mdfunc.h"
+
+#include <map>
+#include <array>
+#include <mutex>
+#include <string>
+#include <vector>
+#include <atomic>
+#include <sstream>
+#include <unordered_map>
+
+// 连接参数
+#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 通道
+ **/
+#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 // 网络号超出范围
+
+// 板块类型
+enum class BoardType {
+	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_TSN = CC_LINK_IE_TSN_CHANNEL(1)          // CC-Link IE TSN
+};
+
+// 软元件类型枚举
+enum class DeviceType {
+	/*
+	 * ER、LX、LY、LB、LW、LSB、LSW和SPG软元件都是范围型
+	 * ER:DevER0~256
+	 * LX:DevLX1~255,DevLX(x)	(DevX*1000+(x))
+	 * LY:DevLY1~255,DevLY(x)	(DevY*1000+(x))
+	 * LB:DevLB1~255,DevLB(x)	(DevB*1000+(x))
+	 * LW:DevLW1~255,DevLW(x)	(DevW*1000+(x))
+	 * LSB:DevLSB1~255,DevLSB(x) (DevQSB*1000+(x))
+	 * LSW:DevLSW1~255,DevLSW(x) (DevQSW*1000+(x))
+	 * SPG:DevSPG0~255,DevSPG(x) (29*1000+(x))
+	 * 扩展文件寄存器代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定块No.(0~256)
+	 * 链接直接软元件代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定网络No.(1~255)
+	 * 智能功能模块软元件代码指定(10进制数)的后3位数及软元件名指定的数值中,应指定(起始I/ONo.÷16)的值
+	 * 扩展文件寄存器和链接直接软元件在随机读取(mdRandR、mdRandREx)函数中,即使指定实际不存在的软元件也有可能正常结束
+	 * MAIL和MAILMC在SEND功能及RECV功能中,与软元件访问一样,指定各功能对应的软元件类型,进行数据的发送(mdSend、mdSendEx)或数据的读取(mdReceive、mdReceiveEx)
+	 **/
+
+	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位)
+};
+
+// 控制代码
+enum class ControlCode {
+	RUN = 0,   // 远程 RUN
+	STOP = 1,  // 远程 STOP
+	PAUSE = 2  // 远程 PAUSE
+};
+
+// 版本信息
+struct BoardVersion {
+	char fixedValue[2];       // 固定值
+	char checksum[2];         // 校验和
+	char swVersion[2];        // 软件版本
+	char date[6];             // 日期 (格式 YYMMDD)
+	uint32_t reserved;        // 保留区域 (4 字节)
+	char swModel[16];         // 软件型号
+	char hwModel[16];         // 硬件型号
+	char twoPortMemory[2];    // 两端口存储器占用容量
+	char twoPortAttribute[2]; // 两端口属性
+	char availableBias[2];    // 可使用偏置
+	char moduleType[10];      // 机型类型
+
+	// 输出结构体内容为字符串 (便于调试)
+	std::string toString() const {
+		std::ostringstream oss;
+		oss << "Fixed Value: " << fixedValue[0] << fixedValue[1] << "\n"
+			<< "Checksum: " << checksum[0] << checksum[1] << "\n"
+			<< "SW Version: " << swVersion[0] << swVersion[1] << "\n"
+			<< "Date: " << std::string(date, 6) << "\n"
+			<< "Reserved: " << reserved << "\n"
+			<< "SW Model: " << std::string(swModel, 16) << "\n"
+			<< "HW Model: " << std::string(hwModel, 16) << "\n"
+			<< "Two Port Memory: " << twoPortMemory[0] << twoPortMemory[1] << "\n"
+			<< "Two Port Attribute: " << twoPortAttribute[0] << twoPortAttribute[1] << "\n"
+			<< "Available Bias: " << availableBias[0] << availableBias[1] << "\n"
+			<< "Module Type: " << std::string(moduleType, 10) << "\n";
+		return oss.str();
+	}
+};
+
+// 站点标识符,默认使用本站
+struct StationIdentifier {
+	/*
+	 * [Network No.]
+	 * 0 表示本站
+	 * 1~239 表示普通网络号
+	 **/
+
+	 /*
+	  * [Station No.]
+	  * 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)
+	  * CC-Link IE Field        : 0~120(Other stations),255(Own station)
+	  * CC-Link IE TSN          : 0~120(Other stations),255(Own station)
+	  **/
+
+	  /*
+	   * 高 8 位(网络号): 指定设备所属的网络
+	   * 低 8 位(站点号): 指定设备在网络中的编号
+	   * 用一个参数传递设备的网络号和站点号时: nSt = station.nStNo | ((station.nNetNo << 8) & 0xFF00);
+	   **/
+
+	short nNetNo = 0;    // 网络编号:PLC所连接的网络编号,0表示默认网络
+	short nStNo = 255;   // 站点编号:指定与PLC连接的站点编号,255通常表示广播或所有站点
+
+	// 自定义构造函数,覆盖默认值
+	explicit StationIdentifier(const short net, const short st) : nNetNo(net), nStNo(st) {}
+
+	StationIdentifier() 
+	{
+		nNetNo = 0;
+		nStNo = 255;
+	}
+
+	// 将“网络号”和“站点号”组合成一个最终编码
+	short StationIdentifier::toNetworkStationCode() const {
+		return static_cast<short>(nStNo | ((nNetNo << 8) & 0xFF00));
+	}
+
+	// 重载 < 运算符(用于排序或比较,通常用于 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;
+			nStNo = other.nStNo;
+		}
+		return *this;
+	}
+};
+
+// 板状态
+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])
+
+	// 将数组映射到结构体
+	static BoardStatus fromBuffer(const short buf[6]) {
+		return {
+			buf[0],
+			buf[1],
+			buf[2],
+			buf[3],
+			buf[4],
+			buf[5]
+		};
+	}
+
+	// 将结构体内容映射到数组
+	void toBuffer(short buf[6]) const {
+		buf[0] = nStationValue;
+		buf[1] = nGroupValue;
+		buf[2] = nNetworkValue;
+		buf[3] = nReserved1;
+		buf[4] = nReserved2;
+		buf[5] = nReserved3;
+	}
+
+	// 调试输出
+	std::string toString() const {
+		std::ostringstream oss;
+		oss << "Station Value: " << nStationValue << "\n"
+			<< "Group Value: " << nGroupValue << "\n"
+			<< "Network Value: " << nNetworkValue << "\n"
+			<< "Reserved1: " << nReserved1 << "\n"
+			<< "Reserved2: " << nReserved2 << "\n"
+			<< "Reserved3: " << nReserved3 << "\n";
+		return oss.str();
+	}
+};
+
+// 事件详情
+struct EventDetails {
+	short nEventNo;  					// 发生的事件号
+	std::array<short, 4> details; 		// 存储事件详情信息
+
+	// 解析事件详情,返回格式化字符串
+	std::string toString() const {
+		std::ostringstream oss;
+		oss << "Details[0]: " << details[0] << ", "
+			<< "Details[1]: " << details[1] << ", "
+			<< "Details[2]: " << details[2] << ", "
+			<< "Details[3]: " << details[3];
+		return oss.str();
+	}
+};
+
+// SoftElement 结构体定义
+struct SoftElement {
+	short nType;         // 软元件类型
+	short nElementCount; // 点数
+	long nStartNo;       // 起始软元件编号
+};
+
+// 错误信息
+struct ErrorInfo {
+	int nErrorCode = 0;              // 错误码
+	std::string strErrorMessageCn;   // 中文描述
+	std::string strErrorMessageEn;   // 英文描述
+
+	// 将结构体序列化为字符串
+	std::string toString() const {
+		std::ostringstream oss;
+		oss << nErrorCode << "|" << strErrorMessageCn << "|" << strErrorMessageEn;
+		return oss.str();
+	}
+
+	// 从字符串反序列化为结构体
+	static ErrorInfo fromString(const std::string& line) {
+		ErrorInfo info;
+		std::istringstream iss(line);
+		std::string token;
+
+		// 使用分隔符 "|" 解析字符串
+		std::getline(iss, token, '|');
+		info.nErrorCode = std::stoi(token);
+
+		std::getline(iss, token, '|');
+		info.strErrorMessageCn = token;
+
+		std::getline(iss, token, '|');
+		info.strErrorMessageEn = token;
+
+		return info;
+	}
+};
+
+using BitContainer = std::vector<bool>;			// 每个元素存储 1  位
+using WordContainer = std::vector<uint16_t>;	// 每个元素存储 16 位
+using DWordContainer = std::vector<uint32_t>;	// 每个元素存储 32 位
+
+// CPerformanceMelsec 类声明
+class CPerformanceMelsec {
+public:
+	// 获取最近的错误信息
+	std::string GetLastError() const;
+
+	// 错误信息加载与保存接口
+	static bool LoadErrorInfoFromFile(const std::string& filename);  // 从文件加载错误信息
+	static bool SaveErrorInfoToFile(const std::string& filename);    // 保存错误信息到文件
+
+	// 连接/断开
+	int Connect(short nChannel, short nMode = -1);
+	int Disconnect();
+
+	// 初始化可编程控制器软元件信息表
+	int InitializeController();
+
+	//	获取版本信息
+	int GetBoardVersion(BoardVersion& version);
+
+	// 板复位
+	int BoardReset();
+
+	// 板LED读取
+	int ReadBoardLed(std::vector<short>& vecLedBuffer);
+
+	// 读取目标站点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, long nDevType, long nDevNo, long 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);
+	int ReadDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nDWordCount, DWordContainer& vecData);
+	int WriteData(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, short* pData);
+	int WriteBitData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, const BitContainer& vecData);
+	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 ReadBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nBitCount, BitContainer& vecData);
+	long ReadWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nWordCount, WordContainer& vecData);
+	long ReadDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nDWordCount, DWordContainer& vecData);
+	long WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& vecData);
+	long WriteBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const BitContainer& vecData);
+	long WriteWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const WordContainer& vecData);
+	long WriteDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const DWordContainer& 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
+	int ControlCPU(const StationIdentifier& station, ControlCode enControlCode);
+
+	// 事件等待,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; 	// 检查连接状态和站点参数有效性
+	int ValidateStationAndSize(const StationIdentifier& station, short nCount) const;
+
+	// 静态辅助函数
+	static void Delay(unsigned int nDelayMs);						// 延时,并且转发窗口消息
+	static BoardType FindBoardTypeByChannel(int nChannel);			// 查找板块类型
+	static short CombineStation(const StationIdentifier& station);  // 合并网络号和站点号
+	static short CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType); // 计算软元件类型
+
+	// 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);
+	static void ConvertShortToUint8(const std::vector<short>& vecShort, std::vector<uint8_t>& vecUint8);
+	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);
+
+	template <typename T, typename U>
+	void ConvertLowToHigh(const std::vector<T>& vecLow, std::vector<U>& vecHigh);
+
+	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;             // 最近一次错误信息
+
+	// 静态成员变量
+	static std::unordered_map<int, std::string> m_mapError; // 错误码映射表
+};
+
+#endif // PERFORMANCE_MELSEC_H
\ No newline at end of file
diff --git a/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp b/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
new file mode 100644
index 0000000..27ad0c9
--- /dev/null
+++ b/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
@@ -0,0 +1,203 @@
+#include "pch.h"
+#include "PLCSignalListener.h"
+
+// === 日志打印类型 ===
+#define LOG_TYPE_ERROR     -1
+#define LOG_TYPE_SUCCESS    0
+#define LOG_TYPE_WARNING    1
+#define LOG_TYPE_NORMAL     2
+
+// === PLC 控制命令输入位配置 ===
+#define PLC_CMD_BIT_START       0     // PLC命令起始位(通常为B0)
+#define PLC_CMD_BIT_COUNT       2     // 总共几个命令位(B0=Start, B1=Stop)
+
+// === PLC 信号监听器相关宏定义 ===
+#define PLC_ACK_MAX_LIFE        5     // PLC响应信号最大保留周期数(每周期为 m_nIntervalMs 毫秒)
+#define PLC_ACK_BASE_BIT        10    // PLC应答起始地址(B10表示B0的应答;B11表示B1)
+
+// === PLC软元件类型宏(用于应答、数据写入)===
+#define PLC_BIT_DEVICE_TYPE    DeviceType::B   // 位操作设备类型(如M、B)
+#define PLC_WORD_DEVICE_TYPE   DeviceType::W   // 字操作设备类型(如D、W)
+
+#define IS_RISING_EDGE(prev, curr) (!(prev) && (curr))
+
+CPLCSignalListener::CPLCSignalListener() = default;
+
+CPLCSignalListener::~CPLCSignalListener() {
+    Stop();
+}
+
+bool CPLCSignalListener::Initialize(StationIdentifier station, int nIntervalMs/* = 200*/)
+{
+    m_pPlc = std::make_unique<CCCLinkIEControl>();
+    if (!m_pPlc) {
+		if (m_cbLog) {
+			m_cbLog(_T("PLC控制器初始化失败,无法创建 CCCLinkIEControl 实例。"), LOG_TYPE_ERROR);
+		}
+        return false;
+    }
+
+    int ret = m_pPlc->Connect(CC_LINK_IE_CONTROL_CHANNEL(1));
+    if (ret != 0) {
+		m_bConnected = false;
+		if (m_cbLog) {
+			CString strError;
+			strError.Format(_T("PLC控制器连接失败,错误码:%d"), ret);
+			m_cbLog(strError, LOG_TYPE_ERROR);
+		}
+        return false;
+    }
+
+	m_bConnected = true;
+    m_station = station;
+    m_nIntervalMs = nIntervalMs;
+
+    m_vecPrevBits.assign(PLC_CMD_BIT_COUNT, false);
+
+    return true;
+}
+
+void CPLCSignalListener::SetStartCallback(Callback cb)
+{
+    m_cbStart = std::move(cb);
+}
+
+void CPLCSignalListener::SetStopCallback(Callback cb)
+{
+    m_cbStop = std::move(cb);
+}
+
+void CPLCSignalListener::SetAnalyzeCallback(AnalyzeCallback cb)
+{
+    m_cbAnalyze = std::move(cb);
+}
+
+void CPLCSignalListener::SetLogCallback(LogCallback cb)
+{
+    m_cbLog = std::move(cb);
+}
+
+bool CPLCSignalListener::Start()
+{
+    if (m_bRunning || !m_pPlc) {
+		if (m_cbLog) {
+			m_cbLog(_T("PLC信号监听器已在运行或PLC控制器未初始化。"), LOG_TYPE_ERROR);
+		}
+        return false;
+    }
+
+    m_bRunning = true;
+    m_thread = std::thread(&CPLCSignalListener::ThreadProc, this);
+    return true;
+}
+
+void CPLCSignalListener::Stop()
+{
+    m_bRunning = false;
+    if (m_thread.joinable()) {
+        m_thread.join();
+    }
+}
+
+void CPLCSignalListener::PulseBitDevice(DeviceType eDevType, short nBitNo, int nDelayMs/* = 50*/)
+{
+    m_pPlc->SetBitDevice(m_station, eDevType, nBitNo);
+    ::Sleep(nDelayMs);
+    m_pPlc->ResetBitDevice(m_station, eDevType, nBitNo);
+}
+
+void CPLCSignalListener::HandleAckLife(int i, bool bCurrTriggerBit)
+{
+    if (m_vecAckSent[i] && !bCurrTriggerBit) {
+        m_pPlc->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
+        m_vecAckSent[i] = false;
+    }
+
+    if (m_vecAckSent[i]) {
+        if (++m_vecAckCounter[i] > PLC_ACK_MAX_LIFE) {
+            m_pPlc->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
+            m_vecAckSent[i] = false;
+        }
+    }
+}
+
+void CPLCSignalListener::ThreadProc()
+{
+    while (m_bRunning) {
+        BitContainer vecBits;
+        int ret = m_pPlc->ReadBitData(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits);
+        if (ret != 0/*&& vecBits.size() != PLC_CMD_BIT_COUNT*/) {
+			::Sleep(m_nIntervalMs);
+
+			if (m_cbLog) {
+				CString strError;
+				strError.Format(_T("PLC读取位数据失败,错误码:%d"), ret);
+				m_cbLog(strError, LOG_TYPE_ERROR);
+			}
+
+			continue;
+        }
+
+        for (int i = 0; i < PLC_CMD_BIT_COUNT; ++i) {
+            if (IS_RISING_EDGE(m_vecPrevBits[i], vecBits[i])) {
+                // 上升沿触发
+                switch (i) {
+                case 0:
+                    if (m_cbStart) {
+                        m_cbStart();
+                        WriteOutValues(OutValuesArray{ 0.0, 0.0, 0.0, 0.0 });
+                        if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
+                            m_vecAckSent[i] = true;
+                            m_vecAckCounter[i] = 0;
+                        }
+                    }
+                    break;
+
+                case 1:
+                    if (m_cbStop) {
+                        m_cbStop();
+                        if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
+                            m_vecAckSent[i] = true;
+                            m_vecAckCounter[i] = 0;
+                        }
+                    }
+
+                    if (m_cbAnalyze) {
+                        auto results = m_cbAnalyze();
+                        WriteOutValues(results);
+                    }
+                    break;
+                }
+            }
+
+            HandleAckLife(i, vecBits[i]);
+            m_vecPrevBits[i] = vecBits[i];
+        }
+
+        ::Sleep(m_nIntervalMs);
+    }
+}
+
+bool CPLCSignalListener::WriteOutValues(const OutValuesArray& values)
+{
+    if (!m_pPlc) {
+		if (m_cbLog) {
+			m_cbLog(_T("PLC控制器未初始化,无法写入输出值。"), LOG_TYPE_ERROR);
+		}
+        return false;
+    }
+
+    static const short PLC_RESULT_ADDR[4] = { 100, 102, 104, 106 };
+
+    for (int i = 0; i < 4; ++i) {
+        uint16_t nScaled = static_cast<uint16_t>(std::round(values[i] * 100.0));
+        WordContainer vec = { nScaled };
+
+        int ret = m_pPlc->WriteWordData(m_station, PLC_WORD_DEVICE_TYPE, PLC_RESULT_ADDR[i], vec);
+        if (ret != 0) {
+            return false;
+        }
+    }
+
+    return true;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/SGMeasurement/PLCSignalListener.h b/SourceCode/Bond/SGMeasurement/PLCSignalListener.h
new file mode 100644
index 0000000..cce8782
--- /dev/null
+++ b/SourceCode/Bond/SGMeasurement/PLCSignalListener.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "CCLinkIEControl.h"
+
+#include <thread>
+#include <atomic>
+#include <functional>
+#include <vector>
+
+using OutValuesArray = std::array<double, 4>;
+using Callback = std::function<void()>;
+using AnalyzeCallback = std::function<OutValuesArray()>;
+using LogCallback = std::function<void(const CString& strContent, int type)>;
+
+class CPLCSignalListener
+{
+public:
+    CPLCSignalListener();
+    ~CPLCSignalListener();
+
+    bool Initialize(StationIdentifier station, int nIntervalMs = 200);
+
+    void SetStartCallback(Callback cb);
+    void SetStopCallback(Callback cb);
+    void SetAnalyzeCallback(AnalyzeCallback cb);
+    void SetLogCallback(LogCallback cb);
+
+    bool Start();
+    void Stop();
+
+    bool WriteOutValues(const OutValuesArray& values);
+
+private:
+    void PulseBitDevice(DeviceType eDevType, short nBitNo, int nDelayMs = 50);
+    void HandleAckLife(int i, bool bCurrTriggerBit);
+    void ThreadProc();
+
+private:
+    std::unique_ptr<CCCLinkIEControl> m_pPlc;
+    StationIdentifier m_station;
+    int m_nIntervalMs = 200;
+
+    std::atomic<bool> m_bConnected{ false };
+    std::atomic<bool> m_bRunning{ false };
+    std::thread m_thread;
+    std::vector<bool> m_vecPrevBits;
+
+    std::array<bool, 2> m_vecAckSent = { false, false }; // 是否已发送 M10/M11
+    std::array<int, 2> m_vecAckCounter = { 0, 0 };       // 计数器,超时自动清除
+
+    Callback m_cbStart;
+    Callback m_cbStop;
+    AnalyzeCallback m_cbAnalyze;
+    LogCallback m_cbLog;
+};
+
diff --git a/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp b/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp
index 7529194..94363a7 100644
--- a/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp
+++ b/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.cpp
@@ -130,6 +130,8 @@
 		m_bTrayIconCreated = FALSE;
 	}
 
+	m_plcListener.Stop();
+
 	DestroyWindow();
 	CDialogEx::OnClose();
 }
@@ -880,6 +882,56 @@
 	// 鍒濆鍖朓P鍦板潃鎺т欢锛岃缃负榛樿IP鍦板潃
 	((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->SetAddress(192, 168, 0, 10);
 
+	// 璁剧疆 PLC 鐩戝惉鍣ㄧ殑鏃ュ織鍥炶皟鍑芥暟
+	m_plcListener.SetLogCallback([this](const CString& msg, int type) {
+		if (type == -1) {
+			AppendLogLineRichStyled(msg, LOG_COLOR_ERROR);
+		}
+		if (type == 0) {
+			AppendLogLineRichStyled(msg, LOG_COLOR_SUCCESS);
+		}
+		else if (type == 1) {
+			AppendLogLineRichStyled(msg, LOG_COLOR_WARNING);
+		}
+		else {
+			AppendLogLineRichStyled(msg, LOG_COLOR_NORMAL);
+		}
+	});
+
+	// 鍒濆鍖� PLC 鐩戝惉鍣�
+	m_plcListener.Initialize(StationIdentifier(0, 255), 200);
+
+	// 璁剧疆 PLC 鐩戝惉鍣ㄧ殑寮�濮嬮噰闆嗗洖璋冨嚱鏁�
+	m_plcListener.SetStartCallback([this]() {
+		InitDataStorage();
+		StartDataStorage();
+		UpdateControlStatus(m_bConnected, m_bSaving);
+	});
+
+	// 璁剧疆 PLC 鐩戝惉鍣ㄧ殑鍋滄閲囬泦鍥炶皟鍑芥暟
+	m_plcListener.SetStopCallback([this]() { 
+		StopDataStorage();
+		UpdateControlStatus(m_bConnected, m_bSaving);
+	});
+
+	// 璁剧疆 PLC 鐩戝惉鍣ㄧ殑鍒嗘瀽鍥炶皟鍑芥暟
+	m_plcListener.SetAnalyzeCallback([this]() {
+		std::array<double, 4> result;
+		for (int i = 0; i < 4; ++i) {
+			result[i] = AnalyzeStoredData(i + 1); // OUT1 ~ OUT4
+		}
+
+		if (std::any_of(result.begin(), result.end(), [](double v) { return v < 0; })) {
+			AppendLogLineRichStyled(_T("鍒嗘瀽澶辫触锛屾煇浜涜緭鍑虹鍙f暟鎹棤鏁堛��"), LOG_COLOR_ERROR);
+			return std::array<double, 4>{ -1.0, -1.0, -1.0, -1.0 };
+		}
+
+		CString strLog;
+		strLog.Format(_T("鍒嗘瀽缁撴灉锛歄UT1: %.3f, OUT2: %.3f, OUT3: %.3f, OUT4: %.3f"), result[0], result[1], result[2], result[3]);
+		return result;
+	});
+	m_plcListener.Start();
+
 	// 鍒濆鍖栨棩蹇楁
 	AppendLogLineRichStyled(_T("鍑嗗灏辩华..."), LOG_COLOR_SUCCESS);
 
diff --git a/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.h b/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.h
index 53293f7..593f7c9 100644
--- a/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.h
+++ b/SourceCode/Bond/SGMeasurement/SGMeasurementDlg.h
@@ -3,6 +3,9 @@
 //
 
 #pragma once
+
+#include "PLCSignalListener.h"
+
 #include <map>
 #include <vector>
 #include <numeric>
@@ -330,4 +333,11 @@
 	 * @brief 鏍囪绋嬪簭鏄惁閫氳繃鎵樼洏鍥炬爣閫�鍑�
 	 */
 	BOOL m_bExitingFromTray;
+
+	// === PLC 淇″彿鐩戝惉鍣� ===
+
+	/**
+	 * @brief PLC 淇″彿鐩戝惉鍣ㄥ疄渚嬶紝鐢ㄤ簬澶勭悊 PLC 淇″彿浜嬩欢
+	 */
+	CPLCSignalListener m_plcListener;
 };

--
Gitblit v1.9.3