altosui: Finish device programming code
authorKeith Packard <keithp@keithp.com>
Tue, 24 Aug 2010 05:02:21 +0000 (22:02 -0700)
committerKeith Packard <keithp@keithp.com>
Tue, 24 Aug 2010 05:02:21 +0000 (22:02 -0700)
Altosui can now reprogram Altusmetrum devices.

Signed-off-by: Keith Packard <keithp@keithp.com>
ao-tools/altosui/AltosFlash.java
ao-tools/altosui/AltosFlashUI.java

index bab60c1fbcdd110ce748ae7ecd53ca69cf5b9b26..0f92d6e7bf2ffb82d27fa31aa0fde7cb240e73d5 100644 (file)
@@ -33,17 +33,274 @@ import altosui.AltosHexfile;
 public class AltosFlash {
        File            file;
        FileInputStream input;
-       Thread          thread;
        AltosHexfile    image;
        JFrame          frame;
        AltosDevice     debug_dongle;
        AltosDebug      debug;
        AltosRomconfig  rom_config;
+       ActionListener  listener;
+       boolean         aborted;
+
+       static final byte MOV_direct_data       = (byte) 0x75;
+       static final byte MOV_DPTR_data16       = (byte) 0x90;
+       static final byte MOV_A_data            = (byte) 0x74;
+       static final byte MOVX_atDPTR_A         = (byte) 0xf0;
+       static final byte MOVX_A_atDPTR         = (byte) 0xe0;
+       static final byte INC_DPTR              = (byte) 0xa3;
+       static final byte TRAP                  = (byte) 0xa5;
+
+       static final byte JB                    = (byte) 0x20;
+
+       static final byte MOV_A_direct          = (byte) 0xe5;
+       static final byte MOV_direct1_direct2   = (byte) 0x85;
+       static final byte MOV_direct_A          = (byte) 0xf5;
+       static final byte MOV_R0_data           = (byte) (0x78 | 0);
+       static final byte MOV_R1_data           = (byte) (0x78 | 1);
+       static final byte MOV_R2_data           = (byte) (0x78 | 2);
+       static final byte MOV_R3_data           = (byte) (0x78 | 3);
+       static final byte MOV_R4_data           = (byte) (0x78 | 4);
+       static final byte MOV_R5_data           = (byte) (0x78 | 5);
+       static final byte MOV_R6_data           = (byte) (0x78 | 6);
+       static final byte MOV_R7_data           = (byte) (0x78 | 7);
+       static final byte DJNZ_R0_rel           = (byte) (0xd8 | 0);
+       static final byte DJNZ_R1_rel           = (byte) (0xd8 | 1);
+       static final byte DJNZ_R2_rel           = (byte) (0xd8 | 2);
+       static final byte DJNZ_R3_rel           = (byte) (0xd8 | 3);
+       static final byte DJNZ_R4_rel           = (byte) (0xd8 | 4);
+       static final byte DJNZ_R5_rel           = (byte) (0xd8 | 5);
+       static final byte DJNZ_R6_rel           = (byte) (0xd8 | 6);
+       static final byte DJNZ_R7_rel           = (byte) (0xd8 | 7);
+
+       static final byte P1DIR                 = (byte) 0xFE;
+       static final byte P1                    = (byte) 0x90;
+
+       /* flash controller */
+       static final byte FWT                   = (byte) 0xAB;
+       static final byte FADDRL                = (byte) 0xAC;
+       static final byte FADDRH                = (byte) 0xAD;
+       static final byte FCTL                  = (byte) 0xAE;
+       static final byte FCTL_BUSY             = (byte) 0x80;
+       static final byte FCTL_BUSY_BIT         = (byte) 7;
+       static final byte FCTL_SWBSY            = (byte) 0x40;
+       static final byte FCTL_SWBSY_BIT        = (byte) 6;
+       static final byte FCTL_CONTRD           = (byte) 0x10;
+       static final byte FCTL_WRITE            = (byte) 0x02;
+       static final byte FCTL_ERASE            = (byte) 0x01;
+       static final byte FWDATA                = (byte) 0xAF;
+
+       static final byte ACC                   = (byte) 0xE0;
+
+       /* offsets within the flash_page program */
+       static final int FLASH_ADDR_HIGH        = 8;
+       static final int FLASH_ADDR_LOW         = 11;
+       static final int RAM_ADDR_HIGH          = 13;
+       static final int RAM_ADDR_LOW           = 14;
+       static final int FLASH_WORDS_HIGH       = 16;
+       static final int FLASH_WORDS_LOW        = 18;
+       static final int FLASH_TIMING           = 21;
+
+       /* sleep mode control */
+       static final int SLEEP                  = (byte) 0xbe;
+       static final int  SLEEP_USB_EN          = (byte) 0x80;
+       static final int  SLEEP_XOSC_STB        = (byte) 0x40;
+       static final int  SLEEP_HFRC_STB        = (byte) 0x20;
+       static final int  SLEEP_RST_MASK        = (byte) 0x18;
+       static final int   SLEEP_RST_POWERON    = (byte) 0x00;
+       static final int   SLEEP_RST_EXTERNAL   = (byte) 0x10;
+       static final int   SLEEP_RST_WATCHDOG   = (byte) 0x08;
+       static final int  SLEEP_OSC_PD          = (byte) 0x04;
+       static final int  SLEEP_MODE_MASK       = (byte) 0x03;
+       static final int   SLEEP_MODE_PM0       = (byte) 0x00;
+       static final int   SLEEP_MODE_PM1       = (byte) 0x01;
+       static final int   SLEEP_MODE_PM2       = (byte) 0x02;
+       static final int   SLEEP_MODE_PM3       = (byte) 0x03;
+
+       /* clock controller */
+       static final byte CLKCON                = (byte) 0xC6;
+       static final byte  CLKCON_OSC32K        = (byte) 0x80;
+       static final byte  CLKCON_OSC           = (byte) 0x40;
+       static final byte  CLKCON_TICKSPD       = (byte) 0x38;
+       static final byte  CLKCON_CLKSPD        = (byte) 0x07;
+
+       static final byte[] flash_page_proto = {
+
+               MOV_direct_data, P1DIR, (byte) 0x02,
+               MOV_direct_data, P1,    (byte) 0xFF,
+
+               MOV_direct_data, FADDRH, 0,     /* FLASH_ADDR_HIGH */
+
+               MOV_direct_data, FADDRL, 0,     /* FLASH_ADDR_LOW */
+
+               MOV_DPTR_data16, 0, 0,          /* RAM_ADDR_HIGH, RAM_ADDR_LOW */
+
+               MOV_R7_data, 0,                 /* FLASH_WORDS_HIGH */
+
+               MOV_R6_data, 0,                 /* FLASH_WORDS_LOW */
+
+
+               MOV_direct_data, FWT, 0x20,     /* FLASH_TIMING */
+
+               MOV_direct_data, FCTL, FCTL_ERASE,
+/* eraseWaitLoop: */
+               MOV_A_direct,           FCTL,
+               JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb,
+
+               MOV_direct_data, P1, (byte) 0xfd,
+
+               MOV_direct_data, FCTL, FCTL_WRITE,
+/* writeLoop: */
+               MOV_R5_data, 2,
+/* writeWordLoop: */
+               MOVX_A_atDPTR,
+               INC_DPTR,
+               MOV_direct_A, FWDATA,
+               DJNZ_R5_rel, (byte) 0xfa,               /* writeWordLoop */
+/* writeWaitLoop: */
+               MOV_A_direct, FCTL,
+               JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb,    /* writeWaitLoop */
+               DJNZ_R6_rel, (byte) 0xf1,               /* writeLoop */
+               DJNZ_R7_rel, (byte) 0xef,                       /* writeLoop */
+
+               MOV_direct_data, P1DIR, (byte) 0x00,
+               MOV_direct_data, P1,    (byte) 0xFF,
+               TRAP,
+       };
+
+       public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) {
+               int flash_word_addr = flash_addr >> 1;
+               int flash_word_count = ((byte_count + 1) >> 1);
+
+               byte[] flash_page = new byte[flash_page_proto.length];
+               for (int i = 0; i < flash_page.length; i++)
+                       flash_page[i] = flash_page_proto[i];
+
+               flash_page[FLASH_ADDR_HIGH]  = (byte) (flash_word_addr >> 8);
+               flash_page[FLASH_ADDR_LOW]   = (byte) (flash_word_addr);
+               flash_page[RAM_ADDR_HIGH]    = (byte) (ram_addr >> 8);
+               flash_page[RAM_ADDR_LOW]     = (byte) (ram_addr);
+
+               byte flash_words_low = (byte) (flash_word_count);
+               byte flash_words_high = (byte) (flash_word_count >> 8);
+               /* the flashing code has a minor 'bug' */
+               if (flash_words_low != 0)
+                       flash_words_high++;
+
+               flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high;
+               flash_page[FLASH_WORDS_LOW]  = (byte) flash_words_low;
+               return flash_page;
+       }
+
+       static byte[] set_clkcon_fast = {
+               MOV_direct_data, CLKCON, 0x00
+       };
+
+       static byte[] get_sleep = {
+               MOV_A_direct, SLEEP
+       };
+
+       public void clock_init() throws IOException, InterruptedException {
+               debug.debug_instr(set_clkcon_fast);
+
+               byte    status;
+               do {
+                       status = debug.debug_instr(get_sleep);
+               } while ((status & SLEEP_XOSC_STB) == 0);
+       }
+
+       void action(String s, int percent) {
+               if (listener != null && !aborted)
+                       listener.actionPerformed(new ActionEvent(this,
+                                                                percent,
+                                                                s));
+       }
+
+       void action(int part, int total) {
+               int percent = 100 * part / total;
+               action(String.format("%d/%d (%d%%)",
+                                    part, total, percent),
+                      percent);
+       }
 
        public void flash() throws IOException, FileNotFoundException, InterruptedException {
                if (!check_rom_config())
                        throw new IOException("Invalid rom config settings");
+               if (image.address + image.data.length > 0x8000)
+                       throw new IOException(String.format("Flash image too long %d",
+                                                           image.address +
+                                                           image.data.length));
+               if ((image.address & 0x3ff) != 0)
+                       throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)",
+                                                           image.address));
+               int ram_address = 0xf000;
+               int flash_prog = 0xf400;
+
+               /*
+                * Store desired config values into image
+                */
                rom_config.write(image);
+               /*
+                * Bring up the clock
+                */
+               clock_init();
+
+               int remain = image.data.length;
+               int flash_addr = image.address;
+               int image_start = 0;
+
+               action(0, image.data.length);
+               while (remain > 0 && !aborted) {
+                       int this_time = remain;
+                       if (this_time > 0x400)
+                               this_time = 0x400;
+
+                       /* write the data */
+                       debug.write_memory(ram_address, image.data,
+                                          image_start, this_time);
+
+                       /* write the flash program */
+                       byte[] flash_page = make_flash_page(flash_addr,
+                                                           ram_address,
+                                                           this_time);
+                       debug.write_memory(flash_prog, flash_page);
+
+                       debug.set_pc(flash_prog);
+                       int pc = debug.get_pc();
+                       debug.resume();
+                       Thread.sleep(100);
+                       for (int times = 0; times < 10; times++) {
+                               byte status = debug.read_status();
+                               if ((status & AltosDebug.STATUS_CPU_HALTED) != 0)
+                                       break;
+                               Thread.sleep(100);
+                       }
+
+                       byte[] check = debug.read_memory(flash_addr, this_time);
+                       for (int i = 0; i < this_time; i++)
+                               if (check[i] != image.data[image_start + i])
+                                       throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
+                                                                           image.address + image_start + i,
+                                                                           check[i], image.data[image_start + i]));
+                       remain -= this_time;
+                       flash_addr += this_time;
+                       image_start += this_time;
+
+                       action(image.data.length - remain, image.data.length);
+               }
+               if (!aborted) {
+                       action("done", 100);
+                       debug.set_pc(image.address);
+                       debug.resume();
+               }
+               debug.close();
+       }
+
+       public void abort() {
+               aborted = true;
+               debug.close();
+       }
+
+       public void addActionListener(ActionListener l) {
+               listener = l;
        }
 
        public boolean check_rom_config() {
@@ -56,6 +313,10 @@ public class AltosFlash {
                rom_config = romconfig;
        }
 
+       public AltosRomconfig romconfig() {
+               return rom_config;
+       }
+
        public void open() throws IOException, FileNotFoundException, InterruptedException {
                input = new FileInputStream(file);
                image = new AltosHexfile(input);
index 5cae475641129315daea9d54e881cfb4ff36e282..0c2041e3cf338f9a8fbdf7adf3125549aaef13aa 100644 (file)
@@ -31,15 +31,43 @@ import java.util.concurrent.LinkedBlockingQueue;
 import altosui.AltosHexfile;
 import altosui.AltosFlash;
 
-public class AltosFlashUI implements Runnable {
+public class AltosFlashUI
+       extends JDialog
+       implements Runnable, ActionListener
+{
+       Container       pane;
+       Box             box;
+       JLabel          serial_label;
+       JLabel          serial_value;
+       JLabel          file_label;
+       JLabel          file_value;
+       JProgressBar    pbar;
+       JButton         cancel;
+
        File            file;
        Thread          thread;
        JFrame          frame;
        AltosDevice     debug_dongle;
        AltosFlash      flash;
 
+       public void actionPerformed(ActionEvent e) {
+               if (e.getSource() == cancel) {
+                       abort();
+                       dispose();
+               } else {
+                       String  cmd = e.getActionCommand();
+                       if (cmd.equals("done"))
+                               dispose();
+                       else {
+                               pbar.setValue(e.getID());
+                               pbar.setString(cmd);
+                       }
+               }
+       }
+
        public void run() {
                flash = new AltosFlash(file, debug_dongle);
+               flash.addActionListener(this);
                try {
                        flash.open();
                        if (!flash.check_rom_config()) {
@@ -50,6 +78,10 @@ public class AltosFlashUI implements Runnable {
                                        return;
                                flash.set_romconfig(romconfig);
                        }
+                       serial_value.setText(String.format("%d",
+                                                          flash.romconfig().serial_number));
+                       file_value.setText(file.toString());
+                       setVisible(true);
                        flash.flash();
                } catch (FileNotFoundException ee) {
                        JOptionPane.showMessageDialog(frame,
@@ -67,9 +99,90 @@ public class AltosFlashUI implements Runnable {
                }
        }
 
+       public void abort() {
+               if (flash != null)
+                       flash.abort();
+       }
+
+       public void build_dialog() {
+               GridBagConstraints c;
+               Insets il = new Insets(4,4,4,4);
+               Insets ir = new Insets(4,4,4,4);
+
+               pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 0;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               serial_label = new JLabel("Serial:");
+               pane.add(serial_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 0;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               serial_value = new JLabel("");
+               pane.add(serial_value, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.gridx = 0; c.gridy = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               file_label = new JLabel("File:");
+               pane.add(file_label, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.gridx = 1; c.gridy = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               file_value = new JLabel("");
+               pane.add(file_value, c);
+
+               pbar = new JProgressBar();
+               pbar.setMinimum(0);
+               pbar.setMaximum(100);
+               pbar.setValue(0);
+               pbar.setString("");
+               pbar.setStringPainted(true);
+               pbar.setPreferredSize(new Dimension(600, 20));
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0; c.gridy = 2;
+               c.gridwidth = GridBagConstraints.REMAINDER;
+               Insets ib = new Insets(4,4,4,4);
+               c.insets = ib;
+               pane.add(pbar, c);
+
+               cancel = new JButton("Cancel");
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0; c.gridy = 3;
+               c.gridwidth = GridBagConstraints.REMAINDER;
+               Insets ic = new Insets(4,4,4,4);
+               c.insets = ic;
+               pane.add(cancel, c);
+               cancel.addActionListener(this);
+               pack();
+               setLocationRelativeTo(frame);
+       }
+
        public AltosFlashUI(JFrame in_frame) {
+               super(in_frame, "Program Altusmetrum Device", false);
+
                frame = in_frame;
 
+               build_dialog();
+
                debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.Any);
 
                if (debug_dongle == null)