forked from upstream-mirrors/OpenTracks
Merge with head.
This commit is contained in:
@@ -284,11 +284,4 @@ limitations under the License.
|
||||
<item>punt de referència</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Cap</item>
|
||||
<item>ANT+ Sensors</item>
|
||||
<item>SRM ANT+ Bridge</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -409,4 +409,6 @@ limitations under the License.
|
||||
<string name="searching">S\'està cercant</string>
|
||||
<string name="sending">S\'està enviant</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Cap</string>
|
||||
</resources>
|
||||
|
||||
@@ -143,11 +143,4 @@ limitations under the License.
|
||||
<item>camino</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Ninguna</item>
|
||||
<item>ANT+ Sensores</item>
|
||||
<item>SRM ANT+ Puente</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -128,4 +128,8 @@ limitations under the License.
|
||||
$6 : Speed units (mph) : Pace units (per mile)
|
||||
-->
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Ninguna</string>
|
||||
<string name="ant_sensor_option">ANT+ Sensores</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ Puente</string>
|
||||
</resources>
|
||||
|
||||
@@ -291,11 +291,4 @@ limitations under the License.
|
||||
<item>point de passage</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Aucun</item>
|
||||
<item>Capteur ANT+</item>
|
||||
<item>Pont SRM ANT+</item>
|
||||
<item>Bluetooth Zephyr</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -397,6 +397,13 @@ limitations under the License.
|
||||
<string name="searching">Recherche</string>
|
||||
<string name="sending">Envoi</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Aucun</string>
|
||||
<string name="ant_sensor_option">Capteur ANT+</string>
|
||||
<string name="ant_bridge_sensor_option">Pont SRM ANT+</string>
|
||||
<string name="polar_bt_sensor_option">Bluetooth Polar</string>
|
||||
<string name="zephyr_bt_sensor_option">Bluetooth Zephyr</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">notifications lors de l\'enregistrement de parcours</string>
|
||||
<string name="read_tracks_permission_label">lecture des parcours enregistrés</string>
|
||||
|
||||
@@ -272,11 +272,4 @@ limitations under the License.
|
||||
<item>ウェイポイント</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>なし</item>
|
||||
<item>ANT+ センサー</item>
|
||||
<item>SRM ANT+ ブリッジ</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -463,6 +463,11 @@ limitations under the License.
|
||||
<string name="searching">検索中</string>
|
||||
<string name="sending">送信中</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">なし</string>
|
||||
<string name="ant_sensor_option">ANT+ センサー</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ ブリッジ</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">トラック記録通知受信</string>
|
||||
<string name="read_tracks_permission_label">トラック読み込み</string>
|
||||
|
||||
@@ -272,11 +272,4 @@ limitations under the License.
|
||||
<item>путевая точка</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Нет</item>
|
||||
<item>ANT+ Sensors</item>
|
||||
<item>SRM ANT+ Bridge</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -490,6 +490,11 @@ limitations under the License.
|
||||
<string name="searching">Поиск</string>
|
||||
<string name="sending">Отправка</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Нет</string>
|
||||
<string name="ant_sensor_option">ANT+ Датчик</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ Bridge</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">получать уведомления о записи трека</string>
|
||||
<string name="read_tracks_permission_label">чтение записанных данных трека</string>
|
||||
|
||||
@@ -277,11 +277,4 @@ limitations under the License.
|
||||
<item>way point</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>None</item>
|
||||
<item>ANT+ Sensors</item>
|
||||
<item>SRM ANT+ Bridge</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -98,10 +98,19 @@ limitations under the License.
|
||||
<item>TCX</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>@string/no_sensor_option</item>
|
||||
<item>@string/ant_sensor_option</item>
|
||||
<item>@string/ant_bridge_sensor_option</item>
|
||||
<item>@string/polar_bt_sensor_option</item>
|
||||
<item>@string/zephyr_bt_sensor_option</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_values">
|
||||
<item>@string/none</item>
|
||||
<item>@string/ant_sensor_type</item>
|
||||
<item>@string/srm_ant_bridge_sensor_type</item>
|
||||
<item>@string/polar_sensor_type</item>
|
||||
<item>@string/zephyr_sensor_type</item>
|
||||
</array>
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ limitations under the License.
|
||||
<string name="none">NONE</string>
|
||||
<string name="ant_sensor_type">ANT</string>
|
||||
<string name="srm_ant_bridge_sensor_type">SRM_ANT_BRIDGE</string>
|
||||
<string name="polar_sensor_type">POLAR</string>
|
||||
<string name="zephyr_sensor_type">ZEPHYR</string>
|
||||
|
||||
<!-- Send to Google URLs -->
|
||||
|
||||
@@ -501,4 +501,12 @@ limitations under the License.
|
||||
<string name="notification_permission_description">Be notified when a track starts or stops being recorded.</string>
|
||||
<string name="read_tracks_permission_description">Be able to read track data, such as points and waypoints.</string>
|
||||
<string name="write_tracks_permission_description">Be able to write track data, such as starting recording or adding waypoints.</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">NONE</string>
|
||||
<string name="ant_sensor_option">ANT+ Sensors</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ Bridge</string>
|
||||
<string name="polar_bt_sensor_option">Polar Bluetooth</string>
|
||||
<string name="zephyr_bt_sensor_option">Zephyr Bluetooth</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -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;
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class PolarMessageParserTest extends TestCase {
|
||||
|
||||
PolarMessageParser parser = new PolarMessageParser();
|
||||
// A complete and valid Polar HxM packet
|
||||
// FE08F701D1001104FE08F702D1001104
|
||||
private final byte[] originalBuf =
|
||||
{(byte) 0xFE, 0x08, (byte) 0xF7, 0x01, (byte) 0xD1, 0x00, 0x11, 0x04, (byte) 0xFE, 0x08,
|
||||
(byte) 0xF7, 0x02, (byte) 0xD1, 0x00, 0x11, 0x04};
|
||||
private byte[] buf;
|
||||
|
||||
public void setUp() {
|
||||
buf = Arrays.copyOf(originalBuf, originalBuf.length);
|
||||
}
|
||||
|
||||
public void testIsValid() {
|
||||
assertTrue(parser.isValid(buf));
|
||||
}
|
||||
|
||||
public void testIsValid_invalidHeader() {
|
||||
// Invalidate header.
|
||||
buf[0] = 0x03;
|
||||
assertFalse(parser.isValid(buf));
|
||||
}
|
||||
|
||||
public void testIsValid_invalidCheckbyte() {
|
||||
// Invalidate checkbyte.
|
||||
buf[2] = 0x03;
|
||||
assertFalse(parser.isValid(buf));
|
||||
}
|
||||
|
||||
public void testIsValid_invalidSequence() {
|
||||
// Invalidate sequence.
|
||||
buf[3] = 0x11;
|
||||
assertFalse(parser.isValid(buf));
|
||||
}
|
||||
|
||||
public void testParseBuffer() {
|
||||
buf[5] = 70;
|
||||
Sensor.SensorDataSet sds = parser.parseBuffer(buf);
|
||||
assertTrue(sds.hasHeartRate());
|
||||
assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING);
|
||||
assertEquals(70, sds.getHeartRate().getValue());
|
||||
}
|
||||
|
||||
public void testFindNextAlignment_offset() {
|
||||
// The first 4 bytes are garbage
|
||||
buf = new byte[originalBuf.length + 4];
|
||||
buf[0] = 4;
|
||||
buf[1] = 2;
|
||||
buf[2] = 4;
|
||||
buf[3] = 2;
|
||||
|
||||
// Then the valid message.
|
||||
System.arraycopy(originalBuf, 0, buf, 4, originalBuf.length);
|
||||
assertEquals(4, parser.findNextAlignment(buf));
|
||||
}
|
||||
|
||||
public void testFindNextAlignment_invalid() {
|
||||
buf[0] = 0;
|
||||
assertEquals(-1, parser.findNextAlignment(buf));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user