2 // Copyright (C) 2015 Google, Inc.
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at:
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 #define LOG_TAG "bt_gatts"
19 #include "gatt_server_old.h"
27 #include <condition_variable>
33 #include <unordered_map>
36 #include <hardware/bluetooth.h>
37 #include <hardware/bt_gatt.h>
39 #include "service/hal/bluetooth_interface.h"
40 #include "service/logging_helpers.h"
43 #include "osi/include/log.h"
44 #include "osi/include/osi.h"
49 const size_t kMaxGattAttributeSize = 512;
50 // TODO(icoolidge): Difficult to generalize without knowing how many attributes.
51 const int kNumBlueDroidHandles = 60;
53 // TODO(icoolidge): Support multiple instances
54 // TODO(armansito): Remove this variable. No point of having this if
55 // each bluetooth::gatt::Server instance already keeps a pointer to the
56 // ServerInternals that is associated with it (which is much cleaner). It looks
57 // like this variable exists because the btif callbacks don't allow the
58 // upper-layer to pass user data to them. We could:
60 // 1. Fix the btif callbacks so that some sort of continuation can be
61 // attached to a callback. This might be a long shot since the callback
62 // interface doesn't allow more than one caller to register its own callbacks
63 // (which might be what we want though, since this would make the API more
66 // 2. Allow creation of Server objects using a factory method that returns
67 // the result asynchronously in a base::Callback. The RegisterServerCallback
68 // provides an |app_uuid|, which can be used to store callback structures in
69 // a map and lazily instantiate the Server and invoke the correct callback.
70 // This is a general pattern that we should use throughout the daemon, since
71 // all operations can timeout or fail and this is best reported in an
72 // asynchronous base::Callback.
74 static bluetooth::gatt::ServerInternals *g_internal = nullptr;
76 enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
83 struct Characteristic {
86 std::vector<uint8_t> blob;
88 // Support synchronized blob updates by latching under mutex.
89 std::vector<uint8_t> next_blob;
90 bool next_blob_pending;
94 struct ServerInternals {
98 bt_status_t AddCharacteristic(
103 // This maps API attribute UUIDs to BlueDroid handles.
104 std::map<UUID, int> uuid_to_attribute;
106 // The attribute cache, indexed by BlueDroid handles.
107 std::unordered_map<int, Characteristic> characteristics;
109 // Associate a control attribute with its value attribute.
110 std::unordered_map<int, int> controlled_blobs;
112 ScanResults scan_results;
115 const btgatt_interface_t *gatt;
119 btgatt_srvc_id_t service_id;
120 std::set<int> connections;
123 std::condition_variable api_synchronize;
124 int pipefd[kPipeNumEnds];
128 } // namespace bluetooth
132 /** Callback invoked in response to register_server */
133 void RegisterServerCallback(int status, int server_if, bt_uuid_t *app_uuid) {
134 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status,
135 server_if, app_uuid);
137 g_internal->server_if = server_if;
139 btgatt_srvc_id_t service_id;
140 service_id.id.uuid = *app_uuid;
141 service_id.id.inst_id = 0;
142 service_id.is_primary = true;
144 g_internal->gatt->server->add_service(
145 server_if, &service_id, kNumBlueDroidHandles);
148 void ServiceAddedCallback(int status, int server_if, btgatt_srvc_id_t *srvc_id,
150 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d gatt_srvc_id:%u srvc_handle:%d",
151 __func__, status, server_if, srvc_id->id.inst_id, srvc_handle);
153 std::lock_guard<std::mutex> lock(g_internal->lock);
154 g_internal->server_if = server_if;
155 g_internal->service_handle = srvc_handle;
156 g_internal->service_id = *srvc_id;
157 // This finishes the Initialize call.
158 g_internal->api_synchronize.notify_one();
161 void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
162 int attr_handle, int attribute_offset_octets,
164 std::lock_guard<std::mutex> lock(g_internal->lock);
166 bluetooth::gatt::Characteristic &ch = g_internal->characteristics[attr_handle];
168 // Latch next_blob to blob on a 'fresh' read.
169 if (ch.next_blob_pending && attribute_offset_octets == 0 &&
170 ch.blob_section == 0) {
171 std::swap(ch.blob, ch.next_blob);
172 ch.next_blob_pending = false;
175 const size_t blob_offset_octets =
176 std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize);
177 const size_t blob_remaining = ch.blob.size() - blob_offset_octets;
178 const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining);
180 std::string addr(BtAddrString(bda));
182 "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d "
183 "blob_section:%u (is_long:%u)",
184 __func__, conn_id, addr.c_str(), attr_handle, attribute_offset_octets,
185 ch.blob_section, is_long);
187 btgatt_response_t response;
188 response.attr_value.len = 0;
190 if (attribute_offset_octets < static_cast<int>(attribute_size)) {
191 std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets,
192 ch.blob.begin() + blob_offset_octets + attribute_size,
193 response.attr_value.value);
194 response.attr_value.len = attribute_size - attribute_offset_octets;
197 response.attr_value.handle = attr_handle;
198 response.attr_value.offset = attribute_offset_octets;
199 response.attr_value.auth_req = 0;
200 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
203 void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
204 int attr_handle, int attribute_offset, int length,
205 bool need_rsp, bool is_prep, uint8_t *value) {
206 std::string addr(BtAddrString(bda));
208 "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d "
210 "need_resp:%u is_prep:%u",
211 __func__, conn_id, addr.c_str(), trans_id, attr_handle, attribute_offset,
212 length, need_rsp, is_prep);
214 std::lock_guard<std::mutex> lock(g_internal->lock);
216 bluetooth::gatt::Characteristic &ch =
217 g_internal->characteristics[attr_handle];
219 ch.blob.resize(attribute_offset + length);
221 std::copy(value, value + length, ch.blob.begin() + attribute_offset);
223 auto target_blob = g_internal->controlled_blobs.find(attr_handle);
224 // If this is a control attribute, adjust offset of the target blob.
225 if (target_blob != g_internal->controlled_blobs.end() &&
226 ch.blob.size() == 1u) {
227 g_internal->characteristics[target_blob->second].blob_section = ch.blob[0];
228 LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__,
229 target_blob->second, ch.blob[0]);
230 } else if (!is_prep) {
231 // This is a single frame characteristic write.
232 // Notify upwards because we're done now.
233 const bluetooth::UUID::UUID128Bit &attr_uuid = ch.uuid.GetFullBigEndian();
234 int status = write(g_internal->pipefd[kPipeWriteEnd], attr_uuid.data(),
237 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
239 // This is a multi-frame characteristic write.
240 // Wait for an 'RequestExecWriteCallback' to notify completion.
241 g_internal->last_write = ch.uuid;
244 // Respond only if needed.
245 if (!need_rsp) return;
247 btgatt_response_t response;
248 response.attr_value.handle = attr_handle;
249 response.attr_value.offset = attribute_offset;
250 response.attr_value.len = length;
251 response.attr_value.auth_req = 0;
252 // Provide written data back to sender for the response.
253 // Remote stacks use this to validate the success of the write.
254 std::copy(value, value + length, response.attr_value.value);
255 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
258 void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
260 std::string addr(BtAddrString(bda));
261 LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__,
262 conn_id, addr.c_str(), trans_id, exec_write);
264 // This 'response' data is unused for ExecWriteResponses.
265 // It is only used to pass BlueDroid argument validation.
266 btgatt_response_t response = {};
267 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
272 std::lock_guard<std::mutex> lock(g_internal->lock);
273 // Communicate the attribute UUID as notification of a write update.
274 const bluetooth::UUID::UUID128Bit uuid =
275 g_internal->last_write.GetFullBigEndian();
276 int status = write(g_internal->pipefd[kPipeWriteEnd],
277 uuid.data(), uuid.size());
279 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
282 void ConnectionCallback(int conn_id, int server_if, int connected,
284 std::string addr(BtAddrString(bda));
285 LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s",
286 __func__, conn_id, server_if, connected, addr.c_str());
287 if (connected == 1) {
288 g_internal->connections.insert(conn_id);
289 } else if (connected == 0) {
290 g_internal->connections.erase(conn_id);
294 void CharacteristicAddedCallback(int status, int server_if, bt_uuid_t *uuid,
295 int srvc_handle, int char_handle) {
297 "%s: status:%d server_if:%d service_handle:%d char_handle:%d", __func__,
298 status, server_if, srvc_handle, char_handle);
300 bluetooth::UUID id(*uuid);
302 std::lock_guard<std::mutex> lock(g_internal->lock);
304 g_internal->uuid_to_attribute[id] = char_handle;
305 g_internal->characteristics[char_handle].uuid = id;
306 g_internal->characteristics[char_handle].blob_section = 0;
308 // This terminates an AddCharacteristic.
309 g_internal->api_synchronize.notify_one();
312 void DescriptorAddedCallback(int status, int server_if, bt_uuid_t *uuid,
313 int srvc_handle, int descr_handle) {
315 "%s: status:%d server_if:%d service_handle:%d uuid[0]:%u "
317 __func__, status, server_if, srvc_handle, uuid->uu[0], descr_handle);
320 void ServiceStartedCallback(int status, int server_if, int srvc_handle) {
321 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
322 status, server_if, srvc_handle);
324 // The UUID provided here is unimportant, and is only used to satisfy
326 // It must be different than any other registered UUID.
327 bt_uuid_t client_id = g_internal->service_id.id.uuid;
330 bt_status_t btstat = g_internal->gatt->client->register_client(&client_id);
331 if (btstat != BT_STATUS_SUCCESS) {
332 LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__);
336 void RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) {
337 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status,
338 client_if, app_uuid->uu[0]);
339 g_internal->client_if = client_if;
341 // Setup our advertisement. This has no callback.
342 bt_status_t btstat = g_internal->gatt->client->set_adv_data(
343 client_if, false, /* beacon, not scan response */
345 false, /* no txpower */
348 0, nullptr, /* no mfg data */
349 0, nullptr, /* no service data */
350 0, nullptr /* no service id yet */);
351 if (btstat != BT_STATUS_SUCCESS) {
352 LOG_ERROR(LOG_TAG, "Failed to set advertising data");
356 // TODO(icoolidge): Deprecated, use multi-adv interface.
357 // This calls back to ListenCallback.
358 btstat = g_internal->gatt->client->listen(client_if, true);
359 if (btstat != BT_STATUS_SUCCESS) {
360 LOG_ERROR(LOG_TAG, "Failed to start listening");
364 void ListenCallback(int status, int client_if) {
365 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d", __func__, status, client_if);
366 // This terminates a Start call.
367 std::lock_guard<std::mutex> lock(g_internal->lock);
368 g_internal->api_synchronize.notify_one();
371 void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
372 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
373 status, server_if, srvc_handle);
374 // This terminates a Stop call.
375 // TODO(icoolidge): make this symmetric with start
376 std::lock_guard<std::mutex> lock(g_internal->lock);
377 g_internal->api_synchronize.notify_one();
380 void ScanResultCallback(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data) {
381 std::string addr(BtAddrString(bda));
383 std::lock_guard<std::mutex> lock(g_internal->lock);
384 g_internal->scan_results[addr] = rssi;
387 void ClientConnectCallback(int conn_id, int status, int client_if,
389 std::string addr(BtAddrString(bda));
390 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
391 conn_id, status, client_if, addr.c_str());
394 void ClientDisconnectCallback(int conn_id, int status, int client_if,
396 std::string addr(BtAddrString(bda));
397 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
398 conn_id, status, client_if, addr.c_str());
401 void IndicationSentCallback(UNUSED_ATTR int conn_id,
402 UNUSED_ATTR int status) {
403 // TODO(icoolidge): what to do
406 void ResponseConfirmationCallback(UNUSED_ATTR int status,
407 UNUSED_ATTR int handle) {
408 // TODO(icoolidge): what to do
411 const btgatt_server_callbacks_t gatt_server_callbacks = {
412 RegisterServerCallback,
414 ServiceAddedCallback,
415 nullptr, /* included_service_added_cb */
416 CharacteristicAddedCallback,
417 DescriptorAddedCallback,
418 ServiceStartedCallback,
419 ServiceStoppedCallback,
420 nullptr, /* service_deleted_cb */
422 RequestWriteCallback,
423 RequestExecWriteCallback,
424 ResponseConfirmationCallback,
425 IndicationSentCallback,
426 nullptr, /* congestion_cb*/
427 nullptr, /* mtu_changed_cb */
430 // TODO(eisenbach): Refactor GATT interface to not require servers
431 // to refer to the client interface.
432 const btgatt_client_callbacks_t gatt_client_callbacks = {
433 RegisterClientCallback,
435 ClientConnectCallback,
436 ClientDisconnectCallback,
437 nullptr, /* search_complete_cb; */
438 nullptr, /* search_result_cb; */
439 nullptr, /* get_characteristic_cb; */
440 nullptr, /* get_descriptor_cb; */
441 nullptr, /* get_included_service_cb; */
442 nullptr, /* register_for_notification_cb; */
443 nullptr, /* notify_cb; */
444 nullptr, /* read_characteristic_cb; */
445 nullptr, /* write_characteristic_cb; */
446 nullptr, /* read_descriptor_cb; */
447 nullptr, /* write_descriptor_cb; */
448 nullptr, /* execute_write_cb; */
449 nullptr, /* read_remote_rssi_cb; */
451 nullptr, /* configure_mtu_cb; */
452 nullptr, /* scan_filter_cfg_cb; */
453 nullptr, /* scan_filter_param_cb; */
454 nullptr, /* scan_filter_status_cb; */
455 nullptr, /* multi_adv_enable_cb */
456 nullptr, /* multi_adv_update_cb; */
457 nullptr, /* multi_adv_data_cb*/
458 nullptr, /* multi_adv_disable_cb; */
459 nullptr, /* congestion_cb; */
460 nullptr, /* batchscan_cfg_storage_cb; */
461 nullptr, /* batchscan_enb_disable_cb; */
462 nullptr, /* batchscan_reports_cb; */
463 nullptr, /* batchscan_threshold_cb; */
464 nullptr, /* track_adv_event_cb; */
465 nullptr, /* scan_parameter_setup_completed_cb; */
468 const btgatt_callbacks_t gatt_callbacks = {
469 /** Set to sizeof(btgatt_callbacks_t) */
470 sizeof(btgatt_callbacks_t),
472 /** GATT Client callbacks */
473 &gatt_client_callbacks,
475 /** GATT Server callbacks */
476 &gatt_server_callbacks};
480 namespace bluetooth {
483 int ServerInternals::Initialize() {
484 // Get the interface to the GATT profile.
485 const bt_interface_t* bt_iface =
486 hal::BluetoothInterface::Get()->GetHALInterface();
487 gatt = reinterpret_cast<const btgatt_interface_t *>(
488 bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
490 LOG_ERROR(LOG_TAG, "Error getting GATT interface");
494 bt_status_t btstat = gatt->init(&gatt_callbacks);
495 if (btstat != BT_STATUS_SUCCESS) {
496 LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface");
500 int status = pipe(pipefd);
502 LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno));
509 bt_status_t ServerInternals::AddCharacteristic(
513 bt_uuid_t c_uuid = uuid.GetBlueDroid();
514 return gatt->server->add_characteristic(
515 server_if, service_handle, &c_uuid, properties, permissions);
518 ServerInternals::ServerInternals()
523 pipefd{INVALID_FD, INVALID_FD} {}
525 ServerInternals::~ServerInternals() {
526 if (pipefd[0] != INVALID_FD)
528 if (pipefd[1] != INVALID_FD)
531 gatt->server->delete_service(server_if, service_handle);
532 gatt->server->unregister_server(server_if);
533 gatt->client->unregister_client(client_if);
536 Server::Server() : internal_(nullptr) {}
540 bool Server::Initialize(const UUID& service_id, int* gatt_pipe) {
541 internal_.reset(new ServerInternals);
543 LOG_ERROR(LOG_TAG, "Error creating internals");
546 g_internal = internal_.get();
548 std::unique_lock<std::mutex> lock(internal_->lock);
549 int status = internal_->Initialize();
551 LOG_ERROR(LOG_TAG, "Error initializing internals");
555 bt_uuid_t uuid = service_id.GetBlueDroid();
557 bt_status_t btstat = internal_->gatt->server->register_server(&uuid);
558 if (btstat != BT_STATUS_SUCCESS) {
559 LOG_ERROR(LOG_TAG, "Failed to register server");
563 internal_->api_synchronize.wait(lock);
564 // TODO(icoolidge): Better error handling.
565 if (internal_->server_if == 0) {
566 LOG_ERROR(LOG_TAG, "Initialization of server failed");
570 *gatt_pipe = internal_->pipefd[kPipeReadEnd];
571 LOG_INFO(LOG_TAG, "Server Initialize succeeded");
575 bool Server::SetAdvertisement(const std::vector<UUID>& ids,
576 const std::vector<uint8_t>& service_data,
577 const std::vector<uint8_t>& manufacturer_data,
578 bool transmit_name) {
579 std::vector<uint8_t> id_data;
580 auto mutable_manufacturer_data = manufacturer_data;
581 auto mutable_service_data = service_data;
583 for (const UUID &id : ids) {
584 const auto le_id = id.GetFullLittleEndian();
585 id_data.insert(id_data.end(), le_id.begin(), le_id.end());
588 std::lock_guard<std::mutex> lock(internal_->lock);
590 // Setup our advertisement. This has no callback.
591 bt_status_t btstat = internal_->gatt->client->set_adv_data(
592 internal_->client_if, false, /* beacon, not scan response */
593 transmit_name, /* name */
594 false, /* no txpower */
597 mutable_manufacturer_data.size(),
598 reinterpret_cast<char *>(mutable_manufacturer_data.data()),
599 mutable_service_data.size(),
600 reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(),
601 reinterpret_cast<char *>(id_data.data()));
602 if (btstat != BT_STATUS_SUCCESS) {
603 LOG_ERROR(LOG_TAG, "Failed to set advertising data");
609 bool Server::SetScanResponse(const std::vector<UUID>& ids,
610 const std::vector<uint8_t>& service_data,
611 const std::vector<uint8_t>& manufacturer_data,
612 bool transmit_name) {
613 std::vector<uint8_t> id_data;
614 auto mutable_manufacturer_data = manufacturer_data;
615 auto mutable_service_data = service_data;
617 for (const UUID &id : ids) {
618 const auto le_id = id.GetFullLittleEndian();
619 id_data.insert(id_data.end(), le_id.begin(), le_id.end());
622 std::lock_guard<std::mutex> lock(internal_->lock);
624 // Setup our advertisement. This has no callback.
625 bt_status_t btstat = internal_->gatt->client->set_adv_data(
626 internal_->client_if, true, /* scan response */
627 transmit_name, /* name */
628 false, /* no txpower */
631 mutable_manufacturer_data.size(),
632 reinterpret_cast<char *>(mutable_manufacturer_data.data()),
633 mutable_service_data.size(),
634 reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(),
635 reinterpret_cast<char *>(id_data.data()));
636 if (btstat != BT_STATUS_SUCCESS) {
637 LOG_ERROR(LOG_TAG, "Failed to set scan response data");
643 bool Server::AddCharacteristic(
644 const UUID &id, int properties, int permissions) {
645 std::unique_lock<std::mutex> lock(internal_->lock);
646 bt_status_t btstat = internal_->AddCharacteristic(
647 id, properties, permissions);
648 if (btstat != BT_STATUS_SUCCESS) {
649 LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x",
650 internal_->service_handle);
653 internal_->api_synchronize.wait(lock);
654 const int handle = internal_->uuid_to_attribute[id];
655 internal_->characteristics[handle].notify = properties & kPropertyNotify;
659 bool Server::AddBlob(const UUID &id, const UUID &control_id, int properties,
661 std::unique_lock<std::mutex> lock(internal_->lock);
663 // First, add the primary attribute (characteristic value)
664 bt_status_t btstat = internal_->AddCharacteristic(
665 id, properties, permissions);
666 if (btstat != BT_STATUS_SUCCESS) {
667 LOG_ERROR(LOG_TAG, "Failed to set scan response data");
671 internal_->api_synchronize.wait(lock);
673 // Next, add the secondary attribute (blob control).
674 // Control attributes have fixed permissions/properties.
675 btstat = internal_->AddCharacteristic(
677 kPropertyRead | kPropertyWrite,
678 kPermissionRead | kPermissionWrite);
679 internal_->api_synchronize.wait(lock);
681 // Finally, associate the control attribute with the value attribute.
682 // Also, initialize the control attribute to a readable zero.
683 const int control_attribute = internal_->uuid_to_attribute[control_id];
684 const int blob_attribute = internal_->uuid_to_attribute[id];
685 internal_->controlled_blobs[control_attribute] = blob_attribute;
686 internal_->characteristics[blob_attribute].notify =
687 properties & kPropertyNotify;
689 Characteristic &ctrl = internal_->characteristics[control_attribute];
690 ctrl.next_blob.clear();
691 ctrl.next_blob.push_back(0);
692 ctrl.next_blob_pending = true;
693 ctrl.blob_section = 0;
698 bool Server::Start() {
699 std::unique_lock<std::mutex> lock(internal_->lock);
700 bt_status_t btstat = internal_->gatt->server->start_service(
701 internal_->server_if, internal_->service_handle, GATT_TRANSPORT_LE);
702 if (btstat != BT_STATUS_SUCCESS) {
703 LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x",
704 internal_->service_handle);
707 internal_->api_synchronize.wait(lock);
711 bool Server::Stop() {
712 std::unique_lock<std::mutex> lock(internal_->lock);
713 bt_status_t btstat = internal_->gatt->server->stop_service(
714 internal_->server_if, internal_->service_handle);
715 if (btstat != BT_STATUS_SUCCESS) {
716 LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x",
717 internal_->service_handle);
720 internal_->api_synchronize.wait(lock);
724 bool Server::ScanEnable() {
725 bt_status_t btstat = internal_->gatt->client->scan(true);
727 LOG_ERROR(LOG_TAG, "Enable scan failed: %d", btstat);
733 bool Server::ScanDisable() {
734 bt_status_t btstat = internal_->gatt->client->scan(false);
736 LOG_ERROR(LOG_TAG, "Disable scan failed: %d", btstat);
742 bool Server::GetScanResults(ScanResults *results) {
743 std::lock_guard<std::mutex> lock(internal_->lock);
744 *results = internal_->scan_results;
748 bool Server::SetCharacteristicValue(const UUID &id,
749 const std::vector<uint8_t> &value) {
750 std::lock_guard<std::mutex> lock(internal_->lock);
751 const int attribute_id = internal_->uuid_to_attribute[id];
752 Characteristic &ch = internal_->characteristics[attribute_id];
753 ch.next_blob = value;
754 ch.next_blob_pending = true;
759 for (auto connection : internal_->connections) {
761 internal_->gatt->server->send_indication(internal_->server_if,
771 bool Server::GetCharacteristicValue(const UUID &id, std::vector<uint8_t> *value) {
772 std::lock_guard<std::mutex> lock(internal_->lock);
773 const int attribute_id = internal_->uuid_to_attribute[id];
774 *value = internal_->characteristics[attribute_id].blob;
779 } // namespace bluetooth