summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ao-tools/Makefile.am2
-rw-r--r--ao-tools/altosui/AltosDevice.java3
-rw-r--r--ao-tools/altosui/AltosDeviceDialog.java4
-rw-r--r--ao-tools/altosui/AltosPreferences.java40
-rw-r--r--ao-tools/altosui/AltosSerial.java67
-rw-r--r--ao-tools/altosui/AltosUI.java157
-rw-r--r--ao-tools/altosui/AltosVoice.java13
-rw-r--r--ao-tools/altosui/Makefile37
-rw-r--r--ao-tools/altosui/Manifest.txt2
-rw-r--r--ao-tools/altosui/voices.txt1
-rw-r--r--src/ao.h2
-rw-r--r--src/ao_log.c6
12 files changed, 219 insertions, 115 deletions
diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am
index 2850e909..54dc777a 100644
--- a/ao-tools/Makefile.am
+++ b/ao-tools/Makefile.am
@@ -1 +1 @@
-SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view
+SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view libaltos altosui
diff --git a/ao-tools/altosui/AltosDevice.java b/ao-tools/altosui/AltosDevice.java
index 0e7d01da..f488174c 100644
--- a/ao-tools/altosui/AltosDevice.java
+++ b/ao-tools/altosui/AltosDevice.java
@@ -42,7 +42,8 @@ public class AltosDevice extends altos_device {
AltosDevice device = new AltosDevice();
if (libaltos.altos_list_next(list, device) == 0)
break;
- device_list.add(device);
+ if (product == null || device.getProduct().startsWith(product))
+ device_list.add(device);
}
libaltos.altos_list_finish(list);
}
diff --git a/ao-tools/altosui/AltosDeviceDialog.java b/ao-tools/altosui/AltosDeviceDialog.java
index eb70877c..08921c3d 100644
--- a/ao-tools/altosui/AltosDeviceDialog.java
+++ b/ao-tools/altosui/AltosDeviceDialog.java
@@ -41,6 +41,10 @@ public class AltosDeviceDialog {
devices[0]);
return (altos_device) o;
} else {
+ JOptionPane.showMessageDialog(frame,
+ "No AltOS devices available",
+ "No AltOS devices",
+ JOptionPane.ERROR_MESSAGE);
return null;
}
}
diff --git a/ao-tools/altosui/AltosPreferences.java b/ao-tools/altosui/AltosPreferences.java
index 0296d935..297e1aae 100644
--- a/ao-tools/altosui/AltosPreferences.java
+++ b/ao-tools/altosui/AltosPreferences.java
@@ -31,6 +31,12 @@ class AltosPreferences {
/* logdir preference name */
final static String logdirPreference = "LOGDIR";
+ /* channel preference name */
+ final static String channelPreference = "CHANNEL";
+
+ /* voice preference name */
+ final static String voicePreference = "VOICE";
+
/* Default logdir is ~/TeleMetrum */
final static String logdirName = "TeleMetrum";
@@ -40,6 +46,12 @@ class AltosPreferences {
/* Log directory */
static File logdir;
+ /* Telemetry channel */
+ static int channel;
+
+ /* Voice preference */
+ static boolean voice;
+
public static void init(Component ui) {
preferences = Preferences.userRoot().node("/org/altusmetrum/altosui");
@@ -55,6 +67,10 @@ class AltosPreferences {
if (!logdir.exists())
logdir.mkdirs();
}
+
+ channel = preferences.getInt(channelPreference, 0);
+
+ voice = preferences.getBoolean(voicePreference, true);
}
static void flush_preferences() {
@@ -114,4 +130,28 @@ class AltosPreferences {
public static File logdir() {
return logdir;
}
+
+ public static void set_channel(int new_channel) {
+ channel = new_channel;
+ synchronized (preferences) {
+ preferences.putInt(channelPreference, channel);
+ flush_preferences();
+ }
+ }
+
+ public static int channel() {
+ return channel;
+ }
+
+ public static void set_voice(boolean new_voice) {
+ voice = new_voice;
+ synchronized (preferences) {
+ preferences.putBoolean(voicePreference, voice);
+ flush_preferences();
+ }
+ }
+
+ public static boolean voice() {
+ return voice;
+ }
}
diff --git a/ao-tools/altosui/AltosSerial.java b/ao-tools/altosui/AltosSerial.java
index 073bfb78..f12b31b3 100644
--- a/ao-tools/altosui/AltosSerial.java
+++ b/ao-tools/altosui/AltosSerial.java
@@ -37,7 +37,9 @@ import libaltosJNI.SWIGTYPE_p_altos_list;
* line in a queue. Dealing with that queue is left up to other
* threads.
*/
-class AltosSerialReader implements Runnable {
+
+public class AltosSerial implements Runnable {
+
SWIGTYPE_p_altos_file altos;
LinkedList<LinkedBlockingQueue<String>> monitors;
LinkedBlockingQueue<String> reply_queue;
@@ -116,50 +118,45 @@ class AltosSerialReader implements Runnable {
}
}
- public void open(altos_device device) throws FileNotFoundException {
- close();
- altos = libaltos.altos_open(device);
- input_thread = new Thread(this);
- input_thread.start();
- }
- public AltosSerialReader () {
- altos = null;
- input_thread = null;
- line = "";
- monitors = new LinkedList<LinkedBlockingQueue<String>> ();
- reply_queue = new LinkedBlockingQueue<String> ();
- }
-}
-
-public class AltosSerial {
- AltosSerialReader reader = null;
-
- public void close() {
- reader.close();
+ public void putc(char c) {
+ if (altos != null)
+ libaltos.altos_putchar(altos, c);
}
- public void open(altos_device device) throws FileNotFoundException {
- reader.open(device);
+ public void print(String data) {
+ for (int i = 0; i < data.length(); i++)
+ putc(data.charAt(i));
}
- void init() {
- reader = new AltosSerialReader();
+ public void printf(String format, Object ... arguments) {
+ print(String.format(format, arguments));
}
- public void add_monitor(LinkedBlockingQueue<String> q) {
- reader.add_monitor(q);
+ public void open(altos_device device) throws FileNotFoundException {
+ close();
+ altos = libaltos.altos_open(device);
+ if (altos == null)
+ throw new FileNotFoundException(device.getPath());
+ input_thread = new Thread(this);
+ input_thread.start();
+ print("\nE 0\nm 1\n");
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ }
+ flush();
}
- public void remove_monitor(LinkedBlockingQueue<String> q) {
- reader.remove_monitor(q);
+ public void set_channel(int channel) {
+ if (altos != null)
+ printf("m 0\nc r %d\nm 1\n", channel);
}
public AltosSerial() {
- init();
- }
-
- public AltosSerial(altos_device device) throws FileNotFoundException {
- init();
- open(device);
+ altos = null;
+ input_thread = null;
+ line = "";
+ monitors = new LinkedList<LinkedBlockingQueue<String>> ();
+ reply_queue = new LinkedBlockingQueue<String> ();
}
}
diff --git a/ao-tools/altosui/AltosUI.java b/ao-tools/altosui/AltosUI.java
index 33ed2c90..ecacffe5 100644
--- a/ao-tools/altosui/AltosUI.java
+++ b/ao-tools/altosui/AltosUI.java
@@ -210,6 +210,7 @@ public class AltosUI extends JFrame {
System.exit(0);
}
});
+ voice.speak("Rocket flight monitor ready.");
}
public void info_reset() {
@@ -221,16 +222,8 @@ public class AltosUI extends JFrame {
flightInfoModel[col].addRow(name, value);
}
- public void info_add_row(int col, String name, String format, Object value) {
- flightInfoModel[col].addRow(name, String.format(format, value));
- }
-
- public void info_add_row(int col, String name, String format, Object v1, Object v2) {
- flightInfoModel[col].addRow(name, String.format(format, v1, v2));
- }
-
- public void info_add_row(int col, String name, String format, Object v1, Object v2, Object v3) {
- flightInfoModel[col].addRow(name, String.format(format, v1, v2, v3));
+ public void info_add_row(int col, String name, String format, Object... parameters) {
+ flightInfoModel[col].addRow(name, String.format(format, parameters));
}
public void info_add_deg(int col, String name, double v, int pos, int neg) {
@@ -346,48 +339,57 @@ public class AltosUI extends JFrame {
class IdleThread extends Thread {
private AltosState state;
+ int reported_landing;
+
+ public void report(boolean last) {
+ if (state == null)
+ return;
+
+ /* reset the landing count once we hear about a new flight */
+ if (state.state < AltosTelemetry.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 (state.state > AltosTelemetry.ao_flight_pad) {
+ voice.speak("%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.ascent &&
+ (last ||
+ System.currentTimeMillis() - state.report_time >= 15000 ||
+ state.state == AltosTelemetry.ao_flight_landed))
+ {
+ if (Math.abs(state.baro_speed) < 20 && state.height < 100)
+ voice.speak("rocket landed safely");
+ else
+ voice.speak("rocket may have crashed");
+ if (state.gps != null)
+ voice.speak("bearing %d degrees, range %d meters",
+ (int) (state.from_pad.bearing + 0.5),
+ (int) (state.from_pad.distance + 0.5));
+ ++reported_landing;
+ }
+ }
public void run () {
- int reported_landing = 0;
+ reported_landing = 0;
state = null;
try {
for (;;) {
Thread.sleep(10000);
- if (state == null)
- continue;
-
- /* reset the landing count once we hear about a new flight */
- if (state.state < AltosTelemetry.ao_flight_drogue)
- reported_landing = 0;
-
- /* Shut up once the rocket is on the ground */
- if (reported_landing > 2)
- continue;
-
- /* If the rocket isn't on the pad, then report height */
- if (state.state > AltosTelemetry.ao_flight_pad) {
- voice.speak(String.format("%d meters", (int) (state.height + 0.5)));
- }
-
- /* 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.ascent &&
- (System.currentTimeMillis() - state.report_time > 10000 ||
- state.state == AltosTelemetry.ao_flight_landed))
- {
- if (Math.abs(state.baro_speed) < 20 && state.height < 100)
- voice.speak("rocket landed safely");
- else
- voice.speak("rocket may have crashed");
- if (state.gps != null)
- voice.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;
- }
+ report(false);
}
} catch (InterruptedException ie) {
}
@@ -401,21 +403,22 @@ public class AltosUI extends JFrame {
private void tell(AltosState state, AltosState old_state) {
if (old_state == null || old_state.state != state.state) {
voice.speak(state.data.state);
- switch (state.state) {
- case AltosTelemetry.ao_flight_fast:
- voice.speak(String.format("max speed %d meters per second",
- (int) (state.max_speed + 0.5)));
- break;
- case AltosTelemetry.ao_flight_drogue:
- voice.speak(String.format("max height %d meters",
- (int) (state.max_height + 0.5)));
- break;
+ if ((old_state == null || old_state.state <= AltosTelemetry.ao_flight_boost) &&
+ state.state > AltosTelemetry.ao_flight_boost) {
+ voice.speak("max speed: %d meters per second.",
+ (int) (state.max_speed + 0.5));
+ } else if ((old_state == null || old_state.state < AltosTelemetry.ao_flight_drogue) &&
+ state.state >= AltosTelemetry.ao_flight_drogue) {
+ voice.speak("max height: %d meters.",
+ (int) (state.max_height + 0.5));
}
}
old_state = state;
}
class DisplayThread extends Thread {
+ IdleThread idle_thread;
+
String read() throws InterruptedException { return null; }
void close() { }
@@ -426,7 +429,8 @@ public class AltosUI extends JFrame {
String line;
AltosState state = null;
AltosState old_state = null;
- IdleThread idle_thread = new IdleThread();
+
+ idle_thread = new IdleThread();
info_reset();
info_finish();
@@ -452,6 +456,11 @@ public class AltosUI extends JFrame {
idle_thread.interrupt();
}
}
+
+ public void report() {
+ if (idle_thread != null)
+ idle_thread.report(true);
+ }
}
class DeviceThread extends DisplayThread {
@@ -465,7 +474,6 @@ public class AltosUI extends JFrame {
void close() {
serial.close();
serial.remove_monitor(telem);
- System.out.println("DisplayThread done");
}
public DeviceThread(AltosSerial s) {
@@ -482,11 +490,13 @@ public class AltosUI extends JFrame {
try {
serial_line.open(device);
DeviceThread thread = new DeviceThread(serial_line);
+ serial_line.set_channel(AltosPreferences.channel());
run_display(thread);
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(AltosUI.this,
- device.getPath(),
- "Cannot open serial port",
+ String.format("Cannot open device \"%s\"",
+ device.getPath()),
+ "Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} catch (IOException ee) {
JOptionPane.showMessageDialog(AltosUI.this,
@@ -508,8 +518,9 @@ public class AltosUI extends JFrame {
while ((c = s.read()) != -1) {
if (c == '\r')
continue;
- if (c == '\n')
+ if (c == '\n') {
return line;
+ }
line = line + (char) c;
}
return null;
@@ -545,12 +556,13 @@ public class AltosUI extends JFrame {
replay.close();
} catch (IOException ee) {
}
+ report();
}
void update(AltosState state) throws InterruptedException {
/* Make it run in realtime after the rocket leaves the pad */
if (state.state > AltosTelemetry.ao_flight_pad)
- Thread.sleep((int) (state.time_change * 1000));
+ Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
}
}
@@ -591,7 +603,7 @@ public class AltosUI extends JFrame {
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(AltosUI.this,
filename,
- "Cannot open serial port",
+ "Cannot open telemetry file",
JOptionPane.ERROR_MESSAGE);
}
}
@@ -695,12 +707,26 @@ public class AltosUI extends JFrame {
menu.setMnemonic(KeyEvent.VK_V);
menubar.add(menu);
- radioitem = new JRadioButtonMenuItem("Enable Voice");
+ radioitem = new JRadioButtonMenuItem("Enable Voice", AltosPreferences.voice());
radioitem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
+ JRadioButtonMenuItem item = (JRadioButtonMenuItem) e.getSource();
+ boolean enabled = item.isSelected();
+ AltosPreferences.set_voice(enabled);
+ if (enabled)
+ voice.speak_always("Enable voice.");
+ else
+ voice.speak_always("Disable voice.");
}
});
menu.add(radioitem);
+ item = new JMenuItem("Test Voice",KeyEvent.VK_T);
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ voice.speak("That's one small step for man; one giant leap for mankind.");
+ }
+ });
+ menu.add(item);
}
// Channel menu
@@ -713,12 +739,13 @@ public class AltosUI extends JFrame {
for (int c = 0; c <= 9; c++) {
radioitem = new JRadioButtonMenuItem(String.format("Channel %1d (%7.3fMHz)", c,
434.550 + c * 0.1),
- c == 0);
+ c == AltosPreferences.channel());
radioitem.setActionCommand(String.format("%d", c));
radioitem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
- System.out.println("Command: " + e.getActionCommand() + " param: " +
- e.paramString());
+ int new_channel = Integer.parseInt(e.getActionCommand());
+ AltosPreferences.set_channel(new_channel);
+ serial_line.set_channel(new_channel);
}
});
menu.add(radioitem);
diff --git a/ao-tools/altosui/AltosVoice.java b/ao-tools/altosui/AltosVoice.java
index e4ea99a2..ebe9d5a8 100644
--- a/ao-tools/altosui/AltosVoice.java
+++ b/ao-tools/altosui/AltosVoice.java
@@ -39,7 +39,8 @@ public class AltosVoice implements Runnable {
} catch (InterruptedException e) {
}
}
- public void speak(String s) {
+
+ public void speak_always(String s) {
try {
if (voice != null)
phrases.put(s);
@@ -47,6 +48,15 @@ public class AltosVoice implements Runnable {
}
}
+ public void speak(String s) {
+ if (AltosPreferences.voice())
+ speak_always(s);
+ }
+
+ public void speak(String format, Object... parameters) {
+ speak(String.format(format, parameters));
+ }
+
public AltosVoice () {
voice_manager = VoiceManager.getInstance();
voice = voice_manager.getVoice(voice_name);
@@ -55,7 +65,6 @@ public class AltosVoice implements Runnable {
phrases = new LinkedBlockingQueue<String> ();
thread = new Thread(this);
thread.start();
- speak("Rocket Flight Monitor Ready");
} else {
System.out.printf("Voice manager failed to open %s\n", voice_name);
Voice[] voices = voice_manager.getVoices();
diff --git a/ao-tools/altosui/Makefile b/ao-tools/altosui/Makefile
index 39d1a70c..0613a494 100644
--- a/ao-tools/altosui/Makefile
+++ b/ao-tools/altosui/Makefile
@@ -1,6 +1,6 @@
.SUFFIXES: .java .class
-CLASSPATH=..:../libaltos:/usr/share/java/*:/Users/keithp/freetts-1.2.2/lib/*
+CLASSPATH=classes:./*
CLASSFILES=\
AltosConvert.class \
AltosFile.class \
@@ -18,15 +18,42 @@ CLASSFILES=\
AltosDeviceDialog.class \
AltosVoice.class
+FREETTSSRC=/home/keithp/src/freetts/freetts-1.2.2
+FREETTSLIB=$(FREETTSSRC)/lib
+FREETTSJAR= \
+ cmudict04.jar \
+ cmulex.jar \
+ cmu_time_awb.jar \
+ cmutimelex.jar \
+ cmu_us_kal.jar \
+ en_us.jar \
+ freetts.jar \
+ freetts-jsapi10.jar \
+ jsapi.jar
+
JAVAFLAGS=-Xlint:unchecked
-all: $(CLASSFILES) altosui.jar
+all: altosui.jar
+
+$(CLASSFILES):
.java.class:
javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
-altosui.jar: $(CLASSFILES) Manifest.txt
- jar cfm $@ altosui/Manifest.txt altosui/*.class libaltosJNI/*.class
+altosui.jar: classes/altosui classes/libaltosJNI $(FREETTSJAR) $(CLASSFILES) Manifest.txt
+ cd ./classes && jar cfm ../$@ altosui/Manifest.txt altosui/*.class libaltosJNI/*.class
+
+classes/altosui:
+ mkdir -p classes
+ ln -s .. classes/altosui
+
+classes/libaltosJNI:
+ mkdir -p classes
+ ln -s ../../libaltos/libaltosJNI classes/libaltosJNI
+
+$(FREETTSJAR):
+ ln -s $(FREETTSLIB)/$@ .
clean:
- rm -f *.class
+ rm -f *.class $(FREETTSJAR) altosui.jar
+ rm -rf classes
diff --git a/ao-tools/altosui/Manifest.txt b/ao-tools/altosui/Manifest.txt
index 7dbaafff..251ce2a0 100644
--- a/ao-tools/altosui/Manifest.txt
+++ b/ao-tools/altosui/Manifest.txt
@@ -1,2 +1,2 @@
Main-Class: altosui.AltosUI
-Class-Path: /home/keithp/src/freetts/freetts-1.2.2/lib/freetts.jar
+Class-Path: freetts.jar
diff --git a/ao-tools/altosui/voices.txt b/ao-tools/altosui/voices.txt
deleted file mode 100644
index e8825fc3..00000000
--- a/ao-tools/altosui/voices.txt
+++ /dev/null
@@ -1 +0,0 @@
-com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory
diff --git a/src/ao.h b/src/ao.h
index dfff8a8d..5dd756da 100644
--- a/src/ao.h
+++ b/src/ao.h
@@ -562,7 +562,7 @@ struct ao_log_record {
/* Write a record to the eeprom log */
void
-ao_log_data(struct ao_log_record *log);
+ao_log_data(__xdata struct ao_log_record *log) __reentrant;
/* Flush the log */
void
diff --git a/src/ao_log.c b/src/ao_log.c
index 44ce90e0..d550d408 100644
--- a/src/ao_log.c
+++ b/src/ao_log.c
@@ -23,7 +23,7 @@ static __xdata uint8_t ao_log_running;
static __xdata uint8_t ao_log_mutex;
static uint8_t
-ao_log_csum(uint8_t *b)
+ao_log_csum(__xdata uint8_t *b) __reentrant
{
uint8_t sum = 0x5a;
uint8_t i;
@@ -34,11 +34,11 @@ ao_log_csum(uint8_t *b)
}
void
-ao_log_data(struct ao_log_record *log)
+ao_log_data(__xdata struct ao_log_record *log) __reentrant
{
/* set checksum */
log->csum = 0;
- log->csum = ao_log_csum((uint8_t *) log);
+ log->csum = ao_log_csum((__xdata uint8_t *) log);
ao_mutex_get(&ao_log_mutex); {
if (ao_log_running) {
ao_ee_write(ao_log_current_pos,