1c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// 2c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// Copyright (C) 2015 Google, Inc. 3c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// 4c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// Licensed under the Apache License, Version 2.0 (the "License"); 5c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// you may not use this file except in compliance with the License. 6c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// You may obtain a copy of the License at: 7c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// 8c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// http://www.apache.org/licenses/LICENSE-2.0 9c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// 10c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// Unless required by applicable law or agreed to in writing, software 11c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// distributed under the License is distributed on an "AS IS" BASIS, 12c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// See the License for the specific language governing permissions and 14c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// limitations under the License. 15c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray// 16c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 17c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray#include "service/low_energy_client.h" 18c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 19c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray#include <base/logging.h> 20c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 2160b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski#include "service/adapter.h" 22a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski#include "service/common/bluetooth/util/address_helper.h" 2382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray#include "service/logging_helpers.h" 2412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray#include "stack/include/bt_types.h" 2512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray#include "stack/include/hcidefs.h" 2612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 27c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Ugurayusing std::lock_guard; 28c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Ugurayusing std::mutex; 29c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 30c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguraynamespace bluetooth { 31c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 3212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraynamespace { 3312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 3482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// 31 + 31 for advertising data and scan response. This is the maximum length 3582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// TODO(armansito): Fix the HAL to return a concatenated blob that contains the 3682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// true length of each field and also provide a length parameter so that we 3782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// can support advertising length extensions in the future. 3882ea72f905565f83116f74d5ccbacea5d710a853Arman Ugurayconst size_t kScanRecordLength = 62; 3982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 4012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman UgurayBLEStatus GetBLEStatus(int status) { 4112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status == BT_STATUS_FAIL) 4212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return BLE_STATUS_FAILURE; 4312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 4412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return static_cast<BLEStatus>(status); 4512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 4612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 4782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// Returns the length of the given scan record array. We have to calculate this 4882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// based on the maximum possible data length and the TLV data. See TODO above 4982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// |kScanRecordLength|. 5082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguraysize_t GetScanRecordLength(uint8_t* bytes) { 5182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray for (size_t i = 0, field_len = 0; i < kScanRecordLength; 5282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray i += (field_len + 1)) { 5382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray field_len = bytes[i]; 5482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 5582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // Assert here that the data returned from the stack is correctly formatted 5682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // in TLV form and that the length of the current field won't exceed the 5782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // total data length. 5882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray CHECK(i + field_len < kScanRecordLength); 5982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 6082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // If the field length is zero and we haven't reached the maximum length, 6182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // then we have found the length, as the stack will pad the data with zeros 6282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // accordingly. 6382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray if (field_len == 0) 6482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray return i; 6582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray } 6682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 6782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // We have reached the end. 6882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray return kScanRecordLength; 6982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray} 7082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 7112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// TODO(armansito): BTIF currently expects each advertising field in a 7212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// specific format passed directly in arguments. We should fix BTIF to accept 7312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// the advertising data directly instead. 7412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraystruct HALAdvertiseData { 7512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray std::vector<uint8_t> manufacturer_data; 7612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray std::vector<uint8_t> service_data; 7712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray std::vector<uint8_t> service_uuid; 7812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}; 7912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 809fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguraybool ProcessUUID(const uint8_t* uuid_data, size_t uuid_len, UUID* out_uuid) { 819fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray // BTIF expects a single 128-bit UUID to be passed in little-endian form, so 829fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray // we need to convert into that from raw data. 839fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray // TODO(armansito): We have three repeated if bodies below only because UUID 849fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray // accepts std::array which requires constexpr lengths. We should just have a 859fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray // single UUID constructor that takes in an std::vector instead. 869fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray if (uuid_len == UUID::kNumBytes16) { 879fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray UUID::UUID16Bit uuid_bytes; 889fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray for (size_t i = 0; i < uuid_len; ++i) 899fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray uuid_bytes[uuid_len - i - 1] = uuid_data[i]; 909fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray *out_uuid = UUID(uuid_bytes); 919fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray } else if (uuid_len == UUID::kNumBytes32) { 929fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray UUID::UUID32Bit uuid_bytes; 939fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray for (size_t i = 0; i < uuid_len; ++i) 949fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray uuid_bytes[uuid_len - i - 1] = uuid_data[i]; 959fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray *out_uuid = UUID(uuid_bytes); 969fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray } else if (uuid_len == UUID::kNumBytes128) { 979fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray UUID::UUID128Bit uuid_bytes; 989fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray for (size_t i = 0; i < uuid_len; ++i) 999fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray uuid_bytes[uuid_len - i - 1] = uuid_data[i]; 1009fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray *out_uuid = UUID(uuid_bytes); 1019fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray } else { 1029fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray LOG(ERROR) << "Invalid UUID length"; 1039fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray return false; 1049fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray } 1059fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray 1069fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray return true; 1079fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray} 1089fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray 109ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panickerbool ProcessServiceData(const uint8_t* data, 1109fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray uint8_t uuid_len, 111a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski HALAdvertiseData* out_data) { 112ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker size_t field_len = data[0]; 113ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 114ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // Minimum packet size should be equal to the uuid length + 1 to include 115ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // the byte for the type of packet 1169fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray if (field_len < uuid_len + 1) { 117ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // Invalid packet size 118ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return false; 119ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } 120ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 121ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker if (!out_data->service_data.empty()) { 122ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // More than one Service Data is not allowed due to the limitations 123ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // of the HAL API. We error in order to make sure there 124ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // is no ambiguity on which data to send. 125ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker VLOG(1) << "More than one Service Data entry not allowed"; 126ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return false; 127ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } 128ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 129ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker const uint8_t* service_uuid = data + 2; 1309fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray UUID uuid; 1319fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray if (!ProcessUUID(service_uuid, uuid_len, &uuid)) 1329fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray return false; 1339fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray 1349fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray UUID::UUID128Bit uuid_bytes = uuid.GetFullLittleEndian(); 1359fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray const std::vector<uint8_t> temp_uuid( 1369fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray uuid_bytes.data(), uuid_bytes.data() + uuid_bytes.size()); 137ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 138ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // This section is to make sure that there is no UUID conflict 139ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker if (out_data->service_uuid.empty()) { 140ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker out_data->service_uuid = temp_uuid; 141ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } else if (out_data->service_uuid != temp_uuid) { 142ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // Mismatch in uuid passed through service data and uuid passed 143ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // through uuid field 144ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker VLOG(1) << "More than one UUID entry not allowed"; 145ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return false; 146a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } // else do nothing as UUID is already properly assigned 147ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 1489fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray // Use + uuid_len + 2 here in order to skip over a 149ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // uuid contained in the beggining of the field 1509fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray const uint8_t* srv_data = data + uuid_len + 2; 151ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 152ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 153ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker out_data->service_data.insert( 154ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker out_data->service_data.begin(), 1559fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray srv_data, srv_data + field_len - uuid_len - 1); 156ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 157ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return true; 158ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker} 159ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 16012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool ProcessAdvertiseData(const AdvertiseData& adv, 16112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray HALAdvertiseData* out_data) { 16212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(out_data); 16312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(out_data->manufacturer_data.empty()); 16412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(out_data->service_data.empty()); 16512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(out_data->service_uuid.empty()); 16612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 16712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray const auto& data = adv.data(); 16812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray size_t len = data.size(); 16912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray for (size_t i = 0, field_len = 0; i < len; i += (field_len + 1)) { 17012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // The length byte is the first byte in the adv. "TLV" format. 17112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray field_len = data[i]; 17212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 17312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // The type byte is the next byte in the adv. "TLV" format. 17412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray uint8_t type = data[i + 1]; 17512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 17612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray switch (type) { 17712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray case HCI_EIR_MANUFACTURER_SPECIFIC_TYPE: { 17812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // TODO(armansito): BTIF doesn't allow setting more than one 17912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // manufacturer-specific data entry. This is something we should fix. For 18012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // now, fail if more than one entry was set. 18112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (!out_data->manufacturer_data.empty()) { 1829fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray LOG(ERROR) << "More than one Manufacturer Specific Data entry not allowed"; 18312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 18412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 18512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 18612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // The value bytes start at the next byte in the "TLV" format. 18712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray const uint8_t* mnf_data = data.data() + i + 2; 18812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_data->manufacturer_data.insert( 18912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_data->manufacturer_data.begin(), 19012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray mnf_data, mnf_data + field_len - 1); 19112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray break; 19212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 193ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_MORE_16BITS_UUID_TYPE: 194ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_COMPLETE_16BITS_UUID_TYPE: 195ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_MORE_32BITS_UUID_TYPE: 196ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_COMPLETE_32BITS_UUID_TYPE: 197ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_MORE_128BITS_UUID_TYPE: 198ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_COMPLETE_128BITS_UUID_TYPE: { 199ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker const uint8_t* uuid_data = data.data() + i + 2; 2009fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray size_t uuid_len = field_len - 1; 2019fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray UUID uuid; 2029fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray if (!ProcessUUID(uuid_data, uuid_len, &uuid)) 2039fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray return false; 2049fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray 2059fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray UUID::UUID128Bit uuid_bytes = uuid.GetFullLittleEndian(); 206ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 207ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker if (!out_data->service_uuid.empty() && 2089fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray memcmp(out_data->service_uuid.data(), 2099fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray uuid_bytes.data(), uuid_bytes.size()) != 0) { 210ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // More than one UUID is not allowed due to the limitations 211ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // of the HAL API. We error in order to make sure there 212ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // is no ambiguity on which UUID to send. Also makes sure that 213ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker // UUID Hasn't been set by service data first 2149fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray LOG(ERROR) << "More than one UUID entry not allowed"; 215ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return false; 216ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } 217ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 218ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker out_data->service_uuid.assign( 2199fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray uuid_bytes.data(), uuid_bytes.data() + UUID::kNumBytes128); 220ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker break; 221ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } 222ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE: { 223ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker if (!ProcessServiceData(data.data() + i, 2, out_data)) 224ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return false; 225ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker break; 226ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } 227ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE: { 228ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker if (!ProcessServiceData(data.data() + i, 4, out_data)) 229ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return false; 230ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker break; 231ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } 232ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker case HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE: { 233ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker if (!ProcessServiceData(data.data() + i, 16, out_data)) 234ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker return false; 235ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker break; 236ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker } 23712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // TODO(armansito): Support other fields. 23812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray default: 23912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray VLOG(1) << "Unrecognized EIR field: " << type; 24012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 24112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 24212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 24312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 24412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return true; 24512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 24612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 24712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// The Bluetooth Core Specification defines time interval (e.g. Page Scan 24812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// Interval, Advertising Interval, etc) units as 0.625 milliseconds (or 1 24912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// Baseband slot). The HAL advertising functions expect the interval in this 25012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// unit. This function maps an AdvertiseSettings::Mode value to the 25112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// corresponding time unit. 25212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayint GetAdvertisingIntervalUnit(AdvertiseSettings::Mode mode) { 25312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray int ms; 25412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 25512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray switch (mode) { 25612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray case AdvertiseSettings::MODE_BALANCED: 25712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray ms = kAdvertisingIntervalMediumMs; 25812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray break; 25912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray case AdvertiseSettings::MODE_LOW_LATENCY: 26012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray ms = kAdvertisingIntervalLowMs; 26112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray break; 26212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray case AdvertiseSettings::MODE_LOW_POWER: 26312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Fall through 26412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray default: 26512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray ms = kAdvertisingIntervalHighMs; 26612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray break; 26712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 26812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 26912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Convert milliseconds Bluetooth units. 27012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return (ms * 1000) / 625; 27112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 27212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 27312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraystruct AdvertiseParams { 27412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray int min_interval; 27512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray int max_interval; 27612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray int event_type; 27712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray int tx_power_level; 27812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray int timeout_s; 27912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}; 28012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 28112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid GetAdvertiseParams(const AdvertiseSettings& settings, bool has_scan_rsp, 28212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray AdvertiseParams* out_params) { 28312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(out_params); 28412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 28512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->min_interval = GetAdvertisingIntervalUnit(settings.mode()); 28612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->max_interval = 28712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->min_interval + kAdvertisingIntervalDeltaUnit; 28812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 28912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (settings.connectable()) 29012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->event_type = kAdvertisingEventTypeConnectable; 29112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray else if (has_scan_rsp) 29212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->event_type = kAdvertisingEventTypeScannable; 29312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray else 29412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->event_type = kAdvertisingEventTypeNonConnectable; 29512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 29612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->tx_power_level = settings.tx_power_level(); 29712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray out_params->timeout_s = settings.timeout().InSeconds(); 29812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 29912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 30012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} // namespace 30112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 30212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// LowEnergyClient implementation 30312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// ======================================================== 30412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 30560b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub PawlowskiLowEnergyClient::LowEnergyClient( 30660b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski Adapter& adapter, const UUID& uuid, int client_id) 30760b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski : adapter_(adapter), 30860b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski app_identifier_(uuid), 309bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray client_id_(client_id), 31012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_data_needs_update_(false), 31112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray scan_rsp_needs_update_(false), 31212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray is_setting_adv_data_(false), 31312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_started_(false), 31412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_start_callback_(nullptr), 315480174f874a664affda33831c904eb3574ae9389Arman Uguray adv_stop_callback_(nullptr), 316480174f874a664affda33831c904eb3574ae9389Arman Uguray scan_started_(false) { 317c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray} 318c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 319c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman UgurayLowEnergyClient::~LowEnergyClient() { 320c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray // Automatically unregister the client. 321bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray VLOG(1) << "LowEnergyClient unregistering client: " << client_id_; 32212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 32312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Unregister as observer so we no longer receive any callbacks. 32412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface::Get()->RemoveClientObserver(this); 32512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 32612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Stop advertising and ignore the result. 32712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface::Get()-> 328bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray GetClientHALInterface()->multi_adv_disable(client_id_); 329c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray hal::BluetoothGattInterface::Get()-> 330bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray GetClientHALInterface()->unregister_client(client_id_); 331480174f874a664affda33831c904eb3574ae9389Arman Uguray 332480174f874a664affda33831c904eb3574ae9389Arman Uguray // Stop any scans started by this client. 333480174f874a664affda33831c904eb3574ae9389Arman Uguray if (scan_started_.load()) 334480174f874a664affda33831c904eb3574ae9389Arman Uguray StopScan(); 335480174f874a664affda33831c904eb3574ae9389Arman Uguray} 336480174f874a664affda33831c904eb3574ae9389Arman Uguray 337a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskibool LowEnergyClient::Connect(std::string address, bool is_direct) { 338a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct; 339a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 340a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski bt_bdaddr_t bda; 341a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski util::BdAddrFromString(address, &bda); 342a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 343a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski bt_status_t status = hal::BluetoothGattInterface::Get()-> 344a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski GetClientHALInterface()->connect(client_id_, &bda, is_direct, 345a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski BT_TRANSPORT_LE); 346a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (status != BT_STATUS_SUCCESS) { 347a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski LOG(ERROR) << "HAL call to connect failed"; 348a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski return false; 349a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 350a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 351a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski return true; 352a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski} 353a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 354a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskibool LowEnergyClient::Disconnect(std::string address) { 355a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski VLOG(2) << __func__ << "Address: " << address; 356a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 357a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski bt_bdaddr_t bda; 358a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski util::BdAddrFromString(address, &bda); 359a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 360a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski std::map<const bt_bdaddr_t, int>::iterator conn_id; 361a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski { 362a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski lock_guard<mutex> lock(connection_fields_lock_); 363a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski conn_id = connection_ids_.find(bda); 364a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (conn_id == connection_ids_.end()) { 365a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski LOG(WARNING) << "Can't disconnect, no existing connection to " << address; 366a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski return false; 367a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 368a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 369a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 370a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski bt_status_t status = hal::BluetoothGattInterface::Get()-> 371a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski GetClientHALInterface()->disconnect(client_id_, &bda, conn_id->second); 372a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (status != BT_STATUS_SUCCESS) { 373a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski LOG(ERROR) << "HAL call to disconnect failed"; 374a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski return false; 375a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 376a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 377a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski return true; 378a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski} 379a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 380a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowskibool LowEnergyClient::SetMtu(std::string address, int mtu) { 381a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski VLOG(2) << __func__ << "Address: " << address 382a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski << " MTU: " << mtu; 383a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 384a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski bt_bdaddr_t bda; 385a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski util::BdAddrFromString(address, &bda); 386a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 387a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski std::map<const bt_bdaddr_t, int>::iterator conn_id; 388a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski { 389a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski lock_guard<mutex> lock(connection_fields_lock_); 390a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski conn_id = connection_ids_.find(bda); 391a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski if (conn_id == connection_ids_.end()) { 392a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski LOG(WARNING) << "Can't set MTU, no existing connection to " << address; 393a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski return false; 394a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski } 395a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski } 396a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 397a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski bt_status_t status = hal::BluetoothGattInterface::Get()-> 398a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski GetClientHALInterface()->configure_mtu(conn_id->second, mtu); 399a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski if (status != BT_STATUS_SUCCESS) { 400a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski LOG(ERROR) << "HAL call to set MTU failed"; 401a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski return false; 402a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski } 403a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 404a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski return true; 405a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski} 406a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 40782ea72f905565f83116f74d5ccbacea5d710a853Arman Ugurayvoid LowEnergyClient::SetDelegate(Delegate* delegate) { 40882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray lock_guard<mutex> lock(delegate_mutex_); 40982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray delegate_ = delegate; 41082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray} 41182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 412480174f874a664affda33831c904eb3574ae9389Arman Uguraybool LowEnergyClient::StartScan(const ScanSettings& settings, 413480174f874a664affda33831c904eb3574ae9389Arman Uguray const std::vector<ScanFilter>& filters) { 414480174f874a664affda33831c904eb3574ae9389Arman Uguray VLOG(2) << __func__; 415480174f874a664affda33831c904eb3574ae9389Arman Uguray 416480174f874a664affda33831c904eb3574ae9389Arman Uguray // Cannot start a scan if the adapter is not enabled. 417480174f874a664affda33831c904eb3574ae9389Arman Uguray if (!adapter_.IsEnabled()) { 418480174f874a664affda33831c904eb3574ae9389Arman Uguray LOG(ERROR) << "Cannot scan while Bluetooth is disabled"; 419480174f874a664affda33831c904eb3574ae9389Arman Uguray return false; 420480174f874a664affda33831c904eb3574ae9389Arman Uguray } 421480174f874a664affda33831c904eb3574ae9389Arman Uguray 422480174f874a664affda33831c904eb3574ae9389Arman Uguray // TODO(jpawlowski): Push settings and filtering logic below the HAL. 423480174f874a664affda33831c904eb3574ae9389Arman Uguray bt_status_t status = hal::BluetoothGattInterface::Get()-> 424480174f874a664affda33831c904eb3574ae9389Arman Uguray StartScan(client_id_); 425480174f874a664affda33831c904eb3574ae9389Arman Uguray if (status != BT_STATUS_SUCCESS) { 426480174f874a664affda33831c904eb3574ae9389Arman Uguray LOG(ERROR) << "Failed to initiate scanning for client: " << client_id_; 427480174f874a664affda33831c904eb3574ae9389Arman Uguray return false; 428480174f874a664affda33831c904eb3574ae9389Arman Uguray } 429480174f874a664affda33831c904eb3574ae9389Arman Uguray 430480174f874a664affda33831c904eb3574ae9389Arman Uguray scan_started_ = true; 431480174f874a664affda33831c904eb3574ae9389Arman Uguray return true; 432480174f874a664affda33831c904eb3574ae9389Arman Uguray} 433480174f874a664affda33831c904eb3574ae9389Arman Uguray 434480174f874a664affda33831c904eb3574ae9389Arman Uguraybool LowEnergyClient::StopScan() { 435480174f874a664affda33831c904eb3574ae9389Arman Uguray VLOG(2) << __func__; 436480174f874a664affda33831c904eb3574ae9389Arman Uguray 437480174f874a664affda33831c904eb3574ae9389Arman Uguray // TODO(armansito): We don't support batch scanning yet so call 438480174f874a664affda33831c904eb3574ae9389Arman Uguray // StopRegularScanForClient directly. In the future we will need to 439480174f874a664affda33831c904eb3574ae9389Arman Uguray // conditionally call a batch scan API here. 440480174f874a664affda33831c904eb3574ae9389Arman Uguray bt_status_t status = hal::BluetoothGattInterface::Get()-> 441480174f874a664affda33831c904eb3574ae9389Arman Uguray StopScan(client_id_); 442480174f874a664affda33831c904eb3574ae9389Arman Uguray if (status != BT_STATUS_SUCCESS) { 443480174f874a664affda33831c904eb3574ae9389Arman Uguray LOG(ERROR) << "Failed to stop scan for client: " << client_id_; 444480174f874a664affda33831c904eb3574ae9389Arman Uguray return false; 445480174f874a664affda33831c904eb3574ae9389Arman Uguray } 446480174f874a664affda33831c904eb3574ae9389Arman Uguray 447480174f874a664affda33831c904eb3574ae9389Arman Uguray scan_started_ = false; 448480174f874a664affda33831c904eb3574ae9389Arman Uguray return true; 449c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray} 450c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 45112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::StartAdvertising(const AdvertiseSettings& settings, 45212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray const AdvertiseData& advertise_data, 45312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray const AdvertiseData& scan_response, 45412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray const StatusCallback& callback) { 45512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray VLOG(2) << __func__; 45612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray lock_guard<mutex> lock(adv_fields_lock_); 45712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 45812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (IsAdvertisingStarted()) { 45912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(WARNING) << "Already advertising"; 46012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 46112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 46212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 46312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (IsStartingAdvertising()) { 46412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(WARNING) << "StartAdvertising already pending"; 46512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 46612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 46712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 46812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (!advertise_data.IsValid()) { 46912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Invalid advertising data"; 47012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 47112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 47212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 47312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (!scan_response.IsValid()) { 47412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Invalid scan response data"; 47512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 47612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 47712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 47812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!adv_data_needs_update_.load()); 47912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!scan_rsp_needs_update_.load()); 48012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 48112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_data_ = advertise_data; 48212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray scan_response_ = scan_response; 483d748ef2bcc24747659dadec242fd5a7a0c8ba3c4Jakub Pawlowski advertise_settings_ = settings; 48412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 48512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray AdvertiseParams params; 48612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray GetAdvertiseParams(settings, !scan_response_.data().empty(), ¶ms); 48712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 48812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray bt_status_t status = hal::BluetoothGattInterface::Get()-> 48912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray GetClientHALInterface()->multi_adv_enable( 490bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray client_id_, 49112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray params.min_interval, 49212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray params.max_interval, 49312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray params.event_type, 49412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray kAdvertisingChannelAll, 49512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray params.tx_power_level, 49612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray params.timeout_s); 49712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status != BT_STATUS_SUCCESS) { 49812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed to initiate call to enable multi-advertising"; 49912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 50012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 50112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 50212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Always update advertising data. 50312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_data_needs_update_ = true; 50412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 50512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Update scan response only if it has data, since otherwise we just won't 50612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // send ADV_SCAN_IND. 50712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (!scan_response_.data().empty()) 50812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray scan_rsp_needs_update_ = true; 50912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 51012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // OK to set this at the end since we're still holding |adv_fields_lock_|. 51112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_start_callback_.reset(new StatusCallback(callback)); 51212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 51312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return true; 51412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 51512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 51612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::StopAdvertising(const StatusCallback& callback) { 51712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray VLOG(2) << __func__; 51812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray lock_guard<mutex> lock(adv_fields_lock_); 51912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 52012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (!IsAdvertisingStarted()) { 52112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Not advertising"; 52212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 52312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 52412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 52512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (IsStoppingAdvertising()) { 52612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "StopAdvertising already pending"; 52712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 52812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 52912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 53012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!adv_start_callback_); 53112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 53212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray bt_status_t status = hal::BluetoothGattInterface::Get()-> 533bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray GetClientHALInterface()->multi_adv_disable(client_id_); 53412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status != BT_STATUS_SUCCESS) { 53512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed to initiate call to disable multi-advertising"; 53612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return false; 53712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 53812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 53912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // OK to set this at the end since we're still holding |adv_fields_lock_|. 54012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_stop_callback_.reset(new StatusCallback(callback)); 54112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 54212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return true; 54312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 54412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 54512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::IsAdvertisingStarted() const { 54612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return adv_started_.load(); 54712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 54812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 54912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::IsStartingAdvertising() const { 55012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return !IsAdvertisingStarted() && adv_start_callback_; 55112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 55212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 55312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::IsStoppingAdvertising() const { 55412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return IsAdvertisingStarted() && adv_stop_callback_; 55512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 55612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 55708f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Ugurayconst UUID& LowEnergyClient::GetAppIdentifier() const { 55808f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray return app_identifier_; 55908f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray} 56008f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray 561bb18c41ffa0370d4eb0c4a15904b114355606466Arman Ugurayint LowEnergyClient::GetInstanceId() const { 562bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray return client_id_; 56308f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray} 56408f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray 56582ea72f905565f83116f74d5ccbacea5d710a853Arman Ugurayvoid LowEnergyClient::ScanResultCallback( 56682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray hal::BluetoothGattInterface* gatt_iface, 56782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) { 56882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // Ignore scan results if this client didn't start a scan. 56982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray if (!scan_started_.load()) 57082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray return; 57182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 57282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray lock_guard<mutex> lock(delegate_mutex_); 57382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray if (!delegate_) 57482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray return; 57582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 57682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray // TODO(armansito): Apply software filters here. 57782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 57882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray size_t record_len = GetScanRecordLength(adv_data); 57982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray std::vector<uint8_t> scan_record(adv_data, adv_data + record_len); 58082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 58182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray ScanResult result(BtAddrString(&bda), scan_record, rssi); 58282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 58382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray delegate_->OnScanResult(this, result); 58482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray} 58582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray 586a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskivoid LowEnergyClient::ConnectCallback( 587a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, 588a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski int client_id, const bt_bdaddr_t& bda) { 589a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (client_id != client_id_) 590a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski return; 591a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 592a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status; 593a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 594a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski { 595a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski lock_guard<mutex> lock(connection_fields_lock_); 596a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski auto success = connection_ids_.emplace(bda, conn_id); 597a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (!success.second) { 598a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!"; 599a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 600a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 601a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 602a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (delegate_) 603a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(), 604a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski true); 605a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski} 606a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 607a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskivoid LowEnergyClient::DisconnectCallback( 608a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, 609a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski int client_id, const bt_bdaddr_t& bda) { 610a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (client_id != client_id_) 611a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski return; 612a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 613a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status; 614a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski { 615a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski lock_guard<mutex> lock(connection_fields_lock_); 616a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (!connection_ids_.erase(bda)) { 617a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!"; 618a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 619a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski } 620a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 621a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski if (delegate_) 622a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(), 623a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski false); 624a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski} 625a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski 626a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowskivoid LowEnergyClient::MtuChangedCallback( 627a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, 628a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski int mtu) { 629a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status 630a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski << " mtu: " << mtu; 631a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 632a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski const bt_bdaddr_t *bda = nullptr; 633a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski { 634a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski lock_guard<mutex> lock(connection_fields_lock_); 635a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski for (auto& connection: connection_ids_) { 636a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski if (connection.second == conn_id) { 637a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski bda = &connection.first; 638a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski break; 639a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski } 640a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski } 641a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski } 642a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 643a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski if (!bda) 644a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski return; 645a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 646a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski const char *addr = BtAddrString(bda).c_str(); 647a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski if (delegate_) 648a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski delegate_->OnMtuChanged(this, status, addr, mtu); 649a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski} 650a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 65112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::MultiAdvEnableCallback( 65212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface* gatt_iface, 653bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray int client_id, int status) { 654bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray if (client_id != client_id_) 65512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return; 65612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 65712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray lock_guard<mutex> lock(adv_fields_lock_); 65812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 659bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status; 66012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 66112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(adv_start_callback_); 66212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!adv_stop_callback_); 66312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 66412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Terminate operation in case of error. 66512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status != BT_STATUS_SUCCESS) { 66612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed to enable multi-advertising"; 66712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray InvokeAndClearStartCallback(GetBLEStatus(status)); 66812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return; 66912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 67012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 67112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Now handle deferred tasks. 67212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray HandleDeferredAdvertiseData(gatt_iface); 67312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 67412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 67512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::MultiAdvDataCallback( 67612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface* gatt_iface, 677bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray int client_id, int status) { 678bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray if (client_id != client_id_) 67912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return; 68012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 68112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray lock_guard<mutex> lock(adv_fields_lock_); 68212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 683bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status; 68412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 68512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray is_setting_adv_data_ = false; 68612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 68712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Terminate operation in case of error. 68812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status != BT_STATUS_SUCCESS) { 68912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed to set advertising data"; 69012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray InvokeAndClearStartCallback(GetBLEStatus(status)); 69112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return; 69212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 69312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 69412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // Now handle deferred tasks. 69512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray HandleDeferredAdvertiseData(gatt_iface); 69612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 69712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 69812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::MultiAdvDisableCallback( 69912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface* /* gatt_iface */, 700bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray int client_id, int status) { 701bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray if (client_id != client_id_) 70212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return; 70312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 70412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray lock_guard<mutex> lock(adv_fields_lock_); 70512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 706bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status; 70712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 70812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!adv_start_callback_); 70912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(adv_stop_callback_); 71012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 71112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status == BT_STATUS_SUCCESS) { 712bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray VLOG(1) << "Multi-advertising stopped for client_id: " << client_id; 71312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_started_ = false; 71412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } else { 71512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed to stop multi-advertising"; 71612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 71712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 71812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray InvokeAndClearStopCallback(GetBLEStatus(status)); 71912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 72012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 72112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybt_status_t LowEnergyClient::SetAdvertiseData( 72212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface* gatt_iface, 72312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray const AdvertiseData& data, 72412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray bool set_scan_rsp) { 72512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray VLOG(2) << __func__; 72612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 72712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray HALAdvertiseData hal_data; 72812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 72912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // TODO(armansito): The stack should check that the length is valid when other 73012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // fields inserted by the stack (e.g. flags, device name, tx-power) are taken 73112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // into account. At the moment we are skipping this check; this means that if 73212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // the given data is too long then the stack will truncate it. 73312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (!ProcessAdvertiseData(data, &hal_data)) { 734ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker LOG(ERROR) << "Malformed advertise data given"; 73512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return BT_STATUS_FAIL; 73612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 73712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 73812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (is_setting_adv_data_.load()) { 739ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker LOG(ERROR) << "Setting advertising data already in progress."; 74012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return BT_STATUS_FAIL; 74112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 74212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 74312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // TODO(armansito): The length fields in the BTIF function below are signed 74412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // integers so a call to std::vector::size might get capped. This is very 74512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // unlikely anyway but it's safer to stop using signed-integer types for 74612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // length in APIs, so we should change that. 74712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray bt_status_t status = gatt_iface->GetClientHALInterface()-> 74812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray multi_adv_set_inst_data( 749bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray client_id_, 75012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray set_scan_rsp, 75112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray data.include_device_name(), 75212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray data.include_tx_power_level(), 75312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 0, // This is what Bluetooth.apk current hardcodes for "appearance". 75412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal_data.manufacturer_data.size(), 75512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray reinterpret_cast<char*>(hal_data.manufacturer_data.data()), 756ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker hal_data.service_data.size(), 757ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker reinterpret_cast<char*>(hal_data.service_data.data()), 758ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker hal_data.service_uuid.size(), 759ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker reinterpret_cast<char*>(hal_data.service_uuid.data())); 760ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker 76112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status != BT_STATUS_SUCCESS) { 76212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed to set instance advertising data."; 76312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return status; 76412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 76512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 76612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (set_scan_rsp) 76712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray scan_rsp_needs_update_ = false; 76812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray else 76912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_data_needs_update_ = false; 77012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 77112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray is_setting_adv_data_ = true; 77212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 77312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return status; 77412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 77512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 77612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::HandleDeferredAdvertiseData( 77712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface* gatt_iface) { 77812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray VLOG(2) << __func__; 77912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 78012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!IsAdvertisingStarted()); 78112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!IsStoppingAdvertising()); 78212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(IsStartingAdvertising()); 78312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray CHECK(!is_setting_adv_data_.load()); 78412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 78512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (adv_data_needs_update_.load()) { 78612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray bt_status_t status = SetAdvertiseData(gatt_iface, adv_data_, false); 78712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status != BT_STATUS_SUCCESS) { 78812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed setting advertisement data"; 78912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray InvokeAndClearStartCallback(GetBLEStatus(status)); 79012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 79112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return; 79212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 79312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 79412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (scan_rsp_needs_update_.load()) { 79512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray bt_status_t status = SetAdvertiseData(gatt_iface, scan_response_, true); 79612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (status != BT_STATUS_SUCCESS) { 79712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray LOG(ERROR) << "Failed setting scan response data"; 79812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray InvokeAndClearStartCallback(GetBLEStatus(status)); 79912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 80012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray return; 80112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray } 80212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 80312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // All pending tasks are complete. Report success. 80412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_started_ = true; 80512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray InvokeAndClearStartCallback(BLE_STATUS_SUCCESS); 80612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 80712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 80812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::InvokeAndClearStartCallback(BLEStatus status) { 80912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_data_needs_update_ = false; 81012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray scan_rsp_needs_update_ = false; 81112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 81212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // We allow NULL callbacks. 81312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (*adv_start_callback_) 81412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray (*adv_start_callback_)(status); 81512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 81612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_start_callback_ = nullptr; 81712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 81812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 81912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::InvokeAndClearStopCallback(BLEStatus status) { 82012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray // We allow NULL callbacks. 82112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray if (*adv_stop_callback_) 82212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray (*adv_stop_callback_)(status); 82312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 82412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray adv_stop_callback_ = nullptr; 82512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray} 82612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 82712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// LowEnergyClientFactory implementation 82812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// ======================================================== 82912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 83060b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub PawlowskiLowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter) 83160b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski : adapter_(adapter) { 832c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray hal::BluetoothGattInterface::Get()->AddClientObserver(this); 833c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray} 834c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 835c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman UgurayLowEnergyClientFactory::~LowEnergyClientFactory() { 836c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray hal::BluetoothGattInterface::Get()->RemoveClientObserver(this); 837c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray} 838c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 839bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguraybool LowEnergyClientFactory::RegisterInstance( 840bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray const UUID& uuid, 841bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray const RegisterCallback& callback) { 842c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray VLOG(1) << __func__ << " - UUID: " << uuid.ToString(); 843c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray lock_guard<mutex> lock(pending_calls_lock_); 844c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 845c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray if (pending_calls_.find(uuid) != pending_calls_.end()) { 846c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray LOG(ERROR) << "Low-Energy client with given UUID already registered - " 847c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray << "UUID: " << uuid.ToString(); 848c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray return false; 849c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray } 850c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 851c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray const btgatt_client_interface_t* hal_iface = 852c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray hal::BluetoothGattInterface::Get()->GetClientHALInterface(); 853c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray bt_uuid_t app_uuid = uuid.GetBlueDroid(); 854c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 855c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS) 856c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray return false; 857c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 858c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray pending_calls_[uuid] = callback; 859c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 860c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray return true; 861c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray} 862c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 863c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Ugurayvoid LowEnergyClientFactory::RegisterClientCallback( 86412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray hal::BluetoothGattInterface* gatt_iface, 865bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray int status, int client_id, 866c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray const bt_uuid_t& app_uuid) { 867c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray UUID uuid(app_uuid); 868c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 869c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray VLOG(1) << __func__ << " - UUID: " << uuid.ToString(); 870c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray lock_guard<mutex> lock(pending_calls_lock_); 871c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 872c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray auto iter = pending_calls_.find(uuid); 873c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray if (iter == pending_calls_.end()) { 874c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString(); 875c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray return; 876c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray } 877c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 878c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray // No need to construct a client if the call wasn't successful. 879c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray std::unique_ptr<LowEnergyClient> client; 880c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray BLEStatus result = BLE_STATUS_FAILURE; 881c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray if (status == BT_STATUS_SUCCESS) { 88260b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski client.reset(new LowEnergyClient(adapter_, uuid, client_id)); 88312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 88425689c1676ab911fa7887ec87b730b00325e4b90Jakub Pawlowski gatt_iface->AddClientObserver(client.get()); 88512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray 886c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray result = BLE_STATUS_SUCCESS; 887c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray } 888c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 88908f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray // Notify the result via the result callback. 890c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray iter->second(result, uuid, std::move(client)); 891c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 892c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray pending_calls_.erase(iter); 893c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray} 894c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray 895c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray} // namespace bluetooth 896