X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=altoslib%2FAltosHexfile.java;h=609d1bcb366f9f3ae747633f1f0a51e8894d04ad;hp=90352927433f219e1a79c359554c84b2e40009d7;hb=3c48b0fd504ae97dfaca91d2064b5822ca6e1344;hpb=5b976a6651f4eb05d30afc08b9e1f27c7e52ae00 diff --git a/altoslib/AltosHexfile.java b/altoslib/AltosHexfile.java index 90352927..609d1bcb 100644 --- a/altoslib/AltosHexfile.java +++ b/altoslib/AltosHexfile.java @@ -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 { - public int address; + public long address; public int type; public byte checksum; public byte[] data; @@ -109,30 +110,39 @@ class HexRecord implements Comparable { 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 { 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 { 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 { } public class AltosHexfile { - public int address; - public byte[] data; + public long address; + public long max_address; + public byte[] data; + LinkedList symlist = new LinkedList(); + + 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 +}