// PerformanceMelsec.cpp: implementation of the CPerformanceMelsec class. // ////////////////////////////////////////////////////////////////////// #include "pch.h" #include "PerformanceMelsec.h" #include #include #include #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 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 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 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 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(buf[0] & 0xFF); version.fixedValue[1] = static_cast((buf[0] >> 8) & 0xFF); version.checksum[0] = static_cast(buf[1] & 0xFF); version.checksum[1] = static_cast((buf[1] >> 8) & 0xFF); version.swVersion[0] = static_cast(buf[2] & 0xFF); version.swVersion[1] = static_cast((buf[2] >> 8) & 0xFF); std::memcpy(version.date, &buf[3], 6); version.reserved = static_cast(buf[6]) | (static_cast(buf[7]) << 16); std::memcpy(version.swModel, &buf[8], 16); std::memcpy(version.hwModel, &buf[16], 16); version.twoPortMemory[0] = static_cast(buf[18] & 0xFF); version.twoPortMemory[1] = static_cast((buf[18] >> 8) & 0xFF); version.twoPortAttribute[0] = static_cast(buf[19] & 0xFF); version.twoPortAttribute[1] = static_cast((buf[19] >> 8) & 0xFF); version.availableBias[0] = static_cast(buf[20] & 0xFF); version.availableBias[1] = static_cast((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 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 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 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 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& vecLedBuffer) { std::lock_guard 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 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& vecData) { // ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ int nRet = ValidateStationAndSize(station, static_cast(nSize)); if (nRet != 0) { UpdateLastError(nRet); return nRet; } // ³õʼ»¯¶ÁÈ¡»º³åÇø vecData.clear(); vecData.resize(nSize, 0); // È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§ { std::lock_guard 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((static_cast(nBitCount) + 15) / 16); // ¼ÆËãÐèÒª¶ÁÈ¡µÄ×ÖÊýÁ¿£¨ÏòÉÏÈ¡Õû£© std::vector 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 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(nDWordCount * 2); // ÿ¸öË«×ÖÕ¼Á½¸ö×Ö£¨Ã¿¸öË«×ÖÕ¼ 4 ×Ö½Ú£© const short nDevType = CalculateDeviceType(station, enDevType); std::vector vecTempBuffer(nSize, 0); nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer); if (nRet == 0) { std::lock_guard 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 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((static_cast(vecData.size()) + 15) / 16); // ¼ÆËãÐèҪдÈëµÄ×ÖÊýÁ¿£¨ÏòÉÏÈ¡Õû£© // ×¼±¸ÁÙʱ»º³åÇøÀ´´æ´¢×ª»»ºóµÄ 16 λÊý¾Ý std::vector vecTempBuffer(nSize, 0); { std::lock_guard lock(m_mtx); // Ḭ̈߳²È«±£»¤ // ½«Î»Êý¾Ý°´×Ö´ò°üµ½ÁÙʱ»º³åÇø for (int i = 0; i < vecData.size(); ++i) { if (vecData[i]) { // ʹÓà & 0xFFFF ±£Ö¤²»»á³¬¹ý 16 룬·ÀÖ¹Òç³ö vecTempBuffer[i / 16] |= static_cast((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(vecData.size()); const auto pData = const_cast(reinterpret_cast(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(vecData.size() * sizeof(short)); std::vector vecBuffer(nSize, 0); { std::lock_guard 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& 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 vecBuffer(nSize / 2, 0); { std::lock_guard 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 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(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 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(vecRaw[i * 2]) | (static_cast(vecRaw[i * 2 + 1]) << 8); for (int j = 0; j < 16; ++j) { vecData.push_back((word & (1 << j)) != 0); if (vecData.size() >= static_cast(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(nWordCount)); if (nRet != 0) { UpdateLastError(nRet); return nRet; } const short nDevType = CalculateDeviceType(station, enDevType); const long nByteSize = nWordCount * sizeof(short); std::vector 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(vecRaw[i * 2]) | (static_cast(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(nDWordCount)); if (nRet != 0) { UpdateLastError(nRet); return nRet; } const short nDevType = CalculateDeviceType(station, enDevType); const long nByteSize = nDWordCount * sizeof(uint32_t); std::vector 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(vecRaw[i * 4 + 0]) | (static_cast(vecRaw[i * 4 + 1]) << 8) | (static_cast(vecRaw[i * 4 + 2]) << 16) | (static_cast(vecRaw[i * 4 + 3]) << 24); vecData.push_back(val); } return 0; } // À©Õ¹Ð´Êý¾Ý long CPerformanceMelsec::WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector& vecData) { // ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ long nRet = ValidateStationAndData(station, vecData); if (nRet != 0) { UpdateLastError(nRet); return nRet; } // ½« vecData ת»»Îª short ÀàÐ͵Ļº³åÇø long nSize = static_cast(vecData.size()); nSize = nSize % 2 != 0 ? nSize + 1 : nSize; std::vector vecBuffer(nSize / 2, 0); { std::lock_guard 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 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 vecByteBuffer; vecByteBuffer.resize(nWordCount * sizeof(short)); for (size_t i = 0; i < nWordCount; ++i) { vecByteBuffer[i * 2] = static_cast(vecWordBuffer[i] & 0xFF); vecByteBuffer[i * 2 + 1] = static_cast((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 vecByteBuffer; vecByteBuffer.resize(vecData.size() * sizeof(short)); for (size_t i = 0; i < vecData.size(); ++i) { vecByteBuffer[i * 2] = static_cast(vecData[i] & 0xFF); vecByteBuffer[i * 2 + 1] = static_cast((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 vecByteBuffer; vecByteBuffer.resize(vecData.size() * sizeof(uint32_t)); for (size_t i = 0; i < vecData.size(); ++i) { vecByteBuffer[i * 4] = static_cast(vecData[i] & 0xFF); vecByteBuffer[i * 4 + 1] = static_cast((vecData[i] >> 8) & 0xFF); vecByteBuffer[i * 4 + 2] = static_cast((vecData[i] >> 16) & 0xFF); vecByteBuffer[i * 4 + 3] = static_cast((vecData[i] >> 24) & 0xFF); } return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer); } // À©Õ¹ÈíÔª¼þËæ»ú¶ÁÈ¡ long CPerformanceMelsec::ReadRandomDataEx(const StationIdentifier& station, const std::vector& vecSoftElements, std::vector& vecData) { if (vecSoftElements.empty()) { UpdateLastError(ERROR_INVALID_PARAMETER); LOG_ERROR("Invalid parameters: soft elements are empty."); return ERROR_INVALID_PARAMETER; } // ×¼±¸ dev Êý¾Ý std::vector devBuffer(vecSoftElements.size() * 3 + 1, 0); // ÿ¸öÈíÔª¼þÐèÒª 3 ¸ö short£¬Íâ¼ÓÒ»¸ö¼ÆÊýÆ÷ devBuffer[0] = static_cast(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(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 vecBuffer(nBufferSize / 2, 0); { std::lock_guard 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(vecBuffer[i] & 0xFF); // µÍ×Ö½Ú vecData[i * 2 + 1] = static_cast((vecBuffer[i] >> 8) & 0xFF); // ¸ß×Ö½Ú } return nRet; } // À©Õ¹ÈíÔª¼þËæ»úдÈ루֧³Ö¶à¸öÈíÔª¼þ£© long CPerformanceMelsec::WriteRandomDataEx(const StationIdentifier& station, const std::vector& vecSoftElements, const std::vector& 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 devBuffer(vecSoftElements.size() * 3 + 1, 0); // ÿ¸öÈíÔª¼þÐèÒª 3 ¸ö long£¬Íâ¼ÓÒ»¸ö¼ÆÊýÆ÷ devBuffer[0] = static_cast(vecSoftElements.size()); // µÚÒ»¸öÔªËØÊÇÈíÔª¼þÊýÁ¿ for (size_t i = 0; i < vecSoftElements.size(); ++i) { const SoftElement& element = vecSoftElements[i]; devBuffer[i * 3 + 1] = static_cast(element.nType); // ÈíÔª¼þÀàÐÍ devBuffer[i * 3 + 2] = element.nStartNo; // ÆðʼÈíÔª¼þ±àºÅ£¨ÒѾ­ÊÇ long ÀàÐÍ£¬ÎÞÐèת»»£© devBuffer[i * 3 + 3] = static_cast(element.nElementCount); // µãÊý } // Ëø±£»¤¼°µ÷Óà mdRandWEx long nRet = 0; std::vector vecBuffer(vecData.size() / 2, 0); { std::lock_guard lock(m_mtx); // È·±£Ḭ̈߳²È« ConvertCharToShort(vecData, vecBuffer); nRet = mdRandWEx(m_nPath, station.nNetNo, station.nStNo, devBuffer.data(), vecBuffer.data(), static_cast(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& 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 vecBuffer(nActualSize, 0); { std::lock_guard 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 lock(m_mtx); // Ḭ̈߳²È«±£»¤ ConvertShortToChar(vecBuffer, vecData); } return nRet; } // Ô¶³ÌÉ豸վ/Ô¶³ÌÕ¾µÄ»º³å´æ´¢Æ÷дÈë long CPerformanceMelsec::WriteRemoteBuffer(const StationIdentifier& station, long nOffset, const std::vector& vecData) { // ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ long nRet = ValidateStationAndData(station, vecData); if (nRet != 0) { UpdateLastError(nRet); return nRet; } // ½« vecData ת»»Îª short ÀàÐ͵Ļº³åÇø long nSize = static_cast(vecData.size()); std::vector vecBuffer((nSize + 1) / 2, 0); { std::lock_guard 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& 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 vecBuffer((nSize + 1) / 2, 0); // ת»»Îª short ÀàÐÍ // µ÷Óõײã SDK long nRet = 0; { std::lock_guard lock(m_mtx); // Ḭ̈߳²È«±£»¤ nRet = mdRemBufReadIPEx(m_nPath, static_cast(nAddress), nOffset, &nSize, vecBuffer.data()); } if (nRet != 0) { UpdateLastError(nRet); LOG_ERROR(m_strLastError); } else { std::lock_guard lock(m_mtx); // Ḭ̈߳²È«±£»¤ ConvertShortToChar(vecBuffer, vecData); } return nRet; } // Ô¶³ÌÕ¾µÄ»º³å´æ´¢Æ÷дÈë ¶ÔÏóÕ¾IPµØÖ·Ö¸¶¨ long CPerformanceMelsec::WriteRemoteBufferByIp(const std::string& strIP, long nOffset, const std::vector& 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(vecData.size()); std::vector vecBuffer((nSize + 1) / 2, 0); long nRet = 0; { std::lock_guard lock(m_mtx); // Ḭ̈߳²È« ConvertCharToShort(vecData, vecBuffer); nRet = mdRemBufWriteIPEx(m_nPath, static_cast(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 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 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 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 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(enControlCode); if (nControlCode < 0 || nControlCode > 2) { UpdateLastError(ERROR_CODE_INVALID_PARAM); // ²ÎÊý´íÎó return ERROR_CODE_INVALID_PARAM; } // È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§ { std::lock_guard 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 vecEventNumbers, const int nTimeoutMs, EventDetails& details) { std::lock_guard 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 eventno = { 0 }; eventno[0] = static_cast(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(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(station.nStNo | ((station.nNetNo << 8) & 0xFF00)); } // ¼ÆËãÈíÔª¼þÀàÐÍ short CPerformanceMelsec::CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType) { int nDevType = static_cast(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(nDevType); } // std::vectorת»»Îªstd::vector void CPerformanceMelsec::ConvertCharToShort(const std::vector& vecChar, std::vector& 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(vecChar[i]); // µÍ×Ö½Ú } else { vecShort[i / 2] |= static_cast(vecChar[i]) << 8; // ¸ß×Ö½Ú } } } // std::vectorת»»Îªstd::vector void CPerformanceMelsec::ConvertShortToChar(const std::vector& vecShort, std::vector& vecChar) { vecChar.resize(vecShort.size() * 2); // µ÷Õû char ÈÝÆ÷´óС for (size_t i = 0; i < vecShort.size(); i++) { vecChar[i * 2] = static_cast(vecShort[i] & 0xFF); // µÍ×Ö½Ú vecChar[i * 2 + 1] = static_cast((vecShort[i] >> 8) & 0xFF); // ¸ß×Ö½Ú } } // std::vectorת»»Îªstd::vector void CPerformanceMelsec::ConvertUint8ToShort(const std::vector& vecUint8, std::vector& 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(vecUint8[i]); // µÍ×Ö½Ú } else { vecShort[i / 2] |= static_cast(vecUint8[i] << 8); // ¸ß×Ö½Ú } } } // std::vectorת»»Îªstd::vector void CPerformanceMelsec::ConvertShortToUint8(const std::vector& vecShort, std::vector& vecUint8) { vecUint8.resize(vecShort.size() * 2); // µ÷Õû uint8_t ÈÝÆ÷´óС for (size_t i = 0; i < vecShort.size(); i++) { vecUint8[i * 2] = static_cast(vecShort[i] & 0xFF); // µÍ×Ö½Ú vecUint8[i * 2 + 1] = static_cast((vecShort[i] >> 8) & 0xFF); // ¸ß×Ö½Ú } } // std::vectorת»»Îªstd::vector void CPerformanceMelsec::ConvertUint32ToShort(const std::vector& vecUint32, std::vector& vecShort) { vecShort.resize(vecUint32.size() * 2); // ÿ¸ö uint32_t ת»»ÎªÁ½¸ö short for (size_t i = 0; i < vecUint32.size(); i++) { vecShort[i * 2] = static_cast(vecUint32[i] & 0xFFFF); // µÍ16λ vecShort[i * 2 + 1] = static_cast((vecUint32[i] >> 16) & 0xFFFF); // ¸ß16λ } } // std::vectorת»»Îªstd::vector void CPerformanceMelsec::ConvertShortToUint32(const std::vector& vecShort, std::vector& vecUint32) { vecUint32.resize((vecShort.size() + 1) / 2, 0); // ÿÁ½¸ö short ºÏ²¢ÎªÒ»¸ö uint32_t for (size_t i = 0; i < vecUint32.size(); i++) { vecUint32[i] = (static_cast(static_cast(vecShort[i * 2 + 1])) << 16) | // ¸ß16λ static_cast(static_cast(vecShort[i * 2])); // µÍ16λ } } //============================================Ä£°å¸¨Öúº¯Êý==================================================== // ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ template int CPerformanceMelsec::ValidateStationAndData(const StationIdentifier& station, const std::vector& vecData) { // ÑéÖ¤Õ¾µã²ÎÊý const int nRet = ValidateStation(station); if (nRet != 0) { return nRet; // Èç¹ûÕ¾µãÑé֤ʧ°Ü£¬·µ»Ø¶ÔÓ¦´íÎóÂë } // ÑéÖ¤Êý¾ÝÊÇ·ñΪ¿Õ if (vecData.empty()) { return ERROR_CODE_INVALID_PARAM; } return 0; // Ñé֤ͨ¹ý } // ÓɵÍת¸ßÈÝÆ÷µÄÄ£°å£¨ÕûÐÍ£© template void CPerformanceMelsec::ConvertLowToHigh(const std::vector& vecLow, std::vector& vecHigh) { static_assert(std::is_integral::value && std::is_integral::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(vecLow[i]) << ((i % nGroupSize) * CHAR_BIT * sizeof(T))); } return vecHigh; } // ÓɸßתµÍÈÝÆ÷µÄÄ£°å£¨ÕûÐÍ£© template void CPerformanceMelsec::ConvertHighToLow(const std::vector& vecHigh, std::vector& vecLow) { static_assert(std::is_integral::value && std::is_integral::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((vecHigh[i] >> (j * CHAR_BIT * sizeof(U))) & ((1ULL << (CHAR_BIT * sizeof(U))) - 1)); } } return vecLow; }