From 5d2144f698980745152b43808bf1d0a1b1cdfbd5 Mon Sep 17 00:00:00 2001 From: Jimmy Shih Date: Tue, 19 Jun 2012 15:13:01 -0700 Subject: [PATCH] Refactor AntSensorManager so each ChannelConfiguration is in its own class. --- .../sensors/ant/AntSensorManager.java | 438 ++++-------------- .../services/sensors/ant/AntSensorValue.java | 60 +++ .../ant/BikeCadenceChannelConfiguration.java | 55 +++ .../services/sensors/ant/CadenceCounter.java | 70 +-- .../sensors/ant/ChannelConfiguration.java | 110 ++++- .../ant/CombinedBikeChannelConfiguration.java | 56 +++ .../ant/HeartRateChannelConfiguration.java | 51 ++ .../SpeedDistanceChannelConfiguration.java | 55 +++ 8 files changed, 507 insertions(+), 388 deletions(-) create mode 100644 MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorValue.java create mode 100644 MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/BikeCadenceChannelConfiguration.java create mode 100644 MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CombinedBikeChannelConfiguration.java create mode 100644 MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/HeartRateChannelConfiguration.java create mode 100644 MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/SpeedDistanceChannelConfiguration.java diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java index 8f86d40bb..7f52846d9 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java @@ -41,7 +41,7 @@ import java.lang.reflect.Field; /** * Ant Sensor Manager. - * + * * @author Jimmy Shih */ public class AntSensorManager extends SensorManager { @@ -58,33 +58,12 @@ public class AntSensorManager extends SensorManager { // recently 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; - + + private static final String TAG = AntSensorManager.class.getSimpleName(); 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 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 ChannelConfiguration channelConfig[]; @@ -93,38 +72,26 @@ public class AntSensorManager extends SensorManager { private boolean serviceConnected = 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 int lastHeartRate = -1; - private int lastCadence = -1; private long lastSensorDataSetTime = 0; - - private CadenceCounter bcsCadenceCounter; - private CadenceCounter cbsCadenceCounter; - + private AntSensorValue antSensorValue = new AntSensorValue(); + private boolean requestedReset = false; /** * Constructor. - * + * * @param context the context */ public AntSensorManager(Context context) { this.context = context; channelConfig = new ChannelConfiguration[CHANNELS]; - channelConfig[HRM_CHANNEL] = new ChannelConfiguration(); - channelConfig[SDM_CHANNEL] = new ChannelConfiguration(); - channelConfig[BCS_CHANNEL] = new ChannelConfiguration(); - channelConfig[CBS_CHANNEL] = new ChannelConfiguration(); + channelConfig[0] = new HeartRateChannelConfiguration(); + channelConfig[1] = new SpeedDistanceChannelConfiguration(); + channelConfig[2] = new BikeCadenceChannelConfiguration(); + channelConfig[3] = new CombinedBikeChannelConfiguration(); statusIntentFilter = new IntentFilter(); statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION); @@ -171,7 +138,7 @@ public class AntSensorManager extends SensorManager { } } } - + @Override protected void tearDownChannel() { try { @@ -214,12 +181,12 @@ public class AntSensorManager extends SensorManager { } private AntInterface.ServiceListener serviceListener = new AntInterface.ServiceListener() { - @Override + @Override public void onServiceConnected() { handleServiceConnected(); } - @Override + @Override public void onServiceDisconnected() { serviceConnected = false; if (hasClaimedInterface) { @@ -256,89 +223,26 @@ public class AntSensorManager extends SensorManager { /** * Opens a channel. - * + * * @param channel the channel */ private void openChannel(byte channel) { - channelConfig[channel].deviceNumber = 0; - channelConfig[channel].deviceType = 0; - channelConfig[channel].TransmissionType = ANT_TRANSMISSION_TYPE; - channelConfig[channel].period = 0; - 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; - } + short deviceNumber = (short) PreferencesUtils.getInt( + context, channelConfig[channel].getDeviceIdKey(), WILDCARD); + channelConfig[channel].setDeviceNumber(deviceNumber); + channelConfig[channel].setChannelState(ChannelStates.PENDING_OPEN); setupAntChannel(ANT_NETWORK, channel); } /** * Closes a channel. - * + * * @param channel the channel */ private void closeChannel(byte channel) { - channelConfig[channel].isInitializing = false; - channelConfig[channel].isDeinitializing = true; - switch (channel) { - 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; - } + channelConfig[channel].setInitializing(false); + channelConfig[channel].setDeinitializing(true); + channelConfig[channel].setChannelState(ChannelStates.CLOSED); setSensorState(SensorState.DISCONNECTED); try { antInterface.ANTCloseChannel(channel); @@ -353,10 +257,9 @@ public class AntSensorManager extends SensorManager { * Clears all channels. */ private void clearAllChannels() { - hrmState = ChannelStates.CLOSED; - sdmState = ChannelStates.CLOSED; - bcsState = ChannelStates.CLOSED; - cbsState = ChannelStates.CLOSED; + for (int i = 0; i < CHANNELS; i++) { + channelConfig[i].setChannelState(ChannelStates.CLOSED); + } setSensorState(SensorState.DISCONNECTED); } @@ -427,66 +330,42 @@ public class AntSensorManager extends SensorManager { }; private final BroadcastReceiver dataReceiver = new BroadcastReceiver() { - @Override + @Override public void onReceive(Context c, Intent intent) { if (intent.getAction().equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) { - byte[] ANTRxMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE); - switch (ANTRxMessage[AntMesg.MESG_ID_OFFSET]) { + byte[] antRxMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE); + byte channel; + switch (antRxMessage[AntMesg.MESG_ID_OFFSET]) { case AntMesg.MESG_BROADCAST_DATA_ID: case AntMesg.MESG_ACKNOWLEDGED_DATA_ID: - // Switch on channel number - switch (ANTRxMessage[AntMesg.MESG_DATA_OFFSET]) { - case HRM_CHANNEL: - decodeHrmMessage(ANTRxMessage); - break; - case SDM_CHANNEL: - decodeSdmMessage(ANTRxMessage); - break; - case BCS_CHANNEL: - decodeBcsMessage(ANTRxMessage); - break; - case CBS_CHANNEL: - decodeCbsMessage(ANTRxMessage); - break; - default: - break; + channel = antRxMessage[AntMesg.MESG_DATA_OFFSET]; + if (channelConfig[channel].getChannelState() != ChannelStates.CLOSED) { + channelConfig[channel].setChannelState(ChannelStates.TRACKING_DATA); } + + 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; case AntMesg.MESG_RESPONSE_EVENT_ID: - handleResponseEventMessage(ANTRxMessage); + handleResponseEventMessage(antRxMessage); break; case AntMesg.MESG_CHANNEL_ID_ID: - short deviceNum = (short) ((ANTRxMessage[AntMesg.MESG_DATA_OFFSET + 1] & 0xFF - | ((ANTRxMessage[AntMesg.MESG_DATA_OFFSET + 2] & 0xFF) << 8)) & 0xFFFF); - int keyId = -1; - // Switch on channel number - switch (ANTRxMessage[AntMesg.MESG_DATA_OFFSET]) { - case HRM_CHANNEL: - hrmDeviceNumber = deviceNum; - keyId = R.string.ant_heart_rate_monitor_id_key; - break; - 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); - } + channel = antRxMessage[AntMesg.MESG_DATA_OFFSET]; + short deviceNumber = (short) ((antRxMessage[AntMesg.MESG_DATA_OFFSET + 1] & 0xFF + | ((antRxMessage[AntMesg.MESG_DATA_OFFSET + 2] & 0xFF) << 8)) & 0xFFFF); + channelConfig[channel].setDeviceNumber(deviceNumber); + PreferencesUtils.setInt(context, channelConfig[channel].getDeviceIdKey(), deviceNumber); + Toast.makeText(context, + context.getString(R.string.settings_sensor_connected, deviceNumber), + Toast.LENGTH_SHORT).show(); + setSensorState(SensorState.CONNECTED); break; default: break; @@ -496,72 +375,54 @@ public class AntSensorManager extends SensorManager { /** * Handles response event message. - * + * * @param message the message */ private void handleResponseEventMessage(byte[] message) { // For a list of possible message codes see ANT Message Protocol and Usage // 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) && (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.EVENT_RX_SEARCH_TIMEOUT)) { // A channel timed out searching, unassign it - channelConfig[channelNumber].isInitializing = false; - channelConfig[channelNumber].isDeinitializing = false; - switch (channelNumber) { - 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; - } + channelConfig[channel].setInitializing(false); + channelConfig[channel].setDeinitializing(false); + channelConfig[channel].setChannelState(ChannelStates.OFFLINE); try { - antInterface.ANTUnassignChannel(channelNumber); + antInterface.ANTUnassignChannel(channel); } catch (AntInterfaceException e) { handleAntError(); } setSensorState(SensorState.DISCONNECTED); } - if (channelConfig[channelNumber].isInitializing) { + if (channelConfig[channel].isInitializing()) { if (message[AntMesg.MESG_DATA_OFFSET + 2] != 0) { // Error response 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 + 1], channelNumber)); + message[AntMesg.MESG_DATA_OFFSET + 2], message[AntMesg.MESG_DATA_OFFSET + 1], + channel)); } else { // Switch on message id switch (message[AntMesg.MESG_DATA_OFFSET + 1]) { case AntMesg.MESG_ASSIGN_CHANNEL_ID: try { - antInterface.ANTSetChannelId(channelNumber, - channelConfig[channelNumber].deviceNumber, - channelConfig[channelNumber].deviceType, - channelConfig[channelNumber].TransmissionType); + antInterface.ANTSetChannelId(channel, channelConfig[channel].getDeviceNumber(), + channelConfig[channel].getDeviceType(), ChannelConfiguration.TRANSMISSION_TYPE); } catch (AntInterfaceException e) { handleAntError(); } break; case AntMesg.MESG_CHANNEL_ID_ID: try { - antInterface.ANTSetChannelPeriod( - channelNumber, channelConfig[channelNumber].period); + antInterface.ANTSetChannelPeriod(channel, channelConfig[channel].getMessagPeriod()); } catch (AntInterfaceException e) { handleAntError(); } break; case AntMesg.MESG_CHANNEL_MESG_PERIOD_ID: try { - antInterface.ANTSetChannelRFFreq(channelNumber, channelConfig[channelNumber].freq); + antInterface.ANTSetChannelRFFreq(channel, ChannelConfiguration.FREQUENCY); } catch (AntInterfaceException e) { handleAntError(); } @@ -569,7 +430,7 @@ public class AntSensorManager extends SensorManager { case AntMesg.MESG_CHANNEL_RADIO_FREQ_ID: try { // Disable high priority search - antInterface.ANTSetChannelSearchTimeout(channelNumber, (byte) 0); + antInterface.ANTSetChannelSearchTimeout(channel, (byte) 0); } catch (AntInterfaceException e) { handleAntError(); } @@ -577,23 +438,23 @@ public class AntSensorManager extends SensorManager { case AntMesg.MESG_CHANNEL_SEARCH_TIMEOUT_ID: try { // Set search timeout to 30 seconds (low priority search) - antInterface.ANTSetLowPriorityChannelSearchTimeout(channelNumber, (byte) 12); + antInterface.ANTSetLowPriorityChannelSearchTimeout(channel, (byte) 12); } catch (AntInterfaceException e) { handleAntError(); } break; case AntMesg.MESG_SET_LP_SEARCH_TIMEOUT_ID: - if (channelConfig[channelNumber].deviceNumber == WILDCARD) { + if (channelConfig[channel].getDeviceNumber() == WILDCARD) { try { // Configure proximity search, if using wild card search antInterface.ANTSetProximitySearch( - channelNumber, channelConfig[channelNumber].proxSearch); + channel, ChannelConfiguration.PROXIMITY_SEARCH); } catch (AntInterfaceException e) { handleAntError(); } } else { try { - antInterface.ANTOpenChannel(channelNumber); + antInterface.ANTOpenChannel(channel); } catch (AntInterfaceException e) { handleAntError(); } @@ -601,162 +462,57 @@ public class AntSensorManager extends SensorManager { break; case AntMesg.MESG_PROX_SEARCH_CONFIG_ID: try { - antInterface.ANTOpenChannel(channelNumber); + antInterface.ANTOpenChannel(channel); } catch (AntInterfaceException e) { handleAntError(); } break; case AntMesg.MESG_OPEN_CHANNEL_ID: - channelConfig[channelNumber].isInitializing = false; - switch (channelNumber) { - 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; - } + channelConfig[channel].setInitializing(false); + channelConfig[channel].setChannelState(ChannelStates.SEARCHING); break; default: break; } } - } else if (channelConfig[channelNumber].isDeinitializing) { + } else if (channelConfig[channel].isDeinitializing()) { if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_EVENT_ID) && (message[AntMesg.MESG_DATA_OFFSET + 2] == AntDefine.EVENT_CHANNEL_CLOSED)) { try { - antInterface.ANTUnassignChannel(channelNumber); + antInterface.ANTUnassignChannel(channel); } catch (AntInterfaceException e) { handleAntError(); } } else if ((message[AntMesg.MESG_DATA_OFFSET + 1] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) && (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. */ - private void setSenorDataSet() { + private void setSensorDataSet() { long now = System.currentTimeMillis(); // Data comes in at ~4Hz rate from the sensors, so after >300 msec fresh // data is here from all the connected sensors - if (now < lastSensorDataSetTime + 300) { return; } + if (now < lastSensorDataSetTime + 300) { + return; + } lastSensorDataSetTime = now; SensorDataSet.Builder builder = Sensor.SensorDataSet.newBuilder(); - if (lastHeartRate != -1) { + int heartRate = antSensorValue.getHeartRate(); + if (heartRate != -1) { 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() - .setValue(lastCadence).setState(Sensor.SensorState.SENDING)); + .setValue(cadence).setState(Sensor.SensorState.SENDING)); } sensorDataSet = builder.setCreationTime(now).build(); setSensorState(SensorState.SENDING); @@ -764,14 +520,14 @@ public class AntSensorManager extends SensorManager { /** * Sets up ant channel. - * + * * @param networkNumber the network number * @param channel the channel */ private void setupAntChannel(byte networkNumber, byte channel) { try { - channelConfig[channel].isInitializing = true; - channelConfig[channel].isDeinitializing = false; + channelConfig[channel].setInitializing(true); + channelConfig[channel].setDeinitializing(false); // Assign as slave channel on selected network antInterface.ANTAssignChannel(channel, AntDefine.PARAMETER_RX_NOT_TX, networkNumber); @@ -785,24 +541,22 @@ public class AntSensorManager extends SensorManager { /** * Enables data message. - * + * * @param enabled true to enable */ private void enableDataMessage(boolean enabled) { if (enabled) { context.registerReceiver( dataReceiver, new IntentFilter(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)); - openChannel(HRM_CHANNEL); - openChannel(SDM_CHANNEL); - openChannel(BCS_CHANNEL); - openChannel(CBS_CHANNEL); + for (int i = 0; i < CHANNELS; i++) { + openChannel((byte) i); + } } else { try { context.unregisterReceiver(dataReceiver); - closeChannel(HRM_CHANNEL); - closeChannel(SDM_CHANNEL); - closeChannel(BCS_CHANNEL); - closeChannel(CBS_CHANNEL); + for (int i = 0; i < CHANNELS; i++) { + closeChannel((byte) i); + } setSensorState(SensorState.DISCONNECTED); } catch (IllegalArgumentException e) { // Can safely ignore diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorValue.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorValue.java new file mode 100644 index 000000000..ca74d3946 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorValue.java @@ -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; + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/BikeCadenceChannelConfiguration.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/BikeCadenceChannelConfiguration.java new file mode 100644 index 000000000..061fd71fc --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/BikeCadenceChannelConfiguration.java @@ -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)); + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CadenceCounter.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CadenceCounter.java index 4080a654c..d49e66ab9 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CadenceCounter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CadenceCounter.java @@ -19,9 +19,9 @@ package com.google.android.apps.mytracks.services.sensors.ant; import java.util.LinkedList; /** - * Counter that processes an Ant+ sensor data (counter + sensor time pair) and - * returns the instantaneous cadence value. - * + * A counter that processes an Ant+ sensor data (count + event time) and returns + * the instantaneous cadence value. + * * @author Laszlo Molnar */ public class CadenceCounter { @@ -29,7 +29,7 @@ public class CadenceCounter { 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_SIZE = 100; - private static final int SENSOR_TIME_PER_MINUTE = 60 * 1024; + private static final int EVENT_TIME_PER_MINUTE = 60 * 1024; /** * Cadence data. @@ -38,18 +38,18 @@ public class CadenceCounter { */ private static class CadenceData { final long systemTime; - final int counter; - final int sensorTime; + final int count; + final int eventTime; - private CadenceData(long systemTime, int counter, int sensorTime) { + private CadenceData(long systemTime, int count, int eventTime) { this.systemTime = systemTime; - this.counter = counter; - this.sensorTime = sensorTime; + this.count = count; + this.eventTime = eventTime; } } - // The last counter value - private int lastCounter; + // The last count + private int lastCount; // The last calculated cadence private int eventsPerMinute; @@ -58,7 +58,7 @@ public class CadenceCounter { private LinkedList history; public CadenceCounter() { - lastCounter = -1; + lastCount = -1; eventsPerMinute = 0; history = new LinkedList(); } @@ -66,35 +66,35 @@ public class CadenceCounter { /** * Gets the cadence value. * - * @param counter counter - * @param sensorTime sensor time + * @param count count + * @param eventTime event time */ - public int getEventsPerMinute(int counter, int sensorTime) { + public int getEventsPerMinute(int count, int eventTime) { 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 - * not updating the history. + * eventTime for the initial count value is probably out of date, so not + * updating the history. */ - lastCounter = counter; + lastCount = count; eventsPerMinute = 0; return 0; } - lastCounter = counter; + lastCount = count; - if (counterChange != 0) { + if (countChange != 0) { if (removeOldHistory(now)) { CadenceData lastCadenceData = history.getLast(); - int sensorTimeChange = (sensorTime - lastCadenceData.sensorTime) & 0xFFFF; - if (sensorTimeChange != 0) { - counterChange = (counter - lastCadenceData.counter) & 0xFFFF; - eventsPerMinute = counterChange * SENSOR_TIME_PER_MINUTE / sensorTimeChange; + int eventTimeChange = (eventTime - lastCadenceData.eventTime) & 0xFFFF; + if (eventTimeChange != 0) { + countChange = (count - lastCadenceData.count) & 0xFFFF; + eventsPerMinute = countChange * EVENT_TIME_PER_MINUTE / eventTimeChange; } } - history.addLast(new CadenceData(now, counter, sensorTime)); + history.addLast(new CadenceData(now, count, eventTime)); return eventsPerMinute; } else { // The sensor has resent old data @@ -114,9 +114,9 @@ public class CadenceCounter { eventsPerMinute = 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 * history. */ @@ -133,12 +133,12 @@ public class CadenceCounter { private int getValueFromHistory(long now) { CadenceData firstCadenceData = history.getFirst(); CadenceData lastCadenceData = history.getLast(); - int sensorTimeChange = (lastCadenceData.sensorTime - firstCadenceData.sensorTime) & 0xFFFF; - int counterChange = (lastCounter - firstCadenceData.counter) & 0xFFFF; + int eventTimeChange = (lastCadenceData.eventTime - firstCadenceData.eventTime) & 0xFFFF; + int countChange = (lastCount - firstCadenceData.count) & 0xFFFF; // (now - lastCadenceData) + (lastCadenceData - firstCadenceData) 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 @@ -147,12 +147,12 @@ public class CadenceCounter { if (systemTimeChange == 0) { 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 - * is only called when more time has passed after the last counter change - * than the interval from eventsPerMinute. + * is only called when more time has passed after the last count change than + * the interval from eventsPerMinute. */ return value < eventsPerMinute ? value : eventsPerMinute; } diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/ChannelConfiguration.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/ChannelConfiguration.java index e08b3de24..f13cd15f8 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/ChannelConfiguration.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/ChannelConfiguration.java @@ -16,20 +16,108 @@ package com.google.android.apps.mytracks.services.sensors.ant; +import com.google.android.apps.mytracks.services.sensors.ant.AntSensorManager.ChannelStates; + /** * Ant channel configuration. - * + * * @author Jimmy Shih */ -public class ChannelConfiguration { +public abstract class ChannelConfiguration { - public short deviceNumber; - public byte deviceType; - public byte TransmissionType; - public short period; - public byte freq; - public byte proxSearch; - public boolean isInitializing = false; - public boolean isDeinitializing = false; + public static final byte FREQUENCY = 57; // 2457Mhz (Ant+ frequency) + public static final byte TRANSMISSION_TYPE = 0; // 0 for wild card search + public static final byte PROXIMITY_SEARCH = 7; + + private short deviceNumber = AntSensorManager.WILDCARD; + private ChannelStates channelState = ChannelStates.CLOSED; + private boolean isInitializing = 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; + } } - diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CombinedBikeChannelConfiguration.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CombinedBikeChannelConfiguration.java new file mode 100644 index 000000000..784aaa4da --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/CombinedBikeChannelConfiguration.java @@ -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)); + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/HeartRateChannelConfiguration.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/HeartRateChannelConfiguration.java new file mode 100644 index 000000000..6ae2d2ae7 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/HeartRateChannelConfiguration.java @@ -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); + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/SpeedDistanceChannelConfiguration.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/SpeedDistanceChannelConfiguration.java new file mode 100644 index 000000000..a107bcec9 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/SpeedDistanceChannelConfiguration.java @@ -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))); + } + } +}