BLE: extract SensorDataCycling.

Part of #1352.
This commit is contained in:
Dennis Guse
2022-08-22 19:30:56 +02:00
parent 67b174feac
commit dc7afbd07f
13 changed files with 330 additions and 318 deletions
@@ -61,7 +61,8 @@ import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataHeartRate;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
@@ -504,16 +505,16 @@ public class ExportImportTest {
sensorDataSet.set(new SensorDataCyclingPower("power", "power", Power.of(power)));
sensorDataSet.set(new SensorDataHeartRate("heartRate", "heartRate", HeartRate.of(heartRate)));
SensorDataCycling.CyclingCadence cyclingCadence = Mockito.mock(SensorDataCycling.CyclingCadence.class);
SensorDataCyclingCadence cyclingCadence = Mockito.mock(SensorDataCyclingCadence.class);
Mockito.when(cyclingCadence.hasValue()).thenReturn(true);
Mockito.when(cyclingCadence.getValue()).thenReturn(Cadence.of(cadence));
sensorDataSet.set(cyclingCadence);
if (distance != null && speed != null) {
SensorDataCycling.DistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCycling.DistanceSpeed.Data.class);
SensorDataCyclingDistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCyclingDistanceSpeed.Data.class);
Mockito.when(distanceSpeedData.getDistanceOverall()).thenReturn(distance);
Mockito.when(distanceSpeedData.getSpeed()).thenReturn(Speed.of(speed));
SensorDataCycling.DistanceSpeed distanceSpeed = Mockito.mock(SensorDataCycling.DistanceSpeed.class);
SensorDataCyclingDistanceSpeed distanceSpeed = Mockito.mock(SensorDataCyclingDistanceSpeed.class);
Mockito.when(distanceSpeed.hasValue()).thenReturn(true);
Mockito.when(distanceSpeed.getValue()).thenReturn(distanceSpeedData);
sensorDataSet.set(distanceSpeed);
@@ -10,7 +10,7 @@ import org.junit.Test;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadenceAndDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
@@ -48,7 +48,7 @@ public class BluetoothUtilsTest {
characteristic.setValue(new byte[]{0x02, (byte) 0xC8, 0x00, 0x00, 0x00, 0x06, (byte) 0x99});
// when
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
SensorDataCyclingCadenceAndDistanceSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
// then
assertNull(sensor.getDistanceSpeed());
@@ -61,7 +61,7 @@ public class BluetoothUtilsTest {
characteristic.setValue(new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, 0, 1, 0x45, (byte) 0x99});
// when
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
SensorDataCyclingCadenceAndDistanceSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
// then
assertEquals(65535 + 16777216, sensor.getDistanceSpeed().getWheelRevolutionsCount());
@@ -74,7 +74,7 @@ public class BluetoothUtilsTest {
characteristic.setValue(new byte[]{0x03, (byte) 0xC8, 0x00, 0x00, 0x01, 0x06, (byte) 0x99, (byte) 0xE1, 0x00, 0x45, (byte) 0x99});
// when
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
SensorDataCyclingCadenceAndDistanceSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
// then
assertEquals(200 + 16777216, sensor.getDistanceSpeed().getWheelRevolutionsCount());
@@ -21,8 +21,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_1() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024); // 1s
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 2048); // 2s
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress", "sensorName", 1, 1024); // 1s
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 2, 2048); // 2s
// when
current.compute(previous);
@@ -34,8 +34,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_2() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 6184);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 8016);
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress", "sensorName", 1, 6184);
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 2, 8016);
// when
current.compute(previous);
@@ -47,8 +47,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_sameCount() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 2048);
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 1, 2048);
// when
current.compute(previous);
@@ -61,8 +61,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_sameTime() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 1024);
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 2, 1024);
// when
current.compute(previous);
@@ -74,8 +74,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_rollOverTime() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, UintUtils.UINT16_MAX - 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 0);
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress", "sensorName", 1, UintUtils.UINT16_MAX - 1024);
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 2, 0);
// when
current.compute(previous);
@@ -89,8 +89,8 @@ public class SensorDataCyclingTest {
@Deprecated
public void compute_cadence_rollOverCount() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 0, 2048);
// when
current.compute(previous);
@@ -102,8 +102,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_overflow() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 0, 2048);
// when
current.compute(previous);
@@ -115,8 +115,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_speed() {
// given
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 1, 6184);
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 2, 8016);
SensorDataCyclingDistanceSpeed previous = new SensorDataCyclingDistanceSpeed("sensorAddress", "sensorName", 1, 6184);
SensorDataCyclingDistanceSpeed current = new SensorDataCyclingDistanceSpeed("sensorAddress", "sensorName", 2, 8016);
// when
current.compute(previous, Distance.ofMM(2150));
@@ -131,8 +131,8 @@ public class SensorDataCyclingTest {
@Deprecated
public void compute_speed_rollOverCount() {
// given
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 0, 2048);
SensorDataCyclingDistanceSpeed previous = new SensorDataCyclingDistanceSpeed("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCyclingDistanceSpeed current = new SensorDataCyclingDistanceSpeed("sensorAddress", "sensorName", 0, 2048);
// when
current.compute(previous, Distance.ofMM(2000));
@@ -145,8 +145,8 @@ public class SensorDataCyclingTest {
@Test
public void compute_speed_overflow() {
// given
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 0, 2048);
SensorDataCyclingDistanceSpeed previous = new SensorDataCyclingDistanceSpeed("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCyclingDistanceSpeed current = new SensorDataCyclingDistanceSpeed("sensorAddress", "sensorName", 0, 2048);
// when
current.compute(previous, Distance.ofMM(2000));
@@ -158,8 +158,8 @@ public class SensorDataCyclingTest {
@Test
public void equals_speed_with_no_data() {
// given
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress");
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 0, 2048);
SensorDataCyclingDistanceSpeed previous = new SensorDataCyclingDistanceSpeed("sensorAddress");
SensorDataCyclingDistanceSpeed current = new SensorDataCyclingDistanceSpeed("sensorAddress", "sensorName", 0, 2048);
// when
previous.toString();
@@ -172,8 +172,8 @@ public class SensorDataCyclingTest {
@Test
public void equals_cadence_with_no_data() {
// given
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress");
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
SensorDataCyclingCadence previous = new SensorDataCyclingCadence("sensorAddress");
SensorDataCyclingCadence current = new SensorDataCyclingCadence("sensorAddress", "sensorName", 0, 2048);
// when
previous.toString();
@@ -31,7 +31,8 @@ import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.sensors.sensorData.SensorData;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.settings.PreferencesUtils;
@@ -186,24 +187,24 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
@Override
public synchronized void onChanged(SensorData<?> sensorData) {
if (sensorData instanceof SensorDataCycling.CyclingCadence) {
SensorDataCycling.CyclingCadence previous = sensorDataSet.getCyclingCadence();
if (sensorData instanceof SensorDataCyclingCadence) {
SensorDataCyclingCadence previous = sensorDataSet.getCyclingCadence();
Log.d(TAG, "Previous: " + previous + "; current: " + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: cadence data repeated.");
return;
}
((SensorDataCycling.CyclingCadence) sensorData).compute(previous);
((SensorDataCyclingCadence) sensorData).compute(previous);
}
if (sensorData instanceof SensorDataCycling.DistanceSpeed) {
SensorDataCycling.DistanceSpeed previous = sensorDataSet.getCyclingDistanceSpeed();
if (sensorData instanceof SensorDataCyclingDistanceSpeed) {
SensorDataCyclingDistanceSpeed previous = sensorDataSet.getCyclingDistanceSpeed();
Log.d(TAG, "Previous: " + previous + "; Current" + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: cycling speed data repeated.");
return;
}
((SensorDataCycling.DistanceSpeed) sensorData).compute(previous, preferenceWheelCircumference);
((SensorDataCyclingDistanceSpeed) sensorData).compute(previous, preferenceWheelCircumference);
}
if (sensorData instanceof SensorDataRunning) {
SensorDataRunning previous = sensorDataSet.getRunningDistanceSpeedCadence();
@@ -3,7 +3,8 @@ package de.dennisguse.opentracks.sensors;
import android.bluetooth.BluetoothGattCharacteristic;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadenceAndDistanceSpeed;
public class BluetoothRemoteSensorManagerCyclingCadence extends BluetoothConnectionManager<Cadence> {
@@ -12,13 +13,13 @@ public class BluetoothRemoteSensorManagerCyclingCadence extends BluetoothConnect
}
@Override
protected SensorDataCycling.CyclingCadence createEmptySensorData(String address) {
return new SensorDataCycling.CyclingCadence(address);
protected SensorDataCyclingCadence createEmptySensorData(String address) {
return new SensorDataCyclingCadence(address);
}
@Override
protected SensorDataCycling.CyclingCadence parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
SensorDataCycling.CadenceAndSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic);
protected SensorDataCyclingCadence parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
SensorDataCyclingCadenceAndDistanceSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic);
if (cadenceAndSpeed == null) {
return null;
}
@@ -2,22 +2,23 @@ package de.dennisguse.opentracks.sensors;
import android.bluetooth.BluetoothGattCharacteristic;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadenceAndDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed;
public class BluetoothRemoteSensorManagerCyclingDistanceSpeed extends BluetoothConnectionManager<SensorDataCycling.DistanceSpeed.Data> {
public class BluetoothRemoteSensorManagerCyclingDistanceSpeed extends BluetoothConnectionManager<SensorDataCyclingDistanceSpeed.Data> {
BluetoothRemoteSensorManagerCyclingDistanceSpeed(SensorDataObserver observer) {
super(BluetoothUtils.CYCLING_SPEED_CADENCE, observer);
}
@Override
protected SensorDataCycling.DistanceSpeed createEmptySensorData(String address) {
return new SensorDataCycling.DistanceSpeed(address);
protected SensorDataCyclingDistanceSpeed createEmptySensorData(String address) {
return new SensorDataCyclingDistanceSpeed(address);
}
@Override
protected SensorDataCycling.DistanceSpeed parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
SensorDataCycling.CadenceAndSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic);
protected SensorDataCyclingDistanceSpeed parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
SensorDataCyclingCadenceAndDistanceSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic);
if (cadenceAndSpeed == null) {
return null;
}
@@ -32,7 +32,9 @@ import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadenceAndDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
@@ -139,20 +141,20 @@ public class BluetoothUtils {
index += 2 + 2;
}
SensorDataCycling.CyclingCadence cadence = null;
SensorDataCyclingCadence cadence = null;
if (hasCrank && valueLength - index >= 4) {
long crankCount = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index);
index += 2;
int crankTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s
cadence = new SensorDataCycling.CyclingCadence("", "", crankCount, crankTime);
cadence = new SensorDataCyclingCadence("", "", crankCount, crankTime);
}
return new SensorDataCyclingPower.Data(Power.of(instantaneousPower), cadence);
}
public static SensorDataCycling.CadenceAndSpeed parseCyclingCrankAndWheel(String address, String sensorName, @NonNull BluetoothGattCharacteristic characteristic) {
public static SensorDataCyclingCadenceAndDistanceSpeed parseCyclingCrankAndWheel(String address, String sensorName, @NonNull BluetoothGattCharacteristic characteristic) {
// DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.csc_measurement.xml
int valueLength = characteristic.getValue().length;
if (valueLength == 0) {
@@ -164,25 +166,25 @@ public class BluetoothUtils {
boolean hasCrank = (flags & 0x02) > 0;
int index = 1;
SensorDataCycling.DistanceSpeed speed = null;
SensorDataCyclingDistanceSpeed speed = null;
if (hasWheel && valueLength - index >= 6) {
int wheelTotalRevolutionCount = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, index);
index += 4;
int wheelTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s
speed = new SensorDataCycling.DistanceSpeed(address, sensorName, wheelTotalRevolutionCount, wheelTime);
speed = new SensorDataCyclingDistanceSpeed(address, sensorName, wheelTotalRevolutionCount, wheelTime);
index += 2;
}
SensorDataCycling.CyclingCadence cadence = null;
SensorDataCyclingCadence cadence = null;
if (hasCrank && valueLength - index >= 4) {
long crankCount = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index);
index += 2;
int crankTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s
cadence = new SensorDataCycling.CyclingCadence(address, sensorName, crankCount, crankTime);
cadence = new SensorDataCyclingCadence(address, sensorName, crankCount, crankTime);
}
return new SensorDataCycling.CadenceAndSpeed(address, sensorName, cadence, speed);
return new SensorDataCyclingCadenceAndDistanceSpeed(address, sensorName, cadence, speed);
}
public static SensorDataRunning parseRunningSpeedAndCadence(String address, String sensorName, @NonNull BluetoothGattCharacteristic characteristic) {
@@ -1,248 +0,0 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import java.time.Duration;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.sensors.UintUtils;
/**
* Provides cadence in rpm and speed in milliseconds from Bluetooth LE Cycling Cadence and Speed sensors.
*/
public final class SensorDataCycling {
private static final String TAG = SensorDataCycling.class.getSimpleName();
private SensorDataCycling() {
}
public static class CyclingCadence extends SensorData<Cadence> {
private final Long crankRevolutionsCount; // UINT32
private final Integer crankRevolutionsTime; // UINT16; 1/1024s
public CyclingCadence(String sensorAddress) {
super(sensorAddress);
this.crankRevolutionsCount = null;
this.crankRevolutionsTime = null;
}
public CyclingCadence(String sensorAddress, String sensorName, long crankRevolutionsCount, int crankRevolutionsTime) {
super(sensorAddress, sensorName);
this.crankRevolutionsCount = crankRevolutionsCount;
this.crankRevolutionsTime = crankRevolutionsTime;
}
public boolean hasData() {
return crankRevolutionsCount != null && crankRevolutionsTime != null;
}
public long getCrankRevolutionsCount() {
return crankRevolutionsCount;
}
public int getCrankRevolutionsTime() {
return crankRevolutionsTime;
}
@NonNull
@Override
protected Cadence getNoneValue() {
return Cadence.of(0);
}
public void compute(CyclingCadence previous) {
if (hasData() && previous != null && previous.hasData()) {
float timeDiff_ms = UintUtils.diff(crankRevolutionsTime, previous.crankRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);
if (timeDiff.isZero() || timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
value = null;
return;
}
// TODO We have to treat with overflow according to the documentation: read https://github.com/OpenTracksApp/OpenTracks/pull/953#discussion_r711625268
if (crankRevolutionsCount < previous.crankRevolutionsCount) {
Log.e(TAG, "Crank revolutions count difference is invalid: cannot compute cadence.");
return;
}
long crankDiff = UintUtils.diff(crankRevolutionsCount, previous.crankRevolutionsCount, UintUtils.UINT32_MAX);
value = Cadence.of(crankDiff, timeDiff);
}
}
@NonNull
@Override
public String toString() {
return super.toString() + " cadence=" + value + " time=" + crankRevolutionsTime + " count=" + crankRevolutionsCount;
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof CyclingCadence)) return false;
CyclingCadence comp = (CyclingCadence) obj;
if (hasData() && comp.hasData() == hasData()) {
return getCrankRevolutionsCount() == comp.getCrankRevolutionsCount() && getCrankRevolutionsTime() == comp.getCrankRevolutionsTime();
} else {
return false;
}
}
}
public static class DistanceSpeed extends SensorData<DistanceSpeed.Data> {
private final Long wheelRevolutionsCount; // UINT32
private final Integer wheelRevolutionsTime; // UINT16; 1/1024s
public DistanceSpeed(String sensorAddress) {
super(sensorAddress);
this.wheelRevolutionsCount = null;
this.wheelRevolutionsTime = null;
}
public DistanceSpeed(String sensorAddress, String sensorName, long wheelRevolutionsCount, int wheelRevolutionsTime) {
super(sensorAddress, sensorName);
this.wheelRevolutionsCount = wheelRevolutionsCount;
this.wheelRevolutionsTime = wheelRevolutionsTime;
}
public boolean hasData() {
return wheelRevolutionsCount != null && wheelRevolutionsTime != null;
}
public long getWheelRevolutionsCount() {
return wheelRevolutionsCount;
}
public int getWheelRevolutionsTime() {
return wheelRevolutionsTime;
}
@NonNull
@Override
protected Data getNoneValue() {
if (value != null) {
return new Data(value.distance, value.distanceOverall, Speed.zero());
} else {
return new Data(Distance.of(0), Distance.of(0), Speed.zero());
}
}
public void compute(DistanceSpeed previous, Distance wheelCircumference) {
if (hasData() && previous != null && previous.hasData()) {
float timeDiff_ms = UintUtils.diff(wheelRevolutionsTime, previous.wheelRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);
if (timeDiff.isZero() || timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute speed.");
value = null;
return;
}
if (wheelRevolutionsCount < previous.wheelRevolutionsCount) {
Log.e(TAG, "Wheel revolutions count difference is invalid: cannot compute speed.");
return;
}
long wheelDiff = UintUtils.diff(wheelRevolutionsCount, previous.wheelRevolutionsCount, UintUtils.UINT32_MAX);
Distance distance = wheelCircumference.multipliedBy(wheelDiff);
Distance distanceOverall = distance;
if (previous.hasValue()) {
distanceOverall = distance.plus(previous.getValue().distanceOverall);
}
Speed speed_mps = Speed.of(distance, timeDiff);
value = new Data(distance, distanceOverall, speed_mps);
}
}
@Override
public void reset() {
if (value != null) {
value = new Data(value.distance, Distance.of(0), value.speed);
}
}
@NonNull
@Override
public String toString() {
return super.toString() + " data=" + value + " time=" + wheelRevolutionsTime + " count=" + wheelRevolutionsCount;
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof DistanceSpeed)) return false;
DistanceSpeed comp = (DistanceSpeed) obj;
if (!(hasData() && comp.hasData())) {
return false;
}
return getWheelRevolutionsCount() == comp.getWheelRevolutionsCount() && getWheelRevolutionsTime() == comp.getWheelRevolutionsTime();
}
public static class Data {
private final Distance distance;
private final Distance distanceOverall;
private final Speed speed;
private Data(Distance distance, Distance distanceOverall, Speed speed) {
this.distance = distance;
this.distanceOverall = distanceOverall;
this.speed = speed;
}
public Distance getDistance() {
return distance;
}
public Distance getDistanceOverall() {
return distanceOverall;
}
public Speed getSpeed() {
return speed;
}
@NonNull
@Override
public String toString() {
return "Data{" +
"distance=" + getDistance() +
", distance_overall=" + getDistanceOverall() +
", speed=" + getSpeed() +
'}';
}
}
}
public static class CadenceAndSpeed extends SensorData<Pair<CyclingCadence, DistanceSpeed>> {
public CadenceAndSpeed(String sensorAddress, String sensorName, @Nullable CyclingCadence cadence, @Nullable DistanceSpeed distanceSpeed) {
super(sensorAddress, sensorName);
this.value = new Pair<>(cadence, distanceSpeed);
}
public CyclingCadence getCadence() {
return this.value != null ? this.value.first : null;
}
public DistanceSpeed getDistanceSpeed() {
return this.value != null ? this.value.second : null;
}
@NonNull
@Override
protected Pair<CyclingCadence, DistanceSpeed> getNoneValue() {
return new Pair<>(null, null);
}
}
}
@@ -0,0 +1,88 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.time.Duration;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.sensors.UintUtils;
public class SensorDataCyclingCadence extends SensorData<Cadence> {
private final String TAG = SensorDataCyclingCadence.class.getSimpleName();
private final Long crankRevolutionsCount; // UINT32
private final Integer crankRevolutionsTime; // UINT16; 1/1024s
public SensorDataCyclingCadence(String sensorAddress) {
super(sensorAddress);
this.crankRevolutionsCount = null;
this.crankRevolutionsTime = null;
}
public SensorDataCyclingCadence(String sensorAddress, String sensorName, long crankRevolutionsCount, int crankRevolutionsTime) {
super(sensorAddress, sensorName);
this.crankRevolutionsCount = crankRevolutionsCount;
this.crankRevolutionsTime = crankRevolutionsTime;
}
public boolean hasData() {
return crankRevolutionsCount != null && crankRevolutionsTime != null;
}
public long getCrankRevolutionsCount() {
return crankRevolutionsCount;
}
public int getCrankRevolutionsTime() {
return crankRevolutionsTime;
}
@NonNull
@Override
protected Cadence getNoneValue() {
return Cadence.of(0);
}
public void compute(SensorDataCyclingCadence previous) {
if (hasData() && previous != null && previous.hasData()) {
float timeDiff_ms = UintUtils.diff(crankRevolutionsTime, previous.crankRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);
if (timeDiff.isZero() || timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute cadence.");
value = null;
return;
}
// TODO We have to treat with overflow according to the documentation: read https://github.com/OpenTracksApp/OpenTracks/pull/953#discussion_r711625268
if (crankRevolutionsCount < previous.crankRevolutionsCount) {
Log.e(TAG, "Crank revolutions count difference is invalid: cannot compute cadence.");
return;
}
long crankDiff = UintUtils.diff(crankRevolutionsCount, previous.crankRevolutionsCount, UintUtils.UINT32_MAX);
value = Cadence.of(crankDiff, timeDiff);
}
}
@NonNull
@Override
public String toString() {
return super.toString() + " cadence=" + value + " time=" + crankRevolutionsTime + " count=" + crankRevolutionsCount;
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof SensorDataCyclingCadence)) return false;
SensorDataCyclingCadence comp = (SensorDataCyclingCadence) obj;
if (hasData() && comp.hasData() == hasData()) {
return getCrankRevolutionsCount() == comp.getCrankRevolutionsCount() && getCrankRevolutionsTime() == comp.getCrankRevolutionsTime();
} else {
return false;
}
}
}
@@ -0,0 +1,27 @@
package de.dennisguse.opentracks.sensors.sensorData;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
public class SensorDataCyclingCadenceAndDistanceSpeed extends SensorData<Pair<SensorDataCyclingCadence, SensorDataCyclingDistanceSpeed>> {
public SensorDataCyclingCadenceAndDistanceSpeed(String sensorAddress, String sensorName, @Nullable SensorDataCyclingCadence cadence, @Nullable SensorDataCyclingDistanceSpeed distanceSpeed) {
super(sensorAddress, sensorName);
this.value = new Pair<>(cadence, distanceSpeed);
}
public SensorDataCyclingCadence getCadence() {
return this.value != null ? this.value.first : null;
}
public SensorDataCyclingDistanceSpeed getDistanceSpeed() {
return this.value != null ? this.value.second : null;
}
@NonNull
@Override
protected Pair<SensorDataCyclingCadence, SensorDataCyclingDistanceSpeed> getNoneValue() {
return new Pair<>(null, null);
}
}
@@ -0,0 +1,139 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.time.Duration;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.sensors.UintUtils;
public class SensorDataCyclingDistanceSpeed extends SensorData<SensorDataCyclingDistanceSpeed.Data> {
private final String TAG = SensorDataCyclingDistanceSpeed.class.getSimpleName();
private final Long wheelRevolutionsCount; // UINT32
private final Integer wheelRevolutionsTime; // UINT16; 1/1024s
public SensorDataCyclingDistanceSpeed(String sensorAddress) {
super(sensorAddress);
this.wheelRevolutionsCount = null;
this.wheelRevolutionsTime = null;
}
public SensorDataCyclingDistanceSpeed(String sensorAddress, String sensorName, long wheelRevolutionsCount, int wheelRevolutionsTime) {
super(sensorAddress, sensorName);
this.wheelRevolutionsCount = wheelRevolutionsCount;
this.wheelRevolutionsTime = wheelRevolutionsTime;
}
public boolean hasData() {
return wheelRevolutionsCount != null && wheelRevolutionsTime != null;
}
public long getWheelRevolutionsCount() {
return wheelRevolutionsCount;
}
public int getWheelRevolutionsTime() {
return wheelRevolutionsTime;
}
@NonNull
@Override
protected Data getNoneValue() {
if (value != null) {
return new Data(value.distance, value.distanceOverall, Speed.zero());
} else {
return new Data(Distance.of(0), Distance.of(0), Speed.zero());
}
}
public void compute(SensorDataCyclingDistanceSpeed previous, Distance wheelCircumference) {
if (hasData() && previous != null && previous.hasData()) {
float timeDiff_ms = UintUtils.diff(wheelRevolutionsTime, previous.wheelRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * 1000;
Duration timeDiff = Duration.ofMillis((long) timeDiff_ms);
if (timeDiff.isZero() || timeDiff.isNegative()) {
Log.e(TAG, "Timestamps difference is invalid: cannot compute speed.");
value = null;
return;
}
if (wheelRevolutionsCount < previous.wheelRevolutionsCount) {
Log.e(TAG, "Wheel revolutions count difference is invalid: cannot compute speed.");
return;
}
long wheelDiff = UintUtils.diff(wheelRevolutionsCount, previous.wheelRevolutionsCount, UintUtils.UINT32_MAX);
Distance distance = wheelCircumference.multipliedBy(wheelDiff);
Distance distanceOverall = distance;
if (previous.hasValue()) {
distanceOverall = distance.plus(previous.getValue().distanceOverall);
}
Speed speed_mps = Speed.of(distance, timeDiff);
value = new Data(distance, distanceOverall, speed_mps);
}
}
@Override
public void reset() {
if (value != null) {
value = new Data(value.distance, Distance.of(0), value.speed);
}
}
@NonNull
@Override
public String toString() {
return super.toString() + " data=" + value + " time=" + wheelRevolutionsTime + " count=" + wheelRevolutionsCount;
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof SensorDataCyclingDistanceSpeed)) return false;
SensorDataCyclingDistanceSpeed comp = (SensorDataCyclingDistanceSpeed) obj;
if (!(hasData() && comp.hasData())) {
return false;
}
return getWheelRevolutionsCount() == comp.getWheelRevolutionsCount() && getWheelRevolutionsTime() == comp.getWheelRevolutionsTime();
}
public static class Data {
private final Distance distance;
private final Distance distanceOverall;
private final Speed speed;
private Data(Distance distance, Distance distanceOverall, Speed speed) {
this.distance = distance;
this.distanceOverall = distanceOverall;
this.speed = speed;
}
public Distance getDistance() {
return distance;
}
public Distance getDistanceOverall() {
return distanceOverall;
}
public Speed getSpeed() {
return speed;
}
@NonNull
@Override
public String toString() {
return "Data{" +
"distance=" + getDistance() +
", distance_overall=" + getDistanceOverall() +
", speed=" + getSpeed() +
'}';
}
}
}
@@ -30,9 +30,9 @@ public class SensorDataCyclingPower extends SensorData<Power> {
public static class Data {
private final Power power;
private final SensorDataCycling.CyclingCadence cadence;
private final SensorDataCyclingCadence cadence;
public Data(Power power, @Nullable SensorDataCycling.CyclingCadence cadence) {
public Data(Power power, @Nullable SensorDataCyclingCadence cadence) {
this.power = power;
this.cadence = cadence;
}
@@ -41,7 +41,7 @@ public class SensorDataCyclingPower extends SensorData<Power> {
return power;
}
public SensorDataCycling.CyclingCadence getCadence() {
public SensorDataCyclingCadence getCadence() {
return cadence;
}
@@ -13,9 +13,9 @@ public final class SensorDataSet {
private SensorDataHeartRate heartRate;
private SensorDataCycling.CyclingCadence cyclingCadence;
private SensorDataCyclingCadence cyclingCadence;
private SensorDataCycling.DistanceSpeed cyclingDistanceSpeed;
private SensorDataCyclingDistanceSpeed cyclingDistanceSpeed;
private SensorDataCyclingPower cyclingPower;
@@ -64,11 +64,11 @@ public final class SensorDataSet {
return null;
}
public SensorDataCycling.CyclingCadence getCyclingCadence() {
public SensorDataCyclingCadence getCyclingCadence() {
return cyclingCadence;
}
public SensorDataCycling.DistanceSpeed getCyclingDistanceSpeed() {
public SensorDataCyclingDistanceSpeed getCyclingDistanceSpeed() {
return cyclingDistanceSpeed;
}
@@ -146,12 +146,12 @@ public final class SensorDataSet {
return;
}
if (type instanceof SensorDataCycling.CyclingCadence) {
this.cyclingCadence = (SensorDataCycling.CyclingCadence) data;
if (type instanceof SensorDataCyclingCadence) {
this.cyclingCadence = (SensorDataCyclingCadence) data;
return;
}
if (type instanceof SensorDataCycling.DistanceSpeed) {
this.cyclingDistanceSpeed = (SensorDataCycling.DistanceSpeed) data;
if (type instanceof SensorDataCyclingDistanceSpeed) {
this.cyclingDistanceSpeed = (SensorDataCyclingDistanceSpeed) data;
return;
}