Home | History | Annotate | Download | only in heart_rate
      1 //
      2 //  Copyright (C) 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:
     40   explicit CLIBluetoothLeAdvertiserCallback(
     41       android::sp<android::bluetooth::IBluetooth> bt)
     42       : bt_(bt) {}
     43 
     44   // IBluetoothLeAdvertiserCallback overrides:
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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(
    243       0, true, kHRServiceUUID,
    244       {{0,
    245         kHRMeasurementUUID,
    246         bluetooth::kCharacteristicPropertyNotify,
    247         0,
    248         {{0, kCCCDescriptorUUID, (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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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