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