1 /* 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 */ 16 package android.bluetooth; 17 18 import java.util.ArrayList; 19 import java.util.IllegalFormatConversionException; 20 import java.util.List; 21 import java.util.UUID; 22 23 /** 24 * Represents a Bluetooth GATT Characteristic 25 * 26 * <p>A GATT characteristic is a basic data element used to construct a GATT service, 27 * {@link BluetoothGattService}. The characteristic contains a value as well as 28 * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}. 29 */ 30 public class BluetoothGattCharacteristic { 31 32 /** 33 * Characteristic proprty: Characteristic is broadcastable. 34 */ 35 public static final int PROPERTY_BROADCAST = 0x01; 36 37 /** 38 * Characteristic property: Characteristic is readable. 39 */ 40 public static final int PROPERTY_READ = 0x02; 41 42 /** 43 * Characteristic property: Characteristic can be written without response. 44 */ 45 public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04; 46 47 /** 48 * Characteristic property: Characteristic can be written. 49 */ 50 public static final int PROPERTY_WRITE = 0x08; 51 52 /** 53 * Characteristic property: Characteristic supports notification 54 */ 55 public static final int PROPERTY_NOTIFY = 0x10; 56 57 /** 58 * Characteristic property: Characteristic supports indication 59 */ 60 public static final int PROPERTY_INDICATE = 0x20; 61 62 /** 63 * Characteristic property: Characteristic supports write with signature 64 */ 65 public static final int PROPERTY_SIGNED_WRITE = 0x40; 66 67 /** 68 * Characteristic property: Characteristic has extended properties 69 */ 70 public static final int PROPERTY_EXTENDED_PROPS = 0x80; 71 72 /** 73 * Characteristic read permission 74 */ 75 public static final int PERMISSION_READ = 0x01; 76 77 /** 78 * Characteristic permission: Allow encrypted read operations 79 */ 80 public static final int PERMISSION_READ_ENCRYPTED = 0x02; 81 82 /** 83 * Characteristic permission: Allow reading with man-in-the-middle protection 84 */ 85 public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04; 86 87 /** 88 * Characteristic write permission 89 */ 90 public static final int PERMISSION_WRITE = 0x10; 91 92 /** 93 * Characteristic permission: Allow encrypted writes 94 */ 95 public static final int PERMISSION_WRITE_ENCRYPTED = 0x20; 96 97 /** 98 * Characteristic permission: Allow encrypted writes with man-in-the-middle 99 * protection 100 */ 101 public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40; 102 103 /** 104 * Characteristic permission: Allow signed write operations 105 */ 106 public static final int PERMISSION_WRITE_SIGNED = 0x80; 107 108 /** 109 * Characteristic permission: Allow signed write operations with 110 * man-in-the-middle protection 111 */ 112 public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100; 113 114 /** 115 * Write characteristic, requesting acknoledgement by the remote device 116 */ 117 public static final int WRITE_TYPE_DEFAULT = 0x02; 118 119 /** 120 * Wrtite characteristic without requiring a response by the remote device 121 */ 122 public static final int WRITE_TYPE_NO_RESPONSE = 0x01; 123 124 /** 125 * Write characteristic including authentication signature 126 */ 127 public static final int WRITE_TYPE_SIGNED = 0x04; 128 129 /** 130 * Characteristic value format type uint8 131 */ 132 public static final int FORMAT_UINT8 = 0x11; 133 134 /** 135 * Characteristic value format type uint16 136 */ 137 public static final int FORMAT_UINT16 = 0x12; 138 139 /** 140 * Characteristic value format type uint32 141 */ 142 public static final int FORMAT_UINT32 = 0x14; 143 144 /** 145 * Characteristic value format type sint8 146 */ 147 public static final int FORMAT_SINT8 = 0x21; 148 149 /** 150 * Characteristic value format type sint16 151 */ 152 public static final int FORMAT_SINT16 = 0x22; 153 154 /** 155 * Characteristic value format type sint32 156 */ 157 public static final int FORMAT_SINT32 = 0x24; 158 159 /** 160 * Characteristic value format type sfloat (16-bit float) 161 */ 162 public static final int FORMAT_SFLOAT = 0x32; 163 164 /** 165 * Characteristic value format type float (32-bit float) 166 */ 167 public static final int FORMAT_FLOAT = 0x34; 168 169 170 /** 171 * The UUID of this characteristic. 172 * @hide 173 */ 174 protected UUID mUuid; 175 176 /** 177 * Instance ID for this characteristic. 178 * @hide 179 */ 180 protected int mInstance; 181 182 /** 183 * Characteristic properties. 184 * @hide 185 */ 186 protected int mProperties; 187 188 /** 189 * Characteristic permissions. 190 * @hide 191 */ 192 protected int mPermissions; 193 194 /** 195 * Key size (default = 16). 196 * @hide 197 */ 198 protected int mKeySize = 16; 199 200 /** 201 * Write type for this characteristic. 202 * See WRITE_TYPE_* constants. 203 * @hide 204 */ 205 protected int mWriteType; 206 207 /** 208 * Back-reference to the service this characteristic belongs to. 209 * @hide 210 */ 211 protected BluetoothGattService mService; 212 213 /** 214 * The cached value of this characteristic. 215 * @hide 216 */ 217 protected byte[] mValue; 218 219 /** 220 * List of descriptors included in this characteristic. 221 */ 222 protected List<BluetoothGattDescriptor> mDescriptors; 223 224 /** 225 * Create a new BluetoothGattCharacteristic. 226 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 227 * 228 * @param uuid The UUID for this characteristic 229 * @param properties Properties of this characteristic 230 * @param permissions Permissions for this characteristic 231 */ BluetoothGattCharacteristic(UUID uuid, int properties, int permissions)232 public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) { 233 initCharacteristic(null, uuid, 0, properties, permissions); 234 } 235 236 /** 237 * Create a new BluetoothGattCharacteristic 238 * @hide 239 */ BluetoothGattCharacteristic(BluetoothGattService service, UUID uuid, int instanceId, int properties, int permissions)240 /*package*/ BluetoothGattCharacteristic(BluetoothGattService service, 241 UUID uuid, int instanceId, 242 int properties, int permissions) { 243 initCharacteristic(service, uuid, instanceId, properties, permissions); 244 } 245 initCharacteristic(BluetoothGattService service, UUID uuid, int instanceId, int properties, int permissions)246 private void initCharacteristic(BluetoothGattService service, 247 UUID uuid, int instanceId, 248 int properties, int permissions) { 249 mUuid = uuid; 250 mInstance = instanceId; 251 mProperties = properties; 252 mPermissions = permissions; 253 mService = service; 254 mValue = null; 255 mDescriptors = new ArrayList<BluetoothGattDescriptor>(); 256 257 if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) { 258 mWriteType = WRITE_TYPE_NO_RESPONSE; 259 } else { 260 mWriteType = WRITE_TYPE_DEFAULT; 261 } 262 } 263 264 /** 265 * Returns the deisred key size. 266 * @hide 267 */ getKeySize()268 /*package*/ int getKeySize() { 269 return mKeySize; 270 } 271 272 /** 273 * Adds a descriptor to this characteristic. 274 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 275 * 276 * @param descriptor Descriptor to be added to this characteristic. 277 * @return true, if the descriptor was added to the characteristic 278 */ addDescriptor(BluetoothGattDescriptor descriptor)279 public boolean addDescriptor(BluetoothGattDescriptor descriptor) { 280 mDescriptors.add(descriptor); 281 descriptor.setCharacteristic(this); 282 return true; 283 } 284 285 /** 286 * Get a descriptor by UUID and isntance id. 287 * @hide 288 */ getDescriptor(UUID uuid, int instanceId)289 /*package*/ BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) { 290 for(BluetoothGattDescriptor descriptor : mDescriptors) { 291 if (descriptor.getUuid().equals(uuid) 292 && descriptor.getInstanceId() == instanceId) { 293 return descriptor; 294 } 295 } 296 return null; 297 } 298 299 /** 300 * Returns the service this characteristic belongs to. 301 * @return The asscociated service 302 */ getService()303 public BluetoothGattService getService() { 304 return mService; 305 } 306 307 /** 308 * Sets the service associated with this device. 309 * @hide 310 */ setService(BluetoothGattService service)311 /*package*/ void setService(BluetoothGattService service) { 312 mService = service; 313 } 314 315 /** 316 * Returns the UUID of this characteristic 317 * 318 * @return UUID of this characteristic 319 */ getUuid()320 public UUID getUuid() { 321 return mUuid; 322 } 323 324 /** 325 * Returns the instance ID for this characteristic. 326 * 327 * <p>If a remote device offers multiple characteristics with the same UUID, 328 * the instance ID is used to distuinguish between characteristics. 329 * 330 * @return Instance ID of this characteristic 331 */ getInstanceId()332 public int getInstanceId() { 333 return mInstance; 334 } 335 336 /** 337 * Returns the properties of this characteristic. 338 * 339 * <p>The properties contain a bit mask of property flags indicating 340 * the features of this characteristic. 341 * 342 * @return Properties of this characteristic 343 */ getProperties()344 public int getProperties() { 345 return mProperties; 346 } 347 348 /** 349 * Returns the permissions for this characteristic. 350 * 351 * @return Permissions of this characteristic 352 */ getPermissions()353 public int getPermissions() { 354 return mPermissions; 355 } 356 357 /** 358 * Gets the write type for this characteristic. 359 * 360 * @return Write type for this characteristic 361 */ getWriteType()362 public int getWriteType() { 363 return mWriteType; 364 } 365 366 /** 367 * Set the write type for this characteristic 368 * 369 * <p>Setting the write type of a characteristic determines how the 370 * {@link BluetoothGatt#writeCharacteristic} function write this 371 * characteristic. 372 * 373 * @param writeType The write type to for this characteristic. Can be one 374 * of: 375 * {@link #WRITE_TYPE_DEFAULT}, 376 * {@link #WRITE_TYPE_NO_RESPONSE} or 377 * {@link #WRITE_TYPE_SIGNED}. 378 */ setWriteType(int writeType)379 public void setWriteType(int writeType) { 380 mWriteType = writeType; 381 } 382 383 /** 384 * Set the desired key size. 385 * @hide 386 */ setKeySize(int keySize)387 public void setKeySize(int keySize) { 388 mKeySize = keySize; 389 } 390 391 /** 392 * Returns a list of descriptors for this characteristic. 393 * 394 * @return Descriptors for this characteristic 395 */ getDescriptors()396 public List<BluetoothGattDescriptor> getDescriptors() { 397 return mDescriptors; 398 } 399 400 /** 401 * Returns a descriptor with a given UUID out of the list of 402 * descriptors for this characteristic. 403 * 404 * @return GATT descriptor object or null if no descriptor with the 405 * given UUID was found. 406 */ getDescriptor(UUID uuid)407 public BluetoothGattDescriptor getDescriptor(UUID uuid) { 408 for(BluetoothGattDescriptor descriptor : mDescriptors) { 409 if (descriptor.getUuid().equals(uuid)) { 410 return descriptor; 411 } 412 } 413 return null; 414 } 415 416 /** 417 * Get the stored value for this characteristic. 418 * 419 * <p>This function returns the stored value for this characteristic as 420 * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached 421 * value of the characteristic is updated as a result of a read characteristic 422 * operation or if a characteristic update notification has been received. 423 * 424 * @return Cached value of the characteristic 425 */ getValue()426 public byte[] getValue() { 427 return mValue; 428 } 429 430 /** 431 * Return the stored value of this characteristic. 432 * 433 * <p>The formatType parameter determines how the characteristic value 434 * is to be interpreted. For example, settting formatType to 435 * {@link #FORMAT_UINT16} specifies that the first two bytes of the 436 * characteristic value at the given offset are interpreted to generate the 437 * return value. 438 * 439 * @param formatType The format type used to interpret the characteristic 440 * value. 441 * @param offset Offset at which the integer value can be found. 442 * @return Cached value of the characteristic or null of offset exceeds 443 * value size. 444 */ getIntValue(int formatType, int offset)445 public Integer getIntValue(int formatType, int offset) { 446 if ((offset + getTypeLen(formatType)) > mValue.length) return null; 447 448 switch (formatType) { 449 case FORMAT_UINT8: 450 return unsignedByteToInt(mValue[offset]); 451 452 case FORMAT_UINT16: 453 return unsignedBytesToInt(mValue[offset], mValue[offset+1]); 454 455 case FORMAT_UINT32: 456 return unsignedBytesToInt(mValue[offset], mValue[offset+1], 457 mValue[offset+2], mValue[offset+3]); 458 case FORMAT_SINT8: 459 return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8); 460 461 case FORMAT_SINT16: 462 return unsignedToSigned(unsignedBytesToInt(mValue[offset], 463 mValue[offset+1]), 16); 464 465 case FORMAT_SINT32: 466 return unsignedToSigned(unsignedBytesToInt(mValue[offset], 467 mValue[offset+1], mValue[offset+2], mValue[offset+3]), 32); 468 } 469 470 return null; 471 } 472 473 /** 474 * Return the stored value of this characteristic. 475 * <p>See {@link #getValue} for details. 476 * 477 * @param formatType The format type used to interpret the characteristic 478 * value. 479 * @param offset Offset at which the float value can be found. 480 * @return Cached value of the characteristic at a given offset or null 481 * if the requested offset exceeds the value size. 482 */ getFloatValue(int formatType, int offset)483 public Float getFloatValue(int formatType, int offset) { 484 if ((offset + getTypeLen(formatType)) > mValue.length) return null; 485 486 switch (formatType) { 487 case FORMAT_SFLOAT: 488 return bytesToFloat(mValue[offset], mValue[offset+1]); 489 490 case FORMAT_FLOAT: 491 return bytesToFloat(mValue[offset], mValue[offset+1], 492 mValue[offset+2], mValue[offset+3]); 493 } 494 495 return null; 496 } 497 498 /** 499 * Return the stored value of this characteristic. 500 * <p>See {@link #getValue} for details. 501 * 502 * @param offset Offset at which the string value can be found. 503 * @return Cached value of the characteristic 504 */ getStringValue(int offset)505 public String getStringValue(int offset) { 506 if (offset > mValue.length) return null; 507 byte[] strBytes = new byte[mValue.length - offset]; 508 for (int i=0; i != (mValue.length-offset); ++i) strBytes[i] = mValue[offset+i]; 509 return new String(strBytes); 510 } 511 512 /** 513 * Updates the locally stored value of this characteristic. 514 * 515 * <p>This function modifies the locally stored cached value of this 516 * characteristic. To send the value to the remote device, call 517 * {@link BluetoothGatt#writeCharacteristic} to send the value to the 518 * remote device. 519 * 520 * @param value New value for this characteristic 521 * @return true if the locally stored value has been set, false if the 522 * requested value could not be stored locally. 523 */ setValue(byte[] value)524 public boolean setValue(byte[] value) { 525 mValue = value; 526 return true; 527 } 528 529 /** 530 * Set the locally stored value of this characteristic. 531 * <p>See {@link #setValue(byte[])} for details. 532 * 533 * @param value New value for this characteristic 534 * @param formatType Integer format type used to transform the value parameter 535 * @param offset Offset at which the value should be placed 536 * @return true if the locally stored value has been set 537 */ setValue(int value, int formatType, int offset)538 public boolean setValue(int value, int formatType, int offset) { 539 int len = offset + getTypeLen(formatType); 540 if (mValue == null) mValue = new byte[len]; 541 if (len > mValue.length) return false; 542 543 switch (formatType) { 544 case FORMAT_SINT8: 545 value = intToSignedBits(value, 8); 546 // Fall-through intended 547 case FORMAT_UINT8: 548 mValue[offset] = (byte)(value & 0xFF); 549 break; 550 551 case FORMAT_SINT16: 552 value = intToSignedBits(value, 16); 553 // Fall-through intended 554 case FORMAT_UINT16: 555 mValue[offset++] = (byte)(value & 0xFF); 556 mValue[offset] = (byte)((value >> 8) & 0xFF); 557 break; 558 559 case FORMAT_SINT32: 560 value = intToSignedBits(value, 32); 561 // Fall-through intended 562 case FORMAT_UINT32: 563 mValue[offset++] = (byte)(value & 0xFF); 564 mValue[offset++] = (byte)((value >> 8) & 0xFF); 565 mValue[offset++] = (byte)((value >> 16) & 0xFF); 566 mValue[offset] = (byte)((value >> 24) & 0xFF); 567 break; 568 569 default: 570 return false; 571 } 572 return true; 573 } 574 575 /** 576 * Set the locally stored value of this characteristic. 577 * <p>See {@link #setValue(byte[])} for details. 578 * 579 * @param mantissa Mantissa for this characteristic 580 * @param exponent exponent value for this characteristic 581 * @param formatType Float format type used to transform the value parameter 582 * @param offset Offset at which the value should be placed 583 * @return true if the locally stored value has been set 584 */ setValue(int mantissa, int exponent, int formatType, int offset)585 public boolean setValue(int mantissa, int exponent, int formatType, int offset) { 586 int len = offset + getTypeLen(formatType); 587 if (mValue == null) mValue = new byte[len]; 588 if (len > mValue.length) return false; 589 590 switch (formatType) { 591 case FORMAT_SFLOAT: 592 mantissa = intToSignedBits(mantissa, 12); 593 exponent = intToSignedBits(exponent, 4); 594 mValue[offset++] = (byte)(mantissa & 0xFF); 595 mValue[offset] = (byte)((mantissa >> 8) & 0x0F); 596 mValue[offset] += (byte)((exponent & 0x0F) << 4); 597 break; 598 599 case FORMAT_FLOAT: 600 mantissa = intToSignedBits(mantissa, 24); 601 exponent = intToSignedBits(exponent, 8); 602 mValue[offset++] = (byte)(mantissa & 0xFF); 603 mValue[offset++] = (byte)((mantissa >> 8) & 0xFF); 604 mValue[offset++] = (byte)((mantissa >> 16) & 0xFF); 605 mValue[offset] += (byte)(exponent & 0xFF); 606 break; 607 608 default: 609 return false; 610 } 611 612 return true; 613 } 614 615 /** 616 * Set the locally stored value of this characteristic. 617 * <p>See {@link #setValue(byte[])} for details. 618 * 619 * @param value New value for this characteristic 620 * @return true if the locally stored value has been set 621 */ setValue(String value)622 public boolean setValue(String value) { 623 mValue = value.getBytes(); 624 return true; 625 } 626 627 /** 628 * Returns the size of a give value type. 629 */ getTypeLen(int formatType)630 private int getTypeLen(int formatType) { 631 return formatType & 0xF; 632 } 633 634 /** 635 * Convert a signed byte to an unsigned int. 636 */ unsignedByteToInt(byte b)637 private int unsignedByteToInt(byte b) { 638 return b & 0xFF; 639 } 640 641 /** 642 * Convert signed bytes to a 16-bit unsigned int. 643 */ unsignedBytesToInt(byte b0, byte b1)644 private int unsignedBytesToInt(byte b0, byte b1) { 645 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)); 646 } 647 648 /** 649 * Convert signed bytes to a 32-bit unsigned int. 650 */ unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3)651 private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) { 652 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)) 653 + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24); 654 } 655 656 /** 657 * Convert signed bytes to a 16-bit short float value. 658 */ bytesToFloat(byte b0, byte b1)659 private float bytesToFloat(byte b0, byte b1) { 660 int mantissa = unsignedToSigned(unsignedByteToInt(b0) 661 + ((unsignedByteToInt(b1) & 0x0F) << 8), 12); 662 int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4); 663 return (float)(mantissa * Math.pow(10, exponent)); 664 } 665 666 /** 667 * Convert signed bytes to a 32-bit short float value. 668 */ bytesToFloat(byte b0, byte b1, byte b2, byte b3)669 private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) { 670 int mantissa = unsignedToSigned(unsignedByteToInt(b0) 671 + (unsignedByteToInt(b1) << 8) 672 + (unsignedByteToInt(b2) << 16), 24); 673 return (float)(mantissa * Math.pow(10, b3)); 674 } 675 676 /** 677 * Convert an unsigned integer value to a two's-complement encoded 678 * signed value. 679 */ unsignedToSigned(int unsigned, int size)680 private int unsignedToSigned(int unsigned, int size) { 681 if ((unsigned & (1 << size-1)) != 0) { 682 unsigned = -1 * ((1 << size-1) - (unsigned & ((1 << size-1) - 1))); 683 } 684 return unsigned; 685 } 686 687 /** 688 * Convert an integer into the signed bits of a given length. 689 */ intToSignedBits(int i, int size)690 private int intToSignedBits(int i, int size) { 691 if (i < 0) { 692 i = (1 << size-1) + (i & ((1 << size-1) - 1)); 693 } 694 return i; 695 } 696 } 697