altoslib: Reduce debug printf spamming during flashing operation
[fw/altos] / altoslib / AltosHexfile.java
index 90352927433f219e1a79c359554c84b2e40009d7..609d1bcb366f9f3ae747633f1f0a51e8894d04ad 100644 (file)
@@ -3,7 +3,8 @@
  *
  * 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
@@ -15,7 +16,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_2;
+package org.altusmetrum.altoslib_13;
 
 import java.io.*;
 import java.util.LinkedList;
@@ -45,7 +46,7 @@ class HexFileInputStream extends PushbackInputStream {
 }
 
 class HexRecord implements Comparable<Object> {
-       public int      address;
+       public long     address;
        public int      type;
        public byte     checksum;
        public byte[]   data;
@@ -109,30 +110,39 @@ class HexRecord implements Comparable<Object> {
 
        public int compareTo(Object other) {
                HexRecord       o = (HexRecord) other;
-               return address - o.address;
+
+               long diff = address - o.address;
+
+               if (diff > 0)
+                       return 1;
+               if (diff < 0)
+                       return -1;
+               return 0;
        }
 
        public String toString() {
                return String.format("%04x: %02x (%d)", address, type, data.length);
        }
 
-       public HexRecord(HexFileInputStream input) throws IOException {
+       public HexRecord(HexFileInputStream input) throws IOException, EOFException {
                read_state      state = read_state.marker;
-               int             nhexbytes = 0;
-               int             hex = 0;
+               long            nhexbytes = 0;
+               long            hex = 0;
                int             ndata = 0;
                byte            got_checksum;
 
                while (state != read_state.done) {
                        int c = input.read();
-                       if (c < 0 && state != read_state.white)
+                       if (c < 0 && state != read_state.white && state != read_state.marker)
                                throw new IOException(String.format("%d: Unexpected EOF", input.line));
                        if (c == ' ')
                                continue;
                        switch (state) {
                        case marker:
+                               if (c == EOF || c == -1)
+                                       throw new EOFException();
                                if (c != ':')
-                                       throw new IOException("Missing ':'");
+                                       throw new IOException(String.format ("Missing ':' (got %x)", c));
                                state = read_state.length;
                                nhexbytes = 2;
                                hex = 0;
@@ -151,7 +161,7 @@ class HexRecord implements Comparable<Object> {
 
                                switch (state) {
                                case length:
-                                       data = new byte[hex];
+                                       data = new byte[(int) hex];
                                        state = read_state.address;
                                        nhexbytes = 4;
                                        break;
@@ -161,7 +171,7 @@ class HexRecord implements Comparable<Object> {
                                        nhexbytes = 2;
                                        break;
                                case type:
-                                       type = hex;
+                                       type = (int) hex;
                                        if (data.length > 0)
                                                state = read_state.data;
                                        else
@@ -208,11 +218,170 @@ class HexRecord implements Comparable<Object> {
 }
 
 public class AltosHexfile {
-       public int      address;
-       public byte[]   data;
+       public long             address;
+       public long             max_address;
+       public byte[]           data;
+       LinkedList<AltosHexsym> symlist = new LinkedList<AltosHexsym>();
+
+       public byte get_byte(long a) {
+               return data[(int) (a - address)];
+       }
+
+       public int get_u8(long a) {
+               return ((int) get_byte(a)) & 0xff;
+       }
+
+       public int get_u16(long a) {
+               return get_u8(a) | (get_u8(a+1) << 8);
+       }
+
+       /* CC1111-based products have the romconfig stuff located
+        * at a fixed address; when the file we load has no symbols,
+        * assume it is one of those and set the symbols appropriately
+        */
+       final static int ao_romconfig_version_addr = 0xa0;
+       final static int ao_romconfig_check_addr = 0xa2;
+       final static int ao_serial_number_addr = 0xa4;
+       final static int ao_radio_cal_addr = 0xa6;
+       final static int ao_usb_descriptors_addr = 0xaa;
+
+       static AltosHexsym[] cc_symbols = {
+               new AltosHexsym("ao_romconfig_version", ao_romconfig_version_addr),
+               new AltosHexsym("ao_romconfig_check", ao_romconfig_check_addr),
+               new AltosHexsym("ao_serial_number", ao_serial_number_addr),
+               new AltosHexsym("ao_radio_cal", ao_radio_cal_addr),
+               new AltosHexsym("ao_usb_descriptors", ao_usb_descriptors_addr)
+       };
+
+       static final int AO_USB_DESC_DEVICE             = 1;
+       static final int AO_USB_DESC_STRING             = 3;
+
+       static final int AO_ROMCONFIG_VERSION_INDEX     = 0;
+       static final int AO_ROMCONFIG_CHECK_INDEX       = 1;
+       static final int AO_SERIAL_NUMBER_INDEX         = 2;
+       static final int AO_RADIO_CAL_INDEX             = 3;
+       static final int AO_USB_DESCRIPTORS_INDEX       = 4;
+
+       private void add_cc_symbols() {
+               for (int i = 0; i < cc_symbols.length; i++)
+                       symlist.add(cc_symbols[i]);
+       }
+
+       public void add_symbol(AltosHexsym symbol) {
+               symlist.add(symbol);
+       }
+
+       /* Take symbols from another hexfile and duplicate them here */
+       public void add_symbols(AltosHexfile other) {
+               for (AltosHexsym symbol : other.symlist)
+                       symlist.add(symbol);
+       }
+
+       public AltosHexsym lookup_symbol(String name) {
+               if (symlist.isEmpty())
+                       add_cc_symbols();
+
+               for (AltosHexsym symbol : symlist)
+                       if (name.equals(symbol.name))
+                               return symbol;
+               return null;
+       }
+
+       private long find_usb_descriptors() {
+               AltosHexsym     usb_descriptors = lookup_symbol("ao_usb_descriptors");
+               long            a;
+
+               if (usb_descriptors == null)
+                       return -1;
+
+               try {
+                       /* Walk the descriptors looking for the device */
+                       a = usb_descriptors.address;
+                       while (get_u8(a+1) != AO_USB_DESC_DEVICE) {
+                               int delta = get_u8(a);
+                               a += delta;
+                               if (delta == 0 || a >= max_address)
+                                       return -1;
+                       }
+                       return a;
+               } catch (ArrayIndexOutOfBoundsException ae) {
+                       return -1;
+               }
+       }
+
+       public AltosUsbId find_usb_id() {
+               long a = find_usb_descriptors();
+
+               if (a == -1)
+                       return null;
 
-       public byte get_byte(int a) {
-               return data[a - address];
+               /* Walk the descriptors looking for the device */
+               while (get_u8(a+1) != AO_USB_DESC_DEVICE) {
+                       int delta = get_u8(a);
+                       a += delta;
+                       if (delta == 0 || a >= max_address)
+                               return null;
+               }
+
+               return new AltosUsbId(get_u16(a + 8),
+                                     get_u16(a + 10));
+       }
+
+       public String find_usb_product() {
+               long            a = find_usb_descriptors();
+               int             num_strings;
+               int             product_string;
+
+               if (a == -1)
+                       return null;
+
+               product_string = get_u8(a+15);
+
+               /* Walk the descriptors looking for the device */
+               num_strings = 0;
+               for (;;) {
+                       if (get_u8(a+1) == AO_USB_DESC_STRING) {
+                               ++num_strings;
+                               if (num_strings == product_string + 1)
+                                       break;
+                       }
+
+                       int delta = get_u8(a);
+                       a += delta;
+                       if (delta == 0 || a >= max_address)
+                               return null;
+               }
+
+               int product_len = get_u8(a);
+
+               if (product_len <= 0)
+                       return null;
+
+               String product = "";
+
+               for (int i = 0; i < product_len - 2; i += 2) {
+                       int     c = get_u16(a + 2 + i);
+
+                       product += Character.toString((char) c);
+               }
+
+               if (AltosLink.debug)
+                       System.out.printf("product %s\n", product);
+
+               return product;
+       }
+
+       private String make_string(byte[] data, int start, int length) {
+               String s = "";
+               for (int i = 0; i < length; i++)
+                       s += (char) data[start + i];
+               return s;
+       }
+
+       public AltosHexfile(byte[] bytes, long offset) {
+               data = bytes;
+               address = offset;
+               max_address = address + bytes.length;
        }
 
        public AltosHexfile(FileInputStream file) throws IOException {
@@ -221,12 +390,13 @@ public class AltosHexfile {
                boolean                 done = false;
 
                while (!done) {
-                       HexRecord       record = new HexRecord(input);
+                       try {
+                               HexRecord       record = new HexRecord(input);
 
-                       if (record.type == HexRecord.EOF)
-                               done = true;
-                       else
                                record_list.add(record);
+                       } catch (EOFException eof) {
+                               done = true;
+                       }
                }
 
                long    extended_addr = 0;
@@ -234,9 +404,10 @@ public class AltosHexfile {
                long    bound = 0;
                boolean set = false;
                for (HexRecord record : record_list) {
+                       long addr;
                        switch (record.type) {
                        case 0:
-                               long addr = extended_addr + record.address;
+                               addr = extended_addr + record.address;
                                long r_bound = addr + record.data.length;
                                if (!set || addr < base)
                                        base = addr;
@@ -256,6 +427,12 @@ public class AltosHexfile {
                                        throw new IOException("invalid extended segment address record");
                                extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16;
                                break;
+                       case 0xfe:
+                               String name = make_string(record.data, 0, record.data.length);
+                               addr = extended_addr + record.address;
+                               AltosHexsym s = new AltosHexsym(name, addr);
+                               symlist.add(s);
+                               break;
                        default:
                                throw new IOException ("invalid hex record type");
                        }
@@ -268,7 +445,8 @@ public class AltosHexfile {
                        throw new IOException("hex file too large");
 
                data = new byte[(int) (bound - base)];
-               address = (int) base;
+               address = base;
+               max_address = bound;
                Arrays.fill(data, (byte) 0xff);
 
                /* Paint the records into the new array */
@@ -292,9 +470,11 @@ public class AltosHexfile {
                                        throw new IOException("invalid extended segment address record");
                                extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16;
                                break;
+                       case 0xfe:
+                               break;
                        default:
                                throw new IOException ("invalid hex record type");
                        }
                }
        }
-}
\ No newline at end of file
+}