diff options
| -rw-r--r-- | ao-tools/Makefile.am | 2 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosDevice.java | 39 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosDeviceDialog.java | 14 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosDeviceLinux.java | 172 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosGPS.java | 4 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosSerial.java | 115 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosUI.java | 147 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosUIIcon.icns | bin | 0 -> 129010 bytes | |||
| -rw-r--r-- | ao-tools/altosui/AltosVoice.java | 4 | ||||
| -rw-r--r-- | ao-tools/altosui/Makefile | 41 | ||||
| -rw-r--r-- | ao-tools/altosui/Manifest.txt | 1 | ||||
| -rw-r--r-- | ao-tools/altosui/voices.txt | 1 | ||||
| -rw-r--r-- | ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui-contents.xml | 1 | ||||
| -rw-r--r-- | ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui.xml | 1 | ||||
| -rw-r--r-- | ao-tools/libaltos/AltOS Package Configuration.pmdoc/index.xml | 1 | ||||
| -rw-r--r-- | ao-tools/libaltos/Makefile | 80 | ||||
| -rw-r--r-- | ao-tools/libaltos/cjnitest.c | 25 | ||||
| -rw-r--r-- | ao-tools/libaltos/libaltos.c | 825 | ||||
| -rw-r--r-- | ao-tools/libaltos/libaltos.h | 54 | ||||
| -rw-r--r-- | ao-tools/libaltos/libaltos.i0 | 5 | 
20 files changed, 1177 insertions, 355 deletions
| diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 2850e909..54dc777a 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view +SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view libaltos altosui diff --git a/ao-tools/altosui/AltosDevice.java b/ao-tools/altosui/AltosDevice.java index 66800c5c..0e7d01da 100644 --- a/ao-tools/altosui/AltosDevice.java +++ b/ao-tools/altosui/AltosDevice.java @@ -18,13 +18,38 @@  package altosui;  import java.lang.*;  import java.util.*; +import libaltosJNI.*; -public class AltosDevice { -	String	tty;	/* suitable to be passed to AltosSerial.connect */ -	String	manufacturer; -	String	product; -	int	serial; -	int	idProduct; -	int	idVendor; +public class AltosDevice extends altos_device { +	public String toString() { +		return String.format("%-20.20s %4d %s", +				     getProduct(), getSerial(), getPath()); +	} + +	static { +		System.loadLibrary("altos"); +		libaltos.altos_init(); +	} +	static AltosDevice[] list(String product) { +		SWIGTYPE_p_altos_list list = libaltos.altos_list_start(); + +		ArrayList<AltosDevice> device_list = new ArrayList<AltosDevice>(); +		if (list != null) { +			SWIGTYPE_p_altos_file file; + +			for (;;) { +				AltosDevice device = new AltosDevice(); +				if (libaltos.altos_list_next(list, device) == 0) +					break; +				device_list.add(device); +			} +			libaltos.altos_list_finish(list); +		} + +		AltosDevice[] devices = new AltosDevice[device_list.size()]; +		for (int i = 0; i < device_list.size(); i++) +			devices[i] = device_list.get(i); +		return devices; +	}  }
\ No newline at end of file diff --git a/ao-tools/altosui/AltosDeviceDialog.java b/ao-tools/altosui/AltosDeviceDialog.java index cb1eef8b..eb70877c 100644 --- a/ao-tools/altosui/AltosDeviceDialog.java +++ b/ao-tools/altosui/AltosDeviceDialog.java @@ -20,15 +20,17 @@ package altosui;  import java.lang.*;  import java.util.*;  import javax.swing.*; +import libaltosJNI.libaltos; +import libaltosJNI.altos_device; +import libaltosJNI.SWIGTYPE_p_altos_file; +import libaltosJNI.SWIGTYPE_p_altos_list;  import altosui.AltosDevice; -import altosui.AltosDeviceLinux;  public class AltosDeviceDialog { -	static AltosDevice show (JFrame frame, String product) { -		AltosDevice[]	devices = null; -		if (System.getProperty("os.name").startsWith("Linux")) -			devices = AltosDeviceLinux.list(product); +	static altos_device show (JFrame frame, String product) { +		AltosDevice[]	devices; +		devices = AltosDevice.list(product);  		if (devices != null & devices.length > 0) {  			Object o = JOptionPane.showInputDialog(frame,  							       "Select a device", @@ -37,7 +39,7 @@ public class AltosDeviceDialog {  							       null,  							       devices,  							       devices[0]); -			return (AltosDevice) o; +			return (altos_device) o;  		} else {  			return null;  		} diff --git a/ao-tools/altosui/AltosDeviceLinux.java b/ao-tools/altosui/AltosDeviceLinux.java deleted file mode 100644 index ffc70aff..00000000 --- a/ao-tools/altosui/AltosDeviceLinux.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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.*; -import altosui.AltosDevice; - -public class AltosDeviceLinux extends AltosDevice { - -	String load_string(File file) { -		try { -			FileInputStream	in = new FileInputStream(file); -			String result = ""; -			int c; -			try { -				while ((c = in.read()) != -1) { -					if (c == '\n') -						break; -					result = result + (char) c; -				} -				return result; -			} catch (IOException ee) { -				return ""; -			} -		} catch (FileNotFoundException ee) { -			return ""; -		} -	} -	String load_string(File dir, String name) { -		return load_string(new File(dir, name)); -	} - -	int load_hex(File file) { -		try { -			return Integer.parseInt(load_string(file).trim(), 16); -		} catch (NumberFormatException ee) { -			return -1; -		} -	} - -	int load_hex(File dir, String name) { -		return load_hex(new File(dir, name)); -	} - -	int load_dec(File file) { -		try { -			return Integer.parseInt(load_string(file).trim()); -		} catch (NumberFormatException ee) { -			return -1; -		} -	} - -	int load_dec(File dir, String name) { -		return load_dec(new File(dir, name)); -	} - -	String usb_tty(File sys_dir) { -		String base = sys_dir.getName(); -		int num_configs = load_hex(sys_dir, "bNumConfigurations"); -		int num_inters = load_hex(sys_dir, "bNumInterfaces"); -		for (int config = 1; config <= num_configs; config++) { -			for (int inter = 0; inter < num_inters; inter++) { -				String endpoint_base = String.format("%s:%d.%d", -								     base, config, inter); -				File endpoint_full = new File(sys_dir, endpoint_base); - -				File[] namelist; - -				/* Check for tty:ttyACMx style names */ -				class tty_colon_filter implements FilenameFilter { -					public boolean accept(File dir, String name) { -						return name.startsWith("tty:"); -					} -				} -				namelist = endpoint_full.listFiles(new tty_colon_filter()); -				if (namelist != null && namelist.length > 0) -					return new File ("/dev", namelist[0].getName().substring(4)).getPath(); - -				/* Check for tty/ttyACMx style names */ -				class tty_filter implements FilenameFilter { -					public boolean accept(File dir, String name) { -						return name.startsWith("tty"); -					} -				} -				File tty_dir = new File(endpoint_full, "tty"); -				namelist = tty_dir.listFiles(new tty_filter()); -				if (namelist != null && namelist.length > 0) -					return new File ("/dev", namelist[0].getName()).getPath(); -			} -		} -		return null; -	} - -	public AltosDeviceLinux (File sys) { -		sys = sys; -		manufacturer = load_string(sys, "manufacturer"); -		product = load_string(sys, "product"); -		serial = load_dec(sys, "serial"); -		idProduct = load_hex(sys, "idProduct"); -		idVendor = load_hex(sys, "idVendor"); -		tty = usb_tty(sys); -	} - -	public String toString() { -		return String.format("%-20s %6d %-15s", product, serial, tty == null ? "" : tty); -	} -	static public AltosDeviceLinux[] list() { -		LinkedList<AltosDeviceLinux> devices = new LinkedList<AltosDeviceLinux>(); - -		class dev_filter implements FilenameFilter{ -			public boolean accept(File dir, String name) { -				for (int i = 0; i < name.length(); i++) { -					char c = name.charAt(i); -					if (Character.isDigit(c)) -						continue; -					if (c == '-') -						continue; -					if (c == '.' && i != 1) -						continue; -					return false; -				} -				return true; -			} -		} - -		File usb_devices = new File("/sys/bus/usb/devices"); -		File[] devs = usb_devices.listFiles(new dev_filter()); -		if (devs != null) { -			for (int e = 0; e < devs.length; e++) { -				AltosDeviceLinux	dev = new AltosDeviceLinux(devs[e]); -				if (dev.idVendor == 0xfffe && dev.tty != null) { -					devices.add(dev); -				} -			} -		} -		AltosDeviceLinux[] foo = new AltosDeviceLinux[devices.size()]; -		for (int e = 0; e < devices.size(); e++) -			foo[e] = devices.get(e); -		return foo; -	} - -	static public AltosDeviceLinux[] list(String model) { -		AltosDeviceLinux[] devices = list(); -		if (model != null) { -			LinkedList<AltosDeviceLinux> subset = new LinkedList<AltosDeviceLinux>(); -			for (int i = 0; i < devices.length; i++) { -				if (devices[i].product.startsWith(model)) -					subset.add(devices[i]); -			} -			devices = new AltosDeviceLinux[subset.size()]; -			for (int e = 0; e < subset.size(); e++) -				devices[e] = subset.get(e); -		} -		return devices; -	} -} diff --git a/ao-tools/altosui/AltosGPS.java b/ao-tools/altosui/AltosGPS.java index c3b368e2..f8eb5f48 100644 --- a/ao-tools/altosui/AltosGPS.java +++ b/ao-tools/altosui/AltosGPS.java @@ -90,6 +90,9 @@ public class AltosGPS {  			gps_connected = true;  			gps_time = new AltosGPSTime();  			i++; +		} else if ((words[i]).equals("not-connected")) { +			gps_time = new AltosGPSTime(); +			i++;  		} else if (words.length >= 40) {  			gps_locked = true;  			gps_connected = true; @@ -106,6 +109,7 @@ public class AltosGPS {  			v_error = AltosParse.parse_int(AltosParse.strip_suffix(words[i++], "(verr)"));  		} else {  			gps_time = new AltosGPSTime(); +			i++;  		}  		AltosParse.word(words[i++], "SAT");  		int tracking_channels = 0; diff --git a/ao-tools/altosui/AltosSerial.java b/ao-tools/altosui/AltosSerial.java index 03ab28c5..e84f5b63 100644 --- a/ao-tools/altosui/AltosSerial.java +++ b/ao-tools/altosui/AltosSerial.java @@ -26,16 +26,21 @@ import java.io.*;  import java.util.concurrent.LinkedBlockingQueue;  import java.util.LinkedList;  import java.util.Iterator; -import gnu.io.*;  import altosui.AltosSerialMonitor; +import libaltosJNI.libaltos; +import libaltosJNI.altos_device; +import libaltosJNI.SWIGTYPE_p_altos_file; +import libaltosJNI.SWIGTYPE_p_altos_list;  /*   * This class reads from the serial port and places each received   * line in a queue. Dealing with that queue is left up to other   * threads.   */ -class AltosSerialReader implements Runnable { -	InputStream	serial_in; + +public class AltosSerial implements Runnable { + +	SWIGTYPE_p_altos_file altos;  	LinkedList<LinkedBlockingQueue<String>> monitors;  	LinkedBlockingQueue<String> reply_queue;  	Thread input_thread; @@ -46,7 +51,7 @@ class AltosSerialReader implements Runnable {  		try {  			for (;;) { -				c = serial_in.read(); +				c = libaltos.altos_getchar(altos, 0);  				if (Thread.interrupted())  					break;  				if (c == -1) @@ -70,7 +75,6 @@ class AltosSerialReader implements Runnable {  					}  				}  			} -		} catch (IOException e) {  		} catch (InterruptedException e) {  		}  	} @@ -96,16 +100,13 @@ class AltosSerialReader implements Runnable {  	}  	public boolean opened() { -		return serial_in != null; +		return altos != null;  	}  	public void close() { -		if (serial_in != null) { -			try { -				serial_in.close(); -			} catch (IOException e) { -			} -			serial_in = null; +		if (altos != null) { +			libaltos.altos_close(altos); +			altos = null;  		}  		if (input_thread != null) {  			try { @@ -117,87 +118,31 @@ class AltosSerialReader implements Runnable {  		}  	} -	public void open(File name) throws FileNotFoundException { -		close(); -		serial_in = new FileInputStream(name); -		input_thread = new Thread(this); -		input_thread.start(); -	} -	public void open(CommPort c) throws IOException { -		close(); -		try { -		c.enableReceiveTimeout(1000);	/* icky. the read method cannot be interrupted */ -		} catch (UnsupportedCommOperationException ee) { -		} -		serial_in = c.getInputStream(); -		input_thread = new Thread(this); -		input_thread.start(); -	} -	public AltosSerialReader () { -		serial_in = null; -		input_thread = null; -		line = ""; -		monitors = new LinkedList<LinkedBlockingQueue<String>> (); -		reply_queue = new LinkedBlockingQueue<String> (); +	public void putc(char c) { +		libaltos.altos_putchar(altos, c);  	} -} - -public class AltosSerial { -	OutputStream serial_out = null; -	AltosSerialReader reader = null; - -	CommPort comm_port = null; - -	public void close() { -		try { -			serial_out.close(); -		} catch (IOException ee) { -		} -		reader.close(); -		if (comm_port != null) { -			comm_port.close(); -		} -	} - -	public void open(File serial_name) throws FileNotFoundException { -		reader.open(serial_name); -		serial_out = new FileOutputStream(serial_name); -	} - -	public void open(CommPort c) throws IOException { -		reader.open(c); -		serial_out = c.getOutputStream(); +	public void print(String data) { +		for (int i = 0; i < data.length(); i++) +			putc(data.charAt(i));  	} -	public void connect(String port_name) throws IOException, NoSuchPortException, PortInUseException { -		comm_port = new RXTXPort(port_name); -		open(comm_port); +	public void printf(String format, Object ... arguments) { +		print(String.format(format, arguments));  	} -	void init() { -		reader = new AltosSerialReader(); -	} - -	public void add_monitor(LinkedBlockingQueue<String> q) { -		reader.add_monitor(q); -	} - -	public void remove_monitor(LinkedBlockingQueue<String> q) { -		reader.remove_monitor(q); +	public void open(altos_device device) throws FileNotFoundException { +		close(); +		altos = libaltos.altos_open(device); +		input_thread = new Thread(this); +		input_thread.start();  	}  	public AltosSerial() { -		init(); -	} - -	public AltosSerial(File serial_name) throws FileNotFoundException { -		init(); -		open(serial_name); -	} - -	public AltosSerial(CommPort comm_port) throws IOException { -		init(); -		open(comm_port); +		altos = null; +		input_thread = null; +		line = ""; +		monitors = new LinkedList<LinkedBlockingQueue<String>> (); +		reply_queue = new LinkedBlockingQueue<String> ();  	}  } diff --git a/ao-tools/altosui/AltosUI.java b/ao-tools/altosui/AltosUI.java index 43c40799..3dfc8952 100644 --- a/ao-tools/altosui/AltosUI.java +++ b/ao-tools/altosui/AltosUI.java @@ -27,7 +27,6 @@ import java.util.*;  import java.text.*;  import java.util.prefs.*;  import java.util.concurrent.LinkedBlockingQueue; -import gnu.io.*;  import altosui.AltosSerial;  import altosui.AltosSerialMonitor; @@ -38,6 +37,8 @@ import altosui.AltosPreferences;  import altosui.AltosLog;  import altosui.AltosVoice; +import libaltosJNI.*; +  class AltosFlightStatusTableModel extends AbstractTableModel {  	private String[] columnNames = {"Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };  	private Object[] data = { 0, "idle", 0, 0 }; @@ -220,16 +221,8 @@ public class AltosUI extends JFrame {  		flightInfoModel[col].addRow(name, value);  	} -	public void info_add_row(int col, String name, String format, Object value) { -		flightInfoModel[col].addRow(name, String.format(format, value)); -	} - -	public void info_add_row(int col, String name, String format, Object v1, Object v2) { -		flightInfoModel[col].addRow(name, String.format(format, v1, v2)); -	} - -	public void info_add_row(int col, String name, String format, Object v1, Object v2, Object v3) { -		flightInfoModel[col].addRow(name, String.format(format, v1, v2, v3)); +	public void info_add_row(int col, String name, String format, Object... parameters) { +		flightInfoModel[col].addRow(name, String.format(format, parameters));  	}  	public void info_add_deg(int col, String name, double v, int pos, int neg) { @@ -345,48 +338,57 @@ public class AltosUI extends JFrame {  	class IdleThread extends Thread {  		private AltosState state; +		int	reported_landing; + +		public void report(boolean last) { +			if (state == null) +				return; + +			/* reset the landing count once we hear about a new flight */ +			if (state.state < AltosTelemetry.ao_flight_drogue) +				reported_landing = 0; + +			/* Shut up once the rocket is on the ground */ +			if (reported_landing > 2) { +				return; +			} + +			/* If the rocket isn't on the pad, then report height */ +			if (state.state > AltosTelemetry.ao_flight_pad) { +				voice.speak("%d meters", (int) (state.height + 0.5)); +			} else { +				reported_landing = 0; +			} + +			/* If the rocket is coming down, check to see if it has landed; +			 * either we've got a landed report or we haven't heard from it in +			 * a long time +			 */ +			if (!state.ascent && +			    (last || +			     System.currentTimeMillis() - state.report_time >= 15000 || +			     state.state == AltosTelemetry.ao_flight_landed)) +			{ +				if (Math.abs(state.baro_speed) < 20 && state.height < 100) +					voice.speak("rocket landed safely"); +				else +					voice.speak("rocket may have crashed"); +				if (state.gps != null) +					voice.speak("bearing %d degrees, range %d meters", +						    (int) (state.from_pad.bearing + 0.5), +						    (int) (state.from_pad.distance + 0.5)); +				++reported_landing; +			} +		}  		public void run () { -			int	reported_landing = 0; +			reported_landing = 0;  			state = null;  			try {  				for (;;) {  					Thread.sleep(10000); -					if (state == null) -						continue; - -					/* reset the landing count once we hear about a new flight */ -					if (state.state < AltosTelemetry.ao_flight_drogue) -						reported_landing = 0; - -					/* Shut up once the rocket is on the ground */ -					if (reported_landing > 2) -						continue; - -					/* If the rocket isn't on the pad, then report height */ -					if (state.state > AltosTelemetry.ao_flight_pad) { -						voice.speak(String.format("%d meters", (int) (state.height + 0.5))); -					} - -					/* If the rocket is coming down, check to see if it has landed; -					 * either we've got a landed report or we haven't heard from it in -					 * a long time -					 */ -					if (!state.ascent && -					    (System.currentTimeMillis() - state.report_time > 10000 || -					     state.state == AltosTelemetry.ao_flight_landed)) -					{ -						if (Math.abs(state.baro_speed) < 20 && state.height < 100) -							voice.speak("rocket landed safely"); -						else -							voice.speak("rocket may have crashed"); -						if (state.gps != null) -							voice.speak(String.format("bearing %d degrees, range %d meters", -										  (int) (state.from_pad.bearing + 0.5), -										  (int) (state.from_pad.distance + 0.5))); -						++reported_landing; -					} +					report(false);  				}  			} catch (InterruptedException ie) {  			} @@ -400,21 +402,22 @@ public class AltosUI extends JFrame {  	private void tell(AltosState state, AltosState old_state) {  		if (old_state == null || old_state.state != state.state) {  			voice.speak(state.data.state); -			switch (state.state) { -			case AltosTelemetry.ao_flight_fast: -				voice.speak(String.format("max speed %d meters per second", -							  (int) (state.max_speed + 0.5))); -				break; -			case AltosTelemetry.ao_flight_drogue: -				voice.speak(String.format("max height %d meters", -							  (int) (state.max_height + 0.5))); -				break; +			if ((old_state == null || old_state.state <= AltosTelemetry.ao_flight_boost) && +			    state.state > AltosTelemetry.ao_flight_boost) { +				voice.speak("max speed: %d meters per second.", +					    (int) (state.max_speed + 0.5)); +			} else if ((old_state == null || old_state.state < AltosTelemetry.ao_flight_drogue) && +				   state.state >= AltosTelemetry.ao_flight_drogue) { +				voice.speak("max height: %d meters.", +					    (int) (state.max_height + 0.5));  			}  		}  		old_state = state;  	}  	class DisplayThread extends Thread { +		IdleThread	idle_thread; +  		String read() throws InterruptedException { return null; }  		void close() { } @@ -425,7 +428,8 @@ public class AltosUI extends JFrame {  			String		line;  			AltosState	state = null;  			AltosState	old_state = null; -			IdleThread	idle_thread = new IdleThread(); + +			idle_thread = new IdleThread();  			info_reset();  			info_finish(); @@ -451,6 +455,11 @@ public class AltosUI extends JFrame {  				idle_thread.interrupt();  			}  		} + +		public void report() { +			if (idle_thread != null) +				idle_thread.report(true); +		}  	}  	class DeviceThread extends DisplayThread { @@ -475,31 +484,21 @@ public class AltosUI extends JFrame {  	}  	private void ConnectToDevice() { -		AltosDevice	device = AltosDeviceDialog.show(AltosUI.this, "TeleDongle"); +		altos_device	device = AltosDeviceDialog.show(AltosUI.this, "TeleDongle");  		if (device != null) {  			try { -				serial_line.connect(device.tty); +				serial_line.open(device);  				DeviceThread thread = new DeviceThread(serial_line);  				run_display(thread);  			} catch (FileNotFoundException ee) {  				JOptionPane.showMessageDialog(AltosUI.this, -							      device.tty, +							      device.getPath(),  							      "Cannot open serial port",  							      JOptionPane.ERROR_MESSAGE); -			} catch (NoSuchPortException ee) { -				JOptionPane.showMessageDialog(AltosUI.this, -							      device.tty, -							      "No such serial port", -							      JOptionPane.ERROR_MESSAGE); -			} catch (PortInUseException ee) { -				JOptionPane.showMessageDialog(AltosUI.this, -							      device.tty, -							      "Port in use", -							      JOptionPane.ERROR_MESSAGE);  			} catch (IOException ee) {  				JOptionPane.showMessageDialog(AltosUI.this, -							      device.tty, +							      device.getPath(),  							      "Unkonwn I/O error",  							      JOptionPane.ERROR_MESSAGE);  			} @@ -517,8 +516,9 @@ public class AltosUI extends JFrame {  		while ((c = s.read()) != -1) {  			if (c == '\r')  				continue; -			if (c == '\n') +			if (c == '\n') {  				return line; +			}  			line = line + (char) c;  		}  		return null; @@ -554,12 +554,13 @@ public class AltosUI extends JFrame {  				replay.close();  			} catch (IOException ee) {  			} +			report();  		}  		void update(AltosState state) throws InterruptedException {  			/* Make it run in realtime after the rocket leaves the pad */  			if (state.state > AltosTelemetry.ao_flight_pad) -				Thread.sleep((int) (state.time_change * 1000)); +				Thread.sleep((int) (Math.min(state.time_change,10) * 1000));  		}  	} @@ -600,7 +601,7 @@ public class AltosUI extends JFrame {  			} catch (FileNotFoundException ee) {  				JOptionPane.showMessageDialog(AltosUI.this,  							      filename, -							      "Cannot open serial port", +							      "Cannot open telemetry file",  							      JOptionPane.ERROR_MESSAGE);  			}  		} diff --git a/ao-tools/altosui/AltosUIIcon.icns b/ao-tools/altosui/AltosUIIcon.icnsBinary files differ new file mode 100644 index 00000000..fe49f362 --- /dev/null +++ b/ao-tools/altosui/AltosUIIcon.icns diff --git a/ao-tools/altosui/AltosVoice.java b/ao-tools/altosui/AltosVoice.java index e4ea99a2..c39bfb9b 100644 --- a/ao-tools/altosui/AltosVoice.java +++ b/ao-tools/altosui/AltosVoice.java @@ -47,6 +47,10 @@ public class AltosVoice implements Runnable {  		}  	} +	public void speak(String format, Object... parameters) { +		speak(String.format(format, parameters)); +	} +  	public AltosVoice () {  		voice_manager = VoiceManager.getInstance();  		voice = voice_manager.getVoice(voice_name); diff --git a/ao-tools/altosui/Makefile b/ao-tools/altosui/Makefile index 57c889b8..cd123023 100644 --- a/ao-tools/altosui/Makefile +++ b/ao-tools/altosui/Makefile @@ -1,6 +1,6 @@  .SUFFIXES: .java .class -CLASSPATH=..:/usr/share/java/*:/home/keithp/src/freetts/freetts-1.2.2 +CLASSPATH=classes:./*  CLASSFILES=\  	AltosConvert.class \  	AltosFile.class \ @@ -15,24 +15,45 @@ CLASSFILES=\  	AltosTelemetry.class \  	AltosUI.class \  	AltosDevice.class \ -	AltosDeviceLinux.class \  	AltosDeviceDialog.class \  	AltosVoice.class +FREETTSSRC=/home/keithp/src/freetts/freetts-1.2.2 +FREETTSLIB=$(FREETTSSRC)/lib +FREETTSJAR= \ +	cmudict04.jar \ +	cmulex.jar \ +	cmu_time_awb.jar \ +	cmutimelex.jar \ +	cmu_us_kal.jar \ +	en_us.jar \ +	freetts.jar \ +	freetts-jsapi10.jar \ +	jsapi.jar +  JAVAFLAGS=-Xlint:unchecked -all: $(CLASSFILES) altosui altosui.jar +all: altosui.jar + +$(CLASSFILES):  .java.class:  	javac -cp "$(CLASSPATH)" $(JAVAFLAGS) $*.java -altosui: Makefile -	(echo '#!/bin/sh'; \ -	echo exec java -cp '"$(CLASSPATH)"' altosui/AltosUI) > $@ -	chmod +x $@ +altosui.jar: classes/altosui classes/libaltosJNI $(FREETTSJAR) $(CLASSFILES) Manifest.txt +	cd ./classes && jar cfm ../$@ altosui/Manifest.txt altosui/*.class libaltosJNI/*.class + +classes/altosui: +	mkdir -p classes +	ln -s .. classes/altosui + +classes/libaltosJNI: +	mkdir -p classes +	ln -s ../../libaltos/libaltosJNI classes/libaltosJNI -altosui.jar: $(CLASSFILES) Manifest.txt -	cd .. && jar cfm altosui/$@ altosui/Manifest.txt altosui/*.class +$(FREETTSJAR): +	ln -s $(FREETTSLIB)/$@ .  clean: -	rm -f *.class +	rm -f *.class $(FREETTSJAR) altosui.jar +	rm -rf classes diff --git a/ao-tools/altosui/Manifest.txt b/ao-tools/altosui/Manifest.txt index 0305fcfb..251ce2a0 100644 --- a/ao-tools/altosui/Manifest.txt +++ b/ao-tools/altosui/Manifest.txt @@ -1 +1,2 @@  Main-Class: altosui.AltosUI +Class-Path: freetts.jar diff --git a/ao-tools/altosui/voices.txt b/ao-tools/altosui/voices.txt deleted file mode 100644 index e8825fc3..00000000 --- a/ao-tools/altosui/voices.txt +++ /dev/null @@ -1 +0,0 @@ -com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory diff --git a/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui-contents.xml b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui-contents.xml new file mode 100644 index 00000000..e19a1e4c --- /dev/null +++ b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui-contents.xml @@ -0,0 +1 @@ +<pkg-contents spec="1.12"><f n="AltosUI.app" o="keithp" g="keithp" p="16877" pt="/Users/keithp/AltosUI.app" m="false" t="file"><f n="Contents" o="keithp" g="keithp" p="16877"><f n="Info.plist" o="keithp" g="keithp" p="33188"/><f n="MacOS" o="keithp" g="keithp" p="16877"><f n="JavaApplicationStub" o="keithp" g="keithp" p="33133"/></f><f n="PkgInfo" o="keithp" g="keithp" p="33188"/><f n="Resources" o="keithp" g="keithp" p="16877"><f n="AltosUIIcon.icns" o="keithp" g="keithp" p="33188"/><f n="Java" o="keithp" g="keithp" p="16877"><f n="altosui.jar" o="keithp" g="keithp" p="33188"/><f n="cmu_time_awb.jar" o="keithp" g="keithp" p="33188"/><f n="cmu_us_kal.jar" o="keithp" g="keithp" p="33188"/><f n="cmudict04.jar" o="keithp" g="keithp" p="33188"/><f n="cmulex.jar" o="keithp" g="keithp" p="33188"/><f n="cmutimelex.jar" o="keithp" g="keithp" p="33188"/><f n="en_us.jar" o="keithp" g="keithp" p="33188"/><f n="freetts-jsapi10.jar" o="keithp" g="keithp" p="33188"/><f n="freetts.jar" o="keithp" g="keithp" p="33188"/><f n="libaltos.dylib" o="keithp" g="keithp" p="33188"/></f></f></f></f></pkg-contents>
\ No newline at end of file diff --git a/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui.xml b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui.xml new file mode 100644 index 00000000..5d84e5f0 --- /dev/null +++ b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui.xml @@ -0,0 +1 @@ +<pkgref spec="1.12" uuid="C5762664-2F26-4536-94C4-56F0FBC08D1A"><config><identifier>org.altusmetrum.altosUi.AltosUI.pkg</identifier><version>1.0</version><description></description><post-install type="none"/><installFrom>/Users/keithp/AltosUI.app</installFrom><installTo mod="true" relocatable="true">/Applications/AltosUI.app</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>installTo.path</mod><mod>parent</mod><mod>requireAuthorization</mod><mod>installTo</mod></config><contents><file-list>01altosui-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>
\ No newline at end of file diff --git a/ao-tools/libaltos/AltOS Package Configuration.pmdoc/index.xml b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/index.xml new file mode 100644 index 00000000..1277db62 --- /dev/null +++ b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/index.xml @@ -0,0 +1 @@ +<pkmkdoc spec="1.12"><properties><title>AltOS UI</title><build>/Users/keithp/Documents/AltosUI.pkg</build><organization>org.altusmetrum</organization><userSees ui="easy"/><min-target os="3"/><domain anywhere="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><contents><choice title="AltosUI" id="choice0" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="org.altusmetrum.altosUi.AltosUI.pkg"/></choice></contents><resources bg-scale="none" bg-align="topleft"><locale lang="en"/></resources><flags/><item type="file">01altosui.xml</item><mod>properties.title</mod></pkmkdoc>
\ No newline at end of file diff --git a/ao-tools/libaltos/Makefile b/ao-tools/libaltos/Makefile new file mode 100644 index 00000000..0bbd304c --- /dev/null +++ b/ao-tools/libaltos/Makefile @@ -0,0 +1,80 @@ +OS:=$(shell uname) + +ifeq ($(OS),Linux) + +JAVA_CFLAGS=-I/usr/lib/jvm/java-6-openjdk/include + +OS_CFLAGS=-DLINUX -DPOSIX_TTY $(JAVA_CFLAGS) + +LIBEXT=so + +endif + +ifeq ($(OS),Darwin) + +DARWIN_CFLAGS=\ +	--sysroot=/Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 \ +	-iwithsysroot /System/Library/Frameworks/JavaVM.framework/Headers \ +	-iwithsysroot /System/Library/Frameworks/IOKit.framework/Headers \ +	-iwithsysroot /System/Library/Frameworks/CoreFoundation.framework/Headers +DARWIN_LIBS=\ +	-framework IOKit -framework CoreFoundation + +OS_CFLAGS = $(DARWIN_CFLAGS) -DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64 +LIBEXT=dylib + +endif + +.SUFFIXES: .java .class + +CLASSPATH=".:jnitest/*:libaltosJNI:/usr/share/java/*" + +SWIG_DIR=swig_bindings/java +SWIG_FILE=$(SWIG_DIR)/libaltos.swig +SWIG_WRAP=$(SWIG_DIR)/libaltos_wrap.c + +JNI_DIR=libaltosJNI +JNI_FILE=$(JNI_DIR)/libaltosJNI.java  +JNI_SRCS=$(JNI_FILE) \ +	$(JNI_DIR)/SWIGTYPE_p_altos_file.java \ +	$(JNI_DIR)/SWIGTYPE_p_altos_list.java \ +	$(JNI_DIR)/altos_device.java \ +	$(JNI_DIR)/libaltos.java + +JAVAFILES=\ +	$(JNI_SRCS) + +CLASSFILES = $(JAVAFILES:%.java=%.class) + +JAVAFLAGS=-Xlint:unchecked + +all: libaltos.$(LIBEXT) cjnitest $(CLASSFILES) + +.java.class: +	javac -cp "$(CLASSPATH)" $(JAVAFLAGS) $*.java + +CFLAGS=$(OS_CFLAGS) -O0 -g -I. + +HEADERS=libaltos.h +SRCS = libaltos.c $(SWIG_WRAP) +OBJS = $(SRCS:%.c=%.o) +LIBS = $(DARWIN_LIBS) + +cjnitest: cjnitest.o $(OBJS) +	cc -o $@ $(CFLAGS) cjnitest.o $(OBJS) $(LIBS) + +libaltos.$(LIBEXT): $(OBJS) +	gcc -shared $(CFLAGS) -o $@ $(OBJS) $(LIBS) + +clean: +	rm -f $(CLASSFILES) $(OBJS) libaltos.$(LIBEXT) cjnitest cjnitest.o +	rm -rf swig_bindings libaltosJNI + +$(JNI_FILE): libaltos.i0 $(HEADERS) +	mkdir -p $(SWIG_DIR) +	mkdir -p libaltosJNI +	sed 's;//%;%;' libaltos.i0 $(HEADERS) > $(SWIG_FILE) +	swig -java -package libaltosJNI $(SWIG_FILE) +	cp swig_bindings/java/*.java libaltosJNI + +$(SWIG_WRAP): $(JNI_FILE) diff --git a/ao-tools/libaltos/cjnitest.c b/ao-tools/libaltos/cjnitest.c new file mode 100644 index 00000000..cd3898ed --- /dev/null +++ b/ao-tools/libaltos/cjnitest.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include "libaltos.h" + +main () +{ +	struct altos_device	device; +	struct altos_list	*list; + +	altos_init(); +	list = altos_list_start(); +	while (altos_list_next(list, &device)) { +		struct altos_file	*file; +		int			c; + +		file = altos_open(&device); +		altos_putchar(file, '?'); altos_putchar(file, '\n'); altos_flush(file); +		while ((c = altos_getchar(file, 100)) >= 0) { +			putchar (c); +		} +		printf ("getchar returns %d\n", c); +		altos_close(file); +	} +	altos_list_finish(list); +	altos_fini(); +} diff --git a/ao-tools/libaltos/libaltos.c b/ao-tools/libaltos/libaltos.c new file mode 100644 index 00000000..df0d5b2e --- /dev/null +++ b/ao-tools/libaltos/libaltos.c @@ -0,0 +1,825 @@ +/* + * 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. + */ + +#include "libaltos.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static int +match_dev(char *product, int serial, struct altos_device *device) +{ +	struct altos_list	*list; +	int			i; + +	list = altos_list_start(); +	if (!list) +		return 0; +	while ((i = altos_list_next(list, device)) != 0) { +		if (product && strncmp (product, device->product, strlen(product)) != 0) +			continue; +		if (serial && serial != device->serial) +			continue; +		break; +	} +	altos_list_finish(list); +	return i; +} + +#ifdef DARWIN +/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */ +static char * +altos_strndup (const char *s, size_t n) +{ +    size_t len = strlen (s); +    char *ret; + +    if (len <= n) +       return strdup (s); +    ret = malloc(n + 1); +    strncpy(ret, s, n); +    ret[n] = '\0'; +    return ret; +} + +#else +#define altos_strndup strndup +#endif + +int +altos_find_by_arg(char *arg, char *default_product, struct altos_device *device) +{ +	char	*product; +	int	serial; +	char	*end; +	char	*colon; +	int	ret; + +	if (arg) +	{ +		/* check for <serial> */ +		serial = strtol(arg, &end, 0); +		if (end != arg) { +			if (*end != '\0') +				return 0; +			product = NULL; +		} else { +			/* check for <product>:<serial> */ +			colon = strchr(arg, ':'); +			if (colon) { +				product = altos_strndup(arg, colon - arg); +				serial = strtol(colon + 1, &end, 0); +				if (*end != '\0') +					return 0; +			} else { +				product = arg; +				serial = 0; +			} +		} +	} else { +		product = NULL; +		serial = 0; +	} +	if (!product && default_product) +		ret = match_dev(default_product, serial, device); +	if (!ret) +		ret = match_dev(product, serial, device); +	if (product && product != arg) +		free(product); +	return ret; +} + +#ifdef LINUX + +#define _GNU_SOURCE +#include <ctype.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static char * +cc_fullname (char *dir, char *file) +{ +	char	*new; +	int	dlen = strlen (dir); +	int	flen = strlen (file); +	int	slen = 0; + +	if (dir[dlen-1] != '/') +		slen = 1; +	new = malloc (dlen + slen + flen + 1); +	if (!new) +		return 0; +	strcpy(new, dir); +	if (slen) +		strcat (new, "/"); +	strcat(new, file); +	return new; +} + +static char * +cc_basename(char *file) +{ +	char *b; + +	b = strrchr(file, '/'); +	if (!b) +		return file; +	return b + 1; +} + +static char * +load_string(char *dir, char *file) +{ +	char	*full = cc_fullname(dir, file); +	char	line[4096]; +	char	*r; +	FILE	*f; +	int	rlen; + +	f = fopen(full, "r"); +	free(full); +	if (!f) +		return NULL; +	r = fgets(line, sizeof (line), f); +	fclose(f); +	if (!r) +		return NULL; +	rlen = strlen(r); +	if (r[rlen-1] == '\n') +		r[rlen-1] = '\0'; +	return strdup(r); +} + +static int +load_hex(char *dir, char *file) +{ +	char	*line; +	char	*end; +	long	i; + +	line = load_string(dir, file); +	if (!line) +		return -1; +	i = strtol(line, &end, 16); +	free(line); +	if (end == line) +		return -1; +	return i; +} + +static int +load_dec(char *dir, char *file) +{ +	char	*line; +	char	*end; +	long	i; + +	line = load_string(dir, file); +	if (!line) +		return -1; +	i = strtol(line, &end, 10); +	free(line); +	if (end == line) +		return -1; +	return i; +} + +static int +dir_filter_tty_colon(const struct dirent *d) +{ +	return strncmp(d->d_name, "tty:", 4) == 0; +} + +static int +dir_filter_tty(const struct dirent *d) +{ +	return strncmp(d->d_name, "tty", 3) == 0; +} + +struct altos_usbdev { +	char	*sys; +	char	*tty; +	char	*manufacturer; +	char	*product; +	int	serial;	/* AltOS always uses simple integer serial numbers */ +	int	idProduct; +	int	idVendor; +}; + +static char * +usb_tty(char *sys) +{ +	char *base; +	int num_configs; +	int config; +	struct dirent **namelist; +	int interface; +	int num_interfaces; +	char endpoint_base[20]; +	char *endpoint_full; +	char *tty_dir; +	int ntty; +	char *tty; + +	base = cc_basename(sys); +	num_configs = load_hex(sys, "bNumConfigurations"); +	num_interfaces = load_hex(sys, "bNumInterfaces"); +	for (config = 1; config <= num_configs; config++) { +		for (interface = 0; interface < num_interfaces; interface++) { +			sprintf(endpoint_base, "%s:%d.%d", +				base, config, interface); +			endpoint_full = cc_fullname(sys, endpoint_base); + +			/* Check for tty:ttyACMx style names +			 */ +			ntty = scandir(endpoint_full, &namelist, +				       dir_filter_tty_colon, +				       alphasort); +			if (ntty > 0) { +				free(endpoint_full); +				tty = cc_fullname("/dev", namelist[0]->d_name + 4); +				free(namelist); +				return tty; +			} + +			/* Check for tty/ttyACMx style names +			 */ +			tty_dir = cc_fullname(endpoint_full, "tty"); +			free(endpoint_full); +			ntty = scandir(tty_dir, &namelist, +				       dir_filter_tty, +				       alphasort); +			free (tty_dir); +			if (ntty > 0) { +				tty = cc_fullname("/dev", namelist[0]->d_name); +				free(namelist); +				return tty; +			} +		} +	} +	return NULL; +} + +static struct altos_usbdev * +usb_scan_device(char *sys) +{ +	struct altos_usbdev *usbdev; + +	usbdev = calloc(1, sizeof (struct altos_usbdev)); +	if (!usbdev) +		return NULL; +	usbdev->sys = strdup(sys); +	usbdev->manufacturer = load_string(sys, "manufacturer"); +	usbdev->product = load_string(sys, "product"); +	usbdev->serial = load_dec(sys, "serial"); +	usbdev->idProduct = load_hex(sys, "idProduct"); +	usbdev->idVendor = load_hex(sys, "idVendor"); +	usbdev->tty = usb_tty(sys); +	return usbdev; +} + +static void +usbdev_free(struct altos_usbdev *usbdev) +{ +	free(usbdev->sys); +	free(usbdev->manufacturer); +	free(usbdev->product); +	/* this can get used as a return value */ +	if (usbdev->tty) +		free(usbdev->tty); +	free(usbdev); +} + +#define USB_DEVICES	"/sys/bus/usb/devices" + +static int +dir_filter_dev(const struct dirent *d) +{ +	const char	*n = d->d_name; +	char	c; + +	while ((c = *n++)) { +		if (isdigit(c)) +			continue; +		if (c == '-') +			continue; +		if (c == '.' && n != d->d_name + 1) +			continue; +		return 0; +	} +	return 1; +} + +struct altos_list { +	struct altos_usbdev	**dev; +	int			current; +	int			ndev; +}; + +int +altos_init(void) +{ +	return 1; +} + +void +altos_fini(void) +{ +} + +struct altos_list * +altos_list_start(void) +{ +	int			e; +	struct dirent		**ents; +	char			*dir; +	struct altos_usbdev	*dev; +	struct altos_list	*devs; +	int			n; + +	devs = calloc(1, sizeof (struct altos_list)); +	if (!devs) +		return NULL; + +	n = scandir (USB_DEVICES, &ents, +		     dir_filter_dev, +		     alphasort); +	if (!n) +		return 0; +	for (e = 0; e < n; e++) { +		dir = cc_fullname(USB_DEVICES, ents[e]->d_name); +		dev = usb_scan_device(dir); +		free(dir); +		if (dev->idVendor == 0xfffe && dev->tty) { +			if (devs->dev) +				devs->dev = realloc(devs->dev, +						    devs->ndev + 1 * sizeof (struct usbdev *)); +			else +				devs->dev = malloc (sizeof (struct usbdev *)); +			devs->dev[devs->ndev++] = dev; +		} +	} +	free(ents); +	devs->current = 0; +	return devs; +} + +int +altos_list_next(struct altos_list *list, struct altos_device *device) +{ +	struct altos_usbdev *dev; +	if (list->current >= list->ndev) +		return 0; +	dev = list->dev[list->current]; +	strcpy(device->product, dev->product); +	strcpy(device->path, dev->tty); +	device->serial = dev->serial; +	list->current++; +	return 1; +} + +void +altos_list_finish(struct altos_list *usbdevs) +{ +	int	i; + +	if (!usbdevs) +		return; +	for (i = 0; i < usbdevs->ndev; i++) +		usbdev_free(usbdevs->dev[i]); +	free(usbdevs); +} + +#endif + +#ifdef DARWIN + +#include <IOKitLib.h> +#include <IOKit/usb/USBspec.h> +#include <sys/param.h> +#include <paths.h> +#include <CFNumber.h> +#include <IOBSD.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +struct altos_list { +	io_iterator_t iterator; +}; + +static int +get_string(io_object_t object, CFStringRef entry, char *result, int result_len) +{ +	CFTypeRef entry_as_string; +	Boolean got_string; + +	entry_as_string = IORegistryEntrySearchCFProperty (object, +							   kIOServicePlane, +							   entry, +							   kCFAllocatorDefault, +							   kIORegistryIterateRecursively); +	if (entry_as_string) { +		got_string = CFStringGetCString(entry_as_string, +						result, result_len, +						kCFStringEncodingASCII); +     +		CFRelease(entry_as_string); +		if (got_string) +			return 1; +	} +	return 0; +} + +int +altos_init(void) +{ +	return 1; +} + +void +altos_fini(void) +{ +} + +struct altos_list * +altos_list_start(void) +{ +	struct altos_list *list = calloc (sizeof (struct altos_list), 1); +	CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice"); +	UInt32 vendor = 0xfffe, product = 0x000a; +	CFNumberRef vendor_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor); +	CFNumberRef product_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product); +	io_iterator_t tdIterator; +	io_object_t tdObject; +   +	CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBVendorID), vendor_ref); +	CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBProductID), product_ref); + +	IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator); +   +	CFRelease(vendor_ref); +	CFRelease(product_ref); +	return list; +} + +int +altos_list_next(struct altos_list *list, struct altos_device *device) +{ +	io_object_t object; +	char serial_string[128]; + +	for (;;) { +		object = IOIteratorNext(list->iterator); +		if (!object) +			return 0; +   +		if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) && +		    get_string (object, CFSTR("USB Product Name"), device->product, sizeof (device->product)) && +		    get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) { +			device->serial = atoi(serial_string); +			return 1; +		} +	} +} + +void +altos_list_finish(struct altos_list *list) +{ +	IOObjectRelease (list->iterator); +	free(list); +} + +#endif + +#ifdef POSIX_TTY + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <termios.h> +#include <errno.h> + +#define USB_BUF_SIZE	64 + +struct altos_file { +	int				fd; +	unsigned char			out_data[USB_BUF_SIZE]; +	int				out_used; +	unsigned char			in_data[USB_BUF_SIZE]; +	int				in_used; +	int				in_read; +}; + +struct altos_file * +altos_open(struct altos_device *device) +{ +	struct altos_file	*file = calloc (sizeof (struct altos_file), 1); +	int			ret; +	struct termios		term; + +	if (!file) +		return NULL; + +	file->fd = open(device->path, O_RDWR | O_NOCTTY); +	if (file->fd < 0) { +		perror(device->path); +		free(file); +		return NULL; +	} +	ret = tcgetattr(file->fd, &term); +	if (ret < 0) { +		perror("tcgetattr"); +		close(file->fd); +		free(file); +		return NULL; +	} +	cfmakeraw(&term); +	term.c_cc[VMIN] = 0; +	term.c_cc[VTIME] = 1; +	ret = tcsetattr(file->fd, TCSAFLUSH, &term); +	if (ret < 0) { +		perror("tcsetattr"); +		close(file->fd); +		free(file); +		return NULL; +	} +	return file; +} + +void +altos_close(struct altos_file *file) +{ +	close(file->fd); +	free(file); +} + +int +altos_putchar(struct altos_file *file, char c) +{ +	int	ret; + +	if (file->out_used == USB_BUF_SIZE) { +		ret = altos_flush(file); +		if (ret) +			return ret; +	} +	file->out_data[file->out_used++] = c; +	if (file->out_used == USB_BUF_SIZE) +		return altos_flush(file); +	return 0; +} + +int +altos_flush(struct altos_file *file) +{ +	while (file->out_used) { +		int	ret; + +		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_getchar(struct altos_file *file, int timeout) +{ +	while (file->in_read == file->in_used) { +		int	ret; + +		altos_flush(file); +		ret = read(file->fd, file->in_data, USB_BUF_SIZE); +		if (ret < 0) +			return -errno; +		file->in_read = 0; +		file->in_used = ret; +	} +	return file->in_data[file->in_read++]; +} + +#endif /* POSIX_TTY */ + +#ifdef USE_LIBUSB +#include <libusb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +libusb_context	*usb_context; + +int altos_init(void) +{ +	int	ret; +	ret = libusb_init(&usb_context); +	if (ret) +		return ret; +	libusb_set_debug(usb_context, 3); +	return 0; +} + +void altos_fini(void) +{ +	libusb_exit(usb_context); +	usb_context = NULL; +} + +static libusb_device **list; +static ssize_t num, current; + +int altos_list_start(void) +{ +	if (list) +		altos_list_finish(); +	current = 0; +	num = libusb_get_device_list(usb_context, &list); +	if (num == 0) { +		current = num = 0; +		list = NULL; +		return 0; +	} +	return 1; +} + +int altos_list_next(struct altos_device *device) +{ +	while (current < num) { +		struct libusb_device_descriptor descriptor; +		libusb_device *usb_device = list[current++]; + +		if (libusb_get_device_descriptor(usb_device, &descriptor) == 0) { +			if (descriptor.idVendor == 0xfffe) +			{ +				libusb_device_handle	*handle; +				if (libusb_open(usb_device, &handle) == 0) { +					char	serial_number[256]; +					libusb_get_string_descriptor_ascii(handle, descriptor.iProduct, +									   device->product, +									   sizeof(device->product)); +					libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber, +									   serial_number, +									   sizeof (serial_number)); +					libusb_close(handle); +					device->serial = atoi(serial_number); +					device->device = usb_device; +					return 1; +				} +			} +		} +	} +	return 0; +} + +void altos_list_finish(void) +{ +	if (list) { +		libusb_free_device_list(list, 1); +		list = NULL; +	} +} + +#define USB_BUF_SIZE	64 + +struct altos_file { +	struct libusb_device		*device; +	struct libusb_device_handle	*handle; +	int				out_ep; +	int				out_size; +	int				in_ep; +	int				in_size; +	unsigned char			out_data[USB_BUF_SIZE]; +	int				out_used; +	unsigned char			in_data[USB_BUF_SIZE]; +	int				in_used; +	int				in_read; +}; + +struct altos_file * +altos_open(struct altos_device *device) +{ +	struct altos_file		*file; +	struct libusb_device_handle	*handle; +	if (libusb_open(device->device, &handle) == 0) { +		int	ret; + +		ret = libusb_claim_interface(handle, 1); +#if 0 +		if (ret) { +			libusb_close(handle); +			return NULL; +		} +#endif +		ret = libusb_detach_kernel_driver(handle, 1); +#if 0 +		if (ret) { +			libusb_close(handle); +			return NULL; +		} +#endif + +		file = calloc(sizeof (struct altos_file), 1); +		file->device = libusb_ref_device(device->device); +		file->handle = handle; +		/* XXX should get these from the endpoint descriptors */ +		file->out_ep = 4 | LIBUSB_ENDPOINT_OUT; +		file->out_size = 64; +		file->in_ep = 5 | LIBUSB_ENDPOINT_IN; +		file->in_size = 64; + +		return file; +	} +	return NULL; +} + +void +altos_close(struct altos_file *file) +{ +	libusb_close(file->handle); +	libusb_unref_device(file->device); +	file->handle = NULL; +	free(file); +} + +int +altos_putchar(struct altos_file *file, char c) +{ +	int	ret; + +	if (file->out_used == file->out_size) { +		ret = altos_flush(file); +		if (ret) +			return ret; +	} +	file->out_data[file->out_used++] = c; +	if (file->out_used == file->out_size) +		return altos_flush(file); +	return 0; +} + +int +altos_flush(struct altos_file *file) +{ +	while (file->out_used) { +		int	transferred; +		int	ret; + +		ret = libusb_bulk_transfer(file->handle, +					   file->out_ep, +					   file->out_data, +					   file->out_used, +					   &transferred, +					   0); +		if (ret) +			return ret; +		if (transferred) { +			memmove(file->out_data, file->out_data + transferred, +				file->out_used - transferred); +			file->out_used -= transferred; +		} +	} +} + +int +altos_getchar(struct altos_file *file, int timeout) +{ +	while (file->in_read == file->in_used) { +		int	ret; +		int	transferred; + +		altos_flush(file); +		ret = libusb_bulk_transfer(file->handle, +					   file->in_ep, +					   file->in_data, +					   file->in_size, +					   &transferred, +					   (unsigned int) timeout); +		if (ret) +			return ret; +		file->in_read = 0; +		file->in_used = transferred; +	} +	return file->in_data[file->in_read++]; +} + +#endif /* USE_LIBUSB */ diff --git a/ao-tools/libaltos/libaltos.h b/ao-tools/libaltos/libaltos.h new file mode 100644 index 00000000..782f244e --- /dev/null +++ b/ao-tools/libaltos/libaltos.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef _LIBALTOS_H_ +#define _LIBALTOS_H_ + +struct altos_device { +	//%immutable; +	char				product[256]; +	int				serial; +	char				path[256]; +	//%mutable; +}; + +int altos_init(void); + +void altos_fini(void); + +struct altos_list * +altos_list_start(void); + +int altos_list_next(struct altos_list *list, struct altos_device *device); + +void altos_list_finish(struct altos_list *list); + +struct altos_file * +altos_open(struct altos_device *device); + +void altos_close(struct altos_file *file); + +int +altos_putchar(struct altos_file *file, char c); + +int +altos_flush(struct altos_file *file); + +int +altos_getchar(struct altos_file *file, int timeout); + +#endif /* _LIBALTOS_H_ */ diff --git a/ao-tools/libaltos/libaltos.i0 b/ao-tools/libaltos/libaltos.i0 new file mode 100644 index 00000000..d06468f5 --- /dev/null +++ b/ao-tools/libaltos/libaltos.i0 @@ -0,0 +1,5 @@ +%module libaltos +%{ +#include "libaltos.h" +%} + | 
