Skip to content

Commit

Permalink
Add: try to get raw acceleration data #3
Browse files Browse the repository at this point in the history
  • Loading branch information
ziqin committed Sep 1, 2018
1 parent 31f7924 commit 4a44e5b
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public final class MainActivity extends AppCompatActivity {
private static final int REQUEST_ENABLE_BT = 1;
private static final int REQUEST_SCAN_BAND = 2;

private Button mButton;
private Button mButton, mAccelerationButton;
private TextView mHeartRateText, mTimeText;

@Override
Expand All @@ -43,12 +43,17 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);

mButton = findViewById(R.id.btn);
mAccelerationButton = findViewById(R.id.acceleration_btn);
mHeartRateText = findViewById(R.id.heart_rate_text);
mTimeText = findViewById(R.id.time_text);

initBle();
registerBroadcast();
CommService.startActionStateUpdate(this);

mAccelerationButton.setOnClickListener(view -> requestStartAccelerationMeasure());
Button mStopAccelerationButton = findViewById(R.id.stop_acceleration_btn);
mStopAccelerationButton.setOnClickListener(view -> requestStopAccelerationMeasure());
}

@Override
Expand Down Expand Up @@ -83,6 +88,9 @@ private void registerBroadcast() {
broadcastMgr.registerReceiver(mBroadcastReceiver, new IntentFilter(Constants.Action.START_HEART_RATE));
broadcastMgr.registerReceiver(mBroadcastReceiver, new IntentFilter(Constants.Action.STOP_HEART_RATE));
broadcastMgr.registerReceiver(mBroadcastReceiver, new IntentFilter(Constants.Action.BROADCAST_HEART_RATE));
// broadcastMgr.registerReceiver(mBroadcastReceiver, new IntentFilter(Constants.Action.START_ACCELERATION));
// broadcastMgr.registerReceiver(mBroadcastReceiver, new IntentFilter(Constants.Action.STOP_ACCELERATION));
broadcastMgr.registerReceiver(mBroadcastReceiver, new IntentFilter(Constants.Action.BROADCAST_ACCELERATION));
Log.i(TAG, "registered broadcast receiver");
}

Expand Down Expand Up @@ -181,6 +189,16 @@ private void requestStopHeartRateMeasure() {
CommService.startActionStopHeartRateMeasure(this);
}

private void requestStartAccelerationMeasure() {
Intent i = new Intent(this, CommService.class).setAction(Constants.Action.START_ACCELERATION);
startService(i);
}

private void requestStopAccelerationMeasure() {
Intent i = new Intent(this, CommService.class).setAction(Constants.Action.STOP_ACCELERATION);
startService(i);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch (requestCode) {
Expand Down Expand Up @@ -264,6 +282,13 @@ private void handleHeartRateBroadcast(Intent data) {
}
}

private void handleAccelerationBroadcast(Intent data) {
float x = data.getFloatExtra(Constants.Extra.ACCELERATION_X, Float.NaN);
float y = data.getFloatExtra(Constants.Extra.ACCELERATION_Y, Float.NaN);
float z = data.getFloatExtra(Constants.Extra.ACCELERATION_Z, Float.NaN);
Log.i(TAG, String.format("handleAccelerationBroadcast: x=%.3f, y=%.3f, z=%.3f", x, y, z));
}

private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Expand All @@ -288,6 +313,9 @@ public void onReceive(Context context, Intent intent) {
case Constants.Action.BROADCAST_HEART_RATE:
handleHeartRateBroadcast(intent);
break;
case Constants.Action.BROADCAST_ACCELERATION:
handleAccelerationBroadcast(intent);
break;
default: Log.i(TAG, "onReceive: Unknown action: " + action);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public static final class Action {
public static final String START_HEART_RATE = BASE + ".services.action.START_HEART_RATE";
public static final String STOP_HEART_RATE = BASE + ".services.action.STOP_HEART_RATE";
public static final String BROADCAST_HEART_RATE = BASE + ".services.action.BROADCAST_HEART_RATE";
public static final String START_ACCELERATION = BASE + ".services.action.START_ACCELERATION";
public static final String STOP_ACCELERATION = BASE + ".services.action.STOP_ACCELERATION";
public static final String BROADCAST_ACCELERATION = BASE + ".services.action.BROADCAST_ACCELERATION";
}

public static final class Extra {
Expand All @@ -20,6 +23,9 @@ public static final class Extra {
public static final String STATE = "extra.data.STATE";
public static final String HEART_RATE = "extra.data.HEART_RATE";
public static final String STATUS = "extra.response.STATUS";
public static final String ACCELERATION_X = "extra.data.acceleration_x";
public static final String ACCELERATION_Y = "extra.data.acceleration_y";
public static final String ACCELERATION_Z = "extra.data.acceleration_z";
}

public static final class Status {
Expand Down
103 changes: 103 additions & 0 deletions app/src/main/java/in/wangziq/fitnessrecorder/hardware/MiBand2.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

public final class MiBand2 {

public interface TriFloatConsumer { void accept(float x, float y, float z); }

private static final int REFRESH_TIMEOUT = 100; // 100ms
private static final int USR_INTERACTION_TIMEOUT = 20000; // 20s
private static final String TAG = MiBand2.class.getSimpleName();
Expand All @@ -40,6 +42,7 @@ public final class MiBand2 {
private Consumer<BandState> mDisconnectHandler;
private SparseArray<Consumer<byte[]>> mNoticeConsumers;
private IntConsumer mHeartRateHandler;
private TriFloatConsumer mAccelerationHandler;
private Timer mHeartRatePingTimer;

public MiBand2(@Nullable String macAddress, @Nullable byte[] key) {
Expand Down Expand Up @@ -132,9 +135,13 @@ public boolean startMeasureHeartRate(IntConsumer heartRateHandler) {
Log.e(TAG, "enableHeartRate: failed to turn on heart rate notification");
return false;
}

if (!enableHeartRateContinuousMonitor()) {
Log.e(TAG, "enableHeartRate: failed to enable heart rate continuous monitor");
}
// turnOnRawDataNotify();
// enableAcceleration();

enableHeartRatePing();
return true;
}
Expand All @@ -146,6 +153,102 @@ public void stopMeasureHeartRate() {
Log.i(TAG, "stopMeasureHeartRate");
}

public boolean startMeasureAcceleration(TriFloatConsumer accelerationHandler) {
mAccelerationHandler = accelerationHandler;
if (!turnOnRawDataNotify()) return false;
if (!enableAcceleration()) return false;
return true;
}

public boolean stopMeasureAcceleration() { // TODO
ResponseWaiter waiter = new ResponseWaiter(REFRESH_TIMEOUT);
BleManager.getInstance().write(mBleDevice, Protocol.Service.BASIC, Protocol.Characteristic.SENSOR_CONTROL,
Protocol.ACCELERATION_STOP,
new BleWriteCallback() {
@Override public void onWriteSuccess(int current, int total, byte[] justWrite) {
waiter.ok();
Log.i(TAG, "stopMeasureAcceleration: succeeded");
}
@Override public void onWriteFailure(BleException exception) {
waiter.fail();
Log.i(TAG, "stopMeasureAcceleration: failed");
}
});
return waiter.work();
}

private boolean turnOnRawDataNotify() {
ResponseWaiter waiter = new ResponseWaiter(REFRESH_TIMEOUT);
BleManager.getInstance().notify(mBleDevice, Protocol.Service.BASIC, Protocol.Characteristic.SENSOR_DATA,
new BleNotifyCallback() {
@Override public void onNotifySuccess() {
waiter.ok();
Log.i(TAG, "turnOnRawDataNotify: succeeded");
}
@Override public void onNotifyFailure(BleException exception) {
waiter.fail();
Log.e(TAG, "turnOnRawDataNotify: failed");
}
@Override public void onCharacteristicChanged(byte[] data) {
Log.i(TAG, "received raw data: length=" + data.length + ", data=" + BytesUtil.toHexStr(data));
parseAcceleration(data);
}
});
return waiter.work();
}

// see https://github.com/Freeyourgadget/Gadgetbridge/pull/703/files for details
private void parseAcceleration(byte[] value) {
if (value.length <= 2 || (value.length - 2) % 6 != 0) {
Log.w(TAG, ">>> parseAcceleration: got unexpected sensor data with length: " + value.length);
return;
}
float count = 0;
float x = 0, y = 0, z = 0;
for (int i = 2; i < value.length; i += 6, count += 1) {
x += (value[i] | (value[i+1] << 8));
y += (value[i+2] | (value[i+3] << 8));
z += (value[i+4] | (value[i+5] << 8));
}
x /= count; y /= count; z /= count;
Log.i(TAG, String.format("parseAcceleration: x=%.3f, y=%.3f, z=%.3f, total=%.3f", x, y, z, Math.sqrt(x*x + y*y + z*z)));
if (mAccelerationHandler != null) mAccelerationHandler.accept(x, y, z);
}

// https://github.com/Freeyourgadget/Gadgetbridge/pull/894
private boolean enableAcceleration() {
ResponseWaiter waiter = new ResponseWaiter(REFRESH_TIMEOUT);
BleManager.getInstance().write(
mBleDevice, Protocol.Service.BASIC, Protocol.Characteristic.SENSOR_CONTROL,
Protocol.ACCELERATION_INIT,
new BleWriteCallback() {
@Override public void onWriteSuccess(int current, int total, byte[] justWrite) {
waiter.ok();
Log.i(TAG, "enableAcceleration step 1: succeeded");
}
@Override public void onWriteFailure(BleException exception) {
waiter.fail();
Log.e(TAG, "enableAcceleration step 1: failed");
}
});
if (!waiter.work()) return false;

waiter.reset();
BleManager.getInstance().write(mBleDevice, Protocol.Service.BASIC, Protocol.Characteristic.SENSOR_CONTROL,
Protocol.ACCELERATION_START,
new BleWriteCallback() {
@Override public void onWriteSuccess(int current, int total, byte[] justWrite) {
waiter.ok();
Log.i(TAG, "enableAcceleration step 2: succeeded");
}
@Override public void onWriteFailure(BleException exception) {
waiter.fail();
Log.i(TAG, "enableAcceleration step 2: failed");
}
});
return waiter.work();
}

private void initAuthNoticeConsumer() {
mNoticeConsumers = new SparseArray<>();
mNoticeConsumers.put(Protocol.SEND_KEY_RESPONSE_OK, data -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public final static class Service {

public final static class Characteristic {
public final static String HZ = String.format(BASE2, 0x0002);
public final static String SENSOR = String.format(BASE2, 0x0001);
public final static String SENSOR_CONTROL = String.format(BASE2, 0x0001);
public final static String SENSOR_DATA = String.format(BASE2, 0x0002);
public final static String AUTH = String.format(BASE2, 0x0009);
public final static String BATTERY = String.format(BASE2, 0x0006);
public final static String STEPS = String.format(BASE2, 0x0007);
Expand Down Expand Up @@ -59,6 +60,10 @@ public final static class Characteristic {
public static final byte[] HEART_START_MANUAL = {0x15, 0x02, 0x01};
public static final byte[] HEART_KEEP_ALIVE = {0x16};

public static final int HEART_KEEP_ALIVE_PERIOD = 12000;
public static final byte[] ACCELERATION_INIT = {0x01, 0x01, 0x19}; // 0x01, 0x02, 0x19 (heart rate) / 0x01, 0x03, 0x19
public static final byte[] ACCELERATION_START = {0x02};
public static final byte[] ACCELERATION_STOP = {0x03}; // or 0x02

public static final int HEART_KEEP_ALIVE_PERIOD = 10000; // 10 s

}
Loading

0 comments on commit 4a44e5b

Please sign in to comment.