blob: 8b8e879b8db9cd497d402eb94a1958aeefc97cf4 [file] [log] [blame]
Arman Uguraye0fe3872015-09-25 20:29:17 -07001//
Jakub Pawlowski5b790fe2017-09-18 09:00:20 -07002// Copyright 2015 Google, Inc.
Arman Uguraye0fe3872015-09-25 20:29:17 -07003//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Arman Uguray1c162dc2015-09-29 22:30:53 -070016#include <base/bind.h>
17#include <base/location.h>
Arman Uguraye0fe3872015-09-25 20:29:17 -070018#include <base/logging.h>
Arman Uguray1c162dc2015-09-29 22:30:53 -070019#include <base/rand_util.h>
Arman Uguraye0fe3872015-09-25 20:29:17 -070020
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070021#include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
22#include <android/bluetooth/IBluetoothLeAdvertiser.h>
Arman Uguray234138e2015-10-06 15:56:36 -070023#include <bluetooth/low_energy_constants.h>
24
Jack Hee2eeff42016-12-07 18:25:17 -080025#include "constants.h"
26#include "heart_rate_server.h"
Arman Uguraye0fe3872015-09-25 20:29:17 -070027
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080028using android::binder::Status;
29using android::String8;
30using android::String16;
31
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070032using android::bluetooth::IBluetoothLeAdvertiser;
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -070033using android::bluetooth::BluetoothGattService;
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080034
Arman Uguraye0fe3872015-09-25 20:29:17 -070035namespace heart_rate {
36
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070037class CLIBluetoothLeAdvertiserCallback
38 : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
Jakub Pawlowski032169c2016-01-22 15:07:07 -080039 public:
Myles Watson911d1ae2016-11-28 16:44:40 -080040 explicit CLIBluetoothLeAdvertiserCallback(
41 android::sp<android::bluetooth::IBluetooth> bt)
Jakub Pawlowski032169c2016-01-22 15:07:07 -080042 : bt_(bt) {}
43
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070044 // IBluetoothLeAdvertiserCallback overrides:
45 Status OnAdvertiserRegistered(int status, int advertiser_id) {
Jakub Pawlowski032169c2016-01-22 15:07:07 -080046 if (status != bluetooth::BLE_STATUS_SUCCESS) {
Myles Watson911d1ae2016-11-28 16:44:40 -080047 LOG(ERROR)
48 << "Failed to register BLE advertiser, will not start advertising";
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080049 return Status::ok();
Jakub Pawlowski032169c2016-01-22 15:07:07 -080050 }
51
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070052 LOG(INFO) << "Registered BLE advertiser with ID: " << advertiser_id;
Jakub Pawlowski032169c2016-01-22 15:07:07 -080053
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -070054 String16 name_param;
55 bt_->GetName(&name_param);
56 std::string name(String8(name_param).string());
57
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -070058 /* Advertising data: 16-bit Service Uuid: Heart Rate Service, Tx power*/
59 std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUuids,
Myles Watson911d1ae2016-11-28 16:44:40 -080060 0x0D, 0x18,
61 0x02, bluetooth::kEIRTypeTxPower,
62 0x00};
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -070063 data.push_back(name.length() + 1);
64 data.push_back(bluetooth::kEIRTypeCompleteLocalName);
Jakub Pawlowskie3051fe2017-01-09 06:47:39 -080065 data.insert(data.end(), name.c_str(), name.c_str() + name.length());
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -070066
Jakub Pawlowski032169c2016-01-22 15:07:07 -080067 base::TimeDelta timeout;
68
69 bluetooth::AdvertiseSettings settings(
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080070 bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
71 bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, true);
Jakub Pawlowski032169c2016-01-22 15:07:07 -080072
73 bluetooth::AdvertiseData adv_data(data);
Jakub Pawlowski032169c2016-01-22 15:07:07 -080074 bluetooth::AdvertiseData scan_rsp;
75
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070076 android::sp<IBluetoothLeAdvertiser> ble;
77 bt_->GetLeAdvertiserInterface(&ble);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080078 bool start_status;
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070079 ble->StartMultiAdvertising(advertiser_id, adv_data, scan_rsp, settings,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080080 &start_status);
81 return Status::ok();
Jakub Pawlowski032169c2016-01-22 15:07:07 -080082 }
83
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080084 Status OnMultiAdvertiseCallback(
85 int status, bool is_start,
86 const android::bluetooth::AdvertiseSettings& /* settings */) {
87 LOG(INFO) << "Advertising" << (is_start ? " started" : " stopped");
88 return Status::ok();
Jakub Pawlowski032169c2016-01-22 15:07:07 -080089 };
90
91 private:
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080092 android::sp<android::bluetooth::IBluetooth> bt_;
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070093 DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
Jakub Pawlowski032169c2016-01-22 15:07:07 -080094};
95
Arman Uguray1c162dc2015-09-29 22:30:53 -070096HeartRateServer::HeartRateServer(
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -080097 android::sp<android::bluetooth::IBluetooth> bluetooth,
Jakub Pawlowski032169c2016-01-22 15:07:07 -080098 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
99 bool advertise)
Arman Uguray1c162dc2015-09-29 22:30:53 -0700100 : simulation_started_(false),
101 bluetooth_(bluetooth),
102 server_if_(-1),
103 hr_notification_count_(0),
104 energy_expended_(0),
Jakub Pawlowski032169c2016-01-22 15:07:07 -0800105 advertise_(advertise),
Arman Uguray1c162dc2015-09-29 22:30:53 -0700106 main_task_runner_(main_task_runner),
107 weak_ptr_factory_(this) {
Arman Uguraye0fe3872015-09-25 20:29:17 -0700108 CHECK(bluetooth_.get());
109}
110
111HeartRateServer::~HeartRateServer() {
112 std::lock_guard<std::mutex> lock(mutex_);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800113 if (!gatt_.get() || server_if_ == -1) return;
Arman Uguraye0fe3872015-09-25 20:29:17 -0700114
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800115 if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) return;
Arman Uguraye0fe3872015-09-25 20:29:17 -0700116
Arman Uguray1c162dc2015-09-29 22:30:53 -0700117 // Manually unregister ourselves from the daemon. It's good practice to do
118 // this, even though the daemon will automatically unregister us if this
119 // process exits.
Arman Uguraye0fe3872015-09-25 20:29:17 -0700120 gatt_->UnregisterServer(server_if_);
121}
122
123bool HeartRateServer::Run(const RunCallback& callback) {
124 std::lock_guard<std::mutex> lock(mutex_);
125
126 if (pending_run_cb_) {
127 LOG(ERROR) << "Already started";
128 return false;
129 }
130
Arman Uguray1c162dc2015-09-29 22:30:53 -0700131 // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800132 bluetooth_->GetGattServerInterface(&gatt_);
Arman Uguraye0fe3872015-09-25 20:29:17 -0700133 if (!gatt_.get()) {
134 LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
135 return false;
136 }
137
Arman Uguray1c162dc2015-09-29 22:30:53 -0700138 // Register this instance as a GATT server. If this call succeeds, we will
139 // asynchronously receive a server ID via the OnServerRegistered callback.
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800140 bool status;
141 gatt_->RegisterServer(this, &status);
142 if (!status) {
Arman Uguraye0fe3872015-09-25 20:29:17 -0700143 LOG(ERROR) << "Failed to register with the server interface";
144 return false;
145 }
146
147 pending_run_cb_ = callback;
148
149 return true;
150}
151
Arman Uguray1c162dc2015-09-29 22:30:53 -0700152void HeartRateServer::ScheduleNextMeasurement() {
153 main_task_runner_->PostDelayedTask(
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800154 FROM_HERE, base::Bind(&HeartRateServer::SendHeartRateMeasurement,
155 weak_ptr_factory_.GetWeakPtr()),
Arman Uguray1c162dc2015-09-29 22:30:53 -0700156 base::TimeDelta::FromSeconds(1));
157}
158
159void HeartRateServer::SendHeartRateMeasurement() {
160 std::lock_guard<std::mutex> lock(mutex_);
161
162 // Send a notification or indication to all enabled devices.
163 bool found = false;
164 for (const auto& iter : device_ccc_map_) {
165 uint8_t ccc_val = iter.second;
166
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800167 if (!ccc_val) continue;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700168
169 found = true;
170
171 // Don't send a notification if one is already pending for this device.
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800172 if (pending_notification_map_[iter.first]) continue;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700173
174 std::vector<uint8_t> value;
175 BuildHeartRateMeasurementValue(&value);
176
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800177 bool status;
178 gatt_->SendNotification(server_if_, String16(String8(iter.first.c_str())),
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700179 hr_measurement_handle_, false, value, &status);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800180 if (status) pending_notification_map_[iter.first] = true;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700181 }
182
183 // Still enabled!
184 if (found) {
185 ScheduleNextMeasurement();
186 return;
187 }
188
189 // All clients disabled notifications.
190 simulation_started_ = false;
191
192 // TODO(armansito): We should keep track of closed connections here so that we
193 // don't send notifications to uninterested clients.
194}
195
196void HeartRateServer::BuildHeartRateMeasurementValue(
197 std::vector<uint8_t>* out_value) {
198 CHECK(out_value); // Assert that |out_value| is not nullptr.
199
200 // Default flags field. Here is what we put in there:
201 // Bit 0: 0 - 8-bit Heart Rate value
202 // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected.
203 uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected;
204
205 // Our demo's heart rate. Pick a value between 90 and 130.
206 uint8_t heart_rate = base::RandInt(90, 130);
207
208 // On every tenth beat we include the Energy Expended value.
209 bool include_ee = false;
210 if (!(hr_notification_count_ % 10)) {
211 include_ee = true;
212 flags |= kHREnergyExpendedPresent;
213 }
214
215 hr_notification_count_++;
216 energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
217
218 // Add all the value bytes.
219 out_value->push_back(flags);
220 out_value->push_back(heart_rate);
221 if (include_ee) {
222 out_value->push_back(energy_expended_);
223 out_value->push_back(energy_expended_ >> 8);
224 }
225}
226
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800227Status HeartRateServer::OnServerRegistered(int status, int server_if) {
Arman Uguraye0fe3872015-09-25 20:29:17 -0700228 std::lock_guard<std::mutex> lock(mutex_);
229
230 if (status != bluetooth::BLE_STATUS_SUCCESS) {
231 LOG(ERROR) << "Failed to register GATT server";
232 pending_run_cb_(false);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800233 return Status::ok();
Arman Uguraye0fe3872015-09-25 20:29:17 -0700234 }
235
Arman Uguray1c162dc2015-09-29 22:30:53 -0700236 // Registration succeeded. Store our ID, as we need it for GATT server
237 // operations.
Arman Uguraye0fe3872015-09-25 20:29:17 -0700238 server_if_ = server_if;
239
240 LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
Arman Uguraye0fe3872015-09-25 20:29:17 -0700241
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700242 bluetooth::Service hrService(0, true, kHRServiceUuid,
243 {{0,
244 kHRMeasurementUuid,
245 bluetooth::kCharacteristicPropertyNotify,
246 0,
247 {{0, kCCCDescriptorUuid,
248 (bluetooth::kAttributePermissionRead |
249 bluetooth::kAttributePermissionWrite)}}},
250 {0,
251 kBodySensorLocationUuid,
252 bluetooth::kCharacteristicPropertyRead,
253 bluetooth::kAttributePermissionRead,
254 {}},
255 {0,
256 kHRControlPointUuid,
257 bluetooth::kCharacteristicPropertyWrite,
258 bluetooth::kAttributePermissionWrite,
259 {}}},
260 {});
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700261
262 bool op_status = true;
263
Myles Watson911d1ae2016-11-28 16:44:40 -0800264 Status stat = gatt_->AddService(server_if_, (BluetoothGattService)hrService,
265 &op_status);
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700266 if (!stat.isOk()) {
267 LOG(ERROR) << "Failed to add service, status is: " /*<< stat*/;
Arman Uguraye0fe3872015-09-25 20:29:17 -0700268 pending_run_cb_(false);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800269 return Status::ok();
Arman Uguraye0fe3872015-09-25 20:29:17 -0700270 }
271
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800272 if (!op_status) {
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700273 LOG(ERROR) << "Failed to add service";
Arman Uguraye0fe3872015-09-25 20:29:17 -0700274 pending_run_cb_(false);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800275 return Status::ok();
Arman Uguraye0fe3872015-09-25 20:29:17 -0700276 }
277
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700278 LOG(INFO) << "Initiated AddService request";
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800279 return Status::ok();
Arman Uguraye0fe3872015-09-25 20:29:17 -0700280}
281
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800282Status HeartRateServer::OnServiceAdded(
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700283 int status, const android::bluetooth::BluetoothGattService& service) {
Arman Uguraye0fe3872015-09-25 20:29:17 -0700284 std::lock_guard<std::mutex> lock(mutex_);
285
286 if (status != bluetooth::BLE_STATUS_SUCCESS) {
287 LOG(ERROR) << "Failed to add Heart Rate service";
288 pending_run_cb_(false);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800289 return Status::ok();
Arman Uguraye0fe3872015-09-25 20:29:17 -0700290 }
291
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700292 hr_service_handle_ = service.handle();
293 hr_measurement_handle_ = service.characteristics()[0].handle();
294 hr_measurement_cccd_handle_ =
295 service.characteristics()[0].descriptors()[0].handle();
296 body_sensor_loc_handle_ = service.characteristics()[1].handle();
297 hr_control_point_handle_ = service.characteristics()[2].handle();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700298
Arman Uguraye0fe3872015-09-25 20:29:17 -0700299 LOG(INFO) << "Heart Rate service added";
300 pending_run_cb_(true);
Jakub Pawlowski032169c2016-01-22 15:07:07 -0800301
302 if (advertise_) {
Jakub Pawlowski67d5a252016-07-13 11:55:16 -0700303 android::sp<IBluetoothLeAdvertiser> ble;
304 bluetooth_->GetLeAdvertiserInterface(&ble);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800305 bool status;
Myles Watson911d1ae2016-11-28 16:44:40 -0800306 ble->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(bluetooth_),
307 &status);
Jakub Pawlowski032169c2016-01-22 15:07:07 -0800308 }
309
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800310 return Status::ok();
Arman Uguraye0fe3872015-09-25 20:29:17 -0700311}
312
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800313Status HeartRateServer::OnCharacteristicReadRequest(
314 const String16& device_address, int request_id, int offset,
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700315 bool /* is_long */, int handle) {
Arman Uguray1c162dc2015-09-29 22:30:53 -0700316 std::lock_guard<std::mutex> lock(mutex_);
317
318 // This is where we handle an incoming characteristic read. Only the body
319 // sensor location characteristic is readable.
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700320 CHECK(handle == body_sensor_loc_handle_);
Arman Uguray1c162dc2015-09-29 22:30:53 -0700321
322 std::vector<uint8_t> value;
323 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
324 if (offset > 1)
325 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
326 else if (offset == 0)
327 value.push_back(kHRBodyLocationFoot);
328
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800329 bool status;
330 gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
331 value, &status);
332 return Status::ok();
Arman Uguray514bf602015-09-29 19:38:03 -0700333}
334
Myles Watson911d1ae2016-11-28 16:44:40 -0800335Status HeartRateServer::OnDescriptorReadRequest(const String16& device_address,
336 int request_id, int offset,
337 bool /* is_long */,
338 int handle) {
Arman Uguray1c162dc2015-09-29 22:30:53 -0700339 std::lock_guard<std::mutex> lock(mutex_);
340
341 // This is where we handle an incoming characteristic descriptor read. There
342 // is only one descriptor.
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700343 if (handle != hr_measurement_cccd_handle_) {
Arman Uguray1c162dc2015-09-29 22:30:53 -0700344 std::vector<uint8_t> value;
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800345 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700346 gatt_->SendResponse(server_if_, device_address, request_id,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800347 bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, offset,
348 value, &status);
349 return Status::ok();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700350 }
351
352 // 16-bit value encoded as little-endian.
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800353 const uint8_t value_bytes[] = {
354 device_ccc_map_[std::string(String8(device_address).string())], 0x00};
Arman Uguray1c162dc2015-09-29 22:30:53 -0700355
356 std::vector<uint8_t> value;
357 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
358 if (offset > 2)
359 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
360 else
361 value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
362
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800363 bool status;
364 gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
365 value, &status);
366 return Status::ok();
Arman Uguray514bf602015-09-29 19:38:03 -0700367}
368
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800369Status HeartRateServer::OnCharacteristicWriteRequest(
370 const String16& device_address, int request_id, int offset,
371 bool is_prepare_write, bool need_response,
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700372 const std::vector<uint8_t>& value, int handle) {
Arman Uguray1c162dc2015-09-29 22:30:53 -0700373 std::lock_guard<std::mutex> lock(mutex_);
374
375 std::vector<uint8_t> dummy;
376
377 // This is where we handle an incoming characteristic write. The Heart Rate
378 // service doesn't really support prepared writes, so we just reject them to
379 // keep things simple.
380 if (is_prepare_write) {
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800381 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700382 gatt_->SendResponse(server_if_, device_address, request_id,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800383 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
384 dummy, &status);
385 return Status::ok();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700386 }
387
388 // Heart Rate Control point is the only writable characteristic.
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700389 CHECK(handle == hr_control_point_handle_);
Arman Uguray1c162dc2015-09-29 22:30:53 -0700390
391 // Writes to the Heart Rate Control Point characteristic must contain a single
392 // byte with the value 0x01.
393 if (value.size() != 1 || value[0] != 0x01) {
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800394 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700395 gatt_->SendResponse(server_if_, device_address, request_id,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800396 bluetooth::GATT_ERROR_OUT_OF_RANGE, offset, dummy,
397 &status);
398 return Status::ok();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700399 }
400
401 LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
402 energy_expended_ = 0;
403
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800404 if (!need_response) return Status::ok();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700405
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800406 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700407 gatt_->SendResponse(server_if_, device_address, request_id,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800408 bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
409 return Status::ok();
Arman Uguray4ebcbd92015-09-29 22:09:46 -0700410}
411
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800412Status HeartRateServer::OnDescriptorWriteRequest(
413 const String16& device_address, int request_id, int offset,
414 bool is_prepare_write, bool need_response,
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700415 const std::vector<uint8_t>& value, int handle) {
Arman Uguray1c162dc2015-09-29 22:30:53 -0700416 std::lock_guard<std::mutex> lock(mutex_);
417
418 std::vector<uint8_t> dummy;
419
420 // This is where we handle an incoming characteristic write. The Heart Rate
421 // service doesn't really support prepared writes, so we just reject them to
422 // keep things simple.
423 if (is_prepare_write) {
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800424 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700425 gatt_->SendResponse(server_if_, device_address, request_id,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800426 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
427 dummy, &status);
428 return Status::ok();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700429 }
430
431 // CCC is the only descriptor we have.
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700432 CHECK(handle == hr_measurement_cccd_handle_);
Arman Uguray1c162dc2015-09-29 22:30:53 -0700433
434 // CCC must contain 2 bytes for a 16-bit value in little-endian. The only
435 // allowed values here are 0x0000 and 0x0001.
436 if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) {
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800437 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700438 gatt_->SendResponse(server_if_, device_address, request_id,
439 bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800440 offset, dummy, &status);
441 return Status::ok();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700442 }
443
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800444 device_ccc_map_[std::string(String8(device_address).string())] = value[0];
Arman Uguray1c162dc2015-09-29 22:30:53 -0700445
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800446 LOG(INFO) << "Heart Rate Measurement CCC written - device: " << device_address
447 << " value: " << (int)value[0];
Arman Uguray1c162dc2015-09-29 22:30:53 -0700448
449 // Start the simulation.
450 if (!simulation_started_ && value[0]) {
451 simulation_started_ = true;
452 ScheduleNextMeasurement();
453 }
454
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800455 if (!need_response) return Status::ok();
Arman Uguray1c162dc2015-09-29 22:30:53 -0700456
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800457 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700458 gatt_->SendResponse(server_if_, device_address, request_id,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800459 bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
460 return Status::ok();
Arman Uguray4ebcbd92015-09-29 22:09:46 -0700461}
462
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800463Status HeartRateServer::OnExecuteWriteRequest(const String16& device_address,
464 int request_id,
465 bool /* is_execute */) {
Arman Uguray1c162dc2015-09-29 22:30:53 -0700466 // We don't support Prepared Writes so, simply return Not Supported error.
467 std::vector<uint8_t> dummy;
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800468 bool status;
Arman Uguray1c162dc2015-09-29 22:30:53 -0700469 gatt_->SendResponse(server_if_, device_address, request_id,
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800470 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy,
471 &status);
472
473 return Status::ok();
Arman Uguray4ebcbd92015-09-29 22:09:46 -0700474}
475
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800476Status HeartRateServer::OnNotificationSent(const String16& device_address,
477 int status) {
Arman Uguray1c162dc2015-09-29 22:30:53 -0700478 LOG(INFO) << "Notification was sent - device: " << device_address
479 << " status: " << status;
480 std::lock_guard<std::mutex> lock(mutex_);
Jakub Pawlowskia4bd0d22016-02-16 11:53:14 -0800481 pending_notification_map_[std::string(String8(device_address).string())] =
482 false;
483
484 return Status::ok();
Arman Uguraycd644e32015-10-01 16:36:38 -0700485}
486
Jakub Pawlowski79327272016-07-07 16:40:11 -0700487Status HeartRateServer::OnConnectionStateChanged(const String16& device_address,
488 bool connected) {
489 LOG(INFO) << "Connection state changed - device: " << device_address
Myles Watson911d1ae2016-11-28 16:44:40 -0800490 << " connected: " << (connected ? "true" : "false");
Jakub Pawlowski79327272016-07-07 16:40:11 -0700491 return Status::ok();
492}
Arman Uguraye0fe3872015-09-25 20:29:17 -0700493} // namespace heart_rate