| | |
| | | #include "pch.h" |
| | | #include "pch.h" |
| | | #include "PLCSignalListener.h" |
| | | |
| | | // === 日志打印类型 === |
| | | // === 日志打印类型 === |
| | | #define LOG_TYPE_ERROR -1 |
| | | #define LOG_TYPE_SUCCESS 0 |
| | | #define LOG_TYPE_WARNING 1 |
| | | #define LOG_TYPE_NORMAL 2 |
| | | |
| | | // === 日志打印宏定义 === |
| | | // === 日志打印宏定义 === |
| | | #define LOG_MSG(msg, type) LogInfo(msg, type) |
| | | |
| | | // === PLC 心跳相关配置 === |
| | | #define PLC_HEARTBEAT_PC_TO_PLC_ADDR 0x107F // PC -> PLC:PC 写入心跳 |
| | | #define PLC_HEARTBEAT_PLC_TO_PC_ADDR 0x6C40 // PLC -> PC:PC 读取 PLC 写入的心跳 |
| | | #define MAX_MISSED_HEARTBEAT 5 // 允许连续丢失心跳的最大次数,超过则判定 PLC 掉线 |
| | | // === PLC 心跳相关配置 === |
| | | #define PLC_HEARTBEAT_PC_TO_PLC_ADDR 0x107F // PC -> PLC:PC 写入心跳 |
| | | #define PLC_HEARTBEAT_PLC_TO_PC_ADDR 0x6C40 // PLC -> PC:PC 读取 PLC 写入的心跳 |
| | | #define MAX_MISSED_HEARTBEAT 5 // 允许连续丢失心跳的最大次数,超过则判定 PLC 掉线 |
| | | |
| | | // === PLC 命令输入配置(PLC -> PC) === |
| | | #define PLC_CMD_BIT_START 0x6CD3 // PLC命令起始位(通常为B6CD3) |
| | | #define PLC_CMD_BIT_COUNT 2 // 总共几个命令位(B6CD3=Start, B6CD4=Stop) |
| | | // === PLC 命令输入配置(PLC -> PC) === |
| | | #define PLC_CMD_BIT_START 0x6CD3 // PLC命令起始位(通常为B6CD3) |
| | | #define PLC_CMD_BIT_COUNT 2 // 总共几个命令位(B6CD3=Start, B6CD4=Stop) |
| | | |
| | | // === PLC 应答输出配置(PC -> PLC) === |
| | | #define PLC_ACK_MAX_LIFE 25 // PLC响应信号最大保留周期数(每周期为 m_nIntervalMs 毫秒) |
| | | #define PLC_ACK_BASE_BIT 0x1060 // PLC应答起始地址(B1060表示B6CD3的应答;B1061表示B6CD4的应答) |
| | | // === PLC 应答输出配置(PC -> PLC) === |
| | | #define PLC_ACK_MAX_LIFE 25 // PLC响应信号最大保留周期数(每周期为 m_nIntervalMs 毫秒) |
| | | #define PLC_ACK_BASE_BIT 0x1060 // PLC应答起始地址(B1060表示B6CD3的应答;B1061表示B6CD4的应答) |
| | | |
| | | // === PLC软元件类型宏(用于应答、数据写入)=== |
| | | #define PLC_BIT_DEVICE_TYPE DeviceType::B // 位操作设备类型(如M、B) |
| | | #define PLC_WORD_DEVICE_TYPE DeviceType::W // 字操作设备类型(如D、W) |
| | | // === PLC软元件类型宏(用于应答、数据写入)=== |
| | | #define PLC_BIT_DEVICE_TYPE DeviceType::B // 位操作设备类型(如M、B) |
| | | #define PLC_WORD_DEVICE_TYPE DeviceType::W // 字操作设备类型(如D、W) |
| | | |
| | | // === PLC结果寄存器地址配置 === |
| | | #define PLC_RESULT_ADDR_START 0x37B0 // PLC结果寄存器起始地址(如W37B0) |
| | | #define PLC_RESULT_ADDR_COUNT 4 // 结果寄存器数量(如W37B0, W37B2, W37B4, W37B6) |
| | | // === PLC结果寄存器地址配置 === |
| | | #define PLC_RESULT_ADDR_START 0x37B0 // PLC结果寄存器起始地址(如W37B0) |
| | | #define PLC_RESULT_ADDR_COUNT 4 // 结果寄存器数量(如W37B0, W37B2, W37B4, W37B6) |
| | | |
| | | // === PLC 产品ID配置(PLC -> PC)=== |
| | | #define PLC_PRODUCT_ID_ADDR 0x1B160 // 产品ID起始地址 (W1B160) |
| | | #define PLC_PRODUCT_ID_WORDS 10 // 产品ID长度(10个Word) |
| | | // === PLC 产品ID配置(PLC -> PC)=== |
| | | #define PLC_PRODUCT_ID_ADDR 0x1B160 // 产品ID起始地址 (W1B160) |
| | | #define PLC_PRODUCT_ID_WORDS 10 // 产品ID长度(10个Word) |
| | | |
| | | #define IS_RISING_EDGE(prev, curr) (!(prev) && (curr)) |
| | | |
| | | CPLCSignalListener::CPLCSignalListener() = default; |
| | | |
| | | CPLCSignalListener::~CPLCSignalListener() { |
| | | Stop(); |
| | | Stop(); |
| | | } |
| | | |
| | | bool CPLCSignalListener::Initialize(StationIdentifier station, int nIntervalMs/* = 200*/) |
| | | { |
| | | m_pPlc = std::make_unique<CCCLinkIEControl>(); |
| | | if (!m_pPlc) { |
| | | LOG_MSG(_T("PLC控制器初始化失败,无法创建 CCCLinkIEControl 实例。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | m_pPlc = std::make_unique<CCCLinkIEControl>(); |
| | | if (!m_pPlc) { |
| | | LOG_MSG(_T("PLC控制器初始化失败,无法创建 CCCLinkIEControl 实例。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | |
| | | int ret = m_pPlc->Connect(CC_LINK_IE_CONTROL_CHANNEL(1)); |
| | | if (ret != 0) { |
| | | m_bConnected = false; |
| | | int ret = m_pPlc->Connect(CC_LINK_IE_CONTROL_CHANNEL(1)); |
| | | if (ret != 0) { |
| | | m_bConnected = false; |
| | | |
| | | CString strError; |
| | | strError.Format(_T("PLC控制器连接失败,错误码:%d"), ret); |
| | | LOG_MSG(strError, LOG_TYPE_ERROR); |
| | | CString strError; |
| | | strError.Format(_T("PLC控制器连接失败,错误码:%d"), ret); |
| | | LOG_MSG(strError, LOG_TYPE_ERROR); |
| | | |
| | | return false; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | m_bConnected = true; |
| | | m_station = station; |
| | | m_nIntervalMs = nIntervalMs; |
| | | m_bConnected = true; |
| | | m_station = station; |
| | | m_nIntervalMs = nIntervalMs; |
| | | |
| | | m_vecPrevBits.assign(PLC_CMD_BIT_COUNT, false); |
| | | m_vecPrevBits.assign(PLC_CMD_BIT_COUNT, false); |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | | |
| | | void CPLCSignalListener::SetStartCallback(Callback cb) |
| | | { |
| | | m_cbStart = std::move(cb); |
| | | m_cbStart = std::move(cb); |
| | | } |
| | | |
| | | void CPLCSignalListener::SetStopCallback(Callback cb) |
| | | { |
| | | m_cbStop = std::move(cb); |
| | | m_cbStop = std::move(cb); |
| | | } |
| | | |
| | | void CPLCSignalListener::SetAnalyzeCallback(AnalyzeCallback cb) |
| | | { |
| | | m_cbAnalyze = std::move(cb); |
| | | m_cbAnalyze = std::move(cb); |
| | | } |
| | | |
| | | void CPLCSignalListener::SetLogCallback(LogCallback cb) |
| | | { |
| | | m_cbLog = std::move(cb); |
| | | m_cbLog = std::move(cb); |
| | | } |
| | | |
| | | bool CPLCSignalListener::Start() |
| | | { |
| | | if (m_bRunning || !m_pPlc) { |
| | | LOG_MSG(_T("PLC信号监听器已在运行或PLC控制器未初始化。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | if (m_bRunning || !m_pPlc) { |
| | | LOG_MSG(_T("PLC信号监听器已在运行或PLC控制器未初始化。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | |
| | | m_bRunning = true; |
| | | m_thread = std::thread(&CPLCSignalListener::ThreadProc, this); |
| | | m_bRunning = true; |
| | | m_thread = std::thread(&CPLCSignalListener::ThreadProc, this); |
| | | |
| | | StartHeartbeatMonitor(); |
| | | return true; |
| | | StartHeartbeatMonitor(); |
| | | return true; |
| | | } |
| | | |
| | | void CPLCSignalListener::Stop() |
| | | { |
| | | m_bRunning = false; |
| | | if (m_thread.joinable()) { |
| | | m_thread.join(); |
| | | } |
| | | m_bRunning = false; |
| | | if (m_thread.joinable()) { |
| | | m_thread.join(); |
| | | } |
| | | |
| | | StopHeartbeatMonitor(); |
| | | StopHeartbeatMonitor(); |
| | | } |
| | | |
| | | void CPLCSignalListener::LogInfo(const CString& strText, int nType) |
| | | { |
| | | if (m_cbLog) { |
| | | m_cbLog(strText, nType); |
| | | } |
| | | if (m_cbLog) { |
| | | m_cbLog(strText, nType); |
| | | } |
| | | } |
| | | |
| | | bool CPLCSignalListener::SendHeartbeat() |
| | | { |
| | | if (!m_pPlc || !m_bConnected) { |
| | | return false; |
| | | } |
| | | if (!m_pPlc || !m_bConnected) { |
| | | return false; |
| | | } |
| | | |
| | | static bool bToggle = false; |
| | | bToggle = !bToggle; |
| | | static bool bToggle = false; |
| | | bToggle = !bToggle; |
| | | |
| | | int ret = m_pPlc->WriteBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PC_TO_PLC_ADDR, BitContainer{ bToggle }); |
| | | int ret = m_pPlc->WriteBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PC_TO_PLC_ADDR, BitContainer{ bToggle }); |
| | | |
| | | return (ret == 0); |
| | | return (ret == 0); |
| | | } |
| | | |
| | | bool CPLCSignalListener::CheckHeartbeat() |
| | | { |
| | | static bool bLastHeartbeat = false; |
| | | static bool bLastHeartbeat = false; |
| | | |
| | | if (!m_pPlc || !m_bConnected) { |
| | | return false; |
| | | } |
| | | if (!m_pPlc || !m_bConnected) { |
| | | return false; |
| | | } |
| | | |
| | | BitContainer vec; |
| | | int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PLC_TO_PC_ADDR, 1, vec); |
| | | if (ret != 0 || vec.empty()) { |
| | | return false; |
| | | } |
| | | BitContainer vec; |
| | | int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_HEARTBEAT_PLC_TO_PC_ADDR, 1, vec); |
| | | if (ret != 0 || vec.empty()) { |
| | | return false; |
| | | } |
| | | |
| | | bool bCurrent = vec[0]; |
| | | bool bChanged = (bCurrent != bLastHeartbeat); |
| | | bLastHeartbeat = bCurrent; |
| | | bool bCurrent = vec[0]; |
| | | bool bChanged = (bCurrent != bLastHeartbeat); |
| | | bLastHeartbeat = bCurrent; |
| | | |
| | | return bChanged; |
| | | return bChanged; |
| | | } |
| | | |
| | | bool CPLCSignalListener::MonitorHeartbeat() |
| | | { |
| | | if (CheckHeartbeat()) { |
| | | m_nMissedHeartbeatCount = 0; |
| | | if (CheckHeartbeat()) { |
| | | m_nMissedHeartbeatCount = 0; |
| | | |
| | | if (m_bHeartbeatLost) { |
| | | m_bHeartbeatLost = false; |
| | | LOG_MSG(_T("PLC心跳恢复!"), LOG_TYPE_SUCCESS); |
| | | } |
| | | if (m_bHeartbeatLost) { |
| | | m_bHeartbeatLost = false; |
| | | LOG_MSG(_T("PLC心跳恢复!"), LOG_TYPE_SUCCESS); |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | else { |
| | | m_nMissedHeartbeatCount++; |
| | | return true; |
| | | } |
| | | else { |
| | | m_nMissedHeartbeatCount++; |
| | | |
| | | if (m_nMissedHeartbeatCount > MAX_MISSED_HEARTBEAT) { |
| | | if (!m_bHeartbeatLost) { |
| | | m_bHeartbeatLost = true; |
| | | if (m_nMissedHeartbeatCount > MAX_MISSED_HEARTBEAT) { |
| | | if (!m_bHeartbeatLost) { |
| | | m_bHeartbeatLost = true; |
| | | m_nMissedHeartbeatCount = 0; |
| | | LOG_MSG(_T("PLC心跳信号中断!"), LOG_TYPE_ERROR); |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | | LOG_MSG(_T("PLC心跳信号中断!"), LOG_TYPE_ERROR); |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | | |
| | | void CPLCSignalListener::StartHeartbeatMonitor() |
| | | { |
| | | m_bHeartbeatRunning = true; |
| | | m_heartbeatThread = std::thread([this]() { |
| | | while (m_bHeartbeatRunning) { |
| | | SendHeartbeat(); |
| | | MonitorHeartbeat(); |
| | | std::this_thread::sleep_for(std::chrono::milliseconds(m_nIntervalMs * 5)); |
| | | } |
| | | }); |
| | | m_bHeartbeatRunning = true; |
| | | m_heartbeatThread = std::thread([this]() { |
| | | while (m_bHeartbeatRunning) { |
| | | SendHeartbeat(); |
| | | MonitorHeartbeat(); |
| | | std::this_thread::sleep_for(std::chrono::milliseconds(m_nIntervalMs * 5)); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | void CPLCSignalListener::StopHeartbeatMonitor() |
| | | { |
| | | m_bHeartbeatRunning = false; |
| | | if (m_heartbeatThread.joinable()) { |
| | | m_heartbeatThread.join(); |
| | | } |
| | | m_bHeartbeatRunning = false; |
| | | if (m_heartbeatThread.joinable()) { |
| | | m_heartbeatThread.join(); |
| | | } |
| | | } |
| | | |
| | | void CPLCSignalListener::PulseBitDevice(DeviceType eDevType, long nBitNo, int nDelayMs/* = 50*/) |
| | | { |
| | | m_pPlc->SetBitDeviceEx(m_station, eDevType, nBitNo); |
| | | ::Sleep(nDelayMs); |
| | | m_pPlc->ResetBitDeviceEx(m_station, eDevType, nBitNo); |
| | | m_pPlc->SetBitDeviceEx(m_station, eDevType, nBitNo); |
| | | ::Sleep(nDelayMs); |
| | | m_pPlc->ResetBitDeviceEx(m_station, eDevType, nBitNo); |
| | | } |
| | | |
| | | void CPLCSignalListener::HandleAckLife(int i, bool bCurrTriggerBit) |
| | | { |
| | | if (m_vecAckSent[i] && !bCurrTriggerBit) { |
| | | m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i)); |
| | | m_vecAckSent[i] = false; |
| | | } |
| | | if (m_vecAckSent[i] && !bCurrTriggerBit) { |
| | | m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i)); |
| | | m_vecAckSent[i] = false; |
| | | } |
| | | |
| | | if (m_vecAckSent[i]) { |
| | | if (++m_vecAckCounter[i] > PLC_ACK_MAX_LIFE) { |
| | | m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i)); |
| | | m_vecAckSent[i] = false; |
| | | } |
| | | } |
| | | if (m_vecAckSent[i]) { |
| | | if (++m_vecAckCounter[i] > PLC_ACK_MAX_LIFE) { |
| | | m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i)); |
| | | m_vecAckSent[i] = false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void CPLCSignalListener::ThreadProc() |
| | | { |
| | | while (m_bRunning && m_bConnected) { |
| | | BitContainer vecBits; |
| | | int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits); |
| | | if (ret != 0 && vecBits.size() != PLC_CMD_BIT_COUNT) { |
| | | ::Sleep(m_nIntervalMs); |
| | | while (m_bRunning && m_bConnected) { |
| | | BitContainer vecBits; |
| | | int ret = m_pPlc->ReadBitDataEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits); |
| | | if (ret != 0 && vecBits.size() != PLC_CMD_BIT_COUNT) { |
| | | ::Sleep(m_nIntervalMs); |
| | | |
| | | CString strError; |
| | | strError.Format(_T("PLC读取位数据失败,错误码:%d"), ret); |
| | | LOG_MSG(strError, LOG_TYPE_ERROR); |
| | | CString strError; |
| | | strError.Format(_T("PLC读取位数据失败,错误码:%d"), ret); |
| | | LOG_MSG(strError, LOG_TYPE_ERROR); |
| | | |
| | | continue; |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | for (int i = 0; i < PLC_CMD_BIT_COUNT; ++i) { |
| | | if (IS_RISING_EDGE(m_vecPrevBits[i], vecBits[i])) { |
| | | // 上升沿触发 |
| | | switch (i) { |
| | | case 0: |
| | | if (m_cbStart) { |
| | | m_cbStart(); |
| | | WriteOutValues(OutValuesArray{ 0.0, 0.0, 0.0, 0.0 }); |
| | | if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) { |
| | | m_vecAckSent[i] = true; |
| | | m_vecAckCounter[i] = 0; |
| | | } |
| | | for (int i = 0; i < PLC_CMD_BIT_COUNT; ++i) { |
| | | if (IS_RISING_EDGE(m_vecPrevBits[i], vecBits[i])) { |
| | | // 上升沿触发 |
| | | switch (i) { |
| | | case 0: |
| | | // Start 命令 |
| | | if (m_cbStart) { |
| | | m_cbStart(); |
| | | WriteOutValues(OutValuesArray{ 0.0, 0.0, 0.0, 0.0 }); |
| | | |
| | | std::string strProductID; |
| | | if (ReadProductID(strProductID)) { |
| | | CString msg; |
| | | msg.Format(_T("读取到产品ID:%s"), strProductID.c_str()); |
| | | LOG_MSG(msg, LOG_TYPE_SUCCESS); |
| | | } |
| | | } |
| | | break; |
| | | std::string strProductID; |
| | | if (ReadProductID(strProductID)) { |
| | | CString msg; |
| | | msg.Format(_T("读取到产品ID:%s"), strProductID); |
| | | LOG_MSG(msg, LOG_TYPE_SUCCESS); |
| | | } |
| | | } |
| | | |
| | | case 1: |
| | | if (m_cbStop) { |
| | | m_cbStop(); |
| | | if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) { |
| | | m_vecAckSent[i] = true; |
| | | m_vecAckCounter[i] = 0; |
| | | } |
| | | } |
| | | // 发送应答信号 |
| | | if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) { |
| | | m_vecAckSent[i] = true; |
| | | m_vecAckCounter[i] = 0; |
| | | } |
| | | break; |
| | | |
| | | if (m_cbAnalyze) { |
| | | auto results = m_cbAnalyze(); |
| | | WriteOutValues(results); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | case 1: |
| | | // Stop 命令 |
| | | if (m_cbStop) { |
| | | m_cbStop(); |
| | | } |
| | | |
| | | HandleAckLife(i, vecBits[i]); |
| | | m_vecPrevBits[i] = vecBits[i]; |
| | | } |
| | | // Analyze 命令 |
| | | if (m_cbAnalyze) { |
| | | auto results = m_cbAnalyze(); |
| | | WriteOutValues(results); |
| | | } |
| | | |
| | | ::Sleep(m_nIntervalMs); |
| | | } |
| | | // 发送应答信号 |
| | | if (m_pPlc->SetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) { |
| | | m_vecAckSent[i] = true; |
| | | m_vecAckCounter[i] = 0; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | HandleAckLife(i, vecBits[i]); |
| | | m_vecPrevBits[i] = vecBits[i]; |
| | | } |
| | | |
| | | ::Sleep(m_nIntervalMs); |
| | | } |
| | | } |
| | | |
| | | bool CPLCSignalListener::WriteOutValues(const OutValuesArray& values) |
| | | { |
| | | if (!m_pPlc || !m_bConnected) { |
| | | LOG_MSG(_T("PLC未连接或未初始化,无法写入输出值。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | if (!m_pPlc || !m_bConnected) { |
| | | LOG_MSG(_T("PLC未连接或未初始化,无法写入输出值。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | |
| | | if (PLC_RESULT_ADDR_COUNT != 4) { |
| | | LOG_MSG(_T("PLC结果寄存器数量配置错误,必须为4个。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | if (PLC_RESULT_ADDR_COUNT != 4) { |
| | | LOG_MSG(_T("PLC结果寄存器数量配置错误,必须为4个。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | |
| | | for (int i = 0; i < PLC_RESULT_ADDR_COUNT; ++i) { |
| | | // 放大100倍并四舍五入,转为PLC整数 |
| | | uint16_t nScaled = static_cast<uint16_t>(std::round(values[i] * 100.0)); |
| | | WordContainer vec = { nScaled }; |
| | | for (int i = 0; i < PLC_RESULT_ADDR_COUNT; ++i) { |
| | | // 放大1000倍并四舍五入,转为PLC整数 |
| | | int32_t nScaled = static_cast<int32_t>(std::round(values[i] * 1000.0)); |
| | | DWordContainer vec = { static_cast<uint32_t>(nScaled) }; |
| | | |
| | | short nTargetAddr = PLC_RESULT_ADDR_START + i * 2; |
| | | int ret = m_pPlc->WriteWordDataEx(m_station, PLC_WORD_DEVICE_TYPE, nTargetAddr, vec); |
| | | if (ret != 0) { |
| | | CString msg; |
| | | msg.Format(_T("写入OUT%d到地址%d失败,值=%.2f"), i + 1, nTargetAddr, values[i]); |
| | | LOG_MSG(msg, LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | } |
| | | short nTargetAddr = PLC_RESULT_ADDR_START + i * 2; |
| | | int ret = m_pPlc->WriteDWordDataEx(m_station, PLC_WORD_DEVICE_TYPE, nTargetAddr, vec); |
| | | if (ret != 0) { |
| | | CString msg; |
| | | msg.Format(_T("写入OUT%d到地址%d失败,值=%.2f"), i + 1, nTargetAddr, values[i]); |
| | | LOG_MSG(msg, LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | return true; |
| | | } |
| | | |
| | | bool CPLCSignalListener::ReadProductID(std::string& strProductID) |
| | | { |
| | | if (!m_pPlc || !m_bConnected) { |
| | | LOG_MSG(_T("PLC未连接或未初始化,无法读取产品ID。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | if (!m_pPlc || !m_bConnected) { |
| | | LOG_MSG(_T("PLC未连接或未初始化,无法读取产品ID。"), LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | |
| | | WordContainer vec; |
| | | int ret = m_pPlc->ReadWordDataEx(m_station, PLC_WORD_DEVICE_TYPE, PLC_PRODUCT_ID_ADDR, PLC_PRODUCT_ID_WORDS, vec); |
| | | if (ret != 0 || vec.size() != PLC_PRODUCT_ID_WORDS) { |
| | | CString msg; |
| | | msg.Format(_T("读取产品ID失败,错误码=%d"), ret); |
| | | LOG_MSG(msg, LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | WordContainer vec; |
| | | int ret = m_pPlc->ReadWordDataEx(m_station, PLC_WORD_DEVICE_TYPE, PLC_PRODUCT_ID_ADDR, PLC_PRODUCT_ID_WORDS, vec); |
| | | if (ret != 0 || vec.size() != PLC_PRODUCT_ID_WORDS) { |
| | | CString msg; |
| | | msg.Format(_T("读取产品ID失败,错误码=%d"), ret); |
| | | LOG_MSG(msg, LOG_TYPE_ERROR); |
| | | return false; |
| | | } |
| | | |
| | | strProductID.clear(); |
| | | for (auto w : vec) { |
| | | char c1 = static_cast<char>(w & 0xFF); // 低字节 |
| | | char c2 = static_cast<char>((w >> 8) & 0xFF); // 高字节 |
| | | strProductID.clear(); |
| | | strProductID.reserve(PLC_PRODUCT_ID_WORDS * 2); |
| | | for (auto w : vec) { |
| | | char c1 = static_cast<char>(w & 0xFF); // 低字节 |
| | | char c2 = static_cast<char>((w >> 8) & 0xFF); // 高字节 |
| | | |
| | | if (c1 == '\0') { |
| | | break; |
| | | } |
| | | strProductID.push_back(c1); |
| | | if (c1 == '\0') { |
| | | break; |
| | | } |
| | | strProductID.push_back(c1); |
| | | |
| | | if (c2 == '\0') { |
| | | break; |
| | | } |
| | | strProductID.push_back(c2); |
| | | } |
| | | if (c2 == '\0') { |
| | | break; |
| | | } |
| | | strProductID.push_back(c2); |
| | | } |
| | | |
| | | return true; |
| | | return true; |
| | | } |