*
* 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
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_2;
+package org.altusmetrum.altoslib_14;
import java.io.*;
import java.util.LinkedList;
}
class HexRecord implements Comparable<Object> {
- public int address;
+ public long address;
public int type;
public byte checksum;
public byte[] data;
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;
switch (state) {
case length:
- data = new byte[hex];
+ data = new byte[(int) hex];
state = read_state.address;
nhexbytes = 4;
break;
nhexbytes = 2;
break;
case type:
- type = hex;
+ type = (int) hex;
if (data.length > 0)
state = read_state.data;
else
}
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;
- public byte get_byte(int a) {
- return data[a - address];
+ 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 {
+ /* The address of this has moved depending on
+ * padding in the linker script. Look forward
+ * and backwards two bytes to see if we can find it
+ */
+ a = usb_descriptors.address;
+
+ if (get_u8(a) == 0x12 && get_u8(a+1) == AO_USB_DESC_DEVICE)
+ return a;
+ else if (get_u8(a+1) == 0x12 && get_u8(a+3) == AO_USB_DESC_DEVICE)
+ return a + 2;
+ else if (get_u8(a-2) == 0x12 && get_u8(a-1) == AO_USB_DESC_DEVICE)
+ return a - 2;
+
+ return -1;
+ } catch (ArrayIndexOutOfBoundsException ae) {
+ return -1;
+ }
+ }
+
+ public AltosUsbId find_usb_id() {
+ long a = find_usb_descriptors();
+
+ if (a == -1)
+ return null;
+
+ /* 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 {
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;
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;
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");
}
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 */
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
+}