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