2 // Copyright (C) 2015 Google, Inc.
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:
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "service/example/heart_rate/heart_rate_server.h"
19 #include <base/bind.h>
20 #include <base/location.h>
21 #include <base/logging.h>
22 #include <base/rand_util.h>
24 #include <bluetooth/low_energy_constants.h>
26 #include "service/example/heart_rate/constants.h"
28 namespace heart_rate {
30 class CLIBluetoothLowEnergyCallback
31 : public ipc::binder::BnBluetoothLowEnergyCallback {
33 CLIBluetoothLowEnergyCallback(android::sp<ipc::binder::IBluetooth> bt)
36 // IBluetoothLowEnergyCallback overrides:
37 void OnConnectionState(int status, int client_id, const char* address,
38 bool connected) override {}
39 void OnMtuChanged(int status, const char *address, int mtu) override {}
41 void OnScanResult(const bluetooth::ScanResult& scan_result) override {}
43 void OnClientRegistered(int status, int client_id){
44 if (status != bluetooth::BLE_STATUS_SUCCESS) {
45 LOG(ERROR) << "Failed to register BLE client, will not start advertising";
49 LOG(INFO) << "Registered BLE client with ID: " << client_id;
51 /* Advertising data: 16-bit Service UUID: Heart Rate Service */
52 std::vector<uint8_t> data{0x03, 0x03, 0x0D, 0x18};
53 base::TimeDelta timeout;
55 bluetooth::AdvertiseSettings settings(
56 bluetooth::AdvertiseSettings::MODE_LOW_POWER,
58 bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM,
61 bluetooth::AdvertiseData adv_data(data);
62 adv_data.set_include_device_name(true);
63 adv_data.set_include_tx_power_level(true);
65 bluetooth::AdvertiseData scan_rsp;
67 bt_->GetLowEnergyInterface()->
68 StartMultiAdvertising(client_id, adv_data, scan_rsp, settings);
71 void OnMultiAdvertiseCallback(int status, bool is_start,
72 const bluetooth::AdvertiseSettings& /* settings */) {
73 LOG(INFO) << "Advertising" << (is_start?" started":" stopped");
77 android::sp<ipc::binder::IBluetooth> bt_;
78 DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
82 HeartRateServer::HeartRateServer(
83 android::sp<ipc::binder::IBluetooth> bluetooth,
84 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
86 : simulation_started_(false),
87 bluetooth_(bluetooth),
89 hr_notification_count_(0),
91 advertise_(advertise),
92 main_task_runner_(main_task_runner),
93 weak_ptr_factory_(this) {
94 CHECK(bluetooth_.get());
97 HeartRateServer::~HeartRateServer() {
98 std::lock_guard<std::mutex> lock(mutex_);
99 if (!gatt_.get() || server_if_ == -1)
102 if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive())
105 // Manually unregister ourselves from the daemon. It's good practice to do
106 // this, even though the daemon will automatically unregister us if this
108 gatt_->UnregisterServer(server_if_);
111 bool HeartRateServer::Run(const RunCallback& callback) {
112 std::lock_guard<std::mutex> lock(mutex_);
114 if (pending_run_cb_) {
115 LOG(ERROR) << "Already started";
119 // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
120 gatt_ = bluetooth_->GetGattServerInterface();
122 LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
126 // Register this instance as a GATT server. If this call succeeds, we will
127 // asynchronously receive a server ID via the OnServerRegistered callback.
128 if (!gatt_->RegisterServer(this)) {
129 LOG(ERROR) << "Failed to register with the server interface";
133 pending_run_cb_ = callback;
138 void HeartRateServer::ScheduleNextMeasurement() {
139 main_task_runner_->PostDelayedTask(
141 base::Bind(&HeartRateServer::SendHeartRateMeasurement,
142 weak_ptr_factory_.GetWeakPtr()),
143 base::TimeDelta::FromSeconds(1));
146 void HeartRateServer::SendHeartRateMeasurement() {
147 std::lock_guard<std::mutex> lock(mutex_);
149 // Send a notification or indication to all enabled devices.
151 for (const auto& iter : device_ccc_map_) {
152 uint8_t ccc_val = iter.second;
159 // Don't send a notification if one is already pending for this device.
160 if (pending_notification_map_[iter.first])
163 std::vector<uint8_t> value;
164 BuildHeartRateMeasurementValue(&value);
166 if (gatt_->SendNotification(server_if_, iter.first, hr_measurement_id_,
168 pending_notification_map_[iter.first] = true;
173 ScheduleNextMeasurement();
177 // All clients disabled notifications.
178 simulation_started_ = false;
180 // TODO(armansito): We should keep track of closed connections here so that we
181 // don't send notifications to uninterested clients.
184 void HeartRateServer::BuildHeartRateMeasurementValue(
185 std::vector<uint8_t>* out_value) {
186 CHECK(out_value); // Assert that |out_value| is not nullptr.
188 // Default flags field. Here is what we put in there:
189 // Bit 0: 0 - 8-bit Heart Rate value
190 // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected.
191 uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected;
193 // Our demo's heart rate. Pick a value between 90 and 130.
194 uint8_t heart_rate = base::RandInt(90, 130);
196 // On every tenth beat we include the Energy Expended value.
197 bool include_ee = false;
198 if (!(hr_notification_count_ % 10)) {
200 flags |= kHREnergyExpendedPresent;
203 hr_notification_count_++;
204 energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
206 // Add all the value bytes.
207 out_value->push_back(flags);
208 out_value->push_back(heart_rate);
210 out_value->push_back(energy_expended_);
211 out_value->push_back(energy_expended_ >> 8);
215 void HeartRateServer::OnServerRegistered(int status, int server_if) {
216 std::lock_guard<std::mutex> lock(mutex_);
218 if (status != bluetooth::BLE_STATUS_SUCCESS) {
219 LOG(ERROR) << "Failed to register GATT server";
220 pending_run_cb_(false);
224 // Registration succeeded. Store our ID, as we need it for GATT server
226 server_if_ = server_if;
228 LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
229 LOG(INFO) << "Populating attributes";
231 // Start service declaration.
232 std::unique_ptr<bluetooth::GattIdentifier> gatt_id;
233 if (!gatt_->BeginServiceDeclaration(server_if_, true,
236 LOG(ERROR) << "Failed to begin service declaration";
237 pending_run_cb_(false);
241 hr_service_id_ = *gatt_id;
243 // Add Heart Rate Measurement characteristic.
244 if (!gatt_->AddCharacteristic(
245 server_if_, kHRMeasurementUUID,
246 bluetooth::kCharacteristicPropertyNotify,
248 LOG(ERROR) << "Failed to add heart rate measurement characteristic";
249 pending_run_cb_(false);
253 hr_measurement_id_ = *gatt_id;
255 // Add Client Characteristic Configuration descriptor for the Heart Rate
256 // Measurement characteristic.
257 if (!gatt_->AddDescriptor(
258 server_if_, kCCCDescriptorUUID,
259 bluetooth::kAttributePermissionRead|bluetooth::kAttributePermissionWrite,
261 LOG(ERROR) << "Failed to add CCC descriptor";
262 pending_run_cb_(false);
266 hr_measurement_cccd_id_ = *gatt_id;
268 // Add Body Sensor Location characteristic.
269 if (!gatt_->AddCharacteristic(
270 server_if_, kBodySensorLocationUUID,
271 bluetooth::kCharacteristicPropertyRead,
272 bluetooth::kAttributePermissionRead,
274 LOG(ERROR) << "Failed to add body sensor location characteristic";
275 pending_run_cb_(false);
279 body_sensor_loc_id_ = *gatt_id;
281 // Add Heart Rate Control Point characteristic.
282 if (!gatt_->AddCharacteristic(
283 server_if_, kHRControlPointUUID,
284 bluetooth::kCharacteristicPropertyWrite,
285 bluetooth::kAttributePermissionWrite,
287 LOG(ERROR) << "Failed to add heart rate control point characteristic";
288 pending_run_cb_(false);
292 hr_control_point_id_ = *gatt_id;
294 // End service declaration. We will be notified whether or not this succeeded
295 // via the OnServiceAdded callback.
296 if (!gatt_->EndServiceDeclaration(server_if_)) {
297 LOG(ERROR) << "Failed to end service declaration";
298 pending_run_cb_(false);
302 LOG(INFO) << "Initiated EndServiceDeclaration request";
305 void HeartRateServer::OnServiceAdded(
307 const bluetooth::GattIdentifier& service_id) {
308 std::lock_guard<std::mutex> lock(mutex_);
310 if (status != bluetooth::BLE_STATUS_SUCCESS) {
311 LOG(ERROR) << "Failed to add Heart Rate service";
312 pending_run_cb_(false);
316 if (service_id != hr_service_id_) {
317 LOG(ERROR) << "Received callback for the wrong service ID";
318 pending_run_cb_(false);
322 // EndServiceDeclaration succeeded! Our Heart Rate service is now discoverable
323 // over GATT connections.
325 LOG(INFO) << "Heart Rate service added";
326 pending_run_cb_(true);
329 auto ble = bluetooth_->GetLowEnergyInterface();
331 LOG(ERROR) << "Failed to obtain handle to IBluetoothLowEnergy interface";
334 ble->RegisterClient(new CLIBluetoothLowEnergyCallback(bluetooth_));
339 void HeartRateServer::OnCharacteristicReadRequest(
340 const std::string& device_address,
341 int request_id, int offset, bool /* is_long */,
342 const bluetooth::GattIdentifier& characteristic_id) {
343 std::lock_guard<std::mutex> lock(mutex_);
345 // This is where we handle an incoming characteristic read. Only the body
346 // sensor location characteristic is readable.
347 CHECK(characteristic_id == body_sensor_loc_id_);
349 std::vector<uint8_t> value;
350 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
352 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
353 else if (offset == 0)
354 value.push_back(kHRBodyLocationFoot);
356 gatt_->SendResponse(server_if_, device_address, request_id, error,
360 void HeartRateServer::OnDescriptorReadRequest(
361 const std::string& device_address,
362 int request_id, int offset, bool /* is_long */,
363 const bluetooth::GattIdentifier& descriptor_id) {
364 std::lock_guard<std::mutex> lock(mutex_);
366 // This is where we handle an incoming characteristic descriptor read. There
367 // is only one descriptor.
368 if (descriptor_id != hr_measurement_cccd_id_) {
369 std::vector<uint8_t> value;
370 gatt_->SendResponse(server_if_, device_address, request_id,
371 bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND,
376 // 16-bit value encoded as little-endian.
377 const uint8_t value_bytes[] = { device_ccc_map_[device_address], 0x00 };
379 std::vector<uint8_t> value;
380 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
382 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
384 value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
386 gatt_->SendResponse(server_if_, device_address, request_id, error,
390 void HeartRateServer::OnCharacteristicWriteRequest(
391 const std::string& device_address,
392 int request_id, int offset, bool is_prepare_write, bool need_response,
393 const std::vector<uint8_t>& value,
394 const bluetooth::GattIdentifier& characteristic_id) {
395 std::lock_guard<std::mutex> lock(mutex_);
397 std::vector<uint8_t> dummy;
399 // This is where we handle an incoming characteristic write. The Heart Rate
400 // service doesn't really support prepared writes, so we just reject them to
401 // keep things simple.
402 if (is_prepare_write) {
403 gatt_->SendResponse(server_if_, device_address, request_id,
404 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED,
409 // Heart Rate Control point is the only writable characteristic.
410 CHECK(characteristic_id == hr_control_point_id_);
412 // Writes to the Heart Rate Control Point characteristic must contain a single
413 // byte with the value 0x01.
414 if (value.size() != 1 || value[0] != 0x01) {
415 gatt_->SendResponse(server_if_, device_address, request_id,
416 bluetooth::GATT_ERROR_OUT_OF_RANGE,
421 LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
422 energy_expended_ = 0;
427 gatt_->SendResponse(server_if_, device_address, request_id,
428 bluetooth::GATT_ERROR_NONE, offset, dummy);
431 void HeartRateServer::OnDescriptorWriteRequest(
432 const std::string& device_address,
433 int request_id, int offset, bool is_prepare_write, bool need_response,
434 const std::vector<uint8_t>& value,
435 const bluetooth::GattIdentifier& descriptor_id) {
436 std::lock_guard<std::mutex> lock(mutex_);
438 std::vector<uint8_t> dummy;
440 // This is where we handle an incoming characteristic write. The Heart Rate
441 // service doesn't really support prepared writes, so we just reject them to
442 // keep things simple.
443 if (is_prepare_write) {
444 gatt_->SendResponse(server_if_, device_address, request_id,
445 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED,
450 // CCC is the only descriptor we have.
451 CHECK(descriptor_id == hr_measurement_cccd_id_);
453 // CCC must contain 2 bytes for a 16-bit value in little-endian. The only
454 // allowed values here are 0x0000 and 0x0001.
455 if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) {
456 gatt_->SendResponse(server_if_, device_address, request_id,
457 bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
462 device_ccc_map_[device_address] = value[0];
464 LOG(INFO) << "Heart Rate Measurement CCC written - device: "
465 << device_address << " value: " << (int)value[0];
467 // Start the simulation.
468 if (!simulation_started_ && value[0]) {
469 simulation_started_ = true;
470 ScheduleNextMeasurement();
476 gatt_->SendResponse(server_if_, device_address, request_id,
477 bluetooth::GATT_ERROR_NONE, offset, dummy);
480 void HeartRateServer::OnExecuteWriteRequest(
481 const std::string& device_address,
483 bool /* is_execute */) {
484 // We don't support Prepared Writes so, simply return Not Supported error.
485 std::vector<uint8_t> dummy;
486 gatt_->SendResponse(server_if_, device_address, request_id,
487 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy);
490 void HeartRateServer::OnNotificationSent(
491 const std::string& device_address, int status) {
492 LOG(INFO) << "Notification was sent - device: " << device_address
493 << " status: " << status;
494 std::lock_guard<std::mutex> lock(mutex_);
495 pending_notification_map_[device_address] = false;
498 } // namespace heart_rate