1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mc_send_adapter.h"
17
18 #include <map>
19 #include <string>
20 #include <securec.h>
21
22 #include "mechbody_controller_log.h"
23 #include "mc_command_factory.h"
24 #include "mc_connect_manager.h"
25 #include "mc_data_buffer.h"
26 #include "mc_protocol_convertor.h"
27
28 namespace OHOS {
29 namespace MechBodyController {
30 namespace {
31 const std::string TAG = "TransportSendAdapter";
32 const std::string RESPONSE_TIMEOUT_TASK = "transport_send_task";
33 constexpr int32_t RESPONSE_TIMEOUT = 10000;
34 constexpr int32_t CMD_RETRY_INTERVAL = 10; //ms
35 }
36
TransportSendAdapter()37 TransportSendAdapter::TransportSendAdapter()
38 {
39 HILOGI("called");
40 if (sendEventHandler_ != nullptr && recvEventHandler_ != nullptr) {
41 HILOGI("already inited, end.");
42 return;
43 }
44 sendEventThread_ = std::thread(&TransportSendAdapter::StartSendEvent, this);
45 std::unique_lock<std::mutex> sendLock(sendEventMutex_);
46 sendEventCon_.wait(sendLock, [this] {
47 return sendEventHandler_ != nullptr;
48 });
49
50 recvEventThread_ = std::thread(&TransportSendAdapter::StartRecvEvent, this);
51 std::unique_lock<std::mutex> recvLock(recvEventMutex_);
52 recvEventCon_.wait(recvLock, [this] {
53 return recvEventHandler_ != nullptr;
54 });
55
56 HILOGI("end");
57 }
58
StartSendEvent()59 void TransportSendAdapter::StartSendEvent()
60 {
61 HILOGI("called");
62 prctl(PR_SET_NAME, TAG.c_str());
63 auto runner = AppExecFwk::EventRunner::Create(false);
64 {
65 std::lock_guard<std::mutex> lock(sendEventMutex_);
66 sendEventHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
67 }
68 sendEventCon_.notify_one();
69 CHECK_POINTER_RETURN(runner, "runner");
70 runner->Run();
71 HILOGI("end");
72 }
73
StartRecvEvent()74 void TransportSendAdapter::StartRecvEvent()
75 {
76 HILOGI("called");
77 prctl(PR_SET_NAME, TAG.c_str());
78 auto runner = AppExecFwk::EventRunner::Create(false);
79 {
80 std::lock_guard<std::mutex> lock(recvEventMutex_);
81 recvEventHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
82 }
83 recvEventCon_.notify_one();
84 CHECK_POINTER_RETURN(runner, "runner");
85 runner->Run();
86 HILOGI("end");
87 }
88
~TransportSendAdapter()89 TransportSendAdapter::~TransportSendAdapter()
90 {
91 HILOGI("called");
92 if (sendEventHandler_ != nullptr) {
93 sendEventHandler_->GetEventRunner()->Stop();
94 HILOGI("prepare to clear thread resources");
95 if (sendEventThread_.joinable()) {
96 HILOGI("start clearing thread resources");
97 sendEventThread_.join();
98 }
99 sendEventHandler_ = nullptr;
100 } else {
101 HILOGE("sendEventHandler is nullptr");
102 }
103 std::lock_guard<std::mutex> lock(recvEventMutex_);
104 if (recvEventHandler_ != nullptr) {
105 recvEventHandler_->GetEventRunner()->Stop();
106 HILOGI("prepare to clear thread resources");
107 if (recvEventThread_.joinable()) {
108 HILOGI("start clearing thread resources");
109 recvEventThread_.join();
110 }
111 recvEventHandler_ = nullptr;
112 } else {
113 HILOGE("recvEventHandler is nullptr");
114 }
115 UnRegisterBluetoothListener();
116 HILOGI("end");
117 }
118
RegisterBluetoothListener()119 int32_t TransportSendAdapter::RegisterBluetoothListener()
120 {
121 HILOGI("called");
122 if (receviceListener_ == nullptr) {
123 HILOGI("RegisterReceiveListener");
124 receviceListener_ = std::make_shared<BleReceviceListenerImpl>(shared_from_this());
125 }
126 int32_t ret = BleSendManager::GetInstance().RegisterTransportSendAdapter(receviceListener_);
127 if (ret != ERR_OK) {
128 HILOGE("get RegisterBluetoothEventListener failed, ret: %{public}d", ret);
129 }
130 HILOGI("end.");
131 return ERR_OK;
132 }
133
UnRegisterBluetoothListener()134 int32_t TransportSendAdapter::UnRegisterBluetoothListener()
135 {
136 HILOGI("UnRegisterBluetoothListenercalled");
137 if (receviceListener_ == nullptr) {
138 HILOGI("UnRegisterReceiveListener ok.");
139 return ERR_OK;
140 }
141 int32_t ret = BleSendManager::GetInstance().UnRegisterTransportSendAdapter(receviceListener_);
142 if (ret != ERR_OK) {
143 HILOGE("get RegisterBluetoothEventListener failed, ret: %{public}d", ret);
144 }
145 HILOGI("end.");
146 return ERR_OK;
147 }
148
SendCommand(const std::shared_ptr<CommandBase> & cmd,int32_t delayMs)149 int32_t TransportSendAdapter::SendCommand(const std::shared_ptr<CommandBase> &cmd, int32_t delayMs)
150 {
151 if (cmd == nullptr) {
152 HILOGE("cmd is nullptr");
153 return INVALID_PARAMETERS_ERR;
154 }
155
156 auto sendTask = [this, cmd]() {
157 HILOGI("sendTask cmdType: 0x%{public}x", cmd->GetCmdType());
158 if (MechConnectManager::GetInstance().GetLocalDeviceBleStatus() == false) {
159 HILOGE("ble status error");
160 return;
161 }
162 std::shared_ptr<MechDataBuffer> mechDataBuffer = cmd->Marshal();
163 if (mechDataBuffer == nullptr) {
164 HILOGE("mechDataBuffer is nullptr");
165 return;
166 }
167 uint16_t seqNo = CreateResponseSeqNo();
168
169 ProtocolConverter protocolConverter;
170 OptType optType = cmd->NeedResponse() ? OptType::GET : OptType::PUT;
171 auto buffer = protocolConverter.Convert(optType, seqNo, mechDataBuffer);
172 if (buffer == nullptr) {
173 HILOGE("buffer is nullptr");
174 return;
175 }
176 int32_t result = BleSendManager::GetInstance().SendData(buffer->Data(), buffer->Size());
177 HILOGI("sendTask cmdType: 0x%{public}x; dataLen= %{public}zu, result = %{public}d",
178 cmd->GetCmdType(), buffer->Size(), result);
179 std::this_thread::sleep_for(std::chrono::milliseconds(CMD_RETRY_INTERVAL));
180 int32_t retry = cmd->GetRetryTimes();
181 while (result != Bluetooth::BT_SUCCESS && retry > 0) {
182 HILOGI("data send failed, retry.");
183 retry--;
184 result = BleSendManager::GetInstance().SendData(buffer->Data(), buffer->Size());
185 HILOGI("sendTask cmdType: 0x%{public}x; dataLen= %{public}zu, result = %{public}d",
186 cmd->GetCmdType(), buffer->Size(), result);
187 std::this_thread::sleep_for(std::chrono::milliseconds(CMD_RETRY_INTERVAL));
188 }
189
190 if (cmd->NeedResponse()) {
191 PushResponseTask(cmd, seqNo);
192 }
193 };
194
195 CHECK_POINTER_RETURN_VALUE(sendEventHandler_, INVALID_PARAMETERS_ERR, "sendEventHandler_");
196 sendEventHandler_->PostTask(sendTask, delayMs);
197
198 HILOGI("end");
199 return ERR_OK;
200 }
201
OnReceive(const uint8_t * data,uint32_t dataLen)202 int32_t BleReceviceListenerImpl::OnReceive(const uint8_t *data, uint32_t dataLen)
203 {
204 HILOGD("called");
205 ProtocolConverter protocolConverter;
206 if (!protocolConverter.Validate(data, dataLen)) {
207 HILOGE("protocolConverter Validate");
208 return INVALID_PARAMETERS_ERR;
209 }
210 std::shared_ptr<MechDataBuffer> mechDataBuffer = std::make_shared<MechDataBuffer>(dataLen);
211 if (mechDataBuffer == nullptr) {
212 HILOGE("mechDataBuffer is nullptr");
213 return INVALID_PARAMETERS_ERR;
214 }
215 mechDataBuffer->SetRange(0, dataLen);
216 if (memcpy_s(mechDataBuffer->Data(), mechDataBuffer->Size(), data, dataLen) != 0) {
217 HILOGE("memcpy failed");
218 return INVALID_PARAMETERS_ERR;
219 }
220 uint16_t seqNo = 0;
221 bool isAck = false;
222 std::shared_ptr<MechDataBuffer> newMechDataBuffer = protocolConverter.GetData(mechDataBuffer, seqNo, isAck);
223 return sendAdapter_->OnReceive(isAck, seqNo, newMechDataBuffer);
224 }
225
OnReceive(bool isAck,uint16_t seqNo,std::shared_ptr<MechDataBuffer> dataBuffer)226 int32_t TransportSendAdapter::OnReceive(bool isAck, uint16_t seqNo, std::shared_ptr<MechDataBuffer> dataBuffer)
227 {
228 CHECK_POINTER_RETURN_VALUE(dataBuffer, INVALID_PARAMETERS_ERR, "dataBuffer");
229 if (!isAck) {
230 CommandFactory commandFactory;
231 std::shared_ptr<CommandBase> cmd = commandFactory.CreateFromData(dataBuffer);
232 if (cmd == nullptr) {
233 HILOGE("cmd is nullptr");
234 return ERR_OK;
235 }
236 auto recvTask = [this, cmd]() {
237 SubscriptionCenter::GetInstance().Notify(cmd);
238 };
239 std::lock_guard<std::mutex> lock(recvEventMutex_);
240 if (recvEventHandler_ == nullptr) {
241 HILOGE("eventHandler is nullptr");
242 return ERR_OK;
243 }
244 recvEventHandler_->PostTask(recvTask);
245 return ERR_OK;
246 }
247
248 auto responseTask = [this, seqNo, dataBuffer]() {
249 ExeResponseTask(seqNo, dataBuffer);
250 };
251 std::lock_guard<std::mutex> lock(recvEventMutex_);
252 if (recvEventHandler_ == nullptr) {
253 HILOGE("eventHandler is nullptr");
254 return ERR_OK;
255 }
256 recvEventHandler_->PostTask(responseTask);
257 const std::string taskName = RESPONSE_TIMEOUT_TASK + std::to_string(seqNo);
258 recvEventHandler_->RemoveTask(taskName);
259 return ERR_OK;
260 }
261
BleReceviceListenerImpl(std::shared_ptr<TransportSendAdapter> sendAdapter)262 BleReceviceListenerImpl::BleReceviceListenerImpl(std::shared_ptr<TransportSendAdapter> sendAdapter)
263 {
264 sendAdapter_ = sendAdapter;
265 }
266
PushResponseTask(const std::shared_ptr<CommandBase> & cmd,uint16_t seqNo)267 int32_t TransportSendAdapter::PushResponseTask(const std::shared_ptr<CommandBase> &cmd, uint16_t seqNo)
268 {
269 if (cmd == nullptr) {
270 HILOGE("cmd is nullptr");
271 return INVALID_PARAMETERS_ERR;
272 }
273 {
274 std::unique_lock<std::shared_mutex> responseReadLock(responseMutex_);
275 pendingRequests_.insert(std::make_pair(seqNo, cmd));
276 }
277 HILOGI("cmdType : 0x%{public}x, seqNo: %{public}d", cmd->GetCmdType(), seqNo);
278 std::lock_guard<std::mutex> lock(recvEventMutex_);
279 if (recvEventHandler_ == nullptr) {
280 HILOGE("eventHandler is nullptr");
281 return INVALID_PARAMETERS_ERR;
282 }
283 auto responseTimeoutTask = [this, seqNo]() {
284 ExeRespTimeoutTask(seqNo);
285 };
286 const std::string taskName = RESPONSE_TIMEOUT_TASK + std::to_string(seqNo);
287 recvEventHandler_->PostTask(responseTimeoutTask, taskName, RESPONSE_TIMEOUT);
288 HILOGI("end");
289 return ERR_OK;
290 }
291
CreateResponseSeqNo()292 uint16_t TransportSendAdapter::CreateResponseSeqNo()
293 {
294 std::unique_lock<std::shared_mutex> responseReadLock(responseMutex_);
295 if (lastSeqNo_ >= UINT16_MAX) {
296 HILOGE("the seqNo is full, reorder the seqNo.");
297 lastSeqNo_ = 0;
298 return 0;
299 }
300 uint16_t seqNo = ++lastSeqNo_;
301 HILOGI("end, new seqNo is %{public}d", seqNo);
302 return seqNo;
303 }
304
GetCmdBySeqNo(uint16_t seqNo)305 const std::shared_ptr<CommandBase> TransportSendAdapter::GetCmdBySeqNo(uint16_t seqNo)
306 {
307 HILOGI("called");
308 std::unique_lock<std::shared_mutex> responseReadLock(responseMutex_);
309 if (pendingRequests_.count(seqNo) != 0) {
310 return pendingRequests_[seqNo];
311 }
312 HILOGI("end");
313 return nullptr;
314 }
315
ExeResponseTask(uint16_t seqNo,const std::shared_ptr<MechDataBuffer> & mechDataBuffer)316 int32_t TransportSendAdapter::ExeResponseTask(uint16_t seqNo, const std::shared_ptr<MechDataBuffer>& mechDataBuffer)
317 {
318 CHECK_POINTER_RETURN_VALUE(mechDataBuffer, INVALID_PARAMETERS_ERR, "mechDataBuffer");
319 HILOGI("called, seqNo: %{public}d", seqNo);
320 {
321 std::unique_lock<std::shared_mutex> responseWriteLock(responseMutex_);
322 auto it = pendingRequests_.find(seqNo);
323 if (it != pendingRequests_.end() && it->second != nullptr) {
324 it->second->TriggerResponse(mechDataBuffer);
325 pendingRequests_.erase(it);
326 }
327 }
328 HILOGI("end");
329 return ERR_OK;
330 }
331
ExeRespTimeoutTask(uint16_t seqNo)332 int32_t TransportSendAdapter::ExeRespTimeoutTask(uint16_t seqNo)
333 {
334 HILOGI("called, seqNo: %{public}d", seqNo);
335 {
336 std::unique_lock<std::shared_mutex> responseWriteLock(responseMutex_);
337 auto it = pendingRequests_.find(seqNo);
338 if (it != pendingRequests_.end() && it->second != nullptr) {
339 it->second->TriggerTimeout();
340 pendingRequests_.erase(it);
341 }
342 }
343 HILOGI("end");
344 return ERR_OK;
345 }
346
RemoveRespTimeoutTask(uint16_t seqNo)347 int32_t TransportSendAdapter::RemoveRespTimeoutTask(uint16_t seqNo)
348 {
349 HILOGI("called");
350 {
351 std::unique_lock<std::shared_mutex> responseWriteLock(responseMutex_);
352 auto it = pendingRequests_.find(seqNo);
353 if (it != pendingRequests_.end()) {
354 pendingRequests_.erase(it);
355 }
356 }
357 HILOGI("end");
358 return ERR_OK;
359 }
360 } // namespace MechBodyController
361 } // namespace OHOS
362