diff options
Diffstat (limited to 'micropeak')
| -rw-r--r-- | micropeak/Makefile.am | 115 | ||||
| -rw-r--r-- | micropeak/MicroData.java | 270 | ||||
| -rw-r--r-- | micropeak/MicroGraph.java | 105 | ||||
| -rw-r--r-- | micropeak/MicroPeak.java | 138 | ||||
| -rw-r--r-- | micropeak/MicroSerial.java | 46 | ||||
| -rw-r--r-- | micropeak/MicroUSB.java | 103 | 
6 files changed, 777 insertions, 0 deletions
| diff --git a/micropeak/Makefile.am b/micropeak/Makefile.am new file mode 100644 index 00000000..a3ecac72 --- /dev/null +++ b/micropeak/Makefile.am @@ -0,0 +1,115 @@ +JAVAROOT=classes +AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation + +CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" + +bin_SCRIPTS=micropeak + +micropeakdir=$(datadir)/java + +micropeak_JAVA= \ +	MicroPeak.java \ +	MicroData.java \ +	MicroGraph.java \ +	MicroSerial.java \ +	MicroUSB.java + +JFREECHART_CLASS= \ +    jfreechart.jar + +JCOMMON_CLASS=\ +    jcommon.jar + +JAR=micropeak.jar + +FATJAR=micropeak-fat.jar + +LIBALTOS= \ +	libaltos.so \ +	libaltos.dylib \ +	altos.dll + +ALTOSLIB_CLASS=\ +	AltosLib.jar + +all-local: micropeak-test $(JAR) + +clean-local: +	-rm -rf classes $(JAR) $(FATJAR) \ +		$(ALTOSLIB_CLASS) \ +		$(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt \ +		micropeak micropeak-test macosx linux windows + +micropeak: Makefile +	echo "#!/bin/sh" > $@ +	echo 'exec java  -cp "$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="$(altoslibdir)" -jar "$(micropeakdir)/micropeak.jar" "$$@"' >> $@ +	chmod +x $@ + +micropeak-test: Makefile +	echo "#!/bin/sh" > $@ +	echo 'exec java -cp "./*:../libaltos/*:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" -jar micropeak.jar "$$@"' >> $@ +	chmod +x $@ + +$(JAR): classmicropeak.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) +	jar cfm $@ Manifest.txt \ +		$(ICONJAR) \ +		-C classes org \ +		-C ../libaltos libaltosJNI + +$(FATJAR): classmicropeak.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(JAVA_ICONS) +	jar cfm $@ Manifest-fat.txt \ +		$(ICONJAR) \ +		-C classes org \ +		-C ../libaltos libaltosJNI + + +libaltos.so: build-libaltos +	-rm -f "$@" +	$(LN_S) ../libaltos/.libs/"$@" . + +libaltos.dylib: +	-rm -f "$@" +	$(LN_S) ../libaltos/"$@" . + +altos.dll: ../libaltos/altos.dll +	-rm -f "$@" +	$(LN_S) ../libaltos/"$@" . + +altos64.dll: ../libaltos/altos64.dll +	-rm -f "$@" +	$(LN_S) ../libaltos/"$@" . + +../libaltos/.libs/libaltos.so: build-libaltos + +../libaltos/altos.dll: build-altos-dll + +../libaltos/altos64.dll: build-altos64-dll + +build-libaltos: +	+cd ../libaltos && make libaltos.la +build-altos-dll: +	+cd ../libaltos && make altos.dll + +build-altos64-dll: +	+cd ../libaltos && make altos64.dll + +$(ALTOSLIB_CLASS): +	-rm -f "$@" +	$(LN_S) ../altoslib/"$@" . + +$(JFREECHART_CLASS): +	-rm -f "$@" +	$(LN_S) "$(JFREECHART)"/"$@" . + +$(JCOMMON_CLASS): +	-rm -f "$@" +	$(LN_S) "$(JCOMMON)"/"$@" . + +Manifest.txt: Makefile +	echo 'Main-Class: org.altusmetrum.micropeak.MicroPeak' > $@ +	echo "Class-Path: AltosLib.jar $(JCOMMON)/jcommon.jar $(JFREECHART)/jfreechart.jar" >> $@ + +Manifest-fat.txt: +	echo 'Main-Class: org.altusmetrum.micropeak.MicroPeak' > $@ +	echo "Class-Path: AltosLib.jar jcommon.jar jfreechart.jar" >> $@ + diff --git a/micropeak/MicroData.java b/micropeak/MicroData.java new file mode 100644 index 00000000..783ae40f --- /dev/null +++ b/micropeak/MicroData.java @@ -0,0 +1,270 @@ +/* + * Copyright © 2012 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 org.altusmetrum.micropeak; + +import java.lang.*; +import java.io.*; +import java.util.*; +import org.altusmetrum.AltosLib.*; + +public class MicroData { +	public int		ground_pressure; +	public int		min_pressure; +	public int[]		pressures; +	private double		time_step; +	private double		ground_altitude; +	private ArrayList<Integer>	bytes; +	 + +	class FileEndedException extends Exception { +	} + +	class NonHexcharException extends Exception { +	} + +	class InvalidCrcException extends Exception { +	} + +	private int getc(InputStream f) throws IOException, FileEndedException { +		int	c = f.read(); + +		if (c == -1) +			throw new FileEndedException(); +		bytes.add(c); +		return c; +	} + +	private int get_nonwhite(InputStream f) throws IOException, FileEndedException { +		int	c; + +		for (;;) { +			c = getc(f); +			if (!Character.isWhitespace(c)) +				return c; +		} +	} + +	private int get_hexc(InputStream f) throws IOException, FileEndedException, NonHexcharException { +		int	c = get_nonwhite(f); + +		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; +		throw new NonHexcharException(); +	} + +	private static final int POLY = 0x8408; + +	private int log_crc(int crc, int b) { +		int	i; + +		for (i = 0; i < 8; i++) { +			if (((crc & 0x0001) ^ (b & 0x0001)) != 0) +				crc = (crc >> 1) ^ POLY; +			else +				crc = crc >> 1; +			b >>= 1; +		} +		return crc & 0xffff; +	} + +	int	file_crc; + +	private int get_hex(InputStream f) throws IOException, FileEndedException, NonHexcharException { +		int	a = get_hexc(f); +		int	b = get_hexc(f); + +		int h = (a << 4) + b; + +		file_crc = log_crc(file_crc, h); +		return h; +	} + +	private boolean find_header(InputStream f) throws IOException { +		try { +			for (;;) { +				if (get_nonwhite(f) == 'M' && get_nonwhite(f) == 'P') +					return true; +			} +		} catch (FileEndedException fe) { +			return false; +		} +	}  + +	private int get_32(InputStream f)  throws IOException, FileEndedException, NonHexcharException { +		int	v = 0; +		for (int i = 0; i < 4; i++) { +			v += get_hex(f) << (i * 8); +		} +		return v; +	} + +	private int get_16(InputStream f) throws IOException, FileEndedException, NonHexcharException { +		int	v = 0; +		for (int i = 0; i < 2; i++) { +			v += get_hex(f) << (i * 8); +		} +		return v; +	} + +	private int swap16(int i) { +		return ((i << 8) & 0xff00) | ((i >> 8) & 0xff); +	} + +	public boolean	crc_valid; + +	int mix_in (int high, int low) { +		return  high - (high & 0xffff) + low; +	} + +	boolean closer (int target, int a, int b) { +		return Math.abs (target - a) < Math.abs(target - b); +	} + +	public double altitude(int i) { +		return AltosConvert.pressure_to_altitude(pressures[i]); +	} + +	int fact(int n) { +		if (n == 0) +			return 1; +		return n * fact(n-1); +	} + +	int choose(int n, int k) { +		return fact(n) / (fact(k) * fact(n-k)); +	} + + +	public double avg_altitude(int center, int dist) { +		int	start = center - dist; +		int	stop = center + dist; + +		if (start < 0) +			start = 0; +		if (stop >= pressures.length) +			stop = pressures.length - 1; + +		double	sum = 0; +		double	div = 0; + +		int	n = dist * 2; + +		for (int i = start; i <= stop; i++) { +			int	k = i - (center - dist); +			int	c = choose (n, k); + +			sum += c * pressures[i]; +			div += c; +		} + +		double pres = sum / div; + +		double alt = AltosConvert.pressure_to_altitude(pres); +		return alt; +	} + +	public double height(int i) { +		return altitude(i) - ground_altitude; +	} + +	static final int speed_avg = 3; +	static final int accel_avg = 5; + +	private double avg_speed(int center, int dist) { +		if (center == 0) +			return 0; + +		double ai = avg_altitude(center, dist); +		double aj = avg_altitude(center - 1, dist); +		double s = (ai - aj) / time_step; + +		return s; +	} + +	public double speed(int i) { +		return avg_speed(i, speed_avg); +	} + +	public double acceleration(int i) { +		if (i == 0) +			return 0; +		return (avg_speed(i, accel_avg) - avg_speed(i-1, accel_avg)) / time_step; +	} + +	public double time(int i) { +		return i * time_step; +	} + +	public void save (OutputStream f) throws IOException { +		for (int c : bytes) +			f.write(c); +	} + +	public MicroData (InputStream f) throws IOException { +		bytes = new ArrayList<Integer>(); +		if (!find_header(f)) +			throw new IOException(); +		try { +			file_crc = 0xffff; +			ground_pressure = get_32(f); +			min_pressure = get_32(f); +			int nsamples = get_16(f); +			pressures = new int[nsamples + 1]; + +			ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure); +			int cur = ground_pressure; +			pressures[0] = cur; +			for (int i = 0; i < nsamples; i++) { +				int	k = get_16(f); +				int	same = mix_in(cur, k); +				int	up = mix_in(cur + 0x10000, k); +				int	down = mix_in(cur - 0x10000, k); + +				if (closer (cur, same, up)) { +					if (closer (cur, same, down)) +						cur = same; +					else +						cur = down; +				} else { +					if (closer (cur, up, down)) +						cur = up; +					else +						cur = down; +				} +				 +				pressures[i+1] = cur; +			} + +			int current_crc = swap16(~file_crc & 0xffff); +			int crc = get_16(f); + +			crc_valid = crc == current_crc; + +			time_step = 0.192; +		} catch (FileEndedException fe) { +			throw new IOException(); +		} catch (NonHexcharException ne) { +			throw new IOException(); +		} +	} +	 +} diff --git a/micropeak/MicroGraph.java b/micropeak/MicroGraph.java new file mode 100644 index 00000000..aac14b9a --- /dev/null +++ b/micropeak/MicroGraph.java @@ -0,0 +1,105 @@ +/* + * Copyright © 2012 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 org.altusmetrum.micropeak; + +import java.io.*; +import java.util.ArrayList; + +import java.awt.*; +import javax.swing.*; +import org.altusmetrum.AltosLib.*; + +import org.jfree.ui.*; +import org.jfree.chart.*; +import org.jfree.chart.plot.*; +import org.jfree.chart.axis.*; +import org.jfree.chart.renderer.*; +import org.jfree.chart.renderer.xy.*; +import org.jfree.chart.labels.*; +import org.jfree.data.xy.*; +import org.jfree.data.*; + +public class MicroGraph { + +	XYPlot		plot; +	JFreeChart	chart; +	ChartPanel	panel; +	NumberAxis	xAxis; +	XYSeries	heightSeries; +	XYSeries	speedSeries; +	XYSeries	accelSeries; + +	MicroData	data; + +	public JPanel panel() { +		return panel; +	} + +	private void addSeries(XYSeries series, int index, String label, String units) { +		XYSeriesCollection	dataset = new XYSeriesCollection(series); +		NumberAxis		axis = new NumberAxis(String.format("%s (%s)", label, units)); +		XYItemRenderer		renderer = new XYLineAndShapeRenderer(true, false); + +		renderer.setPlot(plot); +		renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator(String.format("{1}s: {2}%s ({0})", units), +										new java.text.DecimalFormat("0.00"), +										new java.text.DecimalFormat("0.00"))); +		plot.setRangeAxis(index, axis); +		plot.setDataset(index, dataset); +		plot.setRenderer(index, renderer); +		plot.mapDatasetToRangeAxis(index, index); +	} +	 +	public MicroGraph(MicroData data) { + +		this.data = data; + +		heightSeries = new XYSeries("Height"); +		speedSeries = new XYSeries("Speed"); +		accelSeries = new XYSeries("Acceleration"); + +		for (int i = 0; i < data.pressures.length; i++) { +			double x = data.time(i); +			heightSeries.add(x, data.height(i)); +			speedSeries.add(x, data.speed(i)); +			accelSeries.add(x, data.acceleration(i)); +		} + +		xAxis = new NumberAxis("Time (s)"); +		 +		xAxis.setAutoRangeIncludesZero(true); + +		plot = new XYPlot(); +		plot.setDomainAxis(xAxis); +		plot.setOrientation(PlotOrientation.VERTICAL); +		plot.setDomainPannable(true); +		plot.setRangePannable(true); + +		addSeries(heightSeries, 0, "Height", "m"); +		addSeries(speedSeries, 1, "Speed", "m/s"); +		addSeries(accelSeries, 2, "Acceleration", "m/s²"); + +		chart = new JFreeChart("Flight", JFreeChart.DEFAULT_TITLE_FONT, +				       plot, true); + +		ChartUtilities.applyCurrentTheme(chart); +		panel = new ChartPanel(chart); +		panel.setMouseWheelEnabled(true); +		panel.setPreferredSize(new java.awt.Dimension(800, 500)); +	} +}
\ No newline at end of file diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java new file mode 100644 index 00000000..82d926fb --- /dev/null +++ b/micropeak/MicroPeak.java @@ -0,0 +1,138 @@ +/* + * Copyright © 2012 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 org.altusmetrum.micropeak; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.io.*; +import java.util.concurrent.*; +import java.util.*; +import org.altusmetrum.AltosLib.*; + +public class MicroPeak extends JFrame implements ActionListener, ItemListener { + +	File		filename; +	MicroGraph	graph; +	MicroData	data; +	Container	pane; + +	private void OpenFile(File filename) { +		try { +			FileInputStream	input = new FileInputStream(filename); +			try { +				data = new MicroData(input); +				graph = new MicroGraph(data); +				pane.add(graph.panel); +			} catch (IOException ioe) { +			} +			try { +				input.close(); +			} catch (IOException ioe) { +			} +		} catch (FileNotFoundException fne) { +		} +	} + +	private void SelectFile() { +	} + +	private void DownloadData() { +		java.util.List<MicroUSB>	devices = MicroUSB.list(); +		for (MicroUSB device : devices) +			System.out.printf("device %s\n", device.toString()); +	} + +	public void actionPerformed(ActionEvent ev) { +		System.out.printf("action %s %s\n", ev.getActionCommand(), ev.paramString()); +		if ("Exit".equals(ev.getActionCommand())) +			System.exit(0); +		else if ("Open".equals(ev.getActionCommand())) +			SelectFile(); +		else if ("New".equals(ev.getActionCommand())) +			new MicroPeak(); +		else if ("Download".equals(ev.getActionCommand())) +			DownloadData(); +	} + +	public void itemStateChanged(ItemEvent e) { +	} + +	public MicroPeak(File filename) { + +		this.filename = filename; + +		pane = getContentPane(); + +//		JLabel label = new JLabel ("Hello, World"); +//		pane.add(label); + +		setSize(800, 500); + +		setTitle("MicroPeak"); + +		JMenuBar menuBar = new JMenuBar(); +		setJMenuBar(menuBar); + +		JMenu fileMenu = new JMenu("File"); +		menuBar.add(fileMenu); + +		JMenuItem newAction = new JMenuItem("New"); +		fileMenu.add(newAction); +		newAction.addActionListener(this); + +		JMenuItem openAction = new JMenuItem("Open"); +		fileMenu.add(openAction); +		openAction.addActionListener(this); + +		JMenuItem downloadAction = new JMenuItem("Download"); +		fileMenu.add(downloadAction); +		downloadAction.addActionListener(this); + +		JMenuItem exitAction = new JMenuItem("Exit"); +		fileMenu.add(exitAction); +		exitAction.addActionListener(this); + +		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); +		addWindowListener(new WindowAdapter() { +			@Override +			public void windowClosing(WindowEvent e) { +				System.exit(0); +			} +		}); + +		if (filename != null) +			this.OpenFile(filename); +		setVisible(true); +	} + +	public MicroPeak() { +		this(null); +	} + +	public static void main(final String[] args) { +		boolean	opened = false; + +		for (int i = 0; i < args.length; i++) { +			new MicroPeak(new File(args[i])); +			opened = true; +		} +		if (!opened) +			new MicroPeak(); +	} +}
\ No newline at end of file diff --git a/micropeak/MicroSerial.java b/micropeak/MicroSerial.java new file mode 100644 index 00000000..afe55532 --- /dev/null +++ b/micropeak/MicroSerial.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2012 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 org.altusmetrum.micropeak; +import java.util.*; +import java.io.*; +import libaltosJNI.*; + +public class MicroSerial extends InputStream { +	SWIGTYPE_p_altos_file	file; + +	public int read() { +		return libaltos.altos_getchar(file, 0); +	} + +	public void close() { +		if (file != null) { +			libaltos.altos_close(file); +			file = null; +		} +	} + +	public MicroSerial(MicroUSB usb) throws FileNotFoundException { +		file = usb.open(); +		if (file == null) { +			final String message = usb.getErrorString(); +			throw new FileNotFoundException(String.format("%s (%s)", +								      usb.toShortString(), +								      message)); +		} +	} +} diff --git a/micropeak/MicroUSB.java b/micropeak/MicroUSB.java new file mode 100644 index 00000000..d48610fe --- /dev/null +++ b/micropeak/MicroUSB.java @@ -0,0 +1,103 @@ +/* + * 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 org.altusmetrum.micropeak; +import java.util.*; +import libaltosJNI.*; + +public class MicroUSB extends altos_device { + +	static boolean	initialized = false; +	static boolean	loaded_library = false; + +	public static boolean load_library() { +		if (!initialized) { +			try { +				System.loadLibrary("altos"); +				libaltos.altos_init(); +				loaded_library = true; +			} catch (UnsatisfiedLinkError e) { +				try { +					System.loadLibrary("altos64"); +					libaltos.altos_init(); +					loaded_library = true; +				} catch (UnsatisfiedLinkError e2) { +					loaded_library = false; +				} +			} +			initialized = true; +		} +		return loaded_library; +	} + +	public String toString() { +		String	name = getName(); +		if (name == null) +			name = "Altus Metrum"; +		return String.format("%-20.20s %4d %s", +				     name, getSerial(), getPath()); +	} + +	public String toShortString() { +		String	name = getName(); +		if (name == null) +			name = "Altus Metrum"; +		return String.format("%s %d %s", +				     name, getSerial(), getPath()); + +	} + +	public String getErrorString() { +		altos_error	error = new altos_error(); + +		libaltos.altos_get_last_error(error); +		return String.format("%s (%d)", error.getString(), error.getCode()); +	} + +	public SWIGTYPE_p_altos_file open() { +		return libaltos.altos_open(this); +	} + +	private boolean isMicro() { +		if (getVendor() != 0x0403) +			return false; +		if (getProduct() != 0x6001) +			return false; +		return true; +	} + +	static java.util.List<MicroUSB> list() { +		if (!load_library()) +			return null; + +		SWIGTYPE_p_altos_list list = libaltos.altos_list_start(); + +		ArrayList<MicroUSB> device_list = new ArrayList<MicroUSB>(); +		if (list != null) { +			for (;;) { +				MicroUSB device = new MicroUSB(); +				if (libaltos.altos_list_next(list, device) == 0) +					break; +				if (device.isMicro()) +					device_list.add(device); +			} +			libaltos.altos_list_finish(list); +		} + +		return device_list; +	} +}
\ No newline at end of file | 
