* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "tsd_hdc_client.h"
#include <thread>
#include "driver/ascend_hal.h"
#include "driver/ascend_hal_define.h"
#include "mmpa/mmpa_api.h"
#include "tsd_util_func.h"
#include "tsd_message_parse_client.h"
#include "tsd_log.h"
#include "tsd_version_verify.h"
#include "tsd/status.h"
namespace {
constexpr uint32_t HDC_RESERVE_VALUE(0U);
constexpr uint32_t HDC_CLIENT_DEFAULT_MAX_SESSION_NUM(96U);
constexpr int32_t HDC_SOCKET_STATUS_GET_VERSION(0x05090E);
constexpr uint32_t HDC_CLIENT_RETRY_MAX_NUM = 10U;
constexpr uint32_t HDC_CLIENT_RETRY_WAIT_TIMEOUT = 1000U;
constexpr uint32_t FPGA_HDC_CLIENT_WAIT_TIMEOUT_MS = 3000000U;
constexpr uint32_t WAITFOR_INTERVAL = 30000U;
constexpr uint32_t FPGA_WAITFOR_INTERVAL = 300000U;
}
namespace tsd {
* @ingroup HdcClient
* @brief HdcClient构造函数
*/
HdcClient::HdcClient(const uint32_t devId)
: DeviceComm(devId, DeviceCommType::HDC), hdcClient_(nullptr), isClientClose_(true), hostPid_(0U), hdcCommon_()
{
sessionIdNumVec_.reserve(static_cast<size_t>(HDC_CLIENT_DEFAULT_MAX_SESSION_NUM));
for (uint32_t i = HDC_CLIENT_DEFAULT_MAX_SESSION_NUM; i >= 1U; i--) {
sessionIdNumVec_.push_back(i);
}
}
* @ingroup HdcClient
* @brief 初始化函数,建立hdcclient
* @return TSD_OK : 成功,other:TDT错误码
*/
TSD_StatusT HdcClient::InitPre()
{
if (isClientClose_) {
uint32_t tryNum = 0U;
const drvHdcServiceType drvType = HDC_SERVICE_TYPE_TSD;
while ((drvHdcClientCreate(
&hdcClient_, static_cast<int32_t>(HDC_CLIENT_DEFAULT_MAX_SESSION_NUM), drvType,
static_cast<int32_t>(HDC_RESERVE_VALUE))) != DRV_ERROR_NONE) {
if (tryNum >= HDC_CLIENT_RETRY_MAX_NUM) {
TSD_ERROR("deviceId=%u,drvtype=%u,hdcclient failed", deviceId_, drvType);
return TSD_HDC_CLIENT_INIT_ERROR;
}
++tryNum;
(void)mmSleep(HDC_CLIENT_RETRY_WAIT_TIMEOUT);
}
isClientClose_ = false;
}
return TSD_OK;
}
* @ingroup HdcClient
* @brief 初始化函数,建立hdcclient
* @return TSD_OK : 成功,other:TDT错误码
*/
TSD_StatusT HdcClient::CommInit(const uint32_t clientPid, const bool isAdcEnv)
{
hostPid_ = clientPid;
TSD_StatusT tdtRet = InitPre();
TSD_CHECK(tdtRet == TSD_OK, tdtRet, "hdc client init pre failed");
tdtRet = hdcCommon_.InitMsgSize();
if (tdtRet != TSD_OK) {
TSD_ERROR("initMsgSize() fail");
return TSD_HDC_CLIENT_INIT_ERROR;
}
hdcCommon_.SetAdcEnv(isAdcEnv);
return tdtRet;
}
* @ingroup HdcClient
* @brief 普通数据接收线程
* @param [in] sessionId :某个连接sessionId
*/
TSD_StatusT HdcClient::CommRecvData(const uint32_t sessionId, const bool ignoreRecvErr, const uint32_t timeout)
{
HDCMessage hdcMsg;
TSD_StatusT recvResult = TSD_OK;
if (IsFpgaEnv()) {
recvResult = RecvMsg(sessionId, hdcMsg, FPGA_HDC_CLIENT_WAIT_TIMEOUT_MS);
} else {
uint32_t normalTimeout = HDC_CLIENT_WAIT_TIMEOUT_MS + OPEN_PKT_DEL_WAIT_TIMEOUT_MS;
if (timeout != 0U) {
normalTimeout = timeout;
}
TSD_INFO("recv timeout is:%u ms", normalTimeout);
recvResult = RecvMsg(sessionId, hdcMsg, normalTimeout);
}
if (recvResult != TSD_OK) {
if (ignoreRecvErr) {
TSD_RUN_INFO("recv msg result:%u is not TSD_OK", recvResult);
} else {
TSD_CHECK_NO_RETURN_RUNINFO_LOG(
recvResult != TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "recv no msg by socket closed");
TSD_CHECK_NO_RETURN(
recvResult == TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "[deviceId=%u][sessionId=%u] recv msg failed",
deviceId_, sessionId);
}
return recvResult;
}
hdcMsg.set_device_id(deviceId_);
MessageParseClient::GetInstance()->ProcessMessage(sessionId, hdcMsg);
TSD_INFO("[deviceId=%u] the Tsd recv data already", deviceId_);
return TSD_OK;
}
* @ingroup HdcClient
* @brief 创建连接
* @return TSD_OK:成功 或者其他错误码
*/
TSD_StatusT HdcClient::CommCreateSession(uint32_t& sessionId)
{
TSD_INFO("HdcClient::CommCreateSession Start");
if (isClientClose_) {
TSD_ERROR("hdc client has been closed");
return TSD_HDC_CLIENT_CLOSED;
}
if (sessionIdNumVec_.empty()) {
TSD_ERROR("the connect session is greater than %u", HDC_CLIENT_DEFAULT_MAX_SESSION_NUM);
return TSD_HDCSESSIONID_NOT_AVAILABLE;
}
HDC_SESSION session = nullptr;
hdcError_t retVal;
{
const std::lock_guard<std::mutex> lk(mutextForHdcFreeMemoryMap_);
retVal = drvHdcSessionConnect(0, static_cast<int32_t>(deviceId_), hdcClient_, &session);
}
if (retVal != DRV_ERROR_NONE) {
TSD_ERROR("deviceId: %u drvHdcSessionConnect failed, ret = %d", deviceId_, retVal);
if ((retVal == DRV_ERROR_REPEATED_INIT) || (retVal == DRV_ERROR_REMOTE_NOT_LISTEN)) {
return retVal;
}
return TSD_HDC_CREATE_SESSION_FAILED;
}
TSD_INFO("[HdcClient] deviceId: %u connect session", deviceId_);
const hdcError_t ret = drvHdcSetSessionReference(session);
if (ret != DRV_ERROR_NONE) {
TSD_ERROR(
"deviceId: %u drvHdcSetSessionReference failed, "
"need to close session, ret = %d",
deviceId_, ret);
if (drvHdcSessionClose(session) != DRV_ERROR_NONE) {
TSD_ERROR("HdcClient::Destroy the session failed");
}
return TSD_SET_HDCSESSION_REFERENCE_FAILED;
}
TSD_INFO("[HdcClient] drvHdcSetSessionReference success");
{
const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
sessionId = sessionIdNumVec_.back();
sessionIdNumVec_.pop_back();
hdcClientSessionMap_[sessionId] = session;
hdcClientVerifyMap_[sessionId] = hdcCommon_.MakeVersionVerifyNoThrow();
}
TSD_INFO(
"[HdcClient] deviceId: %u connect session and drvHdcSetSessionReference success, sessionId=%u", deviceId_,
sessionId);
if (CheckHdcConnection(sessionId) != TSD_OK) {
return TSD_HDC_RECV_MSG_ERROR;
}
return TSD_OK;
}
* @ingroup HdcClient
* @brief 与device端进行连接握手测试,确认HDC通道可用
* @param [in] sessionId : 待校验的会话ID
* @return TSD_OK:成功 或者其他错误码
*/
TSD_StatusT HdcClient::CheckHdcConnection(const uint32_t& sessionId)
{
HDCMessage hdcMsg;
ProcessSignPid* const proSignPid = hdcMsg.mutable_proc_sign_pid();
if (proSignPid == nullptr) {
return TSD_INTERNAL_ERROR;
}
proSignPid->set_proc_pid(hostPid_);
hdcMsg.set_type(HDCMessage::TEST_HDC_SEND);
std::shared_ptr<VersionVerify> inspector = nullptr;
(void)CommGetVersionVerify(sessionId, inspector);
TSD_CHECK_NULLPTR(inspector, TSD_HDC_RECV_MSG_ERROR, "no VersionVerify available");
inspector->SetVersionInfo(hdcMsg);
const TSD_StatusT ret = CommSendMsg(sessionId, hdcMsg);
if (ret != TSD_OK) {
TSD_ERROR("CommSendMsg Failed, SendPidMsg sessionId=%u", sessionId);
return ret;
}
TSD_StatusT recvResult = TSD_OK;
if (IsFpgaEnv()) {
recvResult = RecvMsg(sessionId, hdcMsg, FPGA_WAITFOR_INTERVAL);
} else {
recvResult = RecvMsg(sessionId, hdcMsg, WAITFOR_INTERVAL);
}
if (recvResult != TSD_OK) {
TSD_CHECK_NO_RETURN_RUNINFO_LOG(
recvResult != TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "recv no msg by socket closed");
TSD_CHECK_NO_RETURN(
recvResult == TSD_HDC_SERVER_CLIENT_SOCKET_CLOSED, "[deviceId=%u][sessionId=%u] recv msg failed", deviceId_,
sessionId);
return recvResult;
}
if (hdcMsg.type() != HDCMessage::TEST_HDC_RSP) {
TSD_INFO("Hdc service creation was not successful");
return TSD_HDC_RECV_MSG_ERROR;
}
TSD_CHECK(
inspector->PeerVersionCheck(hdcMsg.version_info()), TSD_HDC_RECV_MSG_ERROR,
"client and server version is inconsistent, you need to update your software");
TSD_RUN_INFO("Service create hdc successfully.");
return TSD_OK;
}
* @ingroup HdcClient
* @brief 根据sessionId获取 hdcsession
* @param [in] sessionId : 某个连接sessionId
* @param [out] session : session 会话
* @return TSD_OK:成功 或者其他错误码
*/
TSD_StatusT HdcClient::GetHdcSession(const uint32_t sessionId, HDC_SESSION& session)
{
const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
uint32_t localSessionId = sessionId;
if ((!hdcClientSessionMap_.empty()) && (localSessionId == 0U)) {
localSessionId = hdcClientSessionMap_.begin()->first;
}
const auto iter = hdcClientSessionMap_.find(localSessionId);
if (iter == hdcClientSessionMap_.end()) {
TSD_RUN_INFO("[TsdEVENT] HdcClient::GetHdcSession(): the %d session does not exist", localSessionId);
return TSD_HDC_SESSION_DO_NOT_EXIST;
}
session = hdcClientSessionMap_[localSessionId];
return TSD_OK;
}
* @ingroup HdcClient
* @brief 获取指定sessionId对应的版本校验对象
* @param [in] sessionId : 会话ID
* @param [out] inspector : 版本校验对象的智能指针
* @return TSD_OK:成功 或者其他错误码
*/
TSD_StatusT HdcClient::CommGetVersionVerify(const uint32_t sessionId, std::shared_ptr<VersionVerify>& inspector)
{
const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
uint32_t localSessionId = sessionId;
if ((!hdcClientSessionMap_.empty()) && (localSessionId == 0U)) {
localSessionId = hdcClientSessionMap_.begin()->first;
}
const auto iter = hdcClientVerifyMap_.find(localSessionId);
if (iter == hdcClientVerifyMap_.end()) {
TSD_RUN_INFO("HdcClient::CommGetVersionVerify(): the %u VersionVerify does not exist", localSessionId);
return TSD_HDC_SESSION_DO_NOT_EXIST;
}
inspector = iter->second;
return TSD_OK;
}
* @ingroup HdcClient
* @brief 获取当前HDC连接状态。当driver支持时,会刷新所有sessionMap,关闭已断开的session。
* @param [out] hdcSessStat : 输出当前session状态(HDC_SESSION_STATUS_CONNECT/CLOSE)
* @return TSD_OK:成功 或者其他错误码
*/
TSD_StatusT HdcClient::CommGetConctStatus(int32_t& hdcSessStat)
{
hdcSessStat = HDC_SESSION_STATUS_CONNECT;
int32_t halVersion;
const drvError_t ret = halGetAPIVersion(&halVersion);
if (ret != DRV_ERROR_NONE) {
TSD_ERROR("Get driver api version failed, ret[%d].", static_cast<int32_t>(ret));
return TSD_HDC_SESSION_STATUS_GET_FAILED;
}
if (halVersion > HDC_SOCKET_STATUS_GET_VERSION) {
const std::lock_guard<std::recursive_mutex> lkSessionMap(mutextForClientSessionMap_);
for (auto iter = hdcClientSessionMap_.cbegin(); iter != hdcClientSessionMap_.cend(); iter++) {
const TSD_StatusT getStatusRet = hdcCommon_.GetHdcAttrStatus(iter->second, hdcSessStat);
if (getStatusRet != TSD_OK) {
return TSD_HDC_SESSION_STATUS_GET_FAILED;
}
if (hdcSessStat == HDC_SESSION_STATUS_CLOSE) {
const uint32_t sessionId = iter->first;
TSD_RUN_INFO("Hdc socket close, sessionId[%u].", sessionId);
(void)hdcClientVerifyMap_.erase(sessionId);
(void)drvHdcSessionClose(iter->second);
sessionIdNumVec_.push_back(sessionId);
(void)hdcClientSessionMap_.erase(iter);
return TSD_OK;
}
}
}
return TSD_OK;
}
* @ingroup HdcClient
* @brief 关闭所有会话
*/
void HdcClient::ClearAllSession()
{
const std::lock_guard<std::recursive_mutex> lk(mutextForClientSessionMap_);
hdcClientVerifyMap_.clear();
for (auto iter = hdcClientSessionMap_.begin(); iter != hdcClientSessionMap_.end(); iter++) {
if (drvHdcSessionClose(iter->second) != DRV_ERROR_NONE) {
TSD_ERROR("HdcClient::Destroy the %u session failed", iter->first);
} else {
sessionIdNumVec_.push_back(iter->first);
}
}
hdcClientSessionMap_.clear();
}
* @ingroup HdcClient
* @brief 从DeviceComm::deviceCommMap_里面删除当前实例指针
*/
void HdcClient::ClearClientPtr()
{
TSD_INFO("begin HdcClient::ClearClientPtr");
const uint64_t index = KeyCompose(deviceId_, DeviceCommType::HDC);
std::recursive_mutex* deviceCommMutex = MutexForDeviceCommMap();
std::map<uint64_t, std::shared_ptr<DeviceComm>>* deviceCommMap = DeviceCommMap();
if ((deviceCommMutex == nullptr) || (deviceCommMap == nullptr)) {
TSD_ERROR("deviceCommMap or mutex is nullptr");
return;
}
const std::lock_guard<std::recursive_mutex> lk(*deviceCommMutex);
const std::map<uint64_t, std::shared_ptr<DeviceComm>>::iterator iter = deviceCommMap->find(index);
if (iter == deviceCommMap->end()) {
TSD_ERROR("delete the %lu deviceCommPtr from deviceCommMap failed", index);
return;
}
(void)deviceCommMap->erase(iter);
TSD_INFO("end HdcClient::ClearClientPtr");
}
* @ingroup HdcClient
* @brief 销毁HDC CLIENT
*/
void HdcClient::DestroyClient()
{
TSD_INFO("begin drvHdcClientDestroy");
const hdcError_t retVal = drvHdcClientDestroy(hdcClient_);
if (retVal != DRV_ERROR_NONE) {
TSD_ERROR("drvHdcClientDestroy() return %d", retVal);
}
TSD_INFO("end drvHdcClientDestroy");
isClientClose_ = true;
}
* @ingroup HdcClient
* @brief 关闭HDC连接,消耗相关资源
* @param 无
* @return TSD_OK:成功 或者其他错误码
*/
void HdcClient::CommDestroy()
{
TSD_INFO("enter HdcClient::CommDestroy() function");
if (!isClientClose_) {
const std::lock_guard<std::mutex> lk(mutextForHdcFreeMemoryMap_);
ClearAllSession();
DestroyClient();
ClearClientPtr();
isClientClose_ = true;
TSD_INFO("end HdcClient::CommDestroy() function");
}
}
* @ingroup HdcCommon
* @brief 虚函数 GetDeviceId 获得设备ID
* return 设备ID
*/
uint32_t HdcClient::GetDeviceId() const { return deviceId_; }
* @ingroup HdcClient
* @brief 通过指定session向device发送一条HDC消息,发送前会进行特性兼容校验
* @param [in] sessionId : 会话ID
* @param [in] msg : 要发送的HDC消息
* @return TSD_OK:成功 或者其他错误码
*/
TSD_StatusT HdcClient::CommSendMsg(const uint32_t sessionId, const HDCMessage& msg)
{
HDC_SESSION session = nullptr;
const TSD_StatusT ret = GetHdcSession(sessionId, session);
if (ret != TSD_OK) {
TSD_RUN_WARN("GetHdcSession was not successful, ret[%d]", ret);
return TSD_HDC_SEND_MSG_ERROR;
}
std::shared_ptr<VersionVerify> inspector = nullptr;
(void)CommGetVersionVerify(sessionId, inspector);
TSD_CHECK_NULLPTR(inspector, TSD_HDC_RECV_MSG_ERROR, "VersionVerify does not exist.");
TSD_CHECK(
inspector->SpecialFeatureCheck(msg.type()), TSD_HDC_RECV_MSG_ERROR,
"client and server feature_list is inconsistent, you need to update your software.");
return hdcCommon_.SendNormalMsg(msg, session);
}
* @ingroup HdcClient
* @brief 通过指定session从device接收一条HDC消息(带超时)
* @param [in] sessionId : 会话ID
* @param [out] msg : 接收到的HDC消息
* @param [in] timeout : 接收超时(毫秒)
* @return TSD_OK:成功 或者其他错误码
*/
TSD_StatusT HdcClient::RecvMsg(const uint32_t sessionId, HDCMessage& msg, const uint32_t timeout)
{
HDC_SESSION session = nullptr;
const TSD_StatusT ret = GetHdcSession(sessionId, session);
if (ret != TSD_OK) {
TSD_RUN_WARN("[TsdEVENT] GetHdcSession was not successful, ret[%d]", ret);
return TSD_HDC_RECV_MSG_ERROR;
}
return hdcCommon_.RecvMsg(session, msg, timeout);
}
* @ingroup HdcClient
* @brief 析构函数
*/
HdcClient::~HdcClient() {}
static const bool g_hdcClientRegistered =
DeviceComm::Register(DeviceCommType::HDC, [](uint32_t devId) -> std::shared_ptr<DeviceComm> {
return std::shared_ptr<DeviceComm>(new (std::nothrow) HdcClient(devId));
});
}