From: Keith Packard Date: Sun, 24 Mar 2013 23:01:08 +0000 (-0700) Subject: altosui & altoslib: Move a pile of debug/programming bits to altoslib X-Git-Tag: 1.2.1~41 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=09e0c304b420a12fa1616005db946523c6e5bef1 altosui & altoslib: Move a pile of debug/programming bits to altoslib Prepare to create external Java utilities to flash devices Signed-off-by: Keith Packard --- diff --git a/altoslib/AltosDebug.java b/altoslib/AltosDebug.java new file mode 100644 index 00000000..4d8e3ae7 --- /dev/null +++ b/altoslib/AltosDebug.java @@ -0,0 +1,280 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; + +public class AltosDebug { + + public static final byte WR_CONFIG = 0x1d; + public static final byte RD_CONFIG = 0x24; + public static final byte CONFIG_TIMERS_OFF = (1 << 3); + public static final byte CONFIG_DMA_PAUSE = (1 << 2); + public static final byte CONFIG_TIMER_SUSPEND = (1 << 1); + public static final byte SET_FLASH_INFO_PAGE = (1 << 0); + + public static final byte GET_PC = 0x28; + public static final byte READ_STATUS = 0x34; + public static final byte STATUS_CHIP_ERASE_DONE = (byte) (1 << 7); + public static final byte STATUS_PCON_IDLE = (1 << 6); + public static final byte STATUS_CPU_HALTED = (1 << 5); + public static final byte STATUS_POWER_MODE_0 = (1 << 4); + public static final byte STATUS_HALT_STATUS = (1 << 3); + public static final byte STATUS_DEBUG_LOCKED = (1 << 2); + public static final byte STATUS_OSCILLATOR_STABLE = (1 << 1); + public static final byte STATUS_STACK_OVERFLOW = (1 << 0); + + public static final byte SET_HW_BRKPNT = 0x3b; + public static byte HW_BRKPNT_N(byte n) { return (byte) ((n) << 3); } + public static final byte HW_BRKPNT_N_MASK = (0x3 << 3); + public static final byte HW_BRKPNT_ENABLE = (1 << 2); + + public static final byte HALT = 0x44; + public static final byte RESUME = 0x4c; + public static byte DEBUG_INSTR(byte n) { return (byte) (0x54|(n)); } + public static final byte STEP_INSTR = 0x5c; + public static byte STEP_REPLACE(byte n) { return (byte) (0x64|(n)); } + public static final byte GET_CHIP_ID = 0x68; + + + AltosLink link; + + boolean debug_mode; + + void ensure_debug_mode() { + if (!debug_mode) { + link.printf("D\n"); + try { + link.flush_input(); + } catch (InterruptedException ie) { + } + debug_mode = true; + } + } + + void dump_memory(String header, int address, byte[] bytes, int start, int len) { + System.out.printf("%s\n", header); + for (int j = 0; j < len; j++) { + if ((j & 15) == 0) { + if (j != 0) + System.out.printf("\n"); + System.out.printf ("%04x:", address + j); + } + System.out.printf(" %02x", bytes[start + j]); + } + System.out.printf("\n"); + } + + public void close() { + link.close(); + } + + /* + * Write target memory + */ + public void write_memory(int address, byte[] bytes, int start, int len) { + ensure_debug_mode(); +// dump_memory("write_memory", address, bytes, start, len); + link.printf("O %x %x\n", len, address); + for (int i = 0; i < len; i++) + link.printf("%02x", bytes[start + i]); + } + + public void write_memory(int address, byte[] bytes) { + write_memory(address, bytes, 0, bytes.length); + } + + /* + * Read target memory + */ + public byte[] read_memory(int address, int length) + throws IOException, InterruptedException { + byte[] data = new byte[length]; + + link.flush_input(); + ensure_debug_mode(); + link.printf("I %x %x\n", length, address); + int i = 0; + int start = 0; + while (i < length) { + String line = link.get_reply().trim(); + if (!AltosLib.ishex(line) || line.length() % 2 != 0) + throw new IOException( + String.format + ("Invalid reply \"%s\"", line)); + int this_time = line.length() / 2; + for (int j = 0; j < this_time; j++) + data[start + j] = (byte) ((AltosLib.fromhex(line.charAt(j*2)) << 4) + + AltosLib.fromhex(line.charAt(j*2+1))); + start += this_time; + i += this_time; + } +// dump_memory("read_memory", address, data, 0, length); + + return data; + } + + /* + * Write raw bytes to the debug link using the 'P' command + */ + public void write_bytes(byte[] bytes) throws IOException { + int i = 0; + ensure_debug_mode(); + while (i < bytes.length) { + int this_time = bytes.length - i; + if (this_time > 8) + this_time = 0; + link.printf("P"); + for (int j = 0; j < this_time; j++) + link.printf(" %02x", bytes[i+j]); + link.printf("\n"); + i += this_time; + } + } + + public void write_byte(byte b) throws IOException { + byte[] bytes = { b }; + write_bytes(bytes); + } + + /* + * Read raw bytes from the debug link using the 'G' command + */ + public byte[] read_bytes(int length) + throws IOException, InterruptedException { + + link.flush_input(); + ensure_debug_mode(); + link.printf("G %x\n", length); + int i = 0; + byte[] data = new byte[length]; + while (i < length) { + String line = link.get_reply(); + + if (line == null) + throw new IOException("Timeout in read_bytes"); + line = line.trim(); + String tokens[] = line.split("\\s+"); + for (int j = 0; j < tokens.length; j++) { + if (!AltosLib.ishex(tokens[j]) || + tokens[j].length() != 2) + throw new IOException( + String.format + ("Invalid read_bytes reply \"%s\"", line)); + try { + if (i + j >= length) + throw new IOException( + String.format + ("Invalid read_bytes reply \"%s\"", line)); + else + data[i + j] = (byte) Integer.parseInt(tokens[j], 16); + } catch (NumberFormatException ne) { + throw new IOException( + String.format + ("Invalid read_bytes reply \"%s\"", line)); + } + } + i += tokens.length; + } + return data; + } + + public byte read_byte() throws IOException, InterruptedException { + return read_bytes(1)[0]; + } + + public byte debug_instr(byte[] instruction) throws IOException, InterruptedException { + byte[] command = new byte[1 + instruction.length]; + command[0] = DEBUG_INSTR((byte) instruction.length); + for (int i = 0; i < instruction.length; i++) + command[i+1] = instruction[i]; + write_bytes(command); + return read_byte(); + } + + public byte resume() throws IOException, InterruptedException { + write_byte(RESUME); + return read_byte(); + } + + public int read_uint16() throws IOException, InterruptedException { + byte[] d = read_bytes(2); + return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff); + } + + public int read_uint8() throws IOException, InterruptedException { + byte[] d = read_bytes(1); + return (int) (d[0] & 0xff); + } + + public int get_chip_id() throws IOException, InterruptedException { + write_byte(GET_CHIP_ID); + return read_uint16(); + } + + public int get_pc() throws IOException, InterruptedException { + write_byte(GET_PC); + return read_uint16(); + } + + public byte read_status() throws IOException, InterruptedException { + write_byte(READ_STATUS); + return read_byte(); + } + + static final byte LJMP = 0x02; + + public void set_pc(int pc) throws IOException, InterruptedException { + byte high = (byte) (pc >> 8); + byte low = (byte) pc; + byte[] jump_mem = { LJMP, high, low }; + debug_instr(jump_mem); + } + + public boolean check_connection() throws IOException, InterruptedException { + byte reply = read_status(); + if ((reply & STATUS_CHIP_ERASE_DONE) == 0) + return false; + if ((reply & STATUS_PCON_IDLE) != 0) + return false; + if ((reply & STATUS_POWER_MODE_0) == 0) + return false; + return true; + } + + public AltosRomconfig romconfig() { + try { + byte[] bytes = read_memory(0xa0, 10); + return new AltosRomconfig(bytes, 0); + } catch (IOException ie) { + } catch (InterruptedException ie) { + } + return new AltosRomconfig(); + } + + /* + * Reset target + */ + public void reset() { + link.printf ("R\n"); + } + + public AltosDebug (AltosLink link) { + this.link = link; + } +} \ No newline at end of file diff --git a/altoslib/AltosHexfile.java b/altoslib/AltosHexfile.java new file mode 100644 index 00000000..68f42f14 --- /dev/null +++ b/altoslib/AltosHexfile.java @@ -0,0 +1,298 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; +import java.util.LinkedList; +import java.util.Arrays; + +class HexFileInputStream extends PushbackInputStream { + public int line; + + public HexFileInputStream(FileInputStream o) { + super(new BufferedInputStream(o)); + line = 1; + } + + public int read() throws IOException { + int c = super.read(); + if (c == '\n') + line++; + return c; + } + + public void unread(int c) throws IOException { + if (c == '\n') + line--; + if (c != -1) + super.unread(c); + } +} + +class HexRecord implements Comparable { + public int address; + public int type; + public byte checksum; + public byte[] data; + + static final int NORMAL = 0; + static final int EOF = 1; + static final int EXTENDED_ADDRESS = 2; + + enum read_state { + marker, + length, + address, + type, + data, + checksum, + newline, + white, + done, + } + + boolean ishex(int c) { + if ('0' <= c && c <= '9') + return true; + if ('a' <= c && c <= 'f') + return true; + if ('A' <= c && c <= 'F') + return true; + return false; + } + + boolean isspace(int c) { + switch (c) { + case ' ': + case '\t': + return true; + } + return false; + } + + int fromhex(int c) { + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return c - 'a' + 10; + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + return -1; + } + + public byte checksum() { + byte got = 0; + + got += data.length; + got += (address >> 8) & 0xff; + got += (address ) & 0xff; + got += type; + for (int i = 0; i < data.length; i++) + got += data[i]; + return (byte) (-got); + } + + public int compareTo(Object other) { + HexRecord o = (HexRecord) other; + return address - o.address; + } + + public String toString() { + return String.format("%04x: %02x (%d)", address, type, data.length); + } + + public HexRecord(HexFileInputStream input) throws IOException { + read_state state = read_state.marker; + int nhexbytes = 0; + int hex = 0; + int ndata = 0; + byte got_checksum; + + while (state != read_state.done) { + int c = input.read(); + if (c < 0 && state != read_state.white) + throw new IOException(String.format("%d: Unexpected EOF", input.line)); + if (c == ' ') + continue; + switch (state) { + case marker: + if (c != ':') + throw new IOException("Missing ':'"); + state = read_state.length; + nhexbytes = 2; + hex = 0; + break; + case length: + case address: + case type: + case data: + case checksum: + if(!ishex(c)) + throw new IOException(String.format("Non-hex char '%c'", c)); + hex = hex << 4 | fromhex(c); + --nhexbytes; + if (nhexbytes != 0) + break; + + switch (state) { + case length: + data = new byte[hex]; + state = read_state.address; + nhexbytes = 4; + break; + case address: + address = hex; + state = read_state.type; + nhexbytes = 2; + break; + case type: + type = hex; + if (data.length > 0) + state = read_state.data; + else + state = read_state.checksum; + nhexbytes = 2; + ndata = 0; + break; + case data: + data[ndata] = (byte) hex; + ndata++; + nhexbytes = 2; + if (ndata == data.length) + state = read_state.checksum; + break; + case checksum: + checksum = (byte) hex; + state = read_state.newline; + break; + default: + break; + } + hex = 0; + break; + case newline: + if (c != '\n' && c != '\r') + throw new IOException("Missing newline"); + state = read_state.white; + break; + case white: + if (!isspace(c)) { + input.unread(c); + state = read_state.done; + } + break; + case done: + break; + } + } + got_checksum = checksum(); + if (got_checksum != checksum) + throw new IOException(String.format("Invalid checksum (read 0x%02x computed 0x%02x)\n", + checksum, got_checksum)); + } +} + +public class AltosHexfile { + public int address; + public byte[] data; + + public byte get_byte(int a) { + return data[a - address]; + } + + public AltosHexfile(FileInputStream file) throws IOException { + HexFileInputStream input = new HexFileInputStream(file); + LinkedList record_list = new LinkedList(); + boolean done = false; + + while (!done) { + HexRecord record = new HexRecord(input); + + if (record.type == HexRecord.EOF) + done = true; + else + record_list.add(record); + } + + long extended_addr = 0; + long base = 0xffffffff; + long bound = 0x00000000; + for (HexRecord record : record_list) { + switch (record.type) { + case 0: + long addr = extended_addr + record.address; + long r_bound = addr + record.data.length; + if (addr < base) + base = addr; + if (r_bound > bound) + bound = r_bound; + break; + case 1: + break; + case 2: + if (record.data.length != 2) + throw new IOException("invalid extended segment address record"); + extended_addr = ((record.data[0] << 8) + (record.data[1])) << 4; + break; + case 4: + if (record.data.length != 2) + throw new IOException("invalid extended segment address record"); + extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; + break; + default: + throw new IOException ("invalid hex record type"); + } + } + + if (base >= bound) + throw new IOException("invalid hex file"); + + if (bound - base > 4 * 1024 * 1024) + throw new IOException("hex file too large"); + + data = new byte[(int) (bound - base)]; + address = (int) base; + Arrays.fill(data, (byte) 0xff); + + /* Paint the records into the new array */ + for (HexRecord record : record_list) { + switch (record.type) { + case 0: + long addr = extended_addr + record.address; + long r_bound = addr + record.data.length; + for (int j = 0; j < record.data.length; j++) + data[(int) (addr - base) + j] = record.data[j]; + break; + case 1: + break; + case 2: + if (record.data.length != 2) + throw new IOException("invalid extended segment address record"); + extended_addr = ((record.data[0] << 8) + (record.data[1])) << 4; + break; + case 4: + if (record.data.length != 2) + throw new IOException("invalid extended segment address record"); + extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; + break; + default: + throw new IOException ("invalid hex record type"); + } + } + } +} \ No newline at end of file diff --git a/altoslib/AltosRomconfig.java b/altoslib/AltosRomconfig.java new file mode 100644 index 00000000..0800a2c4 --- /dev/null +++ b/altoslib/AltosRomconfig.java @@ -0,0 +1,148 @@ +/* + * Copyright © 2010 Keith Packard + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +import java.io.*; + +public class AltosRomconfig { + public boolean valid; + public int version; + public int check; + public int serial_number; + public int radio_calibration; + + static int get_int(byte[] bytes, int start, int len) { + int v = 0; + int o = 0; + while (len > 0) { + v = v | ((((int) bytes[start]) & 0xff) << o); + start++; + len--; + o += 8; + } + return v; + } + + static void put_int(int value, byte[] bytes, int start, int len) { + while (len > 0) { + bytes[start] = (byte) (value & 0xff); + start++; + len--; + value >>= 8; + } + } + + static void put_string(String value, byte[] bytes, int start) { + 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; + int string_num = 0; + + while (offset < bytes.length && bytes[offset] != 0) { + if (bytes[offset + 1] == AO_USB_DESC_STRING) { + ++string_num; + if (string_num == 4) + break; + } + offset += ((int) bytes[offset]) & 0xff; + } + if (offset >= bytes.length || bytes[offset] == 0) + return; + int len = ((((int) bytes[offset]) & 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; + } + for (int i = 0; i < len; i++) { + bytes[offset + 2 + i*2] = (byte) s.charAt(i); + bytes[offset + 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; + } + } + } + + public AltosRomconfig(AltosHexfile hexfile) { + this(hexfile.data, 0xa0 - hexfile.address); + } + + public void write(byte[] bytes, int offset) 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); + 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; + } + } + + public void write (AltosHexfile hexfile) throws IOException { + write(hexfile.data, 0xa0 - hexfile.address); + AltosRomconfig check = new AltosRomconfig(hexfile); + if (!check.valid()) + throw new IOException("writing new rom config failed\n"); + } + + public AltosRomconfig(int in_serial_number, int in_radio_calibration) { + valid = true; + version = 1; + check = (~version & 0xffff); + serial_number = in_serial_number; + radio_calibration = in_radio_calibration; + } + + public boolean valid() { + return valid && serial_number != 0; + } + + public AltosRomconfig() { + valid = false; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 30a9d954..db0236a1 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -16,6 +16,7 @@ altoslib_JAVA = \ AltosConfigValues.java \ AltosConvert.java \ AltosCRCException.java \ + AltosDebug.java \ AltosEepromChunk.java \ AltosEepromIterable.java \ AltosEepromLog.java \ @@ -30,6 +31,7 @@ altoslib_JAVA = \ AltosGPSQuery.java \ AltosGPSSat.java \ AltosGreatCircle.java \ + AltosHexfile.java \ AltosIdleMonitor.java \ AltosIdleMonitorListener.java \ AltosIgnite.java \ @@ -53,6 +55,7 @@ altoslib_JAVA = \ AltosRecordTM.java \ AltosRecordMM.java \ AltosReplayReader.java \ + AltosRomconfig.java \ AltosSensorMM.java \ AltosSensorTM.java \ AltosState.java \ diff --git a/altosui/AltosDebug.java b/altosui/AltosDebug.java deleted file mode 100644 index c69369ef..00000000 --- a/altosui/AltosDebug.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -import java.io.*; -import org.altusmetrum.altosuilib_1.*; - -public class AltosDebug extends AltosSerial { - - public static final byte WR_CONFIG = 0x1d; - public static final byte RD_CONFIG = 0x24; - public static final byte CONFIG_TIMERS_OFF = (1 << 3); - public static final byte CONFIG_DMA_PAUSE = (1 << 2); - public static final byte CONFIG_TIMER_SUSPEND = (1 << 1); - public static final byte SET_FLASH_INFO_PAGE = (1 << 0); - - public static final byte GET_PC = 0x28; - public static final byte READ_STATUS = 0x34; - public static final byte STATUS_CHIP_ERASE_DONE = (byte) (1 << 7); - public static final byte STATUS_PCON_IDLE = (1 << 6); - public static final byte STATUS_CPU_HALTED = (1 << 5); - public static final byte STATUS_POWER_MODE_0 = (1 << 4); - public static final byte STATUS_HALT_STATUS = (1 << 3); - public static final byte STATUS_DEBUG_LOCKED = (1 << 2); - public static final byte STATUS_OSCILLATOR_STABLE = (1 << 1); - public static final byte STATUS_STACK_OVERFLOW = (1 << 0); - - public static final byte SET_HW_BRKPNT = 0x3b; - public static byte HW_BRKPNT_N(byte n) { return (byte) ((n) << 3); } - public static final byte HW_BRKPNT_N_MASK = (0x3 << 3); - public static final byte HW_BRKPNT_ENABLE = (1 << 2); - - public static final byte HALT = 0x44; - public static final byte RESUME = 0x4c; - public static byte DEBUG_INSTR(byte n) { return (byte) (0x54|(n)); } - public static final byte STEP_INSTR = 0x5c; - public static byte STEP_REPLACE(byte n) { return (byte) (0x64|(n)); } - public static final byte GET_CHIP_ID = 0x68; - - - boolean debug_mode; - - void ensure_debug_mode() { - if (!debug_mode) { - printf("D\n"); - try { - flush_input(); - } catch (InterruptedException ie) { - } - debug_mode = true; - } - } - - void dump_memory(String header, int address, byte[] bytes, int start, int len) { - System.out.printf("%s\n", header); - for (int j = 0; j < len; j++) { - if ((j & 15) == 0) { - if (j != 0) - System.out.printf("\n"); - System.out.printf ("%04x:", address + j); - } - System.out.printf(" %02x", bytes[start + j]); - } - System.out.printf("\n"); - } - - /* - * Write target memory - */ - public void write_memory(int address, byte[] bytes, int start, int len) { - ensure_debug_mode(); -// dump_memory("write_memory", address, bytes, start, len); - printf("O %x %x\n", len, address); - for (int i = 0; i < len; i++) - printf("%02x", bytes[start + i]); - } - - public void write_memory(int address, byte[] bytes) { - write_memory(address, bytes, 0, bytes.length); - } - - /* - * Read target memory - */ - public byte[] read_memory(int address, int length) - throws IOException, InterruptedException { - byte[] data = new byte[length]; - - flush_input(); - ensure_debug_mode(); - printf("I %x %x\n", length, address); - int i = 0; - int start = 0; - while (i < length) { - String line = get_reply().trim(); - if (!Altos.ishex(line) || line.length() % 2 != 0) - throw new IOException( - String.format - ("Invalid reply \"%s\"", line)); - int this_time = line.length() / 2; - for (int j = 0; j < this_time; j++) - data[start + j] = (byte) ((Altos.fromhex(line.charAt(j*2)) << 4) + - Altos.fromhex(line.charAt(j*2+1))); - start += this_time; - i += this_time; - } -// dump_memory("read_memory", address, data, 0, length); - - return data; - } - - /* - * Write raw bytes to the debug link using the 'P' command - */ - public void write_bytes(byte[] bytes) throws IOException { - int i = 0; - ensure_debug_mode(); - while (i < bytes.length) { - int this_time = bytes.length - i; - if (this_time > 8) - this_time = 0; - printf("P"); - for (int j = 0; j < this_time; j++) - printf(" %02x", bytes[i+j]); - printf("\n"); - i += this_time; - } - } - - public void write_byte(byte b) throws IOException { - byte[] bytes = { b }; - write_bytes(bytes); - } - - /* - * Read raw bytes from the debug link using the 'G' command - */ - public byte[] read_bytes(int length) - throws IOException, InterruptedException { - - flush_input(); - ensure_debug_mode(); - printf("G %x\n", length); - int i = 0; - byte[] data = new byte[length]; - while (i < length) { - String line = get_reply(); - - if (line == null) - throw new IOException("Timeout in read_bytes"); - line = line.trim(); - String tokens[] = line.split("\\s+"); - for (int j = 0; j < tokens.length; j++) { - if (!Altos.ishex(tokens[j]) || - tokens[j].length() != 2) - throw new IOException( - String.format - ("Invalid read_bytes reply \"%s\"", line)); - try { - if (i + j >= length) - throw new IOException( - String.format - ("Invalid read_bytes reply \"%s\"", line)); - else - data[i + j] = (byte) Integer.parseInt(tokens[j], 16); - } catch (NumberFormatException ne) { - throw new IOException( - String.format - ("Invalid read_bytes reply \"%s\"", line)); - } - } - i += tokens.length; - } - return data; - } - - public byte read_byte() throws IOException, InterruptedException { - return read_bytes(1)[0]; - } - - public byte debug_instr(byte[] instruction) throws IOException, InterruptedException { - byte[] command = new byte[1 + instruction.length]; - command[0] = DEBUG_INSTR((byte) instruction.length); - for (int i = 0; i < instruction.length; i++) - command[i+1] = instruction[i]; - write_bytes(command); - return read_byte(); - } - - public byte resume() throws IOException, InterruptedException { - write_byte(RESUME); - return read_byte(); - } - - public int read_uint16() throws IOException, InterruptedException { - byte[] d = read_bytes(2); - return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff); - } - - public int read_uint8() throws IOException, InterruptedException { - byte[] d = read_bytes(1); - return (int) (d[0] & 0xff); - } - - public int get_chip_id() throws IOException, InterruptedException { - write_byte(GET_CHIP_ID); - return read_uint16(); - } - - public int get_pc() throws IOException, InterruptedException { - write_byte(GET_PC); - return read_uint16(); - } - - public byte read_status() throws IOException, InterruptedException { - write_byte(READ_STATUS); - return read_byte(); - } - - static final byte LJMP = 0x02; - - public void set_pc(int pc) throws IOException, InterruptedException { - byte high = (byte) (pc >> 8); - byte low = (byte) pc; - byte[] jump_mem = { LJMP, high, low }; - debug_instr(jump_mem); - } - - public boolean check_connection() throws IOException, InterruptedException { - byte reply = read_status(); - if ((reply & STATUS_CHIP_ERASE_DONE) == 0) - return false; - if ((reply & STATUS_PCON_IDLE) != 0) - return false; - if ((reply & STATUS_POWER_MODE_0) == 0) - return false; - return true; - } - - public AltosRomconfig romconfig() { - try { - byte[] bytes = read_memory(0xa0, 10); - return new AltosRomconfig(bytes, 0); - } catch (IOException ie) { - } catch (InterruptedException ie) { - } - return new AltosRomconfig(); - } - - /* - * Reset target - */ - public void reset() { - printf ("R\n"); - } - - public AltosDebug (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { - super(in_device); - } -} \ No newline at end of file diff --git a/altosui/AltosFlash.java b/altosui/AltosFlash.java index 239d4dd7..b409a611 100644 --- a/altosui/AltosFlash.java +++ b/altosui/AltosFlash.java @@ -20,6 +20,7 @@ package altosui; import java.awt.event.*; import javax.swing.*; import java.io.*; +import org.altusmetrum.altoslib_1.*; import org.altusmetrum.altosuilib_1.*; public class AltosFlash { @@ -362,7 +363,7 @@ public class AltosFlash { file = in_file; debug_dongle = in_debug_dongle; if (debug_dongle != null) - debug = new AltosDebug(in_debug_dongle); + debug = new AltosDebug(new AltosSerial(in_debug_dongle)); input = new FileInputStream(file); image = new AltosHexfile(input); if (debug != null && !debug.check_connection()) { diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index f26a3916..e5176278 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -23,6 +23,7 @@ import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.io.*; import java.util.concurrent.*; +import org.altusmetrum.altoslib_1.*; import org.altusmetrum.altosuilib_1.*; public class AltosFlashUI diff --git a/altosui/AltosHexfile.java b/altosui/AltosHexfile.java deleted file mode 100644 index 625c5ba1..00000000 --- a/altosui/AltosHexfile.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; - -import java.io.*; -import java.util.LinkedList; -import java.util.Arrays; - -class HexFileInputStream extends PushbackInputStream { - public int line; - - public HexFileInputStream(FileInputStream o) { - super(new BufferedInputStream(o)); - line = 1; - } - - public int read() throws IOException { - int c = super.read(); - if (c == '\n') - line++; - return c; - } - - public void unread(int c) throws IOException { - if (c == '\n') - line--; - if (c != -1) - super.unread(c); - } -} - -class HexRecord implements Comparable { - public int address; - public int type; - public byte checksum; - public byte[] data; - - static final int NORMAL = 0; - static final int EOF = 1; - static final int EXTENDED_ADDRESS = 2; - - enum read_state { - marker, - length, - address, - type, - data, - checksum, - newline, - white, - done, - } - - boolean ishex(int c) { - if ('0' <= c && c <= '9') - return true; - if ('a' <= c && c <= 'f') - return true; - if ('A' <= c && c <= 'F') - return true; - return false; - } - - boolean isspace(int c) { - switch (c) { - case ' ': - case '\t': - return true; - } - return false; - } - - int fromhex(int c) { - if ('0' <= c && c <= '9') - return c - '0'; - if ('a' <= c && c <= 'f') - return c - 'a' + 10; - if ('A' <= c && c <= 'F') - return c - 'A' + 10; - return -1; - } - - public byte checksum() { - byte got = 0; - - got += data.length; - got += (address >> 8) & 0xff; - got += (address ) & 0xff; - got += type; - for (int i = 0; i < data.length; i++) - got += data[i]; - return (byte) (-got); - } - - public int compareTo(Object other) { - HexRecord o = (HexRecord) other; - return address - o.address; - } - - public String toString() { - return String.format("%04x: %02x (%d)", address, type, data.length); - } - - public HexRecord(HexFileInputStream input) throws IOException { - read_state state = read_state.marker; - int nhexbytes = 0; - int hex = 0; - int ndata = 0; - byte got_checksum; - - while (state != read_state.done) { - int c = input.read(); - if (c < 0 && state != read_state.white) - throw new IOException(String.format("%d: Unexpected EOF", input.line)); - if (c == ' ') - continue; - switch (state) { - case marker: - if (c != ':') - throw new IOException("Missing ':'"); - state = read_state.length; - nhexbytes = 2; - hex = 0; - break; - case length: - case address: - case type: - case data: - case checksum: - if(!ishex(c)) - throw new IOException(String.format("Non-hex char '%c'", c)); - hex = hex << 4 | fromhex(c); - --nhexbytes; - if (nhexbytes != 0) - break; - - switch (state) { - case length: - data = new byte[hex]; - state = read_state.address; - nhexbytes = 4; - break; - case address: - address = hex; - state = read_state.type; - nhexbytes = 2; - break; - case type: - type = hex; - if (data.length > 0) - state = read_state.data; - else - state = read_state.checksum; - nhexbytes = 2; - ndata = 0; - break; - case data: - data[ndata] = (byte) hex; - ndata++; - nhexbytes = 2; - if (ndata == data.length) - state = read_state.checksum; - break; - case checksum: - checksum = (byte) hex; - state = read_state.newline; - break; - default: - break; - } - hex = 0; - break; - case newline: - if (c != '\n' && c != '\r') - throw new IOException("Missing newline"); - state = read_state.white; - break; - case white: - if (!isspace(c)) { - input.unread(c); - state = read_state.done; - } - break; - case done: - break; - } - } - got_checksum = checksum(); - if (got_checksum != checksum) - throw new IOException(String.format("Invalid checksum (read 0x%02x computed 0x%02x)\n", - checksum, got_checksum)); - } -} - -public class AltosHexfile { - public int address; - public byte[] data; - - public byte get_byte(int a) { - return data[a - address]; - } - - public AltosHexfile(FileInputStream file) throws IOException { - HexFileInputStream input = new HexFileInputStream(file); - LinkedList record_list = new LinkedList(); - boolean done = false; - - while (!done) { - HexRecord record = new HexRecord(input); - - if (record.type == HexRecord.EOF) - done = true; - else - record_list.add(record); - } - - long extended_addr = 0; - long base = 0xffffffff; - long bound = 0x00000000; - for (HexRecord record : record_list) { - switch (record.type) { - case 0: - long addr = extended_addr + record.address; - long r_bound = addr + record.data.length; - if (addr < base) - base = addr; - if (r_bound > bound) - bound = r_bound; - break; - case 1: - break; - case 2: - if (record.data.length != 2) - throw new IOException("invalid extended segment address record"); - extended_addr = ((record.data[0] << 8) + (record.data[1])) << 4; - break; - case 4: - if (record.data.length != 2) - throw new IOException("invalid extended segment address record"); - extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; - break; - default: - throw new IOException ("invalid hex record type"); - } - } - - if (base >= bound) - throw new IOException("invalid hex file"); - - if (bound - base > 4 * 1024 * 1024) - throw new IOException("hex file too large"); - - data = new byte[(int) (bound - base)]; - address = (int) base; - Arrays.fill(data, (byte) 0xff); - - /* Paint the records into the new array */ - for (HexRecord record : record_list) { - switch (record.type) { - case 0: - long addr = extended_addr + record.address; - long r_bound = addr + record.data.length; - for (int j = 0; j < record.data.length; j++) - data[(int) (addr - base) + j] = record.data[j]; - break; - case 1: - break; - case 2: - if (record.data.length != 2) - throw new IOException("invalid extended segment address record"); - extended_addr = ((record.data[0] << 8) + (record.data[1])) << 4; - break; - case 4: - if (record.data.length != 2) - throw new IOException("invalid extended segment address record"); - extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; - break; - default: - throw new IOException ("invalid hex record type"); - } - } - } -} \ No newline at end of file diff --git a/altosui/AltosRomconfig.java b/altosui/AltosRomconfig.java deleted file mode 100644 index 55056b5e..00000000 --- a/altosui/AltosRomconfig.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -package altosui; -import java.io.*; - -public class AltosRomconfig { - public boolean valid; - public int version; - public int check; - public int serial_number; - public int radio_calibration; - - static int get_int(byte[] bytes, int start, int len) { - int v = 0; - int o = 0; - while (len > 0) { - v = v | ((((int) bytes[start]) & 0xff) << o); - start++; - len--; - o += 8; - } - return v; - } - - static void put_int(int value, byte[] bytes, int start, int len) { - while (len > 0) { - bytes[start] = (byte) (value & 0xff); - start++; - len--; - value >>= 8; - } - } - - static void put_string(String value, byte[] bytes, int start) { - 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; - int string_num = 0; - - while (offset < bytes.length && bytes[offset] != 0) { - if (bytes[offset + 1] == AO_USB_DESC_STRING) { - ++string_num; - if (string_num == 4) - break; - } - offset += ((int) bytes[offset]) & 0xff; - } - if (offset >= bytes.length || bytes[offset] == 0) - return; - int len = ((((int) bytes[offset]) & 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; - } - for (int i = 0; i < len; i++) { - bytes[offset + 2 + i*2] = (byte) s.charAt(i); - bytes[offset + 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; - } - } - } - - public AltosRomconfig(AltosHexfile hexfile) { - this(hexfile.data, 0xa0 - hexfile.address); - } - - public void write(byte[] bytes, int offset) 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); - 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; - } - } - - public void write (AltosHexfile hexfile) throws IOException { - write(hexfile.data, 0xa0 - hexfile.address); - AltosRomconfig check = new AltosRomconfig(hexfile); - if (!check.valid()) - throw new IOException("writing new rom config failed\n"); - } - - public AltosRomconfig(int in_serial_number, int in_radio_calibration) { - valid = true; - version = 1; - check = (~version & 0xffff); - serial_number = in_serial_number; - radio_calibration = in_radio_calibration; - } - - public boolean valid() { - return valid && serial_number != 0; - } - - public AltosRomconfig() { - valid = false; - } -} diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index cf4658af..909e72a0 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -20,6 +20,7 @@ package altosui; import java.awt.*; import java.awt.event.*; import javax.swing.*; +import org.altusmetrum.altoslib_1.*; import org.altusmetrum.altosuilib_1.*; public class AltosRomconfigUI diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 4bfef47c..56554697 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -30,7 +30,6 @@ altosui_JAVA = \ AltosConfigTDUI.java \ AltosCSV.java \ AltosCSVUI.java \ - AltosDebug.java \ AltosDescent.java \ AltosDeviceUIDialog.java \ AltosDisplayThread.java \ @@ -50,7 +49,6 @@ altosui_JAVA = \ AltosFlightStatusUpdate.java \ AltosFlightUI.java \ AltosFreqList.java \ - AltosHexfile.java \ Altos.java \ AltosIdleMonitorUI.java \ AltosIgniteUI.java \ @@ -63,7 +61,6 @@ altosui_JAVA = \ AltosLights.java \ AltosPad.java \ AltosUIPreferencesBackend.java \ - AltosRomconfig.java \ AltosRomconfigUI.java \ AltosScanUI.java \ AltosSerial.java \