forked from upstream-mirrors/OpenTracks
added more comments + minor refactoring
This commit is contained in:
@@ -19,7 +19,7 @@ limitations under the License.
|
||||
<string name="allow_access_key">allowAccess</string>
|
||||
<string name="announcement_frequency_key">announcementFrequency</string>
|
||||
<string name="ant_cadence_sensor_id_key">antCadenceSensorId</string>
|
||||
<string name="ant_cadence_speed_sensor_id_key">antCadSpdSensorId</string>
|
||||
<string name="ant_cadence_speed_sensor_id_key">antCadenceSpeedSensorId</string>
|
||||
<string name="ant_heart_rate_sensor_id_key">antHeartRateSensorId</string>
|
||||
<string name="ant_srm_bridge_sensor_id_key">antSRMBridgeSensorId</string>
|
||||
<string name="auto_resume_track_timeout_key">autoResumeTrackTimeout</string>
|
||||
|
||||
+9
-9
@@ -200,13 +200,13 @@ public class AntDirectSensorManager extends AntSensorManager
|
||||
Log.i(TAG, "setup channel=" + channel + " deviceType=" + sensor.getDeviceType());
|
||||
|
||||
return setupAntSensorChannel(sensor.getNetworkNumber(),
|
||||
channel,
|
||||
sensor.getDeviceNumber(),
|
||||
sensor.getDeviceType(),
|
||||
(byte) 0x01,
|
||||
sensor.getChannelPeriod(),
|
||||
sensor.getFrequency(),
|
||||
(byte) 0);
|
||||
channel,
|
||||
sensor.getDeviceNumber(),
|
||||
sensor.getDeviceType(),
|
||||
(byte) 0x01,
|
||||
sensor.getChannelPeriod(),
|
||||
sensor.getFrequency(),
|
||||
(byte) 0);
|
||||
}
|
||||
|
||||
private void sendSensorData(byte index, int value) {
|
||||
@@ -242,11 +242,11 @@ public class AntDirectSensorManager extends AntSensorManager
|
||||
sensorData = b.setCreationTime(now).build();
|
||||
}
|
||||
|
||||
public void sendCadence(int value) {
|
||||
public void setCadence(int value) {
|
||||
sendSensorData(CADENCE_DATA_INDEX, value);
|
||||
}
|
||||
|
||||
public void sendHeartRate(int value) {
|
||||
public void setHeartRate(int value) {
|
||||
sendSensorData(HEART_RATE_DATA_INDEX, value);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -32,9 +32,9 @@ public abstract class AntSensorBase {
|
||||
public static final byte NETWORK_NUMBER = 1;
|
||||
public static final byte RF_FREQUENCY = 57;
|
||||
|
||||
protected short deviceNumber;
|
||||
private byte deviceType;
|
||||
private short channelPeriod;
|
||||
private short deviceNumber;
|
||||
private final byte deviceType;
|
||||
private final short channelPeriod;
|
||||
|
||||
AntSensorBase(short deviceNumber, byte deviceType,
|
||||
String deviceTypeString, short channelPeriod) {
|
||||
|
||||
+9
-4
@@ -17,14 +17,19 @@
|
||||
package com.google.android.apps.mytracks.services.sensors.ant;
|
||||
|
||||
/**
|
||||
* Interface for collecting data from the sensor classes
|
||||
*
|
||||
* Interface for collecting data from the sensors.
|
||||
* @author Laszlo Molnar
|
||||
*/
|
||||
|
||||
public interface AntSensorDataCollector {
|
||||
|
||||
public void sendCadence(int value);
|
||||
/**
|
||||
* Sets the current cadence to the value specified.
|
||||
*/
|
||||
void setCadence(int value);
|
||||
|
||||
public void sendHeartRate(int value);
|
||||
/**
|
||||
* Sets the current heart rate to the value specified.
|
||||
*/
|
||||
void setHeartRate(int value);
|
||||
}
|
||||
|
||||
+5
-5
@@ -17,7 +17,7 @@ package com.google.android.apps.mytracks.services.sensors.ant;
|
||||
|
||||
|
||||
/**
|
||||
* Cadence sensor.
|
||||
* Ant+ cadence sensor.
|
||||
*
|
||||
* @author Laszlo Molnar
|
||||
*/
|
||||
@@ -29,20 +29,20 @@ public class CadenceSensor extends AntSensorBase {
|
||||
public static final byte CADENCE_DEVICE_TYPE = 122;
|
||||
public static final short CADENCE_CHANNEL_PERIOD = 8102;
|
||||
|
||||
SensorDataProcessor cadence = new SensorDataProcessor();
|
||||
SensorDataProcessor dataProcessor = new SensorDataProcessor();
|
||||
|
||||
CadenceSensor(short devNum) {
|
||||
super(devNum, CADENCE_DEVICE_TYPE,
|
||||
"cadence sensor", CADENCE_CHANNEL_PERIOD);
|
||||
super(devNum, CADENCE_DEVICE_TYPE, "cadence sensor", CADENCE_CHANNEL_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an ANT+ cadence sensor message.
|
||||
* @param antMessage The byte array received from the cadence sensor.
|
||||
*/
|
||||
@Override
|
||||
public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) {
|
||||
int sensorTime = ((int) antMessage[5] & 0xFF) + ((int) antMessage[6] & 0xFF) * 256;
|
||||
int crankRevs = ((int) antMessage[7] & 0xFF) + ((int) antMessage[8] & 0xFF) * 256;
|
||||
c.sendCadence(cadence.getValue(crankRevs, sensorTime));
|
||||
c.setCadence(dataProcessor.getValue(crankRevs, sensorTime));
|
||||
}
|
||||
};
|
||||
|
||||
+5
-5
@@ -17,7 +17,7 @@ package com.google.android.apps.mytracks.services.sensors.ant;
|
||||
|
||||
|
||||
/**
|
||||
* Combined cadence and speed sensor.
|
||||
* Ant+ combined cadence and speed sensor.
|
||||
*
|
||||
* @author Laszlo Molnar
|
||||
*/
|
||||
@@ -29,20 +29,20 @@ public class CadenceSpeedSensor extends AntSensorBase {
|
||||
public static final byte CADENCE_SPEED_DEVICE_TYPE = 121;
|
||||
public static final short CADENCE_SPEED_CHANNEL_PERIOD = 8086;
|
||||
|
||||
SensorDataProcessor cadence = new SensorDataProcessor();
|
||||
SensorDataProcessor dataProcessor = new SensorDataProcessor();
|
||||
|
||||
CadenceSpeedSensor(short devNum) {
|
||||
super(devNum, CADENCE_SPEED_DEVICE_TYPE,
|
||||
"speed&cadence sensor", CADENCE_SPEED_CHANNEL_PERIOD);
|
||||
super(devNum, CADENCE_SPEED_DEVICE_TYPE, "speed&cadence sensor", CADENCE_SPEED_CHANNEL_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an ANT+ cadence&speed sensor message.
|
||||
* @param antMessage The byte array received from the sensor.
|
||||
*/
|
||||
@Override
|
||||
public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) {
|
||||
int sensorTime = ((int) antMessage[1] & 0xFF) + ((int) antMessage[2] & 0xFF) * 256;
|
||||
int crankRevs = ((int) antMessage[3] & 0xFF) + ((int) antMessage[4] & 0xFF) * 256;
|
||||
c.sendCadence(cadence.getValue(crankRevs, sensorTime));
|
||||
c.setCadence(dataProcessor.getValue(crankRevs, sensorTime));
|
||||
}
|
||||
};
|
||||
|
||||
+4
-4
@@ -20,7 +20,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Heart reate monitor sensor.
|
||||
* Ant+ heart reate monitor sensor.
|
||||
*
|
||||
* @author Laszlo Molnar
|
||||
*/
|
||||
@@ -33,17 +33,17 @@ public class HeartRateSensor extends AntSensorBase {
|
||||
public static final short HEART_RATE_CHANNEL_PERIOD = 8070;
|
||||
|
||||
HeartRateSensor(short devNum) {
|
||||
super(devNum, HEART_RATE_DEVICE_TYPE,
|
||||
"heart rate monitor", HEART_RATE_CHANNEL_PERIOD);
|
||||
super(devNum, HEART_RATE_DEVICE_TYPE, "heart rate monitor", HEART_RATE_CHANNEL_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an ANT+ heart rate monitor message.
|
||||
* @param antMessage The byte array received from the heart rate monitor.
|
||||
*/
|
||||
@Override
|
||||
public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) {
|
||||
int bpm = (int) antMessage[8] & 0xFF;
|
||||
Log.d(TAG, "now:" + System.currentTimeMillis() + " heart rate=" + bpm);
|
||||
c.sendHeartRate(bpm);
|
||||
c.setHeartRate(bpm);
|
||||
}
|
||||
};
|
||||
|
||||
+102
-45
@@ -20,7 +20,7 @@ import android.util.Log;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Processes an ANT sensor data (counter) + timestamp pair,
|
||||
* Processes an ANT+ sensor data (counter) + timestamp pair,
|
||||
* and returns the instantaneous value of the sensor
|
||||
*
|
||||
* @author Laszlo Molnar
|
||||
@@ -28,84 +28,141 @@ import java.util.LinkedList;
|
||||
public class SensorDataProcessor {
|
||||
|
||||
/**
|
||||
* History is used for looking back at the old data
|
||||
* when no new data is present, but an instantaneous value is needed
|
||||
* HistoryElement stores a time stamped sensor counter
|
||||
*/
|
||||
private class HistoryElement {
|
||||
public long sysTime;
|
||||
public int data;
|
||||
public int sensorTime;
|
||||
private static class HistoryElement {
|
||||
final long systemTime;
|
||||
final int data;
|
||||
final int sensorTime;
|
||||
|
||||
HistoryElement(long sys, int d, int sens) {
|
||||
sysTime = sys;
|
||||
data = d;
|
||||
sensorTime = sens;
|
||||
HistoryElement(long systemTime, int data, int sensorTime) {
|
||||
this.systemTime = systemTime;
|
||||
this.data = data;
|
||||
this.sensorTime = sensorTime;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Removes old data from the history.
|
||||
// Returns true if the remaining history is not empty.
|
||||
/**
|
||||
* Removes old data from the history.
|
||||
*
|
||||
* @param now the current system time
|
||||
* @return true if the remaining history is not empty
|
||||
*/
|
||||
protected boolean removeOldHistory(long now) {
|
||||
HistoryElement h;
|
||||
while ((h = history.peek()) != null) {
|
||||
if (now - h.sysTime <= historyLengthMillis) {
|
||||
// if the first element of the list is in our desired time range then return
|
||||
if (now - h.systemTime <= HISTORY_LENGTH_MILLIS) {
|
||||
return true;
|
||||
}
|
||||
// otherwise remove the too old element, and look at the next (newer) one
|
||||
history.removeFirst();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int counter = -1; // the latest counter value reported by the sensor
|
||||
private int actValue = 0;
|
||||
public static final int historyLengthMillis = 5000; // 5 sec
|
||||
/**
|
||||
* The latest counter value reported by the sensor
|
||||
*/
|
||||
private int counter = -1;
|
||||
|
||||
/**
|
||||
* The calculated instantaneous sensor value to be displayed
|
||||
*/
|
||||
private int displayedValue = 0;
|
||||
|
||||
private static final int ONE_SECOND_MILLIS = 1000;
|
||||
private static final int HISTORY_LENGTH_MILLIS = ONE_SECOND_MILLIS * 5;
|
||||
private static final int ONE_MINUTE_MILLIS = ONE_SECOND_MILLIS * 60;
|
||||
private static final int SENSOR_TIME_RESOLUTION = 1024; // in a second
|
||||
private static final int SENSOR_TIME_ONE_MINUTE = SENSOR_TIME_RESOLUTION * 60;
|
||||
|
||||
/**
|
||||
* History of previous sensor data - oldest first
|
||||
* only the latest HISTORY_LENGTH_MILLIS milliseconds of data is stored
|
||||
*/
|
||||
private LinkedList<HistoryElement> history = new LinkedList<HistoryElement>();
|
||||
|
||||
/**
|
||||
* Calculates the instantaneous sensor value to be displayed
|
||||
* using the history when the sensor only resends the old data
|
||||
*/
|
||||
private int getValueFromHistory(int data, long now) {
|
||||
if (!removeOldHistory(now)) {
|
||||
// there is nothing in the history, return 0
|
||||
return displayedValue = 0;
|
||||
}
|
||||
HistoryElement f = history.getFirst();
|
||||
HistoryElement l = history.getLast();
|
||||
int sensorTimeChange = (l.sensorTime - f.sensorTime) & 0xFFFF;
|
||||
int counterChange = (data - f.data) & 0xFFFF;
|
||||
|
||||
// difference between now and systemTime of the oldest history entry
|
||||
// for better precision sensor timestamps are considered between
|
||||
// the first and the last history entry (could be overkill)
|
||||
int systemTimeChange = (int) (now - l.systemTime
|
||||
+ (sensorTimeChange * ONE_SECOND_MILLIS) / SENSOR_TIME_RESOLUTION);
|
||||
|
||||
// displayedValue is not overwritten by this calculated value
|
||||
// because it is still needed when a new sensor event arrives
|
||||
int v = (counterChange * ONE_MINUTE_MILLIS) / systemTimeChange;
|
||||
Log.d(TAG, "getValue returns (2):" + v);
|
||||
|
||||
// do not return larger number than displayedValue
|
||||
return v < displayedValue ? v : displayedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the instantaneous sensor value to be displayed
|
||||
*
|
||||
* @param data sensor reported counter value
|
||||
* @param sensorTime sensor reported timestamp
|
||||
* @return the calculated value
|
||||
*/
|
||||
public int getValue(int data, int sensorTime) {
|
||||
long now = System.currentTimeMillis();
|
||||
int dDelta = (data - counter) & 0xFFFF;
|
||||
int counterChange = (data - counter) & 0xFFFF;
|
||||
|
||||
Log.d(TAG, "now=" + now + " data=" + data + " sensortime=" + sensorTime);
|
||||
|
||||
if (counter < 0) {
|
||||
// store the actual counter value from the sensor
|
||||
// store the initial counter value reported by the sensor
|
||||
// the timestamp is probably out of date, so the history is not updated
|
||||
counter = data;
|
||||
return actValue = 0;
|
||||
return displayedValue = 0;
|
||||
}
|
||||
counter = data;
|
||||
|
||||
if (dDelta != 0) {
|
||||
if (counterChange != 0) {
|
||||
// if new data is arrived from the sensor ...
|
||||
if (removeOldHistory(now)) {
|
||||
// ... and the history is not empty, then use the latest entry
|
||||
HistoryElement h = history.getLast();
|
||||
actValue = ((int) ((data - h.data) & 0xFFFF)) * 1024 * 60
|
||||
/ (int) ((sensorTime - h.sensorTime) & 0xFFFF);
|
||||
int sensorTimeChange = (sensorTime - h.sensorTime) & 0xFFFF;
|
||||
counterChange = (data - h.data) & 0xFFFF;
|
||||
displayedValue = counterChange * SENSOR_TIME_ONE_MINUTE / sensorTimeChange;
|
||||
}
|
||||
history.addLast(new HistoryElement(now, data, sensorTime));
|
||||
} else if (!history.isEmpty()) {
|
||||
HistoryElement h = history.getLast();
|
||||
if (60000 < (now - h.sysTime) * actValue) {
|
||||
if (!removeOldHistory(now)) {
|
||||
actValue = 0;
|
||||
} else {
|
||||
HistoryElement f = history.getFirst();
|
||||
HistoryElement l = history.getLast();
|
||||
int sDelta = (l.sensorTime - f.sensorTime) & 0xFFFF;
|
||||
int cDelta = (data - f.data) & 0xFFFF;
|
||||
// the sensor has resent an old (counter,timestamp) pair,
|
||||
// but the history is not empty
|
||||
|
||||
// the saved actValue is not overwritten by this
|
||||
// the returned value is computed from the history
|
||||
int v = (int) (cDelta * 60 * 1000 / (now - l.sysTime + (sDelta / 1024) * 1000));
|
||||
Log.d(TAG, "getValue returns (2):" + v);
|
||||
return v < actValue ? v : actValue;
|
||||
}
|
||||
} else {
|
||||
// the current actValue is still valid, nothing to do here
|
||||
}
|
||||
HistoryElement h = history.getLast();
|
||||
if (ONE_MINUTE_MILLIS < (now - h.systemTime) * displayedValue) {
|
||||
// Too much time has passed since the last counter change.
|
||||
// This means that a smaller value than displayedValue must be
|
||||
// returned. So the history is looked up, and a calculated
|
||||
// average number is returned.
|
||||
// Note, that displayedValue is NOT updated unless the history
|
||||
// is empty or contains outdated entries. In that case it is zeroed.
|
||||
return getValueFromHistory(data, now);
|
||||
} // else the current displayedValue is still valid, nothing to do here
|
||||
} else {
|
||||
actValue = 0;
|
||||
// no new data from the sensor & the history is empty -> return 0
|
||||
displayedValue = 0;
|
||||
}
|
||||
|
||||
Log.d(TAG, "getValue returns:" + actValue);
|
||||
return actValue;
|
||||
Log.d(TAG, "getValue returns:" + displayedValue);
|
||||
return displayedValue;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user