1 // 2 // Copyright (C) 2015 Google, Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at: 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "service/example/heart_rate/heart_rate_server.h" 18 19 #include <base/bind.h> 20 #include <base/location.h> 21 #include <base/logging.h> 22 #include <base/rand_util.h> 23 24 #include <bluetooth/low_energy_constants.h> 25 26 #include "service/example/heart_rate/constants.h" 27 28 namespace heart_rate { 29 30 class CLIBluetoothLowEnergyCallback 31 : public ipc::binder::BnBluetoothLowEnergyCallback { 32 public: 33 CLIBluetoothLowEnergyCallback(android::sp<ipc::binder::IBluetooth> bt) 34 : bt_(bt) {} 35 36 // IBluetoothLowEnergyCallback overrides: 37 void OnConnectionState(int status, int client_id, const char* address, 38 bool connected) override {} 39 void OnMtuChanged(int status, const char *address, int mtu) override {} 40 41 void OnScanResult(const bluetooth::ScanResult& scan_result) override {} 42 43 void OnClientRegistered(int status, int client_id){ 44 if (status != bluetooth::BLE_STATUS_SUCCESS) { 45 LOG(ERROR) << "Failed to register BLE client, will not start advertising"; 46 return; 47 } 48 49 LOG(INFO) << "Registered BLE client with ID: " << client_id; 50 51 /* Advertising data: 16-bit Service UUID: Heart Rate Service */ 52 std::vector<uint8_t> data{0x03, 0x03, 0x0D, 0x18}; 53 base::TimeDelta timeout; 54 55 bluetooth::AdvertiseSettings settings( 56 bluetooth::AdvertiseSettings::MODE_LOW_POWER, 57 timeout, 58 bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, 59 true); 60 61 bluetooth::AdvertiseData adv_data(data); 62 adv_data.set_include_device_name(true); 63 adv_data.set_include_tx_power_level(true); 64 65 bluetooth::AdvertiseData scan_rsp; 66 67 bt_->GetLowEnergyInterface()-> 68 StartMultiAdvertising(client_id, adv_data, scan_rsp, settings); 69 } 70 71 void OnMultiAdvertiseCallback(int status, bool is_start, 72 const bluetooth::AdvertiseSettings& /* settings */) { 73 LOG(INFO) << "Advertising" << (is_start?" started":" stopped"); 74 }; 75 76 private: 77 android::sp<ipc::binder::IBluetooth> bt_; 78 DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback); 79 }; 80 81 82 HeartRateServer::HeartRateServer( 83 android::sp<ipc::binder::IBluetooth> bluetooth, 84 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 85 bool advertise) 86 : simulation_started_(false), 87 bluetooth_(bluetooth), 88 server_if_(-1), 89 hr_notification_count_(0), 90 energy_expended_(0), 91 advertise_(advertise), 92 main_task_runner_(main_task_runner), 93 weak_ptr_factory_(this) { 94 CHECK(bluetooth_.get()); 95 } 96 97 HeartRateServer::~HeartRateServer() { 98 std::lock_guard<std::mutex> lock(mutex_); 99 if (!gatt_.get() || server_if_ == -1) 100 return; 101 102 if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) 103 return; 104 105 // Manually unregister ourselves from the daemon. It's good practice to do 106 // this, even though the daemon will automatically unregister us if this 107 // process exits. 108 gatt_->UnregisterServer(server_if_); 109 } 110 111 bool HeartRateServer::Run(const RunCallback& callback) { 112 std::lock_guard<std::mutex> lock(mutex_); 113 114 if (pending_run_cb_) { 115 LOG(ERROR) << "Already started"; 116 return false; 117 } 118 119 // Grab the IBluetoothGattServer binder from the Bluetooth daemon. 120 gatt_ = bluetooth_->GetGattServerInterface(); 121 if (!gatt_.get()) { 122 LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface"; 123 return false; 124 } 125 126 // Register this instance as a GATT server. If this call succeeds, we will 127 // asynchronously receive a server ID via the OnServerRegistered callback. 128 if (!gatt_->RegisterServer(this)) { 129 LOG(ERROR) << "Failed to register with the server interface"; 130 return false; 131 } 132 133 pending_run_cb_ = callback; 134 135 return true; 136 } 137 138 void HeartRateServer::ScheduleNextMeasurement() { 139 main_task_runner_->PostDelayedTask( 140 FROM_HERE, 141 base::Bind(&HeartRateServer::SendHeartRateMeasurement, 142 weak_ptr_factory_.GetWeakPtr()), 143 base::TimeDelta::FromSeconds(1)); 144 } 145 146 void HeartRateServer::SendHeartRateMeasurement() { 147 std::lock_guard<std::mutex> lock(mutex_); 148 149 // Send a notification or indication to all enabled devices. 150 bool found = false; 151 for (const auto& iter : device_ccc_map_) { 152 uint8_t ccc_val = iter.second; 153 154 if (!ccc_val) 155 continue; 156 157 found = true; 158 159 // Don't send a notification if one is already pending for this device. 160 if (pending_notification_map_[iter.first]) 161 continue; 162 163 std::vector<uint8_t> value; 164 BuildHeartRateMeasurementValue(&value); 165 166 if (gatt_->SendNotification(server_if_, iter.first, hr_measurement_id_, 167 false, value)) 168 pending_notification_map_[iter.first] = true; 169 } 170 171 // Still enabled! 172 if (found) { 173 ScheduleNextMeasurement(); 174 return; 175 } 176 177 // All clients disabled notifications. 178 simulation_started_ = false; 179 180 // TODO(armansito): We should keep track of closed connections here so that we 181 // don't send notifications to uninterested clients. 182 } 183 184 void HeartRateServer::BuildHeartRateMeasurementValue( 185 std::vector<uint8_t>* out_value) { 186 CHECK(out_value); // Assert that |out_value| is not nullptr. 187 188 // Default flags field. Here is what we put in there: 189 // Bit 0: 0 - 8-bit Heart Rate value 190 // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected. 191 uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected; 192 193 // Our demo's heart rate. Pick a value between 90 and 130. 194 uint8_t heart_rate = base::RandInt(90, 130); 195 196 // On every tenth beat we include the Energy Expended value. 197 bool include_ee = false; 198 if (!(hr_notification_count_ % 10)) { 199 include_ee = true; 200 flags |= kHREnergyExpendedPresent; 201 } 202 203 hr_notification_count_++; 204 energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1); 205 206 // Add all the value bytes. 207 out_value->push_back(flags); 208 out_value->push_back(heart_rate); 209 if (include_ee) { 210 out_value->push_back(energy_expended_); 211 out_value->push_back(energy_expended_ >> 8); 212 } 213 } 214 215 void HeartRateServer::OnServerRegistered(int status, int server_if) { 216 std::lock_guard<std::mutex> lock(mutex_); 217 218 if (status != bluetooth::BLE_STATUS_SUCCESS) { 219 LOG(ERROR) << "Failed to register GATT server"; 220 pending_run_cb_(false); 221 return; 222 } 223 224 // Registration succeeded. Store our ID, as we need it for GATT server 225 // operations. 226 server_if_ = server_if; 227 228 LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_; 229 LOG(INFO) << "Populating attributes"; 230 231 // Start service declaration. 232 std::unique_ptr<bluetooth::GattIdentifier> gatt_id; 233 if (!gatt_->BeginServiceDeclaration(server_if_, true, 234 kHRServiceUUID, 235 &gatt_id)) { 236 LOG(ERROR) << "Failed to begin service declaration"; 237 pending_run_cb_(false); 238 return; 239 } 240 241 hr_service_id_ = *gatt_id; 242 243 // Add Heart Rate Measurement characteristic. 244 if (!gatt_->AddCharacteristic( 245 server_if_, kHRMeasurementUUID, 246 bluetooth::kCharacteristicPropertyNotify, 247 0, &gatt_id)) { 248 LOG(ERROR) << "Failed to add heart rate measurement characteristic"; 249 pending_run_cb_(false); 250 return; 251 } 252 253 hr_measurement_id_ = *gatt_id; 254 255 // Add Client Characteristic Configuration descriptor for the Heart Rate 256 // Measurement characteristic. 257 if (!gatt_->AddDescriptor( 258 server_if_, kCCCDescriptorUUID, 259 bluetooth::kAttributePermissionRead|bluetooth::kAttributePermissionWrite, 260 &gatt_id)) { 261 LOG(ERROR) << "Failed to add CCC descriptor"; 262 pending_run_cb_(false); 263 return; 264 } 265 266 hr_measurement_cccd_id_ = *gatt_id; 267 268 // Add Body Sensor Location characteristic. 269 if (!gatt_->AddCharacteristic( 270 server_if_, kBodySensorLocationUUID, 271 bluetooth::kCharacteristicPropertyRead, 272 bluetooth::kAttributePermissionRead, 273 &gatt_id)) { 274 LOG(ERROR) << "Failed to add body sensor location characteristic"; 275 pending_run_cb_(false); 276 return; 277 } 278 279 body_sensor_loc_id_ = *gatt_id; 280 281 // Add Heart Rate Control Point characteristic. 282 if (!gatt_->AddCharacteristic( 283 server_if_, kHRControlPointUUID, 284 bluetooth::kCharacteristicPropertyWrite, 285 bluetooth::kAttributePermissionWrite, 286 &gatt_id)) { 287 LOG(ERROR) << "Failed to add heart rate control point characteristic"; 288 pending_run_cb_(false); 289 return; 290 } 291 292 hr_control_point_id_ = *gatt_id; 293 294 // End service declaration. We will be notified whether or not this succeeded 295 // via the OnServiceAdded callback. 296 if (!gatt_->EndServiceDeclaration(server_if_)) { 297 LOG(ERROR) << "Failed to end service declaration"; 298 pending_run_cb_(false); 299 return; 300 } 301 302 LOG(INFO) << "Initiated EndServiceDeclaration request"; 303 } 304 305 void HeartRateServer::OnServiceAdded( 306 int status, 307 const bluetooth::GattIdentifier& service_id) { 308 std::lock_guard<std::mutex> lock(mutex_); 309 310 if (status != bluetooth::BLE_STATUS_SUCCESS) { 311 LOG(ERROR) << "Failed to add Heart Rate service"; 312 pending_run_cb_(false); 313 return; 314 } 315 316 if (service_id != hr_service_id_) { 317 LOG(ERROR) << "Received callback for the wrong service ID"; 318 pending_run_cb_(false); 319 return; 320 } 321 322 // EndServiceDeclaration succeeded! Our Heart Rate service is now discoverable 323 // over GATT connections. 324 325 LOG(INFO) << "Heart Rate service added"; 326 pending_run_cb_(true); 327 328 if (advertise_) { 329 auto ble = bluetooth_->GetLowEnergyInterface(); 330 if (!ble.get()) { 331 LOG(ERROR) << "Failed to obtain handle to IBluetoothLowEnergy interface"; 332 return; 333 } 334 ble->RegisterClient(new CLIBluetoothLowEnergyCallback(bluetooth_)); 335 } 336 337 } 338 339 void HeartRateServer::OnCharacteristicReadRequest( 340 const std::string& device_address, 341 int request_id, int offset, bool /* is_long */, 342 const bluetooth::GattIdentifier& characteristic_id) { 343 std::lock_guard<std::mutex> lock(mutex_); 344 345 // This is where we handle an incoming characteristic read. Only the body 346 // sensor location characteristic is readable. 347 CHECK(characteristic_id == body_sensor_loc_id_); 348 349 std::vector<uint8_t> value; 350 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE; 351 if (offset > 1) 352 error = bluetooth::GATT_ERROR_INVALID_OFFSET; 353 else if (offset == 0) 354 value.push_back(kHRBodyLocationFoot); 355 356 gatt_->SendResponse(server_if_, device_address, request_id, error, 357 offset, value); 358 } 359 360 void HeartRateServer::OnDescriptorReadRequest( 361 const std::string& device_address, 362 int request_id, int offset, bool /* is_long */, 363 const bluetooth::GattIdentifier& descriptor_id) { 364 std::lock_guard<std::mutex> lock(mutex_); 365 366 // This is where we handle an incoming characteristic descriptor read. There 367 // is only one descriptor. 368 if (descriptor_id != hr_measurement_cccd_id_) { 369 std::vector<uint8_t> value; 370 gatt_->SendResponse(server_if_, device_address, request_id, 371 bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, 372 offset, value); 373 return; 374 } 375 376 // 16-bit value encoded as little-endian. 377 const uint8_t value_bytes[] = { device_ccc_map_[device_address], 0x00 }; 378 379 std::vector<uint8_t> value; 380 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE; 381 if (offset > 2) 382 error = bluetooth::GATT_ERROR_INVALID_OFFSET; 383 else 384 value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset); 385 386 gatt_->SendResponse(server_if_, device_address, request_id, error, 387 offset, value); 388 } 389 390 void HeartRateServer::OnCharacteristicWriteRequest( 391 const std::string& device_address, 392 int request_id, int offset, bool is_prepare_write, bool need_response, 393 const std::vector<uint8_t>& value, 394 const bluetooth::GattIdentifier& characteristic_id) { 395 std::lock_guard<std::mutex> lock(mutex_); 396 397 std::vector<uint8_t> dummy; 398 399 // This is where we handle an incoming characteristic write. The Heart Rate 400 // service doesn't really support prepared writes, so we just reject them to 401 // keep things simple. 402 if (is_prepare_write) { 403 gatt_->SendResponse(server_if_, device_address, request_id, 404 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 405 offset, dummy); 406 return; 407 } 408 409 // Heart Rate Control point is the only writable characteristic. 410 CHECK(characteristic_id == hr_control_point_id_); 411 412 // Writes to the Heart Rate Control Point characteristic must contain a single 413 // byte with the value 0x01. 414 if (value.size() != 1 || value[0] != 0x01) { 415 gatt_->SendResponse(server_if_, device_address, request_id, 416 bluetooth::GATT_ERROR_OUT_OF_RANGE, 417 offset, dummy); 418 return; 419 } 420 421 LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!"; 422 energy_expended_ = 0; 423 424 if (!need_response) 425 return; 426 427 gatt_->SendResponse(server_if_, device_address, request_id, 428 bluetooth::GATT_ERROR_NONE, offset, dummy); 429 } 430 431 void HeartRateServer::OnDescriptorWriteRequest( 432 const std::string& device_address, 433 int request_id, int offset, bool is_prepare_write, bool need_response, 434 const std::vector<uint8_t>& value, 435 const bluetooth::GattIdentifier& descriptor_id) { 436 std::lock_guard<std::mutex> lock(mutex_); 437 438 std::vector<uint8_t> dummy; 439 440 // This is where we handle an incoming characteristic write. The Heart Rate 441 // service doesn't really support prepared writes, so we just reject them to 442 // keep things simple. 443 if (is_prepare_write) { 444 gatt_->SendResponse(server_if_, device_address, request_id, 445 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 446 offset, dummy); 447 return; 448 } 449 450 // CCC is the only descriptor we have. 451 CHECK(descriptor_id == hr_measurement_cccd_id_); 452 453 // CCC must contain 2 bytes for a 16-bit value in little-endian. The only 454 // allowed values here are 0x0000 and 0x0001. 455 if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) { 456 gatt_->SendResponse(server_if_, device_address, request_id, 457 bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED, 458 offset, dummy); 459 return; 460 } 461 462 device_ccc_map_[device_address] = value[0]; 463 464 LOG(INFO) << "Heart Rate Measurement CCC written - device: " 465 << device_address << " value: " << (int)value[0]; 466 467 // Start the simulation. 468 if (!simulation_started_ && value[0]) { 469 simulation_started_ = true; 470 ScheduleNextMeasurement(); 471 } 472 473 if (!need_response) 474 return; 475 476 gatt_->SendResponse(server_if_, device_address, request_id, 477 bluetooth::GATT_ERROR_NONE, offset, dummy); 478 } 479 480 void HeartRateServer::OnExecuteWriteRequest( 481 const std::string& device_address, 482 int request_id, 483 bool /* is_execute */) { 484 // We don't support Prepared Writes so, simply return Not Supported error. 485 std::vector<uint8_t> dummy; 486 gatt_->SendResponse(server_if_, device_address, request_id, 487 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy); 488 } 489 490 void HeartRateServer::OnNotificationSent( 491 const std::string& device_address, int status) { 492 LOG(INFO) << "Notification was sent - device: " << device_address 493 << " status: " << status; 494 std::lock_guard<std::mutex> lock(mutex_); 495 pending_notification_map_[device_address] = false; 496 } 497 498 } // namespace heart_rate 499