Switch from GPLv2 to GPLv2+
[fw/altos] / altoslib / AltosRomconfig.java
index 0800a2c4da1e405abad6d9686cfb76514d6355ff..dcfbda32dd139a16ead731a8098a5dcf84c98581 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_1;
+package org.altusmetrum.altoslib_11;
 
 import java.io.*;
 
@@ -26,7 +27,20 @@ public class AltosRomconfig {
        public int      serial_number;
        public int      radio_calibration;
 
-       static int get_int(byte[] bytes, int start, int len) {
+       static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+               AltosHexsym symbol = hexfile.lookup_symbol(name);
+               if (symbol == null)
+                       throw new AltosNoSymbol(name);
+               int offset = (int) symbol.address - hexfile.address;
+               if (offset < 0 || hexfile.data.length < offset + len)
+                       throw new AltosNoSymbol(name);
+               return offset;
+       }
+
+       static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, len);
+
                int     v = 0;
                int     o = 0;
                while (len > 0) {
@@ -38,7 +52,10 @@ public class AltosRomconfig {
                return v;
        }
 
-       static void put_int(int value, byte[] bytes, int start, int len) {
+       static void put_int(int value, AltosHexfile hexfile, String name, int len) throws AltosNoSymbol, IOException {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, len);
+
                while (len > 0) {
                        bytes[start] = (byte) (value & 0xff);
                        start++;
@@ -47,86 +64,155 @@ public class AltosRomconfig {
                }
        }
 
-       static void put_string(String value, byte[] bytes, int start) {
+       static void put_string(String value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, value.length());
+
                for (int i = 0; i < value.length(); i++)
                        bytes[start + i] = (byte) value.charAt(i);
        }
 
        static final int AO_USB_DESC_STRING     = 3;
 
-       static void put_usb_serial(int value, byte[] bytes, int start) {
-               int offset = start + 0xa;
+       static void put_usb_serial(int value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, 2);
+
                int string_num = 0;
 
-               while (offset < bytes.length && bytes[offset] != 0) {
-                       if (bytes[offset + 1] == AO_USB_DESC_STRING) {
+               while (start < bytes.length && bytes[start] != 0) {
+                       if (bytes[start + 1] == AO_USB_DESC_STRING) {
                                ++string_num;
                                if (string_num == 4)
                                        break;
                        }
-                       offset += ((int) bytes[offset]) & 0xff;
+                       start += ((int) bytes[start]) & 0xff;
                }
-               if (offset >= bytes.length || bytes[offset] == 0)
-                       return;
-               int len = ((((int) bytes[offset]) & 0xff) - 2) / 2;
+               if (start >= bytes.length || bytes[start] == 0)
+                       throw new AltosNoSymbol(name);
+
+               int len = ((((int) bytes[start]) & 0xff) - 2) / 2;
                String fmt = String.format("%%0%dd", len);
 
                String s = String.format(fmt, value);
-               if (s.length() != len) {
-                       System.out.printf("weird usb length issue %s isn't %d\n",
-                                         s, len);
-                       return;
-               }
+               if (s.length() != len)
+                       throw new AltosNoSymbol(String.format("weird usb length issue %s isn't %d\n", s, len));
+
                for (int i = 0; i < len; i++) {
-                       bytes[offset + 2 + i*2] = (byte) s.charAt(i);
-                       bytes[offset + 2 + i*2+1] = 0;
+                       bytes[start + 2 + i*2] = (byte) s.charAt(i);
+                       bytes[start + 2 + i*2+1] = 0;
                }
        }
 
-       public AltosRomconfig(byte[] bytes, int offset) {
-               version = get_int(bytes, offset + 0, 2);
-               check = get_int(bytes, offset + 2, 2);
-               if (check == (~version & 0xffff)) {
-                       switch (version) {
-                       case 2:
-                       case 1:
-                               serial_number = get_int(bytes, offset + 4, 2);
-                               radio_calibration = get_int(bytes, offset + 6, 4);
-                               valid = true;
-                               break;
+       final static String ao_romconfig_version = "ao_romconfig_version";
+       final static String ao_romconfig_check = "ao_romconfig_check";
+       final static String ao_serial_number = "ao_serial_number";
+       final static String ao_radio_cal = "ao_radio_cal";
+       final static String ao_usb_descriptors = "ao_usb_descriptors";
+
+       public AltosRomconfig(AltosHexfile hexfile) {
+               try {
+                       version = get_int(hexfile, ao_romconfig_version, 2);
+                       check = get_int(hexfile, ao_romconfig_check, 2);
+                       if (check == (~version & 0xffff)) {
+                               switch (version) {
+                               case 2:
+                               case 1:
+                                       serial_number = get_int(hexfile, ao_serial_number, 2);
+                                       try {
+                                               radio_calibration = get_int(hexfile, ao_radio_cal, 4);
+                                       } catch (AltosNoSymbol missing) {
+                                               radio_calibration = 0;
+                                       }
+                                       valid = true;
+                                       break;
+                               }
                        }
+               } catch (AltosNoSymbol missing) {
+                       valid = false;
                }
        }
 
-       public AltosRomconfig(AltosHexfile hexfile) {
-               this(hexfile.data, 0xa0 - hexfile.address);
+       private final static String[] fetch_names = {
+               ao_romconfig_version,
+               ao_romconfig_check,
+               ao_serial_number,
+               ao_radio_cal
+       };
+
+       private final static String[] required_names = {
+               ao_romconfig_version,
+               ao_romconfig_check,
+               ao_serial_number
+       };
+
+       private static boolean name_required(String name) {
+               for (String required : required_names)
+                       if (name.equals(required))
+                               return true;
+               return false;
        }
 
-       public void write(byte[] bytes, int offset) throws IOException {
+       public static int fetch_base(AltosHexfile hexfile) throws AltosNoSymbol {
+               int     base = 0x7fffffff;
+               for (String name : fetch_names) {
+                       try {
+                               int     addr = find_offset(hexfile, name, 2) + hexfile.address;
+                               if (addr < base)
+                                       base = addr;
+                       } catch (AltosNoSymbol ns) {
+                               if (name_required(name))
+                                       throw (ns);
+                       }
+               }
+               return base;
+       }
+
+       public static int fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol {
+               int     bounds = 0;
+               for (String name : fetch_names) {
+                       try {
+                               int     addr = find_offset(hexfile, name, 2) + hexfile.address;
+                               if (addr > bounds)
+                                       bounds = addr;
+                       } catch (AltosNoSymbol ns) {
+                               if (name_required(name))
+                                       throw (ns);
+                       }
+               }
+               return bounds + 2;
+       }
+
+       public void write (AltosHexfile hexfile) throws IOException {
                if (!valid)
                        throw new IOException("rom configuration invalid");
 
-               if (offset < 0 || bytes.length < offset + 10)
-                       throw new IOException("image cannot contain rom config");
-
-               AltosRomconfig existing = new AltosRomconfig(bytes, offset);
+               AltosRomconfig existing = new AltosRomconfig(hexfile);
                if (!existing.valid)
                        throw new IOException("image does not contain existing rom config");
 
-               switch (existing.version) {
-               case 2:
-                       put_usb_serial(serial_number, bytes, offset);
-               case 1:
-                       put_int(serial_number, bytes, offset + 4, 2);
-                       put_int(radio_calibration, bytes, offset + 6, 4);
-                       break;
+               try {
+                       switch (existing.version) {
+                       case 2:
+                               try {
+                                       put_usb_serial(serial_number, hexfile, ao_usb_descriptors);
+                               } catch (AltosNoSymbol missing) {
+                               }
+                               /* fall through ... */
+                       case 1:
+                               put_int(serial_number, hexfile, ao_serial_number, 2);
+                               try {
+                                       put_int(radio_calibration, hexfile, ao_radio_cal, 4);
+                               } catch (AltosNoSymbol missing) {
+                               }
+                               break;
+                       }
+               } catch (AltosNoSymbol missing) {
+                       throw new IOException(missing.getMessage());
                }
-       }
 
-       public void write (AltosHexfile hexfile) throws IOException {
-               write(hexfile.data, 0xa0 - hexfile.address);
                AltosRomconfig check = new AltosRomconfig(hexfile);
-               if (!check.valid())
+               if (!check.valid)
                        throw new IOException("writing new rom config failed\n");
        }