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 
     17 #include "service/example/heart_rate/heart_rate_server.h"
     18 
     19 #include <base/bind.h>
     20 #include <base/location.h>
     21 #include <base/logging.h>
     22 #include <base/rand_util.h>
     23 
     24 #include <bluetooth/low_energy_constants.h>
     25 
     26 #include "service/example/heart_rate/constants.h"
     27 
     28 namespace heart_rate {
     29 
     30 class CLIBluetoothLowEnergyCallback
     31     : public ipc::binder::BnBluetoothLowEnergyCallback {
     32  public:
     33   CLIBluetoothLowEnergyCallback(android::sp<ipc::binder::IBluetooth> bt)
     34       : bt_(bt) {}
     35 
     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 {}
     40 
     41   void OnScanResult(const bluetooth::ScanResult& scan_result) override {}
     42 
     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";
     46       return;
     47     }
     48 
     49     LOG(INFO) << "Registered BLE client with ID: " << client_id;
     50 
     51     /* Advertising data: 16-bit Service UUID: Heart Rate Service */
     52     std::vector<uint8_t> data{0x03, 0x03, 0x0D, 0x18};
     53     base::TimeDelta timeout;
     54 
     55     bluetooth::AdvertiseSettings settings(
     56         bluetooth::AdvertiseSettings::MODE_LOW_POWER,
     57         timeout,
     58         bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM,
     59         true);
     60 
     61     bluetooth::AdvertiseData adv_data(data);
     62     adv_data.set_include_device_name(true);
     63     adv_data.set_include_tx_power_level(true);
     64 
     65     bluetooth::AdvertiseData scan_rsp;
     66 
     67     bt_->GetLowEnergyInterface()->
     68         StartMultiAdvertising(client_id, adv_data, scan_rsp, settings);
     69   }
     70 
     71   void OnMultiAdvertiseCallback(int status, bool is_start,
     72       const bluetooth::AdvertiseSettings& /* settings */) {
     73     LOG(INFO) << "Advertising" << (is_start?" started":" stopped");
     74   };
     75 
     76  private:
     77   android::sp<ipc::binder::IBluetooth> bt_;
     78   DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
     79 };
     80 
     81 
     82 HeartRateServer::HeartRateServer(
     83     android::sp<ipc::binder::IBluetooth> bluetooth,
     84     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
     85     bool advertise)
     86     : simulation_started_(false),
     87       bluetooth_(bluetooth),
     88       server_if_(-1),
     89       hr_notification_count_(0),
     90       energy_expended_(0),
     91       advertise_(advertise),
     92       main_task_runner_(main_task_runner),
     93       weak_ptr_factory_(this) {
     94   CHECK(bluetooth_.get());
     95 }
     96 
     97 HeartRateServer::~HeartRateServer() {
     98   std::lock_guard<std::mutex> lock(mutex_);
     99   if (!gatt_.get() || server_if_ == -1)
    100     return;
    101 
    102   if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive())
    103     return;
    104 
    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
    107   // process exits.
    108   gatt_->UnregisterServer(server_if_);
    109 }
    110 
    111 bool HeartRateServer::Run(const RunCallback& callback) {
    112   std::lock_guard<std::mutex> lock(mutex_);
    113 
    114   if (pending_run_cb_) {
    115     LOG(ERROR) << "Already started";
    116     return false;
    117   }
    118 
    119   // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
    120   gatt_ = bluetooth_->GetGattServerInterface();
    121   if (!gatt_.get()) {
    122     LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
    123     return false;
    124   }
    125 
    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";
    130     return false;
    131   }
    132 
    133   pending_run_cb_ = callback;
    134 
    135   return true;
    136 }
    137 
    138 void HeartRateServer::ScheduleNextMeasurement() {
    139   main_task_runner_->PostDelayedTask(
    140       FROM_HERE,
    141       base::Bind(&HeartRateServer::SendHeartRateMeasurement,
    142                  weak_ptr_factory_.GetWeakPtr()),
    143       base::TimeDelta::FromSeconds(1));
    144 }
    145 
    146 void HeartRateServer::SendHeartRateMeasurement() {
    147   std::lock_guard<std::mutex> lock(mutex_);
    148 
    149   // Send a notification or indication to all enabled devices.
    150   bool found = false;
    151   for (const auto& iter : device_ccc_map_) {
    152     uint8_t ccc_val = iter.second;
    153 
    154     if (!ccc_val)
    155       continue;
    156 
    157     found = true;
    158 
    159     // Don't send a notification if one is already pending for this device.
    160     if (pending_notification_map_[iter.first])
    161       continue;
    162 
    163     std::vector<uint8_t> value;
    164     BuildHeartRateMeasurementValue(&value);
    165 
    166     if (gatt_->SendNotification(server_if_, iter.first, hr_measurement_id_,
    167                                 false, value))
    168       pending_notification_map_[iter.first] = true;
    169   }
    170 
    171   // Still enabled!
    172   if (found) {
    173     ScheduleNextMeasurement();
    174     return;
    175   }
    176 
    177   // All clients disabled notifications.
    178   simulation_started_ = false;
    179 
    180   // TODO(armansito): We should keep track of closed connections here so that we
    181   // don't send notifications to uninterested clients.
    182 }
    183 
    184 void HeartRateServer::BuildHeartRateMeasurementValue(
    185     std::vector<uint8_t>* out_value) {
    186   CHECK(out_value);  // Assert that |out_value| is not nullptr.
    187 
    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;
    192 
    193   // Our demo's heart rate. Pick a value between 90 and 130.
    194   uint8_t heart_rate = base::RandInt(90, 130);
    195 
    196   // On every tenth beat we include the Energy Expended value.
    197   bool include_ee = false;
    198   if (!(hr_notification_count_ % 10)) {
    199     include_ee = true;
    200     flags |= kHREnergyExpendedPresent;
    201   }
    202 
    203   hr_notification_count_++;
    204   energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
    205 
    206   // Add all the value bytes.
    207   out_value->push_back(flags);
    208   out_value->push_back(heart_rate);
    209   if (include_ee) {
    210     out_value->push_back(energy_expended_);
    211     out_value->push_back(energy_expended_ >> 8);
    212   }
    213 }
    214 
    215 void HeartRateServer::OnServerRegistered(int status, int server_if) {
    216   std::lock_guard<std::mutex> lock(mutex_);
    217 
    218   if (status != bluetooth::BLE_STATUS_SUCCESS) {
    219     LOG(ERROR) << "Failed to register GATT server";
    220     pending_run_cb_(false);
    221     return;
    222   }
    223 
    224   // Registration succeeded. Store our ID, as we need it for GATT server
    225   // operations.
    226   server_if_ = server_if;
    227 
    228   LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
    229   LOG(INFO) << "Populating attributes";
    230 
    231   // Start service declaration.
    232   std::unique_ptr<bluetooth::GattIdentifier> gatt_id;
    233   if (!gatt_->BeginServiceDeclaration(server_if_, true,
    234                                       kHRServiceUUID,
    235                                       &gatt_id)) {
    236     LOG(ERROR) << "Failed to begin service declaration";
    237     pending_run_cb_(false);
    238     return;
    239   }
    240 
    241   hr_service_id_ = *gatt_id;
    242 
    243   // Add Heart Rate Measurement characteristic.
    244   if (!gatt_->AddCharacteristic(
    245       server_if_, kHRMeasurementUUID,
    246       bluetooth::kCharacteristicPropertyNotify,
    247       0, &gatt_id)) {
    248     LOG(ERROR) << "Failed to add heart rate measurement characteristic";
    249     pending_run_cb_(false);
    250     return;
    251   }
    252 
    253   hr_measurement_id_ = *gatt_id;
    254 
    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,
    260       &gatt_id)) {
    261     LOG(ERROR) << "Failed to add CCC descriptor";
    262     pending_run_cb_(false);
    263     return;
    264   }
    265 
    266   hr_measurement_cccd_id_ = *gatt_id;
    267 
    268   // Add Body Sensor Location characteristic.
    269   if (!gatt_->AddCharacteristic(
    270       server_if_, kBodySensorLocationUUID,
    271       bluetooth::kCharacteristicPropertyRead,
    272       bluetooth::kAttributePermissionRead,
    273       &gatt_id)) {
    274     LOG(ERROR) << "Failed to add body sensor location characteristic";
    275     pending_run_cb_(false);
    276     return;
    277   }
    278 
    279   body_sensor_loc_id_ = *gatt_id;
    280 
    281   // Add Heart Rate Control Point characteristic.
    282   if (!gatt_->AddCharacteristic(
    283       server_if_, kHRControlPointUUID,
    284       bluetooth::kCharacteristicPropertyWrite,
    285       bluetooth::kAttributePermissionWrite,
    286       &gatt_id)) {
    287     LOG(ERROR) << "Failed to add heart rate control point characteristic";
    288     pending_run_cb_(false);
    289     return;
    290   }
    291 
    292   hr_control_point_id_ = *gatt_id;
    293 
    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);
    299     return;
    300   }
    301 
    302   LOG(INFO) << "Initiated EndServiceDeclaration request";
    303 }
    304 
    305 void HeartRateServer::OnServiceAdded(
    306     int status,
    307     const bluetooth::GattIdentifier& service_id) {
    308   std::lock_guard<std::mutex> lock(mutex_);
    309 
    310   if (status != bluetooth::BLE_STATUS_SUCCESS) {
    311     LOG(ERROR) << "Failed to add Heart Rate service";
    312     pending_run_cb_(false);
    313     return;
    314   }
    315 
    316   if (service_id != hr_service_id_) {
    317     LOG(ERROR) << "Received callback for the wrong service ID";
    318     pending_run_cb_(false);
    319     return;
    320   }
    321 
    322   // EndServiceDeclaration succeeded! Our Heart Rate service is now discoverable
    323   // over GATT connections.
    324 
    325   LOG(INFO) << "Heart Rate service added";
    326   pending_run_cb_(true);
    327 
    328   if (advertise_) {
    329     auto ble = bluetooth_->GetLowEnergyInterface();
    330     if (!ble.get()) {
    331       LOG(ERROR) << "Failed to obtain handle to IBluetoothLowEnergy interface";
    332       return;
    333     }
    334     ble->RegisterClient(new CLIBluetoothLowEnergyCallback(bluetooth_));
    335   }
    336 
    337 }
    338 
    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_);
    344 
    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_);
    348 
    349   std::vector<uint8_t> value;
    350   bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
    351   if (offset > 1)
    352     error = bluetooth::GATT_ERROR_INVALID_OFFSET;
    353   else if (offset == 0)
    354     value.push_back(kHRBodyLocationFoot);
    355 
    356   gatt_->SendResponse(server_if_, device_address, request_id, error,
    357                       offset, value);
    358 }
    359 
    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_);
    365 
    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,
    372                         offset, value);
    373     return;
    374   }
    375 
    376   // 16-bit value encoded as little-endian.
    377   const uint8_t value_bytes[] = { device_ccc_map_[device_address], 0x00 };
    378 
    379   std::vector<uint8_t> value;
    380   bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
    381   if (offset > 2)
    382     error = bluetooth::GATT_ERROR_INVALID_OFFSET;
    383   else
    384     value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
    385 
    386   gatt_->SendResponse(server_if_, device_address, request_id, error,
    387                       offset, value);
    388 }
    389 
    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_);
    396 
    397   std::vector<uint8_t> dummy;
    398 
    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,
    405                         offset, dummy);
    406     return;
    407   }
    408 
    409   // Heart Rate Control point is the only writable characteristic.
    410   CHECK(characteristic_id == hr_control_point_id_);
    411 
    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,
    417                         offset, dummy);
    418     return;
    419   }
    420 
    421   LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
    422   energy_expended_ = 0;
    423 
    424   if (!need_response)
    425     return;
    426 
    427   gatt_->SendResponse(server_if_, device_address, request_id,
    428                       bluetooth::GATT_ERROR_NONE, offset, dummy);
    429 }
    430 
    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_);
    437 
    438   std::vector<uint8_t> dummy;
    439 
    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,
    446                         offset, dummy);
    447     return;
    448   }
    449 
    450   // CCC is the only descriptor we have.
    451   CHECK(descriptor_id == hr_measurement_cccd_id_);
    452 
    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,
    458                         offset, dummy);
    459     return;
    460   }
    461 
    462   device_ccc_map_[device_address] = value[0];
    463 
    464   LOG(INFO) << "Heart Rate Measurement CCC written - device: "
    465             << device_address << " value: " << (int)value[0];
    466 
    467   // Start the simulation.
    468   if (!simulation_started_ && value[0]) {
    469     simulation_started_ = true;
    470     ScheduleNextMeasurement();
    471   }
    472 
    473   if (!need_response)
    474     return;
    475 
    476   gatt_->SendResponse(server_if_, device_address, request_id,
    477                       bluetooth::GATT_ERROR_NONE, offset, dummy);
    478 }
    479 
    480 void HeartRateServer::OnExecuteWriteRequest(
    481     const std::string& device_address,
    482     int request_id,
    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);
    488 }
    489 
    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;
    496 }
    497 
    498 }  // namespace heart_rate
    499