Refactoring package structure.

Part of #963.
This commit is contained in:
Dennis Guse
2022-01-12 22:57:35 +01:00
parent a9f1381dae
commit 58b1396d64
20 changed files with 28 additions and 34 deletions
@@ -1,181 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.util;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
import de.dennisguse.opentracks.content.sensor.SensorDataRunning;
/**
* Utilities for dealing with bluetooth devices.
*
* @author Rodrigo Damazio
*/
public class BluetoothUtils {
public static final UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = new UUID(0x290200001000L, 0x800000805f9b34fbL);
public static final UUID HEART_RATE_SERVICE_UUID = new UUID(0x180D00001000L, 0x800000805f9b34fbL);
public static final UUID HEART_RATE_MEASUREMENT_CHAR_UUID = new UUID(0x2A3700001000L, 0x800000805f9b34fbL);
public static final List<UUID> HEART_RATE_SUPPORTING_DEVICES = Collections.unmodifiableList(Arrays.asList(
BluetoothUtils.HEART_RATE_SERVICE_UUID,
//Devices that support HEART_RATE_SERVICE_UUID, but do not announce HEART_RATE_SERVICE_UUID in there BLE announcement messages (during device discovery).
UUID.fromString("0000fee0-0000-1000-8000-00805f9b34fb") //Miband3
));
public static final UUID CYCLING_POWER_UUID = new UUID(0x181800001000L, 0x800000805f9b34fbL);
public static final UUID CYCLING_POWER_MEASUREMENT_CHAR_UUID = new UUID(0x2A6300001000L, 0x800000805f9b34fbL);
public static final UUID CYCLING_SPEED_CADENCE_SERVICE_UUID = new UUID(0x181600001000L, 0x800000805f9b34fbL);
public static final UUID CYCLING_SPEED_CADENCE_MEASUREMENT_CHAR_UUID = new UUID(0x2A5B00001000L, 0x800000805f9b34fbL);
public static final UUID RUNNING_RUNNING_SPEED_CADENCE_UUID = new UUID(0x181400001000L, 0x800000805f9b34fbL);
public static final UUID RUNNING_RUNNING_SPEED_CADENCE_CHAR_UUID = new UUID(0x2A5300001000L, 0x800000805f9b34fbL);
private static final String TAG = BluetoothUtils.class.getSimpleName();
private BluetoothUtils() {
}
public static BluetoothAdapter getAdapter(Context context) {
BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager == null) {
Log.i(TAG, "BluetoothManager not available.");
return null;
} else {
return bluetoothManager.getAdapter();
}
}
public static boolean hasBluetooth(Context context) {
return BluetoothUtils.getAdapter(context) != null;
}
public static Integer parseHeartRate(BluetoothGattCharacteristic characteristic) {
//DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.heart_rate_measurement.xml
byte[] raw = characteristic.getValue();
if (raw.length == 0) {
return null;
}
boolean formatUINT16 = ((raw[0] & 0x1) == 1);
if (formatUINT16 && raw.length >= 3) {
return characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 1);
}
if (!formatUINT16 && raw.length >= 2) {
return characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1);
}
return null;
}
public static Integer parseCyclingPower(BluetoothGattCharacteristic characteristic) {
// DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.cycling_power_measurement.xml
int valueLength = characteristic.getValue().length;
if (valueLength < 4) {
return null;
}
return characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, 2);
}
public static SensorDataCycling.CadenceAndSpeed 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) {
return null;
}
int flags = characteristic.getValue()[0];
boolean hasWheel = (flags & 0x01) > 0;
boolean hasCrank = (flags & 0x02) > 0;
int index = 1;
SensorDataCycling.DistanceSpeed 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);
index += 2;
}
SensorDataCycling.Cadence 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.Cadence(address, sensorName, crankCount, crankTime);
}
return new SensorDataCycling.CadenceAndSpeed(address, sensorName, cadence, speed);
}
public static SensorDataRunning parseRunningSpeedAndCadence(String address, String sensorName, @NonNull BluetoothGattCharacteristic characteristic) {
// DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.rsc_measurement.xml
int valueLength = characteristic.getValue().length;
if (valueLength == 0) {
return null;
}
int flags = characteristic.getValue()[0];
boolean hasStrideLength = (flags & 0x01) > 0;
boolean hasTotalDistance = (flags & 0x02) > 0;
boolean hasStatus = (flags & 0x03) > 0; // walking vs running
Speed speed = null;
Float cadence = null;
Distance totalDistance = null;
int index = 1;
if (valueLength - index >= 2) {
speed = Speed.of(characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index) / 256f);
}
index = 3;
if (valueLength - index >= 1) {
cadence = Float.valueOf(characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, index));
}
index = 4;
if (hasStrideLength && valueLength - index >= 2) {
Distance strideDistance = Distance.ofCM(characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index));
index += 2;
}
if (hasTotalDistance && valueLength - index >= 4) {
totalDistance = Distance.ofDM(characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, index));
}
return new SensorDataRunning(address, sensorName, speed, cadence, totalDistance);
}
}
@@ -1,84 +0,0 @@
package de.dennisguse.opentracks.util;
import android.hardware.SensorManager;
import androidx.annotation.VisibleForTesting;
public class PressureSensorUtils {
//Everything above is considered a meaningful change in altitude.
private static final float ALTITUDE_CHANGE_DIFF_M = 3.0f;
private static final float EXPONENTIAL_SMOOTHING = 0.3f;
private static final float p0 = SensorManager.PRESSURE_STANDARD_ATMOSPHERE;
private PressureSensorUtils() {
}
public static class AltitudeChange {
private final float currentSensorValue_hPa;
private final float altitudeChange_m;
public AltitudeChange(float currentSensorValue_hPa, float altitudeChange_m) {
this.currentSensorValue_hPa = currentSensorValue_hPa;
this.altitudeChange_m = altitudeChange_m;
}
public float getCurrentSensorValue_hPa() {
return currentSensorValue_hPa;
}
public float getAltitudeChange_m() {
return altitudeChange_m;
}
public float getAltitudeGain_m() {
return altitudeChange_m > 0 ? altitudeChange_m : 0;
}
public float getAltitudeLoss_m() {
return altitudeChange_m < 0 ? -1 * altitudeChange_m : 0;
}
}
/**
* Applies exponential smoothing to sensor value before computation.
*/
public static AltitudeChange computeChangesWithSmoothing_m(float lastAcceptedSensorValue_hPa, float lastSeenSensorValue_hPa, float currentSensorValue_hPa) {
float nextSensorValue_hPa = EXPONENTIAL_SMOOTHING * currentSensorValue_hPa + (1 - EXPONENTIAL_SMOOTHING) * lastSeenSensorValue_hPa;
return computeChanges(lastAcceptedSensorValue_hPa, nextSensorValue_hPa);
}
@VisibleForTesting
public static AltitudeChange computeChanges(float lastAcceptedSensorValue_hPa, float currentSensorValue_hPa) {
float lastSensorValue_m = SensorManager.getAltitude(p0, lastAcceptedSensorValue_hPa);
float currentSensorValue_m = SensorManager.getAltitude(p0, currentSensorValue_hPa);
float altitudeChange_m = currentSensorValue_m - lastSensorValue_m;
if (Math.abs(altitudeChange_m) < ALTITUDE_CHANGE_DIFF_M) {
return null;
}
// Limit altitudeC change by ALTITUDE_CHANGE_DIFF and computes pressure value accordingly.
AltitudeChange altitudeChange = new AltitudeChange(currentSensorValue_hPa, altitudeChange_m);
if (altitudeChange.getAltitudeChange_m() > 0) {
return new AltitudeChange(getBarometricPressure(lastSensorValue_m + ALTITUDE_CHANGE_DIFF_M), ALTITUDE_CHANGE_DIFF_M);
} else {
return new AltitudeChange(getBarometricPressure(lastSensorValue_m - ALTITUDE_CHANGE_DIFF_M), -1 * ALTITUDE_CHANGE_DIFF_M);
}
}
/*
* Barometeric pressure to altitude estimation; inverts of SensorManager.getAltitude(float, float)
* https://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Internationale_H%C3%B6henformel
* {\color{White} p(h)} = p_0 \cdot \left( 1 - \frac{0{,}0065 \frac{\mathrm K}{\mathrm m} \cdot h}{T_0\ } \right)^{5{,}255}
*/
@VisibleForTesting
public static float getBarometricPressure(float altitude_m) {
return (float) (p0 * Math.pow(1.0 - 0.0065 * altitude_m / 288.15, 5.255f));
}
}
@@ -1,30 +0,0 @@
package de.dennisguse.opentracks.util;
public class UintUtils {
public static final int UINT16_MAX = 0xFFFF;
public static final long UINT32_MAX = 0xFFFFFFFFL;
private UintUtils() {
}
/**
* Computes a - b for UINT with overflow (b < a).
*
* @return diff
*/
public static long diff(long a, long b, final long UINT_MAX) {
if (a < 0 || b < 0) {
throw new RuntimeException("a or b cannot be less than zero.");
}
if (a > UINT_MAX || b > UINT_MAX) {
throw new RuntimeException("a or b are outside of the allowed range.");
}
if (a >= b) {
return a - b;
}
return (UINT_MAX - b) + a;
}
}
@@ -1,65 +0,0 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.util;
/**
* Unit conversion constants.
*
* @author Sandor Dornbush
*/
public class UnitConversions {
// Time //TODO Use Duration
// multiplication factor to convert seconds to milliseconds
public static final long S_TO_MS = 1000;
// multiplication factor to convert milliseconds to seconds
@Deprecated
public static final double MS_TO_S = 1d / S_TO_MS;
// multiplication factor to convert minutes to seconds
@Deprecated
public static final double MIN_TO_S = 60.0;
// multiplication factor to convert seconds to minutes
@Deprecated
public static final double S_TO_MIN = 1 / MIN_TO_S;
// multiplication factor to convert minutes to hours
@Deprecated
public static final double MIN_TO_HR = 1 / 60.0;
// multiplication factor to convert kilometers to miles
public static final double KM_TO_MI = 0.621371192;
// Distance //TODO Make private to Distance class!
// multiplication factor to convert miles to feet
private static final double MI_TO_FT = 5280.0;
// multiplication factor to covert kilometers to meters
public static final double KM_TO_M = 1000.0;
// multiplication factor to convert meters to kilometers
public static final double M_TO_KM = 1 / KM_TO_M;
// multiplication factor to convert meters to miles
public static final double M_TO_MI = M_TO_KM * KM_TO_MI;
// multiplication factor to convert meters to feet
public static final double M_TO_FT = M_TO_MI * MI_TO_FT;
// multiplication factor to convert meters per second to kilometers per hour
public static final double MPS_TO_KMH = M_TO_KM / (S_TO_MIN * MIN_TO_HR);
// multiplication factor to convert miles to km
public static final double MI_TO_KM = 1 / KM_TO_MI;
// multiplication factor to convert miles to m
public static final double MI_TO_M = MI_TO_KM * KM_TO_M;
private UnitConversions() {
}
}