From 238f41fd4edac2febc03d2e428bce7206f609e99 Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期四, 29 一月 2026 15:38:58 +0800
Subject: [PATCH] 1.完善CJ/PJ事件上报;

---
 SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp |  404 ++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 282 insertions(+), 122 deletions(-)

diff --git a/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp b/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
index 27ad0c9..ab32e61 100644
--- a/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
+++ b/SourceCode/Bond/SGMeasurement/PLCSignalListener.cpp
@@ -1,203 +1,363 @@
-#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
 
-// === PLC 控制命令输入位配置 ===
-#define PLC_CMD_BIT_START       0     // PLC命令起始位(通常为B0)
-#define PLC_CMD_BIT_COUNT       2     // 总共几个命令位(B0=Start, B1=Stop)
+// === 鏃ュ織鎵撳嵃瀹忓畾涔� ===
+#define LOG_MSG(msg, type) LogInfo(msg, type)
 
-// === PLC 信号监听器相关宏定义 ===
-#define PLC_ACK_MAX_LIFE        5     // PLC响应信号最大保留周期数(每周期为 m_nIntervalMs 毫秒)
-#define PLC_ACK_BASE_BIT        10    // PLC应答起始地址(B10表示B0的应答;B11表示B1)
+// === PLC 蹇冭烦鐩稿叧閰嶇疆 ===
+#define PLC_HEARTBEAT_PC_TO_PLC_ADDR   0x107F   // PC -> PLC锛歅C 鍐欏叆蹇冭烦
+#define PLC_HEARTBEAT_PLC_TO_PC_ADDR   0x6C40   // PLC -> PC锛歅C 璇诲彇 PLC 鍐欏叆鐨勫績璺�
+#define MAX_MISSED_HEARTBEAT           5        // 鍏佽杩炵画涓㈠け蹇冭烦鐨勬渶澶ф鏁帮紝瓒呰繃鍒欏垽瀹� PLC 鎺夌嚎
 
-// === PLC软元件类型宏(用于应答、数据写入)===
-#define PLC_BIT_DEVICE_TYPE    DeviceType::B   // 位操作设备类型(如M、B)
-#define PLC_WORD_DEVICE_TYPE   DeviceType::W   // 字操作设备类型(如D、W)
+// === PLC 鍛戒护杈撳叆閰嶇疆锛圥LC -> PC锛� ===
+#define PLC_CMD_BIT_START       0x6CD3          // PLC鍛戒护璧峰浣嶏紙閫氬父涓築6CD3锛�
+#define PLC_CMD_BIT_COUNT       2               // 鎬诲叡鍑犱釜鍛戒护浣嶏紙B6CD3=Start, B6CD4=Stop锛�
+
+// === PLC 搴旂瓟杈撳嚭閰嶇疆锛圥C -> PLC锛� ===
+#define PLC_ACK_MAX_LIFE        25              // PLC鍝嶅簲淇″彿鏈�澶т繚鐣欏懆鏈熸暟锛堟瘡鍛ㄦ湡涓� m_nIntervalMs 姣锛�
+#define PLC_ACK_BASE_BIT        0x1060          // PLC搴旂瓟璧峰鍦板潃锛圔1060琛ㄧずB6CD3鐨勫簲绛旓紱B1061琛ㄧずB6CD4鐨勫簲绛旓級
+
+// === PLC杞厓浠剁被鍨嬪畯锛堢敤浜庡簲绛斻�佹暟鎹啓鍏ワ級===
+#define PLC_BIT_DEVICE_TYPE     DeviceType::B   // 浣嶆搷浣滆澶囩被鍨嬶紙濡侻銆丅锛�
+#define PLC_WORD_DEVICE_TYPE    DeviceType::W   // 瀛楁搷浣滆澶囩被鍨嬶紙濡侱銆乄锛�
+
+// === PLC缁撴灉瀵勫瓨鍣ㄥ湴鍧�閰嶇疆 ===
+#define PLC_RESULT_ADDR_START   0x37B0          // PLC缁撴灉瀵勫瓨鍣ㄨ捣濮嬪湴鍧�锛堝W37B0锛�
+#define PLC_RESULT_ADDR_COUNT   4               // 缁撴灉瀵勫瓨鍣ㄦ暟閲忥紙濡俉37B0, W37B2, W37B4, W37B6锛�
+
+// === PLC 浜у搧ID閰嶇疆锛圥LC -> PC锛�===
+#define PLC_PRODUCT_ID_ADDR      0x1B160        // 浜у搧ID璧峰鍦板潃 (W1B160)
+#define PLC_PRODUCT_ID_WORDS     10             // 浜у搧ID闀垮害锛�10涓猈ord锛�
 
 #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) {
-		if (m_cbLog) {
-			m_cbLog(_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) {
+	int ret = m_pPlc->Connect(CC_LINK_IE_CONTROL_CHANNEL(1));
+	if (ret != 0) {
 		m_bConnected = false;
-		if (m_cbLog) {
-			CString strError;
-			strError.Format(_T("PLC控制器连接失败,错误码:%d"), ret);
-			m_cbLog(strError, LOG_TYPE_ERROR);
-		}
-        return false;
-    }
+
+		CString strError;
+		strError.Format(_T("PLC鎺у埗鍣ㄨ繛鎺ュけ璐ワ紝閿欒鐮侊細%d"), ret);
+		LOG_MSG(strError, LOG_TYPE_ERROR);
+
+		return false;
+	}
 
 	m_bConnected = true;
-    m_station = station;
-    m_nIntervalMs = nIntervalMs;
+	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) {
-		if (m_cbLog) {
-			m_cbLog(_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);
-    return true;
+	m_bRunning = true;
+	m_thread = std::thread(&CPLCSignalListener::ThreadProc, this);
+
+	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();
 }
 
-void CPLCSignalListener::PulseBitDevice(DeviceType eDevType, short nBitNo, int nDelayMs/* = 50*/)
+void CPLCSignalListener::LogInfo(const CString& strText, int nType)
 {
-    m_pPlc->SetBitDevice(m_station, eDevType, nBitNo);
-    ::Sleep(nDelayMs);
-    m_pPlc->ResetBitDevice(m_station, eDevType, nBitNo);
+	if (m_cbLog) {
+		m_cbLog(strText, nType);
+	}
+}
+
+bool CPLCSignalListener::SendHeartbeat()
+{
+	if (!m_pPlc || !m_bConnected) {
+		return false;
+	}
+
+	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 });
+
+	return (ret == 0);
+}
+
+bool CPLCSignalListener::CheckHeartbeat()
+{
+	static bool bLastHeartbeat = 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;
+	}
+
+	bool bCurrent = vec[0];
+	bool bChanged = (bCurrent != bLastHeartbeat);
+	bLastHeartbeat = bCurrent;
+
+	return bChanged;
+}
+
+bool CPLCSignalListener::MonitorHeartbeat()
+{
+	if (CheckHeartbeat()) {
+		m_nMissedHeartbeatCount = 0;
+
+		if (m_bHeartbeatLost) {
+			m_bHeartbeatLost = false;
+			LOG_MSG(_T("PLC蹇冭烦鎭㈠锛�"), LOG_TYPE_SUCCESS);
+		}
+
+		return true;
+	}
+	else {
+		m_nMissedHeartbeatCount++;
+
+		if (m_nMissedHeartbeatCount > MAX_MISSED_HEARTBEAT) {
+			if (!m_bHeartbeatLost) {
+				m_bHeartbeatLost = true;
+				m_nMissedHeartbeatCount = 0;
+				LOG_MSG(_T("PLC蹇冭烦淇″彿涓柇锛�"), LOG_TYPE_ERROR);
+			}
+			return false;
+		}
+	}
+
+	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));
+		}
+	});
+}
+
+void CPLCSignalListener::StopHeartbeatMonitor()
+{
+	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);
 }
 
 void CPLCSignalListener::HandleAckLife(int i, bool bCurrTriggerBit)
 {
-    if (m_vecAckSent[i] && !bCurrTriggerBit) {
-        m_pPlc->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
-        m_vecAckSent[i] = false;
-    }
+	if (m_vecAckSent[i] && !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->ResetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, short(PLC_ACK_BASE_BIT + i));
-            m_vecAckSent[i] = false;
-        }
-    }
+	if (m_vecAckSent[i]) {
+		if (++m_vecAckCounter[i] > PLC_ACK_MAX_LIFE) {
+			m_pPlc->ResetBitDeviceEx(m_station, PLC_BIT_DEVICE_TYPE, long(PLC_ACK_BASE_BIT + i));
+			m_vecAckSent[i] = false;
+		}
+	}
 }
 
 void CPLCSignalListener::ThreadProc()
 {
-    while (m_bRunning) {
-        BitContainer vecBits;
-        int ret = m_pPlc->ReadBitData(m_station, PLC_BIT_DEVICE_TYPE, PLC_CMD_BIT_START, PLC_CMD_BIT_COUNT, vecBits);
-        if (ret != 0/*&& vecBits.size() != PLC_CMD_BIT_COUNT*/) {
+	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);
 
-			if (m_cbLog) {
-				CString strError;
-				strError.Format(_T("PLC读取位数据失败,错误码:%d"), ret);
-				m_cbLog(strError, LOG_TYPE_ERROR);
-			}
+			CString strError;
+			strError.Format(_T("PLC璇诲彇浣嶆暟鎹け璐ワ紝閿欒鐮侊細%d"), ret);
+			LOG_MSG(strError, LOG_TYPE_ERROR);
 
 			continue;
-        }
+		}
 
-        for (int i = 0; i < PLC_CMD_BIT_COUNT; ++i) {
-            if (IS_RISING_EDGE(m_vecPrevBits[i], vecBits[i])) {
-                // 上升沿触发
-                switch (i) {
-                case 0:
-                    if (m_cbStart) {
-                        m_cbStart();
-                        WriteOutValues(OutValuesArray{ 0.0, 0.0, 0.0, 0.0 });
-                        if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
-                            m_vecAckSent[i] = true;
-                            m_vecAckCounter[i] = 0;
-                        }
-                    }
-                    break;
+		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 });
 
-                case 1:
-                    if (m_cbStop) {
-                        m_cbStop();
-                        if (m_pPlc->SetBitDevice(m_station, PLC_BIT_DEVICE_TYPE, PLC_ACK_BASE_BIT + i) == 0) {
-                            m_vecAckSent[i] = true;
-                            m_vecAckCounter[i] = 0;
-                        }
-                    }
+						std::string strProductID;
+						if (ReadProductID(strProductID)) {
+							CString msg;
+							msg.Format(_T("璇诲彇鍒颁骇鍝両D锛�%s"), strProductID);
+							LOG_MSG(msg, LOG_TYPE_SUCCESS);
+						}
+					}
 
-                    if (m_cbAnalyze) {
-                        auto results = m_cbAnalyze();
-                        WriteOutValues(results);
-                    }
-                    break;
-                }
-            }
+					// 鍙戦�佸簲绛斾俊鍙�
+					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];
-        }
+				case 1:
+					// Stop 鍛戒护
+					if (m_cbStop) {
+						m_cbStop();
+					}
 
-        ::Sleep(m_nIntervalMs);
-    }
+					// Analyze 鍛戒护
+					if (m_cbAnalyze) {
+						auto results = m_cbAnalyze();
+						WriteOutValues(results);
+					}
+
+					// 鍙戦�佸簲绛斾俊鍙�
+					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) {
-		if (m_cbLog) {
-			m_cbLog(_T("PLC控制器未初始化,无法写入输出值。"), LOG_TYPE_ERROR);
+	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;
+	}
+
+	for (int i = 0; i < PLC_RESULT_ADDR_COUNT; ++i) {
+		// 鏀惧ぇ1000鍊嶅苟鍥涜垗浜斿叆锛岃浆涓篜LC鏁存暟
+		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->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 false;
-    }
+	}
 
-    static const short PLC_RESULT_ADDR[4] = { 100, 102, 104, 106 };
+	return true;
+}
 
-    for (int i = 0; i < 4; ++i) {
-        uint16_t nScaled = static_cast<uint16_t>(std::round(values[i] * 100.0));
-        WordContainer vec = { nScaled };
+bool CPLCSignalListener::ReadProductID(std::string& strProductID)
+{
+	if (!m_pPlc || !m_bConnected) {
+		LOG_MSG(_T("PLC鏈繛鎺ユ垨鏈垵濮嬪寲锛屾棤娉曡鍙栦骇鍝両D銆�"), LOG_TYPE_ERROR);
+		return false;
+	}
 
-        int ret = m_pPlc->WriteWordData(m_station, PLC_WORD_DEVICE_TYPE, PLC_RESULT_ADDR[i], vec);
-        if (ret != 0) {
-            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;
+	}
 
-    return true;
+	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 (c2 == '\0') { 
+			break;
+		}
+		strProductID.push_back(c2);
+	}
+
+	return true;
 }
\ No newline at end of file

--
Gitblit v1.9.3