From: Keith Packard Date: Wed, 28 Jul 2010 20:29:51 +0000 (-0700) Subject: Merge remote branch 'keithp/macos' X-Git-Tag: debian/0.6+268+gd0fd53b~7 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=8a6040e143ecc7830cc1c0114de85f3b72c067eb;hp=554a97ef455c801dcab825815f44520f96f4c3f3 Merge remote branch 'keithp/macos' --- 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> monitors; LinkedBlockingQueue 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> (); - reply_queue = new LinkedBlockingQueue (); - } -} - -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 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 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> (); + reply_queue = new LinkedBlockingQueue (); } } 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 (); 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,