Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc

Issue 206443009: chromeos/dbus: Add fake D-Bus clients for GATT client-mode. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/rand_util.h"
10 #include "base/time/time.h"
11 #include "third_party/cros_system_api/dbus/service_constants.h"
12
13 namespace chromeos {
14
15 namespace {
16
17 const int kHeartRateMeasurementNotificationIntervalMs = 2000;
18
19 } // namespace
20
21 // static
22 const char FakeBluetoothGattCharacteristicClient::
23 kHeartRateMeasurementPathComponent[] = "char0000";
24 const char FakeBluetoothGattCharacteristicClient::
25 kBodySensorLocationPathComponent[] = "char0001";
26 const char FakeBluetoothGattCharacteristicClient::
27 kHeartRateControlPointPathComponent[] = "char0002";
28
29 // static
30 const char FakeBluetoothGattCharacteristicClient::kHeartRateMeasurementUUID[] =
31 "00002a37-0000-1000-8000-00805f9b34fb";
32 const char FakeBluetoothGattCharacteristicClient::kBodySensorLocationUUID[] =
33 "00002a38-0000-1000-8000-00805f9b34fb";
34 const char FakeBluetoothGattCharacteristicClient::kHeartRateControlPointUUID[] =
35 "00002a39-0000-1000-8000-00805f9b34fb";
36
37 FakeBluetoothGattCharacteristicClient::Properties::Properties(
38 const PropertyChangedCallback& callback)
39 : BluetoothGattCharacteristicClient::Properties(
40 NULL,
41 bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
42 callback) {
43 }
44
45 FakeBluetoothGattCharacteristicClient::Properties::~Properties() {
46 }
47
48 void FakeBluetoothGattCharacteristicClient::Properties::Get(
49 dbus::PropertyBase* property,
50 dbus::PropertySet::GetCallback callback) {
51 VLOG(1) << "Get " << property->name();
52 callback.Run(false);
53 }
54
55 void FakeBluetoothGattCharacteristicClient::Properties::GetAll() {
56 VLOG(1) << "GetAll";
57 }
58
59 void FakeBluetoothGattCharacteristicClient::Properties::Set(
60 dbus::PropertyBase* property,
61 dbus::PropertySet::SetCallback callback) {
62 VLOG(1) << "Set " << property->name();
63 if (property->name() != value.name()) {
64 callback.Run(false);
65 return;
66 }
67 // Allow writing to only certain characteristics that are defined with the
68 // write permission.
69 // TODO(armansito): Actually check against the permissions property instead of
70 // UUID, once that property is fully defined in the API.
71 if (uuid.value() != kHeartRateControlPointUUID) {
72 callback.Run(false);
73 return;
74 }
75 callback.Run(true);
76 property->ReplaceValueWithSetValue();
77 }
78
79 FakeBluetoothGattCharacteristicClient::FakeBluetoothGattCharacteristicClient()
80 : heart_rate_visible_(false),
81 calories_burned_(0),
82 weak_ptr_factory_(this) {
83 }
84
85 FakeBluetoothGattCharacteristicClient::
86 ~FakeBluetoothGattCharacteristicClient() {
87 }
88
89 void FakeBluetoothGattCharacteristicClient::Init(dbus::Bus* bus) {
90 }
91
92 void FakeBluetoothGattCharacteristicClient::AddObserver(Observer* observer) {
93 observers_.AddObserver(observer);
94 }
95
96 void FakeBluetoothGattCharacteristicClient::RemoveObserver(Observer* observer) {
97 observers_.RemoveObserver(observer);
98 }
99
100 std::vector<dbus::ObjectPath>
101 FakeBluetoothGattCharacteristicClient::GetCharacteristics() {
102 std::vector<dbus::ObjectPath> paths;
103 if (IsHeartRateVisible()) {
104 paths.push_back(dbus::ObjectPath(heart_rate_measurement_path_));
105 paths.push_back(dbus::ObjectPath(body_sensor_location_path_));
106 paths.push_back(dbus::ObjectPath(heart_rate_control_point_path_));
107 }
108 return paths;
109 }
110
111 FakeBluetoothGattCharacteristicClient::Properties*
112 FakeBluetoothGattCharacteristicClient::GetProperties(
113 const dbus::ObjectPath& object_path) {
114 if (object_path.value() == heart_rate_measurement_path_) {
115 DCHECK(heart_rate_measurement_properties_.get());
116 return heart_rate_measurement_properties_.get();
117 }
118 if (object_path.value() == body_sensor_location_path_) {
119 DCHECK(heart_rate_measurement_properties_.get());
120 return heart_rate_measurement_properties_.get();
121 }
122 if (object_path.value() == heart_rate_control_point_path_) {
123 DCHECK(heart_rate_control_point_properties_.get());
124 return heart_rate_control_point_properties_.get();
125 }
126 return NULL;
127 }
128
129 void FakeBluetoothGattCharacteristicClient::ExposeHeartRateCharacteristics(
130 const dbus::ObjectPath& service_path) {
131 if (IsHeartRateVisible()) {
132 VLOG(2) << "Fake Heart Rate characteristics are already visible.";
133 return;
134 }
135
136 VLOG(2) << "Exposing fake Heart Rate characteristics.";
137
138 // ==== Heart Rate Measurement Characteristic ====
139 heart_rate_measurement_path_ =
140 service_path.value() + "/" + kHeartRateMeasurementPathComponent;
141 heart_rate_measurement_properties_.reset(new Properties(base::Bind(
142 &FakeBluetoothGattCharacteristicClient::OnPropertyChanged,
143 weak_ptr_factory_.GetWeakPtr(),
144 dbus::ObjectPath(heart_rate_measurement_path_))));
145 heart_rate_measurement_properties_->uuid.ReplaceValue(
146 kHeartRateMeasurementUUID);
147 heart_rate_measurement_properties_->service.ReplaceValue(service_path);
148
149 // TODO(armansito): Fill out the flags field once bindings for the values have
150 // been added. For now, leave it empty.
151
152 std::vector<uint8> measurement_value = GetHeartRateMeasurementValue();
153 heart_rate_measurement_properties_->value.ReplaceValue(measurement_value);
154
155 // ==== Body Sensor Location Characteristic ====
156 body_sensor_location_path_ =
157 service_path.value() + "/" + kBodySensorLocationPathComponent;
158 body_sensor_location_properties_.reset(new Properties(base::Bind(
159 &FakeBluetoothGattCharacteristicClient::OnPropertyChanged,
160 weak_ptr_factory_.GetWeakPtr(),
161 dbus::ObjectPath(body_sensor_location_path_))));
162 body_sensor_location_properties_->uuid.ReplaceValue(kBodySensorLocationUUID);
163 body_sensor_location_properties_->service.ReplaceValue(service_path);
164
165 // TODO(armansito): Fill out the flags field once bindings for the values have
166 // been added. For now, leave it empty.
167
168 // The sensor is in the "Other" location.
169 std::vector<uint8> body_sensor_location_value;
170 body_sensor_location_value.push_back(0);
171 body_sensor_location_properties_->value.ReplaceValue(
172 body_sensor_location_value);
173
174 // ==== Heart Rate Control Point Characteristic ====
175 heart_rate_control_point_path_ =
176 service_path.value() + "/" + kHeartRateControlPointPathComponent;
177 heart_rate_control_point_properties_.reset(new Properties(base::Bind(
178 &FakeBluetoothGattCharacteristicClient::OnPropertyChanged,
179 weak_ptr_factory_.GetWeakPtr(),
180 dbus::ObjectPath(heart_rate_control_point_path_))));
181 heart_rate_control_point_properties_->uuid.ReplaceValue(
182 kHeartRateControlPointUUID);
183 heart_rate_control_point_properties_->service.ReplaceValue(service_path);
184
185 // TODO(armansito): Fill out the flags field once bindings for the values have
186 // been added. For now, leave it empty.
187
188 // Set the initial value to 0. Whenever this gets set to 1, we will reset the
189 // total calories burned and change the value back to 0.
190 std::vector<uint8> heart_rate_control_point_value;
191 heart_rate_control_point_value.push_back(0);
192 heart_rate_control_point_properties_->value.ReplaceValue(
193 heart_rate_control_point_value);
194
195 heart_rate_visible_ = true;
196
197 NotifyCharacteristicAdded(dbus::ObjectPath(heart_rate_measurement_path_));
198 NotifyCharacteristicAdded(dbus::ObjectPath(body_sensor_location_path_));
199 NotifyCharacteristicAdded(dbus::ObjectPath(heart_rate_control_point_path_));
200
201 // Set up notifications for heart rate measurement.
202 // TODO(armansito): Do this based on the value of the "client characteristic
203 // configuration" descriptor. Since it's still unclear how descriptors will
204 // be handled by BlueZ, automatically set up notifications for now.
205 ScheduleHeartRateMeasurementValueChange();
206
207 // TODO(armansito): Add descriptors.
208 }
209
210 void FakeBluetoothGattCharacteristicClient::HideHeartRateCharacteristics() {
211 VLOG(2) << "Hiding fake Heart Rate characteristics.";
212 heart_rate_measurement_properties_.reset();
213 body_sensor_location_properties_.reset();
214 heart_rate_control_point_properties_.reset();
215
216 std::string hrm_path = heart_rate_measurement_path_;
217 heart_rate_measurement_path_.clear();
218 std::string bsl_path = body_sensor_location_path_;
219 body_sensor_location_path_.clear();
220 std::string hrcp_path = heart_rate_control_point_path_;
221 heart_rate_control_point_path_.clear();
222 heart_rate_visible_ = false;
223
224 NotifyCharacteristicRemoved(dbus::ObjectPath(hrm_path));
225 NotifyCharacteristicRemoved(dbus::ObjectPath(bsl_path));
226 NotifyCharacteristicRemoved(dbus::ObjectPath(hrcp_path));
227 }
228
229 void FakeBluetoothGattCharacteristicClient::OnPropertyChanged(
230 const dbus::ObjectPath& object_path,
231 const std::string& property_name) {
232 VLOG(2) << "Characteristic property changed: " << object_path.value()
233 << ": " << property_name;
234
235 FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
236 GattCharacteristicPropertyChanged(
237 object_path, property_name));
238
239 // If the heart rate control point was set, reset the calories burned.
240 if (object_path.value() != heart_rate_control_point_path_)
241 return;
242 DCHECK(heart_rate_control_point_properties_.get());
243 dbus::Property<std::vector<uint8> >* value_prop =
244 &heart_rate_control_point_properties_->value;
245 if (property_name != value_prop->name())
246 return;
247
248 std::vector<uint8> value = value_prop->value();
249 DCHECK(value.size() == 1);
250 if (value[0] == 0)
251 return;
252
253 DCHECK(value[0] == 1);
254 calories_burned_ = 0;
255 value[0] = 0;
256 value_prop->ReplaceValue(value);
257 }
258
259 void FakeBluetoothGattCharacteristicClient::NotifyCharacteristicAdded(
260 const dbus::ObjectPath& object_path) {
261 VLOG(2) << "GATT characteristic added: " << object_path.value();
262 FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
263 GattCharacteristicAdded(object_path));
264 }
265
266 void FakeBluetoothGattCharacteristicClient::NotifyCharacteristicRemoved(
267 const dbus::ObjectPath& object_path) {
268 VLOG(2) << "GATT characteristic removed: " << object_path.value();
269 FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
270 GattCharacteristicRemoved(object_path));
271 }
272
273 void FakeBluetoothGattCharacteristicClient::
274 ScheduleHeartRateMeasurementValueChange() {
275 if (!IsHeartRateVisible())
276 return;
277 VLOG(2) << "Updating heart rate value.";
278 std::vector<uint8> measurement = GetHeartRateMeasurementValue();
279 heart_rate_measurement_properties_->value.ReplaceValue(measurement);
280
281 base::MessageLoop::current()->PostDelayedTask(
282 FROM_HERE,
283 base::Bind(&FakeBluetoothGattCharacteristicClient::
284 ScheduleHeartRateMeasurementValueChange,
285 weak_ptr_factory_.GetWeakPtr()),
286 base::TimeDelta::FromMilliseconds(
287 kHeartRateMeasurementNotificationIntervalMs));
288 }
289
290 std::vector<uint8>
291 FakeBluetoothGattCharacteristicClient::GetHeartRateMeasurementValue() {
292 // TODO(armansito): We should make sure to properly pack this struct to ensure
293 // correct byte alignment and endianness. It doesn't matter too much right now
294 // as this is a fake and GCC on Linux seems to do the right thing.
295 struct {
296 uint8 flags;
297 uint8 bpm;
298 uint16 energy_expanded;
299 uint16 rr_interval;
300 } value;
301
302 // Flags in LSB: 0 11 1 1 000
303 // | | | | |
304 // 8-bit bpm format -- | | | |
305 // Sensor contact supported -- | | |
306 // Energy expanded field present -- | |
307 // RR-Interval values present ------- |
308 // Reserved for future use ------------
309 value.flags = 0x0;
310 value.flags |= (0x03 << 1);
311 value.flags |= (0x01 << 3);
312 value.flags |= (0x01 << 4);
313
314 // Pick a value between 117 bpm and 153 bpm for heart rate.
315 value.bpm = static_cast<uint8>(base::RandInt(117, 153));
316
317 // Total calories burned in kJoules since the last reset. Increment this by 1
318 // every time. It's fine if it overflows: it becomes 0 when the user resets
319 // the heart rate monitor (or pretend that he had a lot of cheeseburgers).
320 value.energy_expanded = calories_burned_++;
321
322 // Include one RR-Interval value, in seconds.
323 value.rr_interval = 60/value.bpm;
324
325 // Return the bytes in an array.
326 uint8* bytes = reinterpret_cast<uint8*>(&value);
327 std::vector<uint8> return_value;
328 return_value.assign(bytes, bytes + sizeof(value));
329 return return_value;
330 }
331
332 bool FakeBluetoothGattCharacteristicClient::IsHeartRateVisible() const {
333 DCHECK(heart_rate_visible_ != heart_rate_measurement_path_.empty());
334 DCHECK(heart_rate_visible_ != body_sensor_location_path_.empty());
335 DCHECK(heart_rate_visible_ != heart_rate_control_point_path_.empty());
336 DCHECK(heart_rate_visible_ == !!heart_rate_measurement_properties_.get());
337 DCHECK(heart_rate_visible_ == !!body_sensor_location_properties_.get());
338 DCHECK(heart_rate_visible_ == !!heart_rate_control_point_properties_.get());
339 return heart_rate_visible_;
340 }
341
342 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h ('k') | chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698