Home | History | Annotate | Download | only in bluetooth
      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.annotation.UnsupportedAppUsage;
     19 import android.os.Parcel;
     20 import android.os.ParcelUuid;
     21 import android.os.Parcelable;
     22 
     23 import java.util.ArrayList;
     24 import java.util.List;
     25 import java.util.UUID;
     26 
     27 /**
     28  * Represents a Bluetooth GATT Characteristic
     29  *
     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}.
     33  */
     34 public class BluetoothGattCharacteristic implements Parcelable {
     35 
     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     /**
    124      * Write characteristic without requiring a response by the remote device
    125      */
    126     public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
    127 
    128     /**
    129      * Write characteristic including authentication signature
    130      */
    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.
    176      *
    177      * @hide
    178      */
    179     protected UUID mUuid;
    180 
    181     /**
    182      * Instance ID for this characteristic.
    183      *
    184      * @hide
    185      */
    186     @UnsupportedAppUsage
    187     protected int mInstance;
    188 
    189     /**
    190      * Characteristic properties.
    191      *
    192      * @hide
    193      */
    194     protected int mProperties;
    195 
    196     /**
    197      * Characteristic permissions.
    198      *
    199      * @hide
    200      */
    201     protected int mPermissions;
    202 
    203     /**
    204      * Key size (default = 16).
    205      *
    206      * @hide
    207      */
    208     protected int mKeySize = 16;
    209 
    210     /**
    211      * Write type for this characteristic.
    212      * See WRITE_TYPE_* constants.
    213      *
    214      * @hide
    215      */
    216     protected int mWriteType;
    217 
    218     /**
    219      * Back-reference to the service this characteristic belongs to.
    220      *
    221      * @hide
    222      */
    223     @UnsupportedAppUsage
    224     protected BluetoothGattService mService;
    225 
    226     /**
    227      * The cached value of this characteristic.
    228      *
    229      * @hide
    230      */
    231     protected byte[] mValue;
    232 
    233     /**
    234      * List of descriptors included in this characteristic.
    235      */
    236     protected List<BluetoothGattDescriptor> mDescriptors;
    237 
    238     /**
    239      * 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     /**
    251      * Create a new BluetoothGattCharacteristic
    252      *
    253      * @hide
    254      */
    255     /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
    256             UUID uuid, int instanceId,
    257             int properties, int permissions) {
    258         initCharacteristic(service, uuid, instanceId, properties, permissions);
    259     }
    260 
    261     /**
    262      * Create a new BluetoothGattCharacteristic
    263      *
    264      * @hide
    265      */
    266     public BluetoothGattCharacteristic(UUID uuid, int instanceId,
    267             int properties, int permissions) {
    268         initCharacteristic(null, uuid, instanceId, properties, permissions);
    269     }
    270 
    271     private void initCharacteristic(BluetoothGattService service,
    272             UUID uuid, int instanceId,
    273             int properties, int permissions) {
    274         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 
    289     @Override
    290     public int describeContents() {
    291         return 0;
    292     }
    293 
    294     @Override
    295     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);
    300         out.writeInt(mKeySize);
    301         out.writeInt(mWriteType);
    302         out.writeTypedList(mDescriptors);
    303     }
    304 
    305     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothGattCharacteristic> CREATOR =
    306             new Parcelable.Creator<BluetoothGattCharacteristic>() {
    307         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) {
    317         mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
    318         mInstance = in.readInt();
    319         mProperties = in.readInt();
    320         mPermissions = in.readInt();
    321         mKeySize = in.readInt();
    322         mWriteType = in.readInt();
    323 
    324         mDescriptors = new ArrayList<BluetoothGattDescriptor>();
    325 
    326         ArrayList<BluetoothGattDescriptor> descs =
    327                 in.createTypedArrayList(BluetoothGattDescriptor.CREATOR);
    328         if (descs != null) {
    329             for (BluetoothGattDescriptor desc : descs) {
    330                 desc.setCharacteristic(this);
    331                 mDescriptors.add(desc);
    332             }
    333         }
    334     }
    335 
    336     /**
    337      * Returns the desired key size.
    338      *
    339      * @hide
    340      */
    341     public int getKeySize() {
    342         return mKeySize;
    343     }
    344 
    345     /**
    346      * 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
    351      */
    352     public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
    353         mDescriptors.add(descriptor);
    354         descriptor.setCharacteristic(this);
    355         return true;
    356     }
    357 
    358     /**
    359      * Get a descriptor by UUID and isntance id.
    360      *
    361      * @hide
    362      */
    363     /*package*/  BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) {
    364         for (BluetoothGattDescriptor descriptor : mDescriptors) {
    365             if (descriptor.getUuid().equals(uuid)
    366                     && descriptor.getInstanceId() == instanceId) {
    367                 return descriptor;
    368             }
    369         }
    370         return null;
    371     }
    372 
    373     /**
    374      * Returns the service this characteristic belongs to.
    375      *
    376      * @return The asscociated service
    377      */
    378     public BluetoothGattService getService() {
    379         return mService;
    380     }
    381 
    382     /**
    383      * Sets the service associated with this device.
    384      *
    385      * @hide
    386      */
    387     @UnsupportedAppUsage
    388     /*package*/ void setService(BluetoothGattService service) {
    389         mService = service;
    390     }
    391 
    392     /**
    393      * Returns the UUID of this characteristic
    394      *
    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      *
    407      * @return Instance ID of this characteristic
    408      */
    409     public int getInstanceId() {
    410         return mInstance;
    411     }
    412 
    413     /**
    414      * Force the instance ID.
    415      *
    416      * @hide
    417      */
    418     public void setInstanceId(int instanceId) {
    419         mInstance = instanceId;
    420     }
    421 
    422     /**
    423      * 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      *
    428      * @return Properties of this characteristic
    429      */
    430     public int getProperties() {
    431         return mProperties;
    432     }
    433 
    434     /**
    435      * Returns the permissions for this characteristic.
    436      *
    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.
    445      *
    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      *
    459      * @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}.
    461      */
    462     public void setWriteType(int writeType) {
    463         mWriteType = writeType;
    464     }
    465 
    466     /**
    467      * Set the desired key size.
    468      *
    469      * @hide
    470      */
    471     @UnsupportedAppUsage
    472     public void setKeySize(int keySize) {
    473         mKeySize = keySize;
    474     }
    475 
    476     /**
    477      * Returns a list of descriptors for this characteristic.
    478      *
    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      *
    489      * @return GATT descriptor object or null if no descriptor with the given UUID was found.
    490      */
    491     public BluetoothGattDescriptor getDescriptor(UUID uuid) {
    492         for (BluetoothGattDescriptor descriptor : mDescriptors) {
    493             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
    504      * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
    505      * 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      *
    508      * @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      *
    523      * @param formatType The format type used to interpret the characteristic value.
    524      * @param offset Offset at which the integer value can be found.
    525      * @return Cached value of the characteristic or null of offset exceeds value size.
    526      */
    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:
    535                 return unsignedBytesToInt(mValue[offset], mValue[offset + 1]);
    536 
    537             case FORMAT_UINT32:
    538                 return unsignedBytesToInt(mValue[offset], mValue[offset + 1],
    539                         mValue[offset + 2], mValue[offset + 3]);
    540             case FORMAT_SINT8:
    541                 return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8);
    542 
    543             case FORMAT_SINT16:
    544                 return unsignedToSigned(unsignedBytesToInt(mValue[offset],
    545                         mValue[offset + 1]), 16);
    546 
    547             case FORMAT_SINT32:
    548                 return unsignedToSigned(unsignedBytesToInt(mValue[offset],
    549                         mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32);
    550         }
    551 
    552         return null;
    553     }
    554 
    555     /**
    556      * Return the stored value of this characteristic.
    557      * <p>See {@link #getValue} for details.
    558      *
    559      * @param formatType The format type used to interpret the characteristic value.
    560      * @param offset Offset at which the float value can be found.
    561      * @return Cached value of the characteristic at a given offset or null if the requested offset
    562      * exceeds the value size.
    563      */
    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:
    569                 return bytesToFloat(mValue[offset], mValue[offset + 1]);
    570 
    571             case FORMAT_FLOAT:
    572                 return bytesToFloat(mValue[offset], mValue[offset + 1],
    573                         mValue[offset + 2], mValue[offset + 3]);
    574         }
    575 
    576         return null;
    577     }
    578 
    579     /**
    580      * Return the stored value of this characteristic.
    581      * <p>See {@link #getValue} for details.
    582      *
    583      * @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) {
    587         if (mValue == null || offset > mValue.length) return null;
    588         byte[] strBytes = new byte[mValue.length - offset];
    589         for (int i = 0; i != (mValue.length - offset); ++i) strBytes[i] = mValue[offset + i];
    590         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      *
    601      * @param value New value for this characteristic
    602      * @return true if the locally stored value has been set, false if the requested value could not
    603      * be stored locally.
    604      */
    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.
    613      *
    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:
    629                 mValue[offset] = (byte) (value & 0xFF);
    630                 break;
    631 
    632             case FORMAT_SINT16:
    633                 value = intToSignedBits(value, 16);
    634                 // Fall-through intended
    635             case FORMAT_UINT16:
    636                 mValue[offset++] = (byte) (value & 0xFF);
    637                 mValue[offset] = (byte) ((value >> 8) & 0xFF);
    638                 break;
    639 
    640             case FORMAT_SINT32:
    641                 value = intToSignedBits(value, 32);
    642                 // Fall-through intended
    643             case FORMAT_UINT32:
    644                 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);
    648                 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.
    659      *
    660      * @param mantissa Mantissa for this characteristic
    661      * @param exponent exponent value for this characteristic
    662      * @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);
    675                 mValue[offset++] = (byte) (mantissa & 0xFF);
    676                 mValue[offset] = (byte) ((mantissa >> 8) & 0x0F);
    677                 mValue[offset] += (byte) ((exponent & 0x0F) << 4);
    678                 break;
    679 
    680             case FORMAT_FLOAT:
    681                 mantissa = intToSignedBits(mantissa, 24);
    682                 exponent = intToSignedBits(exponent, 8);
    683                 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);
    687                 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.
    699      *
    700      * @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.
    710      */
    711     private int getTypeLen(int formatType) {
    712         return formatType & 0xF;
    713     }
    714 
    715     /**
    716      * Convert a signed byte to an unsigned int.
    717      */
    718     private int unsignedByteToInt(byte b) {
    719         return b & 0xFF;
    720     }
    721 
    722     /**
    723      * Convert signed bytes to a 16-bit unsigned int.
    724      */
    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.
    731      */
    732     private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
    733         return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
    734                 + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24);
    735     }
    736 
    737     /**
    738      * Convert signed bytes to a 16-bit short float value.
    739      */
    740     private float bytesToFloat(byte b0, byte b1) {
    741         int mantissa = unsignedToSigned(unsignedByteToInt(b0)
    742                 + ((unsignedByteToInt(b1) & 0x0F) << 8), 12);
    743         int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4);
    744         return (float) (mantissa * Math.pow(10, exponent));
    745     }
    746 
    747     /**
    748      * Convert signed bytes to a 32-bit short float value.
    749      */
    750     private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
    751         int mantissa = unsignedToSigned(unsignedByteToInt(b0)
    752                 + (unsignedByteToInt(b1) << 8)
    753                 + (unsignedByteToInt(b2) << 16), 24);
    754         return (float) (mantissa * Math.pow(10, b3));
    755     }
    756 
    757     /**
    758      * Convert an unsigned integer value to a two's-complement encoded
    759      * signed value.
    760      */
    761     private int unsignedToSigned(int unsigned, int size) {
    762         if ((unsigned & (1 << size - 1)) != 0) {
    763             unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
    764         }
    765         return unsigned;
    766     }
    767 
    768     /**
    769      * Convert an integer into the signed bits of a given length.
    770      */
    771     private int intToSignedBits(int i, int size) {
    772         if (i < 0) {
    773             i = (1 << size - 1) + (i & ((1 << size - 1) - 1));
    774         }
    775         return i;
    776     }
    777 }
    778