@Override public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { if (data.size() < 2) { onInvalidDataReceived(device, data); return; } // Read flags int offset = 0; final int flags = data.getIntValue(Data.FORMAT_UINT8, offset); final int hearRateType = (flags & 0x01) == 0 ? Data.FORMAT_UINT8 : Data.FORMAT_UINT16; offset += 1; // Validate packet length. The type's lower nibble is its length. if (data.size() < 1 + (hearRateType & 0x0F)) { onInvalidDataReceived(device, data); return; } final int value = data.getIntValue(hearRateType, offset); // offset += hearRateType & 0xF; // ... // Report the parsed value(s) onSampleValueReceived(device, value); } }
public static String parse(final Data data) { int offset = 0; final int flags = data.getValue()[offset]; // 1 byte offset += 1; final boolean walking = !running; final float instantaneousSpeed = (float) data.getIntValue(Data.FORMAT_UINT16, offset) / 256.0f; // 1/256 m/s offset += 2; final int instantaneousCadence = data.getIntValue(Data.FORMAT_UINT8, offset); offset += 1; instantaneousStrideLength = (float) data.getIntValue(Data.FORMAT_UINT16, offset) / 100.0f; // 1/100 m offset += 2; totalDistance = (float) data.getIntValue(Data.FORMAT_UINT32, offset) / 10.0f;
@Override public Data createFromParcel(final Parcel in) { return new Data(in); }
/** * Returns a long value from the byte array. * <p>Only {@link #FORMAT_UINT32} and {@link #FORMAT_SINT32} are supported. * <p>The formatType parameter determines how the value * is to be interpreted. For example, setting formatType to * {@link #FORMAT_UINT32} specifies that the first four bytes of the * value at the given offset are interpreted to generate the * return value. * * @param formatType The format type used to interpret the value. * @param offset Offset at which the integer value can be found. * @return Cached value or null of offset exceeds value size. */ @Nullable public Long getLongValue(@LongFormat final int formatType, @IntRange(from = 0) final int offset) { if ((offset + getTypeLen(formatType)) > size()) return null; switch (formatType) { case FORMAT_SINT32: return unsignedToSigned(unsignedBytesToLong(mValue[offset], mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32); case FORMAT_UINT32: return unsignedBytesToLong(mValue[offset], mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]); } return null; }
public Integer getIntValue(@IntFormat final int formatType, @IntRange(from = 0) final int offset) { if ((offset + getTypeLen(formatType)) > size()) return null; return unsignedByteToInt(mValue[offset]); return unsignedBytesToInt(mValue[offset], mValue[offset + 1]); return unsignedBytesToInt(mValue[offset], mValue[offset + 1], mValue[offset + 2], (byte) 0); return unsignedBytesToInt(mValue[offset], mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]); return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8); return unsignedToSigned(unsignedBytesToInt(mValue[offset], mValue[offset + 1]), 16); return unsignedToSigned(unsignedBytesToInt(mValue[offset], mValue[offset + 1], mValue[offset + 2], (byte) 0), 24); return unsignedToSigned(unsignedBytesToInt(mValue[offset], mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32);
public Float getFloatValue(@FloatFormat final int formatType, @IntRange(from = 0) final int offset) { if ((offset + getTypeLen(formatType)) > size()) return null; return Float.NEGATIVE_INFINITY; return bytesToFloat(mValue[offset], mValue[offset + 1]); return bytesToFloat(mValue[offset], mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]);
@Test public void getValue_UINT16() { final Data data = new Data(new byte[] {(byte) 0xD0, 0x67 }); final int value = data.getIntValue(Data.FORMAT_UINT16, 0); assertEquals(26576, value); }
final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); final float pressure = data.getFloatValue(Data.FORMAT_SFLOAT, offset); final String unit = unitType == 0 ? " mmHg" : " kPa"; offset += 6; final float pulseRate = data.getFloatValue(Data.FORMAT_SFLOAT, offset); offset += 2; builder.append("\nPulse: ").append(pulseRate).append(" bpm"); final int userId = data.getIntValue(Data.FORMAT_UINT8, offset); offset += 1; builder.append("\nUser ID: ").append(userId); final int status = data.getIntValue(Data.FORMAT_UINT16, offset);
/* package */static String parse(final Data data, final int offset) { final int type = data.getValue()[offset]; switch (type) { case 1: return "Armpit"; case 2: return "Body (general)"; case 3: return "Ear (usually ear lobe)"; case 4: return "Finger"; case 5: return "Gastro-intestinal Tract"; case 6: return "Mouth"; case 7: return "Rectum"; case 8: return "Toe"; case 9: return "Tympanum (ear drum)"; default: return "Unknown"; } } }
public static String parse(final Data data) { final int value = data.getIntValue(Data.FORMAT_UINT8, 0); switch (value) { case 6: return "Foot"; case 5: return "Ear Lobe"; case 4: return "Hand"; case 3: return "Finger"; case 2: return "Wrist"; case 1: return "Chest"; case 0: default: return "Other"; } } }
public static String parse(final Data data) { int offset = 0; final int flags = data.getByte(offset); // 1 byte offset += 1; int lastWheelEventTime = 0; if (wheelRevPresent) { wheelRevolutions = data.getIntValue(Data.FORMAT_UINT32, offset); offset += 4; lastWheelEventTime = data.getIntValue(Data.FORMAT_UINT16, offset); // 1/1024 s offset += 2; int lastCrankEventTime = 0; if (crankRevPreset) { crankRevolutions = data.getIntValue(Data.FORMAT_UINT16, offset); offset += 2; lastCrankEventTime = data.getIntValue(Data.FORMAT_UINT16, offset);
@Test public void getValue_UINT32_big() { final Data data = new Data(new byte[] { 0x01, 0x00, 0x00, (byte) 0xF0}); final long value = data.getLongValue(Data.FORMAT_UINT32, 0); assertEquals(0xF0000001L, value); } }
/** * This method will write important data to the device. * * @param parameter parameter to be written. */ void performAction(final String parameter) { log(Log.VERBOSE, "Changing device name to \"" + parameter + "\""); // Write some data to the characteristic. writeCharacteristic(mDeviceNameCharacteristic, Data.from(parameter)) // If data are longer than MTU-3, they will be chunked into multiple packets. // Check out other split options, with .split(...). .split() // Callback called when data were sent, or added to outgoing queue in case // Write Without Request type was used. .with((device, data) -> log(Log.DEBUG, data.size() + " bytes were sent")) // Callback called when data were sent, or added to outgoing queue in case // Write Without Request type was used. This is called after .with(...) callback. .done(device -> log(LogContract.Log.Level.APPLICATION, "Device name set to \"" + parameter + "\"")) // Callback called when write has failed. .fail((device, status) -> log(Log.WARN, "Failed to change device name")) .enqueue(); } }
@Override public String toString() { if (size() == 0) return ""; final char[] out = new char[mValue.length * 3 - 1]; for (int j = 0; j < mValue.length; j++) { int v = mValue[j] & 0xFF; out[j * 3] = HEX_ARRAY[v >>> 4]; out[j * 3 + 1] = HEX_ARRAY[v & 0x0F]; if (j != mValue.length - 1) out[j * 3 + 2] = '-'; } return "(0x) " + new String(out); }
public static String parse(final BluetoothGattCharacteristic characteristic) { return parse(Data.from(characteristic)); }
@Test public void getValue_UINT24() { final Data data = new Data(new byte[] { 0x03, 0x02, 0x01}); final int value = data.getIntValue(Data.FORMAT_UINT24, 0); assertEquals(0x010203, value); }
final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); final float systolic = data.getFloatValue(Data.FORMAT_SFLOAT, offset); final float diastolic = data.getFloatValue(Data.FORMAT_SFLOAT, offset + 2); final float meanArterialPressure = data.getFloatValue(Data.FORMAT_SFLOAT, offset + 4); final String unit = unitType == 0 ? " mmHg" : " kPa"; offset += 6; final float pulseRate = data.getFloatValue(Data.FORMAT_SFLOAT, offset); offset += 2; builder.append("\nPulse: ").append(pulseRate).append(" bpm"); final int userId = data.getIntValue(Data.FORMAT_UINT8, offset); offset += 1; builder.append("\nUser ID: ").append(userId); final int status = data.getIntValue(Data.FORMAT_UINT16, offset);
public static String parse(final Data data) { // The CGM Measurement characteristic is a variable length structure containing one or more CGM Measurement records int totalSize = data.getValue().length; final StringBuilder builder = new StringBuilder(); int offset = 0; while (offset < totalSize) { offset += parseRecord(builder, data, offset); if (offset < totalSize) builder.append("\n\n"); } return builder.toString(); }
/** * Parses the alert level. * * @param data * @return alert level in human readable format */ public static String parse(final Data data) { final int value = data.getIntValue(Data.FORMAT_UINT8, 0); switch (value) { case 0: return "No Alert"; case 1: return "Mild Alert"; case 2: return "High Alert"; default: return "Reserved value (" + value + ")"; } } }
/** * Returns a byte at the given offset from the byte array. * * @param offset Offset at which the byte value can be found. * @return Cached value or null of offset exceeds value size. */ @Nullable public Byte getByte(@IntRange(from = 0) final int offset) { if (offset + 1 > size()) return null; return mValue[offset]; }