Browse Source

新添加模块devGrpcClient

lwk 14 hours ago
parent
commit
61dcc8e83b

+ 2 - 1
CMakeLists.txt

@@ -30,4 +30,5 @@ add_subdirectory(CDI)
 #add_subdirectory(DrvProc/CcosProc)
 add_subdirectory(DrvProc/libCcosProc)
 add_subdirectory(common_api)
-add_subdirectory(Log4cpp)
+add_subdirectory(Log4cpp)
+add_subdirectory(devGrpcClient)

+ 13 - 11
LogicDevice--mqtt/LogicDevice.cpp

@@ -3070,7 +3070,7 @@ LOGICDEVICE_API DWORD WaitForBrokerRouting(const char* clientId)
 			brokerDelayMs = atoi(envDelay);
 			FINFO("[WaitForBrokerRouting] Using custom delay from environment: {$}ms", brokerDelayMs);
 		} else {
-			brokerDelayMs = 500; // 默认500ms
+			brokerDelayMs = 100; // 默认100ms,足够Broker处理路由表更新
 			FINFO("[WaitForBrokerRouting] Using default delay: {$}ms (set MQTT_BROKER_ROUTING_DELAY_MS to customize)", brokerDelayMs);
 		}
 	}
@@ -3181,7 +3181,7 @@ LOGICDEVICE_API int  PublishAction(ResDataObject* pAction, const char* pszTopic,
 	ResDataObject* pPacket = new ResDataObject();
 	mqtt_msg_list* pList = std::get<MSG_LIST_ID>(*hConnection);
 	pPacket->add(pszTopic, pAction->encode());
-	FDEBUG(" {$} Try push packet to Send list: {$}", client_id, pPacket->encode());
+	//FDEBUG(" {$} Try push packet to Send list: {$}", client_id, pPacket->encode());
 	pList->push_back(pPacket);
 	sem_post(std::get<SEMAPHORE_HANDLE_ID>(*hConnection));
 	std::cout << "try publish " << pAction->encode() << endl;
@@ -3302,9 +3302,6 @@ int  PublishActionWithoutLock(string& message, const char* pszTopic, mqtt_client
 		}
 	} while (rc != MQTT_SUCCESS_ERROR && (nTryTimes <= 2  || GetTickCount() - dwTick < dwTimeout));
 
-	//if(nTryTimes > 1)
-		FWARN("CLT {$} PublishAction  to {$} send Times {$} result {$}", client_id, pszTopic, nTryTimes, rc);
-
 	cout << CurrentDateTime() << " CLT " << client_id.c_str() << " PublishAction  to " << pszTopic << " send Times " << nTryTimes << " result " << rc << endl;
 	FDEBUG("CLT {$} PublishAction  to {$} send Times {$} result {$}", client_id, pszTopic, nTryTimes, rc);
 
@@ -3438,13 +3435,18 @@ LOGICDEVICE_API int  ActionAndRespWithConnection(ccos_mqtt_connection* hConnecti
 LOGICDEVICE_API int  ActionAndRespWithConnDefalt(ccos_mqtt_connection* hConnection, const char* pAction, ResDataObject& req, ResDataObject* pContext,
 	const char* pszTopic, ResDataObject& resObj, DWORD dwWaitTime)
 {
-	// 等待之前的QoS消息握手完成,避免消息冲突导致丢失
-	// 这比固定延时更可靠:只在必要时等待,而不是盲目延时1秒
+	// QoS=2消息握手需要时间(PUBLISH→PUBREC→PUBREL→PUBCOMP)
+	// 连续发送时增加50ms延时,避免握手状态冲突
 	const std::string client_id = std::get<CLINET_ID_ID>(*hConnection);
-	FINFO("[ActionAndRespWithConnDefalt] {$} - Waiting for previous QoS handshakes to complete before sending {$}", client_id, pAction);
-	if (!WaitForSubscriptionComplete(hConnection, 5000)) {
-		FWARN("[ActionAndRespWithConnDefalt] {$} - Some QoS handshakes still pending, proceeding anyway", client_id);
-	}
+	static std::map<std::string, DWORD> lastSendTime;
+	DWORD now = GetTickCount();
+	DWORD elapsed = (lastSendTime.count(client_id) > 0) ? (now - lastSendTime[client_id]) : 1000;
+	if (elapsed < 50) {
+		DWORD sleepMs = 50 - elapsed;
+		FINFO("[ActionAndRespWithConnDefalt] {$} - Sleeping {$}ms to avoid QoS handshake conflict", client_id, sleepMs);
+		usleep(sleepMs * 1000);
+	}
+	lastSendTime[client_id] = GetTickCount();
 
 	std::cout << CurrentDateTime() << std::get<CLINET_ID_ID>(*hConnection) << "\nAction : " << pAction << "  to " << pszTopic <<  "\n Action Body: " << " Context " << pContext->encode() << endl << endl; //<< req.encode()
 

+ 1 - 1
OemLayer/ContainerDPC/CMakeLists.txt

@@ -83,7 +83,7 @@ set_target_properties(ContainerDPC PROPERTIES
 
 # 链接依赖库
 if(UNIX AND NOT APPLE)
-    target_link_libraries(ContainerDPC PRIVATE common_api LogicDevice devClientlib)
+    target_link_libraries(ContainerDPC PRIVATE common_api LogicDevice devGrpcClient)
     message(STATUS "已链接: LogicDevice")
 endif()
 

+ 44 - 44
OemLayer/NewModelDPC/NewModelDPC.cpp

@@ -1,4 +1,4 @@
-// NewModelDPC.cpp : 定义 DLL 应用程序的导出函数。
+锘�// NewModelDPC.cpp : 瀹氫箟 DLL 搴旂敤绋嬪簭鐨勫�鍑哄嚱鏁般€�
 //
 
 #include <iostream>
@@ -6,10 +6,10 @@
 #include <filesystem>
 #include <system_error>
 #include <pthread.h>
-#include <dlfcn.h>       // 动态库加载
+#include <dlfcn.h>       // 鍔ㄦ€佸簱鍔犺浇
 #include <algorithm>     // std::transform
 #include <cstring>       // strerror
-#include <unistd.h>      // 环境变量操作
+#include <unistd.h>      // 鐜��鍙橀噺鎿嶄綔
 #include <cctype>        // toupper
 #include "NewModelDPC.h"
 #include "DevTree.h"
@@ -51,16 +51,16 @@ NewModelDPC::NewModelDPC(void)
 	string LogHost = (string)getRootpath();
 	std::string moduleName = "Platform";
 	bool ret = initLogModule(
-		LogHost,       // 主机名(用于日志路径中的{host}占位符)
-		moduleName,        // 唯一模块名
-		strLogPath,  // 配置文件路径
-		true           // 是否输出到控制台(可选)
+		LogHost,       // 涓绘満鍚嶏紙鐢ㄤ簬鏃ュ織璺�緞涓�殑{host}鍗犱綅绗︼級
+		moduleName,        // 鍞�竴妯″潡鍚�
+		strLogPath,  // 閰嶇疆鏂囦欢璺�緞
+		true           // 鏄�惁杈撳嚭鍒版帶鍒跺彴锛堝彲閫夛級
 	);
 	if (!ret) {
 		std::cerr << "Log init failed!" << std::endl;
 	}
 
-	// 绑定当前动态库的模块名(调用自身实现的接口)
+	// 缁戝畾褰撳墠鍔ㄦ€佸簱鐨勬ā鍧楀悕锛堣皟鐢ㄨ嚜韬�疄鐜扮殑鎺ュ彛锛�
 	NewModelDPC_SetLocalModuleName(moduleName);
 
 	FINFO("Code Build datetime [{$} {$}]", __DATE__, __TIME__);
@@ -205,7 +205,7 @@ bool NewModelDPC::LoadVirtualDevice(const char* pDevicePath, bool isImgDevice, b
 				FreeVirtualDeviceAPI freeFunc = (FreeVirtualDeviceAPI)dlsym(hModle, "ReleaseVirtualDevice");
 				if (freeFunc && pDevice)
 				{
-					//创建对象,只是模型文件操作
+					//鍒涘缓瀵硅薄锛屽彧鏄�ā鍨嬫枃浠舵搷浣�
 					FINFO(" SetDeviceInfo {$} devSrvPath: {$} ",devPath, devSrvPath);
 					pDevice->SetDeviceInfo(devPath, devSrvPath);
 
@@ -250,25 +250,25 @@ std::array<imgFuncThreadParams, MAX_IMG_THREAD>& GetParamImgThread() {
 	return instance;
 }
 
-// 获取线程句柄数组
+// 鑾峰彇绾跨▼鍙ユ焺鏁扮粍
 std::array<pthread_t, MAX_IMG_THREAD>& GetHImgThread() {
 	static std::array<pthread_t, MAX_IMG_THREAD> instance;
 	return instance;
 }
 
-// 获取空闲事件向量
+// 鑾峰彇绌洪棽浜嬩欢鍚戦噺
 std::vector<std::shared_ptr<LinuxEvent>>& GetHIdleEvent() {
 	static std::vector<std::shared_ptr<LinuxEvent>> instance;
 	return instance;
 }
 
-// 获取数据已读事件向量
+// 鑾峰彇鏁版嵁宸茶�浜嬩欢鍚戦噺
 std::vector<std::shared_ptr<LinuxEvent>>& GetHDataReaded() {
 	static std::vector<std::shared_ptr<LinuxEvent>> instance;
 	return instance;
 }
 
-// 获取数据就绪事件向量
+// 鑾峰彇鏁版嵁灏辩华浜嬩欢鍚戦噺
 std::vector<std::shared_ptr<LinuxEvent>>& GetHDataReadyEvent() {
 	static std::vector<std::shared_ptr<LinuxEvent>> instance;
 	return instance;
@@ -296,7 +296,7 @@ bool NewModelDPC::InitDeviceMgr(const char *pDriverpath)
 		const char* dlsym_error = dlerror();
 		if (dlsym_error) {
 			std::cout << "NewModelDPC::InitDeviceMgr: Failed to get 'CreateIODriver' function: " << dlsym_error << std::endl;
-			// 处理错误
+			// 澶勭悊閿欒�
 			dlclose(m_Module);
 			return false;
 		}
@@ -317,22 +317,22 @@ bool NewModelDPC::InitDeviceMgr(const char *pDriverpath)
 					GetHDataReaded().push_back(LinuxEvent::CreateEvent(LinuxEvent::AUTO_RESET, false));
 
 					std::cout << "NewModelDPC::InitDeviceMgr: Creating image processing thread " << x << std::endl;
-					// 创建线程
+					// 鍒涘缓绾跨▼
 					//int ret = pthread_create(&GetHImgThread()[x], nullptr, ImgeProcessThread, (void*)(intptr_t)x);
 					//if (ret != 0) {
 					//	std::cout << "NewModelDPC::InitDeviceMgr: Failed to create thread " << x << " with error code: " << ret << std::endl;
-					//	// 线程创建失败处理
+					//	// 绾跨▼鍒涘缓澶辫触澶勭悊
 					//}
 					//else {
 					//	std::cout << "NewModelDPC::InitDeviceMgr: Successfully created image processing thread " << x << std::endl;
-					//	// 可选:设置线程名称或属性
+					//	// 鍙�€夛細璁剧疆绾跨▼鍚嶇О鎴栧睘鎬�
 					//}
 
 				}
 				GetHDataReadyEvent().push_back(g_hExit);
 				GetHIdleEvent().push_back(g_hExit);
 				std::cout << "NewModelDPC::InitDeviceMgr: Initialized data for image processing threads" << std::endl;
-				///初始化 图像处理线程需要的数据
+				///鍒濆�鍖� 鍥惧儚澶勭悊绾跨▼闇€瑕佺殑鏁版嵁
 
 				return true;
 			}
@@ -354,10 +354,10 @@ bool NewModelDPC::InitDeviceMgr(const char *pDriverpath)
 	}
 	else
 	{
-		// 获取dlopen错误
 		const char* dl_error = dlerror();
-		std::cout << "NewModelDPC::InitDeviceMgr: Failed to load library " << pDriverpath << ". Error: " << (dl_error ? dl_error : "Unknown error") << std::endl;
-		FERROR("Load lib:{$} failed.ErrNo:{$}\n", pDriverpath, errno);
+		std::cout << "NewModelDPC::InitDeviceMgr: Failed to load library " << pDriverpath << ". Error: " << (dl_error ?
+			dl_error : "Unknown error") << std::endl;
+		FERROR("Load lib:{$} failed. Error:{$}\n", pDriverpath, dl_error ? dl_error : "Unknown error");  // 鉁� 浣跨敤dlerror()
 	}
 
 	return false;
@@ -428,7 +428,7 @@ bool NewModelDPC::DriverEntry(ResDataObject &Configuration)
 	if (Configuration.GetKeyCount("ServerID") > 0)
 	{
 		std::cout << "ServerID configuration found" << std::endl;
-		//有ServerID配置
+		//鏈塖erverID閰嶇疆
 		m_nServerIdx = (int)Configuration["ServerID"];
 		std::cout << "ServerID value: " << m_nServerIdx << std::endl;
 		if (m_nServerIdx > 0)
@@ -520,7 +520,7 @@ bool NewModelDPC::DriverEntry(ResDataObject &Configuration)
 		FERROR("Try Load Configration from Driver Config [{$}]", moduleConfig);
 	}
 
-	//这里修改SDKPath和ServerID
+	//杩欓噷淇�敼SDKPath鍜孲erverID
 	if (m_nServerIdx > 0 && sdkPath.length() > 0)
 	{
 		std::cout << "Updating SDKPath and ServerID in config file: " << m_nServerIdx << std::endl;
@@ -581,8 +581,8 @@ bool NewModelDPC::DriverEntry(ResDataObject &Configuration)
 
 	if (ret)
 	{
-		//这里检查模型对象的配置项是否存在,如果是走模型配置,在安装的时候,会自动创建一份修改后的配置文件
-		//这里可以直接检查到
+		//杩欓噷妫€鏌ユā鍨嬪�璞$殑閰嶇疆椤规槸鍚﹀瓨鍦�紝濡傛灉鏄�蛋妯″瀷閰嶇疆锛屽湪瀹夎�鐨勬椂鍊欙紝浼氳嚜鍔ㄥ垱寤轰竴浠戒慨鏀瑰悗鐨勯厤缃�枃浠�
+		//杩欓噷鍙�互鐩存帴妫€鏌ュ埌
 		std::cout << "Calling m_NewDevManager->DriverEntry with path: " << filepath << std::endl;
 		FINFO("m_NewDevManager->DriverEntry {$}", filepath);
 		ret = m_NewDevManager->DriverEntry(filepath);
@@ -654,7 +654,7 @@ DWORD SYSTEM_CALL NewModelDPC::OnNotify(std::vector<std::shared_ptr<LinuxEvent>>
 					FINFO("Notify CONNECTED is ok");
 				}
 			}
-			//此处从程序启动后会一直打印,重复调用work函数
+			//姝ゅ�浠庣▼搴忓惎鍔ㄥ悗浼氫竴鐩存墦鍗帮紝閲嶅�璋冪敤work鍑芥暟
 			//FINFO("ImageSaveDev->work()");
 			//((ImageSaveDev*)m_pImgSaveDev)->Work();
 		}
@@ -667,13 +667,13 @@ RET_STATUS  NewModelDPC::OnAction(const char* pszActionName, const char* pszPara
 	RET_STATUS ret = ModuleDriver::OnAction(pszActionName, pszParams, resResponse);
 	if (ret != RET_NOSUPPORT)
 	{
-		//成功或者失败,
+		//鎴愬姛鎴栬€呭け璐ワ紝
 		return ret;
 	}
 	string action = pszActionName;
 	if (action == "InstallVirutalDevice")
 	{
-		//安装虚拟设备
+		//瀹夎�铏氭嫙璁惧�
 		/// "ABS": {
 		//	"InstalHost":"Detector",
 		//		"ImgeProcessDevice" : "ABS\\ABSX64.dll"
@@ -682,7 +682,7 @@ RET_STATUS  NewModelDPC::OnAction(const char* pszActionName, const char* pszPara
 		//		"MessageProcessDevice": "DAP\\DAPX64.dll"
 		//	}
 		//
-		//找到配置项,检查文件
+		//鎵惧埌閰嶇疆椤癸紝妫€鏌ユ枃浠�
 		//ResDataObject resTest,resdll;
 		//resdll.add("ImgeProcessDevice", "ABS\\ABSX64.dll");
 		//resTest.add("ABS", resdll);
@@ -750,7 +750,7 @@ RET_STATUS  NewModelDPC::OnAction(const char* pszActionName, const char* pszPara
 			}
 			if (got || changed)
 			{
-				//新装
+				//鏂拌�
 				string newdev = "CCOS/DEVICE/" + string(resVirtual.GetKey(vdIdx));
 				string devPath = newdev;
 				devPath += "/" +  string((const char*)m_resHardwareInfo["VendorID"]);// , (const char*)Configuration["VendorID"]);
@@ -766,7 +766,7 @@ RET_STATUS  NewModelDPC::OnAction(const char* pszActionName, const char* pszPara
 
 					FINFO("New install VD {$]", strServDevPath);
 
-					//之前没有配置,则需要测试,并设置
+					//涔嬪墠娌℃湁閰嶇疆锛屽垯闇€瑕佹祴璇曪紝骞惰�缃�
 					LoadVirtualDevice(vdModuleName.c_str(), false, false, devPath, strServDevPath);
 				}
 				else
@@ -979,7 +979,7 @@ RET_STATUS NewModelDPC::GetDeviceResource(ResDataObject *pDeviceResource)
 /*
 void NewModelDPC::SubscribeSelf() {
 
-	//这里订阅topic
+	//杩欓噷璁㈤槄topic
 }*/
 
 bool NewModelDPC::Device_Probe(ResDataObject &HardwareInfo)
@@ -1026,7 +1026,7 @@ bool NewModelDPC::SetDriverWorkPath(const char *pWorkPath)
 {
 	(*m_pWorkpath) = pWorkPath;
 
-	//要把读取单一硬件属性的过程放到此处
+	//瑕佹妸璇诲彇鍗曚竴纭�欢灞炴€х殑杩囩▼鏀惧埌姝ゅ�
 
 	return true;
 
@@ -1098,7 +1098,7 @@ void* ImgeProcessThread(void* pPara)
 		std::cout << "[" << getCurrentTime() << "] ERROR: ImgeProcessThread: GetHDataReadyEvent()[" << nIndex << "] is null, thread exit." << std::endl;
 		return nullptr;
 	}
-	hWait.push_back(GetHDataReadyEvent()[nIndex]); // 第一个事件
+	hWait.push_back(GetHDataReadyEvent()[nIndex]); // 绗�竴涓�簨浠�
 	hWait.push_back(g_hExit);
 
 	while (true)
@@ -1106,7 +1106,7 @@ void* ImgeProcessThread(void* pPara)
 		DWORD dwWait = LinuxEvent::WaitForMultipleEvents(hWait, 1000);
 		if (dwWait == WAIT_OBJECT_0)
 		{
-			//有图像
+			//鏈夊浘鍍�
 			int nNum = std::get<0>(*pParam);
 			ImageProcessAPI* func = std::get<1>(*pParam);
 			LogicDevice** pDev = std::get<8>(*pParam);
@@ -1194,7 +1194,7 @@ int  NewModelDPC::ImageRrocess(int Type, string& imageHead, ResDataObject& resCo
 			FINFO("Notify ImageProcessThread [{$}] work ", dwWait - WAIT_OBJECT_0);
 			GetHDataReadyEvent()[dwWait - WAIT_OBJECT_0]->SetEvent();
 
-			//等待线程 读取完数据 ,就可以下一个
+			//绛夊緟绾跨▼ 璇诲彇瀹屾暟鎹� 锛屽氨鍙�互涓嬩竴涓�
 			FINFO("Start Wait {$} Thread to Read Data.", m_arrImgeFunc.size());
 
 			DWORD dwRet = GetHDataReaded()[dwWait - WAIT_OBJECT_0]->Wait(4000);
@@ -1278,7 +1278,7 @@ PVOID NewModelDPC::LoadLogicDevices()
 				imgLogicDevice = (const char*)Config["CONFIGURATION"][first];
 				if (imgLogicDevice.length() > 0)
 				{
-					//图像处理逻辑设备
+					//鍥惧儚澶勭悊閫昏緫璁惧�
 					LoadVirtualDevice(imgLogicDevice.c_str(), true);
 				}
 				first = Config["CONFIGURATION"].GetNextOf("ImgeProcessDevice", first);
@@ -1294,7 +1294,7 @@ PVOID NewModelDPC::LoadLogicDevices()
 				imgLogicDevice = (const char*)Config["CONFIGURATION"][first];
 				if (imgLogicDevice.length() > 0)
 				{
-					//图像处理逻辑设备
+					//鍥惧儚澶勭悊閫昏緫璁惧�
 					LoadVirtualDevice(imgLogicDevice.c_str(), false);
 				}
 				first = Config["CONFIGURATION"].GetNextOf("MessageProcessDevice", first);
@@ -1314,7 +1314,7 @@ PVOID NewModelDPC::LoadLogicDevices()
 	//m_arrImgeProcessDevices = nullptr;
 	//if (imgLogicDevice.length() > 0)
 	//{
-	//	//图像处理逻辑设备
+	//	//鍥惧儚澶勭悊閫昏緫璁惧�
 	//	LoadVirtualDevice(imgLogicDevice.c_str(), true);
 	//}
 
@@ -1323,7 +1323,7 @@ PVOID NewModelDPC::LoadLogicDevices()
 
 	//if (noImgLogicDevice.length() > 0)
 	//{
-	//	//非图像处理设备
+	//	//闈炲浘鍍忓�鐞嗚�澶�
 	//	LoadVirtualDevice(noImgLogicDevice.c_str());
 	//}
 
@@ -1347,13 +1347,13 @@ PVOID NewModelDPC::LoadLogicDevices()
 			subpath = (guidname).c_str();
 			ResDataObject probe,conn_usless;
 			Device_Probe(probe);
-			//此时知道宿主设备是谁,如果Generator/Detector
+			//姝ゆ椂鐭ラ亾瀹夸富璁惧�鏄�皝锛屽�鏋淕enerator/Detector
 			//
 			string hostName;
 			bool isMain = false;
 			if (probe.GetKeyCount("MajorID") > 0)
 			{
-				//找到宿主
+				//鎵惧埌瀹夸富
 				hostName = "CCOS/DEVICE/" + string((const char* )probe["MajorID"]);
 			}
 			string fullpath = MakeDevicePath(probe, conn_usless, subpath).encode();
@@ -1363,7 +1363,7 @@ PVOID NewModelDPC::LoadLogicDevices()
 			{
 				if (ccospath.substr(0, hostName.length()) == hostName)
 				{
-					//宿主设备
+					//瀹夸富璁惧�
 					isMain = true;
 					FINFO("Got MainHost {$} of {$}", hostName, ccospath);
 				}
@@ -1373,7 +1373,7 @@ PVOID NewModelDPC::LoadLogicDevices()
 				m_MainHostDevice = p;
 
 				FINFO("Add ImageProcess Deivce : {$} ", m_arrImgeProcessDevices.size());
-				//嵌入式设备加载
+				//宓屽叆寮忚�澶囧姞杞�
 				for (int x = 0; x < m_arrImgeProcessDevices.size(); x++)
 				{
 					GUID guid2;

+ 125 - 0
devGrpcClient/CMakeLists.txt

@@ -0,0 +1,125 @@
+cmake_minimum_required(VERSION 3.10)
+project(devGrpcClient VERSION 1.0.0 LANGUAGES CXX)
+
+# 设置编译选项
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+add_compile_options(-fPIC -g -Wall -march=armv8-a)
+
+# 目标目录
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+get_filename_component(DELIVER_DIR "${CMAKE_BINARY_DIR}/../../Deliver" ABSOLUTE)
+file(MAKE_DIRECTORY "${DELIVER_DIR}/lib" "${DELIVER_DIR}/include")
+
+# ========== 静态依赖 gRPC 1.30.2 相关库 ==========
+# 1. 库路径(指定编译的静态库)
+set(GRPC_ROOT "/usr/local/grpc-1.30.2")
+set(ABSEIL_ROOT "/usr/local/abseil-20210324.2")
+
+# 2. 头文件目录
+include_directories(
+  ${GRPC_ROOT}/include  # gRPC头文件
+  ${ABSEIL_ROOT}/include  # Abseil头文件
+  ${CMAKE_CURRENT_SOURCE_DIR}/src
+  ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+# 3. 库文件目录
+link_directories(
+  ${GRPC_ROOT}/lib  # gRPC库文件
+  ${ABSEIL_ROOT}/lib  # Abseil库文件
+)
+
+# 4. gRPC静态库列表(.a文件)
+set(GRPC_STATIC_LIBS
+  grpc++_reflection
+  grpc++
+  grpc
+  gpr
+  address_sorting
+)
+
+# 5. Abseil静态库列表(.a文件)
+set(ABSEIL_STATIC_LIBS
+  absl_base
+  absl_strings
+  absl_synchronization
+  absl_time
+  absl_bad_optional_access
+  absl_str_format_internal
+  absl_int128
+  absl_raw_logging_internal
+  absl_spinlock_wait
+  absl_throw_delegate
+  absl_malloc_internal
+)
+
+# ========== gRPC代码生成器(1.30.2版本的编译器) ==========
+set(_GRPC_CPP_PLUGIN_EXECUTABLE "${GRPC_ROOT}/bin/grpc_cpp_plugin")
+if(NOT EXISTS "${_GRPC_CPP_PLUGIN_EXECUTABLE}")
+  message(FATAL_ERROR "未找到gRPC 1.30.2编译器: ${_GRPC_CPP_PLUGIN_EXECUTABLE}")
+else()
+  message(STATUS "找到gRPC 1.30.2编译器: ${_GRPC_CPP_PLUGIN_EXECUTABLE}")
+endif()
+
+# ========== Protobuf配置(系统静态库) ==========
+find_package(Protobuf REQUIRED)
+message(STATUS "使用系统Protobuf版本: ${Protobuf_VERSION}")
+
+# ========== 编译Proto文件(与1.30.2版本保持兼容) ==========
+get_filename_component(DEV_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protos/device-sm.proto" ABSOLUTE)
+get_filename_component(DEV_PROTO_DIR "${DEV_PROTO}" PATH)
+
+set(DEV_PROTO_SRC "${CMAKE_CURRENT_BINARY_DIR}/device-sm.pb.cc")
+set(DEV_PROTO_HDR "${CMAKE_CURRENT_BINARY_DIR}/device-sm.pb.h")
+set(DEV_GRPC_SRC "${CMAKE_CURRENT_BINARY_DIR}/device-sm.grpc.pb.cc")
+set(DEV_GRPC_HDR "${CMAKE_CURRENT_BINARY_DIR}/device-sm.grpc.pb.h")
+
+add_custom_command(
+  OUTPUT "${DEV_PROTO_SRC}" "${DEV_PROTO_HDR}" "${DEV_GRPC_SRC}" "${DEV_GRPC_HDR}"
+  COMMAND $<TARGET_FILE:protobuf::protoc>
+  ARGS 
+    --grpc_out="${CMAKE_CURRENT_BINARY_DIR}"
+    --cpp_out="${CMAKE_CURRENT_BINARY_DIR}"
+    -I "${DEV_PROTO_DIR}"
+    --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
+    "${DEV_PROTO}"
+  DEPENDS "${DEV_PROTO}"
+  COMMENT "生成基于gRPC 1.30.2的proto代码"
+)
+
+add_custom_target(GenerateProto ALL
+  DEPENDS "${DEV_PROTO_SRC}" "${DEV_PROTO_HDR}" "${DEV_GRPC_SRC}" "${DEV_GRPC_HDR}"
+)
+
+# ========== 编译动态库(依赖静态gRPC和Abseil) ==========
+set(SRC_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/src/devGrpcClient.cpp
+  ${DEV_PROTO_SRC}
+  ${DEV_GRPC_SRC}
+)
+
+add_library(devGrpcClient SHARED ${SRC_FILES})
+add_dependencies(devGrpcClient GenerateProto)
+
+set_target_properties(devGrpcClient PROPERTIES
+  VERSION ${PROJECT_VERSION}
+  SOVERSION 1
+  OUTPUT_NAME "devGrpcClient"
+)
+
+# 链接依赖库(静态库+系统库)
+target_link_libraries(devGrpcClient PRIVATE
+  ${GRPC_STATIC_LIBS}
+  ${ABSEIL_STATIC_LIBS}
+  protobuf::libprotobuf  # 系统Protobuf静态库
+  pthread dl z ssl crypto  # 系统基础库
+)
+
+# ========== 输出到交付目录 ==========
+add_custom_command(TARGET devGrpcClient POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:devGrpcClient>" "${DELIVER_DIR}/lib/"
+  COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_FILE_NAME:devGrpcClient>" "${DELIVER_DIR}/lib/$<TARGET_SONAME_FILE_NAME:devGrpcClient>"
+  COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_SONAME_FILE_NAME:devGrpcClient>" "${DELIVER_DIR}/lib/$<TARGET_LINKER_FILE_NAME:devGrpcClient>"
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/src/devGrpcClient.h" "${DELIVER_DIR}/include/"
+)

+ 279 - 0
devGrpcClient/README.md

@@ -0,0 +1,279 @@
+# devGrpcClient - gRPC设备客户端库
+
+## 简介
+
+devGrpcClient 是一个基于 gRPC 的跨平台设备通信客户端库,提供同步和异步RPC调用接口。该库封装了设备操作的完整功能,支持SSL/TLS安全连接。
+
+## 主要特性
+
+- **完整的设备操作接口**:支持 Get/Set/Update/Add/Del/Action/Message 操作
+- **同步与异步调用**:既支持阻塞式同步调用,也支持高性能异步批量调用
+- **SSL/TLS加密**:所有通信均通过SSL/TLS加密,保证数据安全
+- **跨平台支持**:支持 Linux 和 Windows 平台
+- **C++ 接口**:提供简洁的C++接口,易于集成
+
+## 快速开始
+
+### 环境准备
+
+详细的环境配置步骤请参考:**[环境配置说明.md](./环境配置说明.md)**
+
+**必需依赖:**
+- gRPC 1.30.2(安装在 `/usr/local/grpc-1.30.2`)
+- Abseil C++ 20210324.2(安装在 `/usr/local/abseil-20210324.2`)
+- Protobuf(系统包管理器安装)
+- CMake 3.10+
+- C++17 编译器
+
+### 编译项目
+
+```bash
+# 在项目根目录下
+cd /path/to/DriverPlatform-V3.1
+mkdir -p build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make devGrpcClient -j$(nproc)
+```
+
+编译完成后,库文件和头文件会自动复制到 `Deliver/` 目录:
+- 库文件:`Deliver/lib/libdevGrpcClient.so*`
+- 头文件:`Deliver/include/devGrpcClient.h`
+
+### 使用示例
+
+#### 1. 包含头文件
+
+```cpp
+#include "devGrpcClient.h"
+```
+
+#### 2. 创建客户端连接
+
+```cpp
+// 连接到服务器(需要提供 root.crt 证书文件)
+GrpcDeviceClient* client = CreateClient("192.168.1.100:9010");
+```
+
+#### 3. 打开设备
+
+```cpp
+int result = client->OpenDevice("DIOS/DEVICE/Detector", "");
+if (result != 2) {
+    std::cerr << "设备打开失败" << std::endl;
+}
+```
+
+#### 4. 同步调用
+
+```cpp
+std::string devRes, msg;
+int ret = client->Get("AcqMode", devRes, msg);
+std::cout << "返回码: " << ret << ", 数据: " << devRes << std::endl;
+
+// 设置参数
+ret = client->Set("Brightness", "{\"value\":80}", devRes, msg);
+
+// 执行动作
+ret = client->Action("StartAcquisition", "", devRes, msg);
+```
+
+#### 5. 异步批量调用
+
+```cpp
+// 开始异步调用模式
+client->BeginAyncWait();
+
+// 批量发起异步请求
+int count = 0;
+count = client->AsyncAction("EnterExam", "");
+count = client->AsyncAction("RESET", "");
+count = client->AsyncAction("PrepareAcquisition", "");
+
+// 等待所有请求完成
+client->WaitAllComplete();
+
+// 获取结果
+for (int i = 0; i < count; i++) {
+    std::string action, result, resultMsg;
+    int code = client->GetAsyncResult(i, action, result, resultMsg);
+    std::cout << "异步调用[" << i << "] " << action
+              << " 返回码=" << code << std::endl;
+}
+
+// 结束异步模式
+client->EndAync();
+```
+
+#### 6. 释放客户端
+
+```cpp
+FreeClient(client);
+```
+
+### 完整示例程序
+
+```cpp
+#include "devGrpcClient.h"
+#include <iostream>
+
+int main() {
+    // 创建客户端
+    GrpcDeviceClient* client = CreateClient("localhost:9010");
+
+    // 打开设备
+    if (client->OpenDevice("DIOS/DEVICE/Detector", "") != 2) {
+        std::cerr << "设备打开失败" << std::endl;
+        FreeClient(client);
+        return -1;
+    }
+
+    // 同步获取数据
+    std::string data, msg;
+    client->Get("DeviceInfo", data, msg);
+    std::cout << "设备信息: " << data << std::endl;
+
+    // 释放客户端
+    FreeClient(client);
+    return 0;
+}
+```
+
+编译示例程序:
+
+```bash
+g++ -o example example.cpp \
+  -I/path/to/Deliver/include \
+  -L/path/to/Deliver/lib \
+  -ldevGrpcClient \
+  -Wl,-rpath,/path/to/Deliver/lib
+```
+
+## API 接口说明
+
+### 设备管理接口
+
+- `int OpenDevice(string devUri, string group)` - 打开设备
+- `int CloseDevice()` - 关闭设备
+- `string GetDeviceTarget()` - 获取设备目标地址
+- `int GetClientStatus()` - 获取客户端连接状态
+- `string GetOpendDeviceResource()` - 获取已打开的设备资源
+
+### 同步操作接口
+
+所有同步接口返回操作结果码(2表示成功),并通过参数返回结果数据:
+
+- `int Get(string devResource, string& devRes, string& calResMsg, ...)` - 获取数据
+- `int Set(string devResource, string reqParams, string& devRes, string& calResMsg, ...)` - 设置数据
+- `int Update(string devResource, string reqParams, string& devRes, string& calResMsg, ...)` - 更新数据
+- `int Add(string devResource, string reqParams, string& devRes, string& calResMsg, ...)` - 添加数据
+- `int Del(string devResource, string reqParams, string& devRes, string& calResMsg, ...)` - 删除数据
+- `int Action(string devResource, string reqParams, string& devRes, string& calResMsg, ...)` - 执行动作
+- `int Message(string devResource, string reqParams, string& devRes, string& calResMsg, ...)` - 发送消息
+
+### 异步操作接口
+
+异步接口用于批量并发执行操作,提高性能:
+
+- `int BeginAyncWait()` - 开始异步调用模式
+- `int AsyncAction(string devResource, string reqParams, ...)` - 异步执行动作
+- `int AsyncMessage(string devResource, string reqParams, ...)` - 异步发送消息
+- `void WaitAllComplete()` - 等待所有异步调用完成
+- `int GetAsyncResult(int idx, string& devResource, string& devRes, string& calResMsg)` - 获取异步结果
+- `void EndAync()` - 结束异步模式,清理资源
+
+### 工厂函数
+
+- `GrpcDeviceClient* CreateClient(const char* serverAddress)` - 创建客户端实例
+- `void FreeClient(GrpcDeviceClient* client)` - 释放客户端实例
+
+## 返回码说明
+
+| 返回码 | 含义 |
+|--------|------|
+| 2 | 成功 |
+| 0 | 失败(通用) |
+| < 0 | 网络错误(负数为gRPC错误码) |
+
+## 证书配置
+
+客户端使用SSL/TLS加密连接,需要提供服务器的根证书文件 `root.crt`。
+
+**证书文件位置:** 默认从当前工作目录加载 `root.crt`
+
+如需使用其他路径,可修改 `devGrpcClient.cpp` 中的证书加载代码:
+
+```cpp
+ssl_options.pem_root_certs = LoadStringFromFile("/path/to/root.crt");
+```
+
+## 项目结构
+
+```
+devGrpcClient/
+├── CMakeLists.txt              # CMake构建配置
+├── README.md                   # 本文件
+├── 环境配置说明.md             # 详细的环境配置文档
+├── protos/
+│   └── device-sm.proto         # gRPC服务定义文件
+└── src/
+    ├── devGrpcClient.h         # 客户端头文件
+    └── devGrpcClient.cpp       # 客户端实现
+```
+
+## 技术栈
+
+- **通信协议:** gRPC 1.30.2
+- **序列化:** Protocol Buffers 3
+- **C++标准:** C++17
+- **加密:** SSL/TLS(基于OpenSSL)
+- **线程库:** std::thread(C++11)
+- **依赖库:** Abseil C++ 20210324.2
+
+## 常见问题
+
+### 1. 编译时找不到gRPC库
+
+请确保gRPC已正确安装在 `/usr/local/grpc-1.30.2`,详见[环境配置说明.md](./环境配置说明.md)。
+
+### 2. 运行时找不到动态库
+
+```bash
+export LD_LIBRARY_PATH=/path/to/Deliver/lib:$LD_LIBRARY_PATH
+```
+
+### 3. 证书加载失败
+
+确保 `root.crt` 文件与可执行文件在同一目录,或使用绝对路径。
+
+### 4. 连接超时
+
+检查服务器地址和端口是否正确,防火墙是否允许连接。
+
+更多问题请参考 **[环境配置说明.md](./环境配置说明.md)** 的"常见问题"章节。
+
+## 性能优化建议
+
+1. **使用异步接口进行批量操作**:可显著提高并发性能
+2. **复用客户端连接**:避免频繁创建和销毁客户端
+3. **合理设置超时时间**:根据网络环境调整RPC超时时间
+4. **使用连接池**:在多线程环境中使用连接池管理客户端实例
+
+## 版本历史
+
+### v1.0.0 (2025-10-22)
+- 初始版本发布
+- 支持完整的设备操作接口
+- 实现同步和异步RPC调用
+- 支持SSL/TLS加密连接
+
+## 许可证
+
+本项目为内部使用项目,版权归公司所有。
+
+## 联系方式
+
+如有问题或建议,请联系项目维护者。
+
+---
+
+**注意:** 在生产环境部署前,请务必阅读 **[环境配置说明.md](./环境配置说明.md)** 完成所有环境配置。

+ 75 - 0
devGrpcClient/protos/device-sm.proto

@@ -0,0 +1,75 @@
+syntax = "proto3";
+
+package Device.V3;
+
+message OpenRequest {
+  string deviceUri = 1;
+  string deviceGroup = 2;
+}
+
+message OpenReply {
+  string message = 1;
+  string retCode = 2;
+  string retContext = 3;
+}
+
+message DoRequest{
+  string deviceUri = 1;
+  string reqName = 2;
+  string reqParam = 3;
+  string reqTransaction = 4;
+  string reqClientID = 5;
+}
+
+message DoResponse{
+  string deviceUri = 1;
+  string retCode = 2;
+  string reqName = 3;
+  string respResult = 4;
+  string reqTransaction = 5;
+  string retContext = 6;
+}
+
+// a gRPC service
+service Device {
+ // Open is a rpc call and a option is defined for it
+  rpc Open (OpenRequest) returns (OpenReply) {
+  // option type is http
+ 
+  };
+  rpc Close (OpenRequest) returns (OpenReply) {
+  // option type is http
+
+  };
+  rpc Get (DoRequest) returns (DoResponse) {
+  // option type is http
+
+  };
+
+  rpc Set (DoRequest) returns (DoResponse) {
+  // option type is http
+
+  };
+
+  rpc Update (DoRequest) returns (DoResponse) {
+  // option type is http
+
+  };
+
+  rpc Add (DoRequest) returns (DoResponse) {
+  // option type is http
+
+  };
+  rpc Del (DoRequest) returns (DoResponse) {
+  // option type is http
+
+  };
+  rpc Action (DoRequest) returns (DoResponse) {
+  // option type is http
+
+  };
+  rpc Message (DoRequest) returns (DoResponse) {
+  // option type is http
+
+  };
+}

+ 408 - 0
devGrpcClient/src/devGrpcClient.cpp

@@ -0,0 +1,408 @@
+#include "devGrpcClient.h"
+#include <memory>
+#include <string>
+#include <vector>
+#include <thread>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+//#include "absl/log/check.h"
+
+#include <grpc/support/log.h>
+#include <grpcpp/grpcpp.h>
+
+// 引用protobuf生成的头文件(编译时自动生成)
+#include "device-sm.grpc.pb.h"
+
+using namespace std;
+using grpc::Channel;
+using grpc::ClientAsyncResponseReader;
+using grpc::ClientContext;
+using grpc::CompletionQueue;
+using grpc::Status;
+
+// LoadStringFromFile函数实现
+std::string LoadStringFromFile(std::string path) {
+    std::ifstream file(path);
+    if (!file.is_open()) {
+        std::cout << "Failed to open " << path << std::endl;
+        abort();
+    }
+    std::stringstream sstr;
+    sstr << file.rdbuf();
+    return sstr.str();
+}
+
+// 实现GrpcDeviceClient的派生类
+class GrpcDeviceClientImpl : public GrpcDeviceClient {
+private:
+    // 异步调用结构体(原始逻辑)
+    struct AsyncClientCall {
+        Device::V3::DoResponse reply;
+        ClientContext context;
+        Status status;
+        std::unique_ptr<ClientAsyncResponseReader<Device::V3::DoResponse>> response_reader;
+    };
+
+    std::unique_ptr<Device::V3::Device::Stub> stub_;
+    std::shared_ptr<Channel> channel_;
+    CompletionQueue cq_;
+    std::thread* pthread_ = nullptr;
+    std::vector<AsyncClientCall*> m_reqList;
+    int m_nNeedResult = 0;
+    string m_strDeviceTarget;
+    string m_strDestDeviceUri;
+    string m_strDeviceResource;
+
+    // 异步RPC完成处理(原始逻辑)
+    void AsyncCompleteRpc() {
+        void* got_tag;
+        bool ok = false;
+        int gots = 0;
+
+        while (cq_.Next(&got_tag, &ok)) {
+            AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
+            if (!ok) {
+                std::cerr << "Async RPC failed" << std::endl;
+                break;
+            }
+
+            if (call->status.ok()) {
+                std::cout << "Device Client received: " << call->reply.respresult() << std::endl;
+            } else {
+                std::cout << "RPC failed" << std::endl;
+            }
+
+            if (++gots >= m_nNeedResult) break;
+        }
+    }
+
+public:
+    GrpcDeviceClientImpl(std::shared_ptr<Channel> channel) : stub_(Device::V3::Device::NewStub(channel)) {
+        channel_ = channel;
+    }
+
+    ~GrpcDeviceClientImpl() override {
+        if (pthread_) delete pthread_;
+        EndAync();
+    }
+
+    void SetTarget(const char* pszTarget) { m_strDeviceTarget = pszTarget; }
+
+    // 实现纯虚函数(原始逻辑)
+    int OpenDevice(string devUri, string group) override {
+        Device::V3::OpenRequest request;
+        request.set_deviceuri(devUri);
+        request.set_devicegroup(group);
+        m_strDestDeviceUri = devUri;
+        m_strDeviceResource = "";
+
+        Device::V3::OpenReply reply;
+        ClientContext context;
+        Status status = stub_->Open(&context, request, &reply);
+
+        if (status.ok()) {
+            cout << "Open " << devUri << " Result:" << reply.message() << endl;
+            int retcode = atoi(reply.retcode().c_str());
+            if (2 == retcode) {
+                m_strDeviceResource = reply.retcontext();
+            }
+            return retcode;
+        } else {
+            std::cout << status.error_code() << ": " << status.error_message() << std::endl;
+            return -status.error_code();
+        }
+    }
+
+    int CloseDevice() override { return 2; }
+
+    string GetDeviceTarget() override { return m_strDeviceTarget; }
+    int GetClientStatus() override { return channel_->GetState(true); }
+    string GetOpendDeviceResource() override { return m_strDeviceResource; }
+
+    // 同步接口实现(原始逻辑)
+    int Get(string devResource, string& devRes, string& calResMsg,
+            string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest getq;
+        getq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        getq.set_reqname(devResource);
+        getq.set_reqtransaction(calSection);
+        getq.set_reqclientid(calClientID);
+
+        ClientContext context2;
+        Device::V3::DoResponse getr;
+        Status status = stub_->Get(&context2, getq, &getr);
+
+        if (status.ok()) {
+            if (getr.retcode() == "2") {
+                cout << "Get " << devResource << " Result " << getr.retcontext() << endl;
+                devRes = getr.retcontext();
+                calResMsg = getr.respresult();
+            } else {
+                cout << "Get " << devResource << " failed: " << getr.retcode() << endl;
+            }
+            return atoi(getr.retcode().c_str());
+        }
+        cout << "get failed " << devResource << endl;
+        cout << "error :" << status.error_message() << " with detail " << status.error_details() << endl;
+        return -status.error_code();
+    }
+
+    int Set(string devResource, string reqParams, string& devRes, string& calResMsg,
+            string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        ClientContext context2;
+        Device::V3::DoResponse setr;
+        Status status = stub_->Set(&context2, setq, &setr);
+
+        if (status.ok()) {
+            if (setr.retcode() == "2") {
+                cout << "Set " << devResource << " Result" << setr.retcontext() << endl;
+                devRes = setr.retcontext();
+                calResMsg = setr.respresult();
+            } else {
+                cout << "Set " << devResource << " failed" << setr.retcode() << endl;
+            }
+            return atoi(setr.retcode().c_str());
+        }
+        return -100;
+    }
+
+    int Update(string devResource, string reqParams, string& devRes, string& calResMsg,
+               string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        ClientContext context2;
+        Device::V3::DoResponse setr;
+        Status status = stub_->Update(&context2, setq, &setr);
+
+        if (status.ok()) {
+            if (setr.retcode() == "2") {
+                cout << "Update " << devResource << " Result" << setr.retcontext() << endl;
+                devRes = setr.retcontext();
+                calResMsg = setr.respresult();
+            } else {
+                cout << "Update " << devResource << " failed" << setr.retcode() << endl;
+            }
+            return atoi(setr.retcode().c_str());
+        }
+        return -100;
+    }
+
+    int Add(string devResource, string reqParams, string& devRes, string& calResMsg,
+            string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        ClientContext context2;
+        Device::V3::DoResponse setr;
+        Status status = stub_->Add(&context2, setq, &setr);
+
+        if (status.ok()) {
+            if (setr.retcode() == "2") {
+                cout << "Add " << devResource << " Result" << setr.retcontext() << endl;
+                devRes = setr.retcontext();
+                calResMsg = setr.respresult();
+            } else {
+                cout << "Add " << devResource << " failed" << setr.retcode() << endl;
+            }
+            return atoi(setr.retcode().c_str());
+        }
+        return -100;
+    }
+
+    int Del(string devResource, string reqParams, string& devRes, string& calResMsg,
+            string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        ClientContext context2;
+        Device::V3::DoResponse setr;
+        Status status = stub_->Del(&context2, setq, &setr);
+
+        if (status.ok()) {
+            if (setr.retcode() == "2") {
+                cout << "Del " << devResource << " Result" << setr.retcontext() << endl;
+                devRes = setr.retcontext();
+                calResMsg = setr.respresult();
+            } else {
+                cout << "Del " << devResource << " failed" << setr.retcode() << endl;
+            }
+            return atoi(setr.retcode().c_str());
+        }
+        return -100;
+    }
+
+    int Action(string devResource, string reqParams, string& devRes, string& calResMsg,
+               string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        ClientContext context2;
+        Device::V3::DoResponse setr;
+        Status status = stub_->Action(&context2, setq, &setr);
+
+        if (status.ok()) {
+            if (setr.retcode() == "2") {
+                cout << "Action " << devResource << " Result: " << setr.retcontext() << endl;
+                devRes = setr.retcontext();
+                calResMsg = setr.respresult();
+            } else {
+                cout << "Action " << devResource << " failed: " << setr.retcode() << endl;
+            }
+            return atoi(setr.retcode().c_str());
+        }
+        cout << "action failed " << devResource << endl;
+        cout << "error :" << status.error_message() << " with detail " << status.error_details() << endl;
+        return -status.error_code();
+    }
+
+    int Message(string devResource, string reqParams, string& devRes, string& calResMsg,
+                string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        ClientContext context2;
+        Device::V3::DoResponse setr;
+        Status status = stub_->Message(&context2, setq, &setr);
+
+        if (status.ok()) {
+            if (setr.retcode() == "2") {
+                cout << "Message " << devResource << " Result" << setr.retcontext() << endl;
+                devRes = setr.retcontext();
+                calResMsg = setr.respresult();
+            } else {
+                cout << "Message " << devResource << " failed" << setr.retcode() << endl;
+            }
+            return atoi(setr.retcode().c_str());
+        }
+        return -100;
+    }
+
+    // 异步接口实现(原始逻辑)
+    int AsyncAction(string devResource, string reqParams, string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        AsyncClientCall* call = new AsyncClientCall;
+        call->response_reader = stub_->PrepareAsyncAction(&call->context, setq, &cq_);
+        call->response_reader->StartCall();
+        call->response_reader->Finish(&call->reply, &call->status, (void*)call);
+
+        m_reqList.push_back(call);
+        m_nNeedResult = m_reqList.size();
+        return m_nNeedResult;
+    }
+
+    int AsyncMessage(string devResource, string reqParams, string devUri, string calSection, string calClientID) override {
+        Device::V3::DoRequest setq;
+        setq.set_deviceuri(devUri.empty() ? m_strDestDeviceUri : devUri);
+        setq.set_reqname(devResource);
+        setq.set_reqparam(reqParams);
+        setq.set_reqtransaction(calSection);
+        setq.set_reqclientid(calClientID);
+
+        AsyncClientCall* call = new AsyncClientCall;
+        call->response_reader = stub_->PrepareAsyncMessage(&call->context, setq, &cq_);
+        call->response_reader->StartCall();
+        call->response_reader->Finish(&call->reply, &call->status, (void*)call);
+
+        m_reqList.push_back(call);
+        m_nNeedResult = m_reqList.size();
+        return m_nNeedResult;
+    }
+
+    int BeginAyncWait() override {
+        if (!m_reqList.empty()) {
+            for (auto var : m_reqList) delete var;
+            m_reqList.clear();
+        }
+        pthread_ = new std::thread(&GrpcDeviceClientImpl::AsyncCompleteRpc, this);
+        return 2;
+    }
+
+    void WaitAllComplete() override {
+        if (pthread_) {
+            pthread_->join();
+            delete pthread_;
+            pthread_ = nullptr;
+        }
+    }
+
+    int GetAsyncResult(int idx, string& devResource, string& devRes, string& calResMsg) override {
+        if (idx < m_reqList.size()) {
+            devResource = m_reqList[idx]->reply.reqname();
+            if (m_reqList[idx]->status.ok()) {
+                if (m_reqList[idx]->reply.retcode() == "2") {
+                    cout << "Action " << devResource << " Result: " << m_reqList[idx]->reply.retcontext() << endl;
+                    devRes = m_reqList[idx]->reply.retcontext();
+                    calResMsg = m_reqList[idx]->reply.respresult();
+                } else {
+                    cout << "Action " << devResource << " failed: " << m_reqList[idx]->reply.retcode() << endl;
+                }
+                return atoi(m_reqList[idx]->reply.retcode().c_str());
+            }
+            cout << "action failed " << devResource << endl;
+            cout << "error :" << m_reqList[idx]->status.error_message() << " with detail " << m_reqList[idx]->status.error_details() << endl;
+            return -m_reqList[idx]->status.error_code();
+        }
+        return 0;
+    }
+
+    void EndAync() override {
+        for (auto var : m_reqList) delete var;
+        m_reqList.clear();
+        m_nNeedResult = 0;
+    }
+};
+
+// 工厂函数实现:创建/释放客户端
+GRPC_DEVICE_API GrpcDeviceClient* CreateClient(const char* pszDeviceServerTarget) {
+    std::string target_str = pszDeviceServerTarget;
+    cout << "try connect " << target_str << endl;
+
+    grpc::SslCredentialsOptions ssl_options;
+    ssl_options.pem_root_certs = LoadStringFromFile("root.crt");  // 注意:证书路径可能需要调整
+    auto channel = grpc::CreateChannel(target_str, grpc::SslCredentials(ssl_options));
+
+    GrpcDeviceClientImpl* pClient = new GrpcDeviceClientImpl(channel);
+    cout << "Connect " << target_str << " status: " << pClient->GetClientStatus() << endl;
+    pClient->SetTarget(pszDeviceServerTarget);
+
+    return pClient;
+}
+
+GRPC_DEVICE_API void FreeClient(GrpcDeviceClient* pClient) {
+    if (pClient != nullptr) delete pClient;
+}

+ 79 - 0
devGrpcClient/src/devGrpcClient.h

@@ -0,0 +1,79 @@
+
+
+#ifndef DEVGRPCCLIENT_H
+#define DEVGRPCCLIENT_H
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+// 工具函数:从文件加载字符串
+std::string LoadStringFromFile(std::string path);
+
+// 导出宏定义
+#define GRPC_DEVICE_EXPORTS
+#ifdef _WIN32
+#define GRPC_DEVICE_API __declspec(dllexport)
+#else
+#define GRPC_DEVICE_API __attribute__((visibility("default")))
+#endif
+
+// gRPC设备客户端接口类
+class GrpcDeviceClient {
+
+  public:
+    GrpcDeviceClient() {}
+    virtual ~GrpcDeviceClient() {}
+
+    // 设备操作接口
+    virtual int OpenDevice(std::string devUri, std::string group) = 0;
+    virtual int CloseDevice() = 0;
+
+    virtual std::string GetDeviceTarget() = 0;
+    virtual int GetClientStatus() = 0;
+    virtual std::string GetOpendDeviceResource() = 0;
+
+    // 同步接口
+    virtual int Get(std::string devResource, std::string& devRes, std::string &calResMsg, std::string devUri = "",
+                    std::string calSection = "", std::string calClientID = "") = 0;
+    virtual int Set(std::string devResource, std::string reqParams, std::string& devRes, std::string& calResMsg,
+                    std::string devUri = "", std::string calSection = "",
+                    std::string calClientID = "") = 0;
+    virtual int Update(std::string devResource, std::string reqParams, std::string& devRes, std::string& calResMsg,
+                    std::string devUri = "", std::string calSection = "",
+                    std::string calClientID = "") = 0;
+    virtual int Add(std::string devResource, std::string reqParams, std::string& devRes, std::string& calResMsg,
+                    std::string devUri = "", std::string calSection = "",
+                    std::string calClientID = "") = 0;
+    virtual int Del(std::string devResource, std::string reqParams, std::string& devRes, std::string& calResMsg,
+                    std::string devUri = "", std::string calSection = "",
+                    std::string calClientID = "") = 0;
+    virtual int Action(std::string devResource, std::string reqParams, std::string& devRes, std::string& calResMsg,
+                    std::string devUri = "", std::string calSection = "",
+                    std::string calClientID = "") = 0;
+    virtual int Message(std::string devResource, std::string reqParams, std::string& devRes, std::string& calResMsg,
+                    std::string devUri = "", std::string calSection = "",
+                    std::string calClientID = "") = 0;
+
+    // 异步接口
+    virtual int BeginAyncWait() = 0;
+    virtual void WaitAllComplete() = 0;
+    virtual int GetAsyncResult(int idx, std::string& devResource, std::string& devRes, std::string& calResMsg) = 0;
+    virtual void EndAync() = 0;
+    virtual int AsyncAction(std::string devResource, std::string reqParams,
+                            std::string devUri = "", std::string calSection = "",
+                            std::string calClientID = "") = 0;
+    virtual int AsyncMessage(std::string devResource, std::string reqParams,
+                            std::string devUri = "",  std::string calSection = "",
+                            std::string calClientID = "") = 0;
+};
+
+// 工厂函数:创建客户端实例
+GRPC_DEVICE_API GrpcDeviceClient* CreateClient(const char* pszDeviceServerTarget);
+
+// 工厂函数:释放客户端实例
+GRPC_DEVICE_API void FreeClient(GrpcDeviceClient* pClient);
+
+#endif // DEVGRPCCLIENT_H