10f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 20f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// Copyright (C) 2015 Google, Inc. 30f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 40f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// Licensed under the Apache License, Version 2.0 (the "License"); 50f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// you may not use this file except in compliance with the License. 60f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// You may obtain a copy of the License at: 70f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 80f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// http://www.apache.org/licenses/LICENSE-2.0 90f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// Unless required by applicable law or agreed to in writing, software 110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// distributed under the License is distributed on an "AS IS" BASIS, 120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// See the License for the specific language governing permissions and 140f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// limitations under the License. 150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#define LOG_TAG "bt_gatts" 180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 190f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include "gatt_server_old.h" 200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <stdio.h> 220f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <stdlib.h> 230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <unistd.h> 240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <algorithm> 260f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <array> 270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <condition_variable> 280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <map> 290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <memory> 300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <mutex> 310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <set> 320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <string> 330f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <unordered_map> 340f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <vector> 350f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 360f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <hardware/bluetooth.h> 370f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include <hardware/bt_gatt.h> 380f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 390f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include "service/hal/bluetooth_interface.h" 400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include "service/logging_helpers.h" 410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 420f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayextern "C" { 430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include "osi/include/log.h" 440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray#include "osi/include/osi.h" 450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} // extern "C" 460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraynamespace { 480f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 490f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayconst size_t kMaxGattAttributeSize = 512; 500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// TODO(icoolidge): Difficult to generalize without knowing how many attributes. 510f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayconst int kNumBlueDroidHandles = 60; 520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// TODO(icoolidge): Support multiple instances 540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// TODO(armansito): Remove this variable. No point of having this if 550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// each bluetooth::gatt::Server instance already keeps a pointer to the 560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// ServerInternals that is associated with it (which is much cleaner). It looks 570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// like this variable exists because the btif callbacks don't allow the 580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// upper-layer to pass user data to them. We could: 590f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 1. Fix the btif callbacks so that some sort of continuation can be 610f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// attached to a callback. This might be a long shot since the callback 620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// interface doesn't allow more than one caller to register its own callbacks 630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// (which might be what we want though, since this would make the API more 640f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// flexible). 650f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 660f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 2. Allow creation of Server objects using a factory method that returns 670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// the result asynchronously in a base::Callback. The RegisterServerCallback 680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// provides an |app_uuid|, which can be used to store callback structures in 690f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// a map and lazily instantiate the Server and invoke the correct callback. 700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// This is a general pattern that we should use throughout the daemon, since 710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// all operations can timeout or fail and this is best reported in an 720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// asynchronous base::Callback. 730f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// 740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraystatic bluetooth::gatt::ServerInternals *g_internal = nullptr; 750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 760f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayenum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 }; 770f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 780f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} // namespace 790f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraynamespace bluetooth { 810f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraynamespace gatt { 820f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 830f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraystruct Characteristic { 840f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray UUID uuid; 850f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int blob_section; 860f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::vector<uint8_t> blob; 870f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 880f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Support synchronized blob updates by latching under mutex. 890f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::vector<uint8_t> next_blob; 900f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bool next_blob_pending; 910f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bool notify; 920f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray}; 930f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 940f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraystruct ServerInternals { 950f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ServerInternals(); 960f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ~ServerInternals(); 970f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int Initialize(); 980f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t AddCharacteristic( 990f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const UUID& uuid, 1000f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int properties, 1010f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int permissions); 1020f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1030f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This maps API attribute UUIDs to BlueDroid handles. 1040f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::map<UUID, int> uuid_to_attribute; 1050f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1060f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // The attribute cache, indexed by BlueDroid handles. 1070f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::unordered_map<int, Characteristic> characteristics; 1080f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1090f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Associate a control attribute with its value attribute. 1100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::unordered_map<int, int> controlled_blobs; 1110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ScanResults scan_results; 1130f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1140f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray UUID last_write; 1150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const btgatt_interface_t *gatt; 1160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int server_if; 1170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int client_if; 1180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int service_handle; 1190f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray btgatt_srvc_id_t service_id; 1200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::set<int> connections; 1210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1220f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::mutex lock; 1230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::condition_variable api_synchronize; 1240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int pipefd[kPipeNumEnds]; 1250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray}; 1260f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} // namespace gatt 1280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} // namespace bluetooth 1290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraynamespace { 1310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray/** Callback invoked in response to register_server */ 1330f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid RegisterServerCallback(int status, int server_if, bt_uuid_t *app_uuid) { 1340f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status, 1350f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray server_if, app_uuid); 1360f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1370f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->server_if = server_if; 1380f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1390f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray btgatt_srvc_id_t service_id; 1400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray service_id.id.uuid = *app_uuid; 1410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray service_id.id.inst_id = 0; 1420f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray service_id.is_primary = true; 1430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->gatt->server->add_service( 1450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray server_if, &service_id, kNumBlueDroidHandles); 1460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 1470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1480f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ServiceAddedCallback(int status, int server_if, btgatt_srvc_id_t *srvc_id, 1490f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int srvc_handle) { 1500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d gatt_srvc_id:%u srvc_handle:%d", 1510f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray __func__, status, server_if, srvc_id->id.inst_id, srvc_handle); 1520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 1540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->server_if = server_if; 1550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->service_handle = srvc_handle; 1560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->service_id = *srvc_id; 1570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This finishes the Initialize call. 1580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->api_synchronize.notify_one(); 1590f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 1600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1610f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, 1620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int attr_handle, int attribute_offset_octets, 1630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bool is_long) { 1640f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 1650f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1660f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bluetooth::gatt::Characteristic &ch = g_internal->characteristics[attr_handle]; 1670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Latch next_blob to blob on a 'fresh' read. 1690f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (ch.next_blob_pending && attribute_offset_octets == 0 && 1700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.blob_section == 0) { 1710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::swap(ch.blob, ch.next_blob); 1720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.next_blob_pending = false; 1730f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 1740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const size_t blob_offset_octets = 1760f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize); 1770f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const size_t blob_remaining = ch.blob.size() - blob_offset_octets; 1780f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining); 1790f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::string addr(BtAddrString(bda)); 1810f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, 1820f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d " 1830f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "blob_section:%u (is_long:%u)", 1840f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray __func__, conn_id, addr.c_str(), attr_handle, attribute_offset_octets, 1850f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.blob_section, is_long); 1860f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1870f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray btgatt_response_t response; 1880f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.len = 0; 1890f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1900f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (attribute_offset_octets < static_cast<int>(attribute_size)) { 1910f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets, 1920f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.blob.begin() + blob_offset_octets + attribute_size, 1930f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.value); 1940f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.len = attribute_size - attribute_offset_octets; 1950f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 1960f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 1970f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.handle = attr_handle; 1980f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.offset = attribute_offset_octets; 1990f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.auth_req = 0; 2000f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response); 2010f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 2020f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2030f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, 2040f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int attr_handle, int attribute_offset, int length, 2050f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bool need_rsp, bool is_prep, uint8_t *value) { 2060f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::string addr(BtAddrString(bda)); 2070f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, 2080f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d " 2090f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "length:%d " 2100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "need_resp:%u is_prep:%u", 2110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray __func__, conn_id, addr.c_str(), trans_id, attr_handle, attribute_offset, 2120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray length, need_rsp, is_prep); 2130f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2140f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 2150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bluetooth::gatt::Characteristic &ch = 2170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->characteristics[attr_handle]; 2180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2190f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.blob.resize(attribute_offset + length); 2200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::copy(value, value + length, ch.blob.begin() + attribute_offset); 2220f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray auto target_blob = g_internal->controlled_blobs.find(attr_handle); 2240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // If this is a control attribute, adjust offset of the target blob. 2250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (target_blob != g_internal->controlled_blobs.end() && 2260f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.blob.size() == 1u) { 2270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->characteristics[target_blob->second].blob_section = ch.blob[0]; 2280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__, 2290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray target_blob->second, ch.blob[0]); 2300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } else if (!is_prep) { 2310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This is a single frame characteristic write. 2320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Notify upwards because we're done now. 2330f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const bluetooth::UUID::UUID128Bit &attr_uuid = ch.uuid.GetFullBigEndian(); 234574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov ssize_t status; 235574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], 236574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov attr_uuid.data(), attr_uuid.size())); 2370f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (-1 == status) 2380f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno)); 2390f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } else { 2400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This is a multi-frame characteristic write. 2410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Wait for an 'RequestExecWriteCallback' to notify completion. 2420f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->last_write = ch.uuid; 2430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 2440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Respond only if needed. 2460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (!need_rsp) return; 2470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2480f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray btgatt_response_t response; 2490f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.handle = attr_handle; 2500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.offset = attribute_offset; 2510f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.len = length; 2520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray response.attr_value.auth_req = 0; 2530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Provide written data back to sender for the response. 2540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Remote stacks use this to validate the success of the write. 2550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::copy(value, value + length, response.attr_value.value); 2560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response); 2570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 2580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2590f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, 2600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int exec_write) { 2610f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::string addr(BtAddrString(bda)); 2620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__, 2630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray conn_id, addr.c_str(), trans_id, exec_write); 2640f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2650f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This 'response' data is unused for ExecWriteResponses. 2660f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // It is only used to pass BlueDroid argument validation. 2670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray btgatt_response_t response = {}; 2680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response); 2690f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (!exec_write) 2710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return; 2720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2730f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 2740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Communicate the attribute UUID as notification of a write update. 2750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const bluetooth::UUID::UUID128Bit uuid = 2760f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->last_write.GetFullBigEndian(); 277574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov ssize_t status; 278574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(), 279574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov uuid.size())); 2800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (-1 == status) 2810f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno)); 2820f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 2830f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2840f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ConnectionCallback(int conn_id, int server_if, int connected, 2850f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_bdaddr_t *bda) { 2860f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::string addr(BtAddrString(bda)); 2870f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s", 2880f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray __func__, conn_id, server_if, connected, addr.c_str()); 2890f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (connected == 1) { 2900f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->connections.insert(conn_id); 2910f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } else if (connected == 0) { 2920f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->connections.erase(conn_id); 2930f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 2940f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 2950f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2960f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid CharacteristicAddedCallback(int status, int server_if, bt_uuid_t *uuid, 2970f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int srvc_handle, int char_handle) { 2980f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, 2990f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "%s: status:%d server_if:%d service_handle:%d char_handle:%d", __func__, 3000f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray status, server_if, srvc_handle, char_handle); 3010f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3020f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bluetooth::UUID id(*uuid); 3030f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3040f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 3050f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3060f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->uuid_to_attribute[id] = char_handle; 3070f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->characteristics[char_handle].uuid = id; 3080f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->characteristics[char_handle].blob_section = 0; 3090f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This terminates an AddCharacteristic. 3110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->api_synchronize.notify_one(); 3120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3130f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3140f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid DescriptorAddedCallback(int status, int server_if, bt_uuid_t *uuid, 3150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int srvc_handle, int descr_handle) { 3160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, 3170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "%s: status:%d server_if:%d service_handle:%d uuid[0]:%u " 3180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray "descr_handle:%d", 3190f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray __func__, status, server_if, srvc_handle, uuid->uu[0], descr_handle); 3200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3220f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ServiceStartedCallback(int status, int server_if, int srvc_handle) { 3230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__, 3240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray status, server_if, srvc_handle); 3250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3260f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // The UUID provided here is unimportant, and is only used to satisfy 3270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // BlueDroid. 3280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // It must be different than any other registered UUID. 3290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_uuid_t client_id = g_internal->service_id.id.uuid; 3300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ++client_id.uu[15]; 3310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = g_internal->gatt->client->register_client(&client_id); 3330f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 3340f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__); 3350f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 3360f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3370f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3380f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) { 3390f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status, 3400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray client_if, app_uuid->uu[0]); 3410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->client_if = client_if; 3420f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Setup our advertisement. This has no callback. 3440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = g_internal->gatt->client->set_adv_data( 3450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray client_if, false, /* beacon, not scan response */ 3460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray false, /* name */ 3470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray false, /* no txpower */ 3480f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2, 2, /* interval */ 3490f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 0, /* appearance */ 3500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 0, nullptr, /* no mfg data */ 3510f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 0, nullptr, /* no service data */ 3520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 0, nullptr /* no service id yet */); 3530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 3540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to set advertising data"); 3550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return; 3560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 3570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // TODO(icoolidge): Deprecated, use multi-adv interface. 3590f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This calls back to ListenCallback. 3600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray btstat = g_internal->gatt->client->listen(client_if, true); 3610f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 3620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to start listening"); 3630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 3640f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3650f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3660f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ListenCallback(int status, int client_if) { 3670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d", __func__, status, client_if); 3680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This terminates a Start call. 3690f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 3700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->api_synchronize.notify_one(); 3710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3730f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ServiceStoppedCallback(int status, int server_if, int srvc_handle) { 3740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__, 3750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray status, server_if, srvc_handle); 3760f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // This terminates a Stop call. 3770f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // TODO(icoolidge): make this symmetric with start 3780f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 3790f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->api_synchronize.notify_one(); 3800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3810f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3820f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ScanResultCallback(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data) { 3830f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::string addr(BtAddrString(bda)); 3840f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray (void)adv_data; 3850f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(g_internal->lock); 3860f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal->scan_results[addr] = rssi; 3870f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3880f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3890f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ClientConnectCallback(int conn_id, int status, int client_if, 3900f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_bdaddr_t *bda) { 3910f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::string addr(BtAddrString(bda)); 3920f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, 3930f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray conn_id, status, client_if, addr.c_str()); 3940f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 3950f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 3960f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ClientDisconnectCallback(int conn_id, int status, int client_if, 3970f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_bdaddr_t *bda) { 3980f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::string addr(BtAddrString(bda)); 3990f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, 4000f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray conn_id, status, client_if, addr.c_str()); 4010f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 4020f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4030f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid IndicationSentCallback(UNUSED_ATTR int conn_id, 4040f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray UNUSED_ATTR int status) { 4050f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // TODO(icoolidge): what to do 4060f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 4070f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4080f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayvoid ResponseConfirmationCallback(UNUSED_ATTR int status, 4090f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray UNUSED_ATTR int handle) { 4100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // TODO(icoolidge): what to do 4110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 4120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4130f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayconst btgatt_server_callbacks_t gatt_server_callbacks = { 4140f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray RegisterServerCallback, 4150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ConnectionCallback, 4160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ServiceAddedCallback, 4170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* included_service_added_cb */ 4180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray CharacteristicAddedCallback, 4190f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray DescriptorAddedCallback, 4200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ServiceStartedCallback, 4210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ServiceStoppedCallback, 4220f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* service_deleted_cb */ 4230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray RequestReadCallback, 4240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray RequestWriteCallback, 4250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray RequestExecWriteCallback, 4260f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ResponseConfirmationCallback, 4270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray IndicationSentCallback, 4280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* congestion_cb*/ 4290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* mtu_changed_cb */ 4300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray}; 4310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// TODO(eisenbach): Refactor GATT interface to not require servers 4330f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray// to refer to the client interface. 4340f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayconst btgatt_client_callbacks_t gatt_client_callbacks = { 4350f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray RegisterClientCallback, 4360f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ScanResultCallback, 4370f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ClientConnectCallback, 4380f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ClientDisconnectCallback, 4390f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* search_complete_cb; */ 4400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* register_for_notification_cb; */ 4410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* notify_cb; */ 4420f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* read_characteristic_cb; */ 4430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* write_characteristic_cb; */ 4440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* read_descriptor_cb; */ 4450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* write_descriptor_cb; */ 4460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* execute_write_cb; */ 4470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* read_remote_rssi_cb; */ 4480f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ListenCallback, 4490f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* configure_mtu_cb; */ 4500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* scan_filter_cfg_cb; */ 4510f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* scan_filter_param_cb; */ 4520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* scan_filter_status_cb; */ 4530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* multi_adv_enable_cb */ 4540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* multi_adv_update_cb; */ 4550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* multi_adv_data_cb*/ 4560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* multi_adv_disable_cb; */ 4570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* congestion_cb; */ 4580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* batchscan_cfg_storage_cb; */ 4590f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* batchscan_enb_disable_cb; */ 4600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* batchscan_reports_cb; */ 4610f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* batchscan_threshold_cb; */ 4620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* track_adv_event_cb; */ 4630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray nullptr, /* scan_parameter_setup_completed_cb; */ 4646859e0c7e3e20b1d1725b360378b546dd73dcb90Jakub Pawlowski nullptr, /* get_gatt_db_cb; */ 4650bd8fa5b24103f5376afb4ddd593ecb1a6a2588cJakub Pawlowski nullptr, /* services_removed_cb */ 4660bd8fa5b24103f5376afb4ddd593ecb1a6a2588cJakub Pawlowski nullptr, /* services_added_cb */ 4670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray}; 4680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4690f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayconst btgatt_callbacks_t gatt_callbacks = { 4700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray /** Set to sizeof(btgatt_callbacks_t) */ 4710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray sizeof(btgatt_callbacks_t), 4720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4730f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray /** GATT Client callbacks */ 4740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray &gatt_client_callbacks, 4750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4760f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray /** GATT Server callbacks */ 4770f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray &gatt_server_callbacks}; 4780f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4790f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} // namespace 4800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4810f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraynamespace bluetooth { 4820f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraynamespace gatt { 4830f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4840f2d4897046f037a9f181f47f3d349a9dd646478Arman Ugurayint ServerInternals::Initialize() { 4850f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Get the interface to the GATT profile. 4860f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const bt_interface_t* bt_iface = 4870f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray hal::BluetoothInterface::Get()->GetHALInterface(); 4880f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray gatt = reinterpret_cast<const btgatt_interface_t *>( 4890f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_iface->get_profile_interface(BT_PROFILE_GATT_ID)); 4900f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (!gatt) { 4910f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Error getting GATT interface"); 4920f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return -1; 4930f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 4940f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 4950f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = gatt->init(&gatt_callbacks); 4960f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 4970f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface"); 4980f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return -1; 4990f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 5000f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5010f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int status = pipe(pipefd); 5020f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (status == -1) { 5030f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno)); 5040f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return -1; 5050f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 5060f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5070f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return 0; 5080f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 5090f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybt_status_t ServerInternals::AddCharacteristic( 5110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const UUID& uuid, 5120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int properties, 5130f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int permissions) { 5140f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_uuid_t c_uuid = uuid.GetBlueDroid(); 5150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return gatt->server->add_characteristic( 5160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray server_if, service_handle, &c_uuid, properties, permissions); 5170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 5180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5190f2d4897046f037a9f181f47f3d349a9dd646478Arman UgurayServerInternals::ServerInternals() 5200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray : gatt(nullptr), 5210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray server_if(0), 5220f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray client_if(0), 5230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray service_handle(0), 5240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray pipefd{INVALID_FD, INVALID_FD} {} 5250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5260f2d4897046f037a9f181f47f3d349a9dd646478Arman UgurayServerInternals::~ServerInternals() { 5270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (pipefd[0] != INVALID_FD) 5280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray close(pipefd[0]); 5290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (pipefd[1] != INVALID_FD) 5300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray close(pipefd[1]); 5310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray gatt->server->delete_service(server_if, service_handle); 5330f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray gatt->server->unregister_server(server_if); 5340f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray gatt->client->unregister_client(client_if); 5350f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 5360f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5370f2d4897046f037a9f181f47f3d349a9dd646478Arman UgurayServer::Server() : internal_(nullptr) {} 5380f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5390f2d4897046f037a9f181f47f3d349a9dd646478Arman UgurayServer::~Server() {} 5400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::Initialize(const UUID& service_id, int* gatt_pipe) { 5420f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_.reset(new ServerInternals); 5430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (!internal_) { 5440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Error creating internals"); 5450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 5460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 5470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray g_internal = internal_.get(); 5480f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5490f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::unique_lock<std::mutex> lock(internal_->lock); 5500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int status = internal_->Initialize(); 5510f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (status) { 5520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Error initializing internals"); 5530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 5540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 5550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_uuid_t uuid = service_id.GetBlueDroid(); 5570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->gatt->server->register_server(&uuid); 5590f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 5600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to register server"); 5610f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 5620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 5630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5640f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->api_synchronize.wait(lock); 5650f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // TODO(icoolidge): Better error handling. 5660f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (internal_->server_if == 0) { 5670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Initialization of server failed"); 5680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 5690f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 5700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray *gatt_pipe = internal_->pipefd[kPipeReadEnd]; 5720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_INFO(LOG_TAG, "Server Initialize succeeded"); 5730f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 5740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 5750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5760f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::SetAdvertisement(const std::vector<UUID>& ids, 5770f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const std::vector<uint8_t>& service_data, 5780f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const std::vector<uint8_t>& manufacturer_data, 5790f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bool transmit_name) { 5800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::vector<uint8_t> id_data; 5810f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray auto mutable_manufacturer_data = manufacturer_data; 5820f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray auto mutable_service_data = service_data; 5830f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5840f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray for (const UUID &id : ids) { 5850f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const auto le_id = id.GetFullLittleEndian(); 5860f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray id_data.insert(id_data.end(), le_id.begin(), le_id.end()); 5870f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 5880f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5890f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(internal_->lock); 5900f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 5910f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Setup our advertisement. This has no callback. 5920f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->gatt->client->set_adv_data( 5930f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->client_if, false, /* beacon, not scan response */ 5940f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray transmit_name, /* name */ 5950f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray false, /* no txpower */ 5960f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2, 2, /* interval */ 5970f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 0, /* appearance */ 5980f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray mutable_manufacturer_data.size(), 5990f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray reinterpret_cast<char *>(mutable_manufacturer_data.data()), 6000f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray mutable_service_data.size(), 6010f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(), 6020f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray reinterpret_cast<char *>(id_data.data())); 6030f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 6040f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to set advertising data"); 6050f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 6060f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 6070f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 6080f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 6090f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::SetScanResponse(const std::vector<UUID>& ids, 6110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const std::vector<uint8_t>& service_data, 6120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const std::vector<uint8_t>& manufacturer_data, 6130f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bool transmit_name) { 6140f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::vector<uint8_t> id_data; 6150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray auto mutable_manufacturer_data = manufacturer_data; 6160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray auto mutable_service_data = service_data; 6170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray for (const UUID &id : ids) { 6190f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const auto le_id = id.GetFullLittleEndian(); 6200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray id_data.insert(id_data.end(), le_id.begin(), le_id.end()); 6210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 6220f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(internal_->lock); 6240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Setup our advertisement. This has no callback. 6260f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->gatt->client->set_adv_data( 6270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->client_if, true, /* scan response */ 6280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray transmit_name, /* name */ 6290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray false, /* no txpower */ 6300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 2, 2, /* interval */ 6310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 0, /* appearance */ 6320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray mutable_manufacturer_data.size(), 6330f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray reinterpret_cast<char *>(mutable_manufacturer_data.data()), 6340f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray mutable_service_data.size(), 6350f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(), 6360f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray reinterpret_cast<char *>(id_data.data())); 6370f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 6380f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to set scan response data"); 6390f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 6400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 6410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 6420f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 6430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::AddCharacteristic( 6450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const UUID &id, int properties, int permissions) { 6460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::unique_lock<std::mutex> lock(internal_->lock); 6470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->AddCharacteristic( 6480f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray id, properties, permissions); 6490f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 6500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x", 6510f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->service_handle); 6520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 6530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 6540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->api_synchronize.wait(lock); 6550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const int handle = internal_->uuid_to_attribute[id]; 6560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->characteristics[handle].notify = properties & kPropertyNotify; 6570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 6580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 6590f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::AddBlob(const UUID &id, const UUID &control_id, int properties, 6610f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray int permissions) { 6620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::unique_lock<std::mutex> lock(internal_->lock); 6630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6640f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // First, add the primary attribute (characteristic value) 6650f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->AddCharacteristic( 6660f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray id, properties, permissions); 6670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 6680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to set scan response data"); 6690f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 6700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 6710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->api_synchronize.wait(lock); 6730f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Next, add the secondary attribute (blob control). 6750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Control attributes have fixed permissions/properties. 6760f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray btstat = internal_->AddCharacteristic( 6770f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray control_id, 6780f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray kPropertyRead | kPropertyWrite, 6790f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray kPermissionRead | kPermissionWrite); 6800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->api_synchronize.wait(lock); 6810f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6820f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Finally, associate the control attribute with the value attribute. 6830f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray // Also, initialize the control attribute to a readable zero. 6840f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const int control_attribute = internal_->uuid_to_attribute[control_id]; 6850f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const int blob_attribute = internal_->uuid_to_attribute[id]; 6860f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->controlled_blobs[control_attribute] = blob_attribute; 6870f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->characteristics[blob_attribute].notify = 6880f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray properties & kPropertyNotify; 6890f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6900f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray Characteristic &ctrl = internal_->characteristics[control_attribute]; 6910f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ctrl.next_blob.clear(); 6920f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ctrl.next_blob.push_back(0); 6930f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ctrl.next_blob_pending = true; 6940f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ctrl.blob_section = 0; 6950f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ctrl.notify = false; 6960f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 6970f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 6980f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 6990f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::Start() { 7000f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::unique_lock<std::mutex> lock(internal_->lock); 7010f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->gatt->server->start_service( 7020f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->server_if, internal_->service_handle, GATT_TRANSPORT_LE); 7030f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 7040f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x", 7050f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->service_handle); 7060f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 7070f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 7080f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->api_synchronize.wait(lock); 7090f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7100f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 7110f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7120f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::Stop() { 7130f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::unique_lock<std::mutex> lock(internal_->lock); 7140f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->gatt->server->stop_service( 7150f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->server_if, internal_->service_handle); 7160f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat != BT_STATUS_SUCCESS) { 7170f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x", 7180f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->service_handle); 7190f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 7200f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 7210f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->api_synchronize.wait(lock); 7220f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7230f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 7240f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7250f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::ScanEnable() { 7260f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->gatt->client->scan(true); 7270f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat) { 7280f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Enable scan failed: %d", btstat); 7290f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 7300f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 7310f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7320f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 7330f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7340f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::ScanDisable() { 7350f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray bt_status_t btstat = internal_->gatt->client->scan(false); 7360f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (btstat) { 7370f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray LOG_ERROR(LOG_TAG, "Disable scan failed: %d", btstat); 7380f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return false; 7390f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 7400f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7410f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 7420f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7430f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::GetScanResults(ScanResults *results) { 7440f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(internal_->lock); 7450f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray *results = internal_->scan_results; 7460f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7470f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 7480f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7490f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::SetCharacteristicValue(const UUID &id, 7500f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const std::vector<uint8_t> &value) { 7510f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(internal_->lock); 7520f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const int attribute_id = internal_->uuid_to_attribute[id]; 7530f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray Characteristic &ch = internal_->characteristics[attribute_id]; 7540f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.next_blob = value; 7550f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray ch.next_blob_pending = true; 7560f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7570f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray if (!ch.notify) 7580f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7590f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7600f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray for (auto connection : internal_->connections) { 7610f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray char dummy = 0; 7620f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray internal_->gatt->server->send_indication(internal_->server_if, 7630f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray attribute_id, 7640f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray connection, 7650f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray sizeof(dummy), 7660f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray true, 7670f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray &dummy); 7680f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray } 7690f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7700f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 7710f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7720f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguraybool Server::GetCharacteristicValue(const UUID &id, std::vector<uint8_t> *value) { 7730f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray std::lock_guard<std::mutex> lock(internal_->lock); 7740f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray const int attribute_id = internal_->uuid_to_attribute[id]; 7750f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray *value = internal_->characteristics[attribute_id].blob; 7760f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray return true; 7770f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} 7780f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray 7790f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} // namespace gatt 7800f2d4897046f037a9f181f47f3d349a9dd646478Arman Uguray} // namespace bluetooth 781