summaryrefslogtreecommitdiff
path: root/altosdroid/src
diff options
context:
space:
mode:
Diffstat (limited to 'altosdroid/src')
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java19
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java282
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java90
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java101
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java50
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java53
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java14
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java13
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java8
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java8
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java2
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java30
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java53
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java166
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java46
15 files changed, 625 insertions, 310 deletions
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
index 484efaf8..51ef5e94 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
@@ -52,6 +52,7 @@ public class AltosBluetooth extends AltosLink {
// Constructor
public AltosBluetooth(BluetoothDevice in_device, Handler in_handler) {
+// set_debug(D);
adapter = BluetoothAdapter.getDefaultAdapter();
device = in_device;
handler = in_handler;
@@ -136,9 +137,27 @@ public class AltosBluetooth extends AltosLink {
}
}
+ public double frequency() {
+ return frequency;
+ }
+
+ public int telemetry_rate() {
+ return telemetry_rate;
+ }
+
+ public void save_frequency() {
+ AltosPreferences.set_frequency(0, frequency);
+ }
+
+ public void save_telemetry_rate() {
+ AltosPreferences.set_telemetry_rate(0, telemetry_rate);
+ }
+
private synchronized void wait_connected() throws InterruptedException, IOException {
if (input == null) {
+ if (D) Log.d(TAG, "wait_connected...");
wait();
+ if (D) Log.d(TAG, "wait_connected done");
if (input == null) throw new IOException();
}
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
index c9c38d98..f6cceac9 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
@@ -44,32 +44,34 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Window;
+import android.view.View;
import android.widget.TabHost;
import android.widget.TextView;
+import android.widget.RelativeLayout;
import android.widget.Toast;
import android.app.AlertDialog;
import android.location.Location;
import org.altusmetrum.altoslib_5.*;
-public class AltosDroid extends FragmentActivity {
+public class AltosDroid extends FragmentActivity implements AltosUnitsListener {
// Debugging
static final String TAG = "AltosDroid";
static final boolean D = true;
// Message types received by our Handler
- public static final int MSG_STATE_CHANGE = 1;
- public static final int MSG_TELEMETRY = 2;
- public static final int MSG_UPDATE_AGE = 3;
- public static final int MSG_LOCATION = 4;
- public static final int MSG_CRC_ERROR = 5;
+
+ public static final int MSG_STATE = 1;
+ public static final int MSG_UPDATE_AGE = 2;
// Intent request codes
- private static final int REQUEST_CONNECT_DEVICE = 1;
- private static final int REQUEST_ENABLE_BT = 2;
+ public static final int REQUEST_CONNECT_DEVICE = 1;
+ public static final int REQUEST_ENABLE_BT = 2;
public static FragmentManager fm;
+ private BluetoothAdapter mBluetoothAdapter = null;
+
// Layout Views
private TextView mTitle;
@@ -78,12 +80,16 @@ public class AltosDroid extends FragmentActivity {
private TextView mRSSIView;
private TextView mSerialView;
private TextView mFlightView;
+ private RelativeLayout mStateLayout;
private TextView mStateView;
private TextView mAgeView;
// field to display the version at the bottom of the screen
private TextView mVersion;
+ private double frequency;
+ private int telemetry_rate;
+
// Tabs
TabHost mTabHost;
AltosViewPager mViewPager;
@@ -92,23 +98,14 @@ public class AltosDroid extends FragmentActivity {
int tabHeight;
// Timer and Saved flight state for Age calculation
- private Timer timer = new Timer();
+ private Timer timer;
AltosState saved_state;
- Location saved_location;
// Service
private boolean mIsBound = false;
private Messenger mService = null;
final Messenger mMessenger = new Messenger(new IncomingHandler(this));
- // Preferences
- private AltosDroidPreferences prefs = null;
-
- // TeleBT Config data
- private AltosConfigData mConfigData = null;
- // Local Bluetooth adapter
- private BluetoothAdapter mBluetoothAdapter = null;
-
// Text to Speech
private AltosVoice mAltosVoice = null;
@@ -120,39 +117,21 @@ public class AltosDroid extends FragmentActivity {
@Override
public void handleMessage(Message msg) {
AltosDroid ad = mAltosDroid.get();
+
switch (msg.what) {
- case MSG_STATE_CHANGE:
- if(D) Log.d(TAG, "MSG_STATE_CHANGE: " + msg.arg1);
- switch (msg.arg1) {
- case TelemetryService.STATE_CONNECTED:
- ad.mConfigData = (AltosConfigData) msg.obj;
- String str = String.format(" %s S/N: %d", ad.mConfigData.product, ad.mConfigData.serial);
- ad.mTitle.setText(R.string.title_connected_to);
- ad.mTitle.append(str);
- Toast.makeText(ad.getApplicationContext(), "Connected to " + str, Toast.LENGTH_SHORT).show();
- break;
- case TelemetryService.STATE_CONNECTING:
- ad.mTitle.setText(R.string.title_connecting);
- break;
- case TelemetryService.STATE_READY:
- case TelemetryService.STATE_NONE:
- ad.mConfigData = null;
- ad.mTitle.setText(R.string.title_not_connected);
- break;
+ case MSG_STATE:
+ if(D) Log.d(TAG, "MSG_STATE");
+ TelemetryState telemetry_state = (TelemetryState) msg.obj;
+ if (telemetry_state == null) {
+ Log.d(TAG, "telemetry_state null!");
+ return;
}
- break;
- case MSG_TELEMETRY:
- ad.update_ui((AltosState) msg.obj);
- break;
- case MSG_LOCATION:
- ad.set_location((Location) msg.obj);
- break;
- case MSG_CRC_ERROR:
+
+ ad.update_state(telemetry_state);
break;
case MSG_UPDATE_AGE:
- if (ad.saved_state != null) {
- ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.received_time + 500) / 1000));
- }
+ if(D) Log.d(TAG, "MSG_UPDATE_AGE");
+ ad.update_age();
break;
}
}
@@ -208,10 +187,65 @@ public class AltosDroid extends FragmentActivity {
mTabs.remove(mTab);
}
- void set_location(Location location) {
- saved_location = location;
- Log.d(TAG, "set_location");
- update_ui(saved_state);
+ public void units_changed(boolean imperial_units) {
+ for (AltosDroidTab mTab : mTabs)
+ mTab.units_changed(imperial_units);
+ }
+
+ void update_title(TelemetryState telemetry_state) {
+ switch (telemetry_state.connect) {
+ case TelemetryState.CONNECT_CONNECTED:
+ if (telemetry_state.config != null) {
+ String str = String.format("S/N %d %6.3f MHz", telemetry_state.config.serial,
+ telemetry_state.frequency);
+ if (telemetry_state.telemetry_rate != AltosLib.ao_telemetry_rate_38400)
+ str = str.concat(String.format(" %d bps",
+ AltosLib.ao_telemetry_rate_values[telemetry_state.telemetry_rate]));
+ mTitle.setText(str);
+ } else {
+ mTitle.setText(R.string.title_connected_to);
+ }
+ break;
+ case TelemetryState.CONNECT_CONNECTING:
+ mTitle.setText(R.string.title_connecting);
+ break;
+ case TelemetryState.CONNECT_READY:
+ case TelemetryState.CONNECT_NONE:
+ mTitle.setText(R.string.title_not_connected);
+ break;
+ }
+ }
+
+ void start_timer() {
+ if (timer == null) {
+ timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 1000L, 1000L);
+ }
+ }
+
+ void stop_timer() {
+ if (timer != null) {
+ timer.cancel();
+ timer.purge();
+ timer = null;
+ }
+ }
+
+ boolean registered_units_listener;
+
+ void update_state(TelemetryState telemetry_state) {
+
+ if (!registered_units_listener) {
+ registered_units_listener = true;
+ AltosPreferences.register_units_listener(this);
+ }
+
+ update_title(telemetry_state);
+ update_ui(telemetry_state.state, telemetry_state.location);
+ if (telemetry_state.connect == TelemetryState.CONNECT_CONNECTED)
+ start_timer();
+ else
+ stop_timer();
}
boolean same_string(String a, String b) {
@@ -226,42 +260,73 @@ public class AltosDroid extends FragmentActivity {
}
}
- void update_ui(AltosState state) {
+ void update_age() {
+ if (saved_state != null)
+ mAgeView.setText(String.format("%d", (System.currentTimeMillis() - saved_state.received_time + 500) / 1000));
+ }
+
+ void update_ui(AltosState state, Location location) {
Log.d(TAG, "update_ui");
- if (state != null && saved_state != null) {
- if (saved_state.state != state.state) {
- String currentTab = mTabHost.getCurrentTabTag();
- Log.d(TAG, "switch state");
- switch (state.state) {
- case AltosLib.ao_flight_boost:
- if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("ascent");
- break;
- case AltosLib.ao_flight_drogue:
- if (currentTab.equals("ascent")) mTabHost.setCurrentTabByTag("descent");
- break;
- case AltosLib.ao_flight_landed:
- if (currentTab.equals("descent")) mTabHost.setCurrentTabByTag("landed");
- break;
- }
- }
- }
+
+ int prev_state = AltosLib.ao_flight_invalid;
AltosGreatCircle from_receiver = null;
- if (state != null && saved_location != null && state.gps != null && state.gps.locked) {
- double altitude = 0;
- if (saved_location.hasAltitude())
- altitude = saved_location.getAltitude();
- from_receiver = new AltosGreatCircle(saved_location.getLatitude(),
- saved_location.getLongitude(),
- altitude,
- state.gps.lat,
- state.gps.lon,
- state.gps.alt);
- }
+ if (saved_state != null)
+ prev_state = saved_state.state;
if (state != null) {
+ Log.d(TAG, String.format("prev state %d new state %d\n", prev_state, state.state));
+ if (state.state == AltosLib.ao_flight_stateless) {
+ boolean prev_locked = false;
+ boolean locked = false;
+
+ if(state.gps != null)
+ locked = state.gps.locked;
+ if (saved_state != null && saved_state.gps != null)
+ prev_locked = saved_state.gps.locked;
+ if (prev_locked != locked) {
+ String currentTab = mTabHost.getCurrentTabTag();
+ if (locked) {
+ if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("descent");
+ } else {
+ if (currentTab.equals("descent")) mTabHost.setCurrentTabByTag("pad");
+ }
+ }
+ } else {
+ if (prev_state != state.state) {
+ String currentTab = mTabHost.getCurrentTabTag();
+ Log.d(TAG, "switch state");
+ switch (state.state) {
+ case AltosLib.ao_flight_boost:
+ if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("ascent");
+ break;
+ case AltosLib.ao_flight_drogue:
+ if (currentTab.equals("ascent")) mTabHost.setCurrentTabByTag("descent");
+ break;
+ case AltosLib.ao_flight_landed:
+ if (currentTab.equals("descent")) mTabHost.setCurrentTabByTag("landed");
+ break;
+ case AltosLib.ao_flight_stateless:
+ if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("descent");
+ break;
+ }
+ }
+ }
+
+ if (location != null && state.gps != null && state.gps.locked) {
+ double altitude = 0;
+ if (location.hasAltitude())
+ altitude = location.getAltitude();
+ from_receiver = new AltosGreatCircle(location.getLatitude(),
+ location.getLongitude(),
+ altitude,
+ state.gps.lat,
+ state.gps.lon,
+ state.gps.alt);
+ }
+
if (saved_state == null || !same_string(saved_state.callsign, state.callsign)) {
Log.d(TAG, "update callsign");
mCallsignView.setText(state.callsign);
@@ -276,7 +341,12 @@ public class AltosDroid extends FragmentActivity {
}
if (saved_state == null || state.state != saved_state.state) {
Log.d(TAG, "update state");
- mStateView.setText(state.state_name());
+ if (state.state == AltosLib.ao_flight_stateless) {
+ mStateLayout.setVisibility(View.GONE);
+ } else {
+ mStateView.setText(state.state_name());
+ mStateLayout.setVisibility(View.VISIBLE);
+ }
}
if (saved_state == null || state.rssi != saved_state.rssi) {
Log.d(TAG, "update rssi");
@@ -285,10 +355,10 @@ public class AltosDroid extends FragmentActivity {
}
for (AltosDroidTab mTab : mTabs)
- mTab.update_ui(state, from_receiver, saved_location, mTab == mTabsAdapter.currentItem());
+ mTab.update_ui(state, from_receiver, location, mTab == mTabsAdapter.currentItem());
if (state != null)
- mAltosVoice.tell(state);
+ mAltosVoice.tell(state, from_receiver);
saved_state = state;
}
@@ -330,8 +400,6 @@ public class AltosDroid extends FragmentActivity {
super.onCreate(savedInstanceState);
if(D) Log.e(TAG, "+++ ON CREATE +++");
- fm = getSupportFragmentManager();
-
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -339,12 +407,9 @@ public class AltosDroid extends FragmentActivity {
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
- return;
}
- // Initialise preferences
- prefs = new AltosDroidPreferences(this);
- AltosPreferences.init(prefs);
+ fm = getSupportFragmentManager();
// Set up the window layout
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
@@ -387,7 +452,6 @@ public class AltosDroid extends FragmentActivity {
for (int i = 0; i < 5; i++)
mTabHost.getTabWidget().getChildAt(i).getLayoutParams().height = tabHeight;
-
// Set up the custom title
mTitle = (TextView) findViewById(R.id.title_left_text);
mTitle.setText(R.string.app_name);
@@ -403,11 +467,10 @@ public class AltosDroid extends FragmentActivity {
mRSSIView = (TextView) findViewById(R.id.rssi_value);
mSerialView = (TextView) findViewById(R.id.serial_value);
mFlightView = (TextView) findViewById(R.id.flight_value);
+ mStateLayout = (RelativeLayout) findViewById(R.id.state_container);
mStateView = (TextView) findViewById(R.id.state_value);
mAgeView = (TextView) findViewById(R.id.age_value);
- timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 1000L, 100L);
-
mAltosVoice = new AltosVoice(this);
}
@@ -416,15 +479,16 @@ public class AltosDroid extends FragmentActivity {
super.onStart();
if(D) Log.e(TAG, "++ ON START ++");
+ // Start Telemetry Service
+ startService(new Intent(AltosDroid.this, TelemetryService.class));
+
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
+ startActivityForResult(enableIntent, AltosDroid.REQUEST_ENABLE_BT);
}
- // Start Telemetry Service
- startService(new Intent(AltosDroid.this, TelemetryService.class));
-
doBindService();
+
}
@Override
@@ -453,6 +517,7 @@ public class AltosDroid extends FragmentActivity {
if(D) Log.e(TAG, "--- ON DESTROY ---");
if (mAltosVoice != null) mAltosVoice.stop();
+ stop_timer();
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
@@ -480,19 +545,21 @@ public class AltosDroid extends FragmentActivity {
}
}
- private void connectDevice(Intent data) {
- // Get the device MAC address
- String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
- // Get the BLuetoothDevice object
- BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
+ private void connectDevice(String address) {
// Attempt to connect to the device
try {
- if (D) Log.d(TAG, "Connecting to " + device.getName());
- mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, device));
+ if (D) Log.d(TAG, "Connecting to " + address);
+ mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, address));
} catch (RemoteException e) {
}
}
+ private void connectDevice(Intent data) {
+ // Get the device MAC address
+ String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
+ connectDevice(address);
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
@@ -550,6 +617,11 @@ public class AltosDroid extends FragmentActivity {
serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
return true;
+ case R.id.quit:
+ Log.d(TAG, "R.id.quit");
+ stopService(new Intent(AltosDroid.this, TelemetryService.class));
+ finish();
+ return true;
case R.id.select_freq:
// Set the TBT radio frequency
@@ -597,6 +669,10 @@ public class AltosDroid extends FragmentActivity {
AlertDialog alert_rate = builder_rate.create();
alert_rate.show();
return true;
+ case R.id.change_units:
+ boolean imperial = AltosPreferences.imperial_units();
+ AltosPreferences.set_imperial_units(!imperial);
+ return true;
}
return false;
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java
index 70d7def8..9cef1319 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java
@@ -1,5 +1,5 @@
/*
- * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,88 +14,38 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-
package org.altusmetrum.AltosDroid;
-import java.io.File;
-import java.util.Map;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Environment;
-
import org.altusmetrum.altoslib_5.*;
-public class AltosDroidPreferences implements AltosPreferencesBackend {
- public final static String NAME = "org.altusmetrum.AltosDroid";
- private Context context = null;
- private SharedPreferences prefs = null;
- private SharedPreferences.Editor editor = null;
-
- public AltosDroidPreferences(Context in_context) {
- this(in_context, NAME);
- }
-
- public AltosDroidPreferences(Context in_context, String in_prefs) {
- context = in_context;
- prefs = context.getSharedPreferences(in_prefs, 0);
- editor = prefs.edit();
- }
-
- public String[] keys() {
- Map<String, ?> all = prefs.getAll();
- return (String[])all.keySet().toArray();
- }
-
- public AltosPreferencesBackend node(String key) {
- return new AltosDroidPreferences(context, key);
- }
-
- public boolean nodeExists(String key) {
- return prefs.contains(key);
- }
-
- public boolean getBoolean(String key, boolean def) {
- return prefs.getBoolean(key, def);
- }
-
- public double getDouble(String key, double def) {
- Float f = Float.valueOf(prefs.getFloat(key, (float)def));
- return f.doubleValue();
- }
-
- public int getInt(String key, int def) {
- return prefs.getInt(key, def);
- }
-
- public String getString(String key, String def) {
- return prefs.getString(key, def);
- }
+public class AltosDroidPreferences extends AltosPreferences {
- public void putBoolean(String key, boolean value) {
- editor.putBoolean(key, value);
- }
+ /* Active device preference name */
+ final static String activeDevicePreference = "ACTIVE-DEVICE";
- public void putDouble(String key, double value) {
- editor.putFloat(key, (float)value);
- }
+ static String active_device_address;
- public void putInt(String key, int value) {
- editor.putInt(key, value);
- }
+ public static void init(Context context) {
+ if (backend != null)
+ return;
- public void putString(String key, String value) {
- editor.putString(key, value);
- }
+ AltosPreferences.init(new AltosDroidPreferencesBackend(context));
- public void remove(String key) {
- editor.remove(key);
+ active_device_address = backend.getString(activeDevicePreference, null);
}
- public void flush() {
- editor.apply();
+ public static void set_active_device(String address) {
+ synchronized(backend) {
+ active_device_address = address;
+ backend.putString(activeDevicePreference, active_device_address);
+ flush_preferences();
+ }
}
- public File homeDirectory() {
- return Environment.getExternalStorageDirectory();
+ public static String active_device() {
+ synchronized(backend) {
+ return active_device_address;
+ }
}
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java
new file mode 100644
index 00000000..be41ae7c
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.io.File;
+import java.util.Map;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Environment;
+
+import org.altusmetrum.altoslib_5.*;
+
+public class AltosDroidPreferencesBackend implements AltosPreferencesBackend {
+ public final static String NAME = "org.altusmetrum.AltosDroid";
+ private Context context = null;
+ private SharedPreferences prefs = null;
+ private SharedPreferences.Editor editor = null;
+
+ public AltosDroidPreferencesBackend(Context in_context) {
+ this(in_context, NAME);
+ }
+
+ public AltosDroidPreferencesBackend(Context in_context, String in_prefs) {
+ context = in_context;
+ prefs = context.getSharedPreferences(in_prefs, 0);
+ editor = prefs.edit();
+ }
+
+ public String[] keys() {
+ Map<String, ?> all = prefs.getAll();
+ return (String[])all.keySet().toArray();
+ }
+
+ public AltosPreferencesBackend node(String key) {
+ return new AltosDroidPreferencesBackend(context, key);
+ }
+
+ public boolean nodeExists(String key) {
+ return prefs.contains(key);
+ }
+
+ public boolean getBoolean(String key, boolean def) {
+ return prefs.getBoolean(key, def);
+ }
+
+ public double getDouble(String key, double def) {
+ Float f = Float.valueOf(prefs.getFloat(key, (float)def));
+ return f.doubleValue();
+ }
+
+ public int getInt(String key, int def) {
+ return prefs.getInt(key, def);
+ }
+
+ public String getString(String key, String def) {
+ return prefs.getString(key, def);
+ }
+
+ public void putBoolean(String key, boolean value) {
+ editor.putBoolean(key, value);
+ }
+
+ public void putDouble(String key, double value) {
+ editor.putFloat(key, (float)value);
+ }
+
+ public void putInt(String key, int value) {
+ editor.putInt(key, value);
+ }
+
+ public void putString(String key, String value) {
+ editor.putString(key, value);
+ }
+
+ public void remove(String key) {
+ editor.remove(key);
+ }
+
+ public void flush() {
+ editor.apply();
+ }
+
+ public File homeDirectory() {
+ return Environment.getExternalStorageDirectory();
+ }
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java
index b960eb1a..8e625da6 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java
@@ -27,8 +27,9 @@ import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.FragmentManager;
import android.location.Location;
import android.util.Log;
+import android.widget.TextView;
-public abstract class AltosDroidTab extends Fragment {
+public abstract class AltosDroidTab extends Fragment implements AltosUnitsListener {
AltosState last_state;
AltosGreatCircle last_from_receiver;
Location last_receiver;
@@ -37,39 +38,46 @@ public abstract class AltosDroidTab extends Fragment {
public abstract String tab_name();
+ public void units_changed(boolean imperial_units) {
+ if (!isHidden() && last_state != null)
+ show(last_state, last_from_receiver, last_receiver);
+ }
+
+ public void set_value(TextView text_view,
+ AltosUnits units,
+ int width,
+ double value) {
+ if (value == AltosLib.MISSING)
+ text_view.setText("");
+ else
+ text_view.setText(units.show(width, value));
+ }
+
public void set_visible(boolean visible) {
FragmentTransaction ft = AltosDroid.fm.beginTransaction();
- if (visible)
+ if (visible) {
+ AltosState state = last_state;
+ AltosGreatCircle from_receiver = last_from_receiver;
+ Location receiver = last_receiver;
+
+ show(state, from_receiver, receiver);
ft.show(this);
- else
+ } else
ft.hide(this);
ft.commit();
}
public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver, boolean is_current) {
+ last_state = state;
+ last_from_receiver = from_receiver;
+ last_receiver = receiver;
if (is_current) {
- Log.d(AltosDroid.TAG, String.format("%s: visible, performing update", tab_name()));
+ if (AltosDroid.D) Log.d(AltosDroid.TAG, String.format("%s: visible, performing update", tab_name()));
show(state, from_receiver, receiver);
} else {
- Log.d(AltosDroid.TAG, String.format("%s: not visible, skipping update", tab_name()));
- last_state = state;
- last_from_receiver = from_receiver;
- last_receiver = receiver;
+ if (AltosDroid.D) Log.d(AltosDroid.TAG, String.format("%s: not visible, skipping update", tab_name()));
return;
}
}
-
- public void onHiddenChanged(boolean hidden) {
- if (last_state != null && isVisible()) {
- AltosState state = last_state;
- AltosGreatCircle from_receiver = last_from_receiver;
- Location receiver = last_receiver;
-
- last_state = null;
- last_from_receiver = null;
- last_receiver = null;
- show(state, from_receiver, receiver);
- }
- }
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
index b05913b6..969992d3 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
@@ -58,7 +58,7 @@ public class AltosVoice {
}
}
- public void tell(AltosState state) {
+ public void tell(AltosState state, AltosGreatCircle from_receiver) {
if (!tts_enabled) return;
boolean spoke = false;
@@ -68,12 +68,14 @@ public class AltosVoice {
if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&
state.state > AltosLib.ao_flight_boost) {
if (state.max_speed() != AltosLib.MISSING)
- speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));
+ speak(String.format("Max speed: %s.",
+ AltosConvert.speed.say_units(state.max_speed())));
spoke = true;
} else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&
state.state >= AltosLib.ao_flight_drogue) {
if (state.max_height() != AltosLib.MISSING)
- speak(String.format("max height: %d meters.", (int) (state.max_height() + 0.5)));
+ speak(String.format("Max height: %s.",
+ AltosConvert.height.say_units(state.max_height())));
spoke = true;
}
}
@@ -88,13 +90,14 @@ public class AltosVoice {
}
old_state = state;
if (idle_thread != null)
- idle_thread.notice(state, spoke);
+ idle_thread.notice(state, from_receiver, spoke);
}
class IdleThread extends Thread {
boolean started;
private AltosState state;
+ private AltosGreatCircle from_receiver;
int reported_landing;
int report_interval;
long report_time;
@@ -112,29 +115,30 @@ public class AltosVoice {
return;
}
- /* If the rocket isn't on the pad, then report height */
- if (((AltosLib.ao_flight_drogue <= state.state &&
+ /* If the rocket isn't on the pad, then report location */
+ if ((AltosLib.ao_flight_drogue <= state.state &&
state.state < AltosLib.ao_flight_landed) ||
- state.state == AltosLib.ao_flight_stateless) &&
- state.range >= 0)
+ state.state == AltosLib.ao_flight_stateless)
{
- if (state.from_pad != null) {
- speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",
- (int) (state.height() + 0.5),
- state.from_pad.bearing_words(
+ AltosGreatCircle position;
+
+ if (from_receiver != null)
+ position = from_receiver;
+ else
+ position = state.from_pad;
+
+ if (position != null) {
+ speak(String.format("Height %s, bearing %s %d, elevation %d, range %s.\n",
+ AltosConvert.height.say_units(state.height()),
+ position.bearing_words(
AltosGreatCircle.BEARING_VOICE),
- (int) (state.from_pad.bearing + 0.5),
- (int) (state.elevation + 0.5),
- (int) (state.range + 0.5)));
- } else {
- speak(String.format("Height %d, elevation %d, range %d.\n",
- (int) (state.height() + 0.5),
- (int) (state.elevation + 0.5),
- (int) (state.range + 0.5)));
+ (int) (position.bearing + 0.5),
+ (int) (position.elevation + 0.5),
+ AltosConvert.distance.say_units(position.range)));
}
} else if (state.state > AltosLib.ao_flight_pad) {
if (state.height() != AltosLib.MISSING)
- speak(String.format("%d meters", (int) (state.height() + 0.5)));
+ speak(AltosConvert.height.say_units(state.height()));
} else {
reported_landing = 0;
}
@@ -153,9 +157,9 @@ public class AltosVoice {
else
speak("rocket may have crashed");
if (state.from_pad != null)
- speak(String.format("Bearing %d degrees, range %d meters.",
+ speak(String.format("Bearing %d degrees, range %s.",
(int) (state.from_pad.bearing + 0.5),
- (int) (state.from_pad.distance + 0.5)));
+ AltosConvert.distance.say_units(state.from_pad.distance)));
++reported_landing;
}
}
@@ -186,9 +190,10 @@ public class AltosVoice {
}
}
- public synchronized void notice(AltosState new_state, boolean spoken) {
+ public synchronized void notice(AltosState new_state, AltosGreatCircle new_from_receiver, boolean spoken) {
AltosState old_state = state;
state = new_state;
+ from_receiver = new_from_receiver;
if (!started && state.state > AltosLib.ao_flight_pad) {
started = true;
start();
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java b/altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java
index 8e8d9c03..267c90f8 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java
@@ -20,6 +20,7 @@ package org.altusmetrum.AltosDroid;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
+import android.view.View;
public class GoNoGoLights {
private Boolean state;
@@ -51,14 +52,27 @@ public class GoNoGoLights {
missing = m;
set = true;
if (missing) {
+ hide();
red.setImageDrawable(dGray);
green.setImageDrawable(dGray);
} else if (state) {
red.setImageDrawable(dGray);
green.setImageDrawable(dGreen);
+ show();
} else {
red.setImageDrawable(dRed);
green.setImageDrawable(dGray);
+ show();
}
}
+
+ public void show() {
+ red.setVisibility(View.VISIBLE);
+ green.setVisibility(View.VISIBLE);
+ }
+
+ public void hide() {
+ red.setVisibility(View.GONE);
+ green.setVisibility(View.GONE);
+ }
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
index c146c277..fa4e3c8b 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
@@ -91,12 +91,13 @@ public class TabAscent extends AltosDroidTab {
public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
- mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
- mMaxHeightView.setText(AltosDroid.number("%6.0f m", state.max_height()));
- mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
- mMaxSpeedView.setText(AltosDroid.number("%6.0f m/s", state.max_speed()));
- mAccelView.setText(AltosDroid.number("%6.0f m/s²", state.acceleration()));
- mMaxAccelView.setText(AltosDroid.number("%6.0f m/s²", state.max_acceleration()));
+ set_value(mHeightView, AltosConvert.height, 6, state.height());
+ set_value(mHeightView, AltosConvert.height, 6, state.height());
+ set_value(mMaxHeightView, AltosConvert.height, 6, state.max_height());
+ set_value(mSpeedView, AltosConvert.speed, 6, state.speed());
+ set_value(mMaxSpeedView, AltosConvert.speed, 6, state.max_speed());
+ set_value(mAccelView, AltosConvert.accel, 6, state.acceleration());
+ set_value(mMaxAccelView, AltosConvert.accel, 6, state.max_acceleration());
if (state.gps != null) {
mLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
index 6d781efd..28068666 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
@@ -93,14 +93,14 @@ public class TabDescent extends AltosDroidTab {
public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
- mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
- mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
+ set_value(mSpeedView, AltosConvert.speed, 6, state.speed());
+ set_value(mHeightView, AltosConvert.height, 6, state.height());
if (from_receiver != null) {
mElevationView.setText(AltosDroid.number("%3.0f°", from_receiver.elevation));
- mRangeView.setText(AltosDroid.number("%6.0f m", from_receiver.range));
+ set_value(mRangeView, AltosConvert.distance, 6, from_receiver.range);
mBearingView.setText(AltosDroid.number("%3.0f°", from_receiver.bearing));
mCompassView.setText(from_receiver.bearing_words(AltosGreatCircle.BEARING_LONG));
- mDistanceView.setText(AltosDroid.number("%6.0f m", from_receiver.distance));
+ set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
} else {
mElevationView.setText("<unknown>");
mRangeView.setText("<unknown>");
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java
index 16427d8b..b257b936 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java
@@ -78,7 +78,7 @@ public class TabLanded extends AltosDroidTab {
public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (from_receiver != null) {
mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
- mDistanceView.setText(String.format("%6.0f m", from_receiver.distance));
+ set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
}
if (state != null && state.gps != null) {
mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
@@ -91,9 +91,9 @@ public class TabLanded extends AltosDroidTab {
}
if (state != null) {
- mMaxHeightView.setText(String.format("%6.0f m", state.max_height()));
- mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration()));
- mMaxSpeedView.setText(String.format("%6.0f m/s", state.max_speed()));
+ set_value(mMaxHeightView, AltosConvert.height, 6, state.max_height());
+ set_value(mMaxAccelView, AltosConvert.accel, 6, state.max_acceleration());
+ set_value(mMaxSpeedView, AltosConvert.speed, 6, state.max_speed());
}
}
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
index 811e5482..ab338ac2 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
@@ -158,7 +158,7 @@ public class TabMap extends AltosDroidTab {
public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (from_receiver != null) {
mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
- mDistanceView.setText(String.format("%6.0f m", from_receiver.distance));
+ set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
}
if (state != null) {
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
index 03b78b75..32df71d7 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
@@ -33,10 +33,13 @@ public class TabPad extends AltosDroidTab {
AltosDroid mAltosDroid;
private TextView mBatteryVoltageView;
+ private TextView mBatteryVoltageLabel;
private GoNoGoLights mBatteryLights;
private TextView mApogeeVoltageView;
+ private TextView mApogeeVoltageLabel;
private GoNoGoLights mApogeeLights;
private TextView mMainVoltageView;
+ private TextView mMainVoltageLabel;
private GoNoGoLights mMainLights;
private TextView mDataLoggingView;
private GoNoGoLights mDataLoggingLights;
@@ -59,16 +62,19 @@ public class TabPad extends AltosDroidTab {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.tab_pad, container, false);
mBatteryVoltageView = (TextView) v.findViewById(R.id.battery_voltage_value);
+ mBatteryVoltageLabel = (TextView) v.findViewById(R.id.battery_voltage_label);
mBatteryLights = new GoNoGoLights((ImageView) v.findViewById(R.id.battery_redled),
(ImageView) v.findViewById(R.id.battery_greenled),
getResources());
mApogeeVoltageView = (TextView) v.findViewById(R.id.apogee_voltage_value);
+ mApogeeVoltageLabel = (TextView) v.findViewById(R.id.apogee_voltage_label);
mApogeeLights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
(ImageView) v.findViewById(R.id.apogee_greenled),
getResources());
mMainVoltageView = (TextView) v.findViewById(R.id.main_voltage_value);
+ mMainVoltageLabel = (TextView) v.findViewById(R.id.main_voltage_label);
mMainLights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
(ImageView) v.findViewById(R.id.main_greenled),
getResources());
@@ -107,11 +113,23 @@ public class TabPad extends AltosDroidTab {
if (state != null) {
mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery_voltage));
mBatteryLights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING);
-
- mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+ if (state.apogee_voltage == AltosLib.MISSING) {
+ mApogeeVoltageView.setVisibility(View.GONE);
+ mApogeeVoltageLabel.setVisibility(View.GONE);
+ } else {
+ mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+ mApogeeVoltageView.setVisibility(View.VISIBLE);
+ mApogeeVoltageLabel.setVisibility(View.VISIBLE);
+ }
mApogeeLights.set(state.apogee_voltage >= AltosLib.ao_igniter_good, state.apogee_voltage == AltosLib.MISSING);
-
- mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+ if (state.main_voltage == AltosLib.MISSING) {
+ mMainVoltageView.setVisibility(View.GONE);
+ mMainVoltageLabel.setVisibility(View.GONE);
+ } else {
+ mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+ mMainVoltageView.setVisibility(View.VISIBLE);
+ mMainVoltageLabel.setVisibility(View.VISIBLE);
+ }
mMainLights.set(state.main_voltage >= AltosLib.ao_igniter_good, state.main_voltage == AltosLib.MISSING);
if (state.flight != 0) {
@@ -141,12 +159,12 @@ public class TabPad extends AltosDroidTab {
}
if (receiver != null) {
- double altitude = 0;
+ double altitude = AltosLib.MISSING;
if (receiver.hasAltitude())
altitude = receiver.getAltitude();
mPadLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
mPadLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "W", "E"));
- mPadAltitudeView.setText(AltosDroid.number("%4.0f m", altitude));
+ set_value(mPadAltitudeView, AltosConvert.height, 6, altitude);
}
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java
index 3ba5afa9..971c3e80 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java
@@ -31,6 +31,7 @@ import org.altusmetrum.altoslib_5.*;
public class TelemetryReader extends Thread {
private static final String TAG = "TelemetryReader";
+ private static final boolean D = true;
int crc_errors;
@@ -39,6 +40,8 @@ public class TelemetryReader extends Thread {
AltosLink link;
AltosState state = null;
+ AltosFlightReader stacked;
+
LinkedBlockingQueue<AltosLine> telemQueue;
public AltosState read() throws ParseException, AltosCRCException, InterruptedException, IOException {
@@ -56,6 +59,10 @@ public class TelemetryReader extends Thread {
public void close() {
state = null;
+ if (stacked != null) {
+ stacked.close(false);
+ stacked = null;
+ }
link.remove_monitor(telemQueue);
link = null;
telemQueue.clear();
@@ -66,7 +73,27 @@ public class TelemetryReader extends Thread {
AltosState state = null;
try {
- for (;;) {
+ if (D) Log.d(TAG, "starting reader");
+ while (stacked != null) {
+ AltosState stacked_state = null;
+ try {
+ stacked_state = stacked.read();
+ } catch (ParseException pe) {
+ continue;
+ } catch (AltosCRCException ce) {
+ continue;
+ }
+ if (stacked_state != null)
+ state = stacked_state;
+ else
+ stacked = null;
+ }
+ if (state != null) {
+ if (D) Log.d(TAG, "Send initial state");
+ handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();
+ }
+ if (D) Log.d(TAG, "starting loop");
+ while (telemQueue != null) {
try {
state = read();
handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();
@@ -84,12 +111,34 @@ public class TelemetryReader extends Thread {
}
}
- public TelemetryReader (AltosLink in_link, Handler in_handler) {
+ public TelemetryReader (AltosLink in_link, Handler in_handler, AltosFlightReader in_stacked) {
+ if (D) Log.d(TAG, "connected TelemetryReader create started");
link = in_link;
handler = in_handler;
+ stacked = in_stacked;
state = null;
telemQueue = new LinkedBlockingQueue<AltosLine>();
link.add_monitor(telemQueue);
+ link.set_telemetry(AltosLib.ao_telemetry_standard);
+
+ if (D) Log.d(TAG, "connected TelemetryReader created");
+ }
+
+ private static AltosFlightReader existing_data(AltosLink link) {
+ if (link == null)
+ return null;
+
+ File file = AltosPreferences.logfile(link.serial);
+ if (file != null) {
+ AltosStateIterable iterable = AltosStateIterable.iterable(file);
+ if (iterable != null)
+ return new AltosReplayReader(iterable.iterator(), file, false);
+ }
+ return null;
+ }
+
+ public TelemetryReader(AltosLink link, Handler handler) {
+ this(link, handler, existing_data(link));
}
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java
index 4ec353e3..30d94409 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java
@@ -28,6 +28,7 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.content.Context;
import android.os.Bundle;
@@ -63,11 +64,6 @@ public class TelemetryService extends Service implements LocationListener {
static final int MSG_CRC_ERROR = 9;
static final int MSG_SETBAUD = 10;
- public static final int STATE_NONE = 0;
- public static final int STATE_READY = 1;
- public static final int STATE_CONNECTING = 2;
- public static final int STATE_CONNECTED = 3;
-
// Unique Identification Number for the Notification.
// We use it on Notification start, and to cancel it.
private int NOTIFICATION = R.string.telemetry_service_label;
@@ -81,21 +77,17 @@ public class TelemetryService extends Service implements LocationListener {
final Messenger mMessenger = new Messenger(mHandler); // Target we publish for clients to send messages to IncomingHandler.
// Name of the connected device
- private BluetoothDevice device = null;
+ String address;
private AltosBluetooth mAltosBluetooth = null;
- private AltosConfigData mConfigData = null;
private TelemetryReader mTelemetryReader = null;
private TelemetryLogger mTelemetryLogger = null;
+ // Local Bluetooth adapter
+ private BluetoothAdapter mBluetoothAdapter = null;
- // internally track state of bluetooth connection
- private int state = STATE_NONE;
+ private TelemetryState telemetry_state;
// Last data seen; send to UI when it starts
- private AltosState last_state;
- private Location last_location;
- private int last_crc_errors;
-
// Handler of incoming messages from clients.
static class IncomingHandler extends Handler {
private final WeakReference<TelemetryService> service;
@@ -104,17 +96,15 @@ public class TelemetryService extends Service implements LocationListener {
@Override
public void handleMessage(Message msg) {
TelemetryService s = service.get();
+ if (s == null)
+ return;
switch (msg.what) {
case MSG_REGISTER_CLIENT:
s.mClients.add(msg.replyTo);
try {
// Now we try to send the freshly connected UI any relavant information about what
- // we're talking to - Basically state and Config Data.
- msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_STATE_CHANGE, s.state, -1, s.mConfigData));
- // We also send any recent telemetry or location data that's cached
- if (s.last_state != null) msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_TELEMETRY, s.last_state ));
- if (s.last_location != null) msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_LOCATION , s.last_location ));
- if (s.last_crc_errors != 0 ) msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_CRC_ERROR, s.last_crc_errors));
+ // we're talking to
+ msg.replyTo.send(s.message());
} catch (RemoteException e) {
s.mClients.remove(msg.replyTo);
}
@@ -126,47 +116,59 @@ public class TelemetryService extends Service implements LocationListener {
break;
case MSG_CONNECT:
if (D) Log.d(TAG, "Connect command received");
- s.device = (BluetoothDevice) msg.obj;
- s.startAltosBluetooth();
+ String address = (String) msg.obj;
+ AltosDroidPreferences.set_active_device(address);
+ s.startAltosBluetooth(address);
break;
case MSG_CONNECTED:
if (D) Log.d(TAG, "Connected to device");
- s.connected();
+ try {
+ s.connected();
+ } catch (InterruptedException ie) {
+ }
break;
case MSG_CONNECT_FAILED:
if (D) Log.d(TAG, "Connection failed... retrying");
- s.startAltosBluetooth();
+ if (s.address != null)
+ s.startAltosBluetooth(s.address);
break;
case MSG_DISCONNECTED:
- // Only do the following if we haven't been shutdown elsewhere..
- if (s.device != null) {
- if (D) Log.d(TAG, "Disconnected from " + s.device.getName());
- s.stopAltosBluetooth();
- }
+ Log.d(TAG, "MSG_DISCONNECTED");
+ s.stopAltosBluetooth();
break;
case MSG_TELEMETRY:
// forward telemetry messages
- s.last_state = (AltosState) msg.obj;
- s.sendMessageToClients(Message.obtain(null, AltosDroid.MSG_TELEMETRY, msg.obj));
+ s.telemetry_state.state = (AltosState) msg.obj;
+ if (D) Log.d(TAG, "MSG_TELEMETRY");
+ s.sendMessageToClients();
break;
case MSG_CRC_ERROR:
// forward crc error messages
- s.last_crc_errors = (Integer) msg.obj;
- s.sendMessageToClients(Message.obtain(null, AltosDroid.MSG_CRC_ERROR, msg.obj));
+ s.telemetry_state.crc_errors = (Integer) msg.obj;
+ if (D) Log.d(TAG, "MSG_CRC_ERROR");
+ s.sendMessageToClients();
break;
case MSG_SETFREQUENCY:
- if (s.state == STATE_CONNECTED) {
+ if (D) Log.d(TAG, "MSG_SETFREQUENCY");
+ s.telemetry_state.frequency = (Double) msg.obj;
+ if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
try {
- s.mAltosBluetooth.set_radio_frequency((Double) msg.obj);
+ s.mAltosBluetooth.set_radio_frequency(s.telemetry_state.frequency);
+ s.mAltosBluetooth.save_frequency();
} catch (InterruptedException e) {
} catch (TimeoutException e) {
}
}
+ s.sendMessageToClients();
break;
case MSG_SETBAUD:
- if (s.state == STATE_CONNECTED) {
- s.mAltosBluetooth.set_telemetry_rate((Integer) msg.obj);
+ if (D) Log.d(TAG, "MSG_SETBAUD");
+ s.telemetry_state.telemetry_rate = (Integer) msg.obj;
+ if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) {
+ s.mAltosBluetooth.set_telemetry_rate(s.telemetry_state.telemetry_rate);
+ s.mAltosBluetooth.save_telemetry_rate();
}
+ s.sendMessageToClients();
break;
default:
super.handleMessage(msg);
@@ -174,9 +176,18 @@ public class TelemetryService extends Service implements LocationListener {
}
}
- private void sendMessageToClients(Message m) {
+ private Message message() {
+ if (telemetry_state == null)
+ Log.d(TAG, "telemetry_state null!");
+ return Message.obtain(null, AltosDroid.MSG_STATE, telemetry_state);
+ }
+
+ private void sendMessageToClients() {
+ Message m = message();
+ if (D) Log.d(TAG, String.format("Send message to %d clients", mClients.size()));
for (int i=mClients.size()-1; i>=0; i--) {
try {
+ if (D) Log.d(TAG, String.format("Send message to client %d", i));
mClients.get(i).send(m);
} catch (RemoteException e) {
mClients.remove(i);
@@ -186,7 +197,7 @@ public class TelemetryService extends Service implements LocationListener {
private void stopAltosBluetooth() {
if (D) Log.d(TAG, "stopAltosBluetooth(): begin");
- setState(STATE_READY);
+ telemetry_state.connect = TelemetryState.CONNECT_READY;
if (mTelemetryReader != null) {
if (D) Log.d(TAG, "stopAltosBluetooth(): stopping TelemetryReader");
mTelemetryReader.interrupt();
@@ -206,18 +217,21 @@ public class TelemetryService extends Service implements LocationListener {
mAltosBluetooth.close();
mAltosBluetooth = null;
}
- device = null;
- mConfigData = null;
+ telemetry_state.config = null;
+ if (D) Log.d(TAG, "stopAltosBluetooth(): send message to clients");
+ sendMessageToClients();
}
- private void startAltosBluetooth() {
- if (device == null) {
- return;
- }
+ private void startAltosBluetooth(String address) {
+ // Get the BLuetoothDevice object
+ BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
+
+ this.address = address;
if (mAltosBluetooth == null) {
if (D) Log.d(TAG, String.format("startAltosBluetooth(): Connecting to %s (%s)", device.getName(), device.getAddress()));
mAltosBluetooth = new AltosBluetooth(device, mHandler);
- setState(STATE_CONNECTING);
+ telemetry_state.connect = TelemetryState.CONNECT_CONNECTING;
+ sendMessageToClients();
} else {
// This is a bit of a hack - if it appears we're still connected, we treat this as a restart.
// So, to give a suitable delay to teardown/bringup, we just schedule a resend of a message
@@ -225,28 +239,19 @@ public class TelemetryService extends Service implements LocationListener {
// ... then we tear down the existing connection.
// We do it this way around so that we don't lose a reference to the device when this method
// is called on reception of MSG_CONNECT_FAILED in the handler above.
- mHandler.sendMessageDelayed(Message.obtain(null, MSG_CONNECT, device), 3000);
+ mHandler.sendMessageDelayed(Message.obtain(null, MSG_CONNECT, address), 3000);
stopAltosBluetooth();
}
}
- private synchronized void setState(int s) {
- if (D) Log.d(TAG, "setState(): " + state + " -> " + s);
- state = s;
-
- // This shouldn't be required - mConfigData should be null for any non-connected
- // state, but to be safe and to reduce message size
- AltosConfigData acd = (state == STATE_CONNECTED) ? mConfigData : null;
-
- sendMessageToClients(Message.obtain(null, AltosDroid.MSG_STATE_CHANGE, state, -1, acd));
- }
-
- private void connected() {
+ private void connected() throws InterruptedException {
+ if (D) Log.d(TAG, "connected top");
try {
if (mAltosBluetooth == null)
throw new InterruptedException("no bluetooth");
- mConfigData = mAltosBluetooth.config_data();
- } catch (InterruptedException e) {
+ telemetry_state.config = mAltosBluetooth.config_data();
+ mAltosBluetooth.set_radio_frequency(telemetry_state.frequency);
+ mAltosBluetooth.set_telemetry_rate(telemetry_state.telemetry_rate);
} catch (TimeoutException e) {
// If this timed out, then we really want to retry it, but
// probably safer to just retry the connection from scratch.
@@ -254,19 +259,25 @@ public class TelemetryService extends Service implements LocationListener {
return;
}
- setState(STATE_CONNECTED);
+ if (D) Log.d(TAG, "connected bluetooth configured");
+ telemetry_state.connect = TelemetryState.CONNECT_CONNECTED;
mTelemetryReader = new TelemetryReader(mAltosBluetooth, mHandler);
mTelemetryReader.start();
-
+
+ if (D) Log.d(TAG, "connected TelemetryReader started");
+
mTelemetryLogger = new TelemetryLogger(this, mAltosBluetooth);
- }
+ if (D) Log.d(TAG, "Notify UI of connection");
+
+ sendMessageToClients();
+ }
private void onTimerTick() {
if (D) Log.d(TAG, "Timer wakeup");
try {
- if (mClients.size() <= 0 && state != STATE_CONNECTED) {
+ if (mClients.size() <= 0 && telemetry_state.connect != TelemetryState.CONNECT_CONNECTED) {
stopSelf();
}
} catch (Throwable t) {
@@ -277,19 +288,35 @@ public class TelemetryService extends Service implements LocationListener {
@Override
public void onCreate() {
+ // Get local Bluetooth adapter
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ // If the adapter is null, then Bluetooth is not supported
+ if (mBluetoothAdapter == null) {
+ Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
+ }
+
+ // Initialise preferences
+ AltosDroidPreferences.init(this);
+
+ telemetry_state = new TelemetryState();
+
// Create a reference to the NotificationManager so that we can update our notifcation text later
//mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- setState(STATE_READY);
+ telemetry_state.connect = TelemetryState.CONNECT_READY;
// Start our timer - first event in 10 seconds, then every 10 seconds after that.
timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 10000L, 10000L);
// Listen for GPS and Network position updates
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
-
+
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
-// locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+
+ String address = AltosDroidPreferences.active_device();
+ if (address != null)
+ startAltosBluetooth(address);
}
@Override
@@ -345,8 +372,9 @@ public class TelemetryService extends Service implements LocationListener {
public void onLocationChanged(Location location) {
- last_location = location;
- sendMessageToClients(Message.obtain(null, AltosDroid.MSG_LOCATION, location));
+ telemetry_state.location = location;
+ if (D) Log.d(TAG, "location changed");
+ sendMessageToClients();
}
public void onStatusChanged(String provider, int status, Bundle extras) {
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java
new file mode 100644
index 00000000..d3341739
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_5.*;
+import android.location.Location;
+
+public class TelemetryState {
+ public static final int CONNECT_NONE = 0;
+ public static final int CONNECT_READY = 1;
+ public static final int CONNECT_CONNECTING = 2;
+ public static final int CONNECT_CONNECTED = 3;
+
+ int connect;
+ AltosConfigData config;
+ AltosState state;
+ Location location;
+ int crc_errors;
+ double frequency;
+ int telemetry_rate;
+
+ public TelemetryState() {
+ connect = CONNECT_NONE;
+ config = null;
+ state = null;
+ location = null;
+ crc_errors = 0;
+ frequency = AltosPreferences.frequency(0);
+ telemetry_rate = AltosPreferences.telemetry_rate(0);
+ }
+}