blob: 7066f470aa96b5748cf7a52699c6f374587b6b41 [file] [log] [blame]
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
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 */
16package android.bluetooth;
17
Artur Satayeve23a0eb2019-12-10 17:47:52 +000018import android.compat.annotation.UnsupportedAppUsage;
Jakub Pawlowski8d312a82016-03-01 18:50:27 -080019import android.os.Parcel;
Jakub Pawlowski8d312a82016-03-01 18:50:27 -080020import android.os.ParcelUuid;
Jack Hea355e5e2017-08-22 16:06:54 -070021import android.os.Parcelable;
22
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080023import java.util.ArrayList;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080024import java.util.List;
25import java.util.UUID;
26
27/**
Matthew Xieddf7e472013-03-01 18:41:02 -080028 * Represents a Bluetooth GATT Characteristic
Matthew Xie33ec9842013-04-03 00:29:27 -070029 *
30 * <p>A GATT characteristic is a basic data element used to construct a GATT service,
31 * {@link BluetoothGattService}. The characteristic contains a value as well as
32 * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080033 */
Jakub Pawlowski8d312a82016-03-01 18:50:27 -080034public class BluetoothGattCharacteristic implements Parcelable {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080035
36 /**
37 * Characteristic proprty: Characteristic is broadcastable.
38 */
39 public static final int PROPERTY_BROADCAST = 0x01;
40
41 /**
42 * Characteristic property: Characteristic is readable.
43 */
44 public static final int PROPERTY_READ = 0x02;
45
46 /**
47 * Characteristic property: Characteristic can be written without response.
48 */
49 public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04;
50
51 /**
52 * Characteristic property: Characteristic can be written.
53 */
54 public static final int PROPERTY_WRITE = 0x08;
55
56 /**
57 * Characteristic property: Characteristic supports notification
58 */
59 public static final int PROPERTY_NOTIFY = 0x10;
60
61 /**
62 * Characteristic property: Characteristic supports indication
63 */
64 public static final int PROPERTY_INDICATE = 0x20;
65
66 /**
67 * Characteristic property: Characteristic supports write with signature
68 */
69 public static final int PROPERTY_SIGNED_WRITE = 0x40;
70
71 /**
72 * Characteristic property: Characteristic has extended properties
73 */
74 public static final int PROPERTY_EXTENDED_PROPS = 0x80;
75
76 /**
77 * Characteristic read permission
78 */
79 public static final int PERMISSION_READ = 0x01;
80
81 /**
82 * Characteristic permission: Allow encrypted read operations
83 */
84 public static final int PERMISSION_READ_ENCRYPTED = 0x02;
85
86 /**
87 * Characteristic permission: Allow reading with man-in-the-middle protection
88 */
89 public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04;
90
91 /**
92 * Characteristic write permission
93 */
94 public static final int PERMISSION_WRITE = 0x10;
95
96 /**
97 * Characteristic permission: Allow encrypted writes
98 */
99 public static final int PERMISSION_WRITE_ENCRYPTED = 0x20;
100
101 /**
102 * Characteristic permission: Allow encrypted writes with man-in-the-middle
103 * protection
104 */
105 public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40;
106
107 /**
108 * Characteristic permission: Allow signed write operations
109 */
110 public static final int PERMISSION_WRITE_SIGNED = 0x80;
111
112 /**
113 * Characteristic permission: Allow signed write operations with
114 * man-in-the-middle protection
115 */
116 public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100;
117
118 /**
119 * Write characteristic, requesting acknoledgement by the remote device
120 */
121 public static final int WRITE_TYPE_DEFAULT = 0x02;
122
123 /**
Andrew Solovay237c1892017-10-27 15:11:48 -0700124 * Write characteristic without requiring a response by the remote device
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800125 */
126 public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
127
128 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800129 * Write characteristic including authentication signature
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800130 */
131 public static final int WRITE_TYPE_SIGNED = 0x04;
132
133 /**
134 * Characteristic value format type uint8
135 */
136 public static final int FORMAT_UINT8 = 0x11;
137
138 /**
139 * Characteristic value format type uint16
140 */
141 public static final int FORMAT_UINT16 = 0x12;
142
143 /**
144 * Characteristic value format type uint32
145 */
146 public static final int FORMAT_UINT32 = 0x14;
147
148 /**
149 * Characteristic value format type sint8
150 */
151 public static final int FORMAT_SINT8 = 0x21;
152
153 /**
154 * Characteristic value format type sint16
155 */
156 public static final int FORMAT_SINT16 = 0x22;
157
158 /**
159 * Characteristic value format type sint32
160 */
161 public static final int FORMAT_SINT32 = 0x24;
162
163 /**
164 * Characteristic value format type sfloat (16-bit float)
165 */
166 public static final int FORMAT_SFLOAT = 0x32;
167
168 /**
169 * Characteristic value format type float (32-bit float)
170 */
171 public static final int FORMAT_FLOAT = 0x34;
172
173
174 /**
175 * The UUID of this characteristic.
Jack Hea355e5e2017-08-22 16:06:54 -0700176 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800177 * @hide
178 */
179 protected UUID mUuid;
180
181 /**
182 * Instance ID for this characteristic.
Jack Hea355e5e2017-08-22 16:06:54 -0700183 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800184 * @hide
185 */
Mathew Inwood7acad5e2018-08-01 15:00:35 +0100186 @UnsupportedAppUsage
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800187 protected int mInstance;
188
189 /**
190 * Characteristic properties.
Jack Hea355e5e2017-08-22 16:06:54 -0700191 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800192 * @hide
193 */
194 protected int mProperties;
195
196 /**
197 * Characteristic permissions.
Jack Hea355e5e2017-08-22 16:06:54 -0700198 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800199 * @hide
200 */
201 protected int mPermissions;
202
203 /**
204 * Key size (default = 16).
Jack Hea355e5e2017-08-22 16:06:54 -0700205 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800206 * @hide
207 */
208 protected int mKeySize = 16;
209
210 /**
211 * Write type for this characteristic.
212 * See WRITE_TYPE_* constants.
Jack Hea355e5e2017-08-22 16:06:54 -0700213 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800214 * @hide
215 */
216 protected int mWriteType;
217
218 /**
219 * Back-reference to the service this characteristic belongs to.
Jack Hea355e5e2017-08-22 16:06:54 -0700220 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800221 * @hide
222 */
Mathew Inwood7acad5e2018-08-01 15:00:35 +0100223 @UnsupportedAppUsage
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800224 protected BluetoothGattService mService;
225
226 /**
227 * The cached value of this characteristic.
Jack Hea355e5e2017-08-22 16:06:54 -0700228 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800229 * @hide
230 */
231 protected byte[] mValue;
232
233 /**
234 * List of descriptors included in this characteristic.
235 */
236 protected List<BluetoothGattDescriptor> mDescriptors;
237
238 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800239 * Create a new BluetoothGattCharacteristic.
240 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
241 *
242 * @param uuid The UUID for this characteristic
243 * @param properties Properties of this characteristic
244 * @param permissions Permissions for this characteristic
245 */
246 public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
247 initCharacteristic(null, uuid, 0, properties, permissions);
248 }
249
250 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800251 * Create a new BluetoothGattCharacteristic
Jack Hea355e5e2017-08-22 16:06:54 -0700252 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800253 * @hide
254 */
255 /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
Jack Hea355e5e2017-08-22 16:06:54 -0700256 UUID uuid, int instanceId,
257 int properties, int permissions) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800258 initCharacteristic(service, uuid, instanceId, properties, permissions);
259 }
260
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800261 /**
262 * Create a new BluetoothGattCharacteristic
Jack Hea355e5e2017-08-22 16:06:54 -0700263 *
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800264 * @hide
265 */
266 public BluetoothGattCharacteristic(UUID uuid, int instanceId,
Jack Hea355e5e2017-08-22 16:06:54 -0700267 int properties, int permissions) {
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800268 initCharacteristic(null, uuid, instanceId, properties, permissions);
269 }
270
Matthew Xieddf7e472013-03-01 18:41:02 -0800271 private void initCharacteristic(BluetoothGattService service,
Jack Hea355e5e2017-08-22 16:06:54 -0700272 UUID uuid, int instanceId,
273 int properties, int permissions) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800274 mUuid = uuid;
275 mInstance = instanceId;
276 mProperties = properties;
277 mPermissions = permissions;
278 mService = service;
279 mValue = null;
280 mDescriptors = new ArrayList<BluetoothGattDescriptor>();
281
282 if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) {
283 mWriteType = WRITE_TYPE_NO_RESPONSE;
284 } else {
285 mWriteType = WRITE_TYPE_DEFAULT;
286 }
287 }
288
Jack He2992cd02017-08-22 21:21:23 -0700289 @Override
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800290 public int describeContents() {
291 return 0;
292 }
293
Jack He2992cd02017-08-22 21:21:23 -0700294 @Override
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800295 public void writeToParcel(Parcel out, int flags) {
296 out.writeParcelable(new ParcelUuid(mUuid), 0);
297 out.writeInt(mInstance);
298 out.writeInt(mProperties);
299 out.writeInt(mPermissions);
Jakub Pawlowski2168fc22016-04-01 07:17:15 -0700300 out.writeInt(mKeySize);
301 out.writeInt(mWriteType);
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800302 out.writeTypedList(mDescriptors);
303 }
304
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700305 public static final @android.annotation.NonNull Parcelable.Creator<BluetoothGattCharacteristic> CREATOR =
Jack He2992cd02017-08-22 21:21:23 -0700306 new Parcelable.Creator<BluetoothGattCharacteristic>() {
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800307 public BluetoothGattCharacteristic createFromParcel(Parcel in) {
308 return new BluetoothGattCharacteristic(in);
309 }
310
311 public BluetoothGattCharacteristic[] newArray(int size) {
312 return new BluetoothGattCharacteristic[size];
313 }
314 };
315
316 private BluetoothGattCharacteristic(Parcel in) {
Jack Hea355e5e2017-08-22 16:06:54 -0700317 mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800318 mInstance = in.readInt();
319 mProperties = in.readInt();
320 mPermissions = in.readInt();
Jakub Pawlowski2168fc22016-04-01 07:17:15 -0700321 mKeySize = in.readInt();
322 mWriteType = in.readInt();
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800323
324 mDescriptors = new ArrayList<BluetoothGattDescriptor>();
325
326 ArrayList<BluetoothGattDescriptor> descs =
327 in.createTypedArrayList(BluetoothGattDescriptor.CREATOR);
328 if (descs != null) {
Jack Hea355e5e2017-08-22 16:06:54 -0700329 for (BluetoothGattDescriptor desc : descs) {
Jakub Pawlowski8d312a82016-03-01 18:50:27 -0800330 desc.setCharacteristic(this);
331 mDescriptors.add(desc);
332 }
333 }
334 }
335
336 /**
Jakub Pawlowskid75f5122016-04-01 07:51:45 -0700337 * Returns the desired key size.
Jack Hea355e5e2017-08-22 16:06:54 -0700338 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800339 * @hide
340 */
Jakub Pawlowskid75f5122016-04-01 07:51:45 -0700341 public int getKeySize() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800342 return mKeySize;
343 }
344
345 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800346 * Adds a descriptor to this characteristic.
347 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
348 *
349 * @param descriptor Descriptor to be added to this characteristic.
350 * @return true, if the descriptor was added to the characteristic
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800351 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800352 public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800353 mDescriptors.add(descriptor);
Matthew Xieddf7e472013-03-01 18:41:02 -0800354 descriptor.setCharacteristic(this);
355 return true;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800356 }
357
358 /**
Andre Eisenbach25b9cf92013-07-08 23:58:16 -0700359 * Get a descriptor by UUID and isntance id.
Jack Hea355e5e2017-08-22 16:06:54 -0700360 *
Andre Eisenbach25b9cf92013-07-08 23:58:16 -0700361 * @hide
362 */
363 /*package*/ BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) {
Jack Hea355e5e2017-08-22 16:06:54 -0700364 for (BluetoothGattDescriptor descriptor : mDescriptors) {
Andre Eisenbach25b9cf92013-07-08 23:58:16 -0700365 if (descriptor.getUuid().equals(uuid)
Jack Hea355e5e2017-08-22 16:06:54 -0700366 && descriptor.getInstanceId() == instanceId) {
Andre Eisenbach25b9cf92013-07-08 23:58:16 -0700367 return descriptor;
368 }
369 }
370 return null;
371 }
372
373 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800374 * Returns the service this characteristic belongs to.
Jack Hea355e5e2017-08-22 16:06:54 -0700375 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800376 * @return The asscociated service
377 */
378 public BluetoothGattService getService() {
379 return mService;
380 }
381
382 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800383 * Sets the service associated with this device.
Jack Hea355e5e2017-08-22 16:06:54 -0700384 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800385 * @hide
386 */
Mathew Inwood7acad5e2018-08-01 15:00:35 +0100387 @UnsupportedAppUsage
Matthew Xieddf7e472013-03-01 18:41:02 -0800388 /*package*/ void setService(BluetoothGattService service) {
389 mService = service;
390 }
391
392 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800393 * Returns the UUID of this characteristic
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800394 *
395 * @return UUID of this characteristic
396 */
397 public UUID getUuid() {
398 return mUuid;
399 }
400
401 /**
402 * Returns the instance ID for this characteristic.
403 *
404 * <p>If a remote device offers multiple characteristics with the same UUID,
405 * the instance ID is used to distuinguish between characteristics.
406 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800407 * @return Instance ID of this characteristic
408 */
409 public int getInstanceId() {
410 return mInstance;
411 }
412
413 /**
Jakub Pawlowskid75f5122016-04-01 07:51:45 -0700414 * Force the instance ID.
Jack Hea355e5e2017-08-22 16:06:54 -0700415 *
Jakub Pawlowskid75f5122016-04-01 07:51:45 -0700416 * @hide
417 */
418 public void setInstanceId(int instanceId) {
419 mInstance = instanceId;
420 }
421
422 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800423 * Returns the properties of this characteristic.
424 *
425 * <p>The properties contain a bit mask of property flags indicating
426 * the features of this characteristic.
427 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800428 * @return Properties of this characteristic
429 */
430 public int getProperties() {
431 return mProperties;
432 }
433
434 /**
435 * Returns the permissions for this characteristic.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800436 *
437 * @return Permissions of this characteristic
438 */
439 public int getPermissions() {
440 return mPermissions;
441 }
442
443 /**
444 * Gets the write type for this characteristic.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800445 *
446 * @return Write type for this characteristic
447 */
448 public int getWriteType() {
449 return mWriteType;
450 }
451
452 /**
453 * Set the write type for this characteristic
454 *
455 * <p>Setting the write type of a characteristic determines how the
456 * {@link BluetoothGatt#writeCharacteristic} function write this
457 * characteristic.
458 *
Jack Hea355e5e2017-08-22 16:06:54 -0700459 * @param writeType The write type to for this characteristic. Can be one of: {@link
460 * #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800461 */
462 public void setWriteType(int writeType) {
463 mWriteType = writeType;
464 }
465
466 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800467 * Set the desired key size.
Jack Hea355e5e2017-08-22 16:06:54 -0700468 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800469 * @hide
470 */
Mathew Inwood7acad5e2018-08-01 15:00:35 +0100471 @UnsupportedAppUsage
Matthew Xieddf7e472013-03-01 18:41:02 -0800472 public void setKeySize(int keySize) {
473 mKeySize = keySize;
474 }
475
476 /**
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800477 * Returns a list of descriptors for this characteristic.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800478 *
479 * @return Descriptors for this characteristic
480 */
481 public List<BluetoothGattDescriptor> getDescriptors() {
482 return mDescriptors;
483 }
484
485 /**
486 * Returns a descriptor with a given UUID out of the list of
487 * descriptors for this characteristic.
488 *
Jack Hea355e5e2017-08-22 16:06:54 -0700489 * @return GATT descriptor object or null if no descriptor with the given UUID was found.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800490 */
491 public BluetoothGattDescriptor getDescriptor(UUID uuid) {
Jack Hea355e5e2017-08-22 16:06:54 -0700492 for (BluetoothGattDescriptor descriptor : mDescriptors) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800493 if (descriptor.getUuid().equals(uuid)) {
494 return descriptor;
495 }
496 }
497 return null;
498 }
499
500 /**
501 * Get the stored value for this characteristic.
502 *
503 * <p>This function returns the stored value for this characteristic as
Matthew Xieddf7e472013-03-01 18:41:02 -0800504 * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800505 * value of the characteristic is updated as a result of a read characteristic
506 * operation or if a characteristic update notification has been received.
507 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800508 * @return Cached value of the characteristic
509 */
510 public byte[] getValue() {
511 return mValue;
512 }
513
514 /**
515 * Return the stored value of this characteristic.
516 *
517 * <p>The formatType parameter determines how the characteristic value
518 * is to be interpreted. For example, settting formatType to
519 * {@link #FORMAT_UINT16} specifies that the first two bytes of the
520 * characteristic value at the given offset are interpreted to generate the
521 * return value.
522 *
Jack Hea355e5e2017-08-22 16:06:54 -0700523 * @param formatType The format type used to interpret the characteristic value.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800524 * @param offset Offset at which the integer value can be found.
Jack Hea355e5e2017-08-22 16:06:54 -0700525 * @return Cached value of the characteristic or null of offset exceeds value size.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800526 */
527 public Integer getIntValue(int formatType, int offset) {
528 if ((offset + getTypeLen(formatType)) > mValue.length) return null;
529
530 switch (formatType) {
531 case FORMAT_UINT8:
532 return unsignedByteToInt(mValue[offset]);
533
534 case FORMAT_UINT16:
Jack Hea355e5e2017-08-22 16:06:54 -0700535 return unsignedBytesToInt(mValue[offset], mValue[offset + 1]);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800536
537 case FORMAT_UINT32:
Jack Hea355e5e2017-08-22 16:06:54 -0700538 return unsignedBytesToInt(mValue[offset], mValue[offset + 1],
539 mValue[offset + 2], mValue[offset + 3]);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800540 case FORMAT_SINT8:
541 return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8);
542
543 case FORMAT_SINT16:
544 return unsignedToSigned(unsignedBytesToInt(mValue[offset],
Jack Hea355e5e2017-08-22 16:06:54 -0700545 mValue[offset + 1]), 16);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800546
547 case FORMAT_SINT32:
548 return unsignedToSigned(unsignedBytesToInt(mValue[offset],
Jack Hea355e5e2017-08-22 16:06:54 -0700549 mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800550 }
551
552 return null;
553 }
554
555 /**
556 * Return the stored value of this characteristic.
557 * <p>See {@link #getValue} for details.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800558 *
Jack Hea355e5e2017-08-22 16:06:54 -0700559 * @param formatType The format type used to interpret the characteristic value.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800560 * @param offset Offset at which the float value can be found.
Jack Hea355e5e2017-08-22 16:06:54 -0700561 * @return Cached value of the characteristic at a given offset or null if the requested offset
562 * exceeds the value size.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800563 */
564 public Float getFloatValue(int formatType, int offset) {
565 if ((offset + getTypeLen(formatType)) > mValue.length) return null;
566
567 switch (formatType) {
568 case FORMAT_SFLOAT:
Jack Hea355e5e2017-08-22 16:06:54 -0700569 return bytesToFloat(mValue[offset], mValue[offset + 1]);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800570
571 case FORMAT_FLOAT:
Jack Hea355e5e2017-08-22 16:06:54 -0700572 return bytesToFloat(mValue[offset], mValue[offset + 1],
573 mValue[offset + 2], mValue[offset + 3]);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800574 }
575
576 return null;
577 }
578
579 /**
580 * Return the stored value of this characteristic.
581 * <p>See {@link #getValue} for details.
Matthew Xieddf7e472013-03-01 18:41:02 -0800582 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800583 * @param offset Offset at which the string value can be found.
584 * @return Cached value of the characteristic
585 */
586 public String getStringValue(int offset) {
Andre Eisenbach0fd06a12014-12-09 16:42:14 -0800587 if (mValue == null || offset > mValue.length) return null;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800588 byte[] strBytes = new byte[mValue.length - offset];
Jack Hea355e5e2017-08-22 16:06:54 -0700589 for (int i = 0; i != (mValue.length - offset); ++i) strBytes[i] = mValue[offset + i];
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800590 return new String(strBytes);
591 }
592
593 /**
594 * Updates the locally stored value of this characteristic.
595 *
596 * <p>This function modifies the locally stored cached value of this
597 * characteristic. To send the value to the remote device, call
598 * {@link BluetoothGatt#writeCharacteristic} to send the value to the
599 * remote device.
600 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800601 * @param value New value for this characteristic
Jack Hea355e5e2017-08-22 16:06:54 -0700602 * @return true if the locally stored value has been set, false if the requested value could not
603 * be stored locally.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800604 */
605 public boolean setValue(byte[] value) {
606 mValue = value;
607 return true;
608 }
609
610 /**
611 * Set the locally stored value of this characteristic.
612 * <p>See {@link #setValue(byte[])} for details.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800613 *
614 * @param value New value for this characteristic
615 * @param formatType Integer format type used to transform the value parameter
616 * @param offset Offset at which the value should be placed
617 * @return true if the locally stored value has been set
618 */
619 public boolean setValue(int value, int formatType, int offset) {
620 int len = offset + getTypeLen(formatType);
621 if (mValue == null) mValue = new byte[len];
622 if (len > mValue.length) return false;
623
624 switch (formatType) {
625 case FORMAT_SINT8:
626 value = intToSignedBits(value, 8);
627 // Fall-through intended
628 case FORMAT_UINT8:
Jack Hea355e5e2017-08-22 16:06:54 -0700629 mValue[offset] = (byte) (value & 0xFF);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800630 break;
631
632 case FORMAT_SINT16:
633 value = intToSignedBits(value, 16);
634 // Fall-through intended
635 case FORMAT_UINT16:
Jack Hea355e5e2017-08-22 16:06:54 -0700636 mValue[offset++] = (byte) (value & 0xFF);
637 mValue[offset] = (byte) ((value >> 8) & 0xFF);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800638 break;
639
640 case FORMAT_SINT32:
641 value = intToSignedBits(value, 32);
642 // Fall-through intended
643 case FORMAT_UINT32:
Jack Hea355e5e2017-08-22 16:06:54 -0700644 mValue[offset++] = (byte) (value & 0xFF);
645 mValue[offset++] = (byte) ((value >> 8) & 0xFF);
646 mValue[offset++] = (byte) ((value >> 16) & 0xFF);
647 mValue[offset] = (byte) ((value >> 24) & 0xFF);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800648 break;
649
650 default:
651 return false;
652 }
653 return true;
654 }
655
656 /**
657 * Set the locally stored value of this characteristic.
658 * <p>See {@link #setValue(byte[])} for details.
Matthew Xieddf7e472013-03-01 18:41:02 -0800659 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800660 * @param mantissa Mantissa for this characteristic
Jack Hea355e5e2017-08-22 16:06:54 -0700661 * @param exponent exponent value for this characteristic
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800662 * @param formatType Float format type used to transform the value parameter
663 * @param offset Offset at which the value should be placed
664 * @return true if the locally stored value has been set
665 */
666 public boolean setValue(int mantissa, int exponent, int formatType, int offset) {
667 int len = offset + getTypeLen(formatType);
668 if (mValue == null) mValue = new byte[len];
669 if (len > mValue.length) return false;
670
671 switch (formatType) {
672 case FORMAT_SFLOAT:
673 mantissa = intToSignedBits(mantissa, 12);
674 exponent = intToSignedBits(exponent, 4);
Jack Hea355e5e2017-08-22 16:06:54 -0700675 mValue[offset++] = (byte) (mantissa & 0xFF);
676 mValue[offset] = (byte) ((mantissa >> 8) & 0x0F);
677 mValue[offset] += (byte) ((exponent & 0x0F) << 4);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800678 break;
679
680 case FORMAT_FLOAT:
681 mantissa = intToSignedBits(mantissa, 24);
682 exponent = intToSignedBits(exponent, 8);
Jack Hea355e5e2017-08-22 16:06:54 -0700683 mValue[offset++] = (byte) (mantissa & 0xFF);
684 mValue[offset++] = (byte) ((mantissa >> 8) & 0xFF);
685 mValue[offset++] = (byte) ((mantissa >> 16) & 0xFF);
686 mValue[offset] += (byte) (exponent & 0xFF);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800687 break;
688
689 default:
690 return false;
691 }
692
693 return true;
694 }
695
696 /**
697 * Set the locally stored value of this characteristic.
698 * <p>See {@link #setValue(byte[])} for details.
Matthew Xieddf7e472013-03-01 18:41:02 -0800699 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800700 * @param value New value for this characteristic
701 * @return true if the locally stored value has been set
702 */
703 public boolean setValue(String value) {
704 mValue = value.getBytes();
705 return true;
706 }
707
708 /**
709 * Returns the size of a give value type.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800710 */
711 private int getTypeLen(int formatType) {
712 return formatType & 0xF;
713 }
714
715 /**
716 * Convert a signed byte to an unsigned int.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800717 */
718 private int unsignedByteToInt(byte b) {
719 return b & 0xFF;
720 }
721
722 /**
723 * Convert signed bytes to a 16-bit unsigned int.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800724 */
725 private int unsignedBytesToInt(byte b0, byte b1) {
726 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
727 }
728
729 /**
730 * Convert signed bytes to a 32-bit unsigned int.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800731 */
732 private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
733 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
Jack Hea355e5e2017-08-22 16:06:54 -0700734 + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800735 }
736
737 /**
738 * Convert signed bytes to a 16-bit short float value.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800739 */
740 private float bytesToFloat(byte b0, byte b1) {
741 int mantissa = unsignedToSigned(unsignedByteToInt(b0)
Jack Hea355e5e2017-08-22 16:06:54 -0700742 + ((unsignedByteToInt(b1) & 0x0F) << 8), 12);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800743 int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4);
Jack Hea355e5e2017-08-22 16:06:54 -0700744 return (float) (mantissa * Math.pow(10, exponent));
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800745 }
746
747 /**
748 * Convert signed bytes to a 32-bit short float value.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800749 */
750 private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
751 int mantissa = unsignedToSigned(unsignedByteToInt(b0)
Jack Hea355e5e2017-08-22 16:06:54 -0700752 + (unsignedByteToInt(b1) << 8)
753 + (unsignedByteToInt(b2) << 16), 24);
754 return (float) (mantissa * Math.pow(10, b3));
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800755 }
756
757 /**
758 * Convert an unsigned integer value to a two's-complement encoded
759 * signed value.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800760 */
761 private int unsignedToSigned(int unsigned, int size) {
Jack Hea355e5e2017-08-22 16:06:54 -0700762 if ((unsigned & (1 << size - 1)) != 0) {
763 unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800764 }
765 return unsigned;
766 }
767
768 /**
769 * Convert an integer into the signed bits of a given length.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800770 */
771 private int intToSignedBits(int i, int size) {
772 if (i < 0) {
Jack Hea355e5e2017-08-22 16:06:54 -0700773 i = (1 << size - 1) + (i & ((1 << size - 1) - 1));
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800774 }
775 return i;
776 }
777}