From 8801b8c1947bd39f7c985b91a2ba8dbc81bcc91a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 12 Jan 2011 12:40:45 -0800 Subject: [PATCH] altosui: Add eeprom 'manage' ui to download and delete multiple flights This shows the list of available flights and provides options to download and/or delete each one. Signed-off-by: Keith Packard --- altosui/AltosEepromDelete.java | 148 +++++++++++++++++++++++++++++ altosui/AltosEepromDownload.java | 124 ++++++++++++------------ altosui/AltosEepromList.java | 31 +++++- altosui/AltosEepromLog.java | 16 ++++ altosui/AltosEepromManage.java | 157 +++++++++++++++++++++++++++++++ altosui/AltosEepromMonitor.java | 18 ++++ altosui/AltosEepromSelect.java | 132 ++++++++++++++++++++++++++ altosui/AltosUI.java | 2 +- altosui/Makefile.am | 3 + 9 files changed, 565 insertions(+), 66 deletions(-) create mode 100644 altosui/AltosEepromDelete.java create mode 100644 altosui/AltosEepromManage.java create mode 100644 altosui/AltosEepromSelect.java diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java new file mode 100644 index 00000000..c95eda15 --- /dev/null +++ b/altosui/AltosEepromDelete.java @@ -0,0 +1,148 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosEepromDelete implements Runnable { + AltosEepromList flights; + Thread eeprom_thread; + AltosSerial serial_line; + boolean remote; + JFrame frame; + ActionListener listener; + boolean success; + + private void DeleteLog (AltosEepromLog log) + throws IOException, InterruptedException, TimeoutException { + + if (flights.config_data.flight_log_max != 0) { + + /* Devices with newer firmware can erase the + * flash blocks containing each flight + */ + serial_line.flush_input(); + serial_line.printf("d %d\n", log.flight); + System.out.printf("Attempt to delete flight %d\n", log.flight); + for (;;) { + /* It can take a while to erase the flash... */ + String line = serial_line.get_reply(20000); + System.out.printf("got back line %s\n", line); + if (line == null) + throw new TimeoutException(); + if (line.equals("Erased")) + break; + if (line.startsWith("No such")) + throw new IOException(line); + } + } + } + + private void show_error_internal(String message, String title) { + JOptionPane.showMessageDialog(frame, + message, + title, + JOptionPane.ERROR_MESSAGE); + } + + private void show_error(String in_message, String in_title) { + final String message = in_message; + final String title = in_title; + Runnable r = new Runnable() { + public void run() { + try { + show_error_internal(message, title); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + + public void run () { + if (remote) + serial_line.start_remote(); + + success = false; + try { + for (AltosEepromLog log : flights) { + if (log.delete) { + DeleteLog(log); + } + } + System.out.printf("All flights successfully deleted\n"); + success = true; + } catch (IOException ee) { + show_error (ee.getLocalizedMessage(), + serial_line.device.toShortString()); + } catch (InterruptedException ie) { + } catch (TimeoutException te) { + show_error (String.format("Connection to \"%s\" failed", + serial_line.device.toShortString()), + "Connection Failed"); + } + if (remote) + serial_line.stop_remote(); + serial_line.flush_output(); + serial_line.close(); + if (listener != null) { + Runnable r = new Runnable() { + public void run() { + try { + listener.actionPerformed(new ActionEvent(this, + success ? 1 : 0, + "delete")); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } + } + + public void start() { + eeprom_thread = new Thread(this); + eeprom_thread.start(); + } + + public void addActionListener(ActionListener l) { + listener = l; + } + + public AltosEepromDelete(JFrame given_frame, + AltosSerial given_serial_line, + boolean given_remote, + AltosEepromList given_flights) { + frame = given_frame; + serial_line = given_serial_line; + remote = given_remote; + flights = given_flights; + success = false; + } +} \ No newline at end of file diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index ca31fdcf..5d19acec 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -33,21 +33,21 @@ import libaltosJNI.*; public class AltosEepromDownload implements Runnable { JFrame frame; - AltosDevice device; AltosSerial serial_line; boolean remote; Thread eeprom_thread; AltosEepromMonitor monitor; - int serial = 0; int flight = 0; int year = 0, month = 0, day = 0; boolean want_file = false; FileWriter eeprom_file = null; LinkedList eeprom_pending = new LinkedList(); - AltosConfigData config_data; + AltosEepromList flights; + ActionListener listener; + boolean success; private void FlushPending() throws IOException { - for (String s : config_data) { + for (String s : flights.config_data) { eeprom_file.write(s); eeprom_file.write('\n'); } @@ -62,9 +62,9 @@ public class AltosEepromDownload implements Runnable { if (force || (flight != 0 && want_file)) { AltosFile eeprom_name; if (year != 0 && month != 0 && day != 0) - eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom"); + eeprom_name = new AltosFile(year, month, day, flights.config_data.serial, flight, "eeprom"); else - eeprom_name = new AltosFile(serial, flight, "eeprom"); + eeprom_name = new AltosFile(flights.config_data.serial, flight, "eeprom"); eeprom_file = new FileWriter(eeprom_name); if (eeprom_file != null) { @@ -75,25 +75,24 @@ public class AltosEepromDownload implements Runnable { } } - void CaptureLog(int start_block, int end_block) throws IOException, InterruptedException, TimeoutException { + void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException { int block, state_block = 0; int state = 0; boolean done = false; int record; - config_data = new AltosConfigData(serial_line); - serial = config_data.serial; - if (serial == 0) + if (flights.config_data.serial == 0) throw new IOException("no serial number found"); - monitor.set_serial(serial); + monitor.set_serial(flights.config_data.serial); /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */ - state = 0; state_block = start_block; - for (block = start_block; !done && block < end_block; block++) { + state = 0; state_block = log.start_block; + for (block = log.start_block; !done && block < log.end_block; block++) { monitor.set_value(Altos.state_to_string[state], state, block - state_block); AltosEepromBlock eeblock = new AltosEepromBlock(serial_line, block); + if (eeblock.has_flight) { flight = eeblock.flight; monitor.set_flight(flight); @@ -117,7 +116,7 @@ public class AltosEepromDownload implements Runnable { state = eeblock.state; } - CheckFile(true); + CheckFile(false); for (record = 0; record < eeblock.size(); record++) { AltosEepromRecord r = eeblock.get(record); @@ -158,76 +157,73 @@ public class AltosEepromDownload implements Runnable { SwingUtilities.invokeLater(r); } - int start_block, end_block; - public void run () { - try { - new AltosEepromList(serial_line, remote); - } catch (Exception ee) { } - if (remote) serial_line.start_remote(); try { - CaptureLog(start_block, end_block); + for (AltosEepromLog log : flights) { + if (log.download) { + monitor.reset(); + CaptureLog(log); + } + } + System.out.printf("All flights successfully downloaded\n"); + success = true; } catch (IOException ee) { - show_error (device.toShortString(), + show_error (serial_line.device.toShortString(), ee.getLocalizedMessage()); } catch (InterruptedException ie) { } catch (TimeoutException te) { show_error (String.format("Connection to \"%s\" failed", - device.toShortString()), + serial_line.device.toShortString()), "Connection Failed"); } if (remote) serial_line.stop_remote(); monitor.done(); serial_line.flush_output(); - serial_line.close(); + if (listener != null) { + Runnable r = new Runnable() { + public void run() { + try { + listener.actionPerformed(new ActionEvent(this, + success ? 1 : 0, + "download")); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } } - public AltosEepromDownload(JFrame given_frame) { - frame = given_frame; - device = AltosDeviceDialog.show(frame, AltosDevice.product_any); + public void start() { + eeprom_thread = new Thread(this); + eeprom_thread.start(); + } - remote = false; + public void addActionListener(ActionListener l) { + listener = l; + } - if (device != null) { - try { - serial_line = new AltosSerial(device); - if (!device.matchProduct(AltosDevice.product_telemetrum)) - remote = true; + public AltosEepromDownload(JFrame given_frame, + AltosSerial given_serial_line, + boolean given_remote, + AltosEepromList given_flights) { - monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); - monitor.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (eeprom_thread != null) - eeprom_thread.interrupt(); - } - }); - - eeprom_thread = new Thread(this); - start_block = 0; - end_block = 0xfff; - eeprom_thread.start(); - } catch (FileNotFoundException ee) { - JOptionPane.showMessageDialog(frame, - String.format("Cannot open device \"%s\"", - device.toShortString()), - "Cannot open target device", - JOptionPane.ERROR_MESSAGE); - } catch (AltosSerialInUseException si) { - JOptionPane.showMessageDialog(frame, - String.format("Device \"%s\" already in use", - device.toShortString()), - "Device in use", - JOptionPane.ERROR_MESSAGE); - } catch (IOException ee) { - JOptionPane.showMessageDialog(frame, - device.toShortString(), - ee.getLocalizedMessage(), - JOptionPane.ERROR_MESSAGE); - } - } + frame = given_frame; + serial_line = given_serial_line; + remote = given_remote; + flights = given_flights; + success = false; + + monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed); + monitor.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (eeprom_thread != null) + eeprom_thread.interrupt(); + } + }); } } diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java index ac4a29de..a932dd12 100644 --- a/altosui/AltosEepromList.java +++ b/altosui/AltosEepromList.java @@ -30,6 +30,12 @@ import java.util.concurrent.*; import libaltosJNI.*; +/* + * Temporary structure to hold the list of stored flights; + * each of these will be queried in turn to generate more + * complete information + */ + class AltosEepromFlight { int flight; int start; @@ -42,10 +48,16 @@ class AltosEepromFlight { } } +/* + * Construct a list of flights available in a connected device + */ + public class AltosEepromList extends ArrayList { AltosConfigData config_data; - public AltosEepromList (AltosSerial serial_line, boolean remote) throws IOException, InterruptedException, TimeoutException { + public AltosEepromList (AltosSerial serial_line, boolean remote) + throws IOException, InterruptedException, TimeoutException + { try { if (remote) serial_line.start_remote(); @@ -54,7 +66,13 @@ public class AltosEepromList extends ArrayList { throw new IOException("no serial number found"); ArrayList flights = new ArrayList(); + if (config_data.flight_log_max != 0) { + + /* Devices with newer firmware will support the 'l' + * command which will list the region of storage + * occupied by each available flight + */ serial_line.printf("l\n"); for (;;) { String line = serial_line.get_reply(5000); @@ -83,8 +101,19 @@ public class AltosEepromList extends ArrayList { } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); } } } else { + + /* Older devices will hold only a single + * flight. This also assumes that any older + * device will have a 1MB flash device + */ flights.add(new AltosEepromFlight(0, 0, 0xfff)); } + + /* With the list of flights collected, collect more complete + * information on them by reading the first block or two of + * data. This will add GPS coordinates and a date. For older + * firmware, this will also extract the flight number. + */ for (AltosEepromFlight flight : flights) { System.out.printf("Scanning flight %d %x %x\n", flight.flight, flight.start, flight.end); add(new AltosEepromLog(serial_line, config_data.serial, diff --git a/altosui/AltosEepromLog.java b/altosui/AltosEepromLog.java index 36289b42..f284f103 100644 --- a/altosui/AltosEepromLog.java +++ b/altosui/AltosEepromLog.java @@ -30,6 +30,10 @@ import java.util.concurrent.*; import libaltosJNI.*; +/* + * Extract a bit of information from an eeprom-stored flight log. + */ + public class AltosEepromLog { int serial; boolean has_flight; @@ -42,6 +46,9 @@ public class AltosEepromLog { int hour, minute, second; double lat, lon; + boolean download; + boolean delete; + public AltosEepromLog(AltosSerial serial_line, int in_serial, int in_start_block, int in_end_block) throws InterruptedException, TimeoutException { @@ -53,6 +60,15 @@ public class AltosEepromLog { end_block = in_end_block; serial = in_serial; + /* + * By default, request that every log be downloaded but not deleted + */ + download = true; + delete = false; + /* + * Only look in the first two blocks so that this + * process doesn't take a long time + */ if (in_end_block > in_start_block + 2) in_end_block = in_start_block + 2; diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java new file mode 100644 index 00000000..b64ee525 --- /dev/null +++ b/altosui/AltosEepromManage.java @@ -0,0 +1,157 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import libaltosJNI.*; + +public class AltosEepromManage implements ActionListener { + + JFrame frame; + boolean remote; + AltosDevice device; + AltosSerial serial_line; + AltosEepromList flights; + AltosEepromDownload download; + AltosEepromDelete delete; + boolean any_download; + boolean any_delete; + + public void finish() { + if (serial_line != null) { + serial_line.flush_output(); + serial_line.close(); + serial_line = null; + } + } + + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + boolean success = e.getID() != 0; + + System.out.printf("Eeprom manager action %s %d\n", cmd, e.getID()); + if (cmd.equals("download")) { + if (success) { + System.out.printf("Download succeeded\n"); + if (any_delete) + delete.start(); + else + finish(); + } + } else if (cmd.equals("delete")) { + if (success) + System.out.printf("Delete succeeded\n"); + finish(); + } + } + + public AltosEepromManage(JFrame given_frame) { + + frame = given_frame; + device = AltosDeviceDialog.show(frame, AltosDevice.product_any); + + remote = false; + any_download = false; + any_delete = false; + + if (device != null) { + try { + serial_line = new AltosSerial(device); + if (!device.matchProduct(AltosDevice.product_telemetrum)) + remote = true; + + flights = new AltosEepromList(serial_line, remote); + + if (flights.size() == 0) { + } else { + AltosEepromSelect select = new AltosEepromSelect(frame, flights); + + if (select.run()) { + for (AltosEepromLog flight : flights) { + any_download = any_download || flight.download; + any_delete = any_delete || flight.delete; + } + if (any_download) { + download = new AltosEepromDownload(frame, + serial_line, + remote, + flights); + download.addActionListener(this); + } + + if (any_delete) { + delete = new AltosEepromDelete(frame, + serial_line, + remote, + flights); + delete.addActionListener(this); + } + + /* + * Start flight log download + */ + + if (any_download) + download.start(); + else if (any_delete) + delete.start(); + else + finish(); + } + } + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(frame, + String.format("Cannot open device \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + } catch (AltosSerialInUseException si) { + JOptionPane.showMessageDialog(frame, + String.format("Device \"%s\" already in use", + device.toShortString()), + "Device in use", + JOptionPane.ERROR_MESSAGE); + } catch (IOException ee) { + JOptionPane.showMessageDialog(frame, + device.toShortString(), + ee.getLocalizedMessage(), + JOptionPane.ERROR_MESSAGE); + finish(); + } catch (TimeoutException te) { + JOptionPane.showMessageDialog(frame, + String.format("Communications failed with \"%s\"", + device.toShortString()), + "Cannot open target device", + JOptionPane.ERROR_MESSAGE); + finish(); + } catch (InterruptedException ie) { + finish(); + } + } + } +} diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java index 13a49a95..b9d913fa 100644 --- a/altosui/AltosEepromMonitor.java +++ b/altosui/AltosEepromMonitor.java @@ -239,4 +239,22 @@ public class AltosEepromMonitor extends JDialog { }; SwingUtilities.invokeLater(r); } + + private void reset_internal() { + set_value_internal("startup",min_state,0); + set_flight_internal(0); + set_file_internal(""); + } + + public void reset() { + Runnable r = new Runnable() { + public void run() { + try { + reset_internal(); + } catch (Exception ex) { + } + } + }; + SwingUtilities.invokeLater(r); + } } diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java new file mode 100644 index 00000000..104d3180 --- /dev/null +++ b/altosui/AltosEepromSelect.java @@ -0,0 +1,132 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 altosui; + +import java.lang.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; +import libaltosJNI.libaltos; +import libaltosJNI.altos_device; +import libaltosJNI.SWIGTYPE_p_altos_file; +import libaltosJNI.SWIGTYPE_p_altos_list; + +class AltosEepromItem extends JPanel implements ActionListener { + AltosEepromLog log; + JCheckBox download; + JCheckBox delete; + JLabel label; + + public void actionPerformed(ActionEvent e) { + System.out.printf("eeprom item action %s %d\n", e.getActionCommand(), e.getID()); + if (e.getSource() == download) { + log.download = download.isSelected(); + System.out.printf("download set to %b\n", log.download); + } else if (e.getSource() == delete) { + log.delete = delete.isSelected(); + System.out.printf("delete set to %b\n", log.delete); + } + } + + public AltosEepromItem(AltosEepromLog in_log) { + log = in_log; + + download = new JCheckBox("Download", log.download); + download.addActionListener(this); + add(download); + delete = new JCheckBox("Delete", log.delete); + delete.addActionListener(this); + add(delete); + label = new JLabel(String.format("Flight %d %4d-%02d-%02d", + log.flight, log.year, log.month, log.day)); + add(label); + } +} + +public class AltosEepromSelect extends JDialog implements ActionListener { + private JList list; + private JFrame frame; + JButton ok; + JButton cancel; + boolean success; + + /* Listen for events from our buttons */ + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + + if (cmd.equals("ok")) + success = true; + setVisible(false); + } + + public boolean run() { + success = false; + setLocationRelativeTo(frame); + setVisible(true); + return success; + } + + public AltosEepromSelect (JFrame in_frame, + AltosEepromList flights) { + + super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true); + frame = in_frame; + + JLabel selectLabel = new JLabel("Select flights to download and/or delete", SwingConstants.CENTER); + + JPanel labelPane = new JPanel(); + labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS)); + labelPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); + labelPane.add(Box.createHorizontalGlue()); + labelPane.add(selectLabel); + labelPane.add(Box.createHorizontalGlue()); + + JPanel flightPane = new JPanel(); + flightPane.setLayout(new BoxLayout(flightPane, BoxLayout.Y_AXIS)); + flightPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); + for (AltosEepromLog flight : flights) { + flightPane.add(new AltosEepromItem(flight)); + } + + ok = new JButton("OK"); + ok.addActionListener(this); + ok.setActionCommand("ok"); + + cancel = new JButton("Cancel"); + cancel.addActionListener(this); + cancel.setActionCommand("cancel"); + + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + buttonPane.add(Box.createHorizontalGlue()); + buttonPane.add(cancel); + buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); + buttonPane.add(ok); + + Container contentPane = getContentPane(); + + contentPane.add(labelPane, BorderLayout.PAGE_START); + contentPane.add(flightPane, BorderLayout.CENTER); + contentPane.add(buttonPane, BorderLayout.PAGE_END); + + pack(); + } +} diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 94c4dd2a..90e3d7f0 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -245,7 +245,7 @@ public class AltosUI extends JFrame { * a TeleDongle over the packet link */ private void SaveFlightData() { - new AltosEepromDownload(AltosUI.this); + new AltosEepromManage(AltosUI.this); } /* Load a flight log file and write out a CSV file containing diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 58d23787..196d7032 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -28,12 +28,15 @@ altosui_JAVA = \ AltosDevice.java \ AltosDisplayThread.java \ AltosEepromBlock.java \ + AltosEepromDelete.java \ AltosEepromDownload.java \ AltosEepromList.java \ AltosEepromLog.java \ + AltosEepromManage.java \ AltosEepromMonitor.java \ AltosEepromIterable.java \ AltosEepromRecord.java \ + AltosEepromSelect.java \ AltosFile.java \ AltosFlash.java \ AltosFlashUI.java \ -- 2.30.2