From 0d885fe2e84ac5a6390ddc4d43ab701112eedc64 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期一, 17 二月 2025 16:53:01 +0800
Subject: [PATCH] 1.各设备Alive状态获取,监听状态变化并回调应用层;

---
 SourceCode/Bond/Servo/Servo.vcxproj         |    2 
 SourceCode/Bond/Servo/Servo.vcxproj.filters |    2 
 SourceCode/Bond/Servo/ToolUnits.cpp         |  304 ++++++++++++++++++++++++++++++++++++++
 SourceCode/Bond/Servo/CEquipment.cpp        |   60 +++++++
 SourceCode/Bond/Servo/CMaster.cpp           |   27 ++-
 SourceCode/Bond/Servo/CMaster.h             |    8 +
 SourceCode/Bond/Servo/Model.cpp             |    7 
 SourceCode/Bond/Servo/CEquipment.h          |   25 +++
 SourceCode/Bond/Servo/ToolUnits.h           |   32 ++++
 9 files changed, 459 insertions(+), 8 deletions(-)

diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 6f8cd0b..6534f88 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -1,16 +1,25 @@
 #include "stdafx.h"
 #include "CEquipment.h"
+#include "ToolUnits.h"
+
 
 namespace SERVO {
 
 	CEquipment::CEquipment()
 	{
+		m_alive = {FALSE, 0, FALSE};
+		m_listener.onAlive = {nullptr};
 		InitializeCriticalSection(&m_criticalSection);
 	}
 
 	CEquipment::~CEquipment()
 	{
 		DeleteCriticalSection(&m_criticalSection);
+	}
+
+	void CEquipment::setListener(EquipmentListener listener)
+	{
+		m_listener.onAlive = listener.onAlive;
 	}
 
 	void CEquipment::init()
@@ -60,6 +69,7 @@
 		m_blockReadBit.start = start;
 		m_blockReadBit.end = end;
 		m_blockReadBit.size = (m_blockReadBit.end - m_blockReadBit.start + 1) / 8;
+		ASSERT(m_blockReadBit.size < BLOCK_BUFFER_MAX);
 	}
 
 	MemoryBlock& CEquipment::getReadBitBlock()
@@ -82,7 +92,19 @@
 
 	void CEquipment::onTimer(UINT nTimerid)
 	{
+		// 每隔一秒,检查一下ALIVE状态
 
+		static int tick = 0;
+		tick++;
+		if (tick % (4 * 1) == 0) {
+			m_alive.count++;
+			if (m_alive.alive && m_alive.count > ALIVE_TIMEOUT) {
+				m_alive.alive = FALSE;
+				if (m_listener.onAlive != nullptr) {
+					m_listener.onAlive(this, m_alive.alive);
+				}
+			}
+		}
 	}
 
 	void CEquipment::serialize(CArchive& ar)
@@ -90,4 +112,42 @@
 
 	}
 
+	void CEquipment::onReceiveLBData(const char* pszData, size_t size)
+	{
+		TRACE("%s onReceiveLBData: %d bytes\n", m_strName.c_str(), size);
+		for (unsigned int i = 0; i < size; i++) {
+			if (pszData[i] != 0)
+				TRACE("%d[%x]\n", i, pszData[i]);
+		}
+
+
+		// 解释数据
+		BOOL bAliveFlag = isBitOn(pszData, size, 0x340);
+		if (m_alive.flag != bAliveFlag) {
+			m_alive.flag = bAliveFlag;
+			m_alive.count = 0;
+
+			// 状态
+			if (!m_alive.alive) {
+				m_alive.alive = TRUE;
+				if (m_listener.onAlive != nullptr) {
+					m_listener.onAlive(this, m_alive.alive);
+				}
+			}
+		}
+	}
+
+	BOOL CEquipment::isBitOn(const char* pszData, size_t size, int index)
+	{
+		int byteIndex, bitIndex;
+		byteIndex = (index) / 8;
+		bitIndex = (index) % 8;
+
+		return CToolUnits::getBit(pszData[byteIndex], bitIndex);
+	}
+
+	BOOL CEquipment::isAlive()
+	{
+		return m_alive.alive;
+	}
 }
diff --git a/SourceCode/Bond/Servo/CEquipment.h b/SourceCode/Bond/Servo/CEquipment.h
index 9f83bb8..37d8e2b 100644
--- a/SourceCode/Bond/Servo/CEquipment.h
+++ b/SourceCode/Bond/Servo/CEquipment.h
@@ -3,13 +3,30 @@
 #include "CCLinkIEControl.h"
 
 namespace SERVO {
+#define BLOCK_BUFFER_MAX			1024
+#define ALIVE_TIMEOUT				15
+
+	typedef std::function<void(void* pEiuipment, BOOL bAlive)> ONALIVE;
+	typedef struct _EquipmentListener
+	{
+		ONALIVE				onAlive;
+	} EquipmentListener;
+
 	// Memory Block 结构体定义
 	typedef struct _MemoryBlock {
 		unsigned int type;
 		unsigned int start;
 		unsigned int end;
 		unsigned int size;
+		char buffer[BLOCK_BUFFER_MAX];
 	} MemoryBlock;
+
+	// ALIVE
+	typedef struct _ALIVE {
+		BOOL flag;
+		int count;
+		BOOL alive;
+	} ALIVE;
 
 	class CEquipment
 	{
@@ -20,6 +37,7 @@
 
 	public:
 		virtual const char* getClassName() = 0;
+		virtual void setListener(EquipmentListener listener);
 		void setName(const char* pszName);
 		std::string& getName();
 		void setDescription(const char* pszDescription);
@@ -34,18 +52,25 @@
 		virtual void term();
 		virtual void onTimer(UINT nTimerid);
 		virtual void serialize(CArchive& ar);
+		virtual void onReceiveLBData(const char* pszData, size_t size);
+		BOOL isAlive();
+
+	private:
+		BOOL isBitOn(const char* pszData, size_t size, int index);
 
 	protected:
 		inline void Lock() { EnterCriticalSection(&m_criticalSection); }
 		inline void Unlock() { LeaveCriticalSection(&m_criticalSection); }
 
 	protected:
+		EquipmentListener m_listener;
 		std::string m_strName;
 		std::string m_strDescription;
 		CRITICAL_SECTION m_criticalSection;
 		StationIdentifier m_station;
 		MemoryBlock m_blockReadBit;
 		MemoryBlock m_blockWriteBit;
+		ALIVE m_alive;
 	};
 }
 
diff --git a/SourceCode/Bond/Servo/CMaster.cpp b/SourceCode/Bond/Servo/CMaster.cpp
index 85bf38e..5ea975d 100644
--- a/SourceCode/Bond/Servo/CMaster.cpp
+++ b/SourceCode/Bond/Servo/CMaster.cpp
@@ -12,7 +12,7 @@
 
 	CMaster::CMaster()
 	{
-
+		m_listener = {nullptr};
 	}
 
 	CMaster::~CMaster()
@@ -21,6 +21,11 @@
 			delete item;
 		}
 		m_listEquipment.clear();
+	}
+
+	void CMaster::setListener(MasterListener listener)
+	{
+		m_listener.onEqAlive = listener.onEqAlive;
 	}
 
 	int CMaster::init()
@@ -93,7 +98,16 @@
 
 	int CMaster::addEquipment(CEquipment* pEquipment)
 	{
+		EquipmentListener listener;
+		listener.onAlive = [&](void* pEquipment, BOOL bAlive) -> void {
+			CEquipment* p = (CEquipment*)pEquipment;
+			if (m_listener.onEqAlive != nullptr) {
+				m_listener.onEqAlive(this, p, bAlive);
+			}
+		};
+		pEquipment->setListener(listener);
 		m_listEquipment.push_back(pEquipment);
+
 		return 0;
 	}
 
@@ -104,7 +118,7 @@
 		}
 
 
-		// 以下为测试代码
+		// 按一定频率扫描LB数据
 		static int i = 0;
 		i++;
 		if (i % (4 * 1) == 0) {
@@ -113,14 +127,11 @@
 				const StationIdentifier& station = item->getStation();
 				MemoryBlock& block = item->getReadBitBlock();
 
-				char szBuffer[1024];
 				int nRet = m_cclink.ReadData2(station, (short)block.type,
-					block.start, block.size, szBuffer);
-				for (unsigned int i = 0; i < block.size; i++) {
-					if(szBuffer[i] != 0)
-						TRACE("%d[%x]\n", i, szBuffer[i]);
+					block.start, block.size, block.buffer);
+				if (0 == nRet) {
+					item->onReceiveLBData(block.buffer, block.size);
 				}
-				TRACE("nRet=%d\n", nRet);
 			}
 		}
 	}
diff --git a/SourceCode/Bond/Servo/CMaster.h b/SourceCode/Bond/Servo/CMaster.h
index ad4d0df..f120b12 100644
--- a/SourceCode/Bond/Servo/CMaster.h
+++ b/SourceCode/Bond/Servo/CMaster.h
@@ -7,6 +7,12 @@
 
 
 namespace SERVO {
+    typedef std::function<void(void* pMaster, CEquipment* pEiuipment, BOOL bAlive)> ONEQALIVE;
+    typedef struct _MasterListener
+    {
+        ONEQALIVE				onEqAlive;
+    } MasterListener;
+
     class CMaster
     {
     public:
@@ -15,6 +21,7 @@
 
 
     public:
+        void setListener(MasterListener listener);
         int init();
         int term();
         void onTimer(UINT nTimerid);
@@ -25,6 +32,7 @@
 
 
     private:
+        MasterListener m_listener;
         CCCLinkIEControl m_cclink;
         std::list<CEquipment*> m_listEquipment;
     };
diff --git a/SourceCode/Bond/Servo/Model.cpp b/SourceCode/Bond/Servo/Model.cpp
index 7009492..a7db1b4 100644
--- a/SourceCode/Bond/Servo/Model.cpp
+++ b/SourceCode/Bond/Servo/Model.cpp
@@ -89,6 +89,13 @@
 	m_hsmsPassive.init(this, "APP", 7000);
 
 
+	SERVO::MasterListener masterListener;
+	masterListener.onEqAlive = [&](void* pMaster, SERVO::CEquipment* pEquipment, BOOL bAlive) -> void {
+		LOGI("<CModel>Equipment onAlive:%d.\n", pEquipment->getName().c_str(),
+			bAlive ? _T("ON") : _T("OFF"));
+	};
+	m_master.setListener(masterListener);
+
 	return 0;
 }
 
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 3fa06f5..864617a 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -221,6 +221,7 @@
     <ClInclude Include="stdafx.h" />
     <ClInclude Include="targetver.h" />
     <ClInclude Include="TerminalDisplayDlg.h" />
+    <ClInclude Include="ToolUnits.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="AlarmManager.cpp" />
@@ -251,6 +252,7 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
     </ClCompile>
     <ClCompile Include="TerminalDisplayDlg.cpp" />
+    <ClCompile Include="ToolUnits.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 28a906c..ae0f9c1 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -34,6 +34,7 @@
     <ClCompile Include="CBonder.cpp" />
     <ClCompile Include="CMaster.cpp" />
     <ClCompile Include="CEFEM.cpp" />
+    <ClCompile Include="ToolUnits.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -66,6 +67,7 @@
     <ClInclude Include="CBonder.h" />
     <ClInclude Include="CMaster.h" />
     <ClInclude Include="CEFEM.h" />
+    <ClInclude Include="ToolUnits.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/ToolUnits.cpp b/SourceCode/Bond/Servo/ToolUnits.cpp
new file mode 100644
index 0000000..664f802
--- /dev/null
+++ b/SourceCode/Bond/Servo/ToolUnits.cpp
@@ -0,0 +1,304 @@
+#include "stdafx.h"
+#include "ToolUnits.h"
+#include <chrono>
+#include <memory>
+
+
+CToolUnits::CToolUnits()
+{
+}
+
+
+CToolUnits::~CToolUnits()
+{
+}
+
+std::string CToolUnits::timeToString(ULONGLONG time)
+{
+	ULONGLONG time1, time2;
+	time1 = time / 1000000000;
+	time2 = time % 1000000000;
+
+	char buffer1[256], buffer[128];
+	struct tm timeinfo;
+	time_t t = time_t(time1);
+	localtime_s(&timeinfo, &t);
+	strftime(buffer, 128, "%Y-%m-%d %H:%M:%S", &timeinfo);
+	sprintf_s(buffer1, 256, "%s.%lld", buffer, time2);
+	return std::string(buffer1);
+}
+
+std::string CToolUnits::timeToString2(ULONGLONG time)
+{
+	ULONGLONG time1;
+	time1 = time / 1000;
+
+	char buffer[256];
+	struct tm timeinfo;
+	time_t t = time_t(time1);
+	localtime_s(&timeinfo, &t);
+	strftime(buffer, 128, "%Y-%m-%d %H:%M:%S", &timeinfo);
+	return std::string(buffer);
+}
+
+std::string CToolUnits::timeToString3(ULONGLONG time)
+{
+	ULONGLONG time1;
+	int ms;
+	time1 = time / 1000;
+	ms = time % 1000;
+
+	char buffer1[256], buffer[128];
+	struct tm timeinfo;
+	time_t t = time_t(time1);
+	localtime_s(&timeinfo, &t);
+	strftime(buffer, 128, "%Y-%m-%d %H:%M:%S", &timeinfo);
+	sprintf_s(buffer1, 256, "%s.%03d", buffer, ms);
+	return std::string(buffer1);
+}
+
+ULONGLONG CToolUnits::stringToTime(const char* pszTime)
+{
+	struct tm tm;
+
+	memset(&tm, 0, sizeof(tm));
+	sscanf_s(pszTime, "%d-%d-%d %d:%d:%d",
+		&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+		&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+	tm.tm_year -= 1900;
+	tm.tm_mon--;
+
+	return mktime(&tm) * 1000;
+}
+
+ULONGLONG CToolUnits::getTimestamp()
+{
+	auto now = std::chrono::system_clock::now();
+	auto duration_in_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
+	uint64_t timestamp = duration_in_milliseconds.count();
+	return timestamp;
+}
+
+void CToolUnits::createDir(const char* pszDir)
+{
+	if (isDirectory(std::string(pszDir))) {
+		return;
+	}
+
+	CString strDir = pszDir;
+	int lastIndex = 0;
+	int index = strDir.Find(_T("\\"), lastIndex);
+	while (index > 0) {
+		CString strTempDir = strDir.Left(index);
+		CreateDirectory(strTempDir, NULL);
+
+		lastIndex = index + 1;
+		index = strDir.Find(_T("\\"), lastIndex);
+	}
+	CreateDirectory(strDir, NULL);
+}
+
+CString& CToolUnits::floatToString1(float value, CString& strOut)
+{
+	strOut.Format(_T("%.1f"), value);
+	return strOut;
+}
+
+CString& CToolUnits::floatToString3(float value, CString& strOut)
+{
+	strOut.Format(_T("%.3f"), value);
+	return strOut;
+}
+
+
+BOOL CToolUnits::copyTextToClipboard(CWnd* pWnd, const CString& strText)
+{
+	if (OpenClipboard(pWnd->GetSafeHwnd())) {
+		EmptyClipboard();
+
+		HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (strText.GetLength() + 1) * sizeof(TCHAR));
+		if (hglbCopy == NULL) {
+			CloseClipboard();
+			return FALSE;
+		}
+
+		LPTSTR lptstrCopy = (LPTSTR)GlobalLock(hglbCopy);
+		strcpy_s(lptstrCopy, strText.GetLength()+1, strText);
+		GlobalUnlock(hglbCopy);
+		SetClipboardData(CF_TEXT, hglbCopy);
+		CloseClipboard();
+		GlobalFree(hglbCopy);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+std::string CToolUnits::getCurrentExePath() {
+	char path[MAX_PATH];
+	GetModuleFileName(NULL, path, MAX_PATH);
+	std::string exePath(path);
+	return exePath.substr(0, exePath.find_last_of("\\/"));
+}
+
+bool CToolUnits::isFile(const std::string& path) {
+	DWORD attributes = GetFileAttributes(path.c_str());
+	return (attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+bool CToolUnits::isDirectory(const std::string& path) {
+	DWORD attributes = GetFileAttributes(path.c_str());
+	return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+int CToolUnits::toInt32(const char* pBuffer)
+{
+	return (pBuffer[0] & 0xff) | ((pBuffer[1] & 0xff) << 8) | ((pBuffer[2] & 0xff) << 16) | ((pBuffer[3] & 0xff) << 24);
+}
+
+int CToolUnits::toInt16(const char* pBuffer)
+{
+	return (pBuffer[0] & 0xff) | (pBuffer[1] & 0xff) << 8;
+}
+
+BOOL CToolUnits::getBit(const char c, int index)
+{
+	switch (index)
+	{
+	case 0:
+		return c & 0x01;
+		break;
+	case 1:
+		return c & 0x02;
+		break;
+	case 2:
+		return c & 0x04;
+		break;
+	case 3:
+		return c & 0x08;
+		break;
+	case 4:
+		return c & 0x10;
+		break;
+	case 5:
+		return c & 0x20;
+		break;
+	case 6:
+		return c & 0x40;
+		break;
+	case 7:
+		return c & 0x80;
+		break;
+	default:
+		break;
+	}
+
+	return FALSE;
+}
+
+void CToolUnits::setBit(char* p, int index)
+{
+	int byteIndex = 0;
+	byte b = 0;
+	if (index >= 8) byteIndex = 1;
+	switch (index)
+	{
+	case 0:
+	case 8:
+		b = 0x1;
+		break;
+	case 1:
+	case 9:
+		b = 0x2;
+		break;
+	case 2:
+	case 0xA:
+		b = 0x4;
+		break;
+	case 3:
+	case 0xB:
+		b = 0x8;
+		break;
+	case 4:
+	case 0xC:
+		b = 0x10;
+		break;
+	case 5:
+	case 0xD:
+		b = 0x20;
+		break;
+	case 6:
+	case 0xE:
+		b = 0x40;
+		break;
+	case 7:
+	case 0xF:
+		b = 0x80;
+		break;
+	default:
+		break;
+	}
+
+	p[byteIndex] = b;
+}
+
+void CToolUnits::setDlgItemDouble(CWnd* pWnd, int nCtrlId, double value)
+{
+	CString strText;
+	strText.Format(_T("%.03f"), value);
+	pWnd->SetDlgItemText(nCtrlId, strText);
+}
+
+std::vector<CString> CToolUnits::GetFileNamesInDirectory(const CString& strFolderPath, const CString& strExtension)
+{
+	std::vector<CString> fileNames;
+
+	// 确保目录路径最后有反斜杠
+	CString strSearchPath = strFolderPath;
+	if (strSearchPath[strSearchPath.GetLength() - 1] != '\\') {
+		strSearchPath += '\\';
+	}
+
+	CString finalExtension = strExtension;
+	if (finalExtension.Find('.') == -1) {
+		finalExtension = '.' + finalExtension;
+	}
+	strSearchPath += "*" + finalExtension;
+
+	std::unique_ptr<CFileFind> finder = std::make_unique<CFileFind>();
+	BOOL bWorking = finder->FindFile(strSearchPath);
+
+	// 遍历文件夹
+	while (bWorking) {
+		bWorking = finder->FindNextFile();
+		if (!finder->IsDirectory()) {
+			CString fileName = finder->GetFileName();
+			int dotPos = fileName.ReverseFind('.');
+			if (dotPos != -1) {
+				fileName = fileName.Left(dotPos);
+			}
+			fileNames.push_back(fileName);
+		}
+	}
+
+	return fileNames;
+}
+
+std::string CToolUnits::getRecipePath()
+{
+	return getCurrentExePath() + "\\Recipe";
+}
+
+std::string CToolUnits::getCurrentTimeString()
+{
+	struct tm ltm;
+	time_t now = time(0);
+	localtime_s(&ltm, &now);  // 使用安全的 localtime_s 函数
+
+	char buffer[256];
+	sprintf_s(buffer, sizeof(buffer), "%04d-%02d-%02d %02d:%02d:%02d",
+		ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday,
+		ltm.tm_hour, ltm.tm_min, ltm.tm_sec);
+
+	return std::string(buffer);
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/ToolUnits.h b/SourceCode/Bond/Servo/ToolUnits.h
new file mode 100644
index 0000000..9e8fdfb
--- /dev/null
+++ b/SourceCode/Bond/Servo/ToolUnits.h
@@ -0,0 +1,32 @@
+#pragma once
+#include <string>
+
+class CToolUnits
+{
+public:
+	CToolUnits();
+	~CToolUnits();
+
+public:
+	static std::string timeToString(ULONGLONG time);
+	static std::string timeToString2(ULONGLONG time);
+	static std::string timeToString3(ULONGLONG time);
+	static ULONGLONG stringToTime(const char* pszTime);
+	static CString& floatToString1(float value, CString& strOut);
+	static CString& floatToString3(float value, CString& strOut);
+	static ULONGLONG getTimestamp();
+	static void createDir(const char* pszDir);
+	static BOOL copyTextToClipboard(CWnd* pWnd, const CString& strText);
+	static std::string getCurrentExePath();
+	static bool isFile(const std::string& path);
+	static bool isDirectory(const std::string& path);
+	static int toInt32(const char* pBuffer);
+	static int toInt16(const char* pBuffer);
+	static BOOL getBit(const char c, int index);
+	static void setBit(char* p, int index);
+	static void setDlgItemDouble(CWnd* pWnd, int nCtrlId, double value);
+	static std::vector<CString> GetFileNamesInDirectory(const CString& strFolderPath, const CString& strExtension);
+	static std::string getRecipePath();
+	static std::string getCurrentTimeString();
+};
+

--
Gitblit v1.9.3