1 /*
2  * Copyright (C) 2021-2022 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 "ohos_bt_gatt_client.h"
17 #include <cstring>
18 #include <map>
19 #include "__config"
20 #include <functional>
21 #include <atomic>
22 
23 #include "bluetooth_gatt_characteristic.h"
24 #include "bluetooth_gatt_client.h"
25 #include "bluetooth_gatt_descriptor.h"
26 #include "bluetooth_gatt_service.h"
27 #include "bluetooth_log.h"
28 #include "bluetooth_utils.h"
29 #include "bluetooth_remote_device.h"
30 
31 #include "iosfwd"
32 #include "memory"
33 #include "new"
34 #include "ohos_bt_adapter_utils.h"
35 #include "ohos_bt_def.h"
36 #include "optional"
37 #include "string"
38 #include "type_traits"
39 #include "utility"
40 #include "uuid.h"
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
46 using namespace std;
47 
48 namespace OHOS {
49 namespace Bluetooth {
50 class GattClientCallbackWrapper;
51 
52 struct GattClientWrapper {
53     std::shared_ptr<GattClient> gattClient;
54     std::shared_ptr<GattClientCallbackWrapper> gattClientCallback;
55     string remoteAddr;
56     bool fastestConnFlag;
57 };
58 
59 using ClientIterator = std::map<int, struct GattClientWrapper>::iterator;
60 
61 static std::atomic<int> g_clientIncrease(0);
62 static std::map<int, struct GattClientWrapper> g_MapGattClient;
63 static std::mutex g_MapGattClientMutex;
64 
65 #define GATTCLIENT g_MapGattClient
66 
ConverWriteType(BtGattWriteType writeType)67 int ConverWriteType(BtGattWriteType writeType)
68 {
69     int outWriteType = GattCharacteristic::WriteType::DEFAULT;
70     if (writeType == OHOS_GATT_WRITE_DEFAULT) {
71         outWriteType = GattCharacteristic::WriteType::DEFAULT;
72     } else if (writeType == OHOS_GATT_WRITE_NO_RSP) {
73         outWriteType = GattCharacteristic::WriteType::NO_RESPONSE;
74     } else if (writeType == OHOS_GATT_WRITE_SIGNED) {
75         outWriteType = GattCharacteristic::WriteType::SIGNED;
76     } else {
77         HILOGE("write type: %{public}d is not supported and the default type is used.", writeType);
78         outWriteType = GattCharacteristic::WriteType::DEFAULT;
79     }
80     return outWriteType;
81 }
82 
GattcFindCharacteristic(int clientId, std::shared_ptr<GattClient> &client, BtGattCharacteristic characteristic)83 static GattCharacteristic *GattcFindCharacteristic(int clientId, std::shared_ptr<GattClient> &client,
84     BtGattCharacteristic characteristic)
85 {
86     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
87     ClientIterator iter = GATTCLIENT.find(clientId);
88     if (iter == GATTCLIENT.end()) {
89         HILOGE("clientId: %{public}d, has not been registered.", clientId);
90         return nullptr;
91     }
92 
93     client = iter->second.gattClient;
94     if (client == nullptr) {
95         HILOGE("client is null.");
96         return nullptr;
97     }
98 
99     string strUuidSvc(characteristic.serviceUuid.uuid);
100     string strUuidChar(characteristic.characteristicUuid.uuid);
101     HILOGD("execute, strUuidSvc: %{public}s, strUuidChar: %{public}s",
102         strUuidSvc.c_str(), strUuidChar.c_str());
103     if (!IsValidUuid(strUuidSvc) || !IsValidUuid(strUuidChar)) {
104         HILOGE("match the UUID faild.");
105         return nullptr;
106     }
107     std::optional<std::reference_wrapper<GattService>> service = client->GetService(UUID::FromString(strUuidSvc));
108     if (service == std::nullopt) {
109         HILOGE("find service fail.");
110         return nullptr;
111     }
112     GattCharacteristic *charac = service->get().GetCharacteristic(UUID::FromString(strUuidChar));
113     if (charac == nullptr) {
114         HILOGE("find characteristic fail.");
115     }
116     return charac;
117 }
118 
119 
120 class GattClientCallbackWrapper : public GattClientCallback {
121 public:
GattClientCallbackWrapper(BtGattClientCallbacks *callback, int clientId)122     GattClientCallbackWrapper(BtGattClientCallbacks *callback, int clientId)
123     {
124         appCallback_ = callback;
125         clientId_ = clientId;
126     }
127 
128     void OnConnectionStateChanged(int connectionState, int ret) override
129     {
130         if (appCallback_ == nullptr || appCallback_->ConnectionStateCb == nullptr) {
131             HILOGI("callback is null.");
132             return;
133         }
134 
135         HILOGD("clientId: %{public}d, connectionState: %{public}d, ret: %{public}d",
136             clientId_, connectionState, ret);
137         if (connectionState == static_cast<int>(BTConnectState::CONNECTED)) {
138             HILOGI("GattcOnConnectionStateChanged Connected, clientId: %{public}d", clientId_);
139         }
140         appCallback_->ConnectionStateCb(clientId_, connectionState, GetGattcResult(ret));
141     }
142 
143     void OnConnectionParameterChanged(int interval, int latency, int timeout, int status) override
144     {
145         if (appCallback_ == nullptr || appCallback_->connectParaUpdateCb == nullptr) {
146             HILOGI("callback is null.");
147             return;
148         }
149 
150         HILOGI("clientId: %{public}d, status: %{public}d, interval: %{public}d, latency: %{public}d, "
151             "timeout: %{public}d", clientId_, status, interval, latency, timeout);
152         appCallback_->connectParaUpdateCb(clientId_, interval, latency, timeout, GetGattcResult(status));
153     }
154 
155     void OnServicesDiscovered(int status) override
156     {
157         if (appCallback_ == nullptr || appCallback_->searchServiceCompleteCb == nullptr) {
158             HILOGI("callback is null.");
159             return;
160         }
161 
162         HILOGI("GattcOnServicesDiscovered complete, clientId: %{public}d, status: %{public}d", clientId_, status);
163         appCallback_->searchServiceCompleteCb(clientId_, GetGattcResult(status));
164     }
165 
166     void OnCharacteristicReadResult(const GattCharacteristic &characteristic, int ret) override
167     {
168         if (appCallback_ == nullptr || appCallback_->readCharacteristicCb == nullptr) {
169             HILOGI("callback is null.");
170             return;
171         }
172         if (characteristic.GetService() == nullptr) {
173             HILOGE("get service null.");
174             return;
175         }
176 
177         BtGattReadData characData;
178         string srvUuid = characteristic.GetService()->GetUuid().ToString();
179         string charcUuid = characteristic.GetUuid().ToString();
180         GattcBuildUuid(&characData.attribute.characteristic.serviceUuid, srvUuid);
181         GattcBuildUuid(&characData.attribute.characteristic.characteristicUuid, charcUuid);
182         size_t tmpLen = 0;
183         characData.data = characteristic.GetValue(&tmpLen).get();
184         characData.dataLen = (unsigned short)tmpLen;
185 
186         HILOGI("clientId: %{public}d, ret: %{public}d, dataLen: %{public}d",
187             clientId_, ret, characData.dataLen);
188         HILOGI("srvUuid: %{public}s, charcUuid: %{public}s",
189             srvUuid.c_str(), charcUuid.c_str());
190         appCallback_->readCharacteristicCb(clientId_, &characData, GetGattcResult(ret));
191     }
192 
193     void OnCharacteristicWriteResult(const GattCharacteristic &characteristic, int ret) override
194     {
195         if (appCallback_ == nullptr || appCallback_->writeCharacteristicCb == nullptr) {
196             HILOGI("callback is null.");
197             return;
198         }
199         if (characteristic.GetService() == nullptr) {
200             HILOGE("get service null.");
201             return;
202         }
203 
204         BtGattCharacteristic tmpCharac;
205         string srvUuid = characteristic.GetService()->GetUuid().ToString();
206         string charcUuid = characteristic.GetUuid().ToString();
207         GattcBuildUuid(&tmpCharac.serviceUuid, srvUuid);
208         GattcBuildUuid(&tmpCharac.characteristicUuid, charcUuid);
209 
210         HILOGI("clientId: %{public}d, ret: %{public}d, ", clientId_, ret);
211         HILOGI("srvUuid: %{public}s, charcUuid: %{public}s", srvUuid.c_str(), charcUuid.c_str());
212         appCallback_->writeCharacteristicCb(clientId_, &tmpCharac, GetGattcResult(ret));
213     }
214 
215     void OnDescriptorReadResult(const GattDescriptor &descriptor, int ret) override
216     {
217         if (appCallback_ == nullptr || appCallback_->readDescriptorCb == nullptr) {
218             HILOGI("callback is null.");
219             return;
220         }
221 
222         if (descriptor.GetCharacteristic() == nullptr ||
223             descriptor.GetCharacteristic()->GetService() == nullptr) {
224             HILOGE("get characteristic or service null.");
225             return;
226         }
227 
228         BtGattReadData descData;
229         string srvUuid = descriptor.GetCharacteristic()->GetService()->GetUuid().ToString();
230         string charcUuid = descriptor.GetCharacteristic()->GetUuid().ToString();
231         string descUuid = descriptor.GetUuid().ToString();
232         GattcBuildUuid(&descData.attribute.descriptor.characteristic.serviceUuid, srvUuid);
233         GattcBuildUuid(&descData.attribute.descriptor.characteristic.characteristicUuid, charcUuid);
234         GattcBuildUuid(&descData.attribute.descriptor.descriptorUuid, descUuid);
235         size_t tmpLen = 0;
236         descData.data = descriptor.GetValue(&tmpLen).get();
237         descData.dataLen = (unsigned short)tmpLen;
238 
239         HILOGI("clientId: %{public}d, ret: %{public}d, dataLen: %{public}d", clientId_, ret, descData.dataLen);
240         HILOGI("srvUuid: %{public}s, charcUuid: %{public}s, descUuid: %{public}s",
241             srvUuid.c_str(), charcUuid.c_str(), descUuid.c_str());
242         appCallback_->readDescriptorCb(clientId_, &descData, GetGattcResult(ret));
243     }
244 
245     void OnDescriptorWriteResult(const GattDescriptor &descriptor, int ret) override
246     {
247         if (appCallback_ == nullptr || appCallback_->writeDescriptorCb == NULL) {
248             HILOGI("callback is null.");
249             return;
250         }
251 
252         if (descriptor.GetCharacteristic() == nullptr ||
253             descriptor.GetCharacteristic()->GetService() == nullptr) {
254             HILOGE("get characteristic or service null.");
255             return;
256         }
257 
258         BtGattDescriptor tmpDesc;
259         string srvUuid = descriptor.GetCharacteristic()->GetService()->GetUuid().ToString();
260         string charcUuid = descriptor.GetCharacteristic()->GetUuid().ToString();
261         string descUuid = descriptor.GetUuid().ToString();
262         GattcBuildUuid(&tmpDesc.characteristic.serviceUuid, srvUuid);
263         GattcBuildUuid(&tmpDesc.characteristic.characteristicUuid, charcUuid);
264         GattcBuildUuid(&tmpDesc.descriptorUuid, descUuid);
265 
266         HILOGI("clientId: %{public}d, ret: %{public}d", clientId_, ret);
267         HILOGI("srvUuid: %{public}s, charcUuid: %{public}s, descUuid: %{public}s",
268             srvUuid.c_str(), charcUuid.c_str(), descUuid.c_str());
269         appCallback_->writeDescriptorCb(clientId_, &tmpDesc, GetGattcResult(ret));
270     }
271 
272     void OnMtuUpdate(int mtu, int ret) override
273     {
274         if (appCallback_ == nullptr || appCallback_->configureMtuSizeCb == nullptr) {
275             HILOGI("callback is null.");
276             return;
277         }
278 
279         HILOGI("clientId: %{public}d, mtu: %{public}d, ret: %{public}d", clientId_, mtu, ret);
280         appCallback_->configureMtuSizeCb(clientId_, mtu, GetGattcResult(ret));
281     }
282 
283     void OnSetNotifyCharacteristic(const GattCharacteristic &characteristic, int status) override
284     {
285         if (appCallback_ == nullptr || appCallback_->registerNotificationCb == nullptr) {
286             HILOGI("callback is null.");
287             return;
288         }
289 
290         HILOGI("clientId: %{public}d, status: %{public}d", clientId_, status);
291         appCallback_->registerNotificationCb(clientId_, GetGattcResult(status));
292     }
293 
294     void OnCharacteristicChanged(const GattCharacteristic &characteristic) override
295     {
296         if (appCallback_ == nullptr || appCallback_->notificationCb == nullptr) {
297             HILOGI("callback is null.");
298             return;
299         }
300         if (characteristic.GetService() == nullptr) {
301             HILOGE("get service null.");
302             return;
303         }
304 
305         BtGattReadData notificationData;
306         string srvUuid = characteristic.GetService()->GetUuid().ToString();
307         string charcUuid = characteristic.GetUuid().ToString();
308         GattcBuildUuid(&notificationData.attribute.characteristic.serviceUuid, srvUuid);
309         GattcBuildUuid(&notificationData.attribute.characteristic.characteristicUuid, charcUuid);
310         size_t tmpLen = 0;
311         notificationData.data = characteristic.GetValue(&tmpLen).get();
312         notificationData.dataLen = (unsigned short)tmpLen;
313 
314         HILOGD("clientId: %{public}d, dataLen: %{public}d, ", clientId_, notificationData.dataLen);
315         HILOGD("srvUuid: %{public}s, charcUuid: %{public}s", srvUuid.c_str(), charcUuid.c_str());
316         appCallback_->notificationCb(clientId_, &notificationData, OHOS_BT_STATUS_SUCCESS);
317     }
318 private:
GattcBuildUuid(BtUuid *desUuid, const std::string &srcUuid)319     void GattcBuildUuid(BtUuid *desUuid, const std::string &srcUuid)
320     {
321         desUuid->uuid = (char *)srcUuid.c_str();
322         desUuid->uuidLen = srcUuid.size();
323     }
324 
325     BtGattClientCallbacks *appCallback_;
326     int clientId_;
327 };
328 
329 /**
330  * @brief Registers a GATT client with a specified application UUID.
331  *
332  * @param appUuid Indicates the UUID of the application for which the GATT client is to be registered.
333  * The UUID is defined by the application.
334  * @return Returns the client ID.
335  */
BleGattcRegister(BtUuid appUuid)336 int BleGattcRegister(BtUuid appUuid)
337 {
338     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
339     g_clientIncrease++;
340     struct GattClientWrapper clientWrapper;
341     clientWrapper.gattClient = nullptr;
342     clientWrapper.gattClientCallback = nullptr;
343     clientWrapper.remoteAddr = "";
344     clientWrapper.fastestConnFlag = false;
345     int clientId = g_clientIncrease.load();
346     GATTCLIENT.insert(std::pair<int, struct GattClientWrapper>(clientId, clientWrapper));
347     HILOGI("clientId: %{public}d", clientId);
348     return clientId;
349 }
350 
351 /**
352  * @brief Unregisters a GATT client with a specified ID.
353  *
354  * @param clientId Indicates the ID of the GATT client.
355  * @return Returns the operation result status {@link BtStatus}.
356  */
BleGattcUnRegister(int clientId)357 int BleGattcUnRegister(int clientId)
358 {
359     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
360     HILOGI("clientId: %{public}d", clientId);
361     ClientIterator it = GATTCLIENT.find(clientId);
362     if (it != GATTCLIENT.end()) {
363         auto &clientWrapper = it->second;
364         if (clientWrapper.gattClient != nullptr) {
365             clientWrapper.gattClient = nullptr;
366         }
367         if (clientWrapper.gattClientCallback != nullptr) {
368             clientWrapper.gattClientCallback = nullptr;
369         }
370         GATTCLIENT.erase(it);
371     }
372     return OHOS_BT_STATUS_SUCCESS;
373 }
374 
375 /**
376  * @brief Set fastest connection of the Gatt connection, add address to the accelerate connection map
377  *  before create a new connection.
378  *
379  * @param clientId Indicates the ID of the GATT client.
380  * @param fastestConnFlag Indicates whether to enable the fastest connection.
381  * @return Returns the operation result status {@link BtStatus}.
382  */
BleGattcSetFastestConn(int clientId, bool fastestConnFlag)383 int BleGattcSetFastestConn(int clientId, bool fastestConnFlag)
384 {
385     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
386     HILOGI("clientId: %{public}d, fastestConnFlag: %{public}d", clientId, fastestConnFlag);
387     ClientIterator iter = GATTCLIENT.find(clientId);
388     if (iter == GATTCLIENT.end()) {
389         HILOGE("clientId: %{public}d, has not been registered.", clientId);
390         return OHOS_BT_STATUS_FAIL;
391     }
392     iter->second.fastestConnFlag = fastestConnFlag;
393     return OHOS_BT_STATUS_SUCCESS;
394 }
395 
396 /**
397  * @brief Create a Gatt connection to a remote device.
398  *
399  * @param clientId Indicates the ID of the GATT client.
400  * @param bdAddr Indicates the remote device's address.
401  * @param isAutoConnect Indicates whether it is a direct connection(false) or a background connection(true).
402  * @param transport Indicates the transport of Gatt client {@link BtTransportType}.
403  * @return Returns the operation result status {@link BtStatus}.
404  */
BleGattcConnect(int clientId, BtGattClientCallbacks *func, const BdAddr *bdAddr, bool isAutoConnect, BtTransportType transport)405 int BleGattcConnect(int clientId, BtGattClientCallbacks *func, const BdAddr *bdAddr,
406     bool isAutoConnect, BtTransportType transport)
407 {
408     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
409     if (func == nullptr || bdAddr == nullptr) {
410         HILOGE("func or bdAddr is null.");
411         return OHOS_BT_STATUS_PARM_INVALID;
412     }
413     ClientIterator iter = GATTCLIENT.find(clientId);
414     if (iter == GATTCLIENT.end()) {
415         HILOGE("clientId: %{public}d, has not been registered.", clientId);
416         return OHOS_BT_STATUS_FAIL;
417     }
418 
419     string strAddress;
420     ConvertAddr(bdAddr->addr, strAddress);
421     HILOGI("BleGattcConnect start, clientId: %{public}d, addr: %{public}s, isAutoConnect: %{public}d",
422         clientId, GetEncryptAddr(strAddress).c_str(), isAutoConnect);
423     std::shared_ptr<GattClient> client = nullptr;
424     if (iter->second.gattClient != nullptr && iter->second.remoteAddr == strAddress) {
425         HILOGI("connect to the same remote device again.");
426         client = iter->second.gattClient;
427         iter->second.gattClientCallback = nullptr;
428     } else {
429         BluetoothRemoteDevice device(strAddress, transport);
430         client = std::make_shared<GattClient>(device);
431         client->Init();
432     }
433 
434     if (iter->second.fastestConnFlag) {
435         int result = client->RequestFastestConn();
436         if (result != OHOS_BT_STATUS_SUCCESS) {
437             HILOGE("request fastest connect fail.");
438         }
439         iter->second.fastestConnFlag = false;
440     }
441 
442     std::shared_ptr<GattClientCallbackWrapper> clientWrapper = std::make_shared<GattClientCallbackWrapper>(
443         func, clientId);
444     iter->second.gattClient = client;
445     iter->second.gattClientCallback = clientWrapper;
446     iter->second.remoteAddr = strAddress;
447     int result = client->Connect(clientWrapper, isAutoConnect, transport);
448     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
449     if (result != OHOS_BT_STATUS_SUCCESS) {
450         client = nullptr;
451         clientWrapper = nullptr;
452         iter->second.gattClient = nullptr;
453         iter->second.gattClientCallback = nullptr;
454         iter->second.remoteAddr = "";
455         return OHOS_BT_STATUS_FAIL;
456     }
457 
458     return OHOS_BT_STATUS_SUCCESS;
459 }
460 
461 /**
462  * @brief Set priority of the Gatt connection.
463  *
464  * @param clientId Indicates the ID of the GATT client.
465  * @param bdAddr Indicates the remote device's address.
466  * @param priority Indicates the priority of Gatt client {@link BtGattPriority}.
467  * @return Returns the operation result status {@link BtStatus}.
468  */
BleGattcSetPriority(int clientId, const BdAddr *bdAddr, BtGattPriority priority)469 int BleGattcSetPriority(int clientId, const BdAddr *bdAddr, BtGattPriority priority)
470 {
471     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
472     if (bdAddr == nullptr) {
473         HILOGE("bdAddr is null.");
474         return OHOS_BT_STATUS_PARM_INVALID;
475     }
476     ClientIterator iter = GATTCLIENT.find(clientId);
477     if (iter == GATTCLIENT.end()) {
478         HILOGE("clientId: %{public}d, has not been registered.", clientId);
479         return OHOS_BT_STATUS_FAIL;
480     }
481 
482     string strAddress;
483     ConvertAddr(bdAddr->addr, strAddress);
484     HILOGI("clientId: %{public}d, addr: %{public}s, priority: %{public}d",
485         clientId, GetEncryptAddr(strAddress).c_str(), priority);
486     if (iter->second.gattClient == nullptr || iter->second.remoteAddr != strAddress) {
487         HILOGE("fail.");
488         return OHOS_BT_STATUS_FAIL;
489     }
490 
491     std::shared_ptr<GattClient> client = iter->second.gattClient;
492     int result = client->RequestConnectionPriority(priority);
493     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
494     return GetGattcResult(result);
495 }
496 
497 /**
498  * @brief Disconnect a Gatt connection with a remote device.
499  *
500  * @param clientId Indicates the ID of the GATT client.
501  * @Returns the operation result status {@link BtStatus}.
502  */
BleGattcDisconnect(int clientId)503 int BleGattcDisconnect(int clientId)
504 {
505     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
506     ClientIterator iter = GATTCLIENT.find(clientId);
507     if (iter == GATTCLIENT.end()) {
508         HILOGE("clientId: %{public}d, has not been registered.", clientId);
509         return OHOS_BT_STATUS_FAIL;
510     }
511 
512     std::shared_ptr<GattClient> client = iter->second.gattClient;
513     if (client == nullptr) {
514         HILOGE("clientId: %{public}d, has not been connected.", clientId);
515         return OHOS_BT_STATUS_FAIL;
516     }
517 
518     int result = client->Disconnect();
519     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
520     return GetGattcResult(result);
521 }
522 
523 /**
524  * @brief Request a GATT service discovery on a remote device.
525  *
526  * @param clientId Indicates the ID of the GATT client.
527  * @return Returns the operation result status {@link BtStatus}.
528  */
BleGattcSearchServices(int clientId)529 int BleGattcSearchServices(int clientId)
530 {
531     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
532     HILOGI("BleGattcSearchServices start, clientId: %{public}d", clientId);
533     ClientIterator iter = GATTCLIENT.find(clientId);
534     if (iter == GATTCLIENT.end()) {
535         HILOGE("clientId: %{public}d, has not been registered.", clientId);
536         return OHOS_BT_STATUS_FAIL;
537     }
538 
539     std::shared_ptr<GattClient> client = iter->second.gattClient;
540     if (client == nullptr) {
541         HILOGE("clientId: %{public}d, has not been connected.", clientId);
542         return OHOS_BT_STATUS_FAIL;
543     }
544 
545     HILOGI("DiscoverServices() called");
546     int result = client->DiscoverServices();
547     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
548     return GetGattcResult(result);
549 }
550 
551 /**
552  * @brief Check whether the expected service exists.
553  *
554  * @param clientId Indicates the ID of the GATT client.
555  * @param serviceUuid Indicates the UUID of the service.
556  * @return Returns true or false.
557  */
BleGattcGetService(int clientId, BtUuid serviceUuid)558 bool BleGattcGetService(int clientId, BtUuid serviceUuid)
559 {
560     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
561     HILOGI("clientId: %{public}d", clientId);
562     ClientIterator iter = GATTCLIENT.find(clientId);
563     if (iter == GATTCLIENT.end()) {
564         HILOGE("clientId has not been registered.");
565         return false;
566     }
567 
568     std::shared_ptr<GattClient> client = iter->second.gattClient;
569     if (client == nullptr) {
570         HILOGE("gatt is not connected.");
571         return false;
572     }
573 
574     string strUuid(serviceUuid.uuid);
575     if (!IsValidUuid(strUuid)) {
576         HILOGE("match the UUID faild.");
577         return false;
578     }
579     UUID uuid(UUID::FromString(strUuid));
580     HILOGI("service uuid: %{public}s", strUuid.c_str());
581     std::optional<std::reference_wrapper<GattService>> gattService = client->GetService(uuid);
582     if (gattService == std::nullopt) {
583         HILOGE("get service failed, gattService is null.");
584         return false;
585     }
586     GattService service = gattService->get();
587     if (service.GetUuid().Equals(uuid)) {
588         HILOGI("get service success.");
589         return true;
590     } else {
591         HILOGE("get service failed, the service uuid is not exist.");
592         return false;
593     }
594 }
595 
596 /**
597  * @brief Read characteristic value from the remote device.
598  *
599  * @param clientId Indicates the ID of the GATT client.
600  * @param characteristic The specified characteristic {@link BtGattCharacteristic} to be read.
601  * @return Returns the operation result status {@link BtStatus}.
602  */
BleGattcReadCharacteristic(int clientId, BtGattCharacteristic characteristic)603 int BleGattcReadCharacteristic(int clientId, BtGattCharacteristic characteristic)
604 {
605     HILOGI("clientId: %{public}d", clientId);
606     std::shared_ptr<GattClient> client = nullptr;
607     GattCharacteristic *tmpCharac = GattcFindCharacteristic(clientId, client, characteristic);
608     if (tmpCharac == nullptr || client == nullptr) {
609         HILOGE("find characteristic fail.");
610         return OHOS_BT_STATUS_FAIL;
611     }
612 
613     int result = client->ReadCharacteristic(*tmpCharac);
614     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
615     return GetGattcResult(result);
616 }
617 
618 /**
619  * @brief Write characteristic value to the remote device.
620  *
621  * @param clientId Indicates the ID of the GATT client.
622  * @param characteristic The specified characteristic {@link BtGattCharacteristic} to be read.
623  * @param writeType Indicates the characteristic write type.
624  * @param value The value to be write.
625  * @param len The length of the value.
626  * @return Returns the operation result status {@link BtStatus}.
627  */
BleGattcWriteCharacteristic(int clientId, BtGattCharacteristic characteristic, BtGattWriteType writeType, int len, const char *value)628 int BleGattcWriteCharacteristic(int clientId, BtGattCharacteristic characteristic,
629     BtGattWriteType writeType, int len, const char *value)
630 {
631     HILOGD("clientId:%{public}d, writeType:%{public}d, len:%{public}d", clientId, writeType, len);
632     std::shared_ptr<GattClient> client = nullptr;
633     GattCharacteristic *tmpCharac = GattcFindCharacteristic(clientId, client, characteristic);
634     if (tmpCharac == nullptr || client == nullptr) {
635         HILOGE("find characteristic fail.");
636         return OHOS_BT_STATUS_FAIL;
637     }
638 
639     if (writeType != OHOS_GATT_WRITE_TYPE_UNKNOWN) {
640         int newWriteType = ConverWriteType(writeType);
641         tmpCharac->SetWriteType(newWriteType);
642     }
643 
644     std::vector<uint8_t> characterValue(value, value + len);
645     int result = client->WriteCharacteristic(*tmpCharac, std::move(characterValue));
646     HILOGD("clientId: %{public}d, result: %{public}d", clientId, result);
647     return GetGattcResult(result);
648 }
649 
650 /**
651  * @brief Read descriptor value from the remote device.
652  *
653  * @param clientId Indicates the ID of the GATT client.
654  * @param descriptor The specified characteristic {@link BtGattDescriptor} to be read.
655  * @return Returns the operation result status {@link BtStatus}.
656  */
BleGattcReadDescriptor(int clientId, BtGattDescriptor descriptor)657 int BleGattcReadDescriptor(int clientId, BtGattDescriptor descriptor)
658 {
659     HILOGI("clientId: %{public}d", clientId);
660     std::shared_ptr<GattClient> client = nullptr;
661     GattCharacteristic *tmpCharac = GattcFindCharacteristic(clientId, client, descriptor.characteristic);
662     if (tmpCharac == nullptr || client == nullptr) {
663         HILOGE("find characteristic fail.");
664         return OHOS_BT_STATUS_FAIL;
665     }
666 
667     string strUuidDesc(descriptor.descriptorUuid.uuid);
668     if (!IsValidUuid(strUuidDesc)) {
669         HILOGE("match the UUID faild.");
670         return OHOS_BT_STATUS_PARM_INVALID;
671     }
672     GattDescriptor *tmpDescriptor = tmpCharac->GetDescriptor(UUID::FromString(strUuidDesc));
673     if (tmpDescriptor == nullptr) {
674         HILOGE("find descriptor fail.");
675         return OHOS_BT_STATUS_FAIL;
676     }
677 
678     int result = client->ReadDescriptor(*tmpDescriptor);
679     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
680     return GetGattcResult(result);
681 }
682 
683 /**
684  * @brief Write descriptor value to the remote device.
685  *
686  * @param clientId Indicates the ID of the GATT client.
687  * @param descriptor The specified descriptor {@link BtGattDescriptor} to be read.
688  * @param value The value to be write.
689  * @param len The length of the value.
690  * @return Returns the operation result status {@link BtStatus}.
691  */
BleGattcWriteDescriptor(int clientId, BtGattDescriptor descriptor, int len, const char *value)692 int BleGattcWriteDescriptor(int clientId, BtGattDescriptor descriptor, int len, const char *value)
693 {
694     HILOGI("clientId:%{public}d, len:%{public}d", clientId, len);
695     std::shared_ptr<GattClient> client = nullptr;
696     GattCharacteristic *tmpCharac = GattcFindCharacteristic(clientId, client, descriptor.characteristic);
697     if (tmpCharac == nullptr || client == nullptr) {
698         HILOGE("find characteristic fail.");
699         return OHOS_BT_STATUS_FAIL;
700     }
701 
702     string strUuidDesc(descriptor.descriptorUuid.uuid);
703     if (!IsValidUuid(strUuidDesc)) {
704         HILOGE("match the UUID faild.");
705         return OHOS_BT_STATUS_PARM_INVALID;
706     }
707     GattDescriptor *tmpDescriptor = tmpCharac->GetDescriptor(UUID::FromString(strUuidDesc));
708     if (tmpDescriptor == nullptr) {
709         HILOGE("find descriptor fail.");
710         return OHOS_BT_STATUS_FAIL;
711     }
712 
713     tmpDescriptor->SetValue(reinterpret_cast<unsigned char *>(const_cast<char *>(value)), len);
714     int result = client->WriteDescriptor(*tmpDescriptor);
715     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
716     return GetGattcResult(result);
717 }
718 
719 /**
720  * @brief Configure the ATT MTU size.
721  *
722  * @param clientId Indicates the ID of the GATT client.
723  * @param mtuSize The size of MTU.
724  * @return Returns the operation result status {@link BtStatus}.
725  */
BleGattcConfigureMtuSize(int clientId, int mtuSize)726 int BleGattcConfigureMtuSize(int clientId, int mtuSize)
727 {
728     std::lock_guard<std::mutex> lock(g_MapGattClientMutex);
729     HILOGI("clientId:%{public}d, mtuSize:%{public}d", clientId, mtuSize);
730     ClientIterator iter = GATTCLIENT.find(clientId);
731     if (iter == GATTCLIENT.end()) {
732         HILOGE("GattcFindCharacteristic, clientId: %{public}d, has not been registered.", clientId);
733         return OHOS_BT_STATUS_FAIL;
734     }
735 
736     std::shared_ptr<GattClient> client = iter->second.gattClient;
737     if (client == nullptr) {
738         HILOGE("client is null.");
739         return OHOS_BT_STATUS_FAIL;
740     }
741 
742     int result = client->RequestBleMtuSize(mtuSize);
743     HILOGD("clientId: %{public}d, result: %{public}d", clientId, result);
744     return GetGattcResult(result);
745 }
746 
747 /**
748  * @brief Enable or disable notifications for a given characteristic.
749  *
750  * @param clientId Indicates the ID of the GATT client.
751  * @param characteristic The specified characteristic {@link BtGattCharacteristic}.
752  * @param enable True or false.
753  * @return Returns the operation result status {@link BtStatus}.
754  */
BleGattcRegisterNotification(int clientId, BtGattCharacteristic characteristic, bool enable)755 int BleGattcRegisterNotification(int clientId, BtGattCharacteristic characteristic, bool enable)
756 {
757     HILOGI("clientId:%{public}d, enable:%{public}d", clientId, enable);
758     std::shared_ptr<GattClient> client = nullptr;
759     GattCharacteristic *tmpCharac = GattcFindCharacteristic(clientId, client, characteristic);
760     if (tmpCharac == nullptr || client == nullptr) {
761         HILOGE("find characteristic fail.");
762         return OHOS_BT_STATUS_FAIL;
763     }
764 
765     int result = client->SetNotifyCharacteristic(*tmpCharac, enable);
766     HILOGI("clientId: %{public}d, result: %{public}d", clientId, result);
767     return GetGattcResult(result);
768 }
769 }  // namespace Bluetooth
770 }  // namespace OHOS
771 #ifdef __cplusplus
772 }
773 #endif
774 /** @} */