diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java index 01a314fc..dcfb2ebc 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java @@ -43,18 +43,19 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; /** - * HTSActivity is the main Health Thermometer activity. It implements {@link HTSManagerCallbacks} to receive callbacks from {@link HTSManager} class. The activity supports portrait and landscape + * HTSActivity is the main Health Thermometer activity. It implements {@link HTSManagerCallbacks} + * to receive callbacks from {@link HTSManager} class. The activity supports portrait and landscape * orientations. */ -public class HTSActivity extends BleProfileServiceReadyActivity { +public class HTSActivity extends BleProfileServiceReadyActivity { @SuppressWarnings("unused") private final String TAG = "HTSActivity"; private static final String VALUE = "value"; - private static final DecimalFormat mFormattedTemp = new DecimalFormat("#0.00"); - private TextView mHTSValue; - private TextView mHTSUnit; - private Double mValueC; + private TextView mTempValue; + private TextView mUnit; + private TextView mBatteryLevelView; + private Float mValueC; @Override protected void onCreateView(final Bundle savedInstanceState) { @@ -76,7 +77,7 @@ public class HTSActivity extends BleProfileServiceReadyActivity { +public class HTSManager extends BatteryManager { private static final String TAG = "HTSManager"; /** Health Thermometer service UUID */ @@ -51,32 +54,39 @@ public class HTSManager extends BleManager { private BluetoothGattCharacteristic mHTCharacteristic; - private final static int HIDE_MSB_8BITS_OUT_OF_32BITS = 0x00FFFFFF; - private final static int HIDE_MSB_8BITS_OUT_OF_16BITS = 0x00FF; - private final static int SHIFT_LEFT_8BITS = 8; - private final static int SHIFT_LEFT_16BITS = 16; - private final static int GET_BIT24 = 0x00400000; - private final static int FIRST_BIT_MASK = 0x01; - - public HTSManager(final Context context) { + HTSManager(final Context context) { super(context); } + @NonNull @Override - protected BleManagerGattCallback getGattCallback() { + protected BatteryManagerGattCallback getGattCallback() { return mGattCallback; } /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc. */ - private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() { - + private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { @Override - protected Deque initGatt(@NonNull final BluetoothGatt gatt) { - final LinkedList requests = new LinkedList<>(); - requests.add(Request.newEnableIndicationsRequest(mHTCharacteristic)); - return requests; + protected void initialize() { + super.initialize(); + setIndicationCallback(mHTCharacteristic) + .with(new TemperatureMeasurementDataCallback() { + @Override + public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(LogContract.Log.Level.APPLICATION, "\"" + TemperatureMeasurementParser.parse(data) + "\" received"); + super.onDataReceived(device, data); + } + + @Override + public void onTemperatureMeasurementReceived(final float temperature, final int unit, + @Nullable final Calendar calendar, + @Nullable final Integer type) { + mCallbacks.onTemperatureMeasurementReceived(temperature, unit, calendar, type); + } + }); + enableIndications(mHTCharacteristic); } @Override @@ -90,60 +100,8 @@ public class HTSManager extends BleManager { @Override protected void onDeviceDisconnected() { + super.onDeviceDisconnected(); mHTCharacteristic = null; } - - @Override - public void onCharacteristicIndicated(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) { - log(LogContract.Log.Level.APPLICATION, "\"" + TemperatureMeasurementParser.parse(characteristic) + "\" received"); - - try { - final double tempValue = decodeTemperature(characteristic.getValue()); - mCallbacks.onHTValueReceived(gatt.getDevice(), tempValue); - } catch (Exception e) { - DebugLogger.e(TAG, "Invalid temperature value", e); - } - } }; - - /** - * This method decode temperature value received from Health Thermometer device First byte {0} of data is flag and first bit of flag shows unit information of temperature. if bit 0 has value 1 - * then unit is Fahrenheit and Celsius otherwise Four bytes {1 to 4} after Flag bytes represent the temperature value in IEEE-11073 32-bit Float format - */ - private double decodeTemperature(byte[] data) throws Exception { - double temperatureValue; - byte flag = data[0]; - byte exponential = data[4]; - short firstOctet = convertNegativeByteToPositiveShort(data[1]); - short secondOctet = convertNegativeByteToPositiveShort(data[2]); - short thirdOctet = convertNegativeByteToPositiveShort(data[3]); - int mantissa = ((thirdOctet << SHIFT_LEFT_16BITS) | (secondOctet << SHIFT_LEFT_8BITS) | (firstOctet)) & HIDE_MSB_8BITS_OUT_OF_32BITS; - mantissa = getTwosComplimentOfNegativeMantissa(mantissa); - temperatureValue = (mantissa * Math.pow(10, exponential)); - - /* - * Conversion of temperature unit from Fahrenheit to Celsius if unit is in Fahrenheit - * Celsius = (Fahrenheit -32) 5/9 - */ - if ((flag & FIRST_BIT_MASK) != 0) { - temperatureValue = (float) ((temperatureValue - 32) * (5 / 9.0)); - } - return temperatureValue; - } - - private short convertNegativeByteToPositiveShort(byte octet) { - if (octet < 0) { - return (short) (octet & HIDE_MSB_8BITS_OUT_OF_16BITS); - } else { - return octet; - } - } - - private int getTwosComplimentOfNegativeMantissa(int mantissa) { - if ((mantissa & GET_BIT24) != 0) { - return ((((~mantissa) & HIDE_MSB_8BITS_OUT_OF_32BITS) + 1) * (-1)); - } else { - return mantissa; - } - } } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java index 6fdb6eb0..c8053b06 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java @@ -21,22 +21,13 @@ */ package no.nordicsemi.android.nrftoolbox.hts; -import android.bluetooth.BluetoothDevice; - -import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.ble.common.profile.ht.TemperatureMeasurementCallback; +import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; /** - * Interface {@link HTSManagerCallbacks} must be implemented by {@link HTSActivity} in order to receive callbacks from {@link HTSManager} + * Interface {@link HTSManagerCallbacks} must be implemented by {@link HTSActivity} in order + * to receive callbacks from {@link HTSManager}. */ -public interface HTSManagerCallbacks extends BleManagerCallbacks { - - /** - * Called when Health Thermometer value has been received - * - * @param device the bluetooth device from which the value was obtained - * @param value - * the new value - */ - void onHTValueReceived(final BluetoothDevice device, double value); +interface HTSManagerCallbacks extends BatteryManagerCallbacks, TemperatureMeasurementCallback { } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java index 830296a1..8a0de43c 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java @@ -30,20 +30,29 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.content.LocalBroadcastManager; +import java.util.Calendar; + import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.common.callback.ht.TemperatureMeasurementDataCallback; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +@SuppressWarnings("FieldCanBeLocal") public class HTSService extends BleProfileService implements HTSManagerCallbacks { public static final String BROADCAST_HTS_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.hts.BROADCAST_HTS_MEASUREMENT"; public static final String EXTRA_TEMPERATURE = "no.nordicsemi.android.nrftoolbox.hts.EXTRA_TEMPERATURE"; + public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; + public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; + private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.hts.ACTION_DISCONNECT"; private final static int NOTIFICATION_ID = 267; @@ -52,12 +61,12 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks private HTSManager mManager; - private final LocalBinder mBinder = new RSCBinder(); + private final LocalBinder mBinder = new HTSBinder(); /** * This local binder is an interface for the bonded activity to operate with the HTS sensor */ - public class RSCBinder extends LocalBinder { + class HTSBinder extends LocalBinder { // empty } @@ -102,10 +111,13 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks } @Override - public void onHTValueReceived(final BluetoothDevice device, final double value) { + public void onTemperatureMeasurementReceived(final float temperature, final int unit, + @Nullable final Calendar calendar, + @Nullable final Integer type) { final Intent broadcast = new Intent(BROADCAST_HTS_MEASUREMENT); - broadcast.putExtra(EXTRA_DEVICE, device); - broadcast.putExtra(EXTRA_TEMPERATURE, value); + broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); + broadcast.putExtra(EXTRA_TEMPERATURE, TemperatureMeasurementDataCallback.toCelsius(temperature, unit)); + // ignore the rest LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); if (!mBound) { @@ -114,6 +126,14 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks } } + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); + broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); + broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + /** * Creates the notification * diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java index 7c687334..4f963f75 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java @@ -21,37 +21,37 @@ */ package no.nordicsemi.android.nrftoolbox.parser; -import android.bluetooth.BluetoothGattCharacteristic; - import java.util.Calendar; import java.util.Locale; +import no.nordicsemi.android.ble.data.Data; + public class DateTimeParser { /** * Parses the date and time info. * - * @param characteristic + * @param data * @return time in human readable format */ - public static String parse(final BluetoothGattCharacteristic characteristic) { - return parse(characteristic, 0); + public static String parse(final Data data) { + return parse(data, 0); } /** * Parses the date and time info. This data has 7 bytes * - * @param characteristic + * @param data * @param offset * offset to start reading the time * @return time in human readable format */ - /* package */static String parse(final BluetoothGattCharacteristic characteristic, final int offset) { - final int year = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); - final int month = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2); - final int day = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 3); - final int hours = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 4); - final int minutes = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 5); - final int seconds = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 6); + /* package */static String parse(final Data data, final int offset) { + final int year = data.getIntValue(Data.FORMAT_UINT16, offset); + final int month = data.getIntValue(Data.FORMAT_UINT8, offset + 2); + final int day = data.getIntValue(Data.FORMAT_UINT8, offset + 3); + final int hours = data.getIntValue(Data.FORMAT_UINT8, offset + 4); + final int minutes = data.getIntValue(Data.FORMAT_UINT8, offset + 5); + final int seconds = data.getIntValue(Data.FORMAT_UINT8, offset + 6); final Calendar calendar = Calendar.getInstance(); calendar.set(year, month - 1, day, hours, minutes, seconds); diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java index 9ba0e5bc..2ddd58ad 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java @@ -21,18 +21,18 @@ */ package no.nordicsemi.android.nrftoolbox.parser; -import android.bluetooth.BluetoothGattCharacteristic; - import java.util.Locale; +import no.nordicsemi.android.ble.data.Data; + public class TemperatureMeasurementParser { private static final byte TEMPERATURE_UNIT_FLAG = 0x01; // 1 bit private static final byte TIMESTAMP_FLAG = 0x02; // 1 bits private static final byte TEMPERATURE_TYPE_FLAG = 0x04; // 1 bit - public static String parse(final BluetoothGattCharacteristic characteristic) { + public static String parse(final Data data) { int offset = 0; - final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++); + final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); /* * false Temperature is in Celsius degrees @@ -52,18 +52,18 @@ public class TemperatureMeasurementParser { */ final boolean temperatureTypeIncluded = (flags & TEMPERATURE_TYPE_FLAG) > 0; - final float tempValue = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_FLOAT, offset); + final float tempValue = data.getFloatValue(Data.FORMAT_FLOAT, offset); offset += 4; String dateTime = null; if (timestampIncluded) { - dateTime = DateTimeParser.parse(characteristic, offset); + dateTime = DateTimeParser.parse(data, offset); offset += 7; } String type = null; if (temperatureTypeIncluded) { - type = TemperatureTypeParser.parse(characteristic, offset); + type = TemperatureTypeParser.parse(data, offset); // offset++; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java index 5e287382..e29f81b1 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java @@ -21,16 +21,16 @@ */ package no.nordicsemi.android.nrftoolbox.parser; -import android.bluetooth.BluetoothGattCharacteristic; +import no.nordicsemi.android.ble.data.Data; public class TemperatureTypeParser { - public static String parse(final BluetoothGattCharacteristic characteristic) { - return parse(characteristic, 0); + public static String parse(final Data data) { + return parse(data, 0); } - /* package */static String parse(final BluetoothGattCharacteristic characteristic, final int offset) { - final int type = characteristic.getValue()[offset]; + /* package */static String parse(final Data data, final int offset) { + final int type = data.getValue()[offset]; switch (type) { case 1: diff --git a/app/src/main/res/values/strings_hts.xml b/app/src/main/res/values/strings_hts.xml index 13a66bec..83a1f72d 100644 --- a/app/src/main/res/values/strings_hts.xml +++ b/app/src/main/res/values/strings_hts.xml @@ -31,6 +31,7 @@ °C °F °K + %.2f Disconnect %s is connected.