diff options
| author | Keith Packard <keithp@keithp.com> | 2013-05-19 23:07:54 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2013-05-19 23:07:54 -0700 | 
| commit | 57b4d82dee10b142b820aa306028a288a85214f6 (patch) | |
| tree | 9150c9a89e622e63aa9164d11c3127652bd553a4 | |
| parent | 27e9b93f3d35890a49575b2ead1983ce3c2fc213 (diff) | |
Add Mini logging format. Use in EasyMinilpc
This is a 16-byte record that includes all of the sensor data in each
sensor record, along with records for flight state changes.
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | altoslib/AltosEepromMini.java | 193 | ||||
| -rw-r--r-- | altoslib/AltosEepromMiniIterable.java | 297 | ||||
| -rw-r--r-- | altoslib/AltosLib.java | 1 | ||||
| -rw-r--r-- | altoslib/AltosOrderedMiniRecord.java | 52 | ||||
| -rw-r--r-- | altoslib/AltosRecordMini.java | 129 | ||||
| -rw-r--r-- | altoslib/Makefile.am | 4 | ||||
| -rw-r--r-- | altosui/AltosDataChooser.java | 7 | ||||
| -rw-r--r-- | altosui/AltosEepromDownload.java | 50 | ||||
| -rw-r--r-- | altosui/AltosLanded.java | 3 | ||||
| -rw-r--r-- | altosui/AltosUI.java | 4 | ||||
| -rw-r--r-- | src/core/ao_log.h | 38 | ||||
| -rw-r--r-- | src/core/ao_log_mini.c | 163 | ||||
| -rw-r--r-- | src/easymini-v0.1/Makefile | 2 | ||||
| -rw-r--r-- | src/easymini-v0.1/ao_pins.h | 9 | 
14 files changed, 947 insertions, 5 deletions
diff --git a/altoslib/AltosEepromMini.java b/altoslib/AltosEepromMini.java new file mode 100644 index 00000000..215cd3d9 --- /dev/null +++ b/altoslib/AltosEepromMini.java @@ -0,0 +1,193 @@ +/* + * Copyright © 2011 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.altoslib_1; + +import java.text.*; + +public class AltosEepromMini { +	public int	cmd; +	public int	tick; +	public boolean	valid; +	public String	data; +	public int	config_a, config_b; + +	public int	data8[]; + +	public static final int	record_length = 16; +	static final int	header_length = 4; +	static final int	data_length = record_length - header_length; + +	public int data8(int i) { +		return data8[i]; +	} + +	public int data16(int i) { +		return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16; +	} + +	public int data24(int i) { +		return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16); +	} + +	public int data32(int i) { +		return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24); +	} + +	/* AO_LOG_FLIGHT elements */ +	public int flight() { return data16(0); } +	public int ground_pres() { return data32(4); } + +	/* AO_LOG_STATE elements */ +	public int state() { return data16(0); } +	public int reason() { return data16(2); } + +	/* AO_LOG_SENSOR elements */ +	public int pres() { return data24(0); } +	public int temp() { return data24(3); } +	public int sense_a() { return data16(6); } +	public int sense_m() { return data16(8); } +	public int v_batt() { return data16(10); } + +	public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException { +		cmd = chunk.data(start); + +		valid = !chunk.erased(start, record_length); +		if (valid) { +			if (AltosConvert.checksum(chunk.data, start, record_length) != 0) +				throw new ParseException(String.format("invalid checksum at 0x%x", +								       chunk.address + start), 0); +		} else { +			cmd = AltosLib.AO_LOG_INVALID; +		} + +		tick = chunk.data16(start+2); + +		data8 = new int[data_length]; +		for (int i = 0; i < data_length; i++) +			data8[i] = chunk.data(start + header_length + i); +	} + +	public AltosEepromMini (String line) { +		valid = false; +		tick = 0; + +		if (line == null) { +			cmd = AltosLib.AO_LOG_INVALID; +			line = ""; +		} else { +			try { +				String[] tokens = line.split("\\s+"); + +				if (tokens[0].length() == 1) { +					if (tokens.length != 2 + data_length) { +						cmd = AltosLib.AO_LOG_INVALID; +						data = line; +					} else { +						cmd = tokens[0].codePointAt(0); +						tick = Integer.parseInt(tokens[1],16); +						valid = true; +						data8 = new int[data_length]; +						for (int i = 0; i < data_length; i++) +							data8[i] = Integer.parseInt(tokens[2 + i],16); +					} +				} else if (tokens[0].equals("Config") && tokens[1].equals("version:")) { +					cmd = AltosLib.AO_LOG_CONFIG_VERSION; +					data = tokens[2]; +				} else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) { +					cmd = AltosLib.AO_LOG_MAIN_DEPLOY; +					config_a = Integer.parseInt(tokens[2]); +				} else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) { +					cmd = AltosLib.AO_LOG_APOGEE_DELAY; +					config_a = Integer.parseInt(tokens[2]); +				} else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) { +					cmd = AltosLib.AO_LOG_RADIO_CHANNEL; +					config_a = Integer.parseInt(tokens[2]); +				} else if (tokens[0].equals("Callsign:")) { +					cmd = AltosLib.AO_LOG_CALLSIGN; +					data = tokens[1].replaceAll("\"",""); +				} else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) { +					cmd = AltosLib.AO_LOG_ACCEL_CAL; +					config_a = Integer.parseInt(tokens[3]); +					config_b = Integer.parseInt(tokens[5]); +				} else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) { +					cmd = AltosLib.AO_LOG_RADIO_CAL; +					config_a = Integer.parseInt(tokens[2]); +				} else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) { +					cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG; +					config_a = Integer.parseInt(tokens[3]); +				} else if (tokens[0].equals("manufacturer")) { +					cmd = AltosLib.AO_LOG_MANUFACTURER; +					data = tokens[1]; +				} else if (tokens[0].equals("product")) { +					cmd = AltosLib.AO_LOG_PRODUCT; +					data = tokens[1]; +				} else if (tokens[0].equals("serial-number")) { +					cmd = AltosLib.AO_LOG_SERIAL_NUMBER; +					config_a = Integer.parseInt(tokens[1]); +				} else if (tokens[0].equals("log-format")) { +					cmd = AltosLib.AO_LOG_LOG_FORMAT; +					config_a = Integer.parseInt(tokens[1]); +				} else if (tokens[0].equals("software-version")) { +					cmd = AltosLib.AO_LOG_SOFTWARE_VERSION; +					data = tokens[1]; +				} else if (tokens[0].equals("ms5607")) { +					if (tokens[1].equals("reserved:")) { +						cmd = AltosLib.AO_LOG_BARO_RESERVED; +						config_a = Integer.parseInt(tokens[2]); +					} else if (tokens[1].equals("sens:")) { +						cmd = AltosLib.AO_LOG_BARO_SENS; +						config_a = Integer.parseInt(tokens[2]); +					} else if (tokens[1].equals("off:")) { +						cmd = AltosLib.AO_LOG_BARO_OFF; +						config_a = Integer.parseInt(tokens[2]); +					} else if (tokens[1].equals("tcs:")) { +						cmd = AltosLib.AO_LOG_BARO_TCS; +						config_a = Integer.parseInt(tokens[2]); +					} else if (tokens[1].equals("tco:")) { +						cmd = AltosLib.AO_LOG_BARO_TCO; +						config_a = Integer.parseInt(tokens[2]); +					} else if (tokens[1].equals("tref:")) { +						cmd = AltosLib.AO_LOG_BARO_TREF; +						config_a = Integer.parseInt(tokens[2]); +					} else if (tokens[1].equals("tempsens:")) { +						cmd = AltosLib.AO_LOG_BARO_TEMPSENS; +						config_a = Integer.parseInt(tokens[2]); +					} else if (tokens[1].equals("crc:")) { +						cmd = AltosLib.AO_LOG_BARO_CRC; +						config_a = Integer.parseInt(tokens[2]); +					} else { +						cmd = AltosLib.AO_LOG_INVALID; +						data = line; +					} +				} else { +					cmd = AltosLib.AO_LOG_INVALID; +					data = line; +				} +			} catch (NumberFormatException ne) { +				cmd = AltosLib.AO_LOG_INVALID; +				data = line; +			} +		} +	} + +	public AltosEepromMini(int in_cmd, int in_tick) { +		cmd = in_cmd; +		tick = in_tick; +		valid = true; +	} +} diff --git a/altoslib/AltosEepromMiniIterable.java b/altoslib/AltosEepromMiniIterable.java new file mode 100644 index 00000000..1f221187 --- /dev/null +++ b/altoslib/AltosEepromMiniIterable.java @@ -0,0 +1,297 @@ +/* + * 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.altoslib_1; + +import java.io.*; +import java.util.*; +import java.text.*; + +public class AltosEepromMiniIterable extends AltosRecordIterable { + +	static final int	seen_flight = 1; +	static final int	seen_sensor = 2; + +	static final int	seen_basic = seen_flight|seen_sensor; + +	boolean			has_accel; +	boolean			has_gps; +	boolean			has_ignite; + +	AltosEepromMini	flight_record; + +	TreeSet<AltosOrderedMiniRecord>	records; + +	AltosMs5607		baro; + +	LinkedList<AltosRecord>	list; + +	class EepromState { +		int	seen; +		int	n_pad_samples; +		double	ground_pres; +		int	boost_tick; +		int	sensor_tick; + +		EepromState() { +			seen = 0; +			n_pad_samples = 0; +			ground_pres = 0.0; +		} +	} + +	void update_state(AltosRecordMini state, AltosEepromMini record, EepromState eeprom) { +		state.tick = record.tick; +		switch (record.cmd) { +		case AltosLib.AO_LOG_FLIGHT: +			eeprom.seen |= seen_flight; +			state.ground_pres = record.ground_pres(); +			state.flight_pres = state.ground_pres; +			state.flight = record.data16(0); +			eeprom.boost_tick = record.tick; +			break; +		case AltosLib.AO_LOG_SENSOR: +			baro.set(record.pres(), record.temp()); +			state.pres = baro.pa; +			state.temp = baro.cc; +			state.sense_m = record.sense_m(); +			state.sense_a = record.sense_a(); +			state.v_batt = record.v_batt(); +			if (state.state < AltosLib.ao_flight_boost) { +				eeprom.n_pad_samples++; +				eeprom.ground_pres += state.pres; +				state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples); +				state.flight_pres = state.ground_pres; +			} else { +				state.flight_pres = (state.flight_pres * 15 + state.pres) / 16; +			} +			if ((eeprom.seen & seen_sensor) == 0) +				eeprom.sensor_tick = record.tick - 1; +			eeprom.seen |= seen_sensor; +			eeprom.sensor_tick = record.tick; +			break; +		case AltosLib.AO_LOG_STATE: +			state.state = record.state(); +			break; +		case AltosLib.AO_LOG_CONFIG_VERSION: +			break; +		case AltosLib.AO_LOG_MAIN_DEPLOY: +			break; +		case AltosLib.AO_LOG_APOGEE_DELAY: +			break; +		case AltosLib.AO_LOG_RADIO_CHANNEL: +			break; +		case AltosLib.AO_LOG_CALLSIGN: +			state.callsign = record.data; +			break; +		case AltosLib.AO_LOG_RADIO_CAL: +			break; +		case AltosLib.AO_LOG_MANUFACTURER: +			break; +		case AltosLib.AO_LOG_PRODUCT: +			break; +		case AltosLib.AO_LOG_SERIAL_NUMBER: +			state.serial = record.config_a; +			break; +		case AltosLib.AO_LOG_SOFTWARE_VERSION: +			break; +		case AltosLib.AO_LOG_BARO_RESERVED: +			baro.reserved = record.config_a; +			break; +		case AltosLib.AO_LOG_BARO_SENS: +			baro.sens =record.config_a; +			break; +		case AltosLib.AO_LOG_BARO_OFF: +			baro.off =record.config_a; +			break; +		case AltosLib.AO_LOG_BARO_TCS: +			baro.tcs =record.config_a; +			break; +		case AltosLib.AO_LOG_BARO_TCO: +			baro.tco =record.config_a; +			break; +		case AltosLib.AO_LOG_BARO_TREF: +			baro.tref =record.config_a; +			break; +		case AltosLib.AO_LOG_BARO_TEMPSENS: +			baro.tempsens =record.config_a; +			break; +		case AltosLib.AO_LOG_BARO_CRC: +			baro.crc =record.config_a; +			break; +		} +		state.seen |= eeprom.seen; +	} + +	LinkedList<AltosRecord> make_list() { +		LinkedList<AltosRecord>		list = new LinkedList<AltosRecord>(); +		Iterator<AltosOrderedMiniRecord> iterator = records.iterator(); +		AltosOrderedMiniRecord		record = null; +		AltosRecordMini			state = new AltosRecordMini(); +		//boolean			last_reported = false; +		EepromState			eeprom = new EepromState(); + +		state.state = AltosLib.ao_flight_pad; + +		/* Pull in static data from the flight records */ +		if (flight_record != null) +			update_state(state, flight_record, eeprom); + +		while (iterator.hasNext()) { +			record = iterator.next(); +			if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) { +				AltosRecordMini r = state.clone(); +				r.time = (r.tick - eeprom.boost_tick) / 100.0; +				list.add(r); +			} +			update_state(state, record, eeprom); +		} +		AltosRecordMini r = state.clone(); +		r.time = (r.tick - eeprom.boost_tick) / 100.0; +		list.add(r); +		return list; +	} + +	public Iterator<AltosRecord> iterator() { +		if (list == null) +			list = make_list(); +		return list.iterator(); +	} + +	public boolean has_gps() { return has_gps; } +	public boolean has_accel() { return has_accel; } +	public boolean has_ignite() { return has_ignite; } + +	public void write_comments(PrintStream out) { +		Iterator<AltosOrderedMiniRecord>	iterator = records.iterator(); +		out.printf("# Comments\n"); +		while (iterator.hasNext()) { +			AltosOrderedMiniRecord	record = iterator.next(); +			switch (record.cmd) { +			case AltosLib.AO_LOG_CONFIG_VERSION: +				out.printf("# Config version: %s\n", record.data); +				break; +			case AltosLib.AO_LOG_MAIN_DEPLOY: +				out.printf("# Main deploy: %s\n", record.config_a); +				break; +			case AltosLib.AO_LOG_APOGEE_DELAY: +				out.printf("# Apogee delay: %s\n", record.config_a); +				break; +			case AltosLib.AO_LOG_RADIO_CHANNEL: +				out.printf("# Radio channel: %s\n", record.config_a); +				break; +			case AltosLib.AO_LOG_CALLSIGN: +				out.printf("# Callsign: %s\n", record.data); +				break; +			case AltosLib.AO_LOG_ACCEL_CAL: +				out.printf ("# Accel cal: %d %d\n", record.config_a, record.config_b); +				break; +			case AltosLib.AO_LOG_RADIO_CAL: +				out.printf ("# Radio cal: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_MAX_FLIGHT_LOG: +				out.printf ("# Max flight log: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_MANUFACTURER: +				out.printf ("# Manufacturer: %s\n", record.data); +				break; +			case AltosLib.AO_LOG_PRODUCT: +				out.printf ("# Product: %s\n", record.data); +				break; +			case AltosLib.AO_LOG_SERIAL_NUMBER: +				out.printf ("# Serial number: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_SOFTWARE_VERSION: +				out.printf ("# Software version: %s\n", record.data); +				break; +			case AltosLib.AO_LOG_BARO_RESERVED: +				out.printf ("# Baro reserved: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_BARO_SENS: +				out.printf ("# Baro sens: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_BARO_OFF: +				out.printf ("# Baro off: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_BARO_TCS: +				out.printf ("# Baro tcs: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_BARO_TCO: +				out.printf ("# Baro tco: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_BARO_TREF: +				out.printf ("# Baro tref: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_BARO_TEMPSENS: +				out.printf ("# Baro tempsens: %d\n", record.config_a); +				break; +			case AltosLib.AO_LOG_BARO_CRC: +				out.printf ("# Baro crc: %d\n", record.config_a); +				break; +			} +		} +	} + +	/* +	 * Read the whole file, dumping records into a RB tree so +	 * we can enumerate them in time order -- the eeprom data +	 * are sometimes out of order +	 */ +	public AltosEepromMiniIterable (FileInputStream input) { +		records = new TreeSet<AltosOrderedMiniRecord>(); + +		AltosOrderedMiniRecord last_gps_time = null; + +		baro = new AltosMs5607(); + +		int index = 0; +		int prev_tick = 0; +		boolean prev_tick_valid = false; +		boolean missing_time = false; + +		try { +			for (;;) { +				String line = AltosLib.gets(input); +				if (line == null) +					break; +				AltosOrderedMiniRecord record = new AltosOrderedMiniRecord(line, index++, prev_tick, prev_tick_valid); +				if (record.cmd == AltosLib.AO_LOG_INVALID) +					continue; +				prev_tick = record.tick; +				if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION) +					prev_tick_valid = true; +				if (record.cmd == AltosLib.AO_LOG_FLIGHT) { +					flight_record = record; +					continue; +				} + +				records.add(record); + +				/* Bail after reading the 'landed' record; we're all done */ +				if (record.cmd == AltosLib.AO_LOG_STATE && +				    record.state() == AltosLib.ao_flight_landed) +					break; +			} +		} catch (IOException io) { +		} catch (ParseException pe) { +		} +		try { +			input.close(); +		} catch (IOException ie) { +		} +	} +} diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 25d17e72..a629260b 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -216,6 +216,7 @@ public class AltosLib {  	public static final int AO_LOG_FORMAT_TELEMETRY = 3;  	public static final int AO_LOG_FORMAT_TELESCIENCE = 4;  	public static final int AO_LOG_FORMAT_TELEMEGA = 5; +	public static final int AO_LOG_FORMAT_MINI = 6;  	public static final int AO_LOG_FORMAT_NONE = 127;  	public static boolean isspace(int c) { diff --git a/altoslib/AltosOrderedMiniRecord.java b/altoslib/AltosOrderedMiniRecord.java new file mode 100644 index 00000000..96888941 --- /dev/null +++ b/altoslib/AltosOrderedMiniRecord.java @@ -0,0 +1,52 @@ +/* + * 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.altoslib_1; + +import java.text.ParseException; + +/* + * AltosRecords with an index field so they can be sorted by tick while preserving + * the original ordering for elements with matching ticks + */ +class AltosOrderedMiniRecord extends AltosEepromMini implements Comparable<AltosOrderedMiniRecord> { + +	public int	index; + +	public AltosOrderedMiniRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid) +		throws ParseException { +		super(line); +		if (prev_tick_valid) { +			tick |= (prev_tick & ~0xffff); +			if (tick < prev_tick) { +				if (prev_tick - tick > 0x8000) +					tick += 0x10000; +			} else { +				if (tick - prev_tick > 0x8000) +					tick -= 0x10000; +			} +		} +		index = in_index; +	} + +	public int compareTo(AltosOrderedMiniRecord o) { +		int	tick_diff = tick - o.tick; +		if (tick_diff != 0) +			return tick_diff; +		return index - o.index; +	} +} diff --git a/altoslib/AltosRecordMini.java b/altoslib/AltosRecordMini.java new file mode 100644 index 00000000..253f3804 --- /dev/null +++ b/altoslib/AltosRecordMini.java @@ -0,0 +1,129 @@ +/* + * 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.altoslib_1; + +public class AltosRecordMini extends AltosRecord { + +	/* Sensor values */ +	public int	pres; +	public int	temp; +	 +	public int	sense_a; +	public int	sense_m; +	public int	v_batt; + +	public int      ground_pres; + +	public int	flight_accel; +	public int	flight_vel; +	public int	flight_pres; + +	static double adc(int raw) { +		return raw / 4095.0; +	} + +	public double pressure() { +		if (pres != MISSING) +			return pres; +		return MISSING; +	} + +	public double temperature() { +		if (temp != MISSING) +			return temp; +		return MISSING; +	} + +	public double ground_pressure() { +		if (ground_pres != MISSING) +			return ground_pres; +		return MISSING; +	} + +	public double battery_voltage() { +		if (v_batt != MISSING) +			return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0; +		return MISSING; +	} + +	static double pyro(int raw) { +		if (raw != MISSING) +			return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0; +		return MISSING; +	} + +	public double main_voltage() { +		return pyro(sense_m); +	} + +	public double apogee_voltage() { +		return pyro(sense_a); +	} + +	public void copy (AltosRecordMini old) { +		super.copy(old); + +		pres = old.pres; +		temp = old.temp; + +		sense_a = old.sense_a; +		sense_m = old.sense_m; +		v_batt = old.v_batt; + +		ground_pres = old.ground_pres; +		 +		flight_accel = old.flight_accel; +		flight_vel = old.flight_vel; +		flight_pres = old.flight_pres; +	} + + + +	public AltosRecordMini clone() { +		return new AltosRecordMini(this); +	} + +	void make_missing() { + +		pres = MISSING; + +		sense_a = MISSING; +		sense_m = MISSING; +		v_batt = MISSING; + +		ground_pres = MISSING; + +		flight_accel = 0; +		flight_vel = 0; +		flight_pres = 0; +	} + +	public AltosRecordMini(AltosRecord old) { +		super.copy(old); +		make_missing(); +	} + +	public AltosRecordMini(AltosRecordMini old) { +		copy(old); +	} + +	public AltosRecordMini() { +		super(); +		make_missing(); +	} +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 18b028d6..8c1cf2ad 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -24,6 +24,8 @@ altoslib_JAVA = \  	AltosEepromMegaIterable.java \  	AltosEepromRecord.java \  	AltosEepromTeleScience.java \ +	AltosEepromMini.java \ +	AltosEepromMiniIterable.java \  	AltosFile.java \  	AltosFlash.java \  	AltosFlashListener.java \ @@ -47,6 +49,7 @@ altoslib_JAVA = \  	AltosMs5607Query.java \  	AltosOrderedRecord.java \  	AltosOrderedMegaRecord.java \ +	AltosOrderedMiniRecord.java \  	AltosParse.java \  	AltosPreferences.java \  	AltosPreferencesBackend.java \ @@ -56,6 +59,7 @@ altoslib_JAVA = \  	AltosRecordNone.java \  	AltosRecordTM.java \  	AltosRecordMM.java \ +	AltosRecordMini.java \  	AltosReplayReader.java \  	AltosRomconfig.java \  	AltosSensorMM.java \ diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index f914f138..c7b561d5 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -55,6 +55,9 @@ public class AltosDataChooser extends JFileChooser {  				} else if (filename.endsWith("mega")) {  					FileInputStream in = new FileInputStream(file);  					return new AltosEepromMegaIterable(in); +				} else if (filename.endsWith("mini")) { +					FileInputStream in = new FileInputStream(file); +					return new AltosEepromMiniIterable(in);  				} else {  					throw new FileNotFoundException();  				} @@ -77,8 +80,10 @@ public class AltosDataChooser extends JFileChooser {  							  "telem"));  		setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file",  							  "mega")); +		setFileFilter(new FileNameExtensionFilter("EasyMini eeprom file", +							  "mini"));  		setFileFilter(new FileNameExtensionFilter("Flight data file", -							  "telem", "eeprom", "mega")); +							  "telem", "eeprom", "mega", "mini"));  		setCurrentDirectory(AltosUIPreferences.logdir());  	}  } diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index a0523b58..53d5433f 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -302,6 +302,53 @@ public class AltosEepromDownload implements Runnable {  		CheckFile(false);  	} +	void LogMini(AltosEepromMini r) throws IOException { +		if (r.cmd != Altos.AO_LOG_INVALID) { +			String log_line = String.format("%c %4x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", +							r.cmd, r.tick, +							r.data8[0], r.data8[1], r.data8[2], r.data8[3], +							r.data8[4], r.data8[5], r.data8[6], r.data8[7], +							r.data8[8], r.data8[9], r.data8[10], r.data8[11]); +			if (eeprom_file != null) +				eeprom_file.write(log_line); +			else +				eeprom_pending.add(log_line); +		} +	} + +	void CaptureMini(AltosEepromChunk eechunk) throws IOException { +		boolean any_valid = false; + +		extension = "mini"; +		set_serial(flights.config_data.serial); +		for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromMini.record_length) { +			try { +				AltosEepromMini r = new AltosEepromMini(eechunk, i); +				if (r.cmd == Altos.AO_LOG_FLIGHT) +					set_flight(r.data16(0)); + +				/* Monitor state transitions to update display */ +				if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) <= Altos.ao_flight_landed) { +					state = r.data16(0); +					if (state > Altos.ao_flight_pad) +						want_file = true; +				} + +				if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) == Altos.ao_flight_landed) +					done = true; +				any_valid = true; +				LogMini(r); +			} catch (ParseException pe) { +				if (parse_exception == null) +					parse_exception = pe; +			} +		} +		if (!any_valid) +			done = true; + +		CheckFile(false); +	} +	  	void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException {  	} @@ -369,6 +416,9 @@ public class AltosEepromDownload implements Runnable {  			case AltosLib.AO_LOG_FORMAT_TELEMEGA:  				extension = "mega";  				CaptureMega(eechunk); +			case AltosLib.AO_LOG_FORMAT_MINI: +				extension = "mini"; +				CaptureMini(eechunk);  			}  		}  		CheckFile(true); diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 1d209bda..9dab52c4 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -253,6 +253,9 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio  					} else if (filename.endsWith("mega")) {  						FileInputStream in = new FileInputStream(file);  						records = new AltosEepromMegaIterable(in); +					} else if (filename.endsWith("mini")) { +						FileInputStream in = new FileInputStream(file); +						records = new AltosEepromMiniIterable(in);  					} else {  						throw new FileNotFoundException(filename);  					} diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index 9f8f6dda..4362e36c 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -354,6 +354,8 @@ public class AltosUI extends AltosUIFrame {  				return new AltosEepromIterable(in);  			else if (file.getName().endsWith("mega"))  				return new AltosEepromMegaIterable(in); +			else if (file.getName().endsWith("mini")) +				return new AltosEepromMiniIterable(in);  			else  				return new AltosTelemetryIterable(in);  		} catch (FileNotFoundException fe) { @@ -441,6 +443,8 @@ public class AltosUI extends AltosUIFrame {  			recs = new AltosEepromIterable(in);  		} else if (file.getName().endsWith("mega")) {  			recs = new AltosEepromMegaIterable(in); +		} else if (file.getName().endsWith("mini")) { +			recs = new AltosEepromMiniIterable(in);  		} else {  			recs = new AltosTelemetryIterable(in);  		} diff --git a/src/core/ao_log.h b/src/core/ao_log.h index a68a40dd..95b37649 100644 --- a/src/core/ao_log.h +++ b/src/core/ao_log.h @@ -44,6 +44,7 @@ extern __pdata enum ao_flight_state ao_log_state;  #define AO_LOG_FORMAT_TELEMETRY		3	/* 32 byte ao_telemetry records */  #define AO_LOG_FORMAT_TELESCIENCE	4	/* 32 byte typed telescience records */  #define AO_LOG_FORMAT_TELEMEGA		5	/* 32 byte typed telemega records */ +#define AO_LOG_FORMAT_MINI		6	/* 16-byte MS5607 baro only */  #define AO_LOG_FORMAT_NONE		127	/* No log at all */  extern __code uint8_t ao_log_format; @@ -261,6 +262,40 @@ struct ao_log_mega {  	} u;  }; +struct ao_log_mini { +	char		type;				/* 0 */ +	uint8_t		csum;				/* 1 */ +	uint16_t	tick;				/* 2 */ +	union {						/* 4 */ +		/* AO_LOG_FLIGHT */ +		struct { +			uint16_t	flight;		/* 4 */ +			uint16_t	r6; +			uint32_t	ground_pres;	/* 8 */ +		} flight; +		/* AO_LOG_STATE */ +		struct { +			uint16_t	state;		/* 4 */ +			uint16_t	reason;		/* 6 */ +		} state; +		/* AO_LOG_SENSOR */ +		struct { +			uint8_t		pres[3];	/* 4 */ +			uint8_t		temp[3];	/* 7 */ +			int16_t		sense_a;	/* 10 */ +			int16_t		sense_m;	/* 12 */ +			int16_t		v_batt;		/* 14 */ +		} sensor;				/* 16 */ +	} u;						/* 16 */ +};							/* 16 */ + +static inline void +ao_log_pack24(uint8_t *dst, uint32_t value) { +	dst[0] = value; +	dst[1] = value >> 8; +	dst[2] = value >> 16; +} +  /* Write a record to the eeprom log */  uint8_t  ao_log_data(__xdata struct ao_log_record *log) __reentrant; @@ -268,6 +303,9 @@ ao_log_data(__xdata struct ao_log_record *log) __reentrant;  uint8_t  ao_log_mega(__xdata struct ao_log_mega *log) __reentrant; +uint8_t +ao_log_mini(__xdata struct ao_log_mini *log) __reentrant; +  void  ao_log_flush(void); diff --git a/src/core/ao_log_mini.c b/src/core/ao_log_mini.c new file mode 100644 index 00000000..1273b0e3 --- /dev/null +++ b/src/core/ao_log_mini.c @@ -0,0 +1,163 @@ +/* + * 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. + */ + +#include "ao.h" +#include <ao_log.h> +#include <ao_data.h> +#include <ao_flight.h> + +static __xdata uint8_t	ao_log_mutex; +static __xdata struct ao_log_mini log; + +__code uint8_t ao_log_format = AO_LOG_FORMAT_MINI; + +static uint8_t +ao_log_csum(__xdata uint8_t *b) __reentrant +{ +	uint8_t	sum = 0x5a; +	uint8_t	i; + +	for (i = 0; i < sizeof (struct ao_log_mini); i++) +		sum += *b++; +	return -sum; +} + +uint8_t +ao_log_mini(__xdata struct ao_log_mini *log) __reentrant +{ +	uint8_t wrote = 0; +	/* set checksum */ +	log->csum = 0; +	log->csum = ao_log_csum((__xdata uint8_t *) log); +	ao_mutex_get(&ao_log_mutex); { +		if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) +			ao_log_stop(); +		if (ao_log_running) { +			wrote = 1; +			ao_storage_write(ao_log_current_pos, +					 log, +					 sizeof (struct ao_log_mini)); +			ao_log_current_pos += sizeof (struct ao_log_mini); +		} +	} ao_mutex_put(&ao_log_mutex); +	return wrote; +} + +static uint8_t +ao_log_dump_check_data(void) +{ +	if (ao_log_csum((uint8_t *) &log) != 0) +		return 0; +	return 1; +} + +static __data uint8_t	ao_log_data_pos; + +/* a hack to make sure that ao_log_minis fill the eeprom block in even units */ +typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mini))] ; + +#ifndef AO_SENSOR_INTERVAL_ASCENT +#define AO_SENSOR_INTERVAL_ASCENT	1 +#define AO_SENSOR_INTERVAL_DESCENT	10 +#endif + +void +ao_log(void) +{ +	__pdata uint16_t	next_sensor, next_other; +	uint8_t			i; + +	ao_storage_setup(); + +	ao_log_scan(); + +	while (!ao_log_running) +		ao_sleep(&ao_log_running); + +#if HAS_FLIGHT +	log.type = AO_LOG_FLIGHT; +	log.tick = ao_sample_tick; +	log.u.flight.flight = ao_flight_number; +	log.u.flight.ground_pres = ao_ground_pres; +	ao_log_mini(&log); +#endif + +	/* Write the whole contents of the ring to the log +	 * when starting up. +	 */ +	ao_log_data_pos = ao_data_ring_next(ao_data_head); +	next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick; +	ao_log_state = ao_flight_startup; +	for (;;) { +		/* Write samples to EEPROM */ +		while (ao_log_data_pos != ao_data_head) { +			log.tick = ao_data_ring[ao_log_data_pos].tick; +			if ((int16_t) (log.tick - next_sensor) >= 0) { +				log.type = AO_LOG_SENSOR; +				ao_log_pack24(log.u.sensor.pres, +					      ao_data_ring[ao_log_data_pos].ms5607_raw.pres); +				ao_log_pack24(log.u.sensor.temp, +					      ao_data_ring[ao_log_data_pos].ms5607_raw.temp); +				log.u.sensor.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a; +				log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m; +				log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt; +				ao_log_mini(&log); +				if (ao_log_state <= ao_flight_coast) +					next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT; +				else +					next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT; +			} +			ao_log_data_pos = ao_data_ring_next(ao_log_data_pos); +		} +#if HAS_FLIGHT +		/* Write state change to EEPROM */ +		if (ao_flight_state != ao_log_state) { +			ao_log_state = ao_flight_state; +			log.type = AO_LOG_STATE; +			log.tick = ao_time(); +			log.u.state.state = ao_log_state; +			log.u.state.reason = 0; +			ao_log_mini(&log); + +			if (ao_log_state == ao_flight_landed) +				ao_log_stop(); +		} +#endif + +		ao_log_flush(); + +		/* Wait for a while */ +		ao_delay(AO_MS_TO_TICKS(100)); + +		/* Stop logging when told to */ +		while (!ao_log_running) +			ao_sleep(&ao_log_running); +	} +} + +uint16_t +ao_log_flight(uint8_t slot) +{ +	if (!ao_storage_read(ao_log_pos(slot), +			     &log, +			     sizeof (struct ao_log_mini))) +		return 0; + +	if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) +		return log.u.flight.flight; +	return 0; +} diff --git a/src/easymini-v0.1/Makefile b/src/easymini-v0.1/Makefile index c4e60ada..612cc472 100644 --- a/src/easymini-v0.1/Makefile +++ b/src/easymini-v0.1/Makefile @@ -34,7 +34,7 @@ ALTOS_SRC = \  	ao_led_lpc.c \  	ao_task.c \  	ao_log.c \ -	ao_log_tiny.c \ +	ao_log_mini.c \  	ao_cmd.c \  	ao_config.c \  	ao_timer_lpc.c \ diff --git a/src/easymini-v0.1/ao_pins.h b/src/easymini-v0.1/ao_pins.h index 4102c21d..d4fbe7a1 100644 --- a/src/easymini-v0.1/ao_pins.h +++ b/src/easymini-v0.1/ao_pins.h @@ -106,7 +106,7 @@  #define AO_ADC_2		1  struct ao_adc { -	int16_t		sense_d; +	int16_t		sense_a;  	int16_t		sense_m;  	int16_t		v_batt;  }; @@ -126,6 +126,9 @@ struct ao_adc {  #define AO_IGNITER_MAIN_PIN	3  #define AO_IGNITER_SET_MAIN(v)		ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v) +#define AO_SENSE_DROGUE(p)	((p)->adc.sense_a) +#define AO_SENSE_MAIN(p)	((p)->adc.sense_m) +  #define AO_ADC_DUMP(p) \ -	printf("tick: %5u drogue: %5d main: %5d batt: %5d\n", \ -	       (p)->tick, (p)->adc.sense_d, (p)->adc.sense_m, (p)->adc.v_batt) +	printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \ +	       (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)  | 
