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