// 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;
|
|
// ʹÓ÷ָô·û "|" ½âÎöÿһÐÐ
|
if (std::getline(iss, strToken, '|')) {
|
nCode = std::stoi(strToken);
|
}
|
|
if (std::getline(iss, strToken)) {
|
strMessage = strToken;
|
}
|
|
if (!strMessage.empty()) {
|
m_mapError[nCode] = strMessage;
|
}
|
}
|
|
return true;
|
}
|
|
// Á¬½Óµ½PLC
|
int CPerformanceMelsec::Connect(const short nChannel, const short nMode) {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
if (m_bConnected.load()) {
|
return 0;
|
}
|
|
const BoardType enBoardType = FindBoardTypeByChannel(nChannel);
|
if (enBoardType == BoardType::UNKNOWN || enBoardType != m_enBoardType) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
// Á¬½ÓPLC£¬ÏÔʽÀàÐÍת»»ÒÔÆ¥Åä mdOpen µÄÇ©Ãû
|
const short nRet = mdOpen(nChannel, nMode, &m_nPath);
|
if (nRet == 0) {
|
m_bConnected.store(true);
|
m_enBoardType = enBoardType;
|
}
|
else {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// ¶Ï¿ªÁ¬½Ó
|
int CPerformanceMelsec::Disconnect() {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
short nRet = 0;
|
if (m_bConnected.load()) {
|
nRet = mdClose(m_nPath);
|
m_bConnected.store(false);
|
m_nPath = 0;
|
}
|
|
UpdateLastError(nRet);
|
LOG_DEBUG("Close connect.");
|
|
return nRet;
|
}
|
|
// ¿É±à³Ì¿ØÖÆÆ÷ÈíÔª¼þÐÅÏ¢±íµÄ³õʼ»¯
|
int CPerformanceMelsec::InitializeController() {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
if (!m_bConnected.load()) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
const short nRet = mdInit(m_nPath);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// »ñÈ¡°æ±¾ÐÅÏ¢
|
int CPerformanceMelsec::GetBoardVersion(BoardVersion& version) {
|
if (!m_bConnected.load()) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
// »ñÈ¡°æ±¾ÐÅÏ¢
|
short buf[32] = { 0 };
|
const short nRet = mdBdVerRead(m_nPath, buf);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
return nRet;
|
}
|
|
// Ìî³ä°æ±¾ÐÅÏ¢µ½½á¹¹Ìå
|
version.fixedValue[0] = static_cast<char>(buf[0] & 0xFF);
|
version.fixedValue[1] = static_cast<char>((buf[0] >> 8) & 0xFF);
|
|
version.checksum[0] = static_cast<char>(buf[1] & 0xFF);
|
version.checksum[1] = static_cast<char>((buf[1] >> 8) & 0xFF);
|
|
version.swVersion[0] = static_cast<char>(buf[2] & 0xFF);
|
version.swVersion[1] = static_cast<char>((buf[2] >> 8) & 0xFF);
|
|
std::memcpy(version.date, &buf[3], 6);
|
|
version.reserved = static_cast<uint32_t>(buf[6]) | (static_cast<uint32_t>(buf[7]) << 16);
|
|
std::memcpy(version.swModel, &buf[8], 16);
|
std::memcpy(version.hwModel, &buf[16], 16);
|
|
version.twoPortMemory[0] = static_cast<char>(buf[18] & 0xFF);
|
version.twoPortMemory[1] = static_cast<char>((buf[18] >> 8) & 0xFF);
|
|
version.twoPortAttribute[0] = static_cast<char>(buf[19] & 0xFF);
|
version.twoPortAttribute[1] = static_cast<char>((buf[19] >> 8) & 0xFF);
|
|
version.availableBias[0] = static_cast<char>(buf[20] & 0xFF);
|
version.availableBias[1] = static_cast<char>((buf[20] >> 8) & 0xFF);
|
|
std::memcpy(version.moduleType, &buf[21], 10);
|
|
return nRet;
|
}
|
|
// ¶ÁȡĿ±êÕ¾µãCPUÀàÐÍ
|
int CPerformanceMelsec::ReadCPUCode(const StationIdentifier& station, short& nCPUCode) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§
|
{
|
nCPUCode = 0;
|
std::lock_guard<std::mutex> lock(m_mtx);
|
nRet = mdTypeRead(m_nPath, CombineStation(station), &nCPUCode);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// °åģʽÉèÖÃ
|
int CPerformanceMelsec::SetBoardMode(const short nMode) {
|
// ¼ì²éÊÇ·ñÒѾÁ¬½Ó
|
if (!m_bConnected.load()) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
// È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§
|
short nRet = 0;
|
{
|
std::lock_guard<std::mutex> lock(m_mtx);
|
nRet = mdBdModSet(m_nPath, nMode);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// »ñÈ¡°åģʽ
|
int CPerformanceMelsec::GetBoardMode(short& nMode) {
|
// ¼ì²éÊÇ·ñÒѾÁ¬½Ó
|
if (!m_bConnected.load()) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
short nRet = 0;
|
{
|
nMode = 0;
|
std::lock_guard<std::mutex> lock(m_mtx);
|
nRet = mdBdModRead(m_nPath, &nMode);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_DEBUG("Raw Mode: " << nMode);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return 0;
|
}
|
|
// °å¸´Î»
|
int CPerformanceMelsec::BoardReset() {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
if (!m_bConnected.load()) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
const short nRet = mdBdRst(m_nPath);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// °åLED¶ÁÈ¡
|
int CPerformanceMelsec::ReadBoardLed(std::vector<short>& vecLedBuffer) {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
if (!m_bConnected.load()) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
// Çå¿Õ LED »º³åÇø
|
vecLedBuffer.clear();
|
vecLedBuffer.resize(16, 0);
|
|
// µ÷Óà SDK º¯Êý¶ÁÈ¡ LED Êý¾Ý
|
const short nRet = mdBdLedRead(m_nPath, vecLedBuffer.data());
|
if (nRet != 0) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
LOG_ERROR("Error reading board LED, ErrorCode: " << nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// »ñÈ¡°å״̬
|
int CPerformanceMelsec::GetBoardStatus(BoardStatus& status) {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
if (!m_bConnected) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
short buf[6] = { 0 };
|
const short nRet = mdBdSwRead(m_nPath, buf);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
// ½« buf Ó³Éäµ½½á¹¹Ìå
|
status = BoardStatus::fromBuffer(buf);
|
return 0;
|
}
|
|
// ͨÓöÁÊý¾Ý
|
int CPerformanceMelsec::ReadData(const StationIdentifier& station, const long nDevType, const long nDevNo, long nSize, std::vector<short>& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStationAndSize(station, nSize);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// ³õʼ»¯¶ÁÈ¡»º³åÇø
|
vecData.clear();
|
vecData.resize(nSize, 0);
|
|
// È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§
|
{
|
std::lock_guard<std::mutex> lock(m_mtx);
|
short* pData = vecData.data();
|
nSize *= sizeof(short);
|
nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, (long)(unsigned short)nDevNo, &nSize, pData);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
if (nRet != 0) {
|
vecData.clear(); // Èç¹û¶Áȡʧ°Ü£¬Çå¿Õ»º³åÇø
|
}
|
|
return nRet;
|
}
|
|
// ¶ÁȡλÊý¾Ý
|
int CPerformanceMelsec::ReadBitData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nBitCount, BitContainer& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStationAndSize(station, nBitCount);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
if (nDevNo % 8 != 0) {
|
nRet = -2;
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const auto nSize = static_cast<short>((static_cast<int>(nBitCount) + 15) / 16); // ¼ÆËãÐèÒª¶ÁÈ¡µÄ×ÖÊýÁ¿£¨ÏòÉÏÈ¡Õû£©
|
|
std::vector<short> vecTempBuffer(nSize, 0);
|
nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
|
|
if (nRet == 0) {
|
vecData.clear();
|
|
// ½«×ÖÊý¾Ý½âÎöΪλÊý¾Ý
|
for (short nIdx = 0; nIdx < nSize; ++nIdx) {
|
const short nCurrentValue = vecTempBuffer[nIdx];
|
// ±éÀúµ±Ç° short ÖеÄÿһλ
|
for (int bitIdx = 0; bitIdx < 16; ++bitIdx) {
|
bool bBit = (nCurrentValue & (1 << bitIdx)) != 0;
|
vecData.push_back(bBit);
|
if (vecData.size() >= nBitCount) {
|
return nRet; // Èç¹ûÒѾ¶ÁÈ¡ÍêËùÐèµÄλÊý£¬ÌáǰÍ˳ö
|
}
|
}
|
}
|
}
|
|
return nRet;
|
}
|
|
// ¶ÁÈ¡×ÖÊý¾Ý
|
int CPerformanceMelsec::ReadWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nWordCount, WordContainer& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStationAndSize(station, nWordCount);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
std::vector<short> vecTempBuffer(nWordCount, 0);
|
nRet = ReadData(station, nDevType, nDevNo, nWordCount, vecTempBuffer);
|
|
if (nRet == 0) {
|
vecData.clear();
|
vecData.assign(vecTempBuffer.begin(), vecTempBuffer.end());
|
}
|
|
return nRet;
|
}
|
|
// ¶Áȡ˫×ÖÊý¾Ý
|
int CPerformanceMelsec::ReadDWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const short nDWordCount, DWordContainer& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStationAndSize(station, nDWordCount);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const auto nSize = static_cast<short>(nDWordCount * 2); // ÿ¸öË«×ÖÕ¼Á½¸ö×Ö£¨Ã¿¸öË«×ÖÕ¼ 4 ×Ö½Ú£©
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
std::vector<short> vecTempBuffer(nSize, 0);
|
nRet = ReadData(station, nDevType, nDevNo, nSize, vecTempBuffer);
|
|
if (nRet == 0) {
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
ConvertShortToUint32(vecTempBuffer, vecData);
|
}
|
|
return nRet;
|
}
|
|
// ͨÓÃдÊý¾Ý
|
int CPerformanceMelsec::WriteData(const StationIdentifier& station, const long nDevType, const long nDevNo, long nSize, short* pData) {
|
// ÑéÖ¤Õ¾µã²ÎÊý
|
int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// Êý¾ÝÓÐЧÐÔ
|
if (nSize < 0 || pData == nullptr) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
// È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§
|
{
|
std::lock_guard<std::mutex> lock(m_mtx);
|
nSize *= sizeof(short);
|
nRet = mdSendEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, pData);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// дλÊý¾Ý
|
int CPerformanceMelsec::WriteBitData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const BitContainer& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
if (nDevNo % 8 != 0) {
|
nRet = -2;
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const auto nSize = static_cast<short>((static_cast<int>(vecData.size()) + 15) / 16); // ¼ÆËãÐèҪдÈëµÄ×ÖÊýÁ¿£¨ÏòÉÏÈ¡Õû£©
|
|
// ×¼±¸ÁÙʱ»º³åÇøÀ´´æ´¢×ª»»ºóµÄ 16 λÊý¾Ý
|
std::vector<short> vecTempBuffer(nSize, 0);
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
// ½«Î»Êý¾Ý°´×Ö´ò°üµ½ÁÙʱ»º³åÇø
|
for (int i = 0; i < vecData.size(); ++i) {
|
if (vecData[i]) {
|
// ʹÓà & 0xFFFF ±£Ö¤²»»á³¬¹ý 16 룬·ÀÖ¹Òç³ö
|
vecTempBuffer[i / 16] |= static_cast<short>((1 << (i % 16)) & 0xFFFF);
|
}
|
}
|
}
|
|
return WriteData(station, nDevType, nDevNo, nSize, vecTempBuffer.data());
|
}
|
|
// д×ÖÊý¾Ý
|
int CPerformanceMelsec::WriteWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const WordContainer& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
const int nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// ¼ÆËãÐèҪдÈëµÄ×Ö½ÚÊý£¨Ã¿¸ö×ÖÕ¼ 2 ×Ö½Ú£©
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const auto nSize = static_cast<short>(vecData.size());
|
const auto pData = const_cast<short*>(reinterpret_cast<const short*>(vecData.data()));
|
|
return WriteData(station, nDevType, nDevNo, nSize, pData);
|
}
|
|
// д˫×ÖÊý¾Ý
|
int CPerformanceMelsec::WriteDWordData(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo, const DWordContainer& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
const int nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// ¼ÆËãÐèҪдÈëµÄ×Ö½ÚÊý£¨Ã¿¸öË«×ÖÕ¼ 4 ×Ö½Ú£©
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const auto nSize = static_cast<short>(vecData.size() * sizeof(short));
|
std::vector<short> vecBuffer(nSize, 0);
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
ConvertUint32ToShort(vecData, vecBuffer);
|
}
|
|
return WriteData(station, nDevType, nDevNo, nSize, vecBuffer.data());
|
}
|
|
// À©Õ¹¶ÁÊý¾Ý
|
long CPerformanceMelsec::ReadDataEx(const StationIdentifier& station, long nDevType, long nDevNo, long nSize, std::vector<char>& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍ¶ÁÈ¡´óСÊÇ·ñÓÐЧ
|
long nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
if (nSize < 0) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
nSize = nSize % 2 != 0 ? nSize + 1 : nSize;
|
std::vector<short> vecBuffer(nSize / 2, 0);
|
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
nRet = mdReceiveEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, vecBuffer.data());
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
else {
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
vecData.resize(nSize);
|
ConvertShortToChar(vecBuffer, vecData);
|
}
|
|
return 0;
|
}
|
|
// À©Õ¹¶ÁȡλÊý¾Ý
|
long CPerformanceMelsec::ReadBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nBitCount, BitContainer& vecData) {
|
long nRet = ValidateStationAndSize(station, nBitCount);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
if (nDevNo % 8 != 0) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const long nWordCount = (nBitCount + 15) / 16;
|
const long nByteSize = nWordCount * sizeof(short);
|
|
std::vector<char> vecRaw;
|
nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
|
if (nRet != 0) {
|
return nRet;
|
}
|
|
vecData.clear();
|
for (long i = 0; i < nWordCount; ++i) {
|
short word = static_cast<unsigned char>(vecRaw[i * 2]) |
|
(static_cast<unsigned char>(vecRaw[i * 2 + 1]) << 8);
|
for (int j = 0; j < 16; ++j) {
|
vecData.push_back((word & (1 << j)) != 0);
|
if (vecData.size() >= static_cast<size_t>(nBitCount)) {
|
return 0;
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
// À©Õ¹¶ÁÈ¡×ÖÊý¾Ý
|
long CPerformanceMelsec::ReadWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nWordCount, WordContainer& vecData) {
|
long nRet = ValidateStationAndSize(station, nWordCount);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const long nByteSize = nWordCount * sizeof(short);
|
|
std::vector<char> vecRaw;
|
nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
|
if (nRet != 0) {
|
return nRet;
|
}
|
|
vecData.clear();
|
for (long i = 0; i < nWordCount; ++i) {
|
short value = static_cast<unsigned char>(vecRaw[i * 2]) |
|
(static_cast<unsigned char>(vecRaw[i * 2 + 1]) << 8);
|
vecData.push_back(value);
|
}
|
|
return 0;
|
}
|
|
// À©Õ¹¶Áȡ˫×ÖÊý¾Ý
|
long CPerformanceMelsec::ReadDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, long nDWordCount, DWordContainer& vecData) {
|
long nRet = ValidateStationAndSize(station, nDWordCount);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const long nByteSize = nDWordCount * sizeof(uint32_t);
|
|
std::vector<char> vecRaw;
|
nRet = ReadDataEx(station, nDevType, nDevNo, nByteSize, vecRaw);
|
if (nRet != 0) {
|
return nRet;
|
}
|
|
vecData.clear();
|
for (long i = 0; i < nDWordCount; ++i) {
|
uint32_t val = static_cast<unsigned char>(vecRaw[i * 4 + 0]) |
|
(static_cast<unsigned char>(vecRaw[i * 4 + 1]) << 8) |
|
(static_cast<unsigned char>(vecRaw[i * 4 + 2]) << 16) |
|
(static_cast<unsigned char>(vecRaw[i * 4 + 3]) << 24);
|
vecData.push_back(val);
|
}
|
|
return 0;
|
}
|
|
// À©Õ¹Ð´Êý¾Ý
|
long CPerformanceMelsec::WriteDataEx(const StationIdentifier& station, long nDevType, long nDevNo, const std::vector<char>& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
long nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// ½« vecData ת»»Îª short ÀàÐ͵Ļº³åÇø
|
long nSize = static_cast<long>(vecData.size());
|
nSize = nSize % 2 != 0 ? nSize + 1 : nSize;
|
std::vector<short> vecBuffer(nSize / 2, 0);
|
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
ConvertCharToShort(vecData, vecBuffer);
|
nRet = mdSendEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo, &nSize, vecBuffer.data());
|
}
|
|
// ´íÎó´¦ÀíºÍÈÕÖ¾¼Ç¼
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// À©Õ¹Ð´Î»Êý¾Ý
|
long CPerformanceMelsec::WriteBitDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const BitContainer& vecData) {
|
long nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
if (nDevNo % 8 != 0) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
const size_t nWordCount = (vecData.size() + 15) / 16;
|
|
std::vector<short> vecWordBuffer(nWordCount, 0);
|
for (size_t i = 0; i < vecData.size(); ++i) {
|
if (vecData[i]) {
|
vecWordBuffer[i / 16] |= (1 << (i % 16));
|
}
|
}
|
|
// ת»» short -> char
|
std::vector<char> vecByteBuffer;
|
vecByteBuffer.resize(nWordCount * sizeof(short));
|
for (size_t i = 0; i < nWordCount; ++i) {
|
vecByteBuffer[i * 2] = static_cast<char>(vecWordBuffer[i] & 0xFF);
|
vecByteBuffer[i * 2 + 1] = static_cast<char>((vecWordBuffer[i] >> 8) & 0xFF);
|
}
|
|
return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
|
}
|
|
// À©Õ¹Ð´×ÖÊý¾Ý
|
long CPerformanceMelsec::WriteWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const WordContainer& vecData) {
|
long nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
std::vector<char> vecByteBuffer;
|
vecByteBuffer.resize(vecData.size() * sizeof(short));
|
|
for (size_t i = 0; i < vecData.size(); ++i) {
|
vecByteBuffer[i * 2] = static_cast<char>(vecData[i] & 0xFF);
|
vecByteBuffer[i * 2 + 1] = static_cast<char>((vecData[i] >> 8) & 0xFF);
|
}
|
|
return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
|
}
|
|
// À©Õ¹Ð´Ë«×ÖÊý¾Ý
|
long CPerformanceMelsec::WriteDWordDataEx(const StationIdentifier& station, DeviceType enDevType, long nDevNo, const DWordContainer& vecData) {
|
long nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
std::vector<char> vecByteBuffer;
|
vecByteBuffer.resize(vecData.size() * sizeof(uint32_t));
|
|
for (size_t i = 0; i < vecData.size(); ++i) {
|
vecByteBuffer[i * 4] = static_cast<char>(vecData[i] & 0xFF);
|
vecByteBuffer[i * 4 + 1] = static_cast<char>((vecData[i] >> 8) & 0xFF);
|
vecByteBuffer[i * 4 + 2] = static_cast<char>((vecData[i] >> 16) & 0xFF);
|
vecByteBuffer[i * 4 + 3] = static_cast<char>((vecData[i] >> 24) & 0xFF);
|
}
|
|
return WriteDataEx(station, nDevType, nDevNo, vecByteBuffer);
|
}
|
|
// À©Õ¹ÈíÔª¼þËæ»ú¶ÁÈ¡
|
long CPerformanceMelsec::ReadRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, std::vector<char>& vecData) {
|
if (vecSoftElements.empty()) {
|
UpdateLastError(ERROR_INVALID_PARAMETER);
|
LOG_ERROR("Invalid parameters: soft elements are empty.");
|
return ERROR_INVALID_PARAMETER;
|
}
|
|
// ×¼±¸ dev Êý¾Ý
|
std::vector<short> devBuffer(vecSoftElements.size() * 3 + 1, 0); // ÿ¸öÈíÔª¼þÐèÒª 3 ¸ö short£¬Íâ¼ÓÒ»¸ö¼ÆÊýÆ÷
|
devBuffer[0] = static_cast<short>(vecSoftElements.size()); // µÚÒ»¸öÔªËØÊÇÈíÔª¼þÊýÁ¿
|
for (size_t i = 0; i < vecSoftElements.size(); ++i) {
|
const SoftElement& element = vecSoftElements[i];
|
devBuffer[i * 3 + 1] = element.nType; // ÈíÔª¼þÀàÐÍ
|
devBuffer[i * 3 + 2] = static_cast<short>(element.nStartNo); // ÆðʼÈíÔª¼þ±àºÅ
|
devBuffer[i * 3 + 3] = element.nElementCount; // µãÊý
|
}
|
|
// ¼ÆËã¶ÁÈ¡Êý¾ÝËùÐ軺³åÇø´óС
|
long nBufferSize = 0;
|
for (const auto& element : vecSoftElements) {
|
nBufferSize += element.nElementCount * 2; // ÿ¸öµãÕ¼Óà 2 ¸ö×Ö½Ú
|
}
|
|
// Ëø±£»¤¼°µ÷Óà mdRandREx
|
long nRet = 0;
|
std::vector<short> vecBuffer(nBufferSize / 2, 0);
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // È·±£Ḭ̈߳²È«
|
nRet = mdRandREx(m_nPath, station.nNetNo, station.nStNo, devBuffer.data(), vecBuffer.data(), nBufferSize);
|
}
|
|
// ´íÎó´¦ÀíºÍÈÕÖ¾¼Ç¼
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
return nRet;
|
}
|
|
// ½«¶ÁÈ¡µ½µÄ short Êý¾Ýת»»Îª char Êý¾Ý
|
vecData.resize(nBufferSize);
|
for (size_t i = 0; i < vecBuffer.size(); ++i) {
|
vecData[i * 2] = static_cast<char>(vecBuffer[i] & 0xFF); // µÍ×Ö½Ú
|
vecData[i * 2 + 1] = static_cast<char>((vecBuffer[i] >> 8) & 0xFF); // ¸ß×Ö½Ú
|
}
|
|
return nRet;
|
}
|
|
// À©Õ¹ÈíÔª¼þËæ»úдÈ루֧³Ö¶à¸öÈíÔª¼þ£©
|
long CPerformanceMelsec::WriteRandomDataEx(const StationIdentifier& station, const std::vector<SoftElement>& vecSoftElements, const std::vector<char>& vecData) {
|
if (vecSoftElements.empty() || vecData.empty()) {
|
UpdateLastError(ERROR_INVALID_PARAMETER);
|
LOG_ERROR("Invalid parameters: soft elements or data is empty.");
|
return ERROR_INVALID_PARAMETER;
|
}
|
|
// ×¼±¸ dev Êý¾Ý
|
std::vector<long> devBuffer(vecSoftElements.size() * 3 + 1, 0); // ÿ¸öÈíÔª¼þÐèÒª 3 ¸ö long£¬Íâ¼ÓÒ»¸ö¼ÆÊýÆ÷
|
devBuffer[0] = static_cast<long>(vecSoftElements.size()); // µÚÒ»¸öÔªËØÊÇÈíÔª¼þÊýÁ¿
|
for (size_t i = 0; i < vecSoftElements.size(); ++i) {
|
const SoftElement& element = vecSoftElements[i];
|
devBuffer[i * 3 + 1] = static_cast<long>(element.nType); // ÈíÔª¼þÀàÐÍ
|
devBuffer[i * 3 + 2] = element.nStartNo; // ÆðʼÈíÔª¼þ±àºÅ£¨ÒѾÊÇ long ÀàÐÍ£¬ÎÞÐèת»»£©
|
devBuffer[i * 3 + 3] = static_cast<long>(element.nElementCount); // µãÊý
|
}
|
|
// Ëø±£»¤¼°µ÷Óà mdRandWEx
|
long nRet = 0;
|
std::vector<short> vecBuffer(vecData.size() / 2, 0);
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // È·±£Ḭ̈߳²È«
|
ConvertCharToShort(vecData, vecBuffer);
|
nRet = mdRandWEx(m_nPath, station.nNetNo, station.nStNo, devBuffer.data(), vecBuffer.data(), static_cast<long>(vecBuffer.size()));
|
}
|
|
// ´íÎó´¦ÀíºÍÈÕÖ¾¼Ç¼
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// Ô¶³ÌÉ豸վ/Ô¶³ÌÕ¾µÄ»º³å´æ´¢Æ÷¶ÁÈ¡
|
long CPerformanceMelsec::ReadRemoteBuffer(const StationIdentifier& station, long nOffset, long nSize, std::vector<char>& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
if (nSize < 0) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
long nActualSize = (nSize + 1) / 2;
|
std::vector<short> vecBuffer(nActualSize, 0);
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
nRet = mdRemBufReadEx(m_nPath, station.nNetNo, station.nStNo, nOffset, &nActualSize, vecBuffer.data());
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet); // ¸üдíÎóÂë
|
LOG_ERROR(m_strLastError);
|
}
|
else {
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
ConvertShortToChar(vecBuffer, vecData);
|
}
|
|
return nRet;
|
}
|
|
// Ô¶³ÌÉ豸վ/Ô¶³ÌÕ¾µÄ»º³å´æ´¢Æ÷дÈë
|
long CPerformanceMelsec::WriteRemoteBuffer(const StationIdentifier& station, long nOffset, const std::vector<char>& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
long nRet = ValidateStationAndData(station, vecData);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// ½« vecData ת»»Îª short ÀàÐ͵Ļº³åÇø
|
long nSize = static_cast<long>(vecData.size());
|
std::vector<short> vecBuffer((nSize + 1) / 2, 0);
|
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
ConvertCharToShort(vecData, vecBuffer);
|
nRet = mdRemBufWriteEx(m_nPath, station.nNetNo, station.nStNo, nOffset, &nSize, vecBuffer.data());
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// Ô¶³ÌÕ¾µÄ»º³å´æ´¢Æ÷¶ÁÈ¡ ¶ÔÏóÕ¾IPµØÖ·Ö¸¶¨
|
long CPerformanceMelsec::ReadRemoteBufferByIp(const std::string& strIP, long nOffset, long nSize, std::vector<char>& vecData) {
|
uint32_t nAddress = 0;
|
if (nSize < 0 || !ConvertIpStringToUint32(strIP, nAddress)) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
// ½«»º³åÇø´óСµ÷ÕûΪ nSize
|
vecData.resize(nSize, 0);
|
std::vector<short> vecBuffer((nSize + 1) / 2, 0); // ת»»Îª short ÀàÐÍ
|
|
// µ÷Óõײã SDK
|
long nRet = 0;
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
nRet = mdRemBufReadIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
else {
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«±£»¤
|
ConvertShortToChar(vecBuffer, vecData);
|
}
|
|
return nRet;
|
}
|
|
// Ô¶³ÌÕ¾µÄ»º³å´æ´¢Æ÷дÈë ¶ÔÏóÕ¾IPµØÖ·Ö¸¶¨
|
long CPerformanceMelsec::WriteRemoteBufferByIp(const std::string& strIP, long nOffset, const std::vector<char>& vecData) {
|
uint32_t nAddress = 0;
|
if (vecData.empty() || !ConvertIpStringToUint32(strIP, nAddress)) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
// ת»» vecData Ϊ short ÀàÐ͵Ļº³åÇø
|
long nSize = static_cast<long>(vecData.size());
|
std::vector<short> vecBuffer((nSize + 1) / 2, 0);
|
|
long nRet = 0;
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«
|
ConvertCharToShort(vecData, vecBuffer);
|
nRet = mdRemBufWriteIPEx(m_nPath, static_cast<long>(nAddress), nOffset, &nSize, vecBuffer.data());
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// ÉèÖÃ(ON)¶ÔÏóÕ¾µÄÖ¸¶¨Î»ÈíÔª¼þ
|
int CPerformanceMelsec::SetBitDevice(const StationIdentifier& station, const DeviceType enDevType, const short nDevNo) {
|
// ÑéÖ¤Õ¾µã²ÎÊý
|
int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§
|
{
|
std::lock_guard<std::mutex> lock(m_mtx); // Ḭ̈߳²È«
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
nRet = mdDevSet(m_nPath, CombineStation(station), nDevType, nDevNo);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// ¸´Î»(OFF)¶ÔÏóÕ¾µÄÖ¸¶¨Î»ÈíÔª¼þ
|
int CPerformanceMelsec::ResetBitDevice(const StationIdentifier& station, const DeviceType enDevType, const short enDevNo) {
|
// ÑéÖ¤Õ¾µã²ÎÊý
|
int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§
|
{
|
std::lock_guard<std::mutex> lock(m_mtx);
|
const short nDevType = CalculateDeviceType(station, enDevType);
|
nRet = mdDevRst(m_nPath, CombineStation(station), nDevType, enDevNo);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// À©Õ¹Î»ÈíÔª¼þÉèÖÃ
|
long CPerformanceMelsec::SetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo) {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
// ¼ì²é²ÎÊýÓÐЧÐÔ
|
long nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
nRet = mdDevSetEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// À©Õ¹Î»ÈíÔª¼þ¸´Î»
|
long CPerformanceMelsec::ResetBitDeviceEx(const StationIdentifier& station, long nDevType, long nDevNo) {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
// ¼ì²é²ÎÊýÓÐЧÐÔ
|
long nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
nRet = mdDevRstEx(m_nPath, station.nNetNo, station.nStNo, nDevType, nDevNo);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// Ö´ÐжÔÏóÕ¾µÄCPU
|
int CPerformanceMelsec::ControlCPU(const StationIdentifier& station, ControlCode enControlCode) {
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
return nRet;
|
}
|
|
// ÑéÖ¤¿ØÖÆÂëÊÇ·ñºÏ·¨
|
const auto nControlCode = static_cast<short>(enControlCode);
|
if (nControlCode < 0 || nControlCode > 2) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM); // ²ÎÊý´íÎó
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
// È·±£Ḭ̈߳²È«µÄ×îÐ¡Ëø¶¨·¶Î§
|
{
|
std::lock_guard<std::mutex> lock(m_mtx);
|
nRet = mdControl(m_nPath, CombineStation(station), nControlCode);
|
}
|
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
// ʼþµÈ´ý
|
int CPerformanceMelsec::WaitForBoardEvent(std::vector<short> vecEventNumbers, const int nTimeoutMs, EventDetails& details) {
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
if (!m_bConnected.load()) {
|
UpdateLastError(ERROR_CODE_NOT_CONNECTED);
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
if (vecEventNumbers.empty() || vecEventNumbers.size() > 64) {
|
UpdateLastError(ERROR_CODE_INVALID_PARAM);
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
// µÚ 0 ¸öÔªËØ´æ´¢ÊýÁ¿£¬×î´óÖ§³Ö 64 ¸öʼþ
|
std::array<short, 65> eventno = { 0 };
|
eventno[0] = static_cast<short>(vecEventNumbers.size());
|
std::copy(vecEventNumbers.begin(), vecEventNumbers.end(), eventno.begin() + 1);
|
|
// ³õʼ»¯Êä³ö²ÎÊý
|
details.nEventNo = 0;
|
details.details.fill(0);
|
|
const int nRet = mdWaitBdEvent(m_nPath, eventno.data(), nTimeoutMs, &details.nEventNo, details.details.data());
|
if (nRet != 0) {
|
UpdateLastError(nRet);
|
LOG_ERROR(m_strLastError);
|
}
|
|
return nRet;
|
}
|
|
//============================================¸¨Öúº¯Êý=======================================================
|
// ¸üÐÂ×î½üµÄ´íÎóÐÅÏ¢
|
void CPerformanceMelsec::UpdateLastError(const int nCode) {
|
if (nCode == 0) {
|
return;
|
}
|
|
// ¼ì²é´íÎóÂëÊÇ·ñ´æÔÚÓÚÓ³Éä±íÖÐ
|
const auto it = m_mapError.find(nCode);
|
if (it != m_mapError.end()) {
|
// Èç¹ûÕÒµ½£¬Ö±½Ó·µ»Ø¶ÔÓ¦ÓïÑԵĴíÎóÐÅÏ¢
|
m_strLastError = it->second;
|
}
|
else {
|
// Èç¹ûδÕÒµ½£¬´¦ÀíÌØÊⷶΧ
|
m_strLastError = "Unknown error.";
|
if (nCode == -28611 || nCode == -28612) {
|
// ϵͳ³ö´í
|
m_strLastError = "System error.";
|
}
|
|
if (nCode >= -20480 && nCode <= -16384) {
|
// CC-Link ϵͳ¼ì²â³öµÄ´íÎó
|
m_strLastError = "Error detected in the CC-Link system.";
|
}
|
|
if (nCode >= -12288 && nCode <= -8193) {
|
// CC-Link IE TSN ϵͳ¼ì²â³öµÄ´íÎó
|
m_strLastError = "Error detected in the CC-Link IE TSN system.";
|
}
|
|
if (nCode >= -8192 && nCode <= -4097) {
|
// CC-Link IE ¿ØÖÆÍøÂçϵͳ¼ì²â³öµÄ´íÎó
|
m_strLastError = "Error detected in the CC-Link IE control network system.";
|
}
|
|
if (nCode >= -4096 && nCode <= -257) {
|
// MELSECNET/10 »ò MELSECNET/ÍøÂçϵͳ´íÎó·¶Î§
|
m_strLastError = "Errors detected in MELSECNET/10 or MELSECNET/network system.";
|
}
|
|
if (nCode >= 4096 && nCode <= 16383) {
|
// MELSEC Êý¾ÝÁ´½Ó¿â·¶Î§
|
m_strLastError = "Internal error detected by MELSEC Data Link Library.";
|
}
|
|
if (nCode == 18944 || nCode == 18945) {
|
// Á´½Ó¹ØÁª³ö´í
|
m_strLastError = "Link association error: Network does not exist, unsupported CPU, or incorrect network No./station number.";
|
}
|
|
if (nCode >= 16384 && nCode <= 20479) {
|
// PLC CPU ¼ì²â·¶Î§
|
m_strLastError = "Errors detected by the programmable controller CPU in the target station.";
|
}
|
|
if (nCode >= 28416 && nCode <= 28671) {
|
// ÈßÓ๦ÄÜÄ£¿é·¶Î§
|
m_strLastError = "Error detected in the redundancy module of the target station.";
|
}
|
}
|
}
|
|
// ¼ì²éÁ¬½Ó״̬ºÍÕ¾µã²ÎÊýÓÐЧÐÔ
|
int CPerformanceMelsec::ValidateStation(const StationIdentifier& station) const {
|
// ¼ì²éÊÇ·ñÒÑÁ¬½Ó
|
if (!m_bConnected.load()) {
|
return ERROR_CODE_NOT_CONNECTED;
|
}
|
|
// ¼ì²éÍøÂçºÅºÍÕ¾µãºÅ·¶Î§
|
if (station.nNetNo < 0 || station.nNetNo > 239 || station.nStNo < 0 || station.nStNo > 255) {
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
return 0; // ²ÎÊýÓÐЧ
|
}
|
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
int CPerformanceMelsec::ValidateStationAndSize(const StationIdentifier& station, const short nCount) const {
|
// ÑéÖ¤Õ¾µã²ÎÊý
|
const int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
return nRet; // Èç¹ûÕ¾µãÑé֤ʧ°Ü£¬·µ»Ø¶ÔÓ¦´íÎóÂë
|
}
|
|
if (nCount <= 0) {
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
return 0; // Ñé֤ͨ¹ý
|
}
|
|
// IP×Ö·û´®×ªuint32_t
|
bool CPerformanceMelsec::ConvertIpStringToUint32(const std::string& strIP, uint32_t& nIP) {
|
nIP = 0;
|
std::stringstream ss(strIP);
|
std::string strSegment;
|
int nShift = 24;
|
|
while (std::getline(ss, strSegment, '.')) {
|
const auto nByte = static_cast<uint32_t>(std::stoi(strSegment));
|
if (nByte > 255) {
|
return false;
|
}
|
nIP |= (nByte << nShift);
|
nShift -= 8;
|
}
|
|
return true;
|
}
|
|
//============================================¾²Ì¬¸¨Öúº¯Êý====================================================
|
// ÑÓʱ£¬²¢ÇÒת·¢´°¿ÚÏûÏ¢
|
void CPerformanceMelsec::Delay(const unsigned int nDelayMs) {
|
MSG message;
|
// Èç¹ûÑÓ³Ùʱ¼äΪ 0£¬½ö´¦ÀíÒ»´ÎÏûÏ¢¶ÓÁÐ
|
if (nDelayMs == 0) {
|
// ·Ç×èÈûµÄ¼ì²éÏûÏ¢¶ÓÁÐ
|
if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
|
TranslateMessage(&message); // ½«ÏûϢת»¯ÎªÓÐЧµÄ´°¿ÚÏûÏ¢
|
DispatchMessage(&message); // ÅÉ·¢ÏûÏ¢¸øÏàÓ¦µÄ´°¿Ú¹ý³Ì
|
}
|
return;
|
}
|
|
DWORD finish;
|
const DWORD start = GetTickCount(); // »ñÈ¡µ±Ç°µÄʱ¼ä´Á£¨´ÓϵͳÆô¶¯ÒÔÀ´µÄºÁÃëÊý£©
|
do {
|
if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
|
TranslateMessage(&message); // ת»»ÏûÏ¢
|
DispatchMessage(&message); // ´¦ÀíÏûÏ¢
|
}
|
Sleep(1); // ÔÝÍ£ 1 ºÁÃ룬·ÀÖ¹¹ý¶ÈÕ¼Óà CPU
|
finish = GetTickCount(); // »ñÈ¡µ±Ç°µÄʱ¼ä´Á
|
} while ((finish - start) < nDelayMs); // Ñ»·Ö±µ½¾¹ýµÄʱ¼ä´óÓÚÖ¸¶¨µÄÑÓ³Ùʱ¼ä
|
}
|
|
BoardType CPerformanceMelsec::FindBoardTypeByChannel(const int nChannel) {
|
if (nChannel >= MELSECNET_CHANNEL(1) && nChannel <= MELSECNET_CHANNEL(4)) {
|
return BoardType::MELSECNET_H;
|
}
|
else if (nChannel >= CC_LINK_CHANNEL(1) && nChannel <= CC_LINK_CHANNEL(4)) {
|
return BoardType::CC_LINK_VER_2;
|
}
|
else if (nChannel >= CC_LINK_IE_CONTROL_CHANNEL(1) && nChannel <= CC_LINK_IE_CONTROL_CHANNEL(4)) {
|
return BoardType::CC_LINK_IE_CONTROL;
|
}
|
else if (nChannel >= CC_LINK_IE_FIELD_CHANNEL(1) && nChannel <= CC_LINK_IE_FIELD_CHANNEL(4)) {
|
return BoardType::CC_LINK_IE_FIELD;
|
}
|
else if (nChannel >= CC_LINK_IE_TSN_CHANNEL(1) && nChannel <= CC_LINK_IE_TSN_CHANNEL(4)) {
|
return BoardType::CC_LINK_IE_TSN;
|
}
|
return BoardType::UNKNOWN;
|
}
|
|
// ºÏ²¢ÍøÂçºÅºÍÕ¾µãºÅ
|
short CPerformanceMelsec::CombineStation(const StationIdentifier& station) {
|
return static_cast<short>(station.nStNo | ((station.nNetNo << 8) & 0xFF00));
|
}
|
|
// ¼ÆËãÈíÔª¼þÀàÐÍ
|
short CPerformanceMelsec::CalculateDeviceType(const StationIdentifier& station, DeviceType enDevType) {
|
int nDevType = static_cast<int>(enDevType);
|
|
// ¸ù¾ÝÈíÔª¼þÀàÐ͵ÄÌØ¶¨¹æÔò½øÐмÆËã
|
if (enDevType == DeviceType::LX || enDevType == DeviceType::LY ||
|
enDevType == DeviceType::LB || enDevType == DeviceType::LW ||
|
enDevType == DeviceType::LSB || enDevType == DeviceType::LSW) {
|
// ÍøÂçºÅ¼ÓÆ«ÒÆ
|
nDevType += station.nNetNo;
|
}
|
else if (enDevType == DeviceType::ER) {
|
// Îļþ¼Ä´æÆ÷µÄ¿éºÅ¼ÓÆ«ÒÆ
|
nDevType += 0;
|
}
|
else if (enDevType == DeviceType::SPG) {
|
// Æðʼ I/O No. ¡Â 16 µÄÖµ
|
nDevType += 0 / 16;
|
}
|
|
return static_cast<short>(nDevType);
|
}
|
|
// std::vector<char>ת»»Îªstd::vector<short>
|
void CPerformanceMelsec::ConvertCharToShort(const std::vector<char>& vecChar, std::vector<short>& vecShort) {
|
vecShort.resize((vecChar.size() + 1) / 2, 0); // µ÷Õû short ÈÝÆ÷´óС
|
for (size_t i = 0; i < vecChar.size(); i++) {
|
if (i % 2 == 0) {
|
vecShort[i / 2] = static_cast<unsigned char>(vecChar[i]); // µÍ×Ö½Ú
|
}
|
else {
|
vecShort[i / 2] |= static_cast<unsigned char>(vecChar[i]) << 8; // ¸ß×Ö½Ú
|
}
|
}
|
}
|
|
// std::vector<short>ת»»Îªstd::vector<char>
|
void CPerformanceMelsec::ConvertShortToChar(const std::vector<short>& vecShort, std::vector<char>& vecChar) {
|
vecChar.resize(vecShort.size() * 2); // µ÷Õû char ÈÝÆ÷´óС
|
for (size_t i = 0; i < vecShort.size(); i++) {
|
vecChar[i * 2] = static_cast<char>(vecShort[i] & 0xFF); // µÍ×Ö½Ú
|
vecChar[i * 2 + 1] = static_cast<char>((vecShort[i] >> 8) & 0xFF); // ¸ß×Ö½Ú
|
}
|
}
|
|
// std::vector<uint8_t>ת»»Îªstd::vector<short>
|
void CPerformanceMelsec::ConvertUint8ToShort(const std::vector<uint8_t>& vecUint8, std::vector<short>& vecShort) {
|
vecShort.resize((vecUint8.size() + 1) / 2, 0); // µ÷Õû short ÈÝÆ÷´óС
|
for (size_t i = 0; i < vecUint8.size(); i++) {
|
if (i % 2 == 0) {
|
vecShort[i / 2] = static_cast<short>(vecUint8[i]); // µÍ×Ö½Ú
|
}
|
else {
|
vecShort[i / 2] |= static_cast<short>(vecUint8[i] << 8); // ¸ß×Ö½Ú
|
}
|
}
|
}
|
|
// std::vector<short>ת»»Îªstd::vector<uint8_t>
|
void CPerformanceMelsec::ConvertShortToUint8(const std::vector<short>& vecShort, std::vector<uint8_t>& vecUint8) {
|
vecUint8.resize(vecShort.size() * 2); // µ÷Õû uint8_t ÈÝÆ÷´óС
|
for (size_t i = 0; i < vecShort.size(); i++) {
|
vecUint8[i * 2] = static_cast<uint8_t>(vecShort[i] & 0xFF); // µÍ×Ö½Ú
|
vecUint8[i * 2 + 1] = static_cast<uint8_t>((vecShort[i] >> 8) & 0xFF); // ¸ß×Ö½Ú
|
}
|
}
|
|
// std::vector<uint32_t>ת»»Îªstd::vector<short>
|
void CPerformanceMelsec::ConvertUint32ToShort(const std::vector<uint32_t>& vecUint32, std::vector<short>& vecShort) {
|
vecShort.resize(vecUint32.size() * 2); // ÿ¸ö uint32_t ת»»ÎªÁ½¸ö short
|
for (size_t i = 0; i < vecUint32.size(); i++) {
|
vecShort[i * 2] = static_cast<short>(vecUint32[i] & 0xFFFF); // µÍ16λ
|
vecShort[i * 2 + 1] = static_cast<short>((vecUint32[i] >> 16) & 0xFFFF); // ¸ß16λ
|
}
|
}
|
|
// std::vector<short>ת»»Îªstd::vector<uint32_t>
|
void CPerformanceMelsec::ConvertShortToUint32(const std::vector<short>& vecShort, std::vector<uint32_t>& vecUint32) {
|
vecUint32.resize((vecShort.size() + 1) / 2, 0); // ÿÁ½¸ö short ºÏ²¢ÎªÒ»¸ö uint32_t
|
for (size_t i = 0; i < vecUint32.size(); i++) {
|
vecUint32[i] = (static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2 + 1])) << 16) | // ¸ß16λ
|
static_cast<uint32_t>(static_cast<uint16_t>(vecShort[i * 2])); // µÍ16λ
|
}
|
}
|
|
//============================================Ä£°å¸¨Öúº¯Êý====================================================
|
// ÑéÖ¤Õ¾µã²ÎÊýºÍÊý¾ÝÓÐЧÐÔ
|
template <typename T>
|
int CPerformanceMelsec::ValidateStationAndData(const StationIdentifier& station, const std::vector<T>& vecData) {
|
// ÑéÖ¤Õ¾µã²ÎÊý
|
const int nRet = ValidateStation(station);
|
if (nRet != 0) {
|
return nRet; // Èç¹ûÕ¾µãÑé֤ʧ°Ü£¬·µ»Ø¶ÔÓ¦´íÎóÂë
|
}
|
|
// ÑéÖ¤Êý¾ÝÊÇ·ñΪ¿Õ
|
if (vecData.empty()) {
|
return ERROR_CODE_INVALID_PARAM;
|
}
|
|
return 0; // Ñé֤ͨ¹ý
|
}
|
|
// ÓɵÍת¸ßÈÝÆ÷µÄÄ£°å£¨ÕûÐÍ£©
|
template <typename T, typename U>
|
void CPerformanceMelsec::ConvertLowToHigh(const std::vector<T>& vecLow, std::vector<U>& vecHigh) {
|
static_assert(std::is_integral<T>::value && std::is_integral<U>::value, "T and U must be integral types");
|
|
// ×Ô¶¯¼ÆËã nGroupSize
|
constexpr size_t nGroupSize = sizeof(U) / sizeof(T);
|
|
// Èç¹û T ºÍ U µÄ´óСÏàµÈ£¬Ö±½Óת»»
|
if (sizeof(T) == sizeof(U)) {
|
vecHigh.assign(vecLow.begin(), vecLow.end());
|
return;
|
}
|
|
// Èç¹û U µÄ´óСÊÇ T µÄ±¶Êý£¬Õý³£×éºÏ
|
static_assert(sizeof(U) > sizeof(T), "Size of U must be greater than or equal to size of T");
|
|
// ¼ÆËãÍêÕû×éµÄÊýÁ¿
|
size_t nHighSize = (vecLow.size() + nGroupSize - 1) / nGroupSize; // ÏòÉÏÈ¡Õû
|
vecHigh.resize(nHighSize, 0);
|
|
// ºÏ²¢µÍλÊý¾Ýµ½¸ßλÊý¾Ý
|
for (size_t i = 0; i < vecLow.size(); i++) {
|
vecHigh[i / nGroupSize] |= (static_cast<U>(vecLow[i]) << ((i % nGroupSize) * CHAR_BIT * sizeof(T)));
|
}
|
|
return vecHigh;
|
}
|
|
// ÓɸßתµÍÈÝÆ÷µÄÄ£°å£¨ÕûÐÍ£©
|
template <typename T, typename U>
|
void CPerformanceMelsec::ConvertHighToLow(const std::vector<T>& vecHigh, std::vector<U>& vecLow) {
|
static_assert(std::is_integral<T>::value && std::is_integral<U>::value, "T and U must be integral types");
|
|
// ×Ô¶¯¼ÆËã nGroupSize
|
constexpr size_t nGroupSize = sizeof(T) / sizeof(U);
|
|
// Èç¹û T ºÍ U µÄ´óСÏàµÈ£¬Ö±½Óת»»
|
if (sizeof(T) == sizeof(U)) {
|
vecLow.assign(vecHigh.begin(), vecHigh.end());
|
return;
|
}
|
|
// Èç¹û T µÄ´óСÊÇ U µÄ±¶Êý£¬Õý³£·Ö½â
|
static_assert(sizeof(T) > sizeof(U), "Size of T must be greater than or equal to size of U");
|
|
size_t nLowSize = vecHigh.size() * nGroupSize; // µÍÈÝÆ÷µÄ´óС
|
vecLow.resize(nLowSize, 0);
|
|
// ·Ö½â¸ßλÊý¾Ýµ½µÍλÊý¾Ý
|
for (size_t i = 0; i < vecHigh.size(); i++) {
|
for (size_t j = 0; j < nGroupSize; j++) {
|
vecLow[i * nGroupSize + j] = static_cast<U>((vecHigh[i] >> (j * CHAR_BIT * sizeof(U))) & ((1ULL << (CHAR_BIT * sizeof(U))) - 1));
|
}
|
}
|
|
return vecLow;
|
}
|