• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  Copyright 2015 Google, Inc.
3 //
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 //
16 #include <base/bind.h>
17 #include <base/location.h>
18 #include <base/logging.h>
19 #include <base/rand_util.h>
20 
21 #include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
22 #include <android/bluetooth/IBluetoothLeAdvertiser.h>
23 #include <bluetooth/low_energy_constants.h>
24 
25 #include "constants.h"
26 #include "heart_rate_server.h"
27 
28 using android::binder::Status;
29 using android::String8;
30 using android::String16;
31 
32 using android::bluetooth::IBluetoothLeAdvertiser;
33 using android::bluetooth::BluetoothGattService;
34 
35 namespace heart_rate {
36 
37 class CLIBluetoothLeAdvertiserCallback
38     : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
39  public:
CLIBluetoothLeAdvertiserCallback(android::sp<android::bluetooth::IBluetooth> bt)40   explicit CLIBluetoothLeAdvertiserCallback(
41       android::sp<android::bluetooth::IBluetooth> bt)
42       : bt_(bt) {}
43 
44   // IBluetoothLeAdvertiserCallback overrides:
OnAdvertiserRegistered(int status,int advertiser_id)45   Status OnAdvertiserRegistered(int status, int advertiser_id) {
46     if (status != bluetooth::BLE_STATUS_SUCCESS) {
47       LOG(ERROR)
48           << "Failed to register BLE advertiser, will not start advertising";
49       return Status::ok();
50     }
51 
52     LOG(INFO) << "Registered BLE advertiser with ID: " << advertiser_id;
53 
54     String16 name_param;
55     bt_->GetName(&name_param);
56     std::string name(String8(name_param).string());
57 
58     /* Advertising data: 16-bit Service Uuid: Heart Rate Service, Tx power*/
59     std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUuids,
60                               0x0D, 0x18,
61                               0x02, bluetooth::kEIRTypeTxPower,
62                               0x00};
63     data.push_back(name.length() + 1);
64     data.push_back(bluetooth::kEIRTypeCompleteLocalName);
65     data.insert(data.end(), name.c_str(), name.c_str() + name.length());
66 
67     base::TimeDelta timeout;
68 
69     bluetooth::AdvertiseSettings settings(
70         bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
71         bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, true);
72 
73     bluetooth::AdvertiseData adv_data(data);
74     bluetooth::AdvertiseData scan_rsp;
75 
76     android::sp<IBluetoothLeAdvertiser> ble;
77     bt_->GetLeAdvertiserInterface(&ble);
78     bool start_status;
79     ble->StartMultiAdvertising(advertiser_id, adv_data, scan_rsp, settings,
80                                &start_status);
81     return Status::ok();
82   }
83 
OnMultiAdvertiseCallback(int status,bool is_start,const android::bluetooth::AdvertiseSettings &)84   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();
89   };
90 
91  private:
92   android::sp<android::bluetooth::IBluetooth> bt_;
93   DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
94 };
95 
HeartRateServer(android::sp<android::bluetooth::IBluetooth> bluetooth,scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,bool advertise)96 HeartRateServer::HeartRateServer(
97     android::sp<android::bluetooth::IBluetooth> bluetooth,
98     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
99     bool advertise)
100     : simulation_started_(false),
101       bluetooth_(bluetooth),
102       server_if_(-1),
103       hr_notification_count_(0),
104       energy_expended_(0),
105       advertise_(advertise),
106       main_task_runner_(main_task_runner),
107       weak_ptr_factory_(this) {
108   CHECK(bluetooth_.get());
109 }
110 
~HeartRateServer()111 HeartRateServer::~HeartRateServer() {
112   std::lock_guard<std::mutex> lock(mutex_);
113   if (!gatt_.get() || server_if_ == -1) return;
114 
115   if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) return;
116 
117   // 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.
120   gatt_->UnregisterServer(server_if_);
121 }
122 
Run(const RunCallback & callback)123 bool 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 
131   // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
132   bluetooth_->GetGattServerInterface(&gatt_);
133   if (!gatt_.get()) {
134     LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
135     return false;
136   }
137 
138   // Register this instance as a GATT server. If this call succeeds, we will
139   // asynchronously receive a server ID via the OnServerRegistered callback.
140   bool status;
141   gatt_->RegisterServer(this, &status);
142   if (!status) {
143     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 
ScheduleNextMeasurement()152 void HeartRateServer::ScheduleNextMeasurement() {
153   main_task_runner_->PostDelayedTask(
154       FROM_HERE, base::Bind(&HeartRateServer::SendHeartRateMeasurement,
155                             weak_ptr_factory_.GetWeakPtr()),
156       base::TimeDelta::FromSeconds(1));
157 }
158 
SendHeartRateMeasurement()159 void 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 
167     if (!ccc_val) continue;
168 
169     found = true;
170 
171     // Don't send a notification if one is already pending for this device.
172     if (pending_notification_map_[iter.first]) continue;
173 
174     std::vector<uint8_t> value;
175     BuildHeartRateMeasurementValue(&value);
176 
177     bool status;
178     gatt_->SendNotification(server_if_, String16(String8(iter.first.c_str())),
179                             hr_measurement_handle_, false, value, &status);
180     if (status) pending_notification_map_[iter.first] = true;
181   }
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 
BuildHeartRateMeasurementValue(std::vector<uint8_t> * out_value)196 void 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 
OnServerRegistered(int status,int server_if)227 Status HeartRateServer::OnServerRegistered(int status, int server_if) {
228   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);
233     return Status::ok();
234   }
235 
236   // Registration succeeded. Store our ID, as we need it for GATT server
237   // operations.
238   server_if_ = server_if;
239 
240   LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
241 
242   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                                {});
261 
262   bool op_status = true;
263 
264   Status stat = gatt_->AddService(server_if_, (BluetoothGattService)hrService,
265                                   &op_status);
266   if (!stat.isOk()) {
267     LOG(ERROR) << "Failed to add service, status is: " /*<< stat*/;
268     pending_run_cb_(false);
269     return Status::ok();
270   }
271 
272   if (!op_status) {
273     LOG(ERROR) << "Failed to add service";
274     pending_run_cb_(false);
275     return Status::ok();
276   }
277 
278   LOG(INFO) << "Initiated AddService request";
279   return Status::ok();
280 }
281 
OnServiceAdded(int status,const android::bluetooth::BluetoothGattService & service)282 Status HeartRateServer::OnServiceAdded(
283     int status, const android::bluetooth::BluetoothGattService& service) {
284   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);
289     return Status::ok();
290   }
291 
292   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();
298 
299   LOG(INFO) << "Heart Rate service added";
300   pending_run_cb_(true);
301 
302   if (advertise_) {
303     android::sp<IBluetoothLeAdvertiser> ble;
304     bluetooth_->GetLeAdvertiserInterface(&ble);
305     bool status;
306     ble->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(bluetooth_),
307                             &status);
308   }
309 
310   return Status::ok();
311 }
312 
OnCharacteristicReadRequest(const String16 & device_address,int request_id,int offset,bool,int handle)313 Status HeartRateServer::OnCharacteristicReadRequest(
314     const String16& device_address, int request_id, int offset,
315     bool /* is_long */, int handle) {
316   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.
320   CHECK(handle == body_sensor_loc_handle_);
321 
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 
329   bool status;
330   gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
331                       value, &status);
332   return Status::ok();
333 }
334 
OnDescriptorReadRequest(const String16 & device_address,int request_id,int offset,bool,int handle)335 Status HeartRateServer::OnDescriptorReadRequest(const String16& device_address,
336                                                 int request_id, int offset,
337                                                 bool /* is_long */,
338                                                 int handle) {
339   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.
343   if (handle != hr_measurement_cccd_handle_) {
344     std::vector<uint8_t> value;
345     bool status;
346     gatt_->SendResponse(server_if_, device_address, request_id,
347                         bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, offset,
348                         value, &status);
349     return Status::ok();
350   }
351 
352   // 16-bit value encoded as little-endian.
353   const uint8_t value_bytes[] = {
354       device_ccc_map_[std::string(String8(device_address).string())], 0x00};
355 
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 
363   bool status;
364   gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
365                       value, &status);
366   return Status::ok();
367 }
368 
OnCharacteristicWriteRequest(const String16 & device_address,int request_id,int offset,bool is_prepare_write,bool need_response,const std::vector<uint8_t> & value,int handle)369 Status HeartRateServer::OnCharacteristicWriteRequest(
370     const String16& device_address, int request_id, int offset,
371     bool is_prepare_write, bool need_response,
372     const std::vector<uint8_t>& value, int handle) {
373   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) {
381     bool status;
382     gatt_->SendResponse(server_if_, device_address, request_id,
383                         bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
384                         dummy, &status);
385     return Status::ok();
386   }
387 
388   // Heart Rate Control point is the only writable characteristic.
389   CHECK(handle == hr_control_point_handle_);
390 
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) {
394     bool status;
395     gatt_->SendResponse(server_if_, device_address, request_id,
396                         bluetooth::GATT_ERROR_OUT_OF_RANGE, offset, dummy,
397                         &status);
398     return Status::ok();
399   }
400 
401   LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
402   energy_expended_ = 0;
403 
404   if (!need_response) return Status::ok();
405 
406   bool status;
407   gatt_->SendResponse(server_if_, device_address, request_id,
408                       bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
409   return Status::ok();
410 }
411 
OnDescriptorWriteRequest(const String16 & device_address,int request_id,int offset,bool is_prepare_write,bool need_response,const std::vector<uint8_t> & value,int handle)412 Status HeartRateServer::OnDescriptorWriteRequest(
413     const String16& device_address, int request_id, int offset,
414     bool is_prepare_write, bool need_response,
415     const std::vector<uint8_t>& value, int handle) {
416   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) {
424     bool status;
425     gatt_->SendResponse(server_if_, device_address, request_id,
426                         bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
427                         dummy, &status);
428     return Status::ok();
429   }
430 
431   // CCC is the only descriptor we have.
432   CHECK(handle == hr_measurement_cccd_handle_);
433 
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) {
437     bool status;
438     gatt_->SendResponse(server_if_, device_address, request_id,
439                         bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
440                         offset, dummy, &status);
441     return Status::ok();
442   }
443 
444   device_ccc_map_[std::string(String8(device_address).string())] = value[0];
445 
446   LOG(INFO) << "Heart Rate Measurement CCC written - device: " << device_address
447             << " value: " << (int)value[0];
448 
449   // Start the simulation.
450   if (!simulation_started_ && value[0]) {
451     simulation_started_ = true;
452     ScheduleNextMeasurement();
453   }
454 
455   if (!need_response) return Status::ok();
456 
457   bool status;
458   gatt_->SendResponse(server_if_, device_address, request_id,
459                       bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
460   return Status::ok();
461 }
462 
OnExecuteWriteRequest(const String16 & device_address,int request_id,bool)463 Status HeartRateServer::OnExecuteWriteRequest(const String16& device_address,
464                                               int request_id,
465                                               bool /* is_execute */) {
466   // We don't support Prepared Writes so, simply return Not Supported error.
467   std::vector<uint8_t> dummy;
468   bool status;
469   gatt_->SendResponse(server_if_, device_address, request_id,
470                       bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy,
471                       &status);
472 
473   return Status::ok();
474 }
475 
OnNotificationSent(const String16 & device_address,int status)476 Status HeartRateServer::OnNotificationSent(const String16& device_address,
477                                            int status) {
478   LOG(INFO) << "Notification was sent - device: " << device_address
479             << " status: " << status;
480   std::lock_guard<std::mutex> lock(mutex_);
481   pending_notification_map_[std::string(String8(device_address).string())] =
482       false;
483 
484   return Status::ok();
485 }
486 
OnConnectionStateChanged(const String16 & device_address,bool connected)487 Status HeartRateServer::OnConnectionStateChanged(const String16& device_address,
488                                                  bool connected) {
489   LOG(INFO) << "Connection state changed - device: " << device_address
490             << " connected: " << (connected ? "true" : "false");
491   return Status::ok();
492 }
493 }  // namespace heart_rate
494