/*
* 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;
};