added more comments + minor refactoring

This commit is contained in:
ml1050
2012-01-21 21:35:58 +01:00
parent bee9f46eaf
commit b0afea35ee
8 changed files with 138 additions and 76 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ limitations under the License.
<string name="allow_access_key">allowAccess</string> <string name="allow_access_key">allowAccess</string>
<string name="announcement_frequency_key">announcementFrequency</string> <string name="announcement_frequency_key">announcementFrequency</string>
<string name="ant_cadence_sensor_id_key">antCadenceSensorId</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_heart_rate_sensor_id_key">antHeartRateSensorId</string>
<string name="ant_srm_bridge_sensor_id_key">antSRMBridgeSensorId</string> <string name="ant_srm_bridge_sensor_id_key">antSRMBridgeSensorId</string>
<string name="auto_resume_track_timeout_key">autoResumeTrackTimeout</string> <string name="auto_resume_track_timeout_key">autoResumeTrackTimeout</string>
@@ -200,13 +200,13 @@ public class AntDirectSensorManager extends AntSensorManager
Log.i(TAG, "setup channel=" + channel + " deviceType=" + sensor.getDeviceType()); Log.i(TAG, "setup channel=" + channel + " deviceType=" + sensor.getDeviceType());
return setupAntSensorChannel(sensor.getNetworkNumber(), return setupAntSensorChannel(sensor.getNetworkNumber(),
channel, channel,
sensor.getDeviceNumber(), sensor.getDeviceNumber(),
sensor.getDeviceType(), sensor.getDeviceType(),
(byte) 0x01, (byte) 0x01,
sensor.getChannelPeriod(), sensor.getChannelPeriod(),
sensor.getFrequency(), sensor.getFrequency(),
(byte) 0); (byte) 0);
} }
private void sendSensorData(byte index, int value) { private void sendSensorData(byte index, int value) {
@@ -242,11 +242,11 @@ public class AntDirectSensorManager extends AntSensorManager
sensorData = b.setCreationTime(now).build(); sensorData = b.setCreationTime(now).build();
} }
public void sendCadence(int value) { public void setCadence(int value) {
sendSensorData(CADENCE_DATA_INDEX, value); sendSensorData(CADENCE_DATA_INDEX, value);
} }
public void sendHeartRate(int value) { public void setHeartRate(int value) {
sendSensorData(HEART_RATE_DATA_INDEX, value); sendSensorData(HEART_RATE_DATA_INDEX, value);
} }
} }
@@ -32,9 +32,9 @@ public abstract class AntSensorBase {
public static final byte NETWORK_NUMBER = 1; public static final byte NETWORK_NUMBER = 1;
public static final byte RF_FREQUENCY = 57; public static final byte RF_FREQUENCY = 57;
protected short deviceNumber; private short deviceNumber;
private byte deviceType; private final byte deviceType;
private short channelPeriod; private final short channelPeriod;
AntSensorBase(short deviceNumber, byte deviceType, AntSensorBase(short deviceNumber, byte deviceType,
String deviceTypeString, short channelPeriod) { String deviceTypeString, short channelPeriod) {
@@ -17,14 +17,19 @@
package com.google.android.apps.mytracks.services.sensors.ant; 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 * @author Laszlo Molnar
*/ */
public interface AntSensorDataCollector { 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);
} }
@@ -17,7 +17,7 @@ package com.google.android.apps.mytracks.services.sensors.ant;
/** /**
* Cadence sensor. * Ant+ cadence sensor.
* *
* @author Laszlo Molnar * @author Laszlo Molnar
*/ */
@@ -29,20 +29,20 @@ public class CadenceSensor extends AntSensorBase {
public static final byte CADENCE_DEVICE_TYPE = 122; public static final byte CADENCE_DEVICE_TYPE = 122;
public static final short CADENCE_CHANNEL_PERIOD = 8102; public static final short CADENCE_CHANNEL_PERIOD = 8102;
SensorDataProcessor cadence = new SensorDataProcessor(); SensorDataProcessor dataProcessor = new SensorDataProcessor();
CadenceSensor(short devNum) { CadenceSensor(short devNum) {
super(devNum, CADENCE_DEVICE_TYPE, super(devNum, CADENCE_DEVICE_TYPE, "cadence sensor", CADENCE_CHANNEL_PERIOD);
"cadence sensor", CADENCE_CHANNEL_PERIOD);
} }
/** /**
* Decode an ANT+ cadence sensor message. * Decode an ANT+ cadence sensor message.
* @param antMessage The byte array received from the cadence sensor. * @param antMessage The byte array received from the cadence sensor.
*/ */
@Override
public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) { public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) {
int sensorTime = ((int) antMessage[5] & 0xFF) + ((int) antMessage[6] & 0xFF) * 256; int sensorTime = ((int) antMessage[5] & 0xFF) + ((int) antMessage[6] & 0xFF) * 256;
int crankRevs = ((int) antMessage[7] & 0xFF) + ((int) antMessage[8] & 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));
} }
}; };
@@ -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 * @author Laszlo Molnar
*/ */
@@ -29,20 +29,20 @@ public class CadenceSpeedSensor extends AntSensorBase {
public static final byte CADENCE_SPEED_DEVICE_TYPE = 121; public static final byte CADENCE_SPEED_DEVICE_TYPE = 121;
public static final short CADENCE_SPEED_CHANNEL_PERIOD = 8086; public static final short CADENCE_SPEED_CHANNEL_PERIOD = 8086;
SensorDataProcessor cadence = new SensorDataProcessor(); SensorDataProcessor dataProcessor = new SensorDataProcessor();
CadenceSpeedSensor(short devNum) { CadenceSpeedSensor(short devNum) {
super(devNum, CADENCE_SPEED_DEVICE_TYPE, super(devNum, CADENCE_SPEED_DEVICE_TYPE, "speed&cadence sensor", CADENCE_SPEED_CHANNEL_PERIOD);
"speed&cadence sensor", CADENCE_SPEED_CHANNEL_PERIOD);
} }
/** /**
* Decode an ANT+ cadence&speed sensor message. * Decode an ANT+ cadence&speed sensor message.
* @param antMessage The byte array received from the sensor. * @param antMessage The byte array received from the sensor.
*/ */
@Override
public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) { public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) {
int sensorTime = ((int) antMessage[1] & 0xFF) + ((int) antMessage[2] & 0xFF) * 256; int sensorTime = ((int) antMessage[1] & 0xFF) + ((int) antMessage[2] & 0xFF) * 256;
int crankRevs = ((int) antMessage[3] & 0xFF) + ((int) antMessage[4] & 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));
} }
}; };
@@ -20,7 +20,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import android.util.Log; import android.util.Log;
/** /**
* Heart reate monitor sensor. * Ant+ heart reate monitor sensor.
* *
* @author Laszlo Molnar * @author Laszlo Molnar
*/ */
@@ -33,17 +33,17 @@ public class HeartRateSensor extends AntSensorBase {
public static final short HEART_RATE_CHANNEL_PERIOD = 8070; public static final short HEART_RATE_CHANNEL_PERIOD = 8070;
HeartRateSensor(short devNum) { HeartRateSensor(short devNum) {
super(devNum, HEART_RATE_DEVICE_TYPE, super(devNum, HEART_RATE_DEVICE_TYPE, "heart rate monitor", HEART_RATE_CHANNEL_PERIOD);
"heart rate monitor", HEART_RATE_CHANNEL_PERIOD);
} }
/** /**
* Decode an ANT+ heart rate monitor message. * Decode an ANT+ heart rate monitor message.
* @param antMessage The byte array received from the heart rate monitor. * @param antMessage The byte array received from the heart rate monitor.
*/ */
@Override
public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) { public void handleBroadcastData(byte[] antMessage, AntSensorDataCollector c) {
int bpm = (int) antMessage[8] & 0xFF; int bpm = (int) antMessage[8] & 0xFF;
Log.d(TAG, "now:" + System.currentTimeMillis() + " heart rate=" + bpm); Log.d(TAG, "now:" + System.currentTimeMillis() + " heart rate=" + bpm);
c.sendHeartRate(bpm); c.setHeartRate(bpm);
} }
}; };
@@ -20,7 +20,7 @@ import android.util.Log;
import java.util.LinkedList; 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 * and returns the instantaneous value of the sensor
* *
* @author Laszlo Molnar * @author Laszlo Molnar
@@ -28,84 +28,141 @@ import java.util.LinkedList;
public class SensorDataProcessor { public class SensorDataProcessor {
/** /**
* History is used for looking back at the old data * HistoryElement stores a time stamped sensor counter
* when no new data is present, but an instantaneous value is needed
*/ */
private class HistoryElement { private static class HistoryElement {
public long sysTime; final long systemTime;
public int data; final int data;
public int sensorTime; final int sensorTime;
HistoryElement(long sys, int d, int sens) { HistoryElement(long systemTime, int data, int sensorTime) {
sysTime = sys; this.systemTime = systemTime;
data = d; this.data = data;
sensorTime = sens; 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) { protected boolean removeOldHistory(long now) {
HistoryElement h; HistoryElement h;
while ((h = history.peek()) != null) { 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; return true;
} }
// otherwise remove the too old element, and look at the next (newer) one
history.removeFirst(); history.removeFirst();
} }
return false; return false;
} }
private int counter = -1; // the latest counter value reported by the sensor /**
private int actValue = 0; * The latest counter value reported by the sensor
public static final int historyLengthMillis = 5000; // 5 sec */
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>(); 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) { public int getValue(int data, int sensorTime) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
int dDelta = (data - counter) & 0xFFFF; int counterChange = (data - counter) & 0xFFFF;
Log.d(TAG, "now=" + now + " data=" + data + " sensortime=" + sensorTime); Log.d(TAG, "now=" + now + " data=" + data + " sensortime=" + sensorTime);
if (counter < 0) { 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; counter = data;
return actValue = 0; return displayedValue = 0;
} }
counter = data; counter = data;
if (dDelta != 0) { if (counterChange != 0) {
// if new data is arrived from the sensor ...
if (removeOldHistory(now)) { if (removeOldHistory(now)) {
// ... and the history is not empty, then use the latest entry
HistoryElement h = history.getLast(); HistoryElement h = history.getLast();
actValue = ((int) ((data - h.data) & 0xFFFF)) * 1024 * 60 int sensorTimeChange = (sensorTime - h.sensorTime) & 0xFFFF;
/ (int) ((sensorTime - h.sensorTime) & 0xFFFF); counterChange = (data - h.data) & 0xFFFF;
displayedValue = counterChange * SENSOR_TIME_ONE_MINUTE / sensorTimeChange;
} }
history.addLast(new HistoryElement(now, data, sensorTime)); history.addLast(new HistoryElement(now, data, sensorTime));
} else if (!history.isEmpty()) { } else if (!history.isEmpty()) {
HistoryElement h = history.getLast(); // the sensor has resent an old (counter,timestamp) pair,
if (60000 < (now - h.sysTime) * actValue) { // but the history is not empty
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 saved actValue is not overwritten by this HistoryElement h = history.getLast();
// the returned value is computed from the history if (ONE_MINUTE_MILLIS < (now - h.systemTime) * displayedValue) {
int v = (int) (cDelta * 60 * 1000 / (now - l.sysTime + (sDelta / 1024) * 1000)); // Too much time has passed since the last counter change.
Log.d(TAG, "getValue returns (2):" + v); // This means that a smaller value than displayedValue must be
return v < actValue ? v : actValue; // returned. So the history is looked up, and a calculated
} // average number is returned.
} else { // Note, that displayedValue is NOT updated unless the history
// the current actValue is still valid, nothing to do here // 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 { } else {
actValue = 0; // no new data from the sensor & the history is empty -> return 0
displayedValue = 0;
} }
Log.d(TAG, "getValue returns:" + actValue); Log.d(TAG, "getValue returns:" + displayedValue);
return actValue; return displayedValue;
} }
} }