*
* 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.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altosuilib_11;
+package org.altusmetrum.altosuilib_14;
import java.awt.*;
import java.awt.event.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.io.*;
import java.util.concurrent.*;
-import org.altusmetrum.altoslib_11.*;
+import org.altusmetrum.altoslib_14.*;
public class AltosFlashUI
extends AltosUIDialog
File file;
// Debug connection
- AltosDevice device;
+ AltosUSBDevice device;
AltosLink link;
"teleballoon",
"telebt-v1",
"teledongle-v0",
- "telefire",
+ "telefire-v0",
"telemetrum-v0",
"telemetrum-v1",
- "telemini",
+ "telemini-v1",
"telenano",
- "teleshield",
- "teleterra"
+ "teleshield"
};
private static final String[] pair_programmed_devices = {
"TeleBalloon",
"TeleBT-v1",
"TeleDongle-v0",
+ "TeleFire-v0",
"TeleFire",
"TeleMetrum-v0",
"TeleMetrum-v1",
- "TeleMini",
+ "TeleMini-v1",
"TeleNano",
- "TeleShield",
- "TeleTerra"
+ "TeleShield"
+ };
+
+ private static final String[] log_erased_devices = {
+ "TeleGPS"
};
private boolean is_pair_programmed() {
return false;
}
+ private boolean is_log_erased() {
+ if (device != null) {
+ String name = device.toString();
+ for (int i = 0; i < log_erased_devices.length; i++) {
+ if (name.startsWith(log_erased_devices[i]))
+ return true;
+ }
+ }
+ return false;
+ }
+
public void actionPerformed(ActionEvent e) {
if (e.getSource() == cancel) {
if (programmer != null)
JOptionPane.ERROR_MESSAGE);
setVisible(false);
dispose();
- } else if (cmd.equals("done")) {
+ } else if (cmd.equals(AltosFlashListener.flash_done)) {
setVisible(false);
dispose();
- } else if (cmd.equals("start")) {
+ } else if (cmd.equals(AltosFlashListener.flash_start)) {
setVisible(true);
} else {
pbar.setValue(e.getID());
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
c = new GridBagConstraints();
}
static class AltosHexfileFilter extends javax.swing.filechooser.FileFilter {
- int product;
String head;
String description;
- public AltosHexfileFilter(int product, String head, String description) {
- this.product = product;
- this.head = head;
- this.description = description;
+ public AltosHexfileFilter(String usb_product) {
+ int l;
+ int dash;
+
+ /* Trim off any trailing variants (1.0a vs 1.0) */
+ for (dash = usb_product.length(); dash > 0; dash--) {
+ char c = usb_product.charAt(dash-1);
+ if (c == '-')
+ break;
+ }
+ if (dash == 0)
+ dash = usb_product.length();
+
+ for (l = usb_product.length(); l > dash; l--) {
+ char c = usb_product.charAt(l-1);
+ if (c < 'a' || 'z' < c)
+ break;
+ }
+ head = usb_product.substring(0, l).toLowerCase();
+ description = String.format("%s Image File", usb_product);
}
public boolean accept(File file) {
}
}
- static AltosHexfileFilter[] filters = {
- new AltosHexfileFilter(AltosLib.product_telemetrum, "telemetrum", "TeleMetrum Image"),
- new AltosHexfileFilter(AltosLib.product_teledongle, "teledongle", "TeleDongle Image"),
- new AltosHexfileFilter(AltosLib.product_telemega, "telemega", "TeleMega Image"),
- new AltosHexfileFilter(AltosLib.product_easymini, "easymini", "EasyMini Image"),
- new AltosHexfileFilter(AltosLib.product_easymega, "easymega", "EasyMega Image"),
- };
-
boolean select_source_file() {
JFileChooser hexfile_chooser = new JFileChooser();
hexfile_chooser.setDialogTitle("Select Flash Image");
- for (int i = 0; i < filters.length; i++) {
- hexfile_chooser.addChoosableFileFilter(filters[i]);
- }
javax.swing.filechooser.FileFilter ihx_filter = new FileNameExtensionFilter("Flash Image", "ihx");
hexfile_chooser.addChoosableFileFilter(ihx_filter);
hexfile_chooser.setFileFilter(ihx_filter);
if (!is_pair_programmed() && !device.matchProduct(AltosLib.product_altusmetrum)) {
- for (int i = 0; i < filters.length; i++) {
- if (device != null && device.matchProduct(filters[i].product))
- hexfile_chooser.setFileFilter(filters[i]);
- }
+ AltosHexfileFilter filter = new AltosHexfileFilter(device.usb_product());
+ hexfile_chooser.addChoosableFileFilter(filter);
+ hexfile_chooser.setFileFilter(filter);
}
int returnVal = hexfile_chooser.showOpenDialog(frame);
boolean select_device() {
int product = AltosLib.product_any;
- device = AltosDeviceUIDialog.show(frame, AltosLib.product_any);
+ device = AltosDeviceUIDialog.show_usb(frame, AltosLib.product_any);
if (device == null)
return false;
return true;
}
- boolean update_rom_config_info(AltosRomconfig existing_config) {
+ boolean rom_config_matches (AltosRomconfig a, AltosRomconfig b) {
+ if (a == null || b == null)
+ return (a == null && b == null);
+
+ if (!a.valid || !b.valid)
+ return false;
+
+ if (a.usb_id != null && b.usb_id != null &&
+ (a.usb_id.vid != b.usb_id.vid ||
+ a.usb_id.pid != b.usb_id.pid))
+ return false;
+
+ if (a.usb_product != null && b.usb_product != null &&
+ !a.usb_product.equals(b.usb_product))
+ return false;
+
+ return true;
+ }
+
+ boolean update_rom_config_info(AltosRomconfig existing_config, AltosRomconfig image_config) {
AltosRomconfig new_config;
+
+ if (!rom_config_matches(existing_config, image_config)) {
+ int ret;
+ if (existing_config == null || !existing_config.valid) {
+ ret = JOptionPane.showConfirmDialog(this,
+ String.format("Cannot determine target device type\nImage is %04x:%04x %s\nFlash anyways?",
+ image_config.usb_id.vid,
+ image_config.usb_id.pid,
+ image_config.usb_product),
+ "Unknown Target Device",
+ JOptionPane.YES_NO_OPTION);
+ } else {
+ ret = JOptionPane.showConfirmDialog(this,
+ String.format("Device is %04x:%04x %s\nImage is %04x:%04x %s\nFlash anyways?",
+ existing_config.usb_id.vid,
+ existing_config.usb_id.pid,
+ existing_config.usb_product,
+ image_config.usb_id.vid,
+ image_config.usb_id.pid,
+ image_config.usb_product),
+ "Image doesn't match Device",
+ JOptionPane.YES_NO_OPTION);
+ }
+ if (ret != JOptionPane.YES_OPTION)
+ return false;
+ }
+
+ if (existing_config != null && existing_config.radio_calibration_broken) {
+ int ret = JOptionPane.showConfirmDialog(this,
+ String.format("Radio calibration value %d may be incorrect\nFlash anyways?",
+ existing_config.radio_calibration),
+ "Radio Calibration Invalid",
+ JOptionPane.YES_NO_OPTION);
+ if (ret != JOptionPane.YES_OPTION)
+ return false;
+ }
+
+
new_config = AltosRomconfigUI.show(frame, existing_config);
if (new_config == null)
return false;
device.toShortString()),
"Device in use",
JOptionPane.ERROR_MESSAGE);
- } else if (e instanceof IOException) {
+ } else {
JOptionPane.showMessageDialog(frame,
e.getMessage(),
file.toString(),
else
programmer = new AltosSelfFlash(ui.file, link, this);
- final AltosRomconfig current_config = programmer.romconfig();
+ final AltosRomconfig current_config = programmer.target_romconfig(device.usb_id(), device.usb_product());
+
+ final AltosRomconfig image_config = programmer.image_romconfig();
+
+ System.out.printf("product %s current %s image %s\n", device.usb_product(), current_config, image_config);
final Semaphore await_rom_config = new Semaphore(0);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ui.programmer = programmer;
- ui.update_rom_config_info(current_config);
+ ui.update_rom_config_info(current_config, image_config);
await_rom_config.release();
}
});
flash_task flasher;
- private boolean open_device() throws InterruptedException {
- try {
- link = new AltosSerial(device);
- if (is_pair_programmed())
- return true;
+ boolean erase_answer;
- if (link == null)
- throw new IOException(String.format("%s: open failed", device.toShortString()));
+ class open_task implements Runnable {
+ AltosDevice device;
+ Thread t;
+ open_dialog dialog;
+ AltosLink link;
+
+ public void do_exception(final Exception e) {
+ if (link != null) {
+ try {
+ link.close();
+ } catch (Exception ex) {}
+ }
+ SwingUtilities.invokeLater(
+ new Runnable() {
+ public void run() {
+ try { dialog.open_exception(e); } catch (Exception ex) { }
+ }
+ });
+ }
- while (!link.is_loader()) {
- link.to_loader();
+ public void do_success(final AltosLink link) {
+ SwingUtilities.invokeLater(
+ new Runnable() {
+ public void run() {
+ try { dialog.open_success(link); } catch (Exception ex) { }
+ }
+ });
+ }
- java.util.List<AltosDevice> devices = null;
+ public boolean do_notify_erase(final AltosConfigData config_data) {
+ erase_answer = false;
+ final Semaphore erase_answer_done = new Semaphore(0);
+ SwingUtilities.invokeLater(
+ new Runnable() {
+ public void run() {
+ int ret = JOptionPane.showConfirmDialog(dialog.owner,
+ String.format("Updating %s from firmware %s will erase stored data, continue?",
+ config_data.product,
+ config_data.version),
+ "Erase Stored Data?",
+ JOptionPane.YES_NO_OPTION);
+ erase_answer = ret == JOptionPane.YES_OPTION;
+ erase_answer_done.release();
+ }
+ });
+ try {
+ erase_answer_done.acquire();
+ } catch (Exception ex) {
+ return false;
+ }
+ return erase_answer;
+ }
- for (int tries = 0; tries < 10; tries++) {
- Thread.sleep(100);
- devices = AltosUSBDevice.list(AltosLib.product_altusmetrum);
- if (devices.size() != 0)
- break;
- }
+ public void run () {
+ link = null;
+ try {
+ boolean new_device = false;
- if (devices.size() == 1)
- device = devices.get(0);
- else {
- device = AltosDeviceUIDialog.show(frame, AltosLib.product_altusmetrum);
- if (device == null)
- return false;
+ for (;;) {
+ System.out.printf("Attempting to open %s\n", device.toShortString());
+
+ for (int i = 0; i < 20; i++) {
+ link = new AltosSerial(device);
+
+ if (link != null)
+ break;
+
+ if (!new_device)
+ break;
+
+ System.out.printf("Waiting for device to become ready\n");
+
+ Thread.sleep(1000);
+ }
+ if (link == null)
+ throw new IOException(String.format("%s: open failed",
+ device.toShortString()));
+
+ System.out.printf("Checking device ready\n");
+
+ /* See if the link is usable already */
+ if (is_pair_programmed() || link.is_loader()) {
+ System.out.printf("Device ready for use\n");
+ do_success(link);
+ return;
+ }
+
+ System.out.printf("Checking log erased\n");
+
+ if (is_log_erased()) {
+ System.out.printf("Fetching config data\n");
+ AltosConfigData config_data = link.config_data();
+ System.out.printf("version %s\n", config_data.version);
+ /* Completely erase TeleGPS flash when firmware is old */
+ if (config_data.compare_version("1.9.7") < 0)
+ {
+ if (!do_notify_erase(config_data))
+ throw new IOException(String.format("%s: not erasing log",
+ device.toShortString()));
+ System.out.printf("Erasing log\n");
+ link.printf("Z DoIt\n");
+ link.synchronize(120 * 1000);
+ }
+ }
+
+ java.util.List<AltosDevice> prev_devices =
+ AltosUSBDevice.list(AltosLib.product_altusmetrum);
+
+ /* Nope, switch to loader and
+ * wait for it to re-appear
+ */
+
+ System.out.printf("Switch to loader\n");
+
+ link.to_loader();
+
+ /* This is a bit fragile, but
+ * I'm not sure what else to
+ * do other than ask the user.
+ *
+ * Search for a device which
+ * wasn't there before we
+ * asked the target to switch
+ * to loader mode
+ */
+
+ device = null;
+ for (;;) {
+ Thread.sleep(100);
+ java.util.List<AltosDevice> devices =
+ AltosUSBDevice.list(AltosLib.product_altusmetrum);
+
+ for (AltosDevice d : devices) {
+ boolean matched = false;
+ System.out.printf("\tfound device %s\n", d.toShortString());
+ for (AltosDevice p : prev_devices)
+ if (d.equals(p)) {
+ matched = true;
+ break;
+ }
+ if (!matched) {
+ System.out.printf("Identified new device %s\n", d.toShortString());
+ device = (AltosUSBDevice) d;
+ new_device = true;
+ break;
+ }
+ }
+ if (device != null)
+ break;
+ }
}
- link = new AltosSerial(device);
+ } catch (AltosSerialInUseException ee) {
+ do_exception(ee);
+ } catch (FileNotFoundException fe) {
+ do_exception(fe);
+ } catch (IOException ie) {
+ do_exception (ie);
+ } catch (TimeoutException te) {
+ do_exception (te);
+ } catch (InterruptedException ie) {
+ do_exception (ie);
}
- return true;
- } catch (AltosSerialInUseException ee) {
- exception(ee);
- } catch (FileNotFoundException fe) {
- exception(fe);
- } catch (IOException ie) {
- exception (ie);
}
- return false;
+
+ public void cancel() {
+ t.interrupt();
+ }
+
+ public open_task(AltosDevice device, open_dialog dialog) {
+ this.device = device;
+ this.dialog = dialog;
+ t = new Thread(this);
+ t.start();
+ }
+ }
+
+ class open_dialog
+ extends AltosUIDialog
+ implements ActionListener
+ {
+ AltosUIFrame owner;
+
+ private JLabel opening_label;
+ private JButton cancel_button;
+
+ boolean done = false;
+
+ AltosLink link = null;
+
+ open_task open = null;
+
+ public void open_exception(Exception e) {
+ System.out.printf("open_exception\n");
+ setVisible(false);
+ exception(e);
+ done = true;
+ }
+
+ public void open_success(AltosLink link) {
+ System.out.printf("open_success\n");
+ setVisible(false);
+ this.link = link;
+ done = true;
+ }
+
+ public AltosLink do_open(open_task open) throws InterruptedException {
+ this.open = open;
+ setVisible(true);
+ return link;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+
+ if (cmd.equals("cancel"))
+ if (open != null)
+ open.cancel();
+ done = true;
+ setVisible(false);
+ }
+
+ public open_dialog(AltosUIFrame in_owner) {
+ super(in_owner, "Open Flash Target Device", true);
+ owner = in_owner;
+
+ Container pane = getScrollablePane();
+ GridBagConstraints c = new GridBagConstraints();
+ Insets i = new Insets(4,4,4,4);
+
+
+ pane.setLayout(new GridBagLayout());
+
+ opening_label = new JLabel("Opening Device");
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = i;
+ c.weightx = 0;
+ c.weighty = 0;
+
+ c.gridx = 0;
+ c.gridy = 0;
+
+ pane.add(opening_label, c);
+
+ cancel_button = new JButton("Cancel");
+ cancel_button.addActionListener(this);
+ cancel_button.setActionCommand("cancel");
+
+ c.gridy = 1;
+ pane.add(cancel_button, c);
+ pack();
+ setLocationRelativeTo(owner);
+ }
+ }
+
+ private boolean open_device() throws InterruptedException {
+
+ open_dialog dialog = new open_dialog(frame);
+
+ open_task open = new open_task(device, dialog);
+
+ link = dialog.do_open(open);
+
+ return link != null;
}
/*