/* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "bta/include/bta_gatt_api.h" #include "bta/include/bta_ras_api.h" #include "bta/ras/ras_types.h" #include "gd/hci/uuid.h" #include "gd/os/rand.h" #include "os/logging/log_adapter.h" #include "stack/include/bt_types.h" #include "stack/include/btm_ble_addr.h" using namespace bluetooth; using namespace ::ras; using namespace ::ras::uuid; using bluetooth::ras::VendorSpecificCharacteristic; namespace { class RasServerImpl; RasServerImpl* instance; static constexpr uint32_t kSupportedFeatures = feature::kRealTimeRangingData; static constexpr uint16_t kBufferSize = 3; class RasServerImpl : public bluetooth::ras::RasServer { public: struct RasCharacteristic { bluetooth::Uuid uuid_; uint16_t attribute_handle_; uint16_t attribute_handle_ccc_; }; // Struct to save data of specific ranging counter struct DataBuffer { DataBuffer(uint16_t ranging_counter) : ranging_counter_(ranging_counter), segments_() {} uint16_t ranging_counter_; std::vector> segments_; }; struct PendingWriteResponse { uint16_t conn_id_; uint32_t trans_id_; uint16_t write_req_handle_; }; struct ClientTracker { uint16_t conn_id_; std::unordered_map ccc_values_; std::vector buffers_; bool handling_control_point_command_ = false; uint8_t vendor_specific_reply_counter_ = 0; PendingWriteResponse pending_write_response_; }; void Initialize() { Uuid uuid = Uuid::From128BitBE(bluetooth::os::GenerateRandom()); app_uuid_ = uuid; log::info("Register server with uuid:{}", app_uuid_.ToString()); BTA_GATTS_AppRegister( app_uuid_, [](tBTA_GATTS_EVT event, tBTA_GATTS* p_data) { if (instance && p_data) instance->GattsCallback(event, p_data); }, false); } void RegisterCallbacks(bluetooth::ras::RasServerCallbacks* callbacks) { callbacks_ = callbacks; } void SetVendorSpecificCharacteristic( const std::vector& vendor_specific_characteristics) { vendor_specific_characteristics_ = vendor_specific_characteristics; } void HandleVendorSpecificReplyComplete(RawAddress address, bool success) { log::info("address:{}, success:{}", address, success); tBLE_BD_ADDR ble_bd_addr; ResolveAddress(ble_bd_addr, address); if (trackers_.find(ble_bd_addr.bda) == trackers_.end()) { log::warn("Can't find tracker for address {}", address); return; }; auto response = trackers_[ble_bd_addr.bda].pending_write_response_; tGATTS_RSP p_msg; p_msg.attr_value.handle = response.write_req_handle_; GattStatus status = success ? GATT_SUCCESS : GATT_ERROR; BTA_GATTS_SendRsp(response.conn_id_, response.trans_id_, status, &p_msg); } void PushProcedureData(RawAddress address, uint16_t procedure_counter, bool is_last, std::vector data) { log::debug("{}, counter:{}, is_last:{}, with size {}", address, procedure_counter, is_last, data.size()); tBLE_BD_ADDR ble_bd_addr; ResolveAddress(ble_bd_addr, address); if (trackers_.find(ble_bd_addr.bda) == trackers_.end()) { log::warn("Can't find tracker for {}", ble_bd_addr.bda); return; } ClientTracker& tracker = trackers_[ble_bd_addr.bda]; uint16_t ccc_real_time = tracker.ccc_values_[kRasRealTimeRangingDataCharacteristic]; uint16_t ccc_data_ready = tracker.ccc_values_[kRasRangingDataReadyCharacteristic]; uint16_t ccc_data_over_written = tracker.ccc_values_[kRasRangingDataOverWrittenCharacteristic]; if (ccc_real_time != GATT_CLT_CONFIG_NONE) { bool need_confirm = ccc_real_time == GATT_CHAR_CLIENT_CONFIG_INDICTION; uint16_t attr_id = GetCharacteristic(kRasRealTimeRangingDataCharacteristic) ->attribute_handle_; log::debug("Send Real-time Ranging Data"); BTA_GATTS_HandleValueIndication(tracker.conn_id_, attr_id, data, need_confirm); } if (ccc_data_ready == GATT_CLT_CONFIG_NONE && ccc_data_over_written == GATT_CLT_CONFIG_NONE) { return; } std::lock_guard lock(on_demand_ranging_mutex_); DataBuffer& data_buffer = InitDataBuffer(ble_bd_addr.bda, procedure_counter); data_buffer.segments_.push_back(data); // Send data ready if (is_last) { if (ccc_data_ready == GATT_CLT_CONFIG_NONE) { log::debug("Skip Ranging Data Ready"); } else { bool need_confirm = ccc_data_ready & GATT_CLT_CONFIG_INDICATION; log::debug("Send data ready, ranging_counter {}", procedure_counter); uint16_t attr_id = GetCharacteristic(kRasRangingDataReadyCharacteristic) ->attribute_handle_; std::vector value(kRingingCounterSize); value[0] = (procedure_counter & 0xFF); value[1] = (procedure_counter >> 8) & 0xFF; BTA_GATTS_HandleValueIndication(tracker.conn_id_, attr_id, value, need_confirm); } } // Send data overwritten if (tracker.buffers_.size() > kBufferSize) { auto begin = tracker.buffers_.begin(); if (ccc_data_over_written == GATT_CLT_CONFIG_NONE) { log::debug("Skip Ranging Data Over Written"); tracker.buffers_.erase(begin); return; } bool need_confirm = ccc_data_over_written & GATT_CLT_CONFIG_INDICATION; log::debug("Send data over written, ranging_counter {}", begin->ranging_counter_); uint16_t attr_id = GetCharacteristic(kRasRangingDataOverWrittenCharacteristic) ->attribute_handle_; std::vector value(kRingingCounterSize); value[0] = (begin->ranging_counter_ & 0xFF); value[1] = (begin->ranging_counter_ >> 8) & 0xFF; BTA_GATTS_HandleValueIndication(tracker.conn_id_, attr_id, value, need_confirm); tracker.buffers_.erase(begin); } } void GattsCallback(tBTA_GATTS_EVT event, tBTA_GATTS* p_data) { log::info("event: {}", gatt_server_event_text(event)); switch (event) { case BTA_GATTS_CONNECT_EVT: { OnGattConnect(p_data); } break; case BTA_GATTS_REG_EVT: { OnGattServerRegister(p_data); } break; case BTA_GATTS_READ_CHARACTERISTIC_EVT: { OnReadCharacteristic(p_data); } break; case BTA_GATTS_READ_DESCRIPTOR_EVT: { OnReadDescriptor(p_data); } break; case BTA_GATTS_WRITE_CHARACTERISTIC_EVT: { OnWriteCharacteristic(p_data); } break; case BTA_GATTS_WRITE_DESCRIPTOR_EVT: { OnWriteDescriptor(p_data); } break; default: log::warn("Unhandled event {}", event); } } void OnGattConnect(tBTA_GATTS* p_data) { auto address = p_data->conn.remote_bda; log::info("Address: {}, conn_id:{}", address, p_data->conn.conn_id); if (p_data->conn.transport == BT_TRANSPORT_BR_EDR) { log::warn("Skip BE/EDR connection"); return; } if (trackers_.find(address) == trackers_.end()) { log::warn("Create new tracker"); } trackers_[address].conn_id_ = p_data->conn.conn_id; } void OnGattServerRegister(tBTA_GATTS* p_data) { tGATT_STATUS status = p_data->reg_oper.status; log::info("status: {}", gatt_status_text(p_data->reg_oper.status)); if (status != tGATT_STATUS::GATT_SUCCESS) { log::warn("Register Server fail"); return; } server_if_ = p_data->reg_oper.server_if; uint16_t key_mask = ((16 - 7) << 12); std::vector service; // RAS service btgatt_db_element_t ranging_service; ranging_service.uuid = kRangingService; ranging_service.type = BTGATT_DB_PRIMARY_SERVICE; service.push_back(ranging_service); // RAS Features btgatt_db_element_t features_characteristic; features_characteristic.uuid = kRasFeaturesCharacteristic; features_characteristic.type = BTGATT_DB_CHARACTERISTIC; features_characteristic.properties = GATT_CHAR_PROP_BIT_READ; features_characteristic.permissions = GATT_PERM_READ_ENCRYPTED | key_mask; service.push_back(features_characteristic); // Real-time Ranging Data (Optional) btgatt_db_element_t real_time_ranging_data_characteristic; real_time_ranging_data_characteristic.uuid = kRasRealTimeRangingDataCharacteristic; real_time_ranging_data_characteristic.type = BTGATT_DB_CHARACTERISTIC; real_time_ranging_data_characteristic.properties = GATT_CHAR_PROP_BIT_NOTIFY | GATT_CHAR_PROP_BIT_INDICATE; real_time_ranging_data_characteristic.permissions = GATT_PERM_READ_ENCRYPTED | key_mask; service.push_back(real_time_ranging_data_characteristic); btgatt_db_element_t ccc_descriptor; ccc_descriptor.uuid = kClientCharacteristicConfiguration; ccc_descriptor.type = BTGATT_DB_DESCRIPTOR; ccc_descriptor.permissions = GATT_PERM_WRITE | GATT_PERM_READ | key_mask; service.push_back(ccc_descriptor); // On-demand Ranging Data btgatt_db_element_t on_demand_ranging_data_characteristic; on_demand_ranging_data_characteristic.uuid = kRasOnDemandDataCharacteristic; on_demand_ranging_data_characteristic.type = BTGATT_DB_CHARACTERISTIC; on_demand_ranging_data_characteristic.properties = GATT_CHAR_PROP_BIT_NOTIFY | GATT_CHAR_PROP_BIT_INDICATE; on_demand_ranging_data_characteristic.permissions = GATT_PERM_READ_ENCRYPTED | key_mask; service.push_back(on_demand_ranging_data_characteristic); service.push_back(ccc_descriptor); // RAS Control Point (RAS-CP) btgatt_db_element_t ras_control_point; ras_control_point.uuid = kRasControlPointCharacteristic; ras_control_point.type = BTGATT_DB_CHARACTERISTIC; ras_control_point.properties = GATT_CHAR_PROP_BIT_WRITE | GATT_CHAR_PROP_BIT_INDICATE; ras_control_point.permissions = GATT_PERM_WRITE_ENCRYPTED | key_mask; service.push_back(ras_control_point); service.push_back(ccc_descriptor); // Ranging Data Ready btgatt_db_element_t ranging_data_ready_characteristic; ranging_data_ready_characteristic.uuid = kRasRangingDataReadyCharacteristic; ranging_data_ready_characteristic.type = BTGATT_DB_CHARACTERISTIC; ranging_data_ready_characteristic.properties = GATT_CHAR_PROP_BIT_NOTIFY | GATT_CHAR_PROP_BIT_INDICATE; ranging_data_ready_characteristic.permissions = GATT_PERM_READ_ENCRYPTED | key_mask; service.push_back(ranging_data_ready_characteristic); service.push_back(ccc_descriptor); // Ranging Data Overwritten btgatt_db_element_t ranging_data_overwritten_characteristic; ranging_data_overwritten_characteristic.uuid = kRasRangingDataOverWrittenCharacteristic; ranging_data_overwritten_characteristic.type = BTGATT_DB_CHARACTERISTIC; ranging_data_overwritten_characteristic.properties = GATT_CHAR_PROP_BIT_NOTIFY | GATT_CHAR_PROP_BIT_INDICATE; ranging_data_overwritten_characteristic.permissions = GATT_PERM_READ_ENCRYPTED | key_mask; service.push_back(ranging_data_overwritten_characteristic); service.push_back(ccc_descriptor); for (auto& vendor_specific_characteristics : vendor_specific_characteristics_) { btgatt_db_element_t characteristics; characteristics.uuid = vendor_specific_characteristics.characteristicUuid_; characteristics.type = BTGATT_DB_CHARACTERISTIC; characteristics.properties = GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE; characteristics.permissions = GATT_PERM_READ_ENCRYPTED | GATT_PERM_WRITE_ENCRYPTED | key_mask; service.push_back(characteristics); log::info("Push vendor_specific_characteristics uuid {}", characteristics.uuid); } BTA_GATTS_AddService( server_if_, service, base::BindRepeating([](tGATT_STATUS status, int server_if, std::vector service) { if (instance) instance->OnServiceAdded(status, server_if, service); })); } void OnReadCharacteristic(tBTA_GATTS* p_data) { uint16_t read_req_handle = p_data->req_data.p_data->read_req.handle; log::info("read_req_handle: 0x{:04x},", read_req_handle); tGATTS_RSP p_msg; p_msg.attr_value.handle = read_req_handle; if (characteristics_.find(read_req_handle) == characteristics_.end()) { log::error("Invalid handle 0x{:04x}", read_req_handle); BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_INVALID_HANDLE, &p_msg); return; } auto uuid = characteristics_[read_req_handle].uuid_; auto vendor_specific_characteristic = GetVendorSpecificCharacteristic(uuid); if (vendor_specific_characteristic != nullptr) { log::debug("Read vendor_specific_characteristic uuid {}", uuid); p_msg.attr_value.len = vendor_specific_characteristic->value_.size(); std::copy(vendor_specific_characteristic->value_.begin(), vendor_specific_characteristic->value_.end(), p_msg.attr_value.value); BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_SUCCESS, &p_msg); return; } log::info("Read uuid, {}", getUuidName(uuid)); // Check Characteristic UUID switch (uuid.As16Bit()) { case kRasFeaturesCharacteristic16bit: { p_msg.attr_value.len = kFeatureSize; memcpy(p_msg.attr_value.value, &kSupportedFeatures, sizeof(uint32_t)); } break; default: log::warn("Unhandled uuid {}", uuid.ToString()); BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_ILLEGAL_PARAMETER, &p_msg); return; } BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_SUCCESS, &p_msg); } void OnReadDescriptor(tBTA_GATTS* p_data) { uint16_t conn_id = p_data->req_data.conn_id; uint16_t read_req_handle = p_data->req_data.p_data->read_req.handle; RawAddress remote_bda = p_data->req_data.remote_bda; log::info("conn_id:{}, read_req_handle:0x{:04x}", conn_id, read_req_handle); tGATTS_RSP p_msg; p_msg.attr_value.handle = read_req_handle; // Only Client Characteristic Configuration (CCC) descriptor is expected RasCharacteristic* characteristic = GetCharacteristicByCccHandle(read_req_handle); if (characteristic == nullptr) { log::warn("Can't find Characteristic for CCC Descriptor, handle 0x{:04x}", read_req_handle); BTA_GATTS_SendRsp(conn_id, p_data->req_data.trans_id, GATT_INVALID_HANDLE, &p_msg); return; } log::info("Read CCC for uuid, {}", getUuidName(characteristic->uuid_)); uint16_t ccc_value = 0; if (trackers_.find(remote_bda) != trackers_.end()) { ccc_value = trackers_[remote_bda].ccc_values_[characteristic->uuid_]; } p_msg.attr_value.len = kCccValueSize; memcpy(p_msg.attr_value.value, &ccc_value, sizeof(uint16_t)); log::info("Send response for CCC value 0x{:04x}", ccc_value); BTA_GATTS_SendRsp(conn_id, p_data->req_data.trans_id, GATT_SUCCESS, &p_msg); } void OnWriteCharacteristic(tBTA_GATTS* p_data) { uint16_t conn_id = p_data->req_data.conn_id; uint16_t write_req_handle = p_data->req_data.p_data->write_req.handle; uint16_t len = p_data->req_data.p_data->write_req.len; bool need_rsp = p_data->req_data.p_data->write_req.need_rsp; RawAddress remote_bda = p_data->req_data.remote_bda; log::info("conn_id:{}, write_req_handle:0x{:04x}, need_rsp{}, len:{}", conn_id, write_req_handle, need_rsp, len); tGATTS_RSP p_msg; p_msg.handle = write_req_handle; if (characteristics_.find(write_req_handle) == characteristics_.end()) { log::error("Invalid handle {}", write_req_handle); BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_INVALID_HANDLE, &p_msg); return; } auto uuid = characteristics_[write_req_handle].uuid_; auto vendor_specific_characteristic = GetVendorSpecificCharacteristic(uuid); if (vendor_specific_characteristic != nullptr) { WriteVendorSpecificCharacteristic(vendor_specific_characteristic, p_data, p_msg); return; } log::info("Write uuid, {}", getUuidName(uuid)); // Check Characteristic UUID switch (uuid.As16Bit()) { case kRasControlPointCharacteristic16bit: { if (trackers_.find(p_data->req_data.remote_bda) == trackers_.end()) { log::warn("Can't find trackers for {}", p_data->req_data.remote_bda); BTA_GATTS_SendRsp(conn_id, p_data->req_data.trans_id, GATT_ILLEGAL_PARAMETER, &p_msg); return; } ClientTracker* tracker = &trackers_[p_data->req_data.remote_bda]; if (tracker->handling_control_point_command_) { log::warn("Procedure Already In Progress"); BTA_GATTS_SendRsp(conn_id, p_data->req_data.trans_id, GATT_PRC_IN_PROGRESS, &p_msg); return; } if (need_rsp) { BTA_GATTS_SendRsp(conn_id, p_data->req_data.trans_id, GATT_SUCCESS, &p_msg); } HandleControlPoint(tracker, &p_data->req_data.p_data->write_req); } break; default: log::warn("Unhandled uuid {}", uuid.ToString()); BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_ILLEGAL_PARAMETER, &p_msg); return; } } void WriteVendorSpecificCharacteristic( VendorSpecificCharacteristic* vendor_specific_characteristic, tBTA_GATTS* p_data, tGATTS_RSP& p_msg) { log::debug("uuid {}", vendor_specific_characteristic->characteristicUuid_); uint16_t len = p_data->req_data.p_data->write_req.len; RawAddress remote_bda = p_data->req_data.remote_bda; if (trackers_.find(remote_bda) == trackers_.end()) { BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_INVALID_HANDLE, &p_msg); log::warn("Can't find tracker for remote_bda {}", remote_bda); return; } // Update reply value auto& tracker = trackers_[remote_bda]; auto value = p_data->req_data.p_data->write_req.value; vendor_specific_characteristic->reply_value_.clear(); vendor_specific_characteristic->reply_value_.reserve(len); vendor_specific_characteristic->reply_value_.assign(value, value + len); tracker.vendor_specific_reply_counter_++; if (tracker.vendor_specific_reply_counter_ == vendor_specific_characteristics_.size()) { log::info("All vendor specific characteristics written"); tBLE_BD_ADDR ble_bd_addr; ble_bd_addr.bda = remote_bda; ble_bd_addr.type = BLE_ADDR_RANDOM; btm_random_pseudo_to_identity_addr(&ble_bd_addr.bda, &ble_bd_addr.type); tracker.vendor_specific_reply_counter_ = 0; tracker.pending_write_response_.conn_id_ = p_data->req_data.conn_id; tracker.pending_write_response_.trans_id_ = p_data->req_data.trans_id; tracker.pending_write_response_.write_req_handle_ = p_msg.handle; callbacks_->OnVendorSpecificReply(ble_bd_addr.bda, vendor_specific_characteristics_); } else { BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id, GATT_SUCCESS, &p_msg); } } void OnWriteDescriptor(tBTA_GATTS* p_data) { uint16_t conn_id = p_data->req_data.conn_id; uint16_t write_req_handle = p_data->req_data.p_data->write_req.handle; uint16_t len = p_data->req_data.p_data->write_req.len; RawAddress remote_bda = p_data->req_data.remote_bda; log::info("conn_id:{}, write_req_handle:0x{:04x}, len:{}", conn_id, write_req_handle, len); tGATTS_RSP p_msg; p_msg.handle = write_req_handle; // Only Client Characteristic Configuration (CCC) descriptor is expected RasCharacteristic* characteristic = GetCharacteristicByCccHandle(write_req_handle); if (characteristic == nullptr) { log::warn("Can't find Characteristic for CCC Descriptor, handle 0x{:04x}", write_req_handle); BTA_GATTS_SendRsp(conn_id, p_data->req_data.trans_id, GATT_INVALID_HANDLE, &p_msg); return; } const uint8_t* value = p_data->req_data.p_data->write_req.value; uint16_t ccc_value; STREAM_TO_UINT16(ccc_value, value); if (trackers_.find(remote_bda) != trackers_.end()) { trackers_[remote_bda].ccc_values_[characteristic->uuid_] = ccc_value; } log::info("Write CCC for {}, conn_id:{}, value:0x{:04x}", getUuidName(characteristic->uuid_), conn_id, ccc_value); BTA_GATTS_SendRsp(conn_id, p_data->req_data.trans_id, GATT_SUCCESS, &p_msg); } void HandleControlPoint(ClientTracker* tracker, tGATT_WRITE_REQ* write_req) { ControlPointCommand command; if (!ParseControlPointCommand(&command, write_req->value, write_req->len)) { return; } tracker->handling_control_point_command_ = true; switch (command.opcode_) { case Opcode::GET_RANGING_DATA: { OnGetRangingData(&command, tracker); } break; case Opcode::ACK_RANGING_DATA: { OnAckRangingData(&command, tracker); } break; case Opcode::RETRIEVE_LOST_RANGING_DATA_SEGMENTS: case Opcode::ABORT_OPERATION: case Opcode::FILTER: case Opcode::PCT_FORMAT: { log::warn("Unsupported opcode:0x{:02x}, {}", (uint16_t)command.opcode_, GetOpcodeText(command.opcode_)); SendResponseCode(ResponseCodeValue::OP_CODE_NOT_SUPPORTED, tracker); } break; default: log::warn("Unknown opcode:0x{:02x}", (uint16_t)command.opcode_); SendResponseCode(ResponseCodeValue::OP_CODE_NOT_SUPPORTED, tracker); } } void OnGetRangingData(ControlPointCommand* command, ClientTracker* tracker) { const uint8_t* value = command->parameter_; uint16_t ranging_counter; STREAM_TO_UINT16(ranging_counter, value); log::info("ranging_counter:{}", ranging_counter); uint16_t ccc_value = tracker->ccc_values_[kRasOnDemandDataCharacteristic]; uint16_t attr_id = GetCharacteristic(kRasOnDemandDataCharacteristic)->attribute_handle_; bool need_confirm = ccc_value & GATT_CLT_CONFIG_INDICATION; std::lock_guard lock(on_demand_ranging_mutex_); auto it = std::find_if(tracker->buffers_.begin(), tracker->buffers_.end(), [&ranging_counter](const DataBuffer& buffer) { return buffer.ranging_counter_ == ranging_counter; }); if (it != tracker->buffers_.end()) { for (uint16_t i = 0; i < it->segments_.size(); i++) { if (ccc_value == GATT_CLT_CONFIG_NONE) { log::warn("On Demand Data is not subscribed, Skip"); break; } log::info("Send On Demand Ranging Data, segment {}", i); BTA_GATTS_HandleValueIndication(tracker->conn_id_, attr_id, it->segments_[i], need_confirm); } log::info("Send COMPLETE_RANGING_DATA_RESPONSE, ranging_counter:{}", ranging_counter); std::vector response(8, 0); response[0] = (uint8_t)EventCode::COMPLETE_RANGING_DATA_RESPONSE; response[1] = (ranging_counter & 0xFF); response[2] = (ranging_counter >> 8) & 0xFF; BTA_GATTS_HandleValueIndication( tracker->conn_id_, GetCharacteristic(kRasControlPointCharacteristic)->attribute_handle_, response, true); tracker->handling_control_point_command_ = false; return; } else { log::warn("No Records Found"); SendResponseCode(ResponseCodeValue::NO_RECORDS_FOUND, tracker); } }; void OnAckRangingData(ControlPointCommand* command, ClientTracker* tracker) { const uint8_t* value = command->parameter_; uint16_t ranging_counter; STREAM_TO_UINT16(ranging_counter, value); log::info("ranging_counter:{}", ranging_counter); std::lock_guard lock(on_demand_ranging_mutex_); auto it = std::find_if(tracker->buffers_.begin(), tracker->buffers_.end(), [&ranging_counter](const DataBuffer& buffer) { return buffer.ranging_counter_ == ranging_counter; }); // If found, erase it if (it != tracker->buffers_.end()) { tracker->buffers_.erase(it); tracker->handling_control_point_command_ = false; SendResponseCode(ResponseCodeValue::SUCCESS, tracker); } else { log::warn("No Records Found"); SendResponseCode(ResponseCodeValue::NO_RECORDS_FOUND, tracker); } }; void SendResponseCode(ResponseCodeValue response_code_value, ClientTracker* tracker) { log::info("0x{:02x}, {}", (uint16_t)response_code_value, GetResponseOpcodeValueText(response_code_value)); std::vector response(8, 0); response[0] = (uint8_t)EventCode::RESPONSE_CODE; response[1] = (uint8_t)response_code_value; BTA_GATTS_HandleValueIndication( tracker->conn_id_, GetCharacteristic(kRasControlPointCharacteristic)->attribute_handle_, response, true); tracker->handling_control_point_command_ = false; } void OnServiceAdded(tGATT_STATUS status, int server_if, std::vector service) { log::info("status: {}, server_if: {}", gatt_status_text(status), server_if); RasCharacteristic* current_characteristic; for (uint16_t i = 0; i < service.size(); i++) { uint16_t attribute_handle = service[i].attribute_handle; Uuid uuid = service[i].uuid; if (service[i].type == BTGATT_DB_CHARACTERISTIC) { log::info("Characteristic uuid: 0x{:04x}, handle:0x{:04x}, {}", uuid.As16Bit(), attribute_handle, getUuidName(uuid)); characteristics_[attribute_handle].attribute_handle_ = attribute_handle; characteristics_[attribute_handle].uuid_ = uuid; current_characteristic = &characteristics_[attribute_handle]; } else if (service[i].type == BTGATT_DB_DESCRIPTOR) { log::info("\tDescriptor uuid: 0x{:04x}, handle: 0x{:04x}, {}", uuid.As16Bit(), attribute_handle, getUuidName(uuid)); if (service[i].uuid == kClientCharacteristicConfiguration) { current_characteristic->attribute_handle_ccc_ = attribute_handle; } } } } RasCharacteristic* GetCharacteristic(Uuid uuid) { for (auto& [attribute_handle, characteristic] : characteristics_) { if (characteristic.uuid_ == uuid) { return &characteristic; } } return nullptr; } RasCharacteristic* GetCharacteristicByCccHandle(uint16_t descriptor_handle) { for (auto& [attribute_handle, characteristic] : characteristics_) { if (characteristic.attribute_handle_ccc_ == descriptor_handle) { return &characteristic; } } return nullptr; } void ResolveAddress(tBLE_BD_ADDR& ble_bd_addr, const RawAddress& address) { ble_bd_addr.bda = address; ble_bd_addr.type = BLE_ADDR_RANDOM; maybe_resolve_address(&ble_bd_addr.bda, &ble_bd_addr.type); } DataBuffer& InitDataBuffer(RawAddress address, uint16_t procedure_counter) { std::vector& buffers = trackers_[address].buffers_; for (DataBuffer& data_buffer : buffers) { if (data_buffer.ranging_counter_ == procedure_counter) { // Data already exist, return return data_buffer; } } log::info("Create data for ranging_counter: {}, current size {}", procedure_counter, buffers.size()); buffers.emplace_back(procedure_counter); return buffers.back(); } VendorSpecificCharacteristic* GetVendorSpecificCharacteristic( const bluetooth::Uuid& uuid) { for (auto& characteristic : vendor_specific_characteristics_) { if (characteristic.characteristicUuid_ == uuid) { return &characteristic; } } return nullptr; } private: bluetooth::Uuid app_uuid_; uint16_t server_if_; // A map to associate characteristics with handles std::unordered_map characteristics_; // A map to client trackers with address std::unordered_map trackers_; bluetooth::ras::RasServerCallbacks* callbacks_; std::mutex on_demand_ranging_mutex_; std::vector vendor_specific_characteristics_; }; } // namespace bluetooth::ras::RasServer* bluetooth::ras::GetRasServer() { if (instance == nullptr) { instance = new RasServerImpl(); } return instance; };