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 OnScanResult(const bluetooth::ScanResult& scan_result) override {}
41 void OnClientRegistered(int status, int client_id){
42 if (status != bluetooth::BLE_STATUS_SUCCESS) {
43 LOG(ERROR) << "Failed to register BLE client, will not start advertising";
47 LOG(INFO) << "Registered BLE client with ID: " << client_id;
49 /* Advertising data: 16-bit Service UUID: Heart Rate Service */
50 std::vector<uint8_t> data{0x03, 0x03, 0x0D, 0x18};
51 base::TimeDelta timeout;
53 bluetooth::AdvertiseSettings settings(
54 bluetooth::AdvertiseSettings::MODE_LOW_POWER,
56 bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM,
59 bluetooth::AdvertiseData adv_data(data);
60 adv_data.set_include_device_name(true);
61 adv_data.set_include_tx_power_level(true);
63 bluetooth::AdvertiseData scan_rsp;
65 bt_->GetLowEnergyInterface()->
66 StartMultiAdvertising(client_id, adv_data, scan_rsp, settings);
69 void OnMultiAdvertiseCallback(int status, bool is_start,
70 const bluetooth::AdvertiseSettings& /* settings */) {
71 LOG(INFO) << "Advertising" << (is_start?" started":" stopped");
75 android::sp<ipc::binder::IBluetooth> bt_;
76 DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
80 HeartRateServer::HeartRateServer(
81 android::sp<ipc::binder::IBluetooth> bluetooth,
82 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
84 : simulation_started_(false),
85 bluetooth_(bluetooth),
87 hr_notification_count_(0),
89 advertise_(advertise),
90 main_task_runner_(main_task_runner),
91 weak_ptr_factory_(this) {
92 CHECK(bluetooth_.get());
95 HeartRateServer::~HeartRateServer() {
96 std::lock_guard<std::mutex> lock(mutex_);
97 if (!gatt_.get() || server_if_ == -1)
100 if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive())
103 // Manually unregister ourselves from the daemon. It's good practice to do
104 // this, even though the daemon will automatically unregister us if this
106 gatt_->UnregisterServer(server_if_);
109 bool HeartRateServer::Run(const RunCallback& callback) {
110 std::lock_guard<std::mutex> lock(mutex_);
112 if (pending_run_cb_) {
113 LOG(ERROR) << "Already started";
117 // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
118 gatt_ = bluetooth_->GetGattServerInterface();
120 LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
124 // Register this instance as a GATT server. If this call succeeds, we will
125 // asynchronously receive a server ID via the OnServerRegistered callback.
126 if (!gatt_->RegisterServer(this)) {
127 LOG(ERROR) << "Failed to register with the server interface";
131 pending_run_cb_ = callback;
136 void HeartRateServer::ScheduleNextMeasurement() {
137 main_task_runner_->PostDelayedTask(
139 base::Bind(&HeartRateServer::SendHeartRateMeasurement,
140 weak_ptr_factory_.GetWeakPtr()),
141 base::TimeDelta::FromSeconds(1));
144 void HeartRateServer::SendHeartRateMeasurement() {
145 std::lock_guard<std::mutex> lock(mutex_);
147 // Send a notification or indication to all enabled devices.
149 for (const auto& iter : device_ccc_map_) {
150 uint8_t ccc_val = iter.second;
157 // Don't send a notification if one is already pending for this device.
158 if (pending_notification_map_[iter.first])
161 std::vector<uint8_t> value;
162 BuildHeartRateMeasurementValue(&value);
164 if (gatt_->SendNotification(server_if_, iter.first, hr_measurement_id_,
166 pending_notification_map_[iter.first] = true;
171 ScheduleNextMeasurement();
175 // All clients disabled notifications.
176 simulation_started_ = false;
178 // TODO(armansito): We should keep track of closed connections here so that we
179 // don't send notifications to uninterested clients.
182 void HeartRateServer::BuildHeartRateMeasurementValue(
183 std::vector<uint8_t>* out_value) {
184 CHECK(out_value); // Assert that |out_value| is not nullptr.
186 // Default flags field. Here is what we put in there:
187 // Bit 0: 0 - 8-bit Heart Rate value
188 // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected.
189 uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected;
191 // Our demo's heart rate. Pick a value between 90 and 130.
192 uint8_t heart_rate = base::RandInt(90, 130);
194 // On every tenth beat we include the Energy Expended value.
195 bool include_ee = false;
196 if (!(hr_notification_count_ % 10)) {
198 flags |= kHREnergyExpendedPresent;
201 hr_notification_count_++;
202 energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
204 // Add all the value bytes.
205 out_value->push_back(flags);
206 out_value->push_back(heart_rate);
208 out_value->push_back(energy_expended_);
209 out_value->push_back(energy_expended_ >> 8);
213 void HeartRateServer::OnServerRegistered(int status, int server_if) {
214 std::lock_guard<std::mutex> lock(mutex_);
216 if (status != bluetooth::BLE_STATUS_SUCCESS) {
217 LOG(ERROR) << "Failed to register GATT server";
218 pending_run_cb_(false);
222 // Registration succeeded. Store our ID, as we need it for GATT server
224 server_if_ = server_if;
226 LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
227 LOG(INFO) << "Populating attributes";
229 // Start service declaration.
230 std::unique_ptr<bluetooth::GattIdentifier> gatt_id;
231 if (!gatt_->BeginServiceDeclaration(server_if_, true,
234 LOG(ERROR) << "Failed to begin service declaration";
235 pending_run_cb_(false);
239 hr_service_id_ = *gatt_id;
241 // Add Heart Rate Measurement characteristic.
242 if (!gatt_->AddCharacteristic(
243 server_if_, kHRMeasurementUUID,
244 bluetooth::kCharacteristicPropertyNotify,
246 LOG(ERROR) << "Failed to add heart rate measurement characteristic";
247 pending_run_cb_(false);
251 hr_measurement_id_ = *gatt_id;
253 // Add Client Characteristic Configuration descriptor for the Heart Rate
254 // Measurement characteristic.
255 if (!gatt_->AddDescriptor(
256 server_if_, kCCCDescriptorUUID,
257 bluetooth::kAttributePermissionRead|bluetooth::kAttributePermissionWrite,
259 LOG(ERROR) << "Failed to add CCC descriptor";
260 pending_run_cb_(false);
264 hr_measurement_cccd_id_ = *gatt_id;
266 // Add Body Sensor Location characteristic.
267 if (!gatt_->AddCharacteristic(
268 server_if_, kBodySensorLocationUUID,
269 bluetooth::kCharacteristicPropertyRead,
270 bluetooth::kAttributePermissionRead,
272 LOG(ERROR) << "Failed to add body sensor location characteristic";
273 pending_run_cb_(false);
277 body_sensor_loc_id_ = *gatt_id;
279 // Add Heart Rate Control Point characteristic.
280 if (!gatt_->AddCharacteristic(
281 server_if_, kHRControlPointUUID,
282 bluetooth::kCharacteristicPropertyWrite,
283 bluetooth::kAttributePermissionWrite,
285 LOG(ERROR) << "Failed to add heart rate control point characteristic";
286 pending_run_cb_(false);
290 hr_control_point_id_ = *gatt_id;
292 // End service declaration. We will be notified whether or not this succeeded
293 // via the OnServiceAdded callback.
294 if (!gatt_->EndServiceDeclaration(server_if_)) {
295 LOG(ERROR) << "Failed to end service declaration";
296 pending_run_cb_(false);
300 LOG(INFO) << "Initiated EndServiceDeclaration request";
303 void HeartRateServer::OnServiceAdded(
305 const bluetooth::GattIdentifier& service_id) {
306 std::lock_guard<std::mutex> lock(mutex_);
308 if (status != bluetooth::BLE_STATUS_SUCCESS) {
309 LOG(ERROR) << "Failed to add Heart Rate service";
310 pending_run_cb_(false);
314 if (service_id != hr_service_id_) {
315 LOG(ERROR) << "Received callback for the wrong service ID";
316 pending_run_cb_(false);
320 // EndServiceDeclaration succeeded! Our Heart Rate service is now discoverable
321 // over GATT connections.
323 LOG(INFO) << "Heart Rate service added";
324 pending_run_cb_(true);
327 auto ble = bluetooth_->GetLowEnergyInterface();
329 LOG(ERROR) << "Failed to obtain handle to IBluetoothLowEnergy interface";
332 ble->RegisterClient(new CLIBluetoothLowEnergyCallback(bluetooth_));
337 void HeartRateServer::OnCharacteristicReadRequest(
338 const std::string& device_address,
339 int request_id, int offset, bool /* is_long */,
340 const bluetooth::GattIdentifier& characteristic_id) {
341 std::lock_guard<std::mutex> lock(mutex_);
343 // This is where we handle an incoming characteristic read. Only the body
344 // sensor location characteristic is readable.
345 CHECK(characteristic_id == body_sensor_loc_id_);
347 std::vector<uint8_t> value;
348 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
350 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
351 else if (offset == 0)
352 value.push_back(kHRBodyLocationFoot);
354 gatt_->SendResponse(server_if_, device_address, request_id, error,
358 void HeartRateServer::OnDescriptorReadRequest(
359 const std::string& device_address,
360 int request_id, int offset, bool /* is_long */,
361 const bluetooth::GattIdentifier& descriptor_id) {
362 std::lock_guard<std::mutex> lock(mutex_);
364 // This is where we handle an incoming characteristic descriptor read. There
365 // is only one descriptor.
366 if (descriptor_id != hr_measurement_cccd_id_) {
367 std::vector<uint8_t> value;
368 gatt_->SendResponse(server_if_, device_address, request_id,
369 bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND,
374 // 16-bit value encoded as little-endian.
375 const uint8_t value_bytes[] = { device_ccc_map_[device_address], 0x00 };
377 std::vector<uint8_t> value;
378 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
380 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
382 value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
384 gatt_->SendResponse(server_if_, device_address, request_id, error,
388 void HeartRateServer::OnCharacteristicWriteRequest(
389 const std::string& device_address,
390 int request_id, int offset, bool is_prepare_write, bool need_response,
391 const std::vector<uint8_t>& value,
392 const bluetooth::GattIdentifier& characteristic_id) {
393 std::lock_guard<std::mutex> lock(mutex_);
395 std::vector<uint8_t> dummy;
397 // This is where we handle an incoming characteristic write. The Heart Rate
398 // service doesn't really support prepared writes, so we just reject them to
399 // keep things simple.
400 if (is_prepare_write) {
401 gatt_->SendResponse(server_if_, device_address, request_id,
402 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED,
407 // Heart Rate Control point is the only writable characteristic.
408 CHECK(characteristic_id == hr_control_point_id_);
410 // Writes to the Heart Rate Control Point characteristic must contain a single
411 // byte with the value 0x01.
412 if (value.size() != 1 || value[0] != 0x01) {
413 gatt_->SendResponse(server_if_, device_address, request_id,
414 bluetooth::GATT_ERROR_OUT_OF_RANGE,
419 LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
420 energy_expended_ = 0;
425 gatt_->SendResponse(server_if_, device_address, request_id,
426 bluetooth::GATT_ERROR_NONE, offset, dummy);
429 void HeartRateServer::OnDescriptorWriteRequest(
430 const std::string& device_address,
431 int request_id, int offset, bool is_prepare_write, bool need_response,
432 const std::vector<uint8_t>& value,
433 const bluetooth::GattIdentifier& descriptor_id) {
434 std::lock_guard<std::mutex> lock(mutex_);
436 std::vector<uint8_t> dummy;
438 // This is where we handle an incoming characteristic write. The Heart Rate
439 // service doesn't really support prepared writes, so we just reject them to
440 // keep things simple.
441 if (is_prepare_write) {
442 gatt_->SendResponse(server_if_, device_address, request_id,
443 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED,
448 // CCC is the only descriptor we have.
449 CHECK(descriptor_id == hr_measurement_cccd_id_);
451 // CCC must contain 2 bytes for a 16-bit value in little-endian. The only
452 // allowed values here are 0x0000 and 0x0001.
453 if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) {
454 gatt_->SendResponse(server_if_, device_address, request_id,
455 bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
460 device_ccc_map_[device_address] = value[0];
462 LOG(INFO) << "Heart Rate Measurement CCC written - device: "
463 << device_address << " value: " << (int)value[0];
465 // Start the simulation.
466 if (!simulation_started_ && value[0]) {
467 simulation_started_ = true;
468 ScheduleNextMeasurement();
474 gatt_->SendResponse(server_if_, device_address, request_id,
475 bluetooth::GATT_ERROR_NONE, offset, dummy);
478 void HeartRateServer::OnExecuteWriteRequest(
479 const std::string& device_address,
481 bool /* is_execute */) {
482 // We don't support Prepared Writes so, simply return Not Supported error.
483 std::vector<uint8_t> dummy;
484 gatt_->SendResponse(server_if_, device_address, request_id,
485 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy);
488 void HeartRateServer::OnNotificationSent(
489 const std::string& device_address, int status) {
490 LOG(INFO) << "Notification was sent - device: " << device_address
491 << " status: " << status;
492 std::lock_guard<std::mutex> lock(mutex_);
493 pending_notification_map_[device_address] = false;
496 } // namespace heart_rate