diff --git a/MyTracks/res/values/do_not_translate.xml b/MyTracks/res/values/do_not_translate.xml
index 9454de3fc..17116204f 100644
--- a/MyTracks/res/values/do_not_translate.xml
+++ b/MyTracks/res/values/do_not_translate.xml
@@ -33,7 +33,7 @@ limitations under the License.
NONE
ANT
SRM_ANT_BRIDGE
- Polar
+ POLAR
ZEPHYR
diff --git a/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
index 87773b1df..043479139 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
@@ -19,8 +19,8 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
+import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
-import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
import com.google.android.maps.mytracks.R;
@@ -232,8 +232,8 @@ public class SettingsActivity extends PreferenceActivity {
private void updateSensorSettings(String sensorType) {
boolean usesBluetooth =
- getString(R.string.zephyr_sensor_type).equals(sensorType) ||
- getString(R.string.polar_sensor_type).equals(sensorType);
+ getString(R.string.zephyr_sensor_type).equals(sensorType)
+ || getString(R.string.polar_sensor_type).equals(sensorType);
findPreference(
getString(R.string.bluetooth_sensor_key)).setEnabled(usesBluetooth);
findPreference(
@@ -267,6 +267,9 @@ public class SettingsActivity extends PreferenceActivity {
final ListPreference minRequiredAccuracy =
(ListPreference) findPreference(
getString(R.string.min_required_accuracy_key));
+ final ListPreference splitFrequency =
+ (ListPreference) findPreference(
+ getString(R.string.split_frequency_key));
minRecordingDistance.setEntries(isMetric
? R.array.min_recording_distance_options
@@ -277,20 +280,11 @@ public class SettingsActivity extends PreferenceActivity {
minRequiredAccuracy.setEntries(isMetric
? R.array.min_required_accuracy_options
: R.array.min_required_accuracy_options_ft);
- setTaskOptions(isMetric, R.string.announcement_frequency_key);
- setTaskOptions(isMetric, R.string.split_frequency_key);
+ splitFrequency.setEntries(isMetric
+ ? R.array.split_frequency_options
+ : R.array.split_frequency_options_ft);
}
- /**
- * Set the user visible options for a periodic task.
- */
- private void setTaskOptions(boolean isMetric, int listId) {
- final ListPreference taskFrequency =
- (ListPreference) findPreference(getString(listId));
- taskFrequency.setEntries(isMetric
- ? R.array.task_frequency_options
- : R.array.task_frequency_options_ft);
- }
/**
* Configures preference actions related to bluetooth.
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/BluetoothConnectionManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/BluetoothConnectionManager.java
index 3f1c6ba27..8fbbdc44b 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/BluetoothConnectionManager.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/BluetoothConnectionManager.java
@@ -396,8 +396,7 @@ public class BluetoothConnectionManager {
// Send copy of the obtained bytes to the UI Activity.
// Avoids memory inconsistency issues.
- byte[] b = buffer.clone();
- handler.obtainMessage(MESSAGE_READ, bytes, -1, b)
+ handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer.clone())
.sendToTarget();
} catch (IOException e) {
Log.e(Constants.TAG, "disconnected", e);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarMessageParser.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarMessageParser.java
index ee11135a7..1e5620bfb 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarMessageParser.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarMessageParser.java
@@ -15,84 +15,98 @@
*/
package com.google.android.apps.mytracks.services.sensors;
-import android.util.Log;
-
-import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
/**
- * An implementation of a SensorData parser for Polar Wearlink Bluetooth HRM.
+ * An implementation of a Sensor MessageParser for Polar Wearlink Bluetooth HRM.
*
+ * Polar Bluetooth Wearlink packet example;
+ * Hdr Len Chk Seq Status HeartRate RRInterval_16-bits
+ * FE 08 F7 06 F1 48 03 64
+ * where;
+ * Hdr always = 254 (0xFE),
+ * Chk = 255 - Len
+ * Seq range 0 to 15
+ * Status = Upper nibble may be battery voltage
+ * bit 0 is Beat Detection flag.
+ *
+ * Additional packet examples;
+ * FE 08 F7 06 F1 48 03 64
+ * FE 0A F5 06 F1 48 03 64 03 70
+ *
* @author John R. Gerthoffer
*/
public class PolarMessageParser implements MessageParser {
- // Last Heart Rate value storage (in case of corrupt buffer)
+
private int lastHeartRate = 0;
+
+ /**
+ * Applies Polar packet validation rules to buffer.
+ * Polar packets are checked for following;
+ * offset 0 = header byte, 254 (0xFE).
+ * offset 1 = packet length byte, 8, 10, 12, 14.
+ * offset 2 = check byte, 255 - packet length.
+ * offset 3 = sequence byte, range from 0 to 15.
+ *
+ * @param an array of bytes to parse
+ * @param buffer offset to beginning of packet.
+ * @return whether buffer has a valid packet at offset i
+ */
+ private boolean packetValid (byte[] buffer, int i) {
+ boolean headerValid = (buffer[i] & 0xFF) == 0xFE;
+ boolean checkbyteValid = (buffer[i + 2] & 0xFF) == (0xFF - (buffer[i + 1] & 0xFF));
+ boolean sequenceValid = (buffer[i + 3] & 0xFF) < 16;
+
+ return headerValid && checkbyteValid && sequenceValid;
+ }
@Override
public Sensor.SensorDataSet parseBuffer(byte[] buffer) {
- StringBuilder sb = new StringBuilder();
+
int heartRate = 0;
+ boolean heartrateValid = false;
- // Due to a memory inconsistency issue, the packet does not always start at buffer[0].
- // While it works stepping thru in debug mode, it is not consistent when running real-time.
- // Note: After changing the BluetoothConnectionManager to pass a copy of 'buffer',
- // the problem was resolved! Passing a buffer copy in threaded comm's is typical in my experience.
-
// Minimum length Polar packets is 8, so stop search 8 bytes before buffer ends.
- heartRate = lastHeartRate; // Default to use last value. (If our buffer is corrupted).
for (int i = 0; i < buffer.length - 8; i++) {
- boolean bHdrOK = ((buffer[i] & 0xFF) == 0xFE);
- boolean bChkOK = ((buffer[i+2] & 0xFF) == (0xFF - (buffer[i+1] & 0xFF)));
- boolean bSeqOK = ((buffer[i+3] & 0xFF) < 16);
- boolean bStatusOK = ((buffer[i+4] & 0xFF) > 128); // I've seen 0xF1 or 0xE1.
-
- if (bHdrOK && bChkOK && bSeqOK && bStatusOK) {
+ heartrateValid = packetValid(buffer,i);
+ if (heartrateValid) {
heartRate = buffer[i + 5] & 0xFF;
- lastHeartRate = heartRate; // Remember good value for next time.
- break; // Let's go store our data.
+ break;
}
}
+ // If our buffer is corrupted, use decaying last good value.
+ if(!heartrateValid) {
+ heartRate = (int) (lastHeartRate * 0.8);
+ if(heartRate < 50)
+ heartRate = 0;
+ }
+
+ lastHeartRate = heartRate; // Remember good value for next time.
+
// Heart Rate
Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
.setValue(heartRate)
.setState(Sensor.SensorState.SENDING);
Sensor.SensorDataSet sds =
- Sensor.SensorDataSet.newBuilder()
- .setCreationTime(System.currentTimeMillis())
- .setHeartRate(b)
- .build();
+ Sensor.SensorDataSet.newBuilder()
+ .setCreationTime(System.currentTimeMillis())
+ .setHeartRate(b)
+ .build();
return sds;
}
/**
- * Applies packet validation rule to buffer
- * Parsing rule for a good Polar HRM packet;
- * boolean goodHdr = ((buffer[0] & 0xFF) == 0xFE);
- * boolean goodChk = ((buffer[2] & 0xFF) == (0xFF - (buffer[1] & 0xFF)));
- * goodPacket = goodHdr && goodChk;
+ * Applies packet validation rules to buffer
*
* @param an array of bytes to parse
* @return whether buffer has a valid packet starting at index zero
*/
@Override
public boolean isValid(byte[] buffer) {
- /**
- * Polar Bluetooth Wearlink packet example;
- * Hdr Len Chk Seq Status HeartRate RRInterval_16-bits
- * FE 08 F7 06 F1 48 03 64
- * where Hdr always = 0xFE, Chk = 0xFF - Len
- *
- * Additional packet examples;
- * FE 08 F7 06 F1 48 03 64
- * FE 0A F5 06 F1 48 03 64 03 70
- */
- boolean goodHdr = ((buffer[0] & 0xFF) == 0xFE);
- boolean goodChk = ((buffer[2] & 0xFF) == (0xFF - (buffer[1] & 0xFF)));
- return goodHdr && goodChk;
+ return packetValid(buffer,0);
}
/**
@@ -110,18 +124,15 @@ public class PolarMessageParser implements MessageParser {
/**
* Searches buffer for the beginning of a valid packet.
- * Parsing rule for a good Polar HRM packet;
- * boolean goodHdr = ((buffer[0] & 0xFF) == 0xFE);
- * boolean goodChk = ((buffer[2] & 0xFF) == (0xFF - (buffer[1] & 0xFF)));
- * goodPacket = goodHdr && goodChk;
*
* @param an array of bytes to parse
+ * @return index to beginning of good packet, or -1 if none found.
*/
@Override
public int findNextAlignment(byte[] buffer) {
// Minimum length Polar packets is 8, so stop search 8 bytes before buffer ends.
for (int i = 0; i < buffer.length - 8; i++) {
- if (((buffer[i] & 0xFF) == 0xFE) && ((buffer[i+2] & 0xFF) == (0xFF - (buffer[i+1] & 0xFF)))) {
+ if (packetValid(buffer,i)) {
return i;
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarSensorManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarSensorManager.java
index 7240cd316..d1d1f7441 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarSensorManager.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarSensorManager.java
@@ -18,7 +18,7 @@ package com.google.android.apps.mytracks.services.sensors;
import android.content.Context;
/**
- * PolarSensorManager - Straight copy from ZephyrSensorManager, renamed, of course.
+ * PolarSensorManager - A sensor manager for Polar heart rate monitors.
*/
public class PolarSensorManager extends BluetoothSensorManager {