forked from upstream-mirrors/OpenTracks
Refactor AntSensorManager so each ChannelConfiguration is in its
own class.
This commit is contained in:
+96
-342
@@ -41,7 +41,7 @@ import java.lang.reflect.Field;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Ant Sensor Manager.
|
* Ant Sensor Manager.
|
||||||
*
|
*
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
public class AntSensorManager extends SensorManager {
|
public class AntSensorManager extends SensorManager {
|
||||||
@@ -58,33 +58,12 @@ public class AntSensorManager extends SensorManager {
|
|||||||
// recently
|
// recently
|
||||||
OFFLINE // Channel is closed as the result of a search timeout
|
OFFLINE // Channel is closed as the result of a search timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = AntSensorManager.class.getSimpleName();
|
|
||||||
|
|
||||||
public static final short WILDCARD = 0;
|
public static final short WILDCARD = 0;
|
||||||
|
|
||||||
|
private static final String TAG = AntSensorManager.class.getSimpleName();
|
||||||
private static final int CHANNELS = 4;
|
private static final int CHANNELS = 4;
|
||||||
private static final byte HRM_CHANNEL = (byte) 0; // heart rate monitor
|
|
||||||
private static final byte SDM_CHANNEL = (byte) 1; // speed distance monitor
|
|
||||||
private static final byte BCS_CHANNEL = (byte) 2; // bike cadence sensor
|
|
||||||
private static final byte CBS_CHANNEL = (byte) 3; // combined bike speed and cadence sensor
|
|
||||||
|
|
||||||
private static final byte HRM_DEVICE_TYPE = 0x78;
|
|
||||||
private static final byte SDM_DEVICE_TYPE = 0x7C;
|
|
||||||
private static final byte BCS_DEVICE_TYPE = 0x7A;
|
|
||||||
private static final byte CBS_DEVICE_TYPE = 0x79;
|
|
||||||
|
|
||||||
private static final short HRM_PERIOD = 8070;
|
|
||||||
private static final short SDM_PERIOD = 8134;
|
|
||||||
private static final short BCS_PERIOD = 8102;
|
|
||||||
private static final short CBS_PERIOD = 8086;
|
|
||||||
|
|
||||||
private static final byte DEFAULT_PROXIMITY_SEARCH_BIN = 7;
|
|
||||||
|
|
||||||
private static final String RADIO_ANT = "ant";
|
private static final String RADIO_ANT = "ant";
|
||||||
private static final byte ANT_NETWORK = (byte) 0x01;
|
private static final byte ANT_NETWORK = (byte) 0x01;
|
||||||
private static final int ANT_FREQUENCY = 57; // 2457Mhz (Ant+ frequency)
|
|
||||||
private static final int ANT_TRANSMISSION_TYPE = 0; // 0 for wild card search
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final ChannelConfiguration channelConfig[];
|
private final ChannelConfiguration channelConfig[];
|
||||||
@@ -93,38 +72,26 @@ public class AntSensorManager extends SensorManager {
|
|||||||
|
|
||||||
private boolean serviceConnected = false;
|
private boolean serviceConnected = false;
|
||||||
private boolean hasClaimedInterface = false;
|
private boolean hasClaimedInterface = false;
|
||||||
private ChannelStates hrmState = ChannelStates.CLOSED;
|
|
||||||
private ChannelStates sdmState = ChannelStates.CLOSED;
|
|
||||||
private ChannelStates bcsState = ChannelStates.CLOSED;
|
|
||||||
private ChannelStates cbsState = ChannelStates.CLOSED;
|
|
||||||
private short hrmDeviceNumber = WILDCARD;
|
|
||||||
private short sdmDeviceNumber = WILDCARD;
|
|
||||||
private short bcsDeviceNumber = WILDCARD;
|
|
||||||
private short cbsDeviceNumber = WILDCARD;
|
|
||||||
|
|
||||||
private SensorDataSet sensorDataSet = null;
|
private SensorDataSet sensorDataSet = null;
|
||||||
private int lastHeartRate = -1;
|
|
||||||
private int lastCadence = -1;
|
|
||||||
private long lastSensorDataSetTime = 0;
|
private long lastSensorDataSetTime = 0;
|
||||||
|
private AntSensorValue antSensorValue = new AntSensorValue();
|
||||||
private CadenceCounter bcsCadenceCounter;
|
|
||||||
private CadenceCounter cbsCadenceCounter;
|
|
||||||
|
|
||||||
private boolean requestedReset = false;
|
private boolean requestedReset = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param context the context
|
* @param context the context
|
||||||
*/
|
*/
|
||||||
public AntSensorManager(Context context) {
|
public AntSensorManager(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
channelConfig = new ChannelConfiguration[CHANNELS];
|
channelConfig = new ChannelConfiguration[CHANNELS];
|
||||||
channelConfig[HRM_CHANNEL] = new ChannelConfiguration();
|
channelConfig[0] = new HeartRateChannelConfiguration();
|
||||||
channelConfig[SDM_CHANNEL] = new ChannelConfiguration();
|
channelConfig[1] = new SpeedDistanceChannelConfiguration();
|
||||||
channelConfig[BCS_CHANNEL] = new ChannelConfiguration();
|
channelConfig[2] = new BikeCadenceChannelConfiguration();
|
||||||
channelConfig[CBS_CHANNEL] = new ChannelConfiguration();
|
channelConfig[3] = new CombinedBikeChannelConfiguration();
|
||||||
|
|
||||||
statusIntentFilter = new IntentFilter();
|
statusIntentFilter = new IntentFilter();
|
||||||
statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION);
|
statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION);
|
||||||
@@ -171,7 +138,7 @@ public class AntSensorManager extends SensorManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void tearDownChannel() {
|
protected void tearDownChannel() {
|
||||||
try {
|
try {
|
||||||
@@ -214,12 +181,12 @@ public class AntSensorManager extends SensorManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AntInterface.ServiceListener serviceListener = new AntInterface.ServiceListener() {
|
private AntInterface.ServiceListener serviceListener = new AntInterface.ServiceListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected() {
|
public void onServiceConnected() {
|
||||||
handleServiceConnected();
|
handleServiceConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected() {
|
public void onServiceDisconnected() {
|
||||||
serviceConnected = false;
|
serviceConnected = false;
|
||||||
if (hasClaimedInterface) {
|
if (hasClaimedInterface) {
|
||||||
@@ -256,89 +223,26 @@ public class AntSensorManager extends SensorManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a channel.
|
* Opens a channel.
|
||||||
*
|
*
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
*/
|
*/
|
||||||
private void openChannel(byte channel) {
|
private void openChannel(byte channel) {
|
||||||
channelConfig[channel].deviceNumber = 0;
|
short deviceNumber = (short) PreferencesUtils.getInt(
|
||||||
channelConfig[channel].deviceType = 0;
|
context, channelConfig[channel].getDeviceIdKey(), WILDCARD);
|
||||||
channelConfig[channel].TransmissionType = ANT_TRANSMISSION_TYPE;
|
channelConfig[channel].setDeviceNumber(deviceNumber);
|
||||||
channelConfig[channel].period = 0;
|
channelConfig[channel].setChannelState(ChannelStates.PENDING_OPEN);
|
||||||
channelConfig[channel].freq = ANT_FREQUENCY;
|
|
||||||
channelConfig[channel].proxSearch = DEFAULT_PROXIMITY_SEARCH_BIN;
|
|
||||||
short deviceNumber = -1;
|
|
||||||
byte deviceType = 0;
|
|
||||||
short period = 0;
|
|
||||||
switch (channel) {
|
|
||||||
case HRM_CHANNEL:
|
|
||||||
deviceNumber = (short) PreferencesUtils.getInt(
|
|
||||||
context, R.string.ant_heart_rate_monitor_id_key, WILDCARD);
|
|
||||||
deviceType = HRM_DEVICE_TYPE;
|
|
||||||
period = HRM_PERIOD;
|
|
||||||
hrmDeviceNumber = deviceNumber;
|
|
||||||
hrmState = ChannelStates.PENDING_OPEN;
|
|
||||||
break;
|
|
||||||
case SDM_CHANNEL:
|
|
||||||
deviceNumber = (short) PreferencesUtils.getInt(
|
|
||||||
context, R.string.ant_speed_distance_monitor_id_key, WILDCARD);
|
|
||||||
deviceType = SDM_DEVICE_TYPE;
|
|
||||||
period = SDM_PERIOD;
|
|
||||||
sdmDeviceNumber = deviceNumber;
|
|
||||||
sdmState = ChannelStates.PENDING_OPEN;
|
|
||||||
break;
|
|
||||||
case BCS_CHANNEL:
|
|
||||||
deviceNumber = (short) PreferencesUtils.getInt(
|
|
||||||
context, R.string.ant_bike_cadence_sensor_id_key, WILDCARD);
|
|
||||||
deviceType = BCS_DEVICE_TYPE;
|
|
||||||
period = BCS_PERIOD;
|
|
||||||
bcsDeviceNumber = deviceNumber;
|
|
||||||
bcsState = ChannelStates.PENDING_OPEN;
|
|
||||||
bcsCadenceCounter = new CadenceCounter();
|
|
||||||
break;
|
|
||||||
case CBS_CHANNEL:
|
|
||||||
deviceNumber = (short) PreferencesUtils.getInt(
|
|
||||||
context, R.string.ant_combined_bike_sensor_id_key, WILDCARD);
|
|
||||||
deviceType = CBS_DEVICE_TYPE;
|
|
||||||
period = CBS_PERIOD;
|
|
||||||
cbsDeviceNumber = deviceNumber;
|
|
||||||
cbsState = ChannelStates.PENDING_OPEN;
|
|
||||||
cbsCadenceCounter = new CadenceCounter();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (deviceNumber != -1) {
|
|
||||||
channelConfig[channel].deviceNumber = deviceNumber;
|
|
||||||
channelConfig[channel].deviceType = deviceType;
|
|
||||||
channelConfig[channel].period = period;
|
|
||||||
}
|
|
||||||
setupAntChannel(ANT_NETWORK, channel);
|
setupAntChannel(ANT_NETWORK, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a channel.
|
* Closes a channel.
|
||||||
*
|
*
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
*/
|
*/
|
||||||
private void closeChannel(byte channel) {
|
private void closeChannel(byte channel) {
|
||||||
channelConfig[channel].isInitializing = false;
|
channelConfig[channel].setInitializing(false);
|
||||||
channelConfig[channel].isDeinitializing = true;
|
channelConfig[channel].setDeinitializing(true);
|
||||||
switch (channel) {
|
channelConfig[channel].setChannelState(ChannelStates.CLOSED);
|
||||||
case HRM_CHANNEL:
|
|
||||||
hrmState = ChannelStates.CLOSED;
|
|
||||||
break;
|
|
||||||
case SDM_CHANNEL:
|
|
||||||
sdmState = ChannelStates.CLOSED;
|
|
||||||
break;
|
|
||||||
case BCS_CHANNEL:
|
|
||||||
bcsState = ChannelStates.CLOSED;
|
|
||||||
break;
|
|
||||||
case CBS_CHANNEL:
|
|
||||||
cbsState = ChannelStates.CLOSED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
setSensorState(SensorState.DISCONNECTED);
|
setSensorState(SensorState.DISCONNECTED);
|
||||||
try {
|
try {
|
||||||
antInterface.ANTCloseChannel(channel);
|
antInterface.ANTCloseChannel(channel);
|
||||||
@@ -353,10 +257,9 @@ public class AntSensorManager extends SensorManager {
|
|||||||
* Clears all channels.
|
* Clears all channels.
|
||||||
*/
|
*/
|
||||||
private void clearAllChannels() {
|
private void clearAllChannels() {
|
||||||
hrmState = ChannelStates.CLOSED;
|
for (int i = 0; i < CHANNELS; i++) {
|
||||||
sdmState = ChannelStates.CLOSED;
|
channelConfig[i].setChannelState(ChannelStates.CLOSED);
|
||||||
bcsState = ChannelStates.CLOSED;
|
}
|
||||||
cbsState = ChannelStates.CLOSED;
|
|
||||||
setSensorState(SensorState.DISCONNECTED);
|
setSensorState(SensorState.DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,66 +330,42 @@ public class AntSensorManager extends SensorManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private final BroadcastReceiver dataReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver dataReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context c, Intent intent) {
|
public void onReceive(Context c, Intent intent) {
|
||||||
if (intent.getAction().equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) {
|
if (intent.getAction().equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) {
|
||||||
byte[] ANTRxMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE);
|
byte[] antRxMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE);
|
||||||
switch (ANTRxMessage[AntMesg.MESG_ID_OFFSET]) {
|
byte channel;
|
||||||
|
switch (antRxMessage[AntMesg.MESG_ID_OFFSET]) {
|
||||||
case AntMesg.MESG_BROADCAST_DATA_ID:
|
case AntMesg.MESG_BROADCAST_DATA_ID:
|
||||||
case AntMesg.MESG_ACKNOWLEDGED_DATA_ID:
|
case AntMesg.MESG_ACKNOWLEDGED_DATA_ID:
|
||||||
// Switch on channel number
|
channel = antRxMessage[AntMesg.MESG_DATA_OFFSET];
|
||||||
switch (ANTRxMessage[AntMesg.MESG_DATA_OFFSET]) {
|
if (channelConfig[channel].getChannelState() != ChannelStates.CLOSED) {
|
||||||
case HRM_CHANNEL:
|
channelConfig[channel].setChannelState(ChannelStates.TRACKING_DATA);
|
||||||
decodeHrmMessage(ANTRxMessage);
|
|
||||||
break;
|
|
||||||
case SDM_CHANNEL:
|
|
||||||
decodeSdmMessage(ANTRxMessage);
|
|
||||||
break;
|
|
||||||
case BCS_CHANNEL:
|
|
||||||
decodeBcsMessage(ANTRxMessage);
|
|
||||||
break;
|
|
||||||
case CBS_CHANNEL:
|
|
||||||
decodeCbsMessage(ANTRxMessage);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (channelConfig[channel].getDeviceNumber() == WILDCARD) {
|
||||||
|
try {
|
||||||
|
antInterface.ANTRequestMessage(channel, AntMesg.MESG_CHANNEL_ID_ID);
|
||||||
|
} catch (AntInterfaceException e) {
|
||||||
|
handleAntError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channelConfig[channel].decodeMessage(antRxMessage, antSensorValue);
|
||||||
|
setSensorDataSet();
|
||||||
break;
|
break;
|
||||||
case AntMesg.MESG_RESPONSE_EVENT_ID:
|
case AntMesg.MESG_RESPONSE_EVENT_ID:
|
||||||
handleResponseEventMessage(ANTRxMessage);
|
handleResponseEventMessage(antRxMessage);
|
||||||
break;
|
break;
|
||||||
case AntMesg.MESG_CHANNEL_ID_ID:
|
case AntMesg.MESG_CHANNEL_ID_ID:
|
||||||
short deviceNum = (short) ((ANTRxMessage[AntMesg.MESG_DATA_OFFSET + 1] & 0xFF
|
channel = antRxMessage[AntMesg.MESG_DATA_OFFSET];
|
||||||
| ((ANTRxMessage[AntMesg.MESG_DATA_OFFSET + 2] & 0xFF) << 8)) & 0xFFFF);
|
short deviceNumber = (short) ((antRxMessage[AntMesg.MESG_DATA_OFFSET + 1] & 0xFF
|
||||||
int keyId = -1;
|
| ((antRxMessage[AntMesg.MESG_DATA_OFFSET + 2] & 0xFF) << 8)) & 0xFFFF);
|
||||||
// Switch on channel number
|
channelConfig[channel].setDeviceNumber(deviceNumber);
|
||||||
switch (ANTRxMessage[AntMesg.MESG_DATA_OFFSET]) {
|
PreferencesUtils.setInt(context, channelConfig[channel].getDeviceIdKey(), deviceNumber);
|
||||||
case HRM_CHANNEL:
|
Toast.makeText(context,
|
||||||
hrmDeviceNumber = deviceNum;
|
context.getString(R.string.settings_sensor_connected, deviceNumber),
|
||||||
keyId = R.string.ant_heart_rate_monitor_id_key;
|
Toast.LENGTH_SHORT).show();
|
||||||
break;
|
setSensorState(SensorState.CONNECTED);
|
||||||
case SDM_CHANNEL:
|
|
||||||
sdmDeviceNumber = deviceNum;
|
|
||||||
keyId = R.string.ant_speed_distance_monitor_id_key;
|
|
||||||
break;
|
|
||||||
case BCS_CHANNEL:
|
|
||||||
bcsDeviceNumber = deviceNum;
|
|
||||||
keyId = R.string.ant_bike_cadence_sensor_id_key;
|
|
||||||
break;
|
|
||||||
case CBS_CHANNEL:
|
|
||||||
cbsDeviceNumber = deviceNum;
|
|
||||||
keyId = R.string.ant_combined_bike_sensor_id_key;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (keyId != -1) {
|
|
||||||
PreferencesUtils.setInt(context, keyId, deviceNum);
|
|
||||||
Toast.makeText(context,
|
|
||||||
context.getString(R.string.settings_sensor_connected, deviceNum),
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
setSensorState(SensorState.CONNECTED);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -496,72 +375,54 @@ public class AntSensorManager extends SensorManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles response event message.
|
* Handles response event message.
|
||||||
*
|
*
|
||||||
* @param message the message
|
* @param message the message
|
||||||
*/
|
*/
|
||||||
private void handleResponseEventMessage(byte[] message) {
|
private void handleResponseEventMessage(byte[] message) {
|
||||||
// For a list of possible message codes see ANT Message Protocol and Usage
|
// For a list of possible message codes see ANT Message Protocol and Usage
|
||||||
// section 9.5.6.1 available from thisisant.com
|
// section 9.5.6.1 available from thisisant.com
|
||||||
byte channelNumber = message[AntMesg.MESG_DATA_OFFSET];
|
byte channel = message[AntMesg.MESG_DATA_OFFSET];
|
||||||
if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_EVENT_ID)
|
if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_EVENT_ID)
|
||||||
&& (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.EVENT_RX_SEARCH_TIMEOUT)) {
|
&& (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.EVENT_RX_SEARCH_TIMEOUT)) {
|
||||||
// A channel timed out searching, unassign it
|
// A channel timed out searching, unassign it
|
||||||
channelConfig[channelNumber].isInitializing = false;
|
channelConfig[channel].setInitializing(false);
|
||||||
channelConfig[channelNumber].isDeinitializing = false;
|
channelConfig[channel].setDeinitializing(false);
|
||||||
switch (channelNumber) {
|
channelConfig[channel].setChannelState(ChannelStates.OFFLINE);
|
||||||
case HRM_CHANNEL:
|
|
||||||
hrmState = ChannelStates.OFFLINE;
|
|
||||||
break;
|
|
||||||
case SDM_CHANNEL:
|
|
||||||
sdmState = ChannelStates.OFFLINE;
|
|
||||||
break;
|
|
||||||
case BCS_CHANNEL:
|
|
||||||
bcsState = ChannelStates.OFFLINE;
|
|
||||||
break;
|
|
||||||
case CBS_CHANNEL:
|
|
||||||
cbsState = ChannelStates.OFFLINE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
antInterface.ANTUnassignChannel(channelNumber);
|
antInterface.ANTUnassignChannel(channel);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
setSensorState(SensorState.DISCONNECTED);
|
setSensorState(SensorState.DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channelConfig[channelNumber].isInitializing) {
|
if (channelConfig[channel].isInitializing()) {
|
||||||
if (message[AntMesg.MESG_DATA_OFFSET + 2] != 0) {
|
if (message[AntMesg.MESG_DATA_OFFSET + 2] != 0) {
|
||||||
// Error response
|
// Error response
|
||||||
Log.e(TAG, String.format("Error code(%#02x) on message ID(%#02x) on channel %d",
|
Log.e(TAG, String.format("Error code(%#02x) on message ID(%#02x) on channel %d",
|
||||||
message[AntMesg.MESG_DATA_OFFSET + 2],
|
message[AntMesg.MESG_DATA_OFFSET + 2], message[AntMesg.MESG_DATA_OFFSET + 1],
|
||||||
message[AntMesg.MESG_DATA_OFFSET + 1], channelNumber));
|
channel));
|
||||||
} else {
|
} else {
|
||||||
// Switch on message id
|
// Switch on message id
|
||||||
switch (message[AntMesg.MESG_DATA_OFFSET + 1]) {
|
switch (message[AntMesg.MESG_DATA_OFFSET + 1]) {
|
||||||
case AntMesg.MESG_ASSIGN_CHANNEL_ID:
|
case AntMesg.MESG_ASSIGN_CHANNEL_ID:
|
||||||
try {
|
try {
|
||||||
antInterface.ANTSetChannelId(channelNumber,
|
antInterface.ANTSetChannelId(channel, channelConfig[channel].getDeviceNumber(),
|
||||||
channelConfig[channelNumber].deviceNumber,
|
channelConfig[channel].getDeviceType(), ChannelConfiguration.TRANSMISSION_TYPE);
|
||||||
channelConfig[channelNumber].deviceType,
|
|
||||||
channelConfig[channelNumber].TransmissionType);
|
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AntMesg.MESG_CHANNEL_ID_ID:
|
case AntMesg.MESG_CHANNEL_ID_ID:
|
||||||
try {
|
try {
|
||||||
antInterface.ANTSetChannelPeriod(
|
antInterface.ANTSetChannelPeriod(channel, channelConfig[channel].getMessagPeriod());
|
||||||
channelNumber, channelConfig[channelNumber].period);
|
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AntMesg.MESG_CHANNEL_MESG_PERIOD_ID:
|
case AntMesg.MESG_CHANNEL_MESG_PERIOD_ID:
|
||||||
try {
|
try {
|
||||||
antInterface.ANTSetChannelRFFreq(channelNumber, channelConfig[channelNumber].freq);
|
antInterface.ANTSetChannelRFFreq(channel, ChannelConfiguration.FREQUENCY);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
@@ -569,7 +430,7 @@ public class AntSensorManager extends SensorManager {
|
|||||||
case AntMesg.MESG_CHANNEL_RADIO_FREQ_ID:
|
case AntMesg.MESG_CHANNEL_RADIO_FREQ_ID:
|
||||||
try {
|
try {
|
||||||
// Disable high priority search
|
// Disable high priority search
|
||||||
antInterface.ANTSetChannelSearchTimeout(channelNumber, (byte) 0);
|
antInterface.ANTSetChannelSearchTimeout(channel, (byte) 0);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
@@ -577,23 +438,23 @@ public class AntSensorManager extends SensorManager {
|
|||||||
case AntMesg.MESG_CHANNEL_SEARCH_TIMEOUT_ID:
|
case AntMesg.MESG_CHANNEL_SEARCH_TIMEOUT_ID:
|
||||||
try {
|
try {
|
||||||
// Set search timeout to 30 seconds (low priority search)
|
// Set search timeout to 30 seconds (low priority search)
|
||||||
antInterface.ANTSetLowPriorityChannelSearchTimeout(channelNumber, (byte) 12);
|
antInterface.ANTSetLowPriorityChannelSearchTimeout(channel, (byte) 12);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AntMesg.MESG_SET_LP_SEARCH_TIMEOUT_ID:
|
case AntMesg.MESG_SET_LP_SEARCH_TIMEOUT_ID:
|
||||||
if (channelConfig[channelNumber].deviceNumber == WILDCARD) {
|
if (channelConfig[channel].getDeviceNumber() == WILDCARD) {
|
||||||
try {
|
try {
|
||||||
// Configure proximity search, if using wild card search
|
// Configure proximity search, if using wild card search
|
||||||
antInterface.ANTSetProximitySearch(
|
antInterface.ANTSetProximitySearch(
|
||||||
channelNumber, channelConfig[channelNumber].proxSearch);
|
channel, ChannelConfiguration.PROXIMITY_SEARCH);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
antInterface.ANTOpenChannel(channelNumber);
|
antInterface.ANTOpenChannel(channel);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
@@ -601,162 +462,57 @@ public class AntSensorManager extends SensorManager {
|
|||||||
break;
|
break;
|
||||||
case AntMesg.MESG_PROX_SEARCH_CONFIG_ID:
|
case AntMesg.MESG_PROX_SEARCH_CONFIG_ID:
|
||||||
try {
|
try {
|
||||||
antInterface.ANTOpenChannel(channelNumber);
|
antInterface.ANTOpenChannel(channel);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AntMesg.MESG_OPEN_CHANNEL_ID:
|
case AntMesg.MESG_OPEN_CHANNEL_ID:
|
||||||
channelConfig[channelNumber].isInitializing = false;
|
channelConfig[channel].setInitializing(false);
|
||||||
switch (channelNumber) {
|
channelConfig[channel].setChannelState(ChannelStates.SEARCHING);
|
||||||
case HRM_CHANNEL:
|
|
||||||
hrmState = ChannelStates.SEARCHING;
|
|
||||||
break;
|
|
||||||
case SDM_CHANNEL:
|
|
||||||
sdmState = ChannelStates.SEARCHING;
|
|
||||||
break;
|
|
||||||
case BCS_CHANNEL:
|
|
||||||
bcsState = ChannelStates.SEARCHING;
|
|
||||||
break;
|
|
||||||
case CBS_CHANNEL:
|
|
||||||
cbsState = ChannelStates.SEARCHING;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (channelConfig[channelNumber].isDeinitializing) {
|
} else if (channelConfig[channel].isDeinitializing()) {
|
||||||
if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_EVENT_ID)
|
if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_EVENT_ID)
|
||||||
&& (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.EVENT_CHANNEL_CLOSED)) {
|
&& (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.EVENT_CHANNEL_CLOSED)) {
|
||||||
try {
|
try {
|
||||||
antInterface.ANTUnassignChannel(channelNumber);
|
antInterface.ANTUnassignChannel(channel);
|
||||||
} catch (AntInterfaceException e) {
|
} catch (AntInterfaceException e) {
|
||||||
handleAntError();
|
handleAntError();
|
||||||
}
|
}
|
||||||
} else if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_UNASSIGN_CHANNEL_ID)
|
} else if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_UNASSIGN_CHANNEL_ID)
|
||||||
&& (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.RESPONSE_NO_ERROR)) {
|
&& (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.RESPONSE_NO_ERROR)) {
|
||||||
channelConfig[channelNumber].isDeinitializing = false;
|
channelConfig[channel].setDeinitializing(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes HRM message.
|
|
||||||
*
|
|
||||||
* @param message the message
|
|
||||||
*/
|
|
||||||
private void decodeHrmMessage(byte[] message) {
|
|
||||||
if (hrmState != ChannelStates.CLOSED) {
|
|
||||||
hrmState = ChannelStates.TRACKING_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hrmDeviceNumber == WILDCARD) {
|
|
||||||
try {
|
|
||||||
antInterface.ANTRequestMessage(HRM_CHANNEL, AntMesg.MESG_CHANNEL_ID_ID);
|
|
||||||
} catch (AntInterfaceException e) {
|
|
||||||
handleAntError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastHeartRate = message[10] & 0xFF;
|
|
||||||
setSenorDataSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes SDM message.
|
|
||||||
*
|
|
||||||
* @param message the message
|
|
||||||
*/
|
|
||||||
private void decodeSdmMessage(byte[] message) {
|
|
||||||
if (sdmState != ChannelStates.CLOSED) {
|
|
||||||
sdmState = ChannelStates.TRACKING_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdmDeviceNumber == WILDCARD) {
|
|
||||||
try {
|
|
||||||
antInterface.ANTRequestMessage(SDM_CHANNEL, AntMesg.MESG_CHANNEL_ID_ID);
|
|
||||||
} catch (AntInterfaceException e) {
|
|
||||||
handleAntError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check page 2 data
|
|
||||||
if (message[3] == 0x02) {
|
|
||||||
lastCadence = (int) ((message[6] & 0xFF) + (((message[7] >>> 4) & 0x0F) / 16.0f));
|
|
||||||
setSenorDataSet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes BCS message.
|
|
||||||
*
|
|
||||||
* @param message the message
|
|
||||||
*/
|
|
||||||
private void decodeBcsMessage(byte[] message) {
|
|
||||||
if (bcsState != ChannelStates.CLOSED) {
|
|
||||||
bcsState = ChannelStates.TRACKING_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bcsDeviceNumber == WILDCARD) {
|
|
||||||
try {
|
|
||||||
antInterface.ANTRequestMessage(BCS_CHANNEL, AntMesg.MESG_CHANNEL_ID_ID);
|
|
||||||
} catch (AntInterfaceException e) {
|
|
||||||
handleAntError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int crankRevs = ((int) message[9] & 0xFF) + ((int) message[10] & 0xFF) * 256;
|
|
||||||
int sensorTime = ((int) message[7] & 0xFF) + ((int) message[8] & 0xFF) * 256;
|
|
||||||
lastCadence = bcsCadenceCounter.getEventsPerMinute(crankRevs, sensorTime);
|
|
||||||
setSenorDataSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes CBS message.
|
|
||||||
*
|
|
||||||
* @param message the message
|
|
||||||
*/
|
|
||||||
private void decodeCbsMessage(byte[] message) {
|
|
||||||
if (cbsState != ChannelStates.CLOSED) {
|
|
||||||
cbsState = ChannelStates.TRACKING_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cbsDeviceNumber == WILDCARD) {
|
|
||||||
try {
|
|
||||||
antInterface.ANTRequestMessage(CBS_CHANNEL, AntMesg.MESG_CHANNEL_ID_ID);
|
|
||||||
} catch (AntInterfaceException e) {
|
|
||||||
handleAntError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int crankRevs = ((int) message[5] & 0xFF) + ((int) message[6] & 0xFF) * 256;
|
|
||||||
int sensorTime = ((int) message[3] & 0xFF) + ((int) message[4] & 0xFF) * 256;
|
|
||||||
|
|
||||||
lastCadence = cbsCadenceCounter.getEventsPerMinute(crankRevs, sensorTime);
|
|
||||||
setSenorDataSet();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets sensor data set.
|
* Sets sensor data set.
|
||||||
*/
|
*/
|
||||||
private void setSenorDataSet() {
|
private void setSensorDataSet() {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
// Data comes in at ~4Hz rate from the sensors, so after >300 msec fresh
|
// Data comes in at ~4Hz rate from the sensors, so after >300 msec fresh
|
||||||
// data is here from all the connected sensors
|
// data is here from all the connected sensors
|
||||||
if (now < lastSensorDataSetTime + 300) { return; }
|
if (now < lastSensorDataSetTime + 300) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
lastSensorDataSetTime = now;
|
lastSensorDataSetTime = now;
|
||||||
|
|
||||||
SensorDataSet.Builder builder = Sensor.SensorDataSet.newBuilder();
|
SensorDataSet.Builder builder = Sensor.SensorDataSet.newBuilder();
|
||||||
if (lastHeartRate != -1) {
|
int heartRate = antSensorValue.getHeartRate();
|
||||||
|
if (heartRate != -1) {
|
||||||
builder.setHeartRate(Sensor.SensorData.newBuilder()
|
builder.setHeartRate(Sensor.SensorData.newBuilder()
|
||||||
.setValue(lastHeartRate).setState(Sensor.SensorState.SENDING));
|
.setValue(heartRate).setState(Sensor.SensorState.SENDING));
|
||||||
}
|
}
|
||||||
if (lastCadence != -1) {
|
int cadence = antSensorValue.getCadence();
|
||||||
|
if (cadence != -1) {
|
||||||
builder.setCadence(Sensor.SensorData.newBuilder()
|
builder.setCadence(Sensor.SensorData.newBuilder()
|
||||||
.setValue(lastCadence).setState(Sensor.SensorState.SENDING));
|
.setValue(cadence).setState(Sensor.SensorState.SENDING));
|
||||||
}
|
}
|
||||||
sensorDataSet = builder.setCreationTime(now).build();
|
sensorDataSet = builder.setCreationTime(now).build();
|
||||||
setSensorState(SensorState.SENDING);
|
setSensorState(SensorState.SENDING);
|
||||||
@@ -764,14 +520,14 @@ public class AntSensorManager extends SensorManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up ant channel.
|
* Sets up ant channel.
|
||||||
*
|
*
|
||||||
* @param networkNumber the network number
|
* @param networkNumber the network number
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
*/
|
*/
|
||||||
private void setupAntChannel(byte networkNumber, byte channel) {
|
private void setupAntChannel(byte networkNumber, byte channel) {
|
||||||
try {
|
try {
|
||||||
channelConfig[channel].isInitializing = true;
|
channelConfig[channel].setInitializing(true);
|
||||||
channelConfig[channel].isDeinitializing = false;
|
channelConfig[channel].setDeinitializing(false);
|
||||||
|
|
||||||
// Assign as slave channel on selected network
|
// Assign as slave channel on selected network
|
||||||
antInterface.ANTAssignChannel(channel, AntDefine.PARAMETER_RX_NOT_TX, networkNumber);
|
antInterface.ANTAssignChannel(channel, AntDefine.PARAMETER_RX_NOT_TX, networkNumber);
|
||||||
@@ -785,24 +541,22 @@ public class AntSensorManager extends SensorManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables data message.
|
* Enables data message.
|
||||||
*
|
*
|
||||||
* @param enabled true to enable
|
* @param enabled true to enable
|
||||||
*/
|
*/
|
||||||
private void enableDataMessage(boolean enabled) {
|
private void enableDataMessage(boolean enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
context.registerReceiver(
|
context.registerReceiver(
|
||||||
dataReceiver, new IntentFilter(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION));
|
dataReceiver, new IntentFilter(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION));
|
||||||
openChannel(HRM_CHANNEL);
|
for (int i = 0; i < CHANNELS; i++) {
|
||||||
openChannel(SDM_CHANNEL);
|
openChannel((byte) i);
|
||||||
openChannel(BCS_CHANNEL);
|
}
|
||||||
openChannel(CBS_CHANNEL);
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
context.unregisterReceiver(dataReceiver);
|
context.unregisterReceiver(dataReceiver);
|
||||||
closeChannel(HRM_CHANNEL);
|
for (int i = 0; i < CHANNELS; i++) {
|
||||||
closeChannel(SDM_CHANNEL);
|
closeChannel((byte) i);
|
||||||
closeChannel(BCS_CHANNEL);
|
}
|
||||||
closeChannel(CBS_CHANNEL);
|
|
||||||
setSensorState(SensorState.DISCONNECTED);
|
setSensorState(SensorState.DISCONNECTED);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
// Can safely ignore
|
// Can safely ignore
|
||||||
|
|||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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.ant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the latest ant sensor value.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class AntSensorValue {
|
||||||
|
|
||||||
|
private int heartRate = -1;
|
||||||
|
private int cadence = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the heart rate.
|
||||||
|
*/
|
||||||
|
public int getHeartRate() {
|
||||||
|
return heartRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the heart rate.
|
||||||
|
*
|
||||||
|
* @param heartRate the heart rate to set
|
||||||
|
*/
|
||||||
|
public void setHeartRate(int heartRate) {
|
||||||
|
this.heartRate = heartRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cadence.
|
||||||
|
*/
|
||||||
|
public int getCadence() {
|
||||||
|
return cadence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cadence.
|
||||||
|
*
|
||||||
|
* @param cadence the cadence to set
|
||||||
|
*/
|
||||||
|
public void setCadence(int cadence) {
|
||||||
|
this.cadence = cadence;
|
||||||
|
}
|
||||||
|
}
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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.ant;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bike cadence sensor channel configuration.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class BikeCadenceChannelConfiguration extends ChannelConfiguration {
|
||||||
|
|
||||||
|
private static final int DEVICE_ID_KEY = R.string.ant_bike_cadence_sensor_id_key;
|
||||||
|
private static final byte DEVICE_TYPE = 0x7A;
|
||||||
|
private static final short MESSAGE_PERIOD = 8102;
|
||||||
|
|
||||||
|
private CadenceCounter cadenceCounter = new CadenceCounter();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDeviceIdKey() {
|
||||||
|
return DEVICE_ID_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getDeviceType() {
|
||||||
|
return DEVICE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getMessagPeriod() {
|
||||||
|
return MESSAGE_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decodeMessage(byte[] message, AntSensorValue antSensorValue) {
|
||||||
|
int revolutionCount = ((int) message[9] & 0xFF) + ((int) message[10] & 0xFF) * 256;
|
||||||
|
int eventTime = ((int) message[7] & 0xFF) + ((int) message[8] & 0xFF) * 256;
|
||||||
|
antSensorValue.setCadence(cadenceCounter.getEventsPerMinute(revolutionCount, eventTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
-35
@@ -19,9 +19,9 @@ package com.google.android.apps.mytracks.services.sensors.ant;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counter that processes an Ant+ sensor data (counter + sensor time pair) and
|
* A counter that processes an Ant+ sensor data (count + event time) and returns
|
||||||
* returns the instantaneous cadence value.
|
* the instantaneous cadence value.
|
||||||
*
|
*
|
||||||
* @author Laszlo Molnar
|
* @author Laszlo Molnar
|
||||||
*/
|
*/
|
||||||
public class CadenceCounter {
|
public class CadenceCounter {
|
||||||
@@ -29,7 +29,7 @@ public class CadenceCounter {
|
|||||||
private static final int MILLIS_PER_MINUTE = 60000;
|
private static final int MILLIS_PER_MINUTE = 60000;
|
||||||
private static final int MAX_HISTORY_TIME_IN_MILLIS = 5000; // 5 seconds
|
private static final int MAX_HISTORY_TIME_IN_MILLIS = 5000; // 5 seconds
|
||||||
private static final int MAX_HISTORY_SIZE = 100;
|
private static final int MAX_HISTORY_SIZE = 100;
|
||||||
private static final int SENSOR_TIME_PER_MINUTE = 60 * 1024;
|
private static final int EVENT_TIME_PER_MINUTE = 60 * 1024;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cadence data.
|
* Cadence data.
|
||||||
@@ -38,18 +38,18 @@ public class CadenceCounter {
|
|||||||
*/
|
*/
|
||||||
private static class CadenceData {
|
private static class CadenceData {
|
||||||
final long systemTime;
|
final long systemTime;
|
||||||
final int counter;
|
final int count;
|
||||||
final int sensorTime;
|
final int eventTime;
|
||||||
|
|
||||||
private CadenceData(long systemTime, int counter, int sensorTime) {
|
private CadenceData(long systemTime, int count, int eventTime) {
|
||||||
this.systemTime = systemTime;
|
this.systemTime = systemTime;
|
||||||
this.counter = counter;
|
this.count = count;
|
||||||
this.sensorTime = sensorTime;
|
this.eventTime = eventTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The last counter value
|
// The last count
|
||||||
private int lastCounter;
|
private int lastCount;
|
||||||
|
|
||||||
// The last calculated cadence
|
// The last calculated cadence
|
||||||
private int eventsPerMinute;
|
private int eventsPerMinute;
|
||||||
@@ -58,7 +58,7 @@ public class CadenceCounter {
|
|||||||
private LinkedList<CadenceData> history;
|
private LinkedList<CadenceData> history;
|
||||||
|
|
||||||
public CadenceCounter() {
|
public CadenceCounter() {
|
||||||
lastCounter = -1;
|
lastCount = -1;
|
||||||
eventsPerMinute = 0;
|
eventsPerMinute = 0;
|
||||||
history = new LinkedList<CadenceData>();
|
history = new LinkedList<CadenceData>();
|
||||||
}
|
}
|
||||||
@@ -66,35 +66,35 @@ public class CadenceCounter {
|
|||||||
/**
|
/**
|
||||||
* Gets the cadence value.
|
* Gets the cadence value.
|
||||||
*
|
*
|
||||||
* @param counter counter
|
* @param count count
|
||||||
* @param sensorTime sensor time
|
* @param eventTime event time
|
||||||
*/
|
*/
|
||||||
public int getEventsPerMinute(int counter, int sensorTime) {
|
public int getEventsPerMinute(int count, int eventTime) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
int counterChange = (counter - lastCounter) & 0xFFFF;
|
int countChange = (count - lastCount) & 0xFFFF;
|
||||||
|
|
||||||
if (lastCounter < 0) {
|
if (lastCount < 0) {
|
||||||
/*
|
/*
|
||||||
* sensorTime for the initial counter value is probably out of date, so
|
* eventTime for the initial count value is probably out of date, so not
|
||||||
* not updating the history.
|
* updating the history.
|
||||||
*/
|
*/
|
||||||
lastCounter = counter;
|
lastCount = count;
|
||||||
eventsPerMinute = 0;
|
eventsPerMinute = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastCounter = counter;
|
lastCount = count;
|
||||||
|
|
||||||
if (counterChange != 0) {
|
if (countChange != 0) {
|
||||||
if (removeOldHistory(now)) {
|
if (removeOldHistory(now)) {
|
||||||
CadenceData lastCadenceData = history.getLast();
|
CadenceData lastCadenceData = history.getLast();
|
||||||
int sensorTimeChange = (sensorTime - lastCadenceData.sensorTime) & 0xFFFF;
|
int eventTimeChange = (eventTime - lastCadenceData.eventTime) & 0xFFFF;
|
||||||
if (sensorTimeChange != 0) {
|
if (eventTimeChange != 0) {
|
||||||
counterChange = (counter - lastCadenceData.counter) & 0xFFFF;
|
countChange = (count - lastCadenceData.count) & 0xFFFF;
|
||||||
eventsPerMinute = counterChange * SENSOR_TIME_PER_MINUTE / sensorTimeChange;
|
eventsPerMinute = countChange * EVENT_TIME_PER_MINUTE / eventTimeChange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
history.addLast(new CadenceData(now, counter, sensorTime));
|
history.addLast(new CadenceData(now, count, eventTime));
|
||||||
return eventsPerMinute;
|
return eventsPerMinute;
|
||||||
} else {
|
} else {
|
||||||
// The sensor has resent old data
|
// The sensor has resent old data
|
||||||
@@ -114,9 +114,9 @@ public class CadenceCounter {
|
|||||||
eventsPerMinute = 0;
|
eventsPerMinute = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Too much time has passed since the last counter change. A smaller value
|
* Too much time has passed since the last count change. A smaller value
|
||||||
* than eventsPerMinute must be returned. The value is calculated from the
|
* than eventsPerMinute must be returned. The value is calculated from the
|
||||||
* history.
|
* history.
|
||||||
*/
|
*/
|
||||||
@@ -133,12 +133,12 @@ public class CadenceCounter {
|
|||||||
private int getValueFromHistory(long now) {
|
private int getValueFromHistory(long now) {
|
||||||
CadenceData firstCadenceData = history.getFirst();
|
CadenceData firstCadenceData = history.getFirst();
|
||||||
CadenceData lastCadenceData = history.getLast();
|
CadenceData lastCadenceData = history.getLast();
|
||||||
int sensorTimeChange = (lastCadenceData.sensorTime - firstCadenceData.sensorTime) & 0xFFFF;
|
int eventTimeChange = (lastCadenceData.eventTime - firstCadenceData.eventTime) & 0xFFFF;
|
||||||
int counterChange = (lastCounter - firstCadenceData.counter) & 0xFFFF;
|
int countChange = (lastCount - firstCadenceData.count) & 0xFFFF;
|
||||||
|
|
||||||
// (now - lastCadenceData) + (lastCadenceData - firstCadenceData)
|
// (now - lastCadenceData) + (lastCadenceData - firstCadenceData)
|
||||||
int systemTimeChange = (int) (now - lastCadenceData.systemTime
|
int systemTimeChange = (int) (now - lastCadenceData.systemTime
|
||||||
+ (sensorTimeChange * MILLIS_PER_MINUTE) / SENSOR_TIME_PER_MINUTE);
|
+ (eventTimeChange * MILLIS_PER_MINUTE) / EVENT_TIME_PER_MINUTE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* eventsPerMinute is not updated because it is still needed when a new
|
* eventsPerMinute is not updated because it is still needed when a new
|
||||||
@@ -147,12 +147,12 @@ public class CadenceCounter {
|
|||||||
if (systemTimeChange == 0) {
|
if (systemTimeChange == 0) {
|
||||||
return eventsPerMinute;
|
return eventsPerMinute;
|
||||||
}
|
}
|
||||||
int value = (counterChange * MILLIS_PER_MINUTE) / systemTimeChange;
|
int value = (countChange * MILLIS_PER_MINUTE) / systemTimeChange;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not return a larger number than eventsPerMinute because this function
|
* Do not return a larger number than eventsPerMinute because this function
|
||||||
* is only called when more time has passed after the last counter change
|
* is only called when more time has passed after the last count change than
|
||||||
* than the interval from eventsPerMinute.
|
* the interval from eventsPerMinute.
|
||||||
*/
|
*/
|
||||||
return value < eventsPerMinute ? value : eventsPerMinute;
|
return value < eventsPerMinute ? value : eventsPerMinute;
|
||||||
}
|
}
|
||||||
|
|||||||
+99
-11
@@ -16,20 +16,108 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.services.sensors.ant;
|
package com.google.android.apps.mytracks.services.sensors.ant;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.services.sensors.ant.AntSensorManager.ChannelStates;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ant channel configuration.
|
* Ant channel configuration.
|
||||||
*
|
*
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
public class ChannelConfiguration {
|
public abstract class ChannelConfiguration {
|
||||||
|
|
||||||
public short deviceNumber;
|
public static final byte FREQUENCY = 57; // 2457Mhz (Ant+ frequency)
|
||||||
public byte deviceType;
|
public static final byte TRANSMISSION_TYPE = 0; // 0 for wild card search
|
||||||
public byte TransmissionType;
|
public static final byte PROXIMITY_SEARCH = 7;
|
||||||
public short period;
|
|
||||||
public byte freq;
|
private short deviceNumber = AntSensorManager.WILDCARD;
|
||||||
public byte proxSearch;
|
private ChannelStates channelState = ChannelStates.CLOSED;
|
||||||
public boolean isInitializing = false;
|
private boolean isInitializing = false;
|
||||||
public boolean isDeinitializing = false;
|
private boolean isDeinitializing = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the My Tracks settings device id key.
|
||||||
|
*/
|
||||||
|
public abstract int getDeviceIdKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the device type.
|
||||||
|
*/
|
||||||
|
public abstract byte getDeviceType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message period.
|
||||||
|
*/
|
||||||
|
public abstract short getMessagPeriod();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the message and places the value in antSensorValue.
|
||||||
|
*
|
||||||
|
* @param message the message
|
||||||
|
* @param antSensorValue the ant sensor value
|
||||||
|
*/
|
||||||
|
public abstract void decodeMessage(byte[] message, AntSensorValue antSensorValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the device number.
|
||||||
|
*/
|
||||||
|
public short getDeviceNumber() {
|
||||||
|
return deviceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the device number.
|
||||||
|
*
|
||||||
|
* @param deviceNumber the device number to set
|
||||||
|
*/
|
||||||
|
public void setDeviceNumber(short deviceNumber) {
|
||||||
|
this.deviceNumber = deviceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the channel state.
|
||||||
|
*/
|
||||||
|
public ChannelStates getChannelState() {
|
||||||
|
return channelState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the channel state.
|
||||||
|
*
|
||||||
|
* @param channelState the channelState to set
|
||||||
|
*/
|
||||||
|
public void setChannelState(ChannelStates channelState) {
|
||||||
|
this.channelState = channelState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if initializing.
|
||||||
|
*/
|
||||||
|
public boolean isInitializing() {
|
||||||
|
return isInitializing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets isInitializing.
|
||||||
|
*
|
||||||
|
* @param isInitializing true if isInitializing
|
||||||
|
*/
|
||||||
|
public void setInitializing(boolean isInitializing) {
|
||||||
|
this.isInitializing = isInitializing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if deinitializing.
|
||||||
|
*/
|
||||||
|
public boolean isDeinitializing() {
|
||||||
|
return isDeinitializing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets isDeinitializing.
|
||||||
|
*
|
||||||
|
* @param isDeinitializing true if isDeinitializing
|
||||||
|
*/
|
||||||
|
public void setDeinitializing(boolean isDeinitializing) {
|
||||||
|
this.isDeinitializing = isDeinitializing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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.ant;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combined bike sensor channel configuration.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class CombinedBikeChannelConfiguration extends ChannelConfiguration {
|
||||||
|
|
||||||
|
private static final int DEVICE_ID_KEY = R.string.ant_combined_bike_sensor_id_key;
|
||||||
|
private static final byte DEVICE_TYPE = 0x79;
|
||||||
|
private static final short MESSAGE_PERIOD = 8086;
|
||||||
|
|
||||||
|
private CadenceCounter cadenceCounter = new CadenceCounter();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDeviceIdKey() {
|
||||||
|
return DEVICE_ID_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getDeviceType() {
|
||||||
|
return DEVICE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getMessagPeriod() {
|
||||||
|
return MESSAGE_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decodeMessage(byte[] message, AntSensorValue antSensorValue) {
|
||||||
|
int revolutionCount = ((int) message[5] & 0xFF) + ((int) message[6] & 0xFF) * 256;
|
||||||
|
int eventTime = ((int) message[3] & 0xFF) + ((int) message[4] & 0xFF) * 256;
|
||||||
|
|
||||||
|
antSensorValue.setCadence(cadenceCounter.getEventsPerMinute(revolutionCount, eventTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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.ant;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heart rate monitor channel configuration.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class HeartRateChannelConfiguration extends ChannelConfiguration {
|
||||||
|
|
||||||
|
private static final int DEVICE_ID_KEY = R.string.ant_heart_rate_monitor_id_key;
|
||||||
|
private static final byte DEVICE_TYPE = 0x78;
|
||||||
|
private static final short MESSAGE_PERIOD = 8070;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDeviceIdKey() {
|
||||||
|
return DEVICE_ID_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getDeviceType() {
|
||||||
|
return DEVICE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getMessagPeriod() {
|
||||||
|
return MESSAGE_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decodeMessage(byte[] message, AntSensorValue antSensorValue) {
|
||||||
|
antSensorValue.setHeartRate(message[10] & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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.ant;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speed distance monitor channel configuration.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class SpeedDistanceChannelConfiguration extends ChannelConfiguration {
|
||||||
|
|
||||||
|
private static final int DEVICE_ID_KEY = R.string.ant_speed_distance_monitor_id_key;
|
||||||
|
private static final byte DEVICE_TYPE = 0x7C;
|
||||||
|
private static final short MESSAGE_PERIOD = 8134;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDeviceIdKey() {
|
||||||
|
return DEVICE_ID_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getDeviceType() {
|
||||||
|
return DEVICE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getMessagPeriod() {
|
||||||
|
return MESSAGE_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decodeMessage(byte[] message, AntSensorValue antSensorValue) {
|
||||||
|
// Check page 2 data
|
||||||
|
if (message[3] == 0x02) {
|
||||||
|
antSensorValue.setCadence(
|
||||||
|
(int) ((message[6] & 0xFF) + (((message[7] >>> 4) & 0x0F) / 16.0f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user