Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "tsd_hdc_client.h"
12 : #include <thread>
13 : #include "driver/ascend_hal.h"
14 : #include "driver/ascend_hal_define.h"
15 : #include "mmpa/mmpa_api.h"
16 : #include "tsd_util_func.h"
17 : #include "tsd_message_parse_client.h"
18 : #include "tsd_log.h"
19 : #include "tsd_version_verify.h"
20 : #include "tsd/status.h"
21 :
22 : namespace {
23 : // 保留的flag标记位,当前不适用,填0
24 : constexpr uint32_t HDC_RESERVE_VALUE(0U);
25 :
26 : // client默认的最大session个数
27 : constexpr uint32_t HDC_CLIENT_DEFAULT_MAX_SESSION_NUM(96U);
28 :
29 : // 驱动支持查询socket链路状态的最小版本(不包含该版本)
30 : constexpr int32_t HDC_SOCKET_STATUS_GET_VERSION(0x05090E);
31 : constexpr uint32_t HDC_CLIENT_RETRY_MAX_NUM = 10U; // 最多尝试连接次数
32 : constexpr uint32_t HDC_CLIENT_RETRY_WAIT_TIMEOUT = 1000U; // 1s
33 : constexpr uint32_t FPGA_HDC_CLIENT_WAIT_TIMEOUT_MS = 3000000U; // 3000s
34 : constexpr uint32_t WAITFOR_INTERVAL = 30000U; // 单位毫秒
35 : constexpr uint32_t FPGA_WAITFOR_INTERVAL = 300000U; // 单位毫秒
36 : } // namespace
37 :
38 : namespace tsd {
39 : /**
40 : * @ingroup HdcClient
41 : * @brief HdcClient构造函数
42 : */
43 88 : HdcClient::HdcClient(const uint32_t devId)
44 88 : : DeviceComm(devId, DeviceCommType::HDC), hdcClient_(nullptr), isClientClose_(true), hostPid_(0U), hdcCommon_()
45 : {
46 88 : sessionIdNumVec_.reserve(static_cast<size_t>(HDC_CLIENT_DEFAULT_MAX_SESSION_NUM));
47 8536 : for (uint32_t i = HDC_CLIENT_DEFAULT_MAX_SESSION_NUM; i >= 1U; i--) {
48 8448 : sessionIdNumVec_.push_back(i);
49 : }
50 88 : }
51 :
52 : /**
53 : * @ingroup HdcClient
54 : * @brief 初始化函数,建立hdcclient
55 : * @return TSD_OK : 成功,other:TDT错误码
56 : */
57 69 : TSD_StatusT HdcClient::InitPre()
58 : {
59 69 : if (isClientClose_) {
60 67 : uint32_t tryNum = 0U;
61 67 : const drvHdcServiceType drvType = HDC_SERVICE_TYPE_TSD;
62 78 : while ((drvHdcClientCreate(
63 : &hdcClient_, static_cast<int32_t>(HDC_CLIENT_DEFAULT_MAX_SESSION_NUM), drvType,
64 78 : static_cast<int32_t>(HDC_RESERVE_VALUE))) != DRV_ERROR_NONE) {
65 12 : if (tryNum >= HDC_CLIENT_RETRY_MAX_NUM) {
66 1 : TSD_ERROR("deviceId=%u,drvtype=%u,hdcclient failed", deviceId_, drvType);
67 1 : return TSD_HDC_CLIENT_INIT_ERROR;
68 : }
69 11 : ++tryNum;
70 11 : (void)mmSleep(HDC_CLIENT_RETRY_WAIT_TIMEOUT);
71 : }
72 66 : isClientClose_ = false;
73 : }
74 68 : return TSD_OK;
75 : }
76 :
77 : /**
78 : * @ingroup HdcClient
79 : * @brief 初始化函数,建立hdcclient
80 : * @return TSD_OK : 成功,other:TDT错误码
81 : */
82 37 : TSD_StatusT HdcClient::CommInit(const uint32_t clientPid, const bool isAdcEnv)
83 : {
84 37 : hostPid_ = clientPid;
85 37 : TSD_StatusT tdtRet = InitPre();
86 37 : TSD_CHECK(tdtRet == TSD_OK, tdtRet, "hdc client init pre failed");
87 37 : tdtRet = hdcCommon_.InitMsgSize();
88 37 : if (tdtRet != TSD_OK) {
89 1 : TSD_ERROR("initMsgSize() fail");
90 1 : return TSD_HDC_CLIENT_INIT_ERROR;
91 : }
92 36 : hdcCommon_.SetAdcEnv(isAdcEnv);
93 36 : return tdtRet;
94 : }
95 :
96 : /**
97 : * @ingroup HdcClient
98 : * @brief 普通数据接收线程
99 : * @param [in] sessionId :某个连接sessionId
100 : */
101 117 : TSD_StatusT HdcClient::CommRecvData(const uint32_t sessionId, const bool ignoreRecvErr, const uint32_t timeout)
102 : {
103 117 : HDCMessage hdcMsg;
104 117 : TSD_StatusT recvResult = TSD_OK;
105 117 : if (IsFpgaEnv()) {
106 0 : recvResult = RecvMsg(sessionId, hdcMsg, FPGA_HDC_CLIENT_WAIT_TIMEOUT_MS);
107 : } else {
108 117 : uint32_t normalTimeout = HDC_CLIENT_WAIT_TIMEOUT_MS + OPEN_PKT_DEL_WAIT_TIMEOUT_MS;
109 117 : if (timeout != 0U) {
110 44 : normalTimeout = timeout;
111 : }
112 :
113 117 : TSD_INFO("recv timeout is:%u ms", normalTimeout);
114 117 : recvResult = RecvMsg(sessionId, hdcMsg, normalTimeout);
115 : }
116 117 : if (recvResult != TSD_OK) {
117 26 : if (ignoreRecvErr) {
118 10 : TSD_RUN_INFO("recv msg result:%u is not TSD_OK", recvResult);
119 : } else {
120 16 : TSD_CHECK_NO_RETURN_RUNINFO_LOG(
121 : recvResult != TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "recv no msg by socket closed");
122 16 : TSD_CHECK_NO_RETURN(
123 : recvResult == TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "[deviceId=%u][sessionId=%u] recv msg failed",
124 : deviceId_, sessionId);
125 : }
126 26 : return recvResult;
127 : }
128 :
129 91 : hdcMsg.set_device_id(deviceId_); // 回传时填写的DEVICEID用创建时的补充
130 91 : MessageParseClient::GetInstance()->ProcessMessage(sessionId, hdcMsg);
131 91 : TSD_INFO("[deviceId=%u] the Tsd recv data already", deviceId_);
132 91 : return TSD_OK;
133 117 : }
134 :
135 : /**
136 : * @ingroup HdcClient
137 : * @brief 创建连接
138 : * @return TSD_OK:成功 或者其他错误码
139 : */
140 62 : TSD_StatusT HdcClient::CommCreateSession(uint32_t& sessionId)
141 : {
142 62 : TSD_INFO("HdcClient::CommCreateSession Start");
143 62 : if (isClientClose_) {
144 1 : TSD_ERROR("hdc client has been closed");
145 1 : return TSD_HDC_CLIENT_CLOSED;
146 : }
147 61 : if (sessionIdNumVec_.empty()) {
148 1 : TSD_ERROR("the connect session is greater than %u", HDC_CLIENT_DEFAULT_MAX_SESSION_NUM);
149 1 : return TSD_HDCSESSIONID_NOT_AVAILABLE;
150 : }
151 60 : HDC_SESSION session = nullptr;
152 : hdcError_t retVal;
153 : {
154 60 : const std::lock_guard<std::mutex> lk(mutextForHdcFreeMemoryMap_);
155 60 : retVal = drvHdcSessionConnect(0, static_cast<int32_t>(deviceId_), hdcClient_, &session);
156 60 : }
157 60 : if (retVal != DRV_ERROR_NONE) {
158 3 : TSD_ERROR("deviceId: %u drvHdcSessionConnect failed, ret = %d", deviceId_, retVal);
159 3 : if ((retVal == DRV_ERROR_REPEATED_INIT) || (retVal == DRV_ERROR_REMOTE_NOT_LISTEN)) {
160 2 : return retVal;
161 : }
162 1 : return TSD_HDC_CREATE_SESSION_FAILED;
163 : }
164 :
165 57 : TSD_INFO("[HdcClient] deviceId: %u connect session", deviceId_);
166 :
167 57 : const hdcError_t ret = drvHdcSetSessionReference(session);
168 57 : if (ret != DRV_ERROR_NONE) {
169 2 : TSD_ERROR(
170 : "deviceId: %u drvHdcSetSessionReference failed, "
171 : "need to close session, ret = %d",
172 : deviceId_, ret);
173 2 : if (drvHdcSessionClose(session) != DRV_ERROR_NONE) {
174 1 : TSD_ERROR("HdcClient::Destroy the session failed");
175 : }
176 2 : return TSD_SET_HDCSESSION_REFERENCE_FAILED;
177 : }
178 55 : TSD_INFO("[HdcClient] drvHdcSetSessionReference success");
179 :
180 : {
181 : // sessionIdNumVec_和hdcClientSessionMap_共用一把锁
182 55 : const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
183 55 : sessionId = sessionIdNumVec_.back();
184 55 : sessionIdNumVec_.pop_back();
185 55 : hdcClientSessionMap_[sessionId] = session;
186 55 : hdcClientVerifyMap_[sessionId] = hdcCommon_.MakeVersionVerifyNoThrow();
187 55 : }
188 55 : TSD_INFO(
189 : "[HdcClient] deviceId: %u connect session and drvHdcSetSessionReference success, sessionId=%u", deviceId_,
190 : sessionId);
191 55 : if (CheckHdcConnection(sessionId) != TSD_OK) {
192 19 : return TSD_HDC_RECV_MSG_ERROR;
193 : }
194 36 : return TSD_OK;
195 : }
196 :
197 : /**
198 : * @ingroup HdcClient
199 : * @brief 与device端进行连接握手测试,确认HDC通道可用
200 : * @param [in] sessionId : 待校验的会话ID
201 : * @return TSD_OK:成功 或者其他错误码
202 : */
203 55 : TSD_StatusT HdcClient::CheckHdcConnection(const uint32_t& sessionId)
204 : {
205 55 : HDCMessage hdcMsg;
206 55 : ProcessSignPid* const proSignPid = hdcMsg.mutable_proc_sign_pid();
207 55 : if (proSignPid == nullptr) {
208 0 : return TSD_INTERNAL_ERROR;
209 : }
210 55 : proSignPid->set_proc_pid(hostPid_);
211 55 : hdcMsg.set_type(HDCMessage::TEST_HDC_SEND);
212 55 : std::shared_ptr<VersionVerify> inspector = nullptr;
213 55 : (void)CommGetVersionVerify(sessionId, inspector);
214 55 : TSD_CHECK_NULLPTR(inspector, TSD_HDC_RECV_MSG_ERROR, "no VersionVerify available");
215 55 : inspector->SetVersionInfo(hdcMsg);
216 55 : const TSD_StatusT ret = CommSendMsg(sessionId, hdcMsg);
217 55 : if (ret != TSD_OK) {
218 0 : TSD_ERROR("CommSendMsg Failed, SendPidMsg sessionId=%u", sessionId);
219 0 : return ret;
220 : }
221 55 : TSD_StatusT recvResult = TSD_OK;
222 55 : if (IsFpgaEnv()) {
223 0 : recvResult = RecvMsg(sessionId, hdcMsg, FPGA_WAITFOR_INTERVAL);
224 : } else {
225 55 : recvResult = RecvMsg(sessionId, hdcMsg, WAITFOR_INTERVAL);
226 : }
227 :
228 55 : if (recvResult != TSD_OK) {
229 18 : TSD_CHECK_NO_RETURN_RUNINFO_LOG(
230 : recvResult != TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "recv no msg by socket closed");
231 18 : TSD_CHECK_NO_RETURN(
232 : recvResult == TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "[deviceId=%u][sessionId=%u] recv msg failed", deviceId_,
233 : sessionId);
234 18 : return recvResult;
235 : }
236 37 : if (hdcMsg.type() != HDCMessage::TEST_HDC_RSP) {
237 1 : TSD_INFO("Hdc service creation was not successful");
238 1 : return TSD_HDC_RECV_MSG_ERROR;
239 : }
240 36 : TSD_CHECK(
241 : inspector->PeerVersionCheck(hdcMsg.version_info()), TSD_HDC_RECV_MSG_ERROR,
242 : "client and server version is inconsistent, you need to update your software");
243 36 : TSD_RUN_INFO("Service create hdc successfully.");
244 36 : return TSD_OK;
245 55 : }
246 :
247 : /**
248 : * @ingroup HdcClient
249 : * @brief 根据sessionId获取 hdcsession
250 : * @param [in] sessionId : 某个连接sessionId
251 : * @param [out] session : session 会话
252 : * @return TSD_OK:成功 或者其他错误码
253 : */
254 344 : TSD_StatusT HdcClient::GetHdcSession(const uint32_t sessionId, HDC_SESSION& session)
255 : {
256 344 : const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
257 344 : uint32_t localSessionId = sessionId;
258 344 : if ((!hdcClientSessionMap_.empty()) && (localSessionId == 0U)) {
259 34 : localSessionId = hdcClientSessionMap_.begin()->first;
260 : }
261 344 : const auto iter = hdcClientSessionMap_.find(localSessionId);
262 344 : if (iter == hdcClientSessionMap_.end()) {
263 6 : TSD_RUN_INFO("[TsdEVENT] HdcClient::GetHdcSession(): the %d session does not exist", localSessionId);
264 6 : return TSD_HDC_SESSION_DO_NOT_EXIST;
265 : }
266 338 : session = hdcClientSessionMap_[localSessionId];
267 338 : return TSD_OK;
268 344 : }
269 :
270 : /**
271 : * @ingroup HdcClient
272 : * @brief 获取指定sessionId对应的版本校验对象
273 : * @param [in] sessionId : 会话ID
274 : * @param [out] inspector : 版本校验对象的智能指针
275 : * @return TSD_OK:成功 或者其他错误码
276 : */
277 231 : TSD_StatusT HdcClient::CommGetVersionVerify(const uint32_t sessionId, std::shared_ptr<VersionVerify>& inspector)
278 : {
279 231 : const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
280 231 : uint32_t localSessionId = sessionId;
281 231 : if ((!hdcClientSessionMap_.empty()) && (localSessionId == 0U)) {
282 22 : localSessionId = hdcClientSessionMap_.begin()->first;
283 : }
284 :
285 231 : const auto iter = hdcClientVerifyMap_.find(localSessionId);
286 231 : if (iter == hdcClientVerifyMap_.end()) {
287 3 : TSD_RUN_INFO("HdcClient::CommGetVersionVerify(): the %u VersionVerify does not exist", localSessionId);
288 3 : return TSD_HDC_SESSION_DO_NOT_EXIST;
289 : }
290 228 : inspector = iter->second;
291 228 : return TSD_OK;
292 231 : }
293 :
294 : /**
295 : * @ingroup HdcClient
296 : * @brief 获取当前HDC连接状态。当driver支持时,会刷新所有sessionMap,关闭已断开的session。
297 : * @param [out] hdcSessStat : 输出当前session状态(HDC_SESSION_STATUS_CONNECT/CLOSE)
298 : * @return TSD_OK:成功 或者其他错误码
299 : */
300 5 : TSD_StatusT HdcClient::CommGetConctStatus(int32_t& hdcSessStat)
301 : {
302 5 : hdcSessStat = HDC_SESSION_STATUS_CONNECT;
303 : int32_t halVersion;
304 5 : const drvError_t ret = halGetAPIVersion(&halVersion);
305 5 : if (ret != DRV_ERROR_NONE) {
306 1 : TSD_ERROR("Get driver api version failed, ret[%d].", static_cast<int32_t>(ret));
307 1 : return TSD_HDC_SESSION_STATUS_GET_FAILED;
308 : }
309 4 : if (halVersion > HDC_SOCKET_STATUS_GET_VERSION) {
310 4 : const std::lock_guard<std::recursive_mutex> lkSessionMap(mutextForClientSessionMap_);
311 7 : for (auto iter = hdcClientSessionMap_.cbegin(); iter != hdcClientSessionMap_.cend(); iter++) {
312 5 : const TSD_StatusT getStatusRet = hdcCommon_.GetHdcAttrStatus(iter->second, hdcSessStat);
313 5 : if (getStatusRet != TSD_OK) {
314 2 : return TSD_HDC_SESSION_STATUS_GET_FAILED;
315 : }
316 4 : if (hdcSessStat == HDC_SESSION_STATUS_CLOSE) {
317 1 : const uint32_t sessionId = iter->first;
318 1 : TSD_RUN_INFO("Hdc socket close, sessionId[%u].", sessionId);
319 1 : (void)hdcClientVerifyMap_.erase(sessionId);
320 1 : (void)drvHdcSessionClose(iter->second);
321 1 : sessionIdNumVec_.push_back(sessionId);
322 1 : (void)hdcClientSessionMap_.erase(iter);
323 1 : return TSD_OK;
324 : }
325 : }
326 4 : }
327 2 : return TSD_OK;
328 : }
329 :
330 : /**
331 : * @ingroup HdcClient
332 : * @brief 关闭所有会话
333 : */
334 38 : void HdcClient::ClearAllSession()
335 : {
336 38 : const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
337 38 : hdcClientVerifyMap_.clear();
338 78 : for (auto iter = hdcClientSessionMap_.begin(); iter != hdcClientSessionMap_.end(); iter++) {
339 40 : if (drvHdcSessionClose(iter->second) != DRV_ERROR_NONE) {
340 1 : TSD_ERROR("HdcClient::Destroy the %u session failed", iter->first);
341 : } else {
342 39 : sessionIdNumVec_.push_back(iter->first);
343 : }
344 : }
345 38 : hdcClientSessionMap_.clear();
346 38 : }
347 :
348 : /**
349 : * @ingroup HdcClient
350 : * @brief 从DeviceComm::deviceCommMap_里面删除当前实例指针
351 : */
352 38 : void HdcClient::ClearClientPtr()
353 : {
354 38 : TSD_INFO("begin HdcClient::ClearClientPtr");
355 38 : const uint64_t index = KeyCompose(deviceId_, DeviceCommType::HDC);
356 38 : std::recursive_mutex* deviceCommMutex = MutexForDeviceCommMap();
357 38 : std::map<uint64_t, std::shared_ptr<DeviceComm>>* deviceCommMap = DeviceCommMap();
358 38 : if ((deviceCommMutex == nullptr) || (deviceCommMap == nullptr)) {
359 0 : TSD_ERROR("deviceCommMap or mutex is nullptr");
360 1 : return;
361 : }
362 38 : const std::lock_guard<std::recursive_mutex> lk(*deviceCommMutex);
363 38 : const std::map<uint64_t, std::shared_ptr<DeviceComm>>::iterator iter = deviceCommMap->find(index);
364 38 : if (iter == deviceCommMap->end()) {
365 1 : TSD_ERROR("delete the %lu deviceCommPtr from deviceCommMap failed", index);
366 1 : return;
367 : }
368 37 : (void)deviceCommMap->erase(iter);
369 37 : TSD_INFO("end HdcClient::ClearClientPtr");
370 38 : }
371 :
372 : /**
373 : * @ingroup HdcClient
374 : * @brief 销毁HDC CLIENT
375 : */
376 37 : void HdcClient::DestroyClient()
377 : {
378 37 : TSD_INFO("begin drvHdcClientDestroy");
379 37 : const hdcError_t retVal = drvHdcClientDestroy(hdcClient_);
380 37 : if (retVal != DRV_ERROR_NONE) {
381 1 : TSD_ERROR("drvHdcClientDestroy() return %d", retVal);
382 : }
383 37 : TSD_INFO("end drvHdcClientDestroy");
384 37 : isClientClose_ = true;
385 37 : }
386 :
387 : /**
388 : * @ingroup HdcClient
389 : * @brief 关闭HDC连接,消耗相关资源
390 : * @param 无
391 : * @return TSD_OK:成功 或者其他错误码
392 : */
393 49 : void HdcClient::CommDestroy()
394 : {
395 49 : TSD_INFO("enter HdcClient::CommDestroy() function");
396 49 : if (!isClientClose_) {
397 36 : const std::lock_guard<std::mutex> lk(mutextForHdcFreeMemoryMap_);
398 36 : ClearAllSession();
399 36 : DestroyClient();
400 36 : ClearClientPtr();
401 36 : isClientClose_ = true;
402 36 : TSD_INFO("end HdcClient::CommDestroy() function");
403 36 : }
404 49 : }
405 :
406 : /**
407 : * @ingroup HdcCommon
408 : * @brief 虚函数 GetDeviceId 获得设备ID
409 : * return 设备ID
410 : */
411 1 : uint32_t HdcClient::GetDeviceId() const { return deviceId_; }
412 :
413 : /**
414 : * @ingroup HdcClient
415 : * @brief 通过指定session向device发送一条HDC消息,发送前会进行特性兼容校验
416 : * @param [in] sessionId : 会话ID
417 : * @param [in] msg : 要发送的HDC消息
418 : * @return TSD_OK:成功 或者其他错误码
419 : */
420 168 : TSD_StatusT HdcClient::CommSendMsg(const uint32_t sessionId, const HDCMessage& msg)
421 : {
422 168 : HDC_SESSION session = nullptr;
423 168 : const TSD_StatusT ret = GetHdcSession(sessionId, session);
424 168 : if (ret != TSD_OK) {
425 4 : TSD_RUN_WARN("GetHdcSession was not successful, ret[%d]", ret);
426 4 : return TSD_HDC_SEND_MSG_ERROR;
427 : }
428 164 : std::shared_ptr<VersionVerify> inspector = nullptr;
429 164 : (void)CommGetVersionVerify(sessionId, inspector);
430 164 : TSD_CHECK_NULLPTR(inspector, TSD_HDC_RECV_MSG_ERROR, "VersionVerify does not exist.");
431 164 : TSD_CHECK(
432 : inspector->SpecialFeatureCheck(msg.type()), TSD_HDC_RECV_MSG_ERROR,
433 : "client and server feature_list is inconsistent, you need to update your software.");
434 163 : return hdcCommon_.SendNormalMsg(msg, session);
435 164 : }
436 :
437 : /**
438 : * @ingroup HdcClient
439 : * @brief 通过指定session从device接收一条HDC消息(带超时)
440 : * @param [in] sessionId : 会话ID
441 : * @param [out] msg : 接收到的HDC消息
442 : * @param [in] timeout : 接收超时(毫秒)
443 : * @return TSD_OK:成功 或者其他错误码
444 : */
445 173 : TSD_StatusT HdcClient::RecvMsg(const uint32_t sessionId, HDCMessage& msg, const uint32_t timeout)
446 : {
447 173 : HDC_SESSION session = nullptr;
448 173 : const TSD_StatusT ret = GetHdcSession(sessionId, session);
449 173 : if (ret != TSD_OK) {
450 1 : TSD_RUN_WARN("[TsdEVENT] GetHdcSession was not successful, ret[%d]", ret);
451 1 : return TSD_HDC_RECV_MSG_ERROR;
452 : }
453 :
454 172 : return hdcCommon_.RecvMsg(session, msg, timeout);
455 : }
456 : /**
457 : * @ingroup HdcClient
458 : * @brief 析构函数
459 : */
460 114 : HdcClient::~HdcClient() {}
461 :
462 : // 利用静态变量初始化在 main 之前执行的特性完成自注册
463 : // 新增子类只需在自己的 .cpp 中加这一行,无需修改任何其他文件
464 : static const bool g_hdcClientRegistered =
465 46 : DeviceComm::Register(DeviceCommType::HDC, [](uint32_t devId) -> std::shared_ptr<DeviceComm> {
466 46 : return std::shared_ptr<DeviceComm>(new (std::nothrow) HdcClient(devId));
467 : });
468 : } // namespace tsd
|