OSDN Git Service

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