*
* 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_3;
+package org.altusmetrum.altoslib_14;
import java.io.*;
+import java.util.concurrent.*;
-public class AltosRomconfig {
+public class AltosRomconfig implements AltosUnitInfoListener {
public boolean valid;
+ public boolean radio_calibration_broken;
public int version;
public int check;
public int serial_number;
public int radio_calibration;
+ public int address_offset;
+ public AltosUsbId usb_id;
+ public String usb_product;
- static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+ static private long find_address(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)
+ if (symbol == null) {
throw new AltosNoSymbol(name);
- return offset;
+ }
+ if (hexfile.address <= symbol.address && symbol.address + len <= hexfile.max_address) {
+ return symbol.address;
+ }
+ throw new AltosNoSymbol(name);
}
- static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+ static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+ return (int) (find_address(hexfile, name, len) - hexfile.address);
+ }
+
+ static private int get_int(AltosHexfile hexfile, String name, int len, int adjust) throws AltosNoSymbol {
byte[] bytes = hexfile.data;
- int start = find_offset(hexfile, name, len);
+ int start = (int) find_offset(hexfile, name, len) + adjust;
int v = 0;
int o = 0;
final static String ao_radio_cal = "ao_radio_cal";
final static String ao_usb_descriptors = "ao_usb_descriptors";
+ Semaphore unit_info_done;
+
+ public void notify_unit_info(AltosUnitInfo unit_info) {
+ unit_info_done.release();
+ }
+
+ private void fetch_radio_cal() {
+ unit_info_done = new Semaphore(0);
+ AltosUnitInfo info = new AltosUnitInfo(serial_number, this);
+
+ /* Block waiting for the rf calibration data */
+ radio_calibration_broken = true;
+ try {
+ unit_info_done.acquire();
+ int new_cal = info.rfcal();
+ if (new_cal != AltosLib.MISSING) {
+ radio_calibration = new_cal;
+ radio_calibration_broken = false;
+ }
+ } catch (InterruptedException ie) {
+ }
+ }
+
+ static final int adjust_rom[] = { 0, -4, 4 };
+
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;
+ for (int adjust : adjust_rom) {
+ try {
+ version = get_int(hexfile, ao_romconfig_version, 2, adjust);
+ check = get_int(hexfile, ao_romconfig_check, 2, adjust);
+ if (check == (~version & 0xffff)) {
+ System.out.printf("adjust %d version %x check %x success\n", adjust, version, check);
+ switch (version) {
+ case 2:
+ case 1:
+ serial_number = get_int(hexfile, ao_serial_number, 2, adjust);
+ try {
+ radio_calibration = get_int(hexfile, ao_radio_cal, 4, adjust);
+ } catch (AltosNoSymbol missing) {
+ radio_calibration = 0;
+ }
+
+ valid = true;
+
+ /* XXX TeleBT v4.0 units originally shipped without RF calibration programmed. Go fetch
+ * the correct value from the web site
+ */
+ if (serial_number == 2584 ||
+ (3686 <= serial_number && serial_number <= 3938 && radio_calibration == 5695485))
+ {
+ fetch_radio_cal();
+ }
+
+ break;
+ }
+ break;
+ } else {
+ System.out.printf("adjust %d version %x check %x fail\n", adjust, version, check);
}
- valid = true;
- break;
+ } catch (ArrayIndexOutOfBoundsException aie) {
+ System.out.printf("adjust %d out of bounds\n", adjust);
+ continue;
}
}
+ usb_id = hexfile.find_usb_id();
+ usb_product = hexfile.find_usb_product();
+
} catch (AltosNoSymbol missing) {
valid = false;
}
ao_romconfig_version,
ao_romconfig_check,
ao_serial_number,
- ao_radio_cal
+ ao_radio_cal,
+ ao_usb_descriptors,
};
+ private static int fetch_len(String name) {
+ if (name.equals(ao_usb_descriptors))
+ return 256;
+ return 2;
+ }
+
private final static String[] required_names = {
ao_romconfig_version,
ao_romconfig_check,
return false;
}
- public static int fetch_base(AltosHexfile hexfile) throws AltosNoSymbol {
- int base = 0x7fffffff;
+ public static long fetch_base(AltosHexfile hexfile) throws AltosNoSymbol {
+ long base = 0xffffffffL;
for (String name : fetch_names) {
try {
- int addr = find_offset(hexfile, name, 2) + hexfile.address;
+ int len = fetch_len(name);
+ long addr = find_address(hexfile, name, len);
+
if (addr < base)
base = addr;
} catch (AltosNoSymbol ns) {
return base;
}
- public static int fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol {
- int bounds = 0;
+ public static long fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol {
+ long bounds = 0;
for (String name : fetch_names) {
try {
- int addr = find_offset(hexfile, name, 2) + hexfile.address;
+ int len = fetch_len(name);
+ long addr = find_address(hexfile, name, len) + len;
if (addr > bounds)
bounds = addr;
} catch (AltosNoSymbol ns) {
throw (ns);
}
}
- return bounds + 2;
+
+ return bounds;
}
public void write (AltosHexfile hexfile) throws IOException {
throw new IOException("writing new rom config failed\n");
}
+ public String toString() {
+ return String.format("valid %b version %d serial %d radio %d usb %04x:%04x %s",
+ valid, version, serial_number, radio_calibration,
+ usb_id == null ? 0 : usb_id.vid,
+ usb_id == null ? 0 : usb_id.pid,
+ usb_product == null ? "unknown" : usb_product);
+ }
+
public AltosRomconfig(int in_serial_number, int in_radio_calibration) {
valid = true;
version = 1;
}
public boolean valid() {
- return valid && serial_number != 0;
+ return valid;
}
public AltosRomconfig() {