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// 161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/bind.h> 171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/location.h> 18e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray#include <base/logging.h> 191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/rand_util.h> 20e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 2167d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski#include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h> 2267d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski#include <android/bluetooth/IBluetoothLeAdvertiser.h> 23234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray#include <bluetooth/low_energy_constants.h> 24234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray 25e2eeff4f7f149c59ea8cb67392f287317f40f9bdJack He#include "constants.h" 26e2eeff4f7f149c59ea8cb67392f287317f40f9bdJack He#include "heart_rate_server.h" 27e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 28a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::binder::Status; 29a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::String8; 30a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::String16; 31a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski 3267d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowskiusing android::bluetooth::IBluetoothLeAdvertiser; 33a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowskiusing android::bluetooth::BluetoothGattService; 34a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski 35e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguraynamespace heart_rate { 36e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 3767d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowskiclass CLIBluetoothLeAdvertiserCallback 3867d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski : public android::bluetooth::BnBluetoothLeAdvertiserCallback { 39032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski public: 40911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson explicit CLIBluetoothLeAdvertiserCallback( 41911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson android::sp<android::bluetooth::IBluetooth> bt) 42032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski : bt_(bt) {} 43032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 4467d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski // IBluetoothLeAdvertiserCallback overrides: 4567d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski Status OnAdvertiserRegistered(int status, int advertiser_id) { 46032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski if (status != bluetooth::BLE_STATUS_SUCCESS) { 47911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson LOG(ERROR) 48911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson << "Failed to register BLE advertiser, will not start advertising"; 49a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 50032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski } 51032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 5267d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski LOG(INFO) << "Registered BLE advertiser with ID: " << advertiser_id; 53032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 540ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski String16 name_param; 550ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski bt_->GetName(&name_param); 560ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski std::string name(String8(name_param).string()); 570ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski 580ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski /* Advertising data: 16-bit Service UUID: Heart Rate Service, Tx power*/ 59911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUUIDs, 60911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson 0x0D, 0x18, 61911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson 0x02, bluetooth::kEIRTypeTxPower, 62911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson 0x00}; 630ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski data.push_back(name.length() + 1); 640ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski data.push_back(bluetooth::kEIRTypeCompleteLocalName); 65e3051fec0629b8b10812c2afbadb414bb6cf0629Jakub Pawlowski data.insert(data.end(), name.c_str(), name.c_str() + name.length()); 660ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski 67032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski base::TimeDelta timeout; 68032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 69032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseSettings settings( 70a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout, 71a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, true); 72032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 73032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseData adv_data(data); 74032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bluetooth::AdvertiseData scan_rsp; 75032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 7667d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski android::sp<IBluetoothLeAdvertiser> ble; 7767d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski bt_->GetLeAdvertiserInterface(&ble); 78a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool start_status; 7967d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski ble->StartMultiAdvertising(advertiser_id, adv_data, scan_rsp, settings, 80a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski &start_status); 81a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 82032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski } 83032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 84a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski Status OnMultiAdvertiseCallback( 85a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski int status, bool is_start, 86a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski const android::bluetooth::AdvertiseSettings& /* settings */) { 87a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski LOG(INFO) << "Advertising" << (is_start ? " started" : " stopped"); 88a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 89032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski }; 90032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 91032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski private: 92a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski android::sp<android::bluetooth::IBluetooth> bt_; 9367d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback); 94032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski}; 95032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 961c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman UgurayHeartRateServer::HeartRateServer( 97a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski android::sp<android::bluetooth::IBluetooth> bluetooth, 98032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, 99032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski bool advertise) 1001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray : simulation_started_(false), 1011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth_(bluetooth), 1021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray server_if_(-1), 1031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray hr_notification_count_(0), 1041c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray energy_expended_(0), 105032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski advertise_(advertise), 1061c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray main_task_runner_(main_task_runner), 1071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray weak_ptr_factory_(this) { 108e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray CHECK(bluetooth_.get()); 109e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 110e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 111e0fe387561141e049bb2fc748cacb0b56af4928fArman UgurayHeartRateServer::~HeartRateServer() { 112e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 113a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (!gatt_.get() || server_if_ == -1) return; 114e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 115a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) return; 116e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Manually unregister ourselves from the daemon. It's good practice to do 1181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // this, even though the daemon will automatically unregister us if this 1191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // process exits. 120e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray gatt_->UnregisterServer(server_if_); 121e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 122e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 123e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguraybool HeartRateServer::Run(const RunCallback& callback) { 124e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 125e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 126e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (pending_run_cb_) { 127e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Already started"; 128e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return false; 129e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 130e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1311c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Grab the IBluetoothGattServer binder from the Bluetooth daemon. 132a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth_->GetGattServerInterface(&gatt_); 133e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (!gatt_.get()) { 134e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface"; 135e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return false; 136e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 137e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1381c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Register this instance as a GATT server. If this call succeeds, we will 1391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // asynchronously receive a server ID via the OnServerRegistered callback. 140a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 141a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski gatt_->RegisterServer(this, &status); 142a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (!status) { 143e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to register with the server interface"; 144e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return false; 145e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 146e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 147e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_ = callback; 148e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 149e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray return true; 150e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 151e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 1521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::ScheduleNextMeasurement() { 1531c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray main_task_runner_->PostDelayedTask( 154a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski FROM_HERE, base::Bind(&HeartRateServer::SendHeartRateMeasurement, 155a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski weak_ptr_factory_.GetWeakPtr()), 1561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray base::TimeDelta::FromSeconds(1)); 1571c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray} 1581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1591c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::SendHeartRateMeasurement() { 1601c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 1611c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1621c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Send a notification or indication to all enabled devices. 1631c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bool found = false; 1641c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray for (const auto& iter : device_ccc_map_) { 1651c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray uint8_t ccc_val = iter.second; 1661c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 167a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (!ccc_val) continue; 1681c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1691c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray found = true; 1701c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1711c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Don't send a notification if one is already pending for this device. 172a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (pending_notification_map_[iter.first]) continue; 1731c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1741c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 1751c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray BuildHeartRateMeasurementValue(&value); 1761c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 177a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 178a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski gatt_->SendNotification(server_if_, String16(String8(iter.first.c_str())), 179a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski hr_measurement_handle_, false, value, &status); 180a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (status) pending_notification_map_[iter.first] = true; 1811c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 1821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1831c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Still enabled! 1841c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (found) { 1851c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray ScheduleNextMeasurement(); 1861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray return; 1871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 1881c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1891c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // All clients disabled notifications. 1901c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray simulation_started_ = false; 1911c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1921c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // TODO(armansito): We should keep track of closed connections here so that we 1931c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // don't send notifications to uninterested clients. 1941c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray} 1951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 1961c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::BuildHeartRateMeasurementValue( 1971c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t>* out_value) { 1981c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray CHECK(out_value); // Assert that |out_value| is not nullptr. 1991c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 2001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Default flags field. Here is what we put in there: 2011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Bit 0: 0 - 8-bit Heart Rate value 2021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected. 2031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected; 2041c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 2051c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Our demo's heart rate. Pick a value between 90 and 130. 2061c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray uint8_t heart_rate = base::RandInt(90, 130); 2071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 2081c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // On every tenth beat we include the Energy Expended value. 2091c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bool include_ee = false; 2101c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!(hr_notification_count_ % 10)) { 2111c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray include_ee = true; 2121c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray flags |= kHREnergyExpendedPresent; 2131c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 2141c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 2151c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray hr_notification_count_++; 2161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1); 2171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 2181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Add all the value bytes. 2191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(flags); 2201c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(heart_rate); 2211c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (include_ee) { 2221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(energy_expended_); 2231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray out_value->push_back(energy_expended_ >> 8); 2241c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 2251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray} 2261c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 227a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnServerRegistered(int status, int server_if) { 228e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 229e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 230e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (status != bluetooth::BLE_STATUS_SUCCESS) { 231e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to register GATT server"; 232e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 233a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 234e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 235e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 2361c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Registration succeeded. Store our ID, as we need it for GATT server 2371c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // operations. 238e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray server_if_ = server_if; 239e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 240e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_; 241e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 242911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bluetooth::Service hrService( 243911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson 0, true, kHRServiceUUID, 244911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson {{0, 245911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson kHRMeasurementUUID, 246911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bluetooth::kCharacteristicPropertyNotify, 247911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson 0, 248911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson {{0, kCCCDescriptorUUID, (bluetooth::kAttributePermissionRead | 249911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bluetooth::kAttributePermissionWrite)}}}, 250911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson {0, 251911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson kBodySensorLocationUUID, 252911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bluetooth::kCharacteristicPropertyRead, 253911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bluetooth::kAttributePermissionRead, 254911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson {}}, 255911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson {0, 256911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson kHRControlPointUUID, 257911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bluetooth::kCharacteristicPropertyWrite, 258911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bluetooth::kAttributePermissionWrite, 259911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson {}}}, 260911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson {}); 261e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 262a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski bool op_status = true; 263e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 264911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson Status stat = gatt_->AddService(server_if_, (BluetoothGattService)hrService, 265911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson &op_status); 266a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski if (!stat.isOk()) { 267a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski LOG(ERROR) << "Failed to add service, status is: " /*<< stat*/; 268e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 269a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 270e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 271e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 272a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (!op_status) { 273a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski LOG(ERROR) << "Failed to add service"; 274e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 275a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 276e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 277e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 278a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski LOG(INFO) << "Initiated AddService request"; 279a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 280e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 281e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 282a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnServiceAdded( 283a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski int status, const android::bluetooth::BluetoothGattService& service) { 284e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray std::lock_guard<std::mutex> lock(mutex_); 285e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 286e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray if (status != bluetooth::BLE_STATUS_SUCCESS) { 287e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(ERROR) << "Failed to add Heart Rate service"; 288e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(false); 289a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 290e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray } 291e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 292a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski hr_service_handle_ = service.handle(); 293a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski hr_measurement_handle_ = service.characteristics()[0].handle(); 294a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski hr_measurement_cccd_handle_ = 295a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski service.characteristics()[0].descriptors()[0].handle(); 296a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski body_sensor_loc_handle_ = service.characteristics()[1].handle(); 297a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski hr_control_point_handle_ = service.characteristics()[2].handle(); 2981c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 299e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray LOG(INFO) << "Heart Rate service added"; 300e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray pending_run_cb_(true); 301032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 302032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski if (advertise_) { 30367d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski android::sp<IBluetoothLeAdvertiser> ble; 30467d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski bluetooth_->GetLeAdvertiserInterface(&ble); 305a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 306911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson ble->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(bluetooth_), 307911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson &status); 308032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski } 309032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski 310a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 311e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} 312e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray 313a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnCharacteristicReadRequest( 314a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski const String16& device_address, int request_id, int offset, 315a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski bool /* is_long */, int handle) { 3161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 3171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic read. Only the body 3191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // sensor location characteristic is readable. 320a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski CHECK(handle == body_sensor_loc_handle_); 3211c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 3231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE; 3241c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (offset > 1) 3251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray error = bluetooth::GATT_ERROR_INVALID_OFFSET; 3261c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray else if (offset == 0) 3271c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray value.push_back(kHRBodyLocationFoot); 3281c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 329a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 330a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski gatt_->SendResponse(server_if_, device_address, request_id, error, offset, 331a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski value, &status); 332a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 333514bf6087093375351784b287cb29c5f4603273cArman Uguray} 334514bf6087093375351784b287cb29c5f4603273cArman Uguray 335911d1ae03efec2d54c3b1b605589d790d1745488Myles WatsonStatus HeartRateServer::OnDescriptorReadRequest(const String16& device_address, 336911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson int request_id, int offset, 337911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson bool /* is_long */, 338911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson int handle) { 3391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 3401c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3411c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic descriptor read. There 3421c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // is only one descriptor. 343a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski if (handle != hr_measurement_cccd_handle_) { 3441c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 345a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 3461c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 347a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, offset, 348a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski value, &status); 349a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 3501c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 3511c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // 16-bit value encoded as little-endian. 353a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski const uint8_t value_bytes[] = { 354a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski device_ccc_map_[std::string(String8(device_address).string())], 0x00}; 3551c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> value; 3571c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE; 3581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (offset > 2) 3591c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray error = bluetooth::GATT_ERROR_INVALID_OFFSET; 3601c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray else 3611c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset); 3621c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 363a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 364a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski gatt_->SendResponse(server_if_, device_address, request_id, error, offset, 365a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski value, &status); 366a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 367514bf6087093375351784b287cb29c5f4603273cArman Uguray} 368514bf6087093375351784b287cb29c5f4603273cArman Uguray 369a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnCharacteristicWriteRequest( 370a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski const String16& device_address, int request_id, int offset, 371a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool is_prepare_write, bool need_response, 372a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski const std::vector<uint8_t>& value, int handle) { 3731c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 3741c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3751c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> dummy; 3761c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3771c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic write. The Heart Rate 3781c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // service doesn't really support prepared writes, so we just reject them to 3791c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // keep things simple. 3801c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (is_prepare_write) { 381a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 3821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 383a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset, 384a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski dummy, &status); 385a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 3861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 3871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3881c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Heart Rate Control point is the only writable characteristic. 389a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski CHECK(handle == hr_control_point_handle_); 3901c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 3911c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Writes to the Heart Rate Control Point characteristic must contain a single 3921c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // byte with the value 0x01. 3931c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (value.size() != 1 || value[0] != 0x01) { 394a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 3951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 396a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::GATT_ERROR_OUT_OF_RANGE, offset, dummy, 397a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski &status); 398a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 3991c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!"; 4021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray energy_expended_ = 0; 4031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 404a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (!need_response) return Status::ok(); 4051c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 406a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 4071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 408a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::GATT_ERROR_NONE, offset, dummy, &status); 409a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 4104ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray} 4114ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray 412a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnDescriptorWriteRequest( 413a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski const String16& device_address, int request_id, int offset, 414a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool is_prepare_write, bool need_response, 415a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski const std::vector<uint8_t>& value, int handle) { 4161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 4171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> dummy; 4191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4201c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // This is where we handle an incoming characteristic write. The Heart Rate 4211c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // service doesn't really support prepared writes, so we just reject them to 4221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // keep things simple. 4231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (is_prepare_write) { 424a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 4251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 426a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset, 427a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski dummy, &status); 428a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 4291c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4301c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4311c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // CCC is the only descriptor we have. 432a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski CHECK(handle == hr_measurement_cccd_handle_); 4331c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4341c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // CCC must contain 2 bytes for a 16-bit value in little-endian. The only 4351c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // allowed values here are 0x0000 and 0x0001. 4361c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) { 437a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 4381c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 4391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED, 440a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski offset, dummy, &status); 441a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 4421c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4431c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 444a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski device_ccc_map_[std::string(String8(device_address).string())] = value[0]; 4451c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 446a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski LOG(INFO) << "Heart Rate Measurement CCC written - device: " << device_address 447a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski << " value: " << (int)value[0]; 4481c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 4491c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // Start the simulation. 4501c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray if (!simulation_started_ && value[0]) { 4511c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray simulation_started_ = true; 4521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray ScheduleNextMeasurement(); 4531c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray } 4541c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 455a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski if (!need_response) return Status::ok(); 4561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray 457a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 4581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 459a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::GATT_ERROR_NONE, offset, dummy, &status); 460a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 4614ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray} 4624ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray 463a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnExecuteWriteRequest(const String16& device_address, 464a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski int request_id, 465a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool /* is_execute */) { 4661c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray // We don't support Prepared Writes so, simply return Not Supported error. 4671c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::vector<uint8_t> dummy; 468a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bool status; 4691c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray gatt_->SendResponse(server_if_, device_address, request_id, 470a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy, 471a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski &status); 472a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski 473a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 4744ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray} 4754ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray 476a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnNotificationSent(const String16& device_address, 477a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski int status) { 4781c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray LOG(INFO) << "Notification was sent - device: " << device_address 4791c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray << " status: " << status; 4801c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray std::lock_guard<std::mutex> lock(mutex_); 481a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski pending_notification_map_[std::string(String8(device_address).string())] = 482a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski false; 483a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski 484a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski return Status::ok(); 485cd644e3c54a4321b7626b52531c59f88e24e87beArman Uguray} 486cd644e3c54a4321b7626b52531c59f88e24e87beArman Uguray 4877932727cbe07b4bc176b2d1c04f0bcf350973512Jakub PawlowskiStatus HeartRateServer::OnConnectionStateChanged(const String16& device_address, 4887932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski bool connected) { 4897932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski LOG(INFO) << "Connection state changed - device: " << device_address 490911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson << " connected: " << (connected ? "true" : "false"); 4917932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski return Status::ok(); 4927932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski} 493e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray} // namespace heart_rate 494