From bc7f1c4e028e69be51079b59dae4ae5c4d43f5bb Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期六, 31 一月 2026 21:54:56 +0800
Subject: [PATCH] 1.状态指示图,目前灰色表示掉线,绿色表示在线。增加Slot的小点表示有没有料,及加工状态 。 2.增加图示

---
 SourceCode/Bond/BoounionPLC/PLC.cpp |  529 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 529 insertions(+), 0 deletions(-)

diff --git a/SourceCode/Bond/BoounionPLC/PLC.cpp b/SourceCode/Bond/BoounionPLC/PLC.cpp
index 153d52a..9e4e637 100644
--- a/SourceCode/Bond/BoounionPLC/PLC.cpp
+++ b/SourceCode/Bond/BoounionPLC/PLC.cpp
@@ -1,9 +1,42 @@
 #include "stdafx.h"
 #include "PLC.h"
+#include "Log.h"
+#include "ToolUnits.h"
 
+
+#define ADDR_NIGHT_SHIFT_CAPACTITY		1627
+
+void CALLBACK TimerFileProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
+{
+	CPLC* pPlc = (CPLC*)dwUser;
+	SetEvent(pPlc->m_hTimeEvent);
+}
+
+unsigned __stdcall McMonitorThreadFunction(LPVOID lpParam)
+{
+	CPLC* pPlc = (CPLC*)lpParam;
+	return pPlc->onMonitor();
+}
 
 CPLC::CPLC()
 {
+	m_pChannel = nullptr;
+	m_state = PLCSTATE::READY;
+	m_listener.onStateChanged = nullptr;
+	m_listener.onMonitorData = nullptr;
+	m_listener.onAlarm = nullptr;
+	m_nUnHeartBeat = 0;
+	m_nActionInterval = 500;
+	m_hTimeEvent = nullptr;
+	m_hMcMonitorStop = nullptr;
+	m_hMcMonitorThreadHandle = nullptr;
+	m_mcMonitorThrdaddr = 0;
+	m_nTimerId = 0;
+	m_hTimeEvent = nullptr;
+	m_bMute = false;
+	m_pPlcData = new char[4096];
+	m_nVelocityRatio = 0;
+	InitializeCriticalSection(&m_criticalSection);
 }
 
 CPLC::CPLC(const char* pszName, const char* pszIp, const unsigned int port)
@@ -11,10 +44,49 @@
 	m_strName = pszName;
 	m_strIp = pszIp;
 	m_nPort = port;
+	m_pChannel = nullptr;
+	m_state = PLCSTATE::READY;
+	m_listener.onStateChanged = nullptr;
+	m_listener.onMonitorData = nullptr;
+	m_listener.onAlarm = nullptr;
+	m_nUnHeartBeat = 0;
+	m_hTimeEvent = nullptr;
+	m_hMcMonitorStop = nullptr;
+	m_hMcMonitorThreadHandle = nullptr;
+	m_mcMonitorThrdaddr = 0;
+	m_nTimerId = 0;
+	m_hTimeEvent = nullptr;
+	m_pPlcData = new char[4096];
+	m_nVelocityRatio = 0;
+	m_dTactTime = 0.0;
+	m_nDayShiftCapacity = 0;
+	m_nNightShiftCapacity = 0;
+	for (int i = 0; i < 7; i++) {
+		m_bBlBtnsStates[i] = false;
+	}
+
+	InitializeCriticalSection(&m_criticalSection);
 }
 
 CPLC::~CPLC()
 {
+	if (m_pPlcData != nullptr) {
+		delete[] m_pPlcData;
+		m_pPlcData = nullptr;
+	}
+	DeleteCriticalSection(&m_criticalSection);
+}
+
+void CPLC::setListener(PLCListener& listener)
+{
+	m_listener.onStateChanged = listener.onStateChanged;
+	m_listener.onMonitorData = listener.onMonitorData;
+	m_listener.onAlarm = listener.onAlarm;
+}
+
+void CPLC::setWorkDir(const char* pszDir)
+{
+	m_strWorkDir = pszDir;
 }
 
 std::string& CPLC::getName()
@@ -31,3 +103,460 @@
 {
 	return m_nPort;
 }
+
+bool CPLC::isMute()
+{
+	return m_bMute;
+}
+
+CAlarmMonitor* CPLC::getAlarmMonitor()
+{
+	return (CAlarmMonitor*)getComponent("警告信息");
+}
+
+int CPLC::addMonitor(int id, int beginAddr, int endAddr, MC::SOFT_COMPONENT softComponent, char* pszRecvBuffer)
+{
+	// 检查是否有重复的
+	Lock();
+	for (auto& m : m_monitors) {
+		if (m.id == id) {
+			Unlock();
+			return -1;
+		}
+	}
+
+	MONITOR m;
+	memset(&m, 0, sizeof(MONITOR));
+	m.id = id;
+	m.beginAddr = beginAddr;
+	m.readLen = (endAddr - beginAddr + 1) * 2;
+	m.softComponent = softComponent;
+	m.szRecvBuffer = pszRecvBuffer;
+	m.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+	m_monitors.push_back(m);
+
+	Unlock();
+	return 0;
+}
+
+void CPLC::init()
+{
+	// mc channel
+	McChannelListener m_mcChannellistener;
+	m_mcChannellistener.funOnConnected = [&](IMcChannel* pChannel, int nErrorCode) -> void {
+		LOGI("<PLC-%s>连接结果<code= %d>", m_strName.c_str(), nErrorCode);
+		if (nErrorCode == 0) {
+			setState(PLCSTATE::CONNECTED);
+		}
+		else {
+			setState(PLCSTATE::DISCONNECTED);
+		}
+	};
+	m_mcChannellistener.funOnClose = [&](IMcChannel* pChannel) -> void {
+		setState(PLCSTATE::DISCONNECTED);
+	};
+	m_mcChannellistener.funOnClosing = [&](IMcChannel* pChannel) -> void {
+	};
+	m_mcChannellistener.funOnRead = [&](IMcChannel* pChannel, char* pData, unsigned int nDataSize, int nDecodeRet) -> void {
+		CString strText;
+		dataToHexString(pData, nDataSize, strText);
+		if (nDecodeRet != 0) {
+			LOGE("<PLC-%s>funOnRead[%s], nDecodeRet=%d", m_strName.c_str(), (LPTSTR)(LPCTSTR)strText, nDecodeRet);
+		}
+		m_nUnHeartBeat = 0;
+	};
+	m_mcChannellistener.funOnWrite = [&](IMcChannel* pChannel) -> void {
+
+	};
+
+	if (0 == MCL_CreateChannel(m_pChannel, m_strName.c_str(), m_strIp.c_str(), m_nPort, 0)
+		&& m_pChannel != NULL) {
+		m_pChannel->setChannelListener(&m_mcChannellistener);
+		m_pChannel->setActionInterval(m_nActionInterval);
+		LOGI("<PLC-%s>正在连接PLC.", m_strName.c_str());
+		setState(PLCSTATE::CONNECTING);
+		m_pChannel->connect();
+	}
+	else if (m_pChannel != NULL) {
+		m_pChannel->setChannelListener(&m_mcChannellistener);
+		m_pChannel->setActionInterval(m_nActionInterval);
+	}
+	addMonitor(MONITOR_ID_ALARM, 10001, 10064, MC::SOFT_COMPONENT::M, &m_pPlcData[600]);
+
+
+	// 警告监控
+	CString strAlarmFile;
+	strAlarmFile.Format(_T("%s\\AlarmList.txt"), m_strWorkDir.c_str());
+	CAlarmMonitor* pAlarmMonitor = new CAlarmMonitor();
+	pAlarmMonitor->setName("警告信息");
+	pAlarmMonitor->setDescription("警告信息监控");
+	pAlarmMonitor->setIndex(0);
+	pAlarmMonitor->readAlarmListFromFile((LPTSTR)(LPCTSTR)strAlarmFile);
+	addComponent(pAlarmMonitor);
+	pAlarmMonitor->init();
+
+
+	// 定时器
+	m_hTimeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+	timeBeginPeriod(1);
+	m_nTimerId = timeSetEvent(200, 1, TimerFileProc, (DWORD_PTR)this, TIME_PERIODIC);
+
+
+	// 数据监控线程
+	if (m_hMcMonitorStop != NULL) return;
+	m_hMcMonitorStop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+	m_hMcMonitorThreadHandle = (HANDLE)_beginthreadex(NULL, 0, ::McMonitorThreadFunction, this,
+		0, &m_mcMonitorThrdaddr);
+
+}
+
+void CPLC::term()
+{
+	timeKillEvent(m_nTimerId);
+	timeEndPeriod(1);		// 清除前面对定时器的设置
+
+	for (auto item : m_components) {
+		delete item;
+	}
+	m_components.clear();
+
+	ASSERT(m_hMcMonitorStop);
+	SetEvent(m_hMcMonitorStop);
+	if (m_hMcMonitorThreadHandle != NULL) {
+		WaitForSingleObject(m_hMcMonitorThreadHandle, INFINITE);
+		CloseHandle(m_hMcMonitorThreadHandle);
+		m_hMcMonitorThreadHandle = NULL;
+	}
+	CloseHandle(m_hMcMonitorStop);
+	m_hMcMonitorStop = NULL;
+
+	for (auto& m : m_monitors) {
+		CloseHandle(m.hEvent);
+	}
+}
+
+bool CPLC::isConnected()
+{
+	return m_pChannel != nullptr && m_pChannel->isConnected();
+}
+
+void CPLC::connect()
+{
+	if (m_pChannel != nullptr && !m_pChannel->isConnected()) {
+		m_pChannel->connect();
+	}
+}
+
+void CPLC::setState(PLCSTATE state)
+{
+	m_state = state;
+	if (m_listener.onStateChanged != nullptr) {
+		m_listener.onStateChanged(this, (int)m_state);
+	}
+}
+
+void CPLC::setActionInterval(unsigned int nInterval)
+{
+	m_nActionInterval = nInterval;
+}
+
+CString& CPLC::dataToHexString(const char* pData, const int size, CString& strOut)
+{
+	strOut.Empty();
+	for (int i = 0; i < size; i++) {
+		if (i < size - 1) {
+			strOut.AppendFormat(_T("%02X "), (BYTE)pData[i]);
+		}
+		else {
+			strOut.AppendFormat(_T("%02X"), (BYTE)pData[i]);
+		}
+	}
+
+	return strOut;
+}
+
+unsigned CPLC::onMonitor()
+{
+	HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+
+	int nReadLen = 60 * 2;
+	HANDLE hEvents[2] = { m_hMcMonitorStop, m_hTimeEvent };
+
+	while (1) {
+		int nRet = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
+		ResetEvent(m_hTimeEvent);
+		if (nRet == WAIT_OBJECT_0) {
+			break;
+		}
+
+		if (/*!m_bRunning || */!isConnected()) {
+			continue;
+		}
+
+		for (auto& m : m_monitors) {
+			monitorReadData(m);
+		}
+	}
+
+	TRACE("CPLC::onMonitor 线程退出\n");
+	return 0;
+}
+
+void CPLC::monitorReadData(MONITOR& monitor)
+{
+	BOOL bOutputLog = FALSE;
+	BOOL bReadOk;
+
+
+	// 批量读数据再解释
+	auto funOnReadData = [&](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void {
+		if (flag == 0) {
+			if (bOutputLog) {
+				CString s;
+				s.Format(_T("CPLC::monitorReadData::funOnReadData %d ["), nDataSize);
+				for (unsigned int i = 0; i < nDataSize; i++) {
+					s.AppendFormat(" %x", (BYTE)pData[i]);
+				}
+				s.Append("]");
+				LOGD("<CPLC-%s>Received plc data.%s.monitor=%d", m_strName.c_str(), monitor.id, (LPTSTR)(LPCTSTR)s, monitor.id);
+			}
+		}
+		else {
+			LOGE("<CPLC-%s>PLC批读取数据位超时.monitor=%d, flag=%d", m_strName.c_str(), monitor.id, flag);
+		}
+
+		if (nDataSize == monitor.readLen && flag == 0) {
+			memcpy(monitor.szRecvBuffer, pData, nDataSize);
+			monitor.readCount++;
+			bReadOk = TRUE;
+		}
+		SetEvent(monitor.hEvent);
+	};
+
+
+	bReadOk = FALSE;
+	m_pChannel->readData(monitor.softComponent, monitor.beginAddr, monitor.readLen, funOnReadData);
+	WaitForSingleObject(monitor.hEvent, INFINITE);
+	ResetEvent(monitor.hEvent);
+	if (bReadOk) {
+		onMonitorData(monitor);
+	}
+}
+
+int CPLC::onMonitorData(MONITOR& monitor)
+{
+	// 转发到警告模块处理解释数据
+	if (monitor.id == MONITOR_ID_ALARM) {
+		for (auto c : m_components) {
+			c->onData(monitor.id, monitor.szRecvBuffer, monitor.readLen);
+		}
+	}
+
+	if (m_listener.onMonitorData) {
+		m_listener.onMonitorData(this, monitor.id);
+	}
+
+	return 0;
+}
+
+int CPLC::readWord(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+	ONREAD funOnRead)
+{
+	return m_pChannel->readWord(softComponent, addr, funOnRead);
+}
+
+int CPLC::readData(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+	unsigned int nReadLen, ONREADDATA funOnReadData)
+{
+	return m_pChannel->readData(softComponent, addr, nReadLen, funOnReadData);
+}
+
+int CPLC::writeBit(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+	BOOL bValue, ONWRITE funOnWrite)
+{
+	return m_pChannel->writeBit(softComponent, addr, bValue, funOnWrite);
+}
+
+int CPLC::writeWord(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+	int value, ONWRITE funOnWrite)
+{
+	return m_pChannel->writeWord(softComponent, addr, value, funOnWrite);
+}
+
+int CPLC::writeDWord(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+	int value, ONWRITE funOnWrite)
+{
+	return m_pChannel->writeDWord(softComponent, addr, value, funOnWrite);
+}
+
+int CPLC::writeData(MC::SOFT_COMPONENT softComponent, unsigned int addr,
+	const char* pszData, unsigned int length, ONWRITE funOnWrite)
+{
+	return m_pChannel->writeData(softComponent, addr, pszData, length, funOnWrite);
+}
+
+void CPLC::addComponent(CComponent* pComponent)
+{
+	ASSERT(pComponent);
+	pComponent->setPlc(this);
+	m_components.push_back(pComponent);
+}
+
+CComponent* CPLC::getComponent(const char* pszName)
+{
+	for (auto c : m_components) {
+		if (c->getName().compare(pszName) == 0) {
+			return c;
+		}
+	}
+
+	return nullptr;
+}
+
+void CPLC::sendBroadcast(CComponent* pSender, CIntent* pIntent)
+{
+	for (auto item : m_components) {
+		if (item != pSender) {
+			item->onRecvBroadcast(pSender, pIntent);
+		}
+	}
+	this->onRecvBroadcast(pSender, pIntent);
+}
+
+void CPLC::onRecvBroadcast(CComponent* pSender, CIntent* pIntent)
+{
+	int code = pIntent->getCode();
+	if (BC_CODE_ALARM_ON == code) {
+		if (m_listener.onAlarm != nullptr) {
+			m_listener.onAlarm(this, (CAlarm*)pIntent->getContext(), 1);
+		}
+	}
+	else if (BC_CODE_ALARM_OFF == code) {
+		if (m_listener.onAlarm != nullptr) {
+			m_listener.onAlarm(this, (CAlarm*)pIntent->getContext(), 0);
+		}
+	}
+}
+
+void CPLC::readPLCDataRegularly()
+{
+	if (!isConnected()) return;
+
+	{
+		auto funOnReadData = [this](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void {
+			if (nDataSize == 2 && flag == 0) {
+				int nVelocityRatio = CToolUnits::toInt16(&pData[0]);
+				if (nVelocityRatio != m_nVelocityRatio) {
+					m_nVelocityRatio = nVelocityRatio;
+					//notifyInt(RX_CODE_VELOCITY_RATIO, m_nVelocityRatio);
+				}
+			}
+		};
+		readData(MC::D, 530, 2, funOnReadData);
+	}
+
+	{
+		auto funOnReadData = [this](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void {
+			if (nDataSize == 2 && flag == 0) {
+				double dTactTime = (double)CToolUnits::toInt16(&pData[0]);
+				if (dTactTime != m_dTactTime) {
+					m_dTactTime = dTactTime;
+					// notifyDouble(RX_CODE_TACT_TIME, m_dTactTime);
+				}
+			}
+		};
+		readData(MC::ZR, 1500, 2, funOnReadData);
+	}
+
+	{
+		auto funOnReadData = [this](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void {
+			if (nDataSize == (ADDR_NIGHT_SHIFT_CAPACTITY - 1612 + 1) * 2 && flag == 0) {
+				int nDayShiftCapacity = CToolUnits::toInt16(&pData[0]);
+				int nNightShiftCapacity = CToolUnits::toInt16(&pData[(ADDR_NIGHT_SHIFT_CAPACTITY - 1612) * 2]);
+				if (nDayShiftCapacity != m_nDayShiftCapacity) {
+					m_nDayShiftCapacity = nDayShiftCapacity;
+					// notifyInt(RX_CODE_DAY_SHIFT_CAPACTITY, nDayShiftCapacity);
+				}
+				if (nNightShiftCapacity != m_nNightShiftCapacity) {
+					m_nNightShiftCapacity = nNightShiftCapacity;
+					// notifyInt(RX_CODE_NIGHT_SHIFT_CAPACTITY, nNightShiftCapacity);
+				}
+
+			}
+		};
+		readData(MC::ZR, 1612, (ADDR_NIGHT_SHIFT_CAPACTITY - 1612 + 1) * 2, funOnReadData);
+	}
+
+	{
+		int nStartAddress = 1000;
+		int nEndAddress = 1200;
+		int nReadSize = (nEndAddress - nStartAddress + 1) * 2;
+		auto funOnReadData = [this, nStartAddress, nReadSize](IMcChannel* pChannel, int addr, char* pData, unsigned int nDataSize, int flag) -> void {
+			if (nDataSize == nReadSize && flag == 0) {
+				bool bRun = CToolUnits::toInt16(&pData[(1103 - nStartAddress) * 2]) != 0;		// 启动
+				bool bAuto = CToolUnits::toInt16(&pData[(1100 - nStartAddress) * 2]) != 0;		// 自动
+				bool bPuase = CToolUnits::toInt16(&pData[(1104 - nStartAddress) * 2]) != 0;		// 暂停
+				bool bManual = CToolUnits::toInt16(&pData[(1100 - nStartAddress) * 2]) != 0;	// 手动
+				bool bBeep = CToolUnits::toInt16(&pData[(1003 - nStartAddress) * 2]) != 0;		// 静音
+				bool bResetting = CToolUnits::toInt16(&pData[(1150 - nStartAddress) * 2]) != 0; // 复位
+				bool bStop = CToolUnits::toInt16(&pData[(1114 - nStartAddress) * 2]) != 0;		// 停止
+
+				if (m_bBlBtnsStates[0] != bRun) {
+					m_bBlBtnsStates[0] = bRun;
+					// notifyInt(RX_CODE_ACTIVATE, bRun);
+				}
+
+				if (m_bBlBtnsStates[1] != bAuto) {
+					m_bBlBtnsStates[1] = bAuto;
+					// notifyInt(RX_CODE_AUTO, bAuto);
+				}
+
+				if (m_bBlBtnsStates[2] != bPuase) {
+					m_bBlBtnsStates[2] = bPuase;
+					// notifyInt(RX_CODE_PUASE, bPuase);
+				}
+
+				if (m_bBlBtnsStates[3] != bManual) {
+					m_bBlBtnsStates[3] = bManual;
+					// notifyInt(RX_CODE_MANUAL, bManual);
+				}
+
+				if (m_bBlBtnsStates[4] != bBeep) {
+					m_bBlBtnsStates[4] = bBeep;
+					// notifyInt(RX_CODE_BEEP, bBeep);
+				}
+
+				if (m_bBlBtnsStates[5] != bResetting) {
+					m_bBlBtnsStates[5] = bResetting;
+					// notifyInt(RX_CODE_RESETTING, bResetting);
+				}
+
+				if (m_bBlBtnsStates[6] != bStop) {
+					m_bBlBtnsStates[6] = bStop;
+					// notifyInt(RX_CODE_STOP, bStop);
+				}
+			}
+		};
+		readData(MC::M, nStartAddress, nReadSize, funOnReadData);
+	}
+}
+
+int CPLC::getVelocityRatio()
+{
+	return m_nVelocityRatio;
+}
+
+double CPLC::getTackTime()
+{
+	return m_dTactTime;
+}
+
+int CPLC::getDayShiftCapacity()
+{
+	return m_nDayShiftCapacity;
+}
+
+int CPLC::getNightShiftCapacity()
+{
+	return m_nNightShiftCapacity;
+}

--
Gitblit v1.9.3