From a07301251f7344c19774f78e5230d5d342431a95 Mon Sep 17 00:00:00 2001
From: darker <mr.darker@163.com>
Date: 星期五, 14 二月 2025 14:08:11 +0800
Subject: [PATCH] 1.集成CC-LINK模块
---
SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp | 81 ++
SourceCode/Bond/Servo/Servo.vcxproj | 8
SourceCode/Bond/Servo/Servo.vcxproj.filters | 17
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h | 465 +++++++++++++
SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp | 1355 +++++++++++++++++++++++++++++++++++++++
SourceCode/Bond/Servo/stdafx.h | 3
SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h | 68 ++
7 files changed, 1,995 insertions(+), 2 deletions(-)
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp
new file mode 100644
index 0000000..bc85cc4
--- /dev/null
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.cpp
@@ -0,0 +1,81 @@
+#include "stdafx.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;
+ }
+
+ // 瑙f瀽鍚勪綅鐘舵��
+ 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; // 鏍¢獙閫氳繃
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h
new file mode 100644
index 0000000..a7006fd
--- /dev/null
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/CCLinkIEControl.h
@@ -0,0 +1,68 @@
+#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);
+
+private:
+ static CCLinkIEControlMode ConvertToCCLinkIEControlMode(short nMode);
+ static int ValidateBoardStatus(const BoardStatus& status);
+};
+
+
+#endif //CCLINKIECONTROL_H
diff --git a/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
new file mode 100644
index 0000000..1f6deab
--- /dev/null
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.cpp
@@ -0,0 +1,1355 @@
+// PerformanceMelsec.cpp: implementation of the CPerformanceMelsec class.
+//
+//////////////////////////////////////////////////////////////////////
+#include "stdafx.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;
+
+ // 浣跨敤鍒嗛殧绗� "|" 瑙f瀽姣忎竴琛�
+ 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;
+}
+
+// 杩炴帴鍒癙LC
+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;
+}
+
+// 鏉縇ED璇诲彇
+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 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);
+
+ // 纭繚绾跨▼瀹夊叏鐨勬渶灏忛攣瀹氳寖鍥�
+ {
+ std::lock_guard<std::mutex> lock(m_mtx);
+ short* pData = vecData.data();
+ nRet = mdReceive(m_nPath, CombineStation(station), nDevType, 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;
+ }
+
+ // 璁$畻闇�瑕佽鍙栫殑瀛楄妭澶у皬锛堟寜浣嶅榻愪负瀛楄妭鏁帮級
+ const short nDevType = CalculateDeviceType(station, enDevType);
+ const auto nSize = static_cast<short>((nBitCount + 7) / 8); // 鍚戜笂鍙栨暣
+ std::vector<short> vecTempBuffer((nSize + 1) / 2, 0); // 涓存椂缂撳啿鍖猴紝瀛楄妭瀵归綈
+ nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
+
+ if (nRet == 0) {
+ std::lock_guard<std::mutex> lock(m_mtx); // 绾跨▼瀹夊叏淇濇姢
+ ConvertShortToUint8(vecTempBuffer, vecData);
+ }
+
+ 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 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);
+ nRet = mdSend(m_nPath, CombineStation(station), 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) {
+ // 楠岃瘉绔欑偣鍙傛暟鍜屾暟鎹湁鏁堟��
+ const int nRet = ValidateStationAndData(station, vecData);
+ if (nRet != 0) {
+ UpdateLastError(nRet);
+ return nRet;
+ }
+
+ // 璁$畻闇�瑕佸啓鍏ョ殑瀛楄妭鏁帮紙浣嶆暟鎹渶瑕佹寜 8 浣嶅榻愪负瀛楄妭鏁帮級
+ const short nDevType = CalculateDeviceType(station, enDevType);
+ const auto nSize = static_cast<short>((vecData.size() + 7) / 8);
+ std::vector<short> vecBuffer(vecData.size() / 2 + vecData.size() % 2, 0);
+ {
+ std::lock_guard<std::mutex> lock(m_mtx); // 绾跨▼瀹夊叏淇濇姢
+ ConvertUint8ToShort(vecData, vecBuffer);
+ }
+
+ return WriteData(station, nDevType, nDevNo, nSize, vecBuffer.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() * sizeof(uint16_t));
+ 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(uint32_t));
+ std::vector<short> vecBuffer(vecData.size() * 2, 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;
+ }
+
+ vecData.resize(nSize);
+ long nActualSize = (nSize + 1) / 2;
+ std::vector<short> vecBuffer(nActualSize, 0);
+
+ {
+ std::lock_guard<std::mutex> lock(m_mtx); // 绾跨▼瀹夊叏淇濇姢
+ nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &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 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());
+ std::vector<short> vecBuffer((nSize + 1) / 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::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;
+}
+
+// 杩滅▼绔欑殑缂撳啿瀛樺偍鍣ㄨ鍙� 瀵硅薄绔橧P鍦板潃鎸囧畾
+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;
+}
+
+// 杩滅▼绔欑殑缂撳啿瀛樺偍鍣ㄥ啓鍏� 瀵硅薄绔橧P鍦板潃鎸囧畾
+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;
+}
+
+//============================================闈欐�佽緟鍔╁嚱鏁�====================================================
+// 寤舵椂锛屽苟涓旇浆鍙戠獥鍙f秷鎭�
+void CPerformanceMelsec::Delay(const unsigned int nDelayMs) {
+ MSG message;
+ // 濡傛灉寤惰繜鏃堕棿涓� 0锛屼粎澶勭悊涓�娆℃秷鎭槦鍒�
+ if (nDelayMs == 0) {
+ // 闈為樆濉炵殑妫�鏌ユ秷鎭槦鍒�
+ if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&message); // 灏嗘秷鎭浆鍖栦负鏈夋晥鐨勭獥鍙f秷鎭�
+ 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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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>杞崲涓簊td::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/Servo/CCLinkPerformance/PerformanceMelsec.h b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
new file mode 100644
index 0000000..903ca41
--- /dev/null
+++ b/SourceCode/Bond/Servo/CCLinkPerformance/PerformanceMelsec.h
@@ -0,0 +1,465 @@
+#ifndef PERFORMANCE_MELSEC_H
+#define PERFORMANCE_MELSEC_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銆丩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)
+ **/
+
+ 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 = 0x03E9, // 閾炬帴鐩存帴杞厓浠� (閾炬帴杈撳叆) (0x03E9锝�0x04E7) (浣�)
+ LY = 0x07D1, // 閾炬帴鐩存帴杞厓浠� (閾炬帴杈撳嚭) (0x07D1锝�0x08CF) (浣�)
+ LB = 0x59D9, // 閾炬帴鐩存帴杞厓浠� (閾炬帴缁х數鍣�) (0x59D9锝�0x5AD7) (浣�)
+ LW = 0x5DC1, // 閾炬帴鐩存帴杞厓浠� (閾炬帴瀵勫瓨鍣�) (0x5DC1锝�0x5EBF) (瀛�)
+ LSB = 0x61A9, // 閾炬帴鐩存帴杞厓浠� (閾炬帴鐗规畩缁х數鍣�) (0x61A9锝�0x62A7) (浣�)
+ LSW = 0x6D61, // 閾炬帴鐩存帴杞厓浠� (閾炬帴鐗规畩瀵勫瓨鍣�) (0x6D61锝�0x6E5F) (瀛�)
+ SPG = 0x7148, // 鏅鸿兘鍔熻兘妯″潡杞厓浠� (0x7148锝�0x7247) (瀛�)
+};
+
+// 鏁版嵁绫诲瀷
+enum class DataType {
+ BIT = 1, // 浣� (1浣�)
+ WORD = 2, // 瀛� (16浣�)
+ DWORD =4 // 鍙屽瓧 (32浣�)
+};
+
+// 鎺у埗浠g爜
+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]; // 涓ょ鍙e瓨鍌ㄥ櫒鍗犵敤瀹归噺
+ char twoPortAttribute[2]; // 涓ょ鍙e睘鎬�
+ 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; // 缃戠粶缂栧彿锛歅LC鎵�杩炴帴鐨勭綉缁滅紪鍙凤紝0琛ㄧず榛樿缃戠粶
+ short nStNo = 255; // 绔欑偣缂栧彿锛氭寚瀹氫笌PLC杩炴帴鐨勭珯鐐圭紪鍙凤紝255閫氬父琛ㄧず骞挎挱鎴栨墍鏈夌珯鐐�
+
+ // 鑷畾涔夋瀯閫犲嚱鏁帮紝瑕嗙洊榛樿鍊�
+ explicit StationIdentifier(const short net, const short st) : nNetNo(net), nStNo(st) {}
+
+ // 灏嗏�滅綉缁滃彿鈥濆拰鈥滅珯鐐瑰彿鈥濈粍鍚堟垚涓�涓渶缁堢紪鐮�
+ 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; // 瀛樺偍浜嬩欢璇︽儏淇℃伅
+
+ // 瑙f瀽浜嬩欢璇︽儏锛岃繑鍥炴牸寮忓寲瀛楃涓�
+ 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;
+
+ // 浣跨敤鍒嗛殧绗� "|" 瑙f瀽瀛楃涓�
+ 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<uint8_t>; // 姣忎釜鍏冪礌瀛樺偍 8 涓綅
+using WordContainer = std::vector<uint16_t>; // 姣忎釜鍏冪礌瀛樺偍 16 浣�
+using DWordContainer = std::vector<uint32_t>; // 姣忎釜鍏冪礌瀛樺偍 32 浣�
+
+// CPerformanceMelsec 绫诲0鏄�
+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();
+
+ // 鏉縇ED璇诲彇
+ 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, 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);
+ int ReadDWordData(const StationIdentifier& station, DeviceType enDevType, short nDevNo, short nDWordCount, DWordContainer& vecData);
+ int WriteData(const StationIdentifier& station, short nDevType, short nDevNo, short 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 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
+ int ControlCPU(const StationIdentifier& station, ControlCode enControlCode);
+
+ // 浜嬩欢绛夊緟锛寁ecEventNumbers[0, 64]锛宯TimeoutMs[-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); // 寤舵椂锛屽苟涓旇浆鍙戠獥鍙f秷鎭�
+ 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/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index fed2d8a..1a138ec 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -115,7 +115,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -169,7 +169,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -194,6 +194,8 @@
<ItemGroup>
<ClInclude Include="AlarmManager.h" />
<ClInclude Include="BlButton.h" />
+ <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h" />
+ <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="Configuration.h" />
<ClInclude Include="Context.h" />
@@ -216,6 +218,8 @@
<ItemGroup>
<ClCompile Include="AlarmManager.cpp" />
<ClCompile Include="BlButton.cpp" />
+ <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp" />
+ <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp" />
<ClCompile Include="Configuration.cpp" />
<ClCompile Include="Context.cpp" />
<ClCompile Include="HsmsAction.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index eddda24..58314be 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -24,6 +24,12 @@
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="TerminalDisplayDlg.cpp" />
<ClCompile Include="SECSRuntimeManager.cpp" />
+ <ClCompile Include="CCLinkPerformance\CCLinkIEControl.cpp">
+ <Filter>CCLinkPerformance</Filter>
+ </ClCompile>
+ <ClCompile Include="CCLinkPerformance\PerformanceMelsec.cpp">
+ <Filter>CCLinkPerformance</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlarmManager.h" />
@@ -46,6 +52,12 @@
<ClInclude Include="targetver.h" />
<ClInclude Include="TerminalDisplayDlg.h" />
<ClInclude Include="SECSRuntimeManager.h" />
+ <ClInclude Include="CCLinkPerformance\CCLinkIEControl.h">
+ <Filter>CCLinkPerformance</Filter>
+ </ClInclude>
+ <ClInclude Include="CCLinkPerformance\PerformanceMelsec.h">
+ <Filter>CCLinkPerformance</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Servo.rc" />
@@ -60,4 +72,9 @@
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
+ <ItemGroup>
+ <Filter Include="CCLinkPerformance">
+ <UniqueIdentifier>{77338295-9841-4706-8816-a958b1b5c465}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
</Project>
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/stdafx.h b/SourceCode/Bond/Servo/stdafx.h
index 4768d25..d63dafa 100644
--- a/SourceCode/Bond/Servo/stdafx.h
+++ b/SourceCode/Bond/Servo/stdafx.h
@@ -38,6 +38,9 @@
#include <gdiplus.h>
using namespace Gdiplus;
+// CC-LINK模块
+#include "..\MELSECSDK\include\Mdfunc.h"
+#pragma comment(lib, "..\\MELSECSDK\\lib\\MdFunc32.lib")
// 数据库模块
#include "..\DatabaseSDK\include\Database.h"
--
Gitblit v1.9.3