diff options
Diffstat (limited to 'ao-tools')
| -rw-r--r-- | ao-tools/altosui/AltosConfigUI.java | 21 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosDebug.java | 298 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosFlash.java | 333 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosFlashUI.java | 205 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosHexfile.java | 252 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosRomconfig.java | 107 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosRomconfigUI.java | 160 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosSerial.java | 8 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosUI.java | 14 | ||||
| -rw-r--r-- | ao-tools/altosui/Makefile | 6 | ||||
| -rw-r--r-- | ao-tools/altosui/Manifest.txt | 2 | ||||
| -rw-r--r-- | ao-tools/ao-dumplog/ao-dumplog.c | 4 | ||||
| -rw-r--r-- | ao-tools/libaltos/libaltos.c | 121 | 
13 files changed, 1482 insertions, 49 deletions
| diff --git a/ao-tools/altosui/AltosConfigUI.java b/ao-tools/altosui/AltosConfigUI.java index 1d8c579a..605ccc8b 100644 --- a/ao-tools/altosui/AltosConfigUI.java +++ b/ao-tools/altosui/AltosConfigUI.java @@ -44,7 +44,10 @@ import altosui.AltosFlightInfoTableModel;  import libaltosJNI.*; -public class AltosConfigUI extends JDialog implements ActionListener, ItemListener, DocumentListener { +public class AltosConfigUI +	extends JDialog +	implements ActionListener, ItemListener, DocumentListener +{  	Container	pane;  	Box		box; @@ -144,6 +147,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		c.fill = GridBagConstraints.NONE;  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = il; +		c.ipady = 5;  		version_label = new JLabel("Software version:");  		pane.add(version_label, c); @@ -154,6 +158,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		c.weightx = 1;  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = ir; +		c.ipady = 5;  		version_value = new JLabel("");  		pane.add(version_value, c); @@ -164,6 +169,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		c.fill = GridBagConstraints.NONE;  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = il; +		c.ipady = 5;  		serial_label = new JLabel("Serial:");  		pane.add(serial_label, c); @@ -174,6 +180,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		c.weightx = 1;  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = ir; +		c.ipady = 5;  		serial_value = new JLabel("");  		pane.add(serial_value, c); @@ -184,7 +191,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		c.fill = GridBagConstraints.NONE;  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = il; -		c.ipady = 3; +		c.ipady = 5;  		main_deploy_label = new JLabel("Main Deploy Altitude(m):");  		pane.add(main_deploy_label, c); @@ -275,7 +282,7 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		/* Buttons */  		c = new GridBagConstraints();  		c.gridx = 0; c.gridy = 7; -		c.gridwidth = 2; +		c.gridwidth = 6;  		c.fill = GridBagConstraints.NONE;  		c.anchor = GridBagConstraints.LINE_START;  		c.insets = il; @@ -285,8 +292,8 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		save.setActionCommand("save");  		c = new GridBagConstraints(); -		c.gridx = 2; c.gridy = 7; -		c.gridwidth = 2; +		c.gridx = 0; c.gridy = 7; +		c.gridwidth = 6;  		c.fill = GridBagConstraints.NONE;  		c.anchor = GridBagConstraints.CENTER;  		c.insets = il; @@ -296,8 +303,8 @@ public class AltosConfigUI extends JDialog implements ActionListener, ItemListen  		reset.setActionCommand("reset");  		c = new GridBagConstraints(); -		c.gridx = 4; c.gridy = 7; -		c.gridwidth = 2; +		c.gridx = 0; c.gridy = 7; +		c.gridwidth = 6;  		c.fill = GridBagConstraints.NONE;  		c.anchor = GridBagConstraints.LINE_END;  		c.insets = il; diff --git a/ao-tools/altosui/AltosDebug.java b/ao-tools/altosui/AltosDebug.java new file mode 100644 index 00000000..83ea5bcb --- /dev/null +++ b/ao-tools/altosui/AltosDebug.java @@ -0,0 +1,298 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * 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.lang.*; +import java.io.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.LinkedList; +import java.util.Iterator; +import altosui.AltosSerial; +import altosui.AltosRomconfig; + +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; + + +	static 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; +	} + +	static boolean ishex(String s) { +		for (int i = 0; i < s.length(); i++) +			if (!ishex(s.charAt(i))) +				return false; +		return true; +	} +	static boolean isspace(int c) { +		switch (c) { +		case ' ': +		case '\t': +			return true; +		} +		return false; +	} + +	static 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; +	} + +	boolean	debug_mode; + +	void ensure_debug_mode() { +		if (!debug_mode) { +			printf("D\n"); +			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_reply(); +		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 (!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) ((fromhex(line.charAt(j*2)) << 4) + +						  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_reply(); +		ensure_debug_mode(); +		printf("G %x\n", length); +		int i = 0; +		byte[] data = new byte[length]; +		while (i < length) { +			String line = get_reply().trim(); +			String tokens[] = line.split("\\s+"); +			for (int j = 0; j < tokens.length; j++) { +				if (!ishex(tokens[j]) || +				    tokens[j].length() != 2) +					throw new IOException( +						String.format +						("Invalid read_bytes reply \"%s\"", line)); +				try { +					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"); +	} +}
\ No newline at end of file diff --git a/ao-tools/altosui/AltosFlash.java b/ao-tools/altosui/AltosFlash.java new file mode 100644 index 00000000..0f92d6e7 --- /dev/null +++ b/ao-tools/altosui/AltosFlash.java @@ -0,0 +1,333 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * 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.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +import altosui.AltosHexfile; + +public class AltosFlash { +	File		file; +	FileInputStream	input; +	AltosHexfile	image; +	JFrame		frame; +	AltosDevice	debug_dongle; +	AltosDebug	debug; +	AltosRomconfig	rom_config; +	ActionListener	listener; +	boolean		aborted; + +	static final byte MOV_direct_data	= (byte) 0x75; +	static final byte MOV_DPTR_data16	= (byte) 0x90; +	static final byte MOV_A_data		= (byte) 0x74; +	static final byte MOVX_atDPTR_A		= (byte) 0xf0; +	static final byte MOVX_A_atDPTR	        = (byte) 0xe0; +	static final byte INC_DPTR		= (byte) 0xa3; +	static final byte TRAP			= (byte) 0xa5; + +	static final byte JB			= (byte) 0x20; + +	static final byte MOV_A_direct		= (byte) 0xe5; +	static final byte MOV_direct1_direct2	= (byte) 0x85; +	static final byte MOV_direct_A		= (byte) 0xf5; +	static final byte MOV_R0_data		= (byte) (0x78 | 0); +	static final byte MOV_R1_data		= (byte) (0x78 | 1); +	static final byte MOV_R2_data		= (byte) (0x78 | 2); +	static final byte MOV_R3_data		= (byte) (0x78 | 3); +	static final byte MOV_R4_data		= (byte) (0x78 | 4); +	static final byte MOV_R5_data		= (byte) (0x78 | 5); +	static final byte MOV_R6_data		= (byte) (0x78 | 6); +	static final byte MOV_R7_data		= (byte) (0x78 | 7); +	static final byte DJNZ_R0_rel		= (byte) (0xd8 | 0); +	static final byte DJNZ_R1_rel		= (byte) (0xd8 | 1); +	static final byte DJNZ_R2_rel		= (byte) (0xd8 | 2); +	static final byte DJNZ_R3_rel		= (byte) (0xd8 | 3); +	static final byte DJNZ_R4_rel		= (byte) (0xd8 | 4); +	static final byte DJNZ_R5_rel		= (byte) (0xd8 | 5); +	static final byte DJNZ_R6_rel		= (byte) (0xd8 | 6); +	static final byte DJNZ_R7_rel		= (byte) (0xd8 | 7); + +	static final byte P1DIR			= (byte) 0xFE; +	static final byte P1			= (byte) 0x90; + +	/* flash controller */ +	static final byte FWT			= (byte) 0xAB; +	static final byte FADDRL		= (byte) 0xAC; +	static final byte FADDRH		= (byte) 0xAD; +	static final byte FCTL			= (byte) 0xAE; +	static final byte FCTL_BUSY		= (byte) 0x80; +	static final byte FCTL_BUSY_BIT		= (byte) 7; +	static final byte FCTL_SWBSY		= (byte) 0x40; +	static final byte FCTL_SWBSY_BIT	= (byte) 6; +	static final byte FCTL_CONTRD		= (byte) 0x10; +	static final byte FCTL_WRITE		= (byte) 0x02; +	static final byte FCTL_ERASE		= (byte) 0x01; +	static final byte FWDATA		= (byte) 0xAF; + +	static final byte ACC			= (byte) 0xE0; + +	/* offsets within the flash_page program */ +	static final int FLASH_ADDR_HIGH	= 8; +	static final int FLASH_ADDR_LOW		= 11; +	static final int RAM_ADDR_HIGH		= 13; +	static final int RAM_ADDR_LOW		= 14; +	static final int FLASH_WORDS_HIGH	= 16; +	static final int FLASH_WORDS_LOW	= 18; +	static final int FLASH_TIMING		= 21; + +	/* sleep mode control */ +	static final int SLEEP			= (byte) 0xbe; +	static final int  SLEEP_USB_EN		= (byte) 0x80; +	static final int  SLEEP_XOSC_STB	= (byte) 0x40; +	static final int  SLEEP_HFRC_STB	= (byte) 0x20; +	static final int  SLEEP_RST_MASK	= (byte) 0x18; +	static final int   SLEEP_RST_POWERON	= (byte) 0x00; +	static final int   SLEEP_RST_EXTERNAL	= (byte) 0x10; +	static final int   SLEEP_RST_WATCHDOG	= (byte) 0x08; +	static final int  SLEEP_OSC_PD		= (byte) 0x04; +	static final int  SLEEP_MODE_MASK	= (byte) 0x03; +	static final int   SLEEP_MODE_PM0	= (byte) 0x00; +	static final int   SLEEP_MODE_PM1	= (byte) 0x01; +	static final int   SLEEP_MODE_PM2	= (byte) 0x02; +	static final int   SLEEP_MODE_PM3	= (byte) 0x03; + +	/* clock controller */ +	static final byte CLKCON		= (byte) 0xC6; +	static final byte  CLKCON_OSC32K	= (byte) 0x80; +	static final byte  CLKCON_OSC		= (byte) 0x40; +	static final byte  CLKCON_TICKSPD	= (byte) 0x38; +	static final byte  CLKCON_CLKSPD	= (byte) 0x07; + +	static final byte[] flash_page_proto = { + +		MOV_direct_data, P1DIR, (byte) 0x02, +		MOV_direct_data, P1,	(byte) 0xFF, + +		MOV_direct_data, FADDRH, 0,	/* FLASH_ADDR_HIGH */ + +		MOV_direct_data, FADDRL, 0,	/* FLASH_ADDR_LOW */ + +		MOV_DPTR_data16, 0, 0,		/* RAM_ADDR_HIGH, RAM_ADDR_LOW */ + +		MOV_R7_data, 0,			/* FLASH_WORDS_HIGH */ + +		MOV_R6_data, 0,			/* FLASH_WORDS_LOW */ + + +		MOV_direct_data, FWT, 0x20,	/* FLASH_TIMING */ + +		MOV_direct_data, FCTL, FCTL_ERASE, +/* eraseWaitLoop: */ +		MOV_A_direct,		FCTL, +		JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb, + +		MOV_direct_data, P1, (byte) 0xfd, + +		MOV_direct_data, FCTL, FCTL_WRITE, +/* writeLoop: */ +		MOV_R5_data, 2, +/* writeWordLoop: */ +		MOVX_A_atDPTR, +		INC_DPTR, +		MOV_direct_A, FWDATA, +		DJNZ_R5_rel, (byte) 0xfa,		/* writeWordLoop */ +/* writeWaitLoop: */ +		MOV_A_direct, FCTL, +		JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb,	/* writeWaitLoop */ +		DJNZ_R6_rel, (byte) 0xf1,		/* writeLoop */ +		DJNZ_R7_rel, (byte) 0xef,			/* writeLoop */ + +		MOV_direct_data, P1DIR, (byte) 0x00, +		MOV_direct_data, P1,	(byte) 0xFF, +		TRAP, +	}; + +	public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) { +		int flash_word_addr = flash_addr >> 1; +		int flash_word_count = ((byte_count + 1) >> 1); + +		byte[] flash_page = new byte[flash_page_proto.length]; +		for (int i = 0; i < flash_page.length; i++) +			flash_page[i] = flash_page_proto[i]; + +		flash_page[FLASH_ADDR_HIGH]  = (byte) (flash_word_addr >> 8); +		flash_page[FLASH_ADDR_LOW]   = (byte) (flash_word_addr); +		flash_page[RAM_ADDR_HIGH]    = (byte) (ram_addr >> 8); +		flash_page[RAM_ADDR_LOW]     = (byte) (ram_addr); + +		byte flash_words_low = (byte) (flash_word_count); +		byte flash_words_high = (byte) (flash_word_count >> 8); +		/* the flashing code has a minor 'bug' */ +		if (flash_words_low != 0) +			flash_words_high++; + +		flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high; +		flash_page[FLASH_WORDS_LOW]  = (byte) flash_words_low; +		return flash_page; +	} + +	static byte[] set_clkcon_fast = { +		MOV_direct_data, CLKCON, 0x00 +	}; + +	static byte[] get_sleep = { +		MOV_A_direct, SLEEP +	}; + +	public void clock_init() throws IOException, InterruptedException { +		debug.debug_instr(set_clkcon_fast); + +		byte	status; +		do { +			status = debug.debug_instr(get_sleep); +		} while ((status & SLEEP_XOSC_STB) == 0); +	} + +	void action(String s, int percent) { +		if (listener != null && !aborted) +			listener.actionPerformed(new ActionEvent(this, +								 percent, +								 s)); +	} + +	void action(int part, int total) { +		int percent = 100 * part / total; +		action(String.format("%d/%d (%d%%)", +				     part, total, percent), +		       percent); +	} + +	public void flash() throws IOException, FileNotFoundException, InterruptedException { +		if (!check_rom_config()) +			throw new IOException("Invalid rom config settings"); +		if (image.address + image.data.length > 0x8000) +			throw new IOException(String.format("Flash image too long %d", +							    image.address + +							    image.data.length)); +		if ((image.address & 0x3ff) != 0) +			throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)", +							    image.address)); +		int ram_address = 0xf000; +		int flash_prog = 0xf400; + +		/* +		 * Store desired config values into image +		 */ +		rom_config.write(image); +		/* +		 * Bring up the clock +		 */ +		clock_init(); + +		int remain = image.data.length; +		int flash_addr = image.address; +		int image_start = 0; + +		action(0, image.data.length); +		while (remain > 0 && !aborted) { +			int this_time = remain; +			if (this_time > 0x400) +				this_time = 0x400; + +			/* write the data */ +			debug.write_memory(ram_address, image.data, +					   image_start, this_time); + +			/* write the flash program */ +			byte[] flash_page = make_flash_page(flash_addr, +							    ram_address, +							    this_time); +			debug.write_memory(flash_prog, flash_page); + +			debug.set_pc(flash_prog); +			int pc = debug.get_pc(); +			debug.resume(); +			Thread.sleep(100); +			for (int times = 0; times < 10; times++) { +				byte status = debug.read_status(); +				if ((status & AltosDebug.STATUS_CPU_HALTED) != 0) +					break; +				Thread.sleep(100); +			} + +			byte[] check = debug.read_memory(flash_addr, this_time); +			for (int i = 0; i < this_time; i++) +				if (check[i] != image.data[image_start + i]) +					throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)", +									    image.address + image_start + i, +									    check[i], image.data[image_start + i])); +			remain -= this_time; +			flash_addr += this_time; +			image_start += this_time; + +			action(image.data.length - remain, image.data.length); +		} +		if (!aborted) { +			action("done", 100); +			debug.set_pc(image.address); +			debug.resume(); +		} +		debug.close(); +	} + +	public void abort() { +		aborted = true; +		debug.close(); +	} + +	public void addActionListener(ActionListener l) { +		listener = l; +	} + +	public boolean check_rom_config() { +		if (rom_config == null) +			rom_config = debug.romconfig(); +		return rom_config != null && rom_config.valid(); +	} + +	public void set_romconfig (AltosRomconfig romconfig) { +		rom_config = romconfig; +	} + +	public AltosRomconfig romconfig() { +		return rom_config; +	} + +	public void open() throws IOException, FileNotFoundException, InterruptedException { +		input = new FileInputStream(file); +		image = new AltosHexfile(input); +		debug.open(debug_dongle); +		if (!debug.check_connection()) +			throw new IOException("Debug port not connected"); +	} + +	public AltosFlash(File in_file, AltosDevice in_debug_dongle) { +		file = in_file; +		debug_dongle = in_debug_dongle; +		debug = new AltosDebug(); +	} +}
\ No newline at end of file diff --git a/ao-tools/altosui/AltosFlashUI.java b/ao-tools/altosui/AltosFlashUI.java new file mode 100644 index 00000000..0c2041e3 --- /dev/null +++ b/ao-tools/altosui/AltosFlashUI.java @@ -0,0 +1,205 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * 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.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; +import java.util.concurrent.LinkedBlockingQueue; + +import altosui.AltosHexfile; +import altosui.AltosFlash; + +public class AltosFlashUI +	extends JDialog +	implements Runnable, ActionListener +{ +	Container	pane; +	Box		box; +	JLabel		serial_label; +	JLabel		serial_value; +	JLabel		file_label; +	JLabel		file_value; +	JProgressBar	pbar; +	JButton		cancel; + +	File		file; +	Thread		thread; +	JFrame		frame; +	AltosDevice	debug_dongle; +	AltosFlash	flash; + +	public void actionPerformed(ActionEvent e) { +		if (e.getSource() == cancel) { +			abort(); +			dispose(); +		} else { +			String	cmd = e.getActionCommand(); +			if (cmd.equals("done")) +				dispose(); +			else { +				pbar.setValue(e.getID()); +				pbar.setString(cmd); +			} +		} +	} + +	public void run() { +		flash = new AltosFlash(file, debug_dongle); +		flash.addActionListener(this); +		try { +			flash.open(); +			if (!flash.check_rom_config()) { +				AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame); +				romconfig_ui.showDialog(); +				AltosRomconfig romconfig = romconfig_ui.romconfig(); +				if (romconfig == null) +					return; +				flash.set_romconfig(romconfig); +			} +			serial_value.setText(String.format("%d", +							   flash.romconfig().serial_number)); +			file_value.setText(file.toString()); +			setVisible(true); +			flash.flash(); +		} catch (FileNotFoundException ee) { +			JOptionPane.showMessageDialog(frame, +						      "Cannot open image", +						      file.toString(), +						      JOptionPane.ERROR_MESSAGE); +			return; +		} catch (IOException e) { +			JOptionPane.showMessageDialog(frame, +						      e.getMessage(), +						      file.toString(), +						      JOptionPane.ERROR_MESSAGE); +			return; +		} catch (InterruptedException ie) { +		} +	} + +	public void abort() { +		if (flash != null) +			flash.abort(); +	} + +	public void build_dialog() { +		GridBagConstraints c; +		Insets il = new Insets(4,4,4,4); +		Insets ir = new Insets(4,4,4,4); + +		pane = getContentPane(); +		pane.setLayout(new GridBagLayout()); + +		c = new GridBagConstraints(); +		c.gridx = 0; c.gridy = 0; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		serial_label = new JLabel("Serial:"); +		pane.add(serial_label, c); + +		c = new GridBagConstraints(); +		c.gridx = 1; c.gridy = 0; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		serial_value = new JLabel(""); +		pane.add(serial_value, c); + +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.NONE; +		c.gridx = 0; c.gridy = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		file_label = new JLabel("File:"); +		pane.add(file_label, c); + +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.gridx = 1; c.gridy = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		file_value = new JLabel(""); +		pane.add(file_value, c); + +		pbar = new JProgressBar(); +		pbar.setMinimum(0); +		pbar.setMaximum(100); +		pbar.setValue(0); +		pbar.setString(""); +		pbar.setStringPainted(true); +		pbar.setPreferredSize(new Dimension(600, 20)); +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.HORIZONTAL; +		c.anchor = GridBagConstraints.CENTER; +		c.gridx = 0; c.gridy = 2; +		c.gridwidth = GridBagConstraints.REMAINDER; +		Insets ib = new Insets(4,4,4,4); +		c.insets = ib; +		pane.add(pbar, c); + +		cancel = new JButton("Cancel"); +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.CENTER; +		c.gridx = 0; c.gridy = 3; +		c.gridwidth = GridBagConstraints.REMAINDER; +		Insets ic = new Insets(4,4,4,4); +		c.insets = ic; +		pane.add(cancel, c); +		cancel.addActionListener(this); +		pack(); +		setLocationRelativeTo(frame); +	} + +	public AltosFlashUI(JFrame in_frame) { +		super(in_frame, "Program Altusmetrum Device", false); + +		frame = in_frame; + +		build_dialog(); + +		debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.Any); + +		if (debug_dongle == null) +			return; + +		JFileChooser	hexfile_chooser = new JFileChooser(); + +		hexfile_chooser.setDialogTitle("Select Flash Image"); +		hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx")); +		int returnVal = hexfile_chooser.showOpenDialog(frame); + +		if (returnVal != JFileChooser.APPROVE_OPTION) +			return; + +		file = hexfile_chooser.getSelectedFile(); + +		thread = new Thread(this); +		thread.start(); +	} +}
\ No newline at end of file diff --git a/ao-tools/altosui/AltosHexfile.java b/ao-tools/altosui/AltosHexfile.java new file mode 100644 index 00000000..19e35ae1 --- /dev/null +++ b/ao-tools/altosui/AltosHexfile.java @@ -0,0 +1,252 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * 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.lang.*; +import java.io.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.LinkedList; +import java.util.Iterator; +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<HexRecord>	record_list = new LinkedList<HexRecord>(); +		boolean			done = false; + +		while (!done) { +			HexRecord	record = new HexRecord(input); + +			if (record.type == HexRecord.EOF) +				done = true; +			else +				record_list.add(record); +		} +		HexRecord[] records  = record_list.toArray(new HexRecord[0]); +		Arrays.sort(records); +		if (records.length > 0) { +			int	base = records[0].address; +			int	bound = records[records.length-1].address + +				records[records.length-1].data.length; + +			data = new byte[bound - base]; +			address = base; +			Arrays.fill(data, (byte) 0xff); + +			/* Paint the records into the new array */ +			for (int i = 0; i < records.length; i++) { +				for (int j = 0; j < records[i].data.length; j++) +					data[records[i].address - base + j] = records[i].data[j]; +			} +		} +	} +}
\ No newline at end of file diff --git a/ao-tools/altosui/AltosRomconfig.java b/ao-tools/altosui/AltosRomconfig.java new file mode 100644 index 00000000..844da7c4 --- /dev/null +++ b/ao-tools/altosui/AltosRomconfig.java @@ -0,0 +1,107 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * 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 altosui.AltosHexfile; + +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; +		} +	} + +	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 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 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); +		new AltosRomconfig(hexfile); +	} + +	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/ao-tools/altosui/AltosRomconfigUI.java b/ao-tools/altosui/AltosRomconfigUI.java new file mode 100644 index 00000000..21c34ef4 --- /dev/null +++ b/ao-tools/altosui/AltosRomconfigUI.java @@ -0,0 +1,160 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * 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.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.table.*; +import javax.swing.event.*; +import java.io.*; +import java.util.*; +import java.text.*; +import java.util.prefs.*; + +import altosui.AltosRomconfig; + +public class AltosRomconfigUI +	extends JDialog +	implements ActionListener +{ +	Container	pane; +	Box		box; +	JLabel		serial_label; +	JLabel		radio_calibration_label; + +	JFrame		owner; +	JTextField	serial_value; +	JTextField	radio_calibration_value; + +	JButton		ok; +	JButton		cancel; + +	/* Build the UI using a grid bag */ +	public AltosRomconfigUI(JFrame in_owner) { +		super (in_owner, "Configure TeleMetrum Rom Values", true); + +		owner = in_owner; +		GridBagConstraints c; + +		Insets il = new Insets(4,4,4,4); +		Insets ir = new Insets(4,4,4,4); + +		pane = getContentPane(); +		pane.setLayout(new GridBagLayout()); + +		/* Serial */ +		c = new GridBagConstraints(); +		c.gridx = 0; c.gridy = 0; +		c.gridwidth = 3; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		serial_label = new JLabel("Serial:"); +		pane.add(serial_label, c); + +		c = new GridBagConstraints(); +		c.gridx = 3; c.gridy = 0; +		c.gridwidth = 3; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		serial_value = new JTextField("0"); +		pane.add(serial_value, c); + +		/* Radio calibration value */ +		c = new GridBagConstraints(); +		c.gridx = 0; c.gridy = 1; +		c.gridwidth = 3; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		c.ipady = 5; +		radio_calibration_label = new JLabel("Radio Calibration:"); +		pane.add(radio_calibration_label, c); + +		c = new GridBagConstraints(); +		c.gridx = 3; c.gridy = 1; +		c.gridwidth = 3; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		c.ipady = 5; +		radio_calibration_value = new JTextField("1186611"); +		pane.add(radio_calibration_value, c); + +		/* Buttons */ +		c = new GridBagConstraints(); +		c.gridx = 0; c.gridy = 2; +		c.gridwidth = 3; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.CENTER; +		c.insets = il; +		ok = new JButton("OK"); +		pane.add(ok, c); +		ok.addActionListener(this); +		ok.setActionCommand("ok"); + +		c = new GridBagConstraints(); +		c.gridx = 3; c.gridy = 2; +		c.gridwidth = 3; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.CENTER; +		c.insets = il; +		cancel = new JButton("Cancel"); +		pane.add(cancel, c); +		cancel.addActionListener(this); +		cancel.setActionCommand("cancel"); + +		pack(); +		setLocationRelativeTo(owner); +	} + +	boolean	selected; + +	/* Listen for events from our buttons */ +	public void actionPerformed(ActionEvent e) { +		String	cmd = e.getActionCommand(); + +		if (cmd.equals("ok")) +			selected = true; +		setVisible(false); +	} + +	int serial() { +		return Integer.parseInt(serial_value.getText()); +	} + +	int radio_calibration() { +		return Integer.parseInt(radio_calibration_value.getText()); +	} + +	public AltosRomconfig romconfig() { +		return new AltosRomconfig(serial(), radio_calibration()); +	} + +	public AltosRomconfig showDialog() { +		setVisible(true); +		if (selected) +			return romconfig(); +		return null; +	} +} diff --git a/ao-tools/altosui/AltosSerial.java b/ao-tools/altosui/AltosSerial.java index ba00b55e..d02e25a9 100644 --- a/ao-tools/altosui/AltosSerial.java +++ b/ao-tools/altosui/AltosSerial.java @@ -79,8 +79,14 @@ public class AltosSerial implements Runnable {  		}  	} +	public void flush_reply() { +		reply_queue.clear(); +	} +  	public String get_reply() throws InterruptedException { -		return reply_queue.take(); +		libaltos.altos_flush(altos); +		String line = reply_queue.take(); +		return line;  	}  	public void add_monitor(LinkedBlockingQueue<String> q) { diff --git a/ao-tools/altosui/AltosUI.java b/ao-tools/altosui/AltosUI.java index 49d1f11a..9fd47ea7 100644 --- a/ao-tools/altosui/AltosUI.java +++ b/ao-tools/altosui/AltosUI.java @@ -41,6 +41,7 @@ import altosui.AltosVoice;  import altosui.AltosFlightStatusTableModel;  import altosui.AltosFlightInfoTableModel;  import altosui.AltosChannelMenu; +import altosui.AltosFlashUI;  import libaltosJNI.*; @@ -457,6 +458,11 @@ public class AltosUI extends JFrame {  	void ConfigureTeleMetrum() {  		new AltosConfig(AltosUI.this);  	} + +	void FlashImage() { +		new AltosFlashUI(AltosUI.this); +	} +  	/*  	 * Open an existing telemetry file and replay it in realtime  	 */ @@ -589,6 +595,14 @@ public class AltosUI extends JFrame {  				});  			menu.add(item); +			item = new JMenuItem("Flash Image",KeyEvent.VK_F); +			item.addActionListener(new ActionListener() { +					public void actionPerformed(ActionEvent e) { +						FlashImage(); +					} +				}); +			menu.add(item); +  			item = new JMenuItem("Quit",KeyEvent.VK_Q);  			item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,  								   ActionEvent.CTRL_MASK)); diff --git a/ao-tools/altosui/Makefile b/ao-tools/altosui/Makefile index 63359fbb..d4d3ee7a 100644 --- a/ao-tools/altosui/Makefile +++ b/ao-tools/altosui/Makefile @@ -8,15 +8,19 @@ CLASSFILES=\  	AltosConfigUI.class \  	AltosConvert.class \  	AltosCSV.class \ +	AltosDebug.class \  	AltosEepromDownload.class \  	AltosEepromMonitor.class \  	AltosEepromReader.class \  	AltosEepromRecord.class \  	AltosFile.class \ +	AltosFlash.class \ +	AltosFlashUI.class \  	AltosFlightInfoTableModel.class \  	AltosFlightStatusTableModel.class \  	AltosGPS.class \  	AltosGreatCircle.class \ +	AltosHexfile.class \  	AltosLog.class \  	AltosParse.class \  	AltosPreferences.class \ @@ -29,6 +33,8 @@ CLASSFILES=\  	AltosUI.class \  	AltosDevice.class \  	AltosDeviceDialog.class \ +	AltosRomconfig.class \ +	AltosRomconfigUI.class \  	AltosVoice.class  #FREETTSSRC=/home/keithp/src/freetts/freetts-1.2.2 diff --git a/ao-tools/altosui/Manifest.txt b/ao-tools/altosui/Manifest.txt index 504d0de3..251ce2a0 100644 --- a/ao-tools/altosui/Manifest.txt +++ b/ao-tools/altosui/Manifest.txt @@ -1,2 +1,2 @@  Main-Class: altosui.AltosUI -Class-Path: /usr/share/java/freetts.jar +Class-Path: freetts.jar diff --git a/ao-tools/ao-dumplog/ao-dumplog.c b/ao-tools/ao-dumplog/ao-dumplog.c index 57c43290..6d4fa5bf 100644 --- a/ao-tools/ao-dumplog/ao-dumplog.c +++ b/ao-tools/ao-dumplog/ao-dumplog.c @@ -29,7 +29,7 @@  static const struct option options[] = {  	{ .name = "tty", .has_arg = 1, .val = 'T' },  	{ .name = "device", .has_arg = 1, .val = 'D' }, -	{ .name = "remote", .has_arg = 1, .val = 'R' }, +	{ .name = "remote", .has_arg = 0, .val = 'R' },  	{ .name = "channel", .has_arg = 1, .val = 'C' },  	{ 0, 0, 0, 0},  }; @@ -91,7 +91,7 @@ main (int argc, char **argv)  	int		invalid;  	char		serial_line[8192]; -	while ((c = getopt_long(argc, argv, "T:D:R", options, NULL)) != -1) { +	while ((c = getopt_long(argc, argv, "T:D:C:R", options, NULL)) != -1) {  		switch (c) {  		case 'T':  			tty = optarg; diff --git a/ao-tools/libaltos/libaltos.c b/ao-tools/libaltos/libaltos.c index 3e8485e4..ffdb2366 100644 --- a/ao-tools/libaltos/libaltos.c +++ b/ao-tools/libaltos/libaltos.c @@ -448,16 +448,20 @@ altos_list_finish(struct altos_list *list)  #include <fcntl.h>  #include <termios.h>  #include <errno.h> +#include <pthread.h>  #define USB_BUF_SIZE	64  struct altos_file {  	int				fd; +	int				pipe[2];  	unsigned char			out_data[USB_BUF_SIZE];  	int				out_used;  	unsigned char			in_data[USB_BUF_SIZE];  	int				in_used;  	int				in_read; +	pthread_mutex_t			putc_mutex; +	pthread_mutex_t			getc_mutex;  };  struct altos_file * @@ -470,6 +474,7 @@ altos_open(struct altos_device *device)  	if (!file)  		return NULL; +	pipe(file->pipe);  	file->fd = open(device->path, O_RDWR | O_NOCTTY);  	if (file->fd < 0) {  		perror(device->path); @@ -484,8 +489,8 @@ altos_open(struct altos_device *device)  		return NULL;  	}  	cfmakeraw(&term); -	term.c_cc[VMIN] = 0; -	term.c_cc[VTIME] = 1; +	term.c_cc[VMIN] = 1; +	term.c_cc[VTIME] = 0;  	ret = tcsetattr(file->fd, TCSAFLUSH, &term);  	if (ret < 0) {  		perror("tcsetattr"); @@ -493,6 +498,8 @@ altos_open(struct altos_device *device)  		free(file);  		return NULL;  	} +	pthread_mutex_init(&file->putc_mutex,NULL); +	pthread_mutex_init(&file->getc_mutex,NULL);  	return file;  } @@ -500,8 +507,10 @@ void  altos_close(struct altos_file *file)  {  	if (file->fd != -1) { -		close(file->fd); +		int	fd = file->fd;  		file->fd = -1; +		write(file->pipe[1], "\r", 1); +		close(fd);  	}  } @@ -512,68 +521,104 @@ altos_free(struct altos_file *file)  	free(file);  } +static int +_altos_flush(struct altos_file *file) +{ +	while (file->out_used) { +		int	ret; + +		if (file->fd < 0) +			return -EBADF; +		fflush(stdout); +		ret = write (file->fd, file->out_data, file->out_used); +		if (ret < 0) +			return -errno; +		if (ret) { +			memmove(file->out_data, file->out_data + ret, +				file->out_used - ret); +			file->out_used -= ret; +		} +	} +} +  int  altos_putchar(struct altos_file *file, char c)  {  	int	ret; +	pthread_mutex_lock(&file->putc_mutex);  	if (file->out_used == USB_BUF_SIZE) { -		ret = altos_flush(file); -		if (ret) +		ret = _altos_flush(file); +		if (ret) { +			pthread_mutex_unlock(&file->putc_mutex);  			return ret; +		}  	}  	file->out_data[file->out_used++] = c; +	ret = 0;  	if (file->out_used == USB_BUF_SIZE) -		return altos_flush(file); +		ret = _altos_flush(file); +	pthread_mutex_unlock(&file->putc_mutex);  	return 0;  }  int  altos_flush(struct altos_file *file)  { -	while (file->out_used) { -		int	ret; - -		if (file->fd < 0) -			return -EBADF; -		ret = write (file->fd, file->out_data, file->out_used); -		if (ret < 0) -			return -errno; -		if (ret) { -			memmove(file->out_data, file->out_data + ret, -				file->out_used - ret); -			file->out_used -= ret; -		} -	} +	int ret; +	pthread_mutex_lock(&file->putc_mutex); +	ret = _altos_flush(file); +	pthread_mutex_unlock(&file->putc_mutex); +	return ret;  } +  #include <poll.h>  int  altos_getchar(struct altos_file *file, int timeout)  { -	while (file->in_read == file->in_used) { -		int	ret; +	int		ret; +	struct pollfd	fd[2]; -		altos_flush(file); -		if (file->fd < 0) -			return -EBADF; -		if (timeout) { -			struct pollfd fd; -			int ret; -			fd.fd = file->fd; -			fd.events = POLLIN; -			ret = poll(&fd, 1, timeout); -			if (ret == 0) -				return LIBALTOS_TIMEOUT; +	if (timeout == 0) +		timeout = -1; +	pthread_mutex_lock(&file->getc_mutex); +	fd[0].fd = file->fd; +	fd[0].events = POLLIN; +	fd[1].fd = file->pipe[0]; +	fd[1].events = POLLIN; +	while (file->in_read == file->in_used) { +		if (file->fd < 0) { +			pthread_mutex_unlock(&file->getc_mutex); +			return LIBALTOS_ERROR;  		} -		ret = read(file->fd, file->in_data, USB_BUF_SIZE); -		if (ret < 0) +		altos_flush(file); + +		ret = poll(fd, 2, timeout); +		if (ret < 0) { +			perror("altos_getchar"); +			pthread_mutex_unlock(&file->getc_mutex);  			return LIBALTOS_ERROR; -		file->in_read = 0; -		file->in_used = ret; +		} +		if (ret == 0) { +			pthread_mutex_unlock(&file->getc_mutex); +			return LIBALTOS_TIMEOUT; +		} +		if (fd[0].revents & POLLIN) { +			ret = read(file->fd, file->in_data, USB_BUF_SIZE); +			if (ret < 0) { +				perror("altos_getchar"); +				pthread_mutex_unlock(&file->getc_mutex); +				return LIBALTOS_ERROR; +			} +			file->in_read = 0; +			file->in_used = ret; +		}  	} -	return file->in_data[file->in_read++]; +	ret = file->in_data[file->in_read++]; +	pthread_mutex_unlock(&file->getc_mutex); +	return ret;  }  #endif /* POSIX_TTY */ | 
