/*
* Copyright (c) 2013, Will Szumski
* Copyright (c) 2013, Doug Szumski
*
* This file is part of Cyclismo.
*
* Cyclismo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cyclismo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cyclismo. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* 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 org.cowboycoders.cyclismo.services.sensors.ant;
import org.cowboycoders.cyclismo.content.Sensor.SensorDataSet;
import org.cowboycoders.cyclismo.services.sensors.SensorManager;
/**
* Ant Sensor Manager.
*
* @author Jimmy Shih
*/
public class AntSensorManager extends SensorManager {
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return false;
}
@Override
protected void setUpChannel() {
// TODO Auto-generated method stub
}
@Override
protected void tearDownChannel() {
// TODO Auto-generated method stub
}
@Override
public SensorDataSet getSensorDataSet() {
// TODO Auto-generated method stub
return null;
}
/**
* Channel States
*/
public enum ChannelStates {
CLOSED, // Channel is closed
PENDING_OPEN, // User has requested opening the channel, waiting for a reset
SEARCHING, // Channel is opened, but has not received data
TRACKING_STATUS, // Channel is opened and has received status data recently
TRACKING_DATA, // Channel is opened and has received measurement data
// recently
OFFLINE // Channel is closed as the result of a search timeout
}
public static final short WILDCARD = 0;
// private static final String TAG = AntSensorManager.class.getSimpleName();
// private static final int CHANNELS = 4;
// private static final String RADIO_ANT = "ant";
// private static final byte ANT_NETWORK = (byte) 0x01;
//
// private final Context context;
// private final ChannelConfiguration channelConfig[];
// private final IntentFilter statusIntentFilter;
// private final AntInterface antInterface;
//
// private boolean serviceConnected = false;
// private boolean hasClaimedInterface = false;
//
// private SensorDataSet sensorDataSet = null;
// private long lastSensorDataSetTime = 0;
// private AntSensorValue antSensorValue = new AntSensorValue();
//
// private boolean requestedReset = false;
//
// private AntInterface.ServiceListener serviceListener = new AntInterface.ServiceListener() {
// @Override
// public void onServiceConnected() {
// setSensorState(Sensor.SensorState.CONNECTING);
// serviceConnected = true;
// try {
// hasClaimedInterface = antInterface.hasClaimedInterface();
// if (!hasClaimedInterface) {
// hasClaimedInterface = antInterface.claimInterface();
// }
// if (!hasClaimedInterface) {
// tryClaimAnt();
// return;
// }
// if (!antInterface.isEnabled()) {
// antInterface.enable();
// }
// requestReset();
// enableDataMessage(true);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// }
//
// @Override
// public void onServiceDisconnected() {
// serviceConnected = false;
// if (hasClaimedInterface) {
// enableDataMessage(false);
// }
// setSensorState(SensorState.DISCONNECTED);
// }
// };
//
// /**
// * Constructor.
// *
// * @param context the context
// */
// public AntSensorManager(Context context) {
// this.context = context;
//
// channelConfig = new ChannelConfiguration[CHANNELS];
// 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);
// statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLING_ACTION);
// statusIntentFilter.addAction(AntInterfaceIntent.ANT_DISABLED_ACTION);
// statusIntentFilter.addAction(AntInterfaceIntent.ANT_DISABLING_ACTION);
// statusIntentFilter.addAction(AntInterfaceIntent.ANT_RESET_ACTION);
// statusIntentFilter.addAction(AntInterfaceIntent.ANT_INTERFACE_CLAIMED_ACTION);
// statusIntentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
//
// antInterface = new AntInterface();
// }
//
// @Override
// protected synchronized void setUpChannel() {
// tearDownChannel();
// if (AntInterface.hasAntSupport(context)) {
// context.registerReceiver(statusReceiver, statusIntentFilter);
// if (!antInterface.initService(context, serviceListener)) {
// AntInterface.goToMarket(context);
// }
// }
// }
//
// @Override
// protected void tearDownChannel() {
// try {
// context.unregisterReceiver(statusReceiver);
// } catch (IllegalArgumentException e) {
// // Can safely ignore
// }
// enableDataMessage(false);
// if (serviceConnected) {
// try {
// if (hasClaimedInterface) {
// antInterface.releaseInterface();
// }
// hasClaimedInterface = false;
// antInterface.stopRequestForceClaimInterface();
// } catch (AntServiceNotConnectedException e) {
// // Can safely ignore
// } catch (AntInterfaceException e) {
// Log.w(TAG, "Exception in tearDonwChannel.", e);
// }
// antInterface.releaseService();
// serviceConnected = false;
// }
// setSensorState(SensorState.DISCONNECTED);
// }
//
// @Override
// public SensorDataSet getSensorDataSet() {
// return sensorDataSet;
// }
//
// /**
// * Tries to claim the ant interface.
// */
// private void tryClaimAnt() {
// try {
// antInterface.requestForceClaimInterface(context.getString(R.string.my_tracks_app_name));
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// }
//
// /**
// * Configures ant radio.
// */
// private void configureAntRadio() {
// try {
// if (serviceConnected && hasClaimedInterface && antInterface.isEnabled()) {
// try {
// antInterface.ANTDisableEventBuffering();
// } catch (AntInterfaceException e) {
// Log.e(TAG, "Cannot disable event buffering.", e);
// }
// } else {
// Log.i(TAG, "Cannot disable event buffering now.");
// }
// } catch (AntInterfaceException e) {
// Log.e(TAG, "Unable to check enabled state.", e);
// }
// }
//
// /**
// * Handles ant error.
// */
// private void handleAntError() {
// clearAllChannels();
// }
//
// /**
// * Opens a channel.
// *
// * @param channel the channel
// */
// private void openChannel(byte channel) {
// 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].setInitializing(false);
// channelConfig[channel].setDeinitializing(true);
// channelConfig[channel].setChannelState(ChannelStates.CLOSED);
// try {
// antInterface.ANTCloseChannel(channel);
// // Note, unassign channel after getting channel closed event
// } catch (AntInterfaceException e) {
// Log.w(TAG, "Unable to close channel: " + channel, e);
// handleAntError();
// }
// }
//
// /**
// * Clears all channels.
// */
// private void clearAllChannels() {
// for (int i = 0; i < CHANNELS; i++) {
// channelConfig[i].setChannelState(ChannelStates.CLOSED);
// }
// setSensorState(SensorState.DISCONNECTED);
// }
//
// /**
// * Requests reset.
// */
// private void requestReset() {
// try {
// requestedReset = true;
// antInterface.ANTResetSystem();
// configureAntRadio();
// } catch (AntInterfaceException e) {
// Log.e(TAG, "Unable to reset ant.", e);
// requestedReset = false;
// }
// }
//
// @Override
// public boolean isEnabled() {
// if (antInterface == null || !antInterface.isServiceConnected()) {
// return false;
// }
// try {
// return antInterface.isEnabled();
// } catch (AntInterfaceException e) {
// Log.w(TAG, "Unable to check enabled.", e);
// return false;
// }
// }
//
// private final BroadcastReceiver statusReceiver = new BroadcastReceiver() {
// public void onReceive(Context c, Intent intent) {
// String ANTAction = intent.getAction();
// if (ANTAction.equals(AntInterfaceIntent.ANT_DISABLED_ACTION)) {
// clearAllChannels();
// } else if (ANTAction.equals(AntInterfaceIntent.ANT_RESET_ACTION)) {
// if (!requestedReset) {
// // Someone else triggered an ant reset
// clearAllChannels();
// } else {
// requestedReset = false;
// configureAntRadio();
// }
// } else if (ANTAction.equals(AntInterfaceIntent.ANT_INTERFACE_CLAIMED_ACTION)) {
// boolean wasClaimed = hasClaimedInterface;
//
// // Could also read ANT_INTERFACE_CLAIMED_PID from intent and see if it
// // matches the current process PID.
// try {
// hasClaimedInterface = antInterface.hasClaimedInterface();
// if (hasClaimedInterface) {
// enableDataMessage(true);
// } else {
// if (wasClaimed) {
// // Claimed by another application
// enableDataMessage(false);
// setSensorState(SensorState.DISCONNECTED);
// }
// }
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// } else if (ANTAction.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
// if (isAirPlaneMode()) {
// clearAllChannels();
// }
// }
// }
// };
//
// private final BroadcastReceiver dataReceiver = new BroadcastReceiver() {
// @Override
// public void onReceive(Context c, Intent intent) {
// if (intent.getAction().equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) {
// 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:
// 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);
// break;
// case AntMesg.MESG_CHANNEL_ID_ID:
// 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;
// }
// }
// }
//
// /**
// * 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 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[channel].setInitializing(false);
// channelConfig[channel].setDeinitializing(false);
// channelConfig[channel].setChannelState(ChannelStates.OFFLINE);
// try {
// antInterface.ANTUnassignChannel(channel);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// setSensorState(SensorState.DISCONNECTED);
// }
//
// 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],
// channel));
// } else {
// // Switch on message id
// switch (message[AntMesg.MESG_DATA_OFFSET + 1]) {
// case AntMesg.MESG_ASSIGN_CHANNEL_ID:
// try {
// 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(channel, channelConfig[channel].getMessagPeriod());
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// break;
// case AntMesg.MESG_CHANNEL_MESG_PERIOD_ID:
// try {
// antInterface.ANTSetChannelRFFreq(channel, ChannelConfiguration.FREQUENCY);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// break;
// case AntMesg.MESG_CHANNEL_RADIO_FREQ_ID:
// try {
// // Disable high priority search
// antInterface.ANTSetChannelSearchTimeout(channel, (byte) 0);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// break;
// case AntMesg.MESG_CHANNEL_SEARCH_TIMEOUT_ID:
// try {
// // Set search timeout to 30 seconds (low priority search)
// antInterface.ANTSetLowPriorityChannelSearchTimeout(channel, (byte) 12);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// break;
// case AntMesg.MESG_SET_LP_SEARCH_TIMEOUT_ID:
// if (channelConfig[channel].getDeviceNumber() == WILDCARD) {
// try {
// // Configure proximity search, if using wild card search
// antInterface.ANTSetProximitySearch(
// channel, ChannelConfiguration.PROXIMITY_SEARCH);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// } else {
// try {
// antInterface.ANTOpenChannel(channel);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// }
// break;
// case AntMesg.MESG_PROX_SEARCH_CONFIG_ID:
// try {
// antInterface.ANTOpenChannel(channel);
// } catch (AntInterfaceException e) {
// handleAntError();
// }
// break;
// case AntMesg.MESG_OPEN_CHANNEL_ID:
// channelConfig[channel].setInitializing(false);
// channelConfig[channel].setChannelState(ChannelStates.SEARCHING);
// break;
// default:
// break;
// }
// }
// } 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(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[channel].setDeinitializing(false);
// }
// }
// }
// };
//
// /**
// * Sets sensor data set.
// */
// 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;
// }
// lastSensorDataSetTime = now;
//
// SensorDataSet.Builder builder = Sensor.SensorDataSet.newBuilder();
// int heartRate = antSensorValue.getHeartRate();
// if (heartRate != -1) {
// builder.setHeartRate(Sensor.SensorData.newBuilder()
// .setValue(heartRate).setState(Sensor.SensorState.SENDING));
// }
// int cadence = antSensorValue.getCadence();
// if (cadence != -1) {
// builder.setCadence(Sensor.SensorData.newBuilder()
// .setValue(cadence).setState(Sensor.SensorState.SENDING));
// }
// sensorDataSet = builder.setCreationTime(now).build();
// setSensorState(SensorState.SENDING);
// }
//
// /**
// * Sets up ant channel.
// *
// * @param networkNumber the network number
// * @param channel the channel
// */
// private void setupAntChannel(byte networkNumber, byte channel) {
// try {
// channelConfig[channel].setInitializing(true);
// channelConfig[channel].setDeinitializing(false);
//
// // Assign as slave channel on selected network
// antInterface.ANTAssignChannel(channel, AntDefine.PARAMETER_RX_NOT_TX, networkNumber);
//
// // The rest of the channel configuration will occur after the response is
// // received in handleResponseEventMessage
// } catch (AntInterfaceException aie) {
// handleAntError();
// }
// }
//
// /**
// * 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));
// for (int i = 0; i < CHANNELS; i++) {
// openChannel((byte) i);
// }
// } else {
// try {
// context.unregisterReceiver(dataReceiver);
// for (int i = 0; i < CHANNELS; i++) {
// closeChannel((byte) i);
// }
// } catch (IllegalArgumentException e) {
// // Can safely ignore
// }
// }
// }
//
// /**
// * Returns true if in airplane mode.
// */
// private boolean isAirPlaneMode() {
// if (!Settings.System.getString(
// context.getContentResolver(), Settings.System.AIRPLANE_MODE_RADIOS)
// .contains(RADIO_ANT)) {
// return false;
// }
// if (Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0)
// == 0) {
// return false;
// }
//
// try {
// Field field = Settings.System.class.getField("AIRPLANE_MODE_TOGGLEABLE_RADIOS");
// return !Settings.System.getString(context.getContentResolver(), (String) field.get(null))
// .contains(RADIO_ANT);
// } catch (Exception e) {
// // This is expected if the list does not yet exist, so just return true
// return true;
// }
// }
}