2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 package org.altusmetrum.altoslib_13;
23 public class AltosRomconfig {
27 public int serial_number;
28 public int radio_calibration;
29 public AltosUsbId usb_id;
30 public String usb_product;
32 static private long find_address(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
33 AltosHexsym symbol = hexfile.lookup_symbol(name);
35 throw new AltosNoSymbol(name);
37 if (hexfile.address <= symbol.address && symbol.address + len <= hexfile.max_address) {
38 return symbol.address;
40 throw new AltosNoSymbol(name);
43 static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
44 return (int) (find_address(hexfile, name, len) - hexfile.address);
47 static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
48 byte[] bytes = hexfile.data;
49 int start = (int) find_offset(hexfile, name, len);
54 v = v | ((((int) bytes[start]) & 0xff) << o);
62 static void put_int(int value, AltosHexfile hexfile, String name, int len) throws AltosNoSymbol, IOException {
63 byte[] bytes = hexfile.data;
64 int start = find_offset(hexfile, name, len);
67 bytes[start] = (byte) (value & 0xff);
74 static void put_string(String value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
75 byte[] bytes = hexfile.data;
76 int start = find_offset(hexfile, name, value.length());
78 for (int i = 0; i < value.length(); i++)
79 bytes[start + i] = (byte) value.charAt(i);
82 static final int AO_USB_DESC_STRING = 3;
84 static void put_usb_serial(int value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
85 byte[] bytes = hexfile.data;
86 int start = find_offset(hexfile, name, 2);
90 while (start < bytes.length && bytes[start] != 0) {
91 if (bytes[start + 1] == AO_USB_DESC_STRING) {
96 start += ((int) bytes[start]) & 0xff;
98 if (start >= bytes.length || bytes[start] == 0)
99 throw new AltosNoSymbol(name);
101 int len = ((((int) bytes[start]) & 0xff) - 2) / 2;
102 String fmt = String.format("%%0%dd", len);
104 String s = String.format(fmt, value);
105 if (s.length() != len)
106 throw new AltosNoSymbol(String.format("weird usb length issue %s isn't %d\n", s, len));
108 for (int i = 0; i < len; i++) {
109 bytes[start + 2 + i*2] = (byte) s.charAt(i);
110 bytes[start + 2 + i*2+1] = 0;
114 final static String ao_romconfig_version = "ao_romconfig_version";
115 final static String ao_romconfig_check = "ao_romconfig_check";
116 final static String ao_serial_number = "ao_serial_number";
117 final static String ao_radio_cal = "ao_radio_cal";
118 final static String ao_usb_descriptors = "ao_usb_descriptors";
120 public AltosRomconfig(AltosHexfile hexfile) {
122 version = get_int(hexfile, ao_romconfig_version, 2);
123 check = get_int(hexfile, ao_romconfig_check, 2);
124 if (check == (~version & 0xffff)) {
128 serial_number = get_int(hexfile, ao_serial_number, 2);
130 radio_calibration = get_int(hexfile, ao_radio_cal, 4);
131 } catch (AltosNoSymbol missing) {
132 radio_calibration = 0;
138 usb_id = hexfile.find_usb_id();
139 usb_product = hexfile.find_usb_product();
141 } catch (AltosNoSymbol missing) {
146 private final static String[] fetch_names = {
147 ao_romconfig_version,
154 private static int fetch_len(String name) {
155 if (name.equals(ao_usb_descriptors))
160 private final static String[] required_names = {
161 ao_romconfig_version,
166 private static boolean name_required(String name) {
167 for (String required : required_names)
168 if (name.equals(required))
173 public static long fetch_base(AltosHexfile hexfile) throws AltosNoSymbol {
174 long base = 0xffffffffL;
175 for (String name : fetch_names) {
177 int len = fetch_len(name);
178 long addr = find_address(hexfile, name, len);
182 } catch (AltosNoSymbol ns) {
183 if (name_required(name))
190 public static long fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol {
192 for (String name : fetch_names) {
194 int len = fetch_len(name);
195 long addr = find_address(hexfile, name, len) + len;
198 } catch (AltosNoSymbol ns) {
199 if (name_required(name))
207 public void write (AltosHexfile hexfile) throws IOException {
209 throw new IOException("rom configuration invalid");
211 AltosRomconfig existing = new AltosRomconfig(hexfile);
213 throw new IOException("image does not contain existing rom config");
216 switch (existing.version) {
219 put_usb_serial(serial_number, hexfile, ao_usb_descriptors);
220 } catch (AltosNoSymbol missing) {
222 /* fall through ... */
224 put_int(serial_number, hexfile, ao_serial_number, 2);
226 put_int(radio_calibration, hexfile, ao_radio_cal, 4);
227 } catch (AltosNoSymbol missing) {
231 } catch (AltosNoSymbol missing) {
232 throw new IOException(missing.getMessage());
235 AltosRomconfig check = new AltosRomconfig(hexfile);
237 throw new IOException("writing new rom config failed\n");
240 public AltosRomconfig(int in_serial_number, int in_radio_calibration) {
243 check = (~version & 0xffff);
244 serial_number = in_serial_number;
245 radio_calibration = in_radio_calibration;
248 public boolean valid() {
249 return valid && serial_number != 0;
252 public AltosRomconfig() {