| /* | |
| * Copyright (C) 2013 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package android.bluetooth; | |
| import android.annotation.Hide; | |
| import android.annotation.IntDef; | |
| import android.annotation.NonNull; | |
| import android.annotation.RequiresNoPermission; | |
| import android.compat.annotation.UnsupportedAppUsage; | |
| import android.os.Parcel; | |
| import android.os.ParcelUuid; | |
| import android.os.Parcelable; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.UUID; | |
| /** | |
| * Represents a Bluetooth GATT Characteristic | |
| * | |
| * <p>A GATT characteristic is a basic data element used to construct a GATT service, {@link | |
| * BluetoothGattService}. The characteristic contains a value as well as additional information and | |
| * optional GATT descriptors, {@link BluetoothGattDescriptor}. | |
| */ | |
| public class BluetoothGattCharacteristic implements Parcelable { | |
| /** Characteristic property: Characteristic is broadcastable. */ | |
| public static final int PROPERTY_BROADCAST = 0x01; | |
| /** Characteristic property: Characteristic is readable. */ | |
| public static final int PROPERTY_READ = 0x02; | |
| /** Characteristic property: Characteristic can be written without response. */ | |
| public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04; | |
| /** Characteristic property: Characteristic can be written. */ | |
| public static final int PROPERTY_WRITE = 0x08; | |
| /** Characteristic property: Characteristic supports notification */ | |
| public static final int PROPERTY_NOTIFY = 0x10; | |
| /** Characteristic property: Characteristic supports indication */ | |
| public static final int PROPERTY_INDICATE = 0x20; | |
| /** Characteristic property: Characteristic supports write with signature */ | |
| public static final int PROPERTY_SIGNED_WRITE = 0x40; | |
| /** Characteristic property: Characteristic has extended properties */ | |
| public static final int PROPERTY_EXTENDED_PROPS = 0x80; | |
| /** Characteristic read permission */ | |
| public static final int PERMISSION_READ = 0x01; | |
| /** Characteristic permission: Allow encrypted read operations */ | |
| public static final int PERMISSION_READ_ENCRYPTED = 0x02; | |
| /** Characteristic permission: Allow reading with person-in-the-middle protection */ | |
| public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04; | |
| /** Characteristic write permission */ | |
| public static final int PERMISSION_WRITE = 0x10; | |
| /** Characteristic permission: Allow encrypted writes */ | |
| public static final int PERMISSION_WRITE_ENCRYPTED = 0x20; | |
| /** Characteristic permission: Allow encrypted writes with person-in-the-middle protection */ | |
| public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40; | |
| /** Characteristic permission: Allow signed write operations */ | |
| public static final int PERMISSION_WRITE_SIGNED = 0x80; | |
| /** | |
| * Characteristic permission: Allow signed write operations with person-in-the-middle protection | |
| */ | |
| public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100; | |
| @Hide | |
| @Retention(RetentionPolicy.SOURCE) | |
| @IntDef( | |
| prefix = "WRITE_TYPE_", | |
| value = {WRITE_TYPE_DEFAULT, WRITE_TYPE_NO_RESPONSE, WRITE_TYPE_SIGNED}) | |
| public @interface WriteType {} | |
| /** Write characteristic, requesting acknowledgement by the remote device */ | |
| public static final int WRITE_TYPE_DEFAULT = 0x02; | |
| /** Write characteristic without requiring a response by the remote device */ | |
| public static final int WRITE_TYPE_NO_RESPONSE = 0x01; | |
| /** Write characteristic including authentication signature */ | |
| public static final int WRITE_TYPE_SIGNED = 0x04; | |
| /** Characteristic value format type uint8 */ | |
| public static final int FORMAT_UINT8 = 0x11; | |
| /** Characteristic value format type uint16 */ | |
| public static final int FORMAT_UINT16 = 0x12; | |
| /** Characteristic value format type uint32 */ | |
| public static final int FORMAT_UINT32 = 0x14; | |
| /** Characteristic value format type sint8 */ | |
| public static final int FORMAT_SINT8 = 0x21; | |
| /** Characteristic value format type sint16 */ | |
| public static final int FORMAT_SINT16 = 0x22; | |
| /** Characteristic value format type sint32 */ | |
| public static final int FORMAT_SINT32 = 0x24; | |
| /** Characteristic value format type sfloat (16-bit float) */ | |
| public static final int FORMAT_SFLOAT = 0x32; | |
| /** Characteristic value format type float (32-bit float) */ | |
| public static final int FORMAT_FLOAT = 0x34; | |
| /** The UUID of this characteristic. */ | |
| @Hide protected UUID mUuid; | |
| /** Instance ID for this characteristic. */ | |
| @Hide @UnsupportedAppUsage protected int mInstance; | |
| /** Characteristic properties. */ | |
| @Hide protected int mProperties; | |
| /** Characteristic permissions. */ | |
| @Hide protected int mPermissions; | |
| /** Key size (default = 16). */ | |
| @Hide protected int mKeySize = 16; | |
| /** Write type for this characteristic. */ | |
| @Hide protected @WriteType int mWriteType; | |
| /** Back-reference to the service this characteristic belongs to. */ | |
| @Hide @UnsupportedAppUsage protected BluetoothGattService mService; | |
| /** The cached value of this characteristic. */ | |
| @Hide protected byte[] mValue; | |
| /** List of descriptors included in this characteristic. */ | |
| protected List<BluetoothGattDescriptor> mDescriptors; | |
| /** | |
| * Create a new BluetoothGattCharacteristic. | |
| * | |
| * @param uuid The UUID for this characteristic | |
| * @param properties Properties of this characteristic | |
| * @param permissions Permissions for this characteristic | |
| */ | |
| public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) { | |
| initCharacteristic(null, uuid, 0, properties, permissions); | |
| } | |
| /** Create a new BluetoothGattCharacteristic */ | |
| @Hide | |
| /*package*/ BluetoothGattCharacteristic( | |
| BluetoothGattService service, | |
| UUID uuid, | |
| int instanceId, | |
| int properties, | |
| int permissions) { | |
| initCharacteristic(service, uuid, instanceId, properties, permissions); | |
| } | |
| /** Create a new BluetoothGattCharacteristic */ | |
| @Hide | |
| public BluetoothGattCharacteristic(UUID uuid, int instanceId, int properties, int permissions) { | |
| initCharacteristic(null, uuid, instanceId, properties, permissions); | |
| } | |
| private void initCharacteristic( | |
| BluetoothGattService service, | |
| UUID uuid, | |
| int instanceId, | |
| int properties, | |
| int permissions) { | |
| mUuid = uuid; | |
| mInstance = instanceId; | |
| mProperties = properties; | |
| mPermissions = permissions; | |
| mService = service; | |
| mValue = null; | |
| mDescriptors = new ArrayList<>(); | |
| if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) { | |
| mWriteType = WRITE_TYPE_NO_RESPONSE; | |
| } else { | |
| mWriteType = WRITE_TYPE_DEFAULT; | |
| } | |
| } | |
| @Override | |
| public int describeContents() { | |
| return 0; | |
| } | |
| @Override | |
| public void writeToParcel(Parcel out, int flags) { | |
| (new ParcelUuid(mUuid)).writeToParcel(out, flags); | |
| out.writeInt(mInstance); | |
| out.writeInt(mProperties); | |
| out.writeInt(mPermissions); | |
| out.writeInt(mKeySize); | |
| out.writeInt(mWriteType); | |
| out.writeTypedList(mDescriptors); | |
| } | |
| public static final @NonNull Creator<BluetoothGattCharacteristic> CREATOR = | |
| new Creator<>() { | |
| public BluetoothGattCharacteristic createFromParcel(Parcel in) { | |
| return new BluetoothGattCharacteristic(in); | |
| } | |
| public BluetoothGattCharacteristic[] newArray(int size) { | |
| return new BluetoothGattCharacteristic[size]; | |
| } | |
| }; | |
| private BluetoothGattCharacteristic(Parcel in) { | |
| mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid(); | |
| mInstance = in.readInt(); | |
| mProperties = in.readInt(); | |
| mPermissions = in.readInt(); | |
| mKeySize = in.readInt(); | |
| mWriteType = in.readInt(); | |
| mDescriptors = in.createTypedArrayList(BluetoothGattDescriptor.CREATOR); | |
| for (BluetoothGattDescriptor desc : mDescriptors) { | |
| desc.setCharacteristic(this); | |
| } | |
| } | |
| /** Returns the desired key size. */ | |
| @Hide | |
| @RequiresNoPermission | |
| public int getKeySize() { | |
| return mKeySize; | |
| } | |
| /** | |
| * Adds a descriptor to this characteristic. | |
| * | |
| * @param descriptor Descriptor to be added to this characteristic. | |
| * @return true, if the descriptor was added to the characteristic | |
| */ | |
| @RequiresNoPermission | |
| public boolean addDescriptor(BluetoothGattDescriptor descriptor) { | |
| mDescriptors.add(descriptor); | |
| descriptor.setCharacteristic(this); | |
| return true; | |
| } | |
| /** Get a descriptor by UUID and instance id. */ | |
| @Hide | |
| /*package*/ BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) { | |
| for (BluetoothGattDescriptor descriptor : mDescriptors) { | |
| if (descriptor.getUuid().equals(uuid) && descriptor.getInstanceId() == instanceId) { | |
| return descriptor; | |
| } | |
| } | |
| return null; | |
| } | |
| /** | |
| * Returns the service this characteristic belongs to. | |
| * | |
| * @return The associated service | |
| */ | |
| @RequiresNoPermission | |
| public BluetoothGattService getService() { | |
| return mService; | |
| } | |
| /** Sets the service associated with this device. */ | |
| @Hide | |
| @UnsupportedAppUsage | |
| /*package*/ void setService(BluetoothGattService service) { | |
| mService = service; | |
| } | |
| /** | |
| * Returns the UUID of this characteristic | |
| * | |
| * @return UUID of this characteristic | |
| */ | |
| @RequiresNoPermission | |
| public UUID getUuid() { | |
| return mUuid; | |
| } | |
| /** | |
| * Returns the instance ID for this characteristic. | |
| * | |
| * <p>If a remote device offers multiple characteristics with the same UUID, the instance ID is | |
| * used to distinguish between characteristics. | |
| * | |
| * @return Instance ID of this characteristic | |
| */ | |
| @RequiresNoPermission | |
| public int getInstanceId() { | |
| return mInstance; | |
| } | |
| /** Force the instance ID. */ | |
| @Hide | |
| @RequiresNoPermission | |
| public void setInstanceId(int instanceId) { | |
| mInstance = instanceId; | |
| } | |
| /** | |
| * Returns the properties of this characteristic. | |
| * | |
| * <p>The properties contain a bit mask of property flags indicating the features of this | |
| * characteristic. | |
| * | |
| * @return Properties of this characteristic | |
| */ | |
| @RequiresNoPermission | |
| public int getProperties() { | |
| return mProperties; | |
| } | |
| /** | |
| * Returns the permissions for this characteristic. | |
| * | |
| * @return Permissions of this characteristic | |
| */ | |
| @RequiresNoPermission | |
| public int getPermissions() { | |
| return mPermissions; | |
| } | |
| /** | |
| * Gets the write type for this characteristic. | |
| * | |
| * @return Write type for this characteristic | |
| */ | |
| @RequiresNoPermission | |
| public @WriteType int getWriteType() { | |
| return mWriteType; | |
| } | |
| /** | |
| * Set the write type for this characteristic | |
| * | |
| * <p>Setting the write type of a characteristic determines how the {@link | |
| * BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} function write | |
| * this characteristic. | |
| * | |
| * @param writeType The write type to for this characteristic. | |
| */ | |
| @RequiresNoPermission | |
| public void setWriteType(@WriteType int writeType) { | |
| mWriteType = writeType; | |
| } | |
| /** Set the desired key size. */ | |
| @Hide | |
| @UnsupportedAppUsage | |
| @RequiresNoPermission | |
| public void setKeySize(int keySize) { | |
| mKeySize = keySize; | |
| } | |
| /** | |
| * Returns a list of descriptors for this characteristic. | |
| * | |
| * @return Descriptors for this characteristic | |
| */ | |
| @RequiresNoPermission | |
| public List<BluetoothGattDescriptor> getDescriptors() { | |
| return mDescriptors; | |
| } | |
| /** | |
| * Returns a descriptor with a given UUID out of the list of descriptors for this | |
| * characteristic. | |
| * | |
| * @return GATT descriptor object or null if no descriptor with the given UUID was found. | |
| */ | |
| @RequiresNoPermission | |
| public BluetoothGattDescriptor getDescriptor(UUID uuid) { | |
| for (BluetoothGattDescriptor descriptor : mDescriptors) { | |
| if (descriptor.getUuid().equals(uuid)) { | |
| return descriptor; | |
| } | |
| } | |
| return null; | |
| } | |
| /** | |
| * Get the stored value for this characteristic. | |
| * | |
| * <p>This function returns the stored value for this characteristic as retrieved by calling | |
| * {@link BluetoothGatt#readCharacteristic}. The cached value of the characteristic is updated | |
| * as a result of a read characteristic operation or if a characteristic update notification has | |
| * been received. | |
| * | |
| * @return Cached value of the characteristic | |
| * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} instead | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public byte[] getValue() { | |
| return mValue; | |
| } | |
| /** | |
| * Return the stored value of this characteristic. | |
| * | |
| * <p>The formatType parameter determines how the characteristic value is to be interpreted. For | |
| * example, setting formatType to {@link #FORMAT_UINT16} specifies that the first two bytes of | |
| * the characteristic value at the given offset are interpreted to generate the return value. | |
| * | |
| * @param formatType The format type used to interpret the characteristic value. | |
| * @param offset Offset at which the integer value can be found. | |
| * @return Cached value of the characteristic or null of offset exceeds value size. | |
| * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get | |
| * the characteristic value | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public Integer getIntValue(int formatType, int offset) { | |
| if ((offset + getTypeLen(formatType)) > mValue.length) { | |
| return null; | |
| } | |
| return switch (formatType) { | |
| case FORMAT_UINT8 -> unsignedByteToInt(mValue[offset]); | |
| case FORMAT_UINT16 -> unsignedBytesToInt(mValue[offset], mValue[offset + 1]); | |
| case FORMAT_UINT32 -> | |
| unsignedBytesToInt( | |
| mValue[offset], | |
| mValue[offset + 1], | |
| mValue[offset + 2], | |
| mValue[offset + 3]); | |
| case FORMAT_SINT8 -> unsignedToSigned(unsignedByteToInt(mValue[offset]), 8); | |
| case FORMAT_SINT16 -> | |
| unsignedToSigned(unsignedBytesToInt(mValue[offset], mValue[offset + 1]), 16); | |
| case FORMAT_SINT32 -> | |
| unsignedToSigned( | |
| unsignedBytesToInt( | |
| mValue[offset], | |
| mValue[offset + 1], | |
| mValue[offset + 2], | |
| mValue[offset + 3]), | |
| 32); | |
| default -> null; | |
| }; | |
| } | |
| /** | |
| * Return the stored value of this characteristic. | |
| * | |
| * <p>See {@link #getValue} for details. | |
| * | |
| * @param formatType The format type used to interpret the characteristic value. | |
| * @param offset Offset at which the float value can be found. | |
| * @return Cached value of the characteristic at a given offset or null if the requested offset | |
| * exceeds the value size. | |
| * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get | |
| * the characteristic value | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public Float getFloatValue(int formatType, int offset) { | |
| if ((offset + getTypeLen(formatType)) > mValue.length) { | |
| return null; | |
| } | |
| return switch (formatType) { | |
| case FORMAT_SFLOAT -> bytesToFloat(mValue[offset], mValue[offset + 1]); | |
| case FORMAT_FLOAT -> | |
| bytesToFloat( | |
| mValue[offset], | |
| mValue[offset + 1], | |
| mValue[offset + 2], | |
| mValue[offset + 3]); | |
| default -> null; | |
| }; | |
| } | |
| /** | |
| * Return the stored value of this characteristic. | |
| * | |
| * <p>See {@link #getValue} for details. | |
| * | |
| * @param offset Offset at which the string value can be found. | |
| * @return Cached value of the characteristic | |
| * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get | |
| * the characteristic value | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public String getStringValue(int offset) { | |
| if (mValue == null || offset > mValue.length) return null; | |
| byte[] strBytes = new byte[mValue.length - offset]; | |
| for (int i = 0; i != (mValue.length - offset); ++i) strBytes[i] = mValue[offset + i]; | |
| return new String(strBytes); | |
| } | |
| /** | |
| * Updates the locally stored value of this characteristic. | |
| * | |
| * <p>This function modifies the locally stored cached value of this characteristic. To send the | |
| * value to the remote device, call {@link BluetoothGatt#writeCharacteristic} to send the value | |
| * to the remote device. | |
| * | |
| * @param value New value for this characteristic | |
| * @return true if the locally stored value has been set, false if the requested value could not | |
| * be stored locally. | |
| * @deprecated Pass the characteristic value directly into {@link | |
| * BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public boolean setValue(byte[] value) { | |
| mValue = value; | |
| return true; | |
| } | |
| /** | |
| * Set the locally stored value of this characteristic. | |
| * | |
| * <p>See {@link #setValue(byte[])} for details. | |
| * | |
| * @param value New value for this characteristic | |
| * @param formatType Integer format type used to transform the value parameter | |
| * @param offset Offset at which the value should be placed | |
| * @return true if the locally stored value has been set | |
| * @deprecated Pass the characteristic value directly into {@link | |
| * BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public boolean setValue(int value, int formatType, int offset) { | |
| int len = offset + getTypeLen(formatType); | |
| if (mValue == null) mValue = new byte[len]; | |
| if (len > mValue.length) return false; | |
| switch (formatType) { | |
| case FORMAT_SINT8: | |
| value = intToSignedBits(value, 8); | |
| // Fall-through intended | |
| case FORMAT_UINT8: | |
| mValue[offset] = (byte) (value & 0xFF); | |
| break; | |
| case FORMAT_SINT16: | |
| value = intToSignedBits(value, 16); | |
| // Fall-through intended | |
| case FORMAT_UINT16: | |
| mValue[offset++] = (byte) (value & 0xFF); | |
| mValue[offset] = (byte) ((value >> 8) & 0xFF); | |
| break; | |
| case FORMAT_SINT32: | |
| value = intToSignedBits(value, 32); | |
| // Fall-through intended | |
| case FORMAT_UINT32: | |
| mValue[offset++] = (byte) (value & 0xFF); | |
| mValue[offset++] = (byte) ((value >> 8) & 0xFF); | |
| mValue[offset++] = (byte) ((value >> 16) & 0xFF); | |
| mValue[offset] = (byte) ((value >> 24) & 0xFF); | |
| break; | |
| default: | |
| return false; | |
| } | |
| return true; | |
| } | |
| /** | |
| * Set the locally stored value of this characteristic. | |
| * | |
| * <p>See {@link #setValue(byte[])} for details. | |
| * | |
| * @param mantissa Mantissa for this characteristic | |
| * @param exponent exponent value for this characteristic | |
| * @param formatType Float format type used to transform the value parameter | |
| * @param offset Offset at which the value should be placed | |
| * @return true if the locally stored value has been set | |
| * @deprecated Pass the characteristic value directly into {@link | |
| * BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public boolean setValue(int mantissa, int exponent, int formatType, int offset) { | |
| int len = offset + getTypeLen(formatType); | |
| if (mValue == null) mValue = new byte[len]; | |
| if (len > mValue.length) return false; | |
| switch (formatType) { | |
| case FORMAT_SFLOAT -> { | |
| mantissa = intToSignedBits(mantissa, 12); | |
| exponent = intToSignedBits(exponent, 4); | |
| mValue[offset++] = (byte) (mantissa & 0xFF); | |
| mValue[offset] = (byte) ((mantissa >> 8) & 0x0F); | |
| mValue[offset] += (byte) ((exponent & 0x0F) << 4); | |
| } | |
| case FORMAT_FLOAT -> { | |
| mantissa = intToSignedBits(mantissa, 24); | |
| exponent = intToSignedBits(exponent, 8); | |
| mValue[offset++] = (byte) (mantissa & 0xFF); | |
| mValue[offset++] = (byte) ((mantissa >> 8) & 0xFF); | |
| mValue[offset++] = (byte) ((mantissa >> 16) & 0xFF); | |
| mValue[offset] += (byte) (exponent & 0xFF); | |
| } | |
| default -> { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /** | |
| * Set the locally stored value of this characteristic. | |
| * | |
| * <p>See {@link #setValue(byte[])} for details. | |
| * | |
| * @param value New value for this characteristic | |
| * @return true if the locally stored value has been set | |
| * @deprecated Pass the characteristic value directly into {@link | |
| * BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} | |
| */ | |
| @Deprecated | |
| @RequiresNoPermission | |
| public boolean setValue(String value) { | |
| mValue = value.getBytes(); | |
| return true; | |
| } | |
| /** Returns the size of a give value type. */ | |
| private static int getTypeLen(int formatType) { | |
| return formatType & 0xF; | |
| } | |
| /** Convert a signed byte to an unsigned int. */ | |
| private static int unsignedByteToInt(byte b) { | |
| return b & 0xFF; | |
| } | |
| /** Convert signed bytes to a 16-bit unsigned int. */ | |
| private static int unsignedBytesToInt(byte b0, byte b1) { | |
| return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)); | |
| } | |
| /** Convert signed bytes to a 32-bit unsigned int. */ | |
| private static int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) { | |
| return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)) | |
| + (unsignedByteToInt(b2) << 16) | |
| + (unsignedByteToInt(b3) << 24); | |
| } | |
| /** Convert signed bytes to a 16-bit short float value. */ | |
| private static float bytesToFloat(byte b0, byte b1) { | |
| int mantissa = | |
| unsignedToSigned(unsignedByteToInt(b0) + ((unsignedByteToInt(b1) & 0x0F) << 8), 12); | |
| int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4); | |
| return (float) (mantissa * Math.pow(10, exponent)); | |
| } | |
| /** Convert signed bytes to a 32-bit short float value. */ | |
| private static float bytesToFloat(byte b0, byte b1, byte b2, byte b3) { | |
| int mantissa = | |
| unsignedToSigned( | |
| unsignedByteToInt(b0) | |
| + (unsignedByteToInt(b1) << 8) | |
| + (unsignedByteToInt(b2) << 16), | |
| 24); | |
| return (float) (mantissa * Math.pow(10, b3)); | |
| } | |
| /** Convert an unsigned integer value to a two's-complement encoded signed value. */ | |
| private static int unsignedToSigned(int unsigned, int size) { | |
| if ((unsigned & (1 << (size - 1))) != 0) { | |
| unsigned = -1 * ((1 << (size - 1)) - (unsigned & ((1 << (size - 1)) - 1))); | |
| } | |
| return unsigned; | |
| } | |
| /** Convert an integer into the signed bits of a given length. */ | |
| private static int intToSignedBits(int i, int size) { | |
| if (i < 0) { | |
| i = (1 << (size - 1)) + (i & ((1 << (size - 1)) - 1)); | |
| } | |
| return i; | |
| } | |
| } |