1e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// 2e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// Copyright (C) 2015 Google, Inc. 3e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// 4e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// Licensed under the Apache License, Version 2.0 (the "License"); 5e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// you may not use this file except in compliance with the License. 6e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// You may obtain a copy of the License at: 7e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// 8e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// http://www.apache.org/licenses/LICENSE-2.0 9e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// 10e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// Unless required by applicable law or agreed to in writing, software 11e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// distributed under the License is distributed on an "AS IS" BASIS, 12e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// See the License for the specific language governing permissions and 14e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// limitations under the License. 15e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray// 16e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 17e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray#include "service/example/heart_rate/heart_rate_server.h" 18e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/bind.h> 201c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/location.h> 21e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray#include <base/logging.h> 221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/rand_util.h> 23e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 24234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray#include <bluetooth/low_energy_constants.h> 25234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray 261c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include "service/example/heart_rate/constants.h" 27e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 28e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguraynamespace heart_rate { 29e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 30032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowskiclass CLIBluetoothLowEnergyCallback 31032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski : public ipc::binder::BnBluetoothLowEnergyCallback { 32032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski public: 33032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski CLIBluetoothLowEnergyCallback(android::sp<ipc::binder::IBluetooth> bt) 34032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski : bt_(bt) {} 35032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 36032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski // IBluetoothLowEnergyCallback overrides: 37032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski void OnConnectionState(int status, int client_id, const char* address, 38032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bool connected) override {} 39a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski void OnMtuChanged(int status, const char *address, int mtu) override {} 40a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski 41032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski void OnScanResult(const bluetooth::ScanResult& scan_result) override {} 42032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 43032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski void OnClientRegistered(int status, int client_id){ 44032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski if (status != bluetooth::BLE_STATUS_SUCCESS) { 45032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski LOG(ERROR) << "Failed to register BLE client, will not start advertising"; 46032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski return; 47032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski } 48032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 49032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski LOG(INFO) << "Registered BLE client with ID: " << client_id; 50032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 5174385e53ac82a3e2d10c17d47f46a444bb856b4eJakub Pawlowski /* Advertising data: 16-bit Service UUID: Heart Rate Service */ 5274385e53ac82a3e2d10c17d47f46a444bb856b4eJakub Pawlowski std::vector<uint8_t> data{0x03, 0x03, 0x0D, 0x18}; 53032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski base::TimeDelta timeout; 54032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 55032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseSettings settings( 56032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseSettings::MODE_LOW_POWER, 57032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski timeout, 58032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, 59032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski true); 60032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 61032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseData adv_data(data); 62032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski adv_data.set_include_device_name(true); 63032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski adv_data.set_include_tx_power_level(true); 64032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 65032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseData scan_rsp; 66032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 67032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bt_->GetLowEnergyInterface()-> 68032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski StartMultiAdvertising(client_id, adv_data, scan_rsp, settings); 69032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski } 70032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 71032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski void OnMultiAdvertiseCallback(int status, bool is_start, 72032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski const bluetooth::AdvertiseSettings& /* settings */) { 73032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski LOG(INFO) << "Advertising" << (is_start?" started":" stopped"); 74032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski }; 75032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 76032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski private: 77032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski android::sp<ipc::binder::IBluetooth> bt_; 78032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback); 79032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski}; 80032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 81032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman UgurayHeartRateServer::HeartRateServer( 831c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray android::sp<ipc::binder::IBluetooth> bluetooth, 84032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 85032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bool advertise) 861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray : simulation_started_(false), 871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth_(bluetooth), 881c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray server_if_(-1), 891c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray hr_notification_count_(0), 901c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray energy_expended_(0), 91032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski advertise_(advertise), 921c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray main_task_runner_(main_task_runner), 931c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray weak_ptr_factory_(this) { 94e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray CHECK(bluetooth_.get()); 95e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 96e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 97e0fe387561141e049bb2fc748cacb0b56af4928fArman UgurayHeartRateServer::~HeartRateServer() { 98e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 99e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_.get() || server_if_ == -1) 100e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 101e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 102e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) 103e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 104e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1051c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Manually unregister ourselves from the daemon. It's good practice to do 1061c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // this, even though the daemon will automatically unregister us if this 1071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // process exits. 108e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray gatt_->UnregisterServer(server_if_); 109e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 110e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 111e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguraybool HeartRateServer::Run(const RunCallback& callback) { 112e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 113e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 114e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (pending_run_cb_) { 115e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Already started"; 116e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return false; 117e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 118e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Grab the IBluetoothGattServer binder from the Bluetooth daemon. 120e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray gatt_ = bluetooth_->GetGattServerInterface(); 121e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_.get()) { 122e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface"; 123e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return false; 124e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 125e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1261c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Register this instance as a GATT server. If this call succeeds, we will 1271c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // asynchronously receive a server ID via the OnServerRegistered callback. 128e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_->RegisterServer(this)) { 129e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to register with the server interface"; 130e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return false; 131e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 132e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 133e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_ = callback; 134e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 135e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return true; 136e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 137e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1381c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::ScheduleNextMeasurement() { 1391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray main_task_runner_->PostDelayedTask( 1401c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray FROM_HERE, 1411c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray base::Bind(&HeartRateServer::SendHeartRateMeasurement, 1421c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray weak_ptr_factory_.GetWeakPtr()), 1431c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray base::TimeDelta::FromSeconds(1)); 1441c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray} 1451c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1461c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::SendHeartRateMeasurement() { 1471c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 1481c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1491c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Send a notification or indication to all enabled devices. 1501c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bool found = false; 1511c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray for (const auto& iter : device_ccc_map_) { 1521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray uint8_t ccc_val = iter.second; 1531c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1541c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!ccc_val) 1551c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray continue; 1561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1571c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray found = true; 1581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1591c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Don't send a notification if one is already pending for this device. 1601c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (pending_notification_map_[iter.first]) 1611c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray continue; 1621c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1631c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 1641c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray BuildHeartRateMeasurementValue(&value); 1651c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1661c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (gatt_->SendNotification(server_if_, iter.first, hr_measurement_id_, 1671c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray false, value)) 1681c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray pending_notification_map_[iter.first] = true; 1691c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 1701c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1711c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Still enabled! 1721c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (found) { 1731c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray ScheduleNextMeasurement(); 1741c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 1751c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 1761c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1771c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // All clients disabled notifications. 1781c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray simulation_started_ = false; 1791c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1801c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // TODO(armansito): We should keep track of closed connections here so that we 1811c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // don't send notifications to uninterested clients. 1821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray} 1831c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1841c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::BuildHeartRateMeasurementValue( 1851c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t>* out_value) { 1861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray CHECK(out_value); // Assert that |out_value| is not nullptr. 1871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1881c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Default flags field. Here is what we put in there: 1891c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Bit 0: 0 - 8-bit Heart Rate value 1901c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected. 1911c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected; 1921c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1931c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Our demo's heart rate. Pick a value between 90 and 130. 1941c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray uint8_t heart_rate = base::RandInt(90, 130); 1951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1961c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // On every tenth beat we include the Energy Expended value. 1971c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bool include_ee = false; 1981c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!(hr_notification_count_ % 10)) { 1991c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray include_ee = true; 2001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray flags |= kHREnergyExpendedPresent; 2011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 2021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 2031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray hr_notification_count_++; 2041c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1); 2051c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 2061c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Add all the value bytes. 2071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(flags); 2081c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(heart_rate); 2091c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (include_ee) { 2101c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(energy_expended_); 2111c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(energy_expended_ >> 8); 2121c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 2131c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray} 2141c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 215e0fe387561141e049bb2fc748cacb0b56af4928fArman Ugurayvoid HeartRateServer::OnServerRegistered(int status, int server_if) { 216e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 217e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 218e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (status != bluetooth::BLE_STATUS_SUCCESS) { 219e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to register GATT server"; 220e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 221e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 222e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 223e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 2241c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Registration succeeded. Store our ID, as we need it for GATT server 2251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // operations. 226e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray server_if_ = server_if; 227e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 228e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_; 229e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(INFO) << "Populating attributes"; 230e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 231e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray // Start service declaration. 232e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::unique_ptr<bluetooth::GattIdentifier> gatt_id; 2331c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!gatt_->BeginServiceDeclaration(server_if_, true, 2341c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray kHRServiceUUID, 2351c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray &gatt_id)) { 236e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to begin service declaration"; 237e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 238e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 239e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 240e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 241e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray hr_service_id_ = *gatt_id; 242e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 243e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray // Add Heart Rate Measurement characteristic. 244e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_->AddCharacteristic( 2451c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray server_if_, kHRMeasurementUUID, 2461c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::kCharacteristicPropertyNotify, 2471c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 0, &gatt_id)) { 248e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to add heart rate measurement characteristic"; 249e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 250e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 251e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 252e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 253e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray hr_measurement_id_ = *gatt_id; 254e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 255e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray // Add Client Characteristic Configuration descriptor for the Heart Rate 256e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray // Measurement characteristic. 257e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_->AddDescriptor( 2581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray server_if_, kCCCDescriptorUUID, 259e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray bluetooth::kAttributePermissionRead|bluetooth::kAttributePermissionWrite, 260e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray &gatt_id)) { 261e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to add CCC descriptor"; 262e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 263e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 264e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 265e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 266e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray hr_measurement_cccd_id_ = *gatt_id; 267e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 268e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray // Add Body Sensor Location characteristic. 269e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_->AddCharacteristic( 2701c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray server_if_, kBodySensorLocationUUID, 271e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray bluetooth::kCharacteristicPropertyRead, 272e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray bluetooth::kAttributePermissionRead, 273e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray &gatt_id)) { 274e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to add body sensor location characteristic"; 275e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 276e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 277e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 278e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 279e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray body_sensor_loc_id_ = *gatt_id; 280e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 281e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray // Add Heart Rate Control Point characteristic. 282e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_->AddCharacteristic( 2831c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray server_if_, kHRControlPointUUID, 284e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray bluetooth::kCharacteristicPropertyWrite, 285e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray bluetooth::kAttributePermissionWrite, 286e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray &gatt_id)) { 287e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to add heart rate control point characteristic"; 288e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 289e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 290e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 291e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 292e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray hr_control_point_id_ = *gatt_id; 293e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 2941c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // End service declaration. We will be notified whether or not this succeeded 2951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // via the OnServiceAdded callback. 296e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_->EndServiceDeclaration(server_if_)) { 297e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to end service declaration"; 298e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 299e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 300e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 301e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 302e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(INFO) << "Initiated EndServiceDeclaration request"; 303e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 304e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 305e0fe387561141e049bb2fc748cacb0b56af4928fArman Ugurayvoid HeartRateServer::OnServiceAdded( 306e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray int status, 307e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray const bluetooth::GattIdentifier& service_id) { 308e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 309e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 310e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (status != bluetooth::BLE_STATUS_SUCCESS) { 311e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to add Heart Rate service"; 312e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 313e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 314e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 315e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 316e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (service_id != hr_service_id_) { 317e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Received callback for the wrong service ID"; 318e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 319e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return; 320e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 321e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 3221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // EndServiceDeclaration succeeded! Our Heart Rate service is now discoverable 3231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // over GATT connections. 3241c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 325e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(INFO) << "Heart Rate service added"; 326e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(true); 327032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 328032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski if (advertise_) { 329032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski auto ble = bluetooth_->GetLowEnergyInterface(); 330032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski if (!ble.get()) { 331032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski LOG(ERROR) << "Failed to obtain handle to IBluetoothLowEnergy interface"; 332032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski return; 333032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski } 334032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski ble->RegisterClient(new CLIBluetoothLowEnergyCallback(bluetooth_)); 335032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski } 336032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 337e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 338e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 339514bf6087093375351784b287cb29c5f4603273cArman Ugurayvoid HeartRateServer::OnCharacteristicReadRequest( 340514bf6087093375351784b287cb29c5f4603273cArman Uguray const std::string& device_address, 3411c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray int request_id, int offset, bool /* is_long */, 342514bf6087093375351784b287cb29c5f4603273cArman Uguray const bluetooth::GattIdentifier& characteristic_id) { 3431c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 3441c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3451c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic read. Only the body 3461c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // sensor location characteristic is readable. 3471c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray CHECK(characteristic_id == body_sensor_loc_id_); 3481c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3491c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 3501c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE; 3511c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (offset > 1) 3521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray error = bluetooth::GATT_ERROR_INVALID_OFFSET; 3531c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray else if (offset == 0) 3541c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray value.push_back(kHRBodyLocationFoot); 3551c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, error, 3571c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray offset, value); 358514bf6087093375351784b287cb29c5f4603273cArman Uguray} 359514bf6087093375351784b287cb29c5f4603273cArman Uguray 360514bf6087093375351784b287cb29c5f4603273cArman Ugurayvoid HeartRateServer::OnDescriptorReadRequest( 361514bf6087093375351784b287cb29c5f4603273cArman Uguray const std::string& device_address, 3621c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray int request_id, int offset, bool /* is_long */, 363514bf6087093375351784b287cb29c5f4603273cArman Uguray const bluetooth::GattIdentifier& descriptor_id) { 3641c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 3651c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3661c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic descriptor read. There 3671c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // is only one descriptor. 3681c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (descriptor_id != hr_measurement_cccd_id_) { 3691c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 3701c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 3711c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, 3721c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray offset, value); 3731c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 3741c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 3751c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3761c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // 16-bit value encoded as little-endian. 3771c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray const uint8_t value_bytes[] = { device_ccc_map_[device_address], 0x00 }; 3781c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3791c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 3801c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE; 3811c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (offset > 2) 3821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray error = bluetooth::GATT_ERROR_INVALID_OFFSET; 3831c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray else 3841c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset); 3851c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, error, 3871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray offset, value); 388514bf6087093375351784b287cb29c5f4603273cArman Uguray} 389514bf6087093375351784b287cb29c5f4603273cArman Uguray 3904ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Ugurayvoid HeartRateServer::OnCharacteristicWriteRequest( 3914ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray const std::string& device_address, 3924ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray int request_id, int offset, bool is_prepare_write, bool need_response, 3934ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray const std::vector<uint8_t>& value, 3941c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray const bluetooth::GattIdentifier& characteristic_id) { 3951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 3961c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3971c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> dummy; 3981c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3991c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic write. The Heart Rate 4001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // service doesn't really support prepared writes, so we just reject them to 4011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // keep things simple. 4021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (is_prepare_write) { 4031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4041c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 4051c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray offset, dummy); 4061c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 4071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4081c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4091c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Heart Rate Control point is the only writable characteristic. 4101c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray CHECK(characteristic_id == hr_control_point_id_); 4111c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4121c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Writes to the Heart Rate Control Point characteristic must contain a single 4131c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // byte with the value 0x01. 4141c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (value.size() != 1 || value[0] != 0x01) { 4151c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_OUT_OF_RANGE, 4171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray offset, dummy); 4181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 4191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4201c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4211c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!"; 4221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray energy_expended_ = 0; 4231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4241c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!need_response) 4251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 4261c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4271c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4281c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_NONE, offset, dummy); 4294ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray} 4304ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray 4314ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Ugurayvoid HeartRateServer::OnDescriptorWriteRequest( 4324ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray const std::string& device_address, 4334ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray int request_id, int offset, bool is_prepare_write, bool need_response, 4344ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray const std::vector<uint8_t>& value, 4351c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray const bluetooth::GattIdentifier& descriptor_id) { 4361c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 4371c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4381c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> dummy; 4391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4401c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic write. The Heart Rate 4411c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // service doesn't really support prepared writes, so we just reject them to 4421c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // keep things simple. 4431c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (is_prepare_write) { 4441c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4451c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 4461c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray offset, dummy); 4471c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 4481c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4491c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4501c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // CCC is the only descriptor we have. 4511c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray CHECK(descriptor_id == hr_measurement_cccd_id_); 4521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4531c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // CCC must contain 2 bytes for a 16-bit value in little-endian. The only 4541c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // allowed values here are 0x0000 and 0x0001. 4551c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) { 4561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4571c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED, 4581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray offset, dummy); 4591c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 4601c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4611c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4621c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray device_ccc_map_[device_address] = value[0]; 4631c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4641c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray LOG(INFO) << "Heart Rate Measurement CCC written - device: " 4651c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray << device_address << " value: " << (int)value[0]; 4661c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4671c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Start the simulation. 4681c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!simulation_started_ && value[0]) { 4691c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray simulation_started_ = true; 4701c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray ScheduleNextMeasurement(); 4711c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4721c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4731c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!need_response) 4741c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 4751c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4761c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4771c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_NONE, offset, dummy); 4784ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray} 4794ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray 4804ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Ugurayvoid HeartRateServer::OnExecuteWriteRequest( 4814ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray const std::string& device_address, 4821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray int request_id, 4831c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bool /* is_execute */) { 4841c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // We don't support Prepared Writes so, simply return Not Supported error. 4851c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> dummy; 4861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy); 4884ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray} 4894ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray 490cd644e3c54a4321b7626b52531c59f88e24e87beArman Ugurayvoid HeartRateServer::OnNotificationSent( 491cd644e3c54a4321b7626b52531c59f88e24e87beArman Uguray const std::string& device_address, int status) { 4921c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray LOG(INFO) << "Notification was sent - device: " << device_address 4931c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray << " status: " << status; 4941c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 4951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray pending_notification_map_[device_address] = false; 496cd644e3c54a4321b7626b52531c59f88e24e87beArman Uguray} 497cd644e3c54a4321b7626b52531c59f88e24e87beArman Uguray 498e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} // namespace heart_rate 499