Add a quit button to menu.
When restarting, reconnect to previous device.
When connecting, set the freq/rate to previous values.
Signed-off-by: Keith Packard <keithp@keithp.com>
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <TextView android:id="@+id/title_paired_devices"
+ <Button android:id="@+id/button_scan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/title_paired_devices"
+ android:text="@string/button_scan"
+ />
+ <TextView android:id="@+id/title_new_devices"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/title_other_devices"
android:visibility="gone"
android:background="#666"
android:textColor="#fff"
android:paddingLeft="5dp"
/>
- <ListView android:id="@+id/paired_devices"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:stackFromBottom="true"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/title_new_devices"
+ <TextView android:id="@+id/title_paired_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/title_other_devices"
+ android:text="@string/title_paired_devices"
android:visibility="gone"
android:background="#666"
android:textColor="#fff"
android:paddingLeft="5dp"
/>
- <ListView android:id="@+id/new_devices"
+ <ListView android:id="@+id/paired_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stackFromBottom="true"
- android:layout_weight="2"
+ android:layout_weight="1"
/>
- <Button android:id="@+id/button_scan"
+ <ListView android:id="@+id/new_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/button_scan"
+ android:stackFromBottom="true"
+ android:layout_weight="2"
/>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
<item android:id="@+id/connect_scan"
android:icon="@android:drawable/ic_menu_search"
android:title="@string/connect_device" />
+ <item android:id="@+id/quit"
+ android:icon="@android:drawable/ic_menu_close_clear_cancel"
+ android:title="@string/quit" />
<item android:id="@+id/select_freq"
android:icon="@android:drawable/ic_menu_preferences"
android:title="@string/select_freq" />
<!-- Options Menu -->
<string name="connect_device">Connect a device</string>
+ <string name="quit">Quit</string>
<string name="select_freq">Select radio frequency</string>
<string name="select_rate">Select data rate</string>
// Constructor
public AltosBluetooth(BluetoothDevice in_device, Handler in_handler) {
+// set_debug(D);
adapter = BluetoothAdapter.getDefaultAdapter();
device = in_device;
handler = in_handler;
}
}
+ public double frequency() {
+ return frequency;
+ }
+
+ public int telemetry_rate() {
+ return telemetry_rate;
+ }
+
+ public void save_frequency() {
+ AltosPreferences.set_frequency(serial, frequency);
+ }
+
+ public void save_telemetry_rate() {
+ AltosPreferences.set_telemetry_rate(serial, telemetry_rate);
+ }
+
private synchronized void wait_connected() throws InterruptedException, IOException {
if (input == null) {
wait();
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;
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_FREQUENCY = 6;
+ public static final int MSG_TELEMETRY_RATE = 7;
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
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;
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();
+ ad.set_config_data((AltosConfigData) msg.obj);
break;
case TelemetryService.STATE_CONNECTING:
ad.mTitle.setText(R.string.title_connecting);
case TelemetryService.STATE_NONE:
ad.mConfigData = null;
ad.mTitle.setText(R.string.title_not_connected);
+ String active_device = AltosDroidPreferences.active_device();
+ if (active_device != null)
+ ad.connectDevice(active_device);
break;
}
break;
ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.received_time + 500) / 1000));
}
break;
+ case MSG_FREQUENCY:
+ ad.set_frequency((Double) msg.obj);
+ break;
+ case MSG_TELEMETRY_RATE:
+ ad.set_telemetry_rate((Integer) msg.obj);
+ break;
}
}
};
update_ui(saved_state);
}
+ void set_title() {
+ if (mConfigData != null) {
+ String str = String.format("S/N %d %6.3f MHz", mConfigData.serial, frequency);
+
+ if (telemetry_rate != AltosLib.ao_telemetry_rate_38400)
+ str = str.concat(String.format(" %d bps", AltosLib.ao_telemetry_rate_values[telemetry_rate]));
+ mTitle.setText(str);
+ }
+ }
+
+ void set_frequency(double frequency) {
+ if (D) Log.d(TAG, String.format("AltosDroid: set_frequency %f\n", frequency));
+ this.frequency = frequency;
+ set_title();
+ }
+
+ void set_telemetry_rate(int telemetry_rate) {
+ if (D) Log.d(TAG, String.format("AltosDroid: set_telemetry_rate %d\n", telemetry_rate));
+ this.telemetry_rate = telemetry_rate;
+ set_title();
+ }
+
+ void set_config_data(AltosConfigData config_data) {
+ mConfigData = config_data;
+ set_title();
+ }
+
boolean same_string(String a, String b) {
if (a == null) {
if (b == null)
void update_ui(AltosState state) {
Log.d(TAG, "update_ui");
- if (state != null && saved_state != null) {
- if (saved_state.state != state.state) {
+
+ int prev_state = AltosLib.ao_flight_invalid;
+
+ 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 (prev_state != state.state) {
String currentTab = mTabHost.getCurrentTabTag();
Log.d(TAG, "switch state");
switch (state.state) {
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 (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");
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);
startService(new Intent(AltosDroid.this, TelemetryService.class));
doBindService();
+
}
@Override
private void connectDevice(Intent data) {
// Get the device MAC address
String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
+ AltosDroidPreferences.set_active_device(address);
connectDevice(address);
}
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
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
+import android.view.View;
public class GoNoGoLights {
private Boolean state;
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);
+ }
}
if (state != null) {
mMaxHeightView.setText(String.format("%6.0f m", state.max_height()));
- mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration()));
+ if (state.max_acceleration() != AltosLib.MISSING)
+ mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration()));
+ else
+ mMaxAccelView.setText("missing");
mMaxSpeedView.setText(String.format("%6.0f m/s", state.max_speed()));
}
}
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;
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());
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) {
AltosState state = null;
try {
- for (;;) {
+ while (telemQueue != null) {
try {
state = read();
handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();
state = null;
telemQueue = new LinkedBlockingQueue<AltosLine>();
link.add_monitor(telemQueue);
+ try {
+ link.set_radio_frequency(AltosPreferences.frequency(link.serial));
+ link.set_telemetry(AltosLib.ao_telemetry_standard);
+ link.set_telemetry_rate(AltosPreferences.telemetry_rate(link.serial));
+ } catch (InterruptedException ee) {
+ close();
+ } catch (TimeoutException te) {
+ close();
+ }
}
}
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));
+ if (s.state == STATE_CONNECTED) {
+ msg.replyTo.send(s.frequency_message());
+ msg.replyTo.send(s.telemetry_rate_message());
+ }
} catch (RemoteException e) {
s.mClients.remove(msg.replyTo);
}
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();
break;
case MSG_DISCONNECTED:
+ Log.d(TAG, "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());
if (s.state == STATE_CONNECTED) {
try {
s.mAltosBluetooth.set_radio_frequency((Double) msg.obj);
+ s.mAltosBluetooth.save_frequency();
+ s.sendMessageToClients(s.frequency_message());
} catch (InterruptedException e) {
} catch (TimeoutException e) {
}
case MSG_SETBAUD:
if (s.state == STATE_CONNECTED) {
s.mAltosBluetooth.set_telemetry_rate((Integer) msg.obj);
+ s.mAltosBluetooth.save_telemetry_rate();
+ s.sendMessageToClients(s.telemetry_rate_message());
}
break;
default:
}
}
+ private Message frequency_message() {
+ if (D) Log.d(TAG, String.format("frequency_message %f\n", mAltosBluetooth.frequency()));
+ return Message.obtain(null, AltosDroid.MSG_FREQUENCY, mAltosBluetooth.frequency());
+ }
+
+ private Message telemetry_rate_message() {
+ if (D) Log.d(TAG, String.format("telemetry_rate_message %d\n", mAltosBluetooth.telemetry_rate()));
+ return Message.obtain(null, AltosDroid.MSG_TELEMETRY_RATE, mAltosBluetooth.telemetry_rate());
+ }
+
private void stopAltosBluetooth() {
if (D) Log.d(TAG, "stopAltosBluetooth(): begin");
setState(STATE_READY);
sendMessageToClients(Message.obtain(null, AltosDroid.MSG_STATE_CHANGE, state, -1, acd));
}
- private void connected() {
+ private void connected() throws InterruptedException {
try {
if (mAltosBluetooth == null)
throw new InterruptedException("no bluetooth");
mConfigData = mAltosBluetooth.config_data();
- } catch (InterruptedException e) {
+ if (D) Log.d(TAG, "send frequency/rate messages\n");
+ sendMessageToClients(frequency_message());
+ sendMessageToClients(telemetry_rate_message());
} catch (TimeoutException e) {
// If this timed out, then we really want to retry it, but
// probably safer to just retry the connection from scratch.
mTelemetryReader = new TelemetryReader(mAltosBluetooth, mHandler);
mTelemetryReader.start();
-
+
mTelemetryLogger = new TelemetryLogger(this, mAltosBluetooth);
- }
+ sendMessageToClients(frequency_message());
+ sendMessageToClients(telemetry_rate_message());
+ }
private void onTimerTick() {
if (D) Log.d(TAG, "Timer wakeup");