summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2012-08-30 16:24:38 -0500
committerKeith Packard <keithp@keithp.com>2012-08-30 16:24:38 -0500
commitb635cb26ba54c8f5c6a958e0ab0bc4d34d33b635 (patch)
treec48d7e70f091a4149572525c9fae4c8de1bff0c8
parent354c1fed7f06c2c45c661e7265c2ac4bc47e2750 (diff)
parenta8ecf3aa4e88d4c76643fb541fb1d5535a454aba (diff)
Merge remote-tracking branch 'mjb/master'
-rw-r--r--altosdroid/res/layout/altosdroid.xml193
-rw-r--r--altosdroid/res/values/strings.xml14
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java90
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java203
4 files changed, 352 insertions, 148 deletions
diff --git a/altosdroid/res/layout/altosdroid.xml b/altosdroid/res/layout/altosdroid.xml
index 33d89d52..f185ea9f 100644
--- a/altosdroid/res/layout/altosdroid.xml
+++ b/altosdroid/res/layout/altosdroid.xml
@@ -51,11 +51,77 @@
</RelativeLayout>
<RelativeLayout
- android:id="@+id/state_container"
+ android:id="@+id/rssi_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_toRightOf="@+id/strut" >
+ android:layout_toRightOf="@id/strut"
+ android:layout_alignParentRight="true" >
+
+ <TextView
+ android:id="@+id/rssi_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rssi_label" />
+
+ <TextView
+ android:id="@+id/rssi_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/rssi_label"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/serial_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/callsign_container"
+ android:layout_toLeftOf="@+id/strut" >
+
+ <TextView
+ android:id="@+id/serial_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/serial_label" />
+
+ <TextView
+ android:id="@+id/serial_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/serial_label"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/flight_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/callsign_container"
+ android:layout_toRightOf="@+id/strut"
+ android:layout_alignParentRight="true" >
+
+ <TextView
+ android:id="@+id/flight_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/flight_label" />
+
+ <TextView
+ android:id="@+id/flight_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/flight_label"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/state_container"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/serial_container" >
<TextView
android:id="@+id/state_label"
@@ -67,10 +133,10 @@
android:id="@+id/state_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
android:layout_below="@+id/state_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
+ android:layout_centerInParent="true"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="50dip" />
</RelativeLayout>
@@ -79,7 +145,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
- android:layout_below="@+id/callsign_container"
+ android:layout_below="@+id/state_container"
android:layout_toLeftOf="@+id/strut" >
<TextView
@@ -92,23 +158,11 @@
android:id="@+id/speed_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
android:layout_below="@id/speed_label"
- android:layout_toLeftOf="@+id/speed_units"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
- <TextView
- android:id="@+id/speed_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@id/speed_value"
- android:layout_alignParentRight="true"
- android:layout_below="@id/speed_label"
- android:gravity="right"
- android:paddingLeft="10dip"
- android:text="@string/speed_units"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
</RelativeLayout>
<RelativeLayout
@@ -129,22 +183,11 @@
android:id="@+id/accel_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
android:layout_below="@+id/accel_label"
- android:layout_toLeftOf="@+id/accel_units"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
- <TextView
- android:id="@+id/accel_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/accel_value"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/accel_label"
- android:gravity="right"
- android:paddingLeft="10dip"
- android:text="@string/accel_units"
- android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<RelativeLayout
@@ -165,63 +208,39 @@
android:id="@+id/range_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
android:layout_below="@+id/range_label"
- android:layout_toLeftOf="@+id/range_units"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
- <TextView
- android:id="@+id/range_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/range_value"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/range_label"
- android:gravity="right"
- android:paddingLeft="10dip"
- android:text="@string/range_units"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
</RelativeLayout>
<RelativeLayout
- android:id="@+id/altitude_container"
+ android:id="@+id/height_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
- android:layout_below="@id/accel_container"
+ android:layout_below="@id/speed_container"
android:layout_toRightOf="@id/strut" >
<TextView
- android:id="@+id/altitude_label"
+ android:id="@+id/height_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/altitude_label" />
+ android:text="@string/height_label" />
<TextView
- android:id="@+id/altitude_value"
+ android:id="@+id/height_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@+id/altitude_label"
- android:layout_toLeftOf="@+id/altitude_units"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/height_label"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <TextView
- android:id="@+id/altitude_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/altitude_value"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/altitude_label"
- android:gravity="right"
- android:paddingLeft="10dip"
- android:text="@string/altitude_units"
- android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<RelativeLayout
- android:id="@+id/azimuth_container"
+ android:id="@+id/elevation_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
@@ -229,30 +248,19 @@
android:layout_toLeftOf="@id/strut" >
<TextView
- android:id="@+id/azimuth_label"
+ android:id="@+id/elevation_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/azimuth_label" />
+ android:text="@string/elevation_label" />
<TextView
- android:id="@+id/azimuth_value"
+ android:id="@+id/elevation_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@+id/azimuth_label"
- android:layout_toLeftOf="@+id/azimuth_units"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/elevation_label"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <TextView
- android:id="@+id/azimuth_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/azimuth_label"
- android:gravity="right"
- android:paddingLeft="10dip"
- android:text="@string/azimuth_units"
- android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<RelativeLayout
@@ -260,7 +268,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
- android:layout_below="@+id/altitude_container"
+ android:layout_below="@+id/range_container"
android:layout_toRightOf="@+id/strut" >
<TextView
@@ -273,28 +281,18 @@
android:id="@+id/bearing_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
android:layout_below="@+id/bearing_label"
- android:layout_toLeftOf="@+id/bearing_units"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
- <TextView
- android:id="@+id/bearing_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/bearing_label"
- android:gravity="right"
- android:paddingLeft="10dip"
- android:text="@string/bearing_units"
- android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/latitude_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@+id/azimuth_container" >
+ android:layout_below="@+id/elevation_container" >
<TextView
android:id="@+id/latitude_label"
@@ -335,13 +333,14 @@
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
-
- <TextView
+
+
+ <TextView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_alignParentBottom="true"
- android:layout_below="@id/longitude_container"
+ android:layout_below="@+id/longitude_container"
android:gravity="bottom"
android:scrollbars="vertical"
android:textSize="7dp"
diff --git a/altosdroid/res/values/strings.xml b/altosdroid/res/values/strings.xml
index 59f4f827..f8038406 100644
--- a/altosdroid/res/values/strings.xml
+++ b/altosdroid/res/values/strings.xml
@@ -43,21 +43,17 @@
<!-- UI fields -->
<string name="callsign_label">Callsign</string>
+ <string name="serial_label">Serial no.</string>
+ <string name="flight_label">Flight no.</string>
+ <string name="rssi_label">RSSI</string>
<string name="state_label">State</string>
<string name="speed_label">Speed</string>
- <string name="speed_units">m/s</string>
<string name="accel_label">Acceleration</string>
- <string name="accel_units">m/s²</string>
<string name="range_label">Range</string>
- <string name="range_units">m</string>
- <string name="altitude_label">Altitude</string>
- <string name="altitude_units">m</string>
- <string name="azimuth_label">Azimuth</string>
- <string name="azimuth_units">°</string>
+ <string name="height_label">Height</string>
+ <string name="elevation_label">Elevation</string>
<string name="bearing_label">Bearing</string>
- <string name="bearing_units">°</string>
<string name="latitude_label">Latitude</string>
<string name="longitude_label">Longitude</string>
-
</resources>
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
index ba424e79..20904d2b 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
@@ -32,8 +32,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.speech.tts.TextToSpeech;
-import android.speech.tts.TextToSpeech.OnInitListener;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.Menu;
@@ -63,18 +61,25 @@ public class AltosDroid extends Activity {
// Layout Views
private TextView mTitle;
- private TextView mSerialView;
+
+ // Flight state values
private TextView mCallsignView;
+ private TextView mRSSIView;
+ private TextView mSerialView;
+ private TextView mFlightView;
private TextView mStateView;
private TextView mSpeedView;
private TextView mAccelView;
private TextView mRangeView;
- private TextView mAltitudeView;
- private TextView mAzimuthView;
+ private TextView mHeightView;
+ private TextView mElevationView;
private TextView mBearingView;
private TextView mLatitudeView;
private TextView mLongitudeView;
+ // Generic field for extras at the bottom
+ private TextView mTextView;
+
// Service
private boolean mIsBound = false;
private Messenger mService = null;
@@ -86,8 +91,7 @@ public class AltosDroid extends Activity {
private BluetoothAdapter mBluetoothAdapter = null;
// Text to Speech
- private TextToSpeech tts = null;
- private boolean tts_enabled = false;
+ private AltosVoice mAltosVoice = null;
// The Handler that gets information back from the Telemetry Service
static class IncomingHandler extends Handler {
@@ -107,8 +111,9 @@ public class AltosDroid extends Activity {
ad.mTitle.setText(R.string.title_connected_to);
ad.mTitle.append(str);
Toast.makeText(ad.getApplicationContext(), "Connected to " + str, Toast.LENGTH_SHORT).show();
+ ad.mAltosVoice.speak("Connected");
//TEST!
- ad.mSerialView.setText(Dumper.dump(ad.mConfigData));
+ ad.mTextView.setText(Dumper.dump(ad.mConfigData));
break;
case TelemetryService.STATE_CONNECTING:
ad.mTitle.setText(R.string.title_connecting);
@@ -117,14 +122,14 @@ public class AltosDroid extends Activity {
case TelemetryService.STATE_NONE:
ad.mConfigData = null;
ad.mTitle.setText(R.string.title_not_connected);
- ad.mSerialView.setText("");
+ ad.mTextView.setText("");
break;
}
break;
case MSG_TELEMETRY:
ad.update_ui((AltosState) msg.obj);
// TEST!
- ad.mSerialView.setText(Dumper.dump(msg.obj));
+ ad.mTextView.setText(Dumper.dump(msg.obj));
break;
}
}
@@ -175,19 +180,24 @@ public class AltosDroid extends Activity {
void update_ui(AltosState state) {
mCallsignView.setText(state.data.callsign);
+ mRSSIView.setText(String.format("%d", state.data.rssi));
+ mSerialView.setText(String.format("%d", state.data.serial));
+ mFlightView.setText(String.format("%d", state.data.flight));
mStateView.setText(state.data.state());
double speed = state.speed;
if (!state.ascent)
speed = state.baro_speed;
- mSpeedView.setText(String.format("%6.0f", speed));
- mAccelView.setText(String.format("%6.0f", state.acceleration));
- mRangeView.setText(String.format("%6.0f", state.range));
- mAltitudeView.setText(String.format("%6.0f", state.height));
- mAzimuthView.setText(String.format("%3.0f", state.elevation));
+ mSpeedView.setText(String.format("%6.0f m/s", speed));
+ mAccelView.setText(String.format("%6.0f m/s²", state.acceleration));
+ mRangeView.setText(String.format("%6.0f m", state.range));
+ mHeightView.setText(String.format("%6.0f m", state.height));
+ mElevationView.setText(String.format("%3.0f°", state.elevation));
if (state.from_pad != null)
- mBearingView.setText(String.format("%3.0f", state.from_pad.bearing));
+ mBearingView.setText(String.format("%3.0f°", state.from_pad.bearing));
mLatitudeView.setText(pos(state.gps.lat, "N", "S"));
mLongitudeView.setText(pos(state.gps.lon, "W", "E"));
+
+ mAltosVoice.tell(state);
}
String pos(double p, String pos, String neg) {
@@ -198,7 +208,7 @@ public class AltosDroid extends Activity {
}
int deg = (int) Math.floor(p);
double min = (p - Math.floor(p)) * 60.0;
- return String.format("%s %d° %9.6f", h, deg, min);
+ return String.format("%d° %9.6f\" %s", deg, min, h);
}
@Override
@@ -206,6 +216,16 @@ public class AltosDroid extends Activity {
super.onCreate(savedInstanceState);
if(D) Log.e(TAG, "+++ ON CREATE +++");
+ // 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();
+ finish();
+ return;
+ }
+
// Set up the window layout
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
//setContentView(R.layout.main);
@@ -218,40 +238,26 @@ public class AltosDroid extends Activity {
mTitle = (TextView) findViewById(R.id.title_right_text);
// Set up the temporary Text View
- mSerialView = (TextView) findViewById(R.id.text);
- mSerialView.setMovementMethod(new ScrollingMovementMethod());
- mSerialView.setClickable(false);
- mSerialView.setLongClickable(false);
+ mTextView = (TextView) findViewById(R.id.text);
+ mTextView.setMovementMethod(new ScrollingMovementMethod());
+ mTextView.setClickable(false);
+ mTextView.setLongClickable(false);
mCallsignView = (TextView) findViewById(R.id.callsign_value);
+ mRSSIView = (TextView) findViewById(R.id.rssi_value);
+ mSerialView = (TextView) findViewById(R.id.serial_value);
+ mFlightView = (TextView) findViewById(R.id.flight_value);
mStateView = (TextView) findViewById(R.id.state_value);
mSpeedView = (TextView) findViewById(R.id.speed_value);
mAccelView = (TextView) findViewById(R.id.accel_value);
mRangeView = (TextView) findViewById(R.id.range_value);
- mAltitudeView = (TextView) findViewById(R.id.altitude_value);
- mAzimuthView = (TextView) findViewById(R.id.azimuth_value);
+ mHeightView = (TextView) findViewById(R.id.height_value);
+ mElevationView = (TextView) findViewById(R.id.elevation_value);
mBearingView = (TextView) findViewById(R.id.bearing_value);
mLatitudeView = (TextView) findViewById(R.id.latitude_value);
mLongitudeView = (TextView) findViewById(R.id.longitude_value);
- // 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();
- finish();
- return;
- }
-
- // Enable Text to Speech
- tts = new TextToSpeech(this, new OnInitListener() {
- public void onInit(int status) {
- if (status == TextToSpeech.SUCCESS) tts_enabled = true;
- if (tts_enabled) tts.speak("AltosDroid ready", TextToSpeech.QUEUE_ADD, null );
- }
- });
-
+ mAltosVoice = new AltosVoice(this);
}
@Override
@@ -295,7 +301,7 @@ public class AltosDroid extends Activity {
super.onDestroy();
if(D) Log.e(TAG, "--- ON DESTROY ---");
- if (tts != null) tts.shutdown();
+ mAltosVoice.stop();
}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
new file mode 100644
index 00000000..3f7c5979
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ * 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 android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+
+import org.altusmetrum.AltosLib.*;
+
+public class AltosVoice {
+
+ private TextToSpeech tts = null;
+ private boolean tts_enabled = false;
+
+ private IdleThread idle_thread = null;
+
+ private AltosState old_state = null;
+
+ public AltosVoice(AltosDroid a) {
+
+ tts = new TextToSpeech(a, new OnInitListener() {
+ public void onInit(int status) {
+ if (status == TextToSpeech.SUCCESS) tts_enabled = true;
+ if (tts_enabled) {
+ speak("AltosDroid ready");
+ idle_thread = new IdleThread();
+ }
+ }
+ });
+
+ }
+
+ public void speak(String s) {
+ if (!tts_enabled) return;
+ tts.speak(s, TextToSpeech.QUEUE_ADD, null);
+ }
+
+ public void stop() {
+ if (tts != null) tts.shutdown();
+ if (idle_thread != null) {
+ idle_thread.interrupt();
+ idle_thread = null;
+ }
+ }
+
+ public void tell(AltosState state) {
+ if (!tts_enabled) return;
+
+ boolean spoke = false;
+ if (old_state == null || old_state.state != state.state) {
+ speak(state.data.state());
+ if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&
+ state.state > AltosLib.ao_flight_boost) {
+ speak(String.format("max speed: %d meters per second.", (int) (state.max_speed + 0.5)));
+ spoke = true;
+ } else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&
+ state.state >= AltosLib.ao_flight_drogue) {
+ speak(String.format("max height: %d meters.", (int) (state.max_height + 0.5)));
+ spoke = true;
+ }
+ }
+ if (old_state == null || old_state.gps_ready != state.gps_ready) {
+ if (state.gps_ready) {
+ speak("GPS ready");
+ spoke = true;
+ } else if (old_state != null) {
+ speak("GPS lost");
+ spoke = true;
+ }
+ }
+ old_state = state;
+ idle_thread.notice(state, spoke);
+ }
+
+
+ class IdleThread extends Thread {
+ boolean started;
+ private AltosState state;
+ int reported_landing;
+ int report_interval;
+ long report_time;
+
+ public synchronized void report(boolean last) {
+ if (state == null)
+ return;
+
+ /* reset the landing count once we hear about a new flight */
+ if (state.state < AltosLib.ao_flight_drogue)
+ reported_landing = 0;
+
+ /* Shut up once the rocket is on the ground */
+ if (reported_landing > 2) {
+ return;
+ }
+
+ /* If the rocket isn't on the pad, then report height */
+ if (AltosLib.ao_flight_drogue <= state.state &&
+ state.state < AltosLib.ao_flight_landed &&
+ state.range >= 0)
+ {
+ speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",
+ (int) (state.height + 0.5),
+ state.from_pad.bearing_words(
+ AltosGreatCircle.BEARING_VOICE),
+ (int) (state.from_pad.bearing + 0.5),
+ (int) (state.elevation + 0.5),
+ (int) (state.range + 0.5)));
+ } else if (state.state > AltosLib.ao_flight_pad) {
+ speak(String.format("%d meters", (int) (state.height + 0.5)));
+ } else {
+ reported_landing = 0;
+ }
+
+ /* If the rocket is coming down, check to see if it has landed;
+ * either we've got a landed report or we haven't heard from it in
+ * a long time
+ */
+ if (state.state >= AltosLib.ao_flight_drogue &&
+ (last ||
+ System.currentTimeMillis() - state.report_time >= 15000 ||
+ state.state == AltosLib.ao_flight_landed))
+ {
+ if (Math.abs(state.baro_speed) < 20 && state.height < 100)
+ speak("rocket landed safely");
+ else
+ speak("rocket may have crashed");
+ if (state.from_pad != null)
+ speak(String.format("Bearing %d degrees, range %d meters.",
+ (int) (state.from_pad.bearing + 0.5),
+ (int) (state.from_pad.distance + 0.5)));
+ ++reported_landing;
+ }
+ }
+
+ long now () {
+ return System.currentTimeMillis();
+ }
+
+ void set_report_time() {
+ report_time = now() + report_interval;
+ }
+
+ public void run () {
+ try {
+ for (;;) {
+ set_report_time();
+ for (;;) {
+ synchronized (this) {
+ long sleep_time = report_time - now();
+ if (sleep_time <= 0)
+ break;
+ wait(sleep_time);
+ }
+ }
+ report(false);
+ }
+ } catch (InterruptedException ie) {
+ }
+ }
+
+ public synchronized void notice(AltosState new_state, boolean spoken) {
+ AltosState old_state = state;
+ state = new_state;
+ if (!started && state.state > AltosLib.ao_flight_pad) {
+ started = true;
+ start();
+ }
+
+ if (state.state < AltosLib.ao_flight_drogue)
+ report_interval = 10000;
+ else
+ report_interval = 20000;
+ if (old_state != null && old_state.state != state.state) {
+ report_time = now();
+ this.notify();
+ } else if (spoken)
+ set_report_time();
+ }
+
+ public IdleThread() {
+ state = null;
+ reported_landing = 0;
+ report_interval = 10000;
+ }
+ }
+
+}