RSC modified to use BLE Common lib

This commit is contained in:
Aleksander Nowakowski
2018-05-22 15:20:15 +02:00
parent 9bb5187332
commit 1caa9ba38d
5 changed files with 112 additions and 93 deletions

View File

@@ -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 RSCMeasurementParser {
private static final byte INSTANTANEOUS_STRIDE_LENGTH_PRESENT = 0x01; // 1 bit
private static final byte TOTAL_DISTANCE_PRESENT = 0x02; // 1 bit
private static final byte WALKING_OR_RUNNING_STATUS_BITS = 0x04; // 1 bit
public static String parse(final BluetoothGattCharacteristic characteristic) {
public static String parse(final Data data) {
int offset = 0;
final int flags = characteristic.getValue()[offset]; // 1 byte
final int flags = data.getValue()[offset]; // 1 byte
offset += 1;
final boolean islmPresent = (flags & INSTANTANEOUS_STRIDE_LENGTH_PRESENT) > 0;
@@ -40,21 +40,21 @@ public class RSCMeasurementParser {
final boolean running = (flags & WALKING_OR_RUNNING_STATUS_BITS) > 0;
final boolean walking = !running;
final float instantaneousSpeed = (float) characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset) / 256.0f; // 1/256 m/s
final float instantaneousSpeed = (float) data.getIntValue(Data.FORMAT_UINT16, offset) / 256.0f; // 1/256 m/s
offset += 2;
final int instantaneousCadence = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
final int instantaneousCadence = data.getIntValue(Data.FORMAT_UINT8, offset);
offset += 1;
float instantaneousStrideLength = 0;
if (islmPresent) {
instantaneousStrideLength = (float) characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset) / 100.0f; // 1/100 m
instantaneousStrideLength = (float) data.getIntValue(Data.FORMAT_UINT16, offset) / 100.0f; // 1/100 m
offset += 2;
}
float totalDistance = 0;
if (tdPreset) {
totalDistance = (float) characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset) / 10.0f;
totalDistance = (float) data.getIntValue(Data.FORMAT_UINT32, offset) / 10.0f;
// offset += 4;
}

View File

@@ -53,6 +53,7 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
private TextView mTotalDistanceUnitView;
private TextView mStridesCountView;
private TextView mActivityView;
private TextView mBatteryLevelView;
@Override
protected void onCreateView(final Bundle savedInstanceState) {
@@ -81,6 +82,7 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
mTotalDistanceUnitView = findViewById(R.id.total_distance_unit);
mStridesCountView = findViewById(R.id.strides);
mActivityView = findViewById(R.id.activity);
mBatteryLevelView = findViewById(R.id.battery);
}
@Override
@@ -97,6 +99,7 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
mTotalDistanceView.setText(R.string.not_available_value);
mStridesCountView.setText(R.string.not_available_value);
mActivityView.setText(R.string.not_available);
mBatteryLevelView.setText(R.string.not_available);
setUnits();
}
@@ -181,7 +184,13 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
// not used
}
private void onMeasurementReceived(float speed, int cadence, float totalDistance, final int activity) {
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
mBatteryLevelView.setText(R.string.not_available);
}
private void onMeasurementReceived(float speed, int cadence, long totalDistance, final boolean running) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT)));
@@ -190,7 +199,7 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
speed = speed * 3.6f;
// pass through intended
case SettingsFragment.SETTINGS_UNIT_M_S:
if (totalDistance == RSCManagerCallbacks.NOT_AVAILABLE) {
if (totalDistance == -1) {
mTotalDistanceView.setText(R.string.not_available);
mTotalDistanceUnitView.setText(null);
} else {
@@ -200,7 +209,7 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
break;
case SettingsFragment.SETTINGS_UNIT_MPH:
speed = speed * 2.2369f;
if (totalDistance == RSCManagerCallbacks.NOT_AVAILABLE) {
if (totalDistance == -1) {
mTotalDistanceView.setText(R.string.not_available);
mTotalDistanceUnitView.setText(null);
} else {
@@ -212,11 +221,11 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
mSpeedView.setText(String.format(Locale.US, "%.1f", speed));
mCadenceView.setText(String.format(Locale.US, "%d", cadence));
mActivityView.setText(activity == RSCManagerCallbacks.ACTIVITY_RUNNING ? R.string.rsc_running : R.string.rsc_walking);
mActivityView.setText(running ? R.string.rsc_running : R.string.rsc_walking);
}
private void onStripesUpdate(final float distance, final int strides) {
if (distance == RSCManagerCallbacks.NOT_AVAILABLE) {
private void onStripesUpdate(final long distance, final int strides) {
if (distance == -1) {
mDistanceView.setText(R.string.not_available);
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
} else {
@@ -226,8 +235,8 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
switch (unit) {
case SettingsFragment.SETTINGS_UNIT_KM_H:
case SettingsFragment.SETTINGS_UNIT_M_S:
if (distance < 100000) { // 1 km in cm
mDistanceView.setText(String.format(Locale.US, "%.0f", distance / 100.0f));
if (distance < 100000L) { // 1 km in cm
mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 100.0f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
} else {
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 100000.0f));
@@ -235,8 +244,8 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
}
break;
case SettingsFragment.SETTINGS_UNIT_MPH:
if (distance < 160931) { // 1 mile in cm
mDistanceView.setText(String.format(Locale.US, "%.0f", distance / 91.4392f));
if (distance < 160931L) { // 1 mile in cm
mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 91.4392f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_yd);
} else {
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 160931.23f));
@@ -257,13 +266,13 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
if (RSCService.BROADCAST_RSC_MEASUREMENT.equals(action)) {
final float speed = intent.getFloatExtra(RSCService.EXTRA_SPEED, 0.0f);
final int cadence = intent.getIntExtra(RSCService.EXTRA_CADENCE, 0);
final float totalDistance = intent.getFloatExtra(RSCService.EXTRA_TOTAL_DISTANCE, RSCManagerCallbacks.NOT_AVAILABLE);
final int activity = intent.getIntExtra(RSCService.EXTRA_ACTIVITY, RSCManagerCallbacks.ACTIVITY_WALKING);
final long totalDistance = intent.getLongExtra(RSCService.EXTRA_TOTAL_DISTANCE, -1);
final boolean running = intent.getBooleanExtra(RSCService.EXTRA_ACTIVITY, false);
// Update GUI
onMeasurementReceived(speed, cadence, totalDistance, activity);
onMeasurementReceived(speed, cadence, totalDistance, running);
} else if (RSCService.BROADCAST_STRIDES_UPDATE.equals(action)) {
final int strides = intent.getIntExtra(RSCService.EXTRA_STRIDES, 0);
final float distance = intent.getFloatExtra(RSCService.EXTRA_DISTANCE, 0);
final long distance = intent.getLongExtra(RSCService.EXTRA_DISTANCE, -1);
// Update GUI
onStripesUpdate(distance, strides);
}

View File

@@ -22,11 +22,13 @@
package no.nordicsemi.android.nrftoolbox.rsc;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.Deque;
import java.util.LinkedList;
@@ -34,40 +36,56 @@ import java.util.UUID;
import no.nordicsemi.android.ble.BleManager;
import no.nordicsemi.android.ble.Request;
import no.nordicsemi.android.ble.common.callback.rsc.RunningSpeedAndCadenceMeasurementDataCallback;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
import no.nordicsemi.android.nrftoolbox.parser.RSCMeasurementParser;
public class RSCManager extends BleManager<RSCManagerCallbacks> {
private static final byte INSTANTANEOUS_STRIDE_LENGTH_PRESENT = 0x01; // 1 bit
private static final byte TOTAL_DISTANCE_PRESENT = 0x02; // 1 bit
private static final byte WALKING_OR_RUNNING_STATUS_BITS = 0x04; // 1 bit
public class RSCManager extends BatteryManager<RSCManagerCallbacks> {
/** Running Speed and Cadence Measurement service UUID */
public final static UUID RUNNING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001814-0000-1000-8000-00805f9b34fb");
public static final UUID RUNNING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001814-0000-1000-8000-00805f9b34fb");
/** Running Speed and Cadence Measurement characteristic UUID */
private static final UUID RSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A53-0000-1000-8000-00805f9b34fb");
private BluetoothGattCharacteristic mRSCMeasurementCharacteristic;
public RSCManager(final Context context) {
RSCManager(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
*/
private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() {
private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
@Override
protected Deque<Request> initGatt(@NonNull final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.add(Request.newEnableNotificationsRequest(mRSCMeasurementCharacteristic));
return requests;
protected void initialize() {
super.initialize();
setNotificationCallback(mRSCMeasurementCharacteristic)
.with(new RunningSpeedAndCadenceMeasurementDataCallback() {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
log(LogContract.Log.Level.APPLICATION, "\"" + RSCMeasurementParser.parse(data) + "\" received");
super.onDataReceived(device, data);
}
@Override
public void onRSCMeasurementReceived(@NonNull final BluetoothDevice device, final boolean running,
final float instantaneousSpeed, final int instantaneousCadence,
@Nullable final Integer strideLength,
@Nullable final Long totalDistance) {
mCallbacks.onRSCMeasurementReceived(device, running, instantaneousSpeed,
instantaneousCadence, strideLength, totalDistance);
}
});
enableNotifications(mRSCMeasurementCharacteristic);
}
@Override
@@ -81,43 +99,8 @@ public class RSCManager extends BleManager<RSCManagerCallbacks> {
@Override
protected void onDeviceDisconnected() {
super.onDeviceDisconnected();
mRSCMeasurementCharacteristic = null;
}
@Override
public void onCharacteristicNotified(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) {
log(LogContract.Log.Level.APPLICATION, "\"" + RSCMeasurementParser.parse(characteristic) + "\" received");
// Decode the new data
int offset = 0;
final int flags = characteristic.getValue()[offset]; // 1 byte
offset += 1;
final boolean islmPresent = (flags & INSTANTANEOUS_STRIDE_LENGTH_PRESENT) > 0;
final boolean tdPreset = (flags & TOTAL_DISTANCE_PRESENT) > 0;
final boolean running = (flags & WALKING_OR_RUNNING_STATUS_BITS) > 0;
final float instantaneousSpeed = (float) characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset) / 256.0f; // 1/256 m/s in [m/s]
offset += 2;
final int instantaneousCadence = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); // [SPM]
offset += 1;
float instantaneousStrideLength = RSCManagerCallbacks.NOT_AVAILABLE;
if (islmPresent) {
instantaneousStrideLength = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); // [cm]
offset += 2;
}
float totalDistance = RSCManagerCallbacks.NOT_AVAILABLE;
if (tdPreset) {
totalDistance = (float) characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset) / 10.0f; // 1/10 m in [m]
//offset += 4;
}
// Notify listener about the new measurement
mCallbacks.onMeasurementReceived(gatt.getDevice(), instantaneousSpeed, instantaneousCadence, totalDistance, instantaneousStrideLength,
running ? RSCManagerCallbacks.ACTIVITY_RUNNING : RSCManagerCallbacks.ACTIVITY_WALKING);
}
};
}

View File

@@ -21,14 +21,9 @@
*/
package no.nordicsemi.android.nrftoolbox.rsc;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.ble.common.profile.rsc.RunningSpeedAndCadenceMeasurementCallback;
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
import no.nordicsemi.android.ble.BleManagerCallbacks;
interface RSCManagerCallbacks extends BatteryManagerCallbacks, RunningSpeedAndCadenceMeasurementCallback {
public interface RSCManagerCallbacks extends BleManagerCallbacks {
int NOT_AVAILABLE = -1;
int ACTIVITY_WALKING = 0;
int ACTIVITY_RUNNING = 1;
void onMeasurementReceived(final BluetoothDevice device, float speed, int cadence, float distance, float strideLen, int activity);
}

View File

@@ -31,8 +31,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import no.nordicsemi.android.ble.BleManager;
import no.nordicsemi.android.log.Logger;
@@ -47,6 +50,7 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
public static final String BROADCAST_RSC_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_RSC_MEASUREMENT";
public static final String EXTRA_SPEED = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_SPEED";
public static final String EXTRA_CADENCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_CADENCE";
public static final String EXTRA_STRIDE_LENGTH = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDE_LENGTH";
public static final String EXTRA_TOTAL_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_TOTAL_DISTANCE";
public static final String EXTRA_ACTIVITY = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_ACTIVITY";
@@ -54,6 +58,9 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
public static final String EXTRA_STRIDES = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDES";
public static final String EXTRA_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_DISTANCE";
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.rsc.ACTION_DISCONNECT";
private RSCManager mManager;
@@ -61,9 +68,9 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
/** The last value of a cadence */
private float mCadence;
/** Trip distance in cm */
private float mDistance;
private long mDistance;
/** Stride length in cm */
private float mStrideLength;
private Integer mStrideLength;
/** Number of steps in the trip */
private int mStepsNumber;
private boolean mTaskInProgress;
@@ -76,9 +83,9 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
private final LocalBinder mBinder = new RSCBinder();
/**
* This local binder is an interface for the bound activity to operate with the RSC sensor
* This local binder is an interface for the bound activity to operate with the RSC sensor.
*/
public class RSCBinder extends LocalBinder {
class RSCBinder extends LocalBinder {
// empty
}
@@ -114,10 +121,21 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
protected void onRebind() {
// when the activity rebinds to the service, remove the notification
cancelNotification();
if (isConnected()) {
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
// If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications.
mManager.readBatteryLevelCharacteristic();
}
}
@Override
protected void onUnbind() {
// When we are connected, but the application is not open, we are not really interested in battery level notifications.
// But we will still be receiving other values, if enabled.
if (isConnected())
mManager.disableBatteryLevelCharacteristicNotifications();
// when the activity closes we need to show the notification that user is connected to the sensor
createNotification(R.string.rsc_notification_connected_message, 0);
}
@@ -129,14 +147,14 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
return;
mStepsNumber++;
mDistance += mStrideLength;
mDistance += mStrideLength; // [cm]
final Intent broadcast = new Intent(BROADCAST_STRIDES_UPDATE);
broadcast.putExtra(EXTRA_STRIDES, mStepsNumber);
broadcast.putExtra(EXTRA_DISTANCE, mDistance);
LocalBroadcastManager.getInstance(RSCService.this).sendBroadcast(broadcast);
if (mCadence > 0) {
final long interval = (long) (1000.0f * 65.0f / mCadence); // 60s + 5s for calibration in milliseconds
final long interval = (long) (1000.0f * 60.0f / mCadence);
mHandler.postDelayed(mUpdateStridesTask, interval);
} else {
mTaskInProgress = false;
@@ -145,26 +163,40 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
};
@Override
public void onMeasurementReceived(final BluetoothDevice device, final float speed, final int cadence, final float totalDistance, final float strideLen, final int activity) {
public void onRSCMeasurementReceived(@NonNull final BluetoothDevice device, final boolean running,
final float instantaneousSpeed, final int instantaneousCadence,
@Nullable final Integer strideLength,
@Nullable final Long totalDistance) {
final Intent broadcast = new Intent(BROADCAST_RSC_MEASUREMENT);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_SPEED, speed);
broadcast.putExtra(EXTRA_CADENCE, cadence);
broadcast.putExtra(EXTRA_SPEED, instantaneousSpeed);
broadcast.putExtra(EXTRA_CADENCE, instantaneousCadence);
broadcast.putExtra(EXTRA_STRIDE_LENGTH, strideLength);
broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance);
broadcast.putExtra(EXTRA_ACTIVITY, activity);
broadcast.putExtra(EXTRA_ACTIVITY, running);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
// Start strides counter if not in progress
mCadence = cadence;
mStrideLength = strideLen;
if (!mTaskInProgress && cadence > 0) {
mCadence = instantaneousCadence;
if (strideLength != null) {
mStrideLength = strideLength;
}
if (!mTaskInProgress && strideLength != null && instantaneousCadence > 0) {
mTaskInProgress = true;
final long interval = (long) (1000.0f * 65.0f / mCadence); // 60s + 5s for calibration in milliseconds
final long interval = (long) (1000.0f * 60.0f / mCadence);
mHandler.postDelayed(mUpdateStridesTask, interval);
}
}
@Override
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
/**
* Creates the notification
*