altoslib: Add self-flashing code
authorKeith Packard <keithp@keithp.com>
Mon, 9 Dec 2013 04:09:10 +0000 (20:09 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 9 Dec 2013 04:09:10 +0000 (20:09 -0800)
This adds the ability to use the AltOS flash-loader on both STM and
NXP processors.

Signed-off-by: Keith Packard <keithp@keithp.com>
altoslib/AltosSelfFlash.java
altoslib/Makefile.am
altosui/AltosFlashUI.java

index 0ae797a0877f2afb16613d58a81c8244d8bb13fd..07952d7f76fc97ba61519a4a55ef79ce6a91183a 100644 (file)
@@ -19,14 +19,14 @@ package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 
-public class AltosSelfFlash {
+public class AltosSelfFlash extends AltosProgrammer {
        File                    file;
        FileInputStream         input;
        AltosHexfile            image;
        AltosLink               link;
        boolean                 aborted;
        AltosFlashListener      listener;
-       byte[]                  read_block, write_block;
+       AltosRomconfig          rom_config;
 
        void action(String s, int percent) {
                if (listener != null && !aborted)
@@ -40,23 +40,49 @@ public class AltosSelfFlash {
                       percent);
        }
 
-       void read_block(long addr) {
-               link.printf("R %x\n", addr);
-               
-       }
-
-       void read_memory(long addr, int len) {
+       byte[] read_memory(long addr, int len) throws InterruptedException, IOException {
+               int b;
+               byte[]  data = new byte[len];
+
+               for (int offset = 0; offset < len; offset += 0x100) {
+                       link.printf("R %x\n", addr + offset);
+                       byte[]  reply = link.get_binary_reply(5000, 0x100);
+                       
+                       if (reply == null)
+                               throw new IOException("Read device memory timeout");
+                       for (b = 0; b < len; b++)
+                               data[b+offset] = reply[b];
+               }
+               return data;
        }
                
        void write_memory(long addr, byte[] data, int start, int len) {
-               
+               int b;
+               System.out.printf ("write_memory %x %d\n", addr, len);
+               link.printf("W %x\n", addr);
+               link.flush_output();
+               for (b = 0; b < len; b++)
+                       link.putchar(data[start + b]);
+               for (; b < 0x100; b++)
+                       link.putchar((byte) 0xff);
        }
 
        void reboot() {
+               System.out.printf("reboot\n");
+               link.printf("a\n");
+               link.flush_output();
        }
 
        public void flash() {
                try {
+                       if (!check_rom_config())
+                               throw new IOException("Invalid rom config settings");
+
+                       /*
+                        * Store desired config values into image
+                        */
+                       rom_config.write(image);
+
                        int remain = image.data.length;
                        long flash_addr = image.address;
                        int image_start = 0;
@@ -89,13 +115,10 @@ public class AltosSelfFlash {
                                action(image.data.length - remain, image.data.length);
                        }
                        if (!aborted) {
+                               System.out.printf ("done\n");
                                action("done", 100);
-                               if (link != null) {
-                                       reboot();
-                               }
                        }
-                       if (link != null)
-                               link.close();
+                       close();
                } catch (IOException ie) {
                        action(ie.getMessage(), -1);
                        abort();
@@ -105,8 +128,11 @@ public class AltosSelfFlash {
        }
 
        public void close() {
-               if (link != null)
+               if (link != null) {
+                       reboot();
                        link.close();
+                       link = null;
+               }
        }
 
        synchronized public void abort() {
@@ -114,11 +140,36 @@ public class AltosSelfFlash {
                close();
        }
 
+       private AltosHexfile get_rom() {
+               System.out.printf("get rom\n");
+               try {
+                       int base = AltosRomconfig.fetch_base(image);
+                       int bounds = AltosRomconfig.fetch_bounds(image);
+                       byte[] data = read_memory(base, bounds - base);
+                       AltosHexfile hexfile = new AltosHexfile(data, base);
+                       hexfile.add_symbols(image);
+                       return hexfile;
+               } catch (AltosNoSymbol none) {
+                       System.out.printf("no symbol %s\n", none.getMessage());
+                       return null;
+               } catch (InterruptedException ie) {
+                       return null;
+               } catch (IOException ie) {
+                       return null;
+               }
+
+       }
+
        public boolean check_rom_config() {
-               if (link == null)
+               if (link == null) {
+                       System.out.printf ("no link\n");
                        return true;
-               if (rom_config == null)
-                       rom_config = debug.romconfig();
+               }
+               if (rom_config == null) {
+                       AltosHexfile hexfile = get_rom();
+                       if (hexfile != null)
+                               rom_config = new AltosRomconfig(hexfile);
+               }
                return rom_config != null && rom_config.valid();
        }
 
@@ -127,23 +178,19 @@ public class AltosSelfFlash {
        }
 
        public AltosRomconfig romconfig() {
+               System.out.printf("fetch romconfig\n");
                if (!check_rom_config())
                        return null;
                return rom_config;
        }
 
-       public AltosFlash(File file, AltosLink link, AltosFlashListener listener)
+       public AltosSelfFlash(File file, AltosLink link, AltosFlashListener listener)
                throws IOException, FileNotFoundException, InterruptedException {
                this.file = file;
                this.link = link;
                this.listener = listener;
-               this.read_block = new byte[256];
-               this.write_block = new byte[256];
                input = new FileInputStream(file);
                image = new AltosHexfile(input);
-               if (link != null) {
-                       debug.close();
-                       throw new IOException("Debug port not connected");
-               }
+               System.out.printf ("AltosSelfFlash %x\n", image.address);
        }
 }
\ No newline at end of file
index 919d098fed70c2658ae6c63d6e8c61066f4c723d..2c26220bd2ee1d821c62d3e4147a7f22b9c27f31 100644 (file)
@@ -76,6 +76,7 @@ altoslib_JAVA = \
        AltosProgrammer.java \
        AltosReplayReader.java \
        AltosRomconfig.java \
+       AltosSelfFlash.java \
        AltosSensorMM.java \
        AltosSensorEMini.java \
        AltosSensorTM.java \
index 6eccface19815f29c00a2ef4ddd366d3545aee0e..7e4cddb12dd0b1cd31b42082b08467cd1c76cb2a 100644 (file)
@@ -45,18 +45,42 @@ public class AltosFlashUI
        File            file;
 
        // Debug connection
-       AltosDevice     debug_dongle;
+       AltosDevice     device;
+
+       AltosLink       link;
 
        // Desired Rom configuration
        AltosRomconfig  rom_config;
 
        // Flash controller
-       AltosFlash      flash;
+       AltosProgrammer programmer;
+
+       private static String[] pair_programmed = {
+               "teleballoon",
+               "telebt",
+               "teledongle",
+               "telefire",
+               "telemetrum-v0",
+               "telemetrum-v1",
+               "telemini",
+               "telenano",
+               "teleshield",
+               "teleterra"
+       };
+
+       private boolean is_pair_programmed() {
+               String  name = file.getName();
+               for (int i = 0; i < pair_programmed.length; i++) {
+                       if (name.startsWith(pair_programmed[i]))
+                               return true;
+               }
+               return false;
+       }
 
        public void actionPerformed(ActionEvent e) {
                if (e.getSource() == cancel) {
-                       if (flash != null)
-                               flash.abort();
+                       if (programmer != null)
+                               programmer.abort();
                        setVisible(false);
                        dispose();
                } else {
@@ -156,6 +180,33 @@ public class AltosFlashUI
                serial_value.setText(String.format("%d", serial_number));
        }
 
+       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 boolean accept(File file) {
+                       return file.getName().startsWith(head) && file.getName().endsWith(".ihx");
+               }
+
+               public String getDescription() {
+                       return description;
+               }
+       }
+
+       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"),
+       };
+
        boolean select_source_file() {
                JFileChooser    hexfile_chooser = new JFileChooser();
 
@@ -164,7 +215,24 @@ public class AltosFlashUI
                        hexfile_chooser.setCurrentDirectory(firmwaredir);
 
                hexfile_chooser.setDialogTitle("Select Flash Image");
-               hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx"));
+
+               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 (!device.matchProduct(AltosLib.product_altusmetrum)) {
+                       for (int i = 0; i < filters.length; i++) {
+                               System.out.printf ("device %s filter %d\n", device, filters[i].product);
+                               if (device != null && device.matchProduct(filters[i].product)) {
+                                       System.out.printf ("select filter %s\n", filters[i].head);
+                                       hexfile_chooser.setFileFilter(filters[i]);
+                               }
+                       }
+               }
+
                int returnVal = hexfile_chooser.showOpenDialog(frame);
 
                if (returnVal != JFileChooser.APPROVE_OPTION)
@@ -173,13 +241,16 @@ public class AltosFlashUI
                if (file == null)
                        return false;
                AltosUIPreferences.set_firmwaredir(file.getParentFile());
+               
                return true;
        }
 
-       boolean select_debug_dongle() {
-               debug_dongle = AltosDeviceUIDialog.show(frame, Altos.product_any);
+       boolean select_device() {
+               int     product = Altos.product_any;
 
-               if (debug_dongle == null)
+               device = AltosDeviceUIDialog.show(frame, Altos.product_any);
+
+               if (device == null)
                        return false;
                return true;
        }
@@ -204,7 +275,7 @@ public class AltosFlashUI
                } else if (e instanceof AltosSerialInUseException) {
                        JOptionPane.showMessageDialog(frame,
                                                      String.format("Device \"%s\" already in use",
-                                                                   debug_dongle.toShortString()),
+                                                                   device.toShortString()),
                                                      "Device in use",
                                                      JOptionPane.ERROR_MESSAGE);
                } else if (e instanceof IOException) {
@@ -218,7 +289,7 @@ public class AltosFlashUI
        class flash_task implements Runnable, AltosFlashListener {
                AltosFlashUI    ui;
                Thread          t;
-               AltosFlash      flash;
+               AltosProgrammer programmer;
 
                public void position(String in_s, int in_percent) {
                        final String s = in_s;
@@ -238,14 +309,17 @@ public class AltosFlashUI
 
                public void run () {
                        try {
-                               flash = new AltosFlash(ui.file, new AltosSerial(ui.debug_dongle), this);
+                               if (ui.is_pair_programmed())
+                                       programmer = new AltosFlash(ui.file, link, this);
+                               else
+                                       programmer = new AltosSelfFlash(ui.file, link, this);
 
-                               final AltosRomconfig    current_config = flash.romconfig();
+                               final AltosRomconfig    current_config = programmer.romconfig();
 
                                final Semaphore await_rom_config = new Semaphore(0);
                                SwingUtilities.invokeLater(new Runnable() {
                                                public void run() {
-                                                       ui.flash = flash;
+                                                       ui.programmer = programmer;
                                                        ui.update_rom_config_info(current_config);
                                                        await_rom_config.release();
                                                }
@@ -253,8 +327,8 @@ public class AltosFlashUI
                                await_rom_config.acquire();
 
                                if (ui.rom_config != null) {
-                                       flash.set_romconfig(ui.rom_config);
-                                       flash.flash();
+                                       programmer.set_romconfig(ui.rom_config);
+                                       programmer.flash();
                                }
                        } catch (InterruptedException ee) {
                                final Exception e = ee;
@@ -270,16 +344,9 @@ public class AltosFlashUI
                                                        ui.exception(e);
                                                }
                                        });
-                       } catch (AltosSerialInUseException ee) {
-                               final Exception e = ee;
-                               SwingUtilities.invokeLater(new Runnable() {
-                                               public void run() {
-                                                       ui.exception(e);
-                                               }
-                                       });
                        } finally {
-                               if (flash != null)
-                                       flash.close();
+                               if (programmer != null)
+                                       programmer.close();
                        }
                }
 
@@ -292,16 +359,51 @@ public class AltosFlashUI
 
        flash_task      flasher;
 
+       private boolean open_device() {
+               try {
+                       link = new AltosSerial(device);
+                       if (is_pair_programmed())
+                               return true;
+
+                       if (link == null)
+                               throw new IOException(String.format("%s: open failed", device.toShortString()));
+
+                       while (!link.is_loader()) {
+                               link.to_loader();
+
+                               java.util.List<AltosDevice> devices = AltosUSBDevice.list(AltosLib.product_altusmetrum);
+                               if (devices.size() == 1)
+                                       device = devices.get(0);
+                               else {
+                                       device = AltosDeviceUIDialog.show(frame, AltosLib.product_altusmetrum);
+                                       if (device == null)
+                                               return false;
+                               }
+                               link = new AltosSerial(device);
+                       }
+                       return true;
+               } catch (AltosSerialInUseException ee) {
+                       exception(ee);
+               } catch (FileNotFoundException fe) {
+                       exception(fe);
+               } catch (IOException ie) {
+                       exception (ie);
+               }
+               return false;
+       }
+
        /*
         * Execute the steps for flashing
         * a device. Note that this returns immediately;
         * this dialog is not modal
         */
        void showDialog() {
-               if (!select_debug_dongle())
+               if (!select_device())
                        return;
                if (!select_source_file())
                        return;
+               if (!open_device())
+                       return;
                build_dialog();
                flash_task      f = new flash_task(this);
        }