forked from upstream-mirrors/OpenTracks
Merge with head.
This commit is contained in:
@@ -232,7 +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.zephyr_sensor_type).equals(sensorType)
|
||||
|| getString(R.string.polar_sensor_type).equals(sensorType);
|
||||
findPreference(
|
||||
getString(R.string.bluetooth_sensor_key)).setEnabled(usesBluetooth);
|
||||
findPreference(
|
||||
|
||||
+3
-2
@@ -394,8 +394,9 @@ public class BluetoothConnectionManager {
|
||||
|
||||
offset = 0;
|
||||
|
||||
// Send the obtained bytes to the UI Activity
|
||||
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
|
||||
// Send copy of the obtained bytes to the UI Activity.
|
||||
// Avoids memory inconsistency issues.
|
||||
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer.clone())
|
||||
.sendToTarget();
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "disconnected", e);
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2011 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 com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
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) {
|
||||
|
||||
int heartRate = 0;
|
||||
boolean heartrateValid = false;
|
||||
|
||||
// Minimum length Polar packets is 8, so stop search 8 bytes before buffer ends.
|
||||
for (int i = 0; i < buffer.length - 8; i++) {
|
||||
heartrateValid = packetValid(buffer,i);
|
||||
if (heartrateValid) {
|
||||
heartRate = buffer[i + 5] & 0xFF;
|
||||
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();
|
||||
|
||||
return sds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return packetValid(buffer,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polar uses variable packet sizes; 8, 10, 12, 14 and rarely 16.
|
||||
* The most frequent are 8 and 10.
|
||||
* We will wait for 16 bytes.
|
||||
* This way, we are assured of getting one good one.
|
||||
*
|
||||
* @return the size of buffer needed to parse a good packet
|
||||
*/
|
||||
@Override
|
||||
public int getFrameSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches buffer for the beginning of a valid packet.
|
||||
*
|
||||
* @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 (packetValid(buffer,i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2011 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 com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* PolarSensorManager - A sensor manager for Polar heart rate monitors.
|
||||
*/
|
||||
|
||||
public class PolarSensorManager extends BluetoothSensorManager {
|
||||
public PolarSensorManager(Context context) {
|
||||
super(context, new PolarMessageParser());
|
||||
}
|
||||
}
|
||||
+2
@@ -59,6 +59,8 @@ public class SensorManagerFactory {
|
||||
return new AntSRMSensorManager(context);
|
||||
} else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) {
|
||||
return new ZephyrSensorManager(context);
|
||||
} else if (sensor.equals(context.getString(R.string.polar_sensor_type))) {
|
||||
return new PolarSensorManager(context);
|
||||
} else {
|
||||
Log.w(Constants.TAG, "Unable to find sensor type: " + sensor);
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user