diff options
60 files changed, 1389 insertions, 395 deletions
| diff --git a/altosdroid/.externalToolBuilders/Generate BuildInfo.java.launch b/altosdroid/.externalToolBuilders/Generate BuildInfo.java.launch new file mode 100644 index 00000000..3b8eff45 --- /dev/null +++ b/altosdroid/.externalToolBuilders/Generate BuildInfo.java.launch @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType"> +<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?>
<resources>
<item path="/AltosDroid/src/org/altusmetrum/AltosDroid/BuildInfo.java" type="1"/>
</resources>}"/> +<booleanAttribute key="org.eclipse.debug.core.capture_output" value="false"/> +<booleanAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON" value="false"/> +<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/> +<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/AltosDroid/buildinfo.sh}"/> +<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/> +<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/> +<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/AltosDroid}"/> +</launchConfiguration> diff --git a/altosdroid/.gitignore b/altosdroid/.gitignore index c0bb8dd4..e3acba40 100644 --- a/altosdroid/.gitignore +++ b/altosdroid/.gitignore @@ -1,3 +1,4 @@  local.properties  bin  gen +src/org/altusmetrum/AltosDroid/BuildInfo.java diff --git a/altosdroid/.project b/altosdroid/.project index 7b56596a..ebe4a4bb 100644 --- a/altosdroid/.project +++ b/altosdroid/.project @@ -6,6 +6,16 @@  	</projects>  	<buildSpec>  		<buildCommand> +			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name> +			<triggers>auto,full,incremental,</triggers> +			<arguments> +				<dictionary> +					<key>LaunchConfigHandle</key> +					<value><project>/.externalToolBuilders/Generate BuildInfo.java.launch</value> +				</dictionary> +			</arguments> +		</buildCommand> +		<buildCommand>  			<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>  			<arguments>  			</arguments> diff --git a/altosdroid/Makefile.am b/altosdroid/Makefile.am index 96831b72..3860e110 100644 --- a/altosdroid/Makefile.am +++ b/altosdroid/Makefile.am @@ -30,6 +30,7 @@ SRC=\  	$(SRC_DIR)/TelemetryLogger.java \  	$(SRC_DIR)/AltosBluetooth.java \  	$(SRC_DIR)/DeviceListActivity.java \ +	$(SRC_DIR)/BuildInfo.java \  	$(SRC_DIR)/Dumper.java  all: $(all_target) @@ -38,6 +39,9 @@ $(ALTOSLIB): $(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR)  	mkdir -p $(EXT_LIBDIR)  	cd $(EXT_LIBDIR) && ln -s $(shell echo $(EXT_LIBDIR) | sed 's|[^/]\+|..|g')/$(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR) . +$(SRC_DIR)/BuildInfo.java: +	./buildinfo.sh +  if ANDROID  install-release: bin/AltosDroid-release.apk  	$(ADB) install -r bin/AltosDroid-release.apk @@ -55,3 +59,4 @@ endif  clean:  	$(clean_command) +.PHONY: $(SRC_DIR)/BuildInfo.java diff --git a/altosdroid/buildinfo.sh b/altosdroid/buildinfo.sh new file mode 100755 index 00000000..f620c4a0 --- /dev/null +++ b/altosdroid/buildinfo.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# + +describe=$(git describe --always 2>/dev/null || echo '') +if [ -n "$describe" ]; then +   version=$(echo $describe | cut -d- -f1) +   commitnum=$(echo $describe | cut -d- -f2) +   commithash=$(echo $describe | cut -d- -f3) +else +   . ../src/Version +   version=$VERSION +   commitnum='' +   commithash='' +fi + +builddate=$(date "+%Y-%m-%d") +buildtime=$(date "+%H:%M") + + +infile=src/org/altusmetrum/AltosDroid/BuildInfo.java.in +outfile=src/org/altusmetrum/AltosDroid/BuildInfo.java + +echo "Version $describe, built on $builddate, $buildtime" + +sed -e "s/@DESCRIBE@/$describe/" \ +    -e "s/@VERSION@/$version/" \ +    -e "s/@COMMITNUM@/$commitnum/" \ +    -e "s/@COMMITHASH@/$commithash/" \ +    -e "s/@BUILDDATE@/$builddate/" \ +    -e "s/@BUILDTIME@/$buildtime/" \ + $infile > $outfile diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 3396f77e..b1fc8d30 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -189,10 +189,7 @@ public class AltosDroid extends Activity {  		mSerialView.setText(String.format("%d", state.data.serial));  		mFlightView.setText(String.format("%d", state.data.flight));  		mStateView.setText(state.data.state()); -		double speed = state.speed; -		if (!state.ascent) -			speed = state.baro_speed; -		mSpeedView.setText(String.format("%6.0f m/s", speed)); +		mSpeedView.setText(String.format("%6.0f m/s", state.speed()));  		mAccelView.setText(String.format("%6.0f m/s²", state.acceleration));  		mRangeView.setText(String.format("%6.0f m", state.range));  		mHeightView.setText(String.format("%6.0f m", state.height)); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java index 3382d551..264e35c6 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java @@ -67,7 +67,7 @@ public class AltosVoice {  			speak(state.data.state());
  			if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&
  			    state.state > AltosLib.ao_flight_boost) {
 -				speak(String.format("max speed: %d meters per second.", (int) (state.max_speed + 0.5)));
 +				speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));
  				spoke = true;
  			} else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&
  			           state.state >= AltosLib.ao_flight_drogue) {
 diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/BuildInfo.java.in b/altosdroid/src/org/altusmetrum/AltosDroid/BuildInfo.java.in new file mode 100644 index 00000000..763f814e --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/BuildInfo.java.in @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 Mike Beattie <mike@ethernal.org> + * + * 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.AltosDroid; + +public class BuildInfo { +	public static final String git_describe = "@DESCRIBE@"; +	public static final String version      = "@VERSION@"; +	public static final String commitnum    = "@COMMITNUM@"; +	public static final String commithash   = "@COMMITHASH@"; +	public static final String builddate    = "@BUILDDATE@"; +	public static final String buildtime    = "@BUILDTIME@"; +} + diff --git a/altoslib/AltosConfigData.java b/altoslib/AltosConfigData.java index a962b105..45a88783 100644 --- a/altoslib/AltosConfigData.java +++ b/altoslib/AltosConfigData.java @@ -50,6 +50,8 @@ public class AltosConfigData implements Iterable<String> {  	public int	storage_size;  	public int	storage_erase_unit; +	public AltosPyro[]	pyros; +  	public static String get_string(String line, String label) throws  ParseException {  		if (line.startsWith(label)) {  			String	quoted = line.substring(label.length()).trim(); @@ -135,6 +137,10 @@ public class AltosConfigData implements Iterable<String> {  		radio_frequency = 0;  		stored_flight = 0;  		serial = -1; +		pyros = null; + +		int npyro = 0; +		int pyro = 0;  		for (;;) {  			String line = link.get_reply();  			if (line == null) @@ -142,6 +148,16 @@ public class AltosConfigData implements Iterable<String> {  			if (line.contains("Syntax error"))  				continue;  			lines.add(line); +			if (pyro < npyro - 1) { +				if (pyros == null) +					pyros = new AltosPyro[npyro]; +				try { +					pyros[pyro] = new AltosPyro(pyro, line); +				} catch (ParseException e) { +				} +				++pyro; +				continue; +			}  			try { serial = get_int(line, "serial-number"); } catch (Exception e) {}  			try { log_format = get_int(line, "log-format"); } catch (Exception e) {}  			try { main_deploy = get_int(line, "Main deploy:"); } catch (Exception e) {} @@ -173,6 +189,7 @@ public class AltosConfigData implements Iterable<String> {  			try { get_int(line, "flight"); stored_flight++; }  catch (Exception e) {}  			try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {}  			try { storage_erase_unit = get_int(line, "Storage erase unit"); } catch (Exception e) {} +			try { npyro = get_int(line, "Pyro-count:"); pyro = 0; } catch (Exception e) {}  			/* signals the end of the version info */  			if (line.startsWith("software-version")) diff --git a/altoslib/AltosEepromMega.java b/altoslib/AltosEepromMega.java index 26bacf8d..af4f8aca 100644 --- a/altoslib/AltosEepromMega.java +++ b/altoslib/AltosEepromMega.java @@ -24,7 +24,7 @@ public class AltosEepromMega {  	public int	tick;  	public boolean	valid;  	public String	data; -	public int	a, b; +	public int	config_a, config_b;  	public int	data8[]; @@ -66,12 +66,7 @@ public class AltosEepromMega {  	public int mag_x() { return data16(20); }  	public int mag_y() { return data16(22); }  	public int mag_z() { return data16(24); } -	public int accel() { -		int a = data16(26); -		if (a != 0xffff) -			return a; -		return accel_y(); -	} +	public int accel() { return data16(26); }  	/* AO_LOG_VOLT elements */  	public int v_batt() { return data16(0); } @@ -79,6 +74,22 @@ public class AltosEepromMega {  	public int nsense() { return data16(4); }  	public int sense(int i) { return data16(6 + i * 2); } +	/* AO_LOG_GPS_TIME elements */ +	public int latitude() { return data32(0); } +	public int longitude() { return data32(4); } +	public int altitude() { return data16(8); } +	public int hour() { return data8(10); } +	public int minute() { return data8(11); } +	public int second() { return data8(12); } +	public int flags() { return data8(13); } +	public int year() { return data8(14); } +	public int month() { return data8(15); } +	public int day() { return data8(16); } +	 +	/* AO_LOG_GPS_SAT elements */ +	public int nsat() { return data16(0); } +	public int svid(int n) { return data8(2 + n * 2); } +	public int c_n(int n) { return data8(2 + n * 2 + 1); }  	public AltosEepromMega (AltosEepromChunk chunk, int start) throws ParseException {  		cmd = chunk.data(start); @@ -126,26 +137,26 @@ public class AltosEepromMega {  					data = tokens[2];  				} else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {  					cmd = AltosLib.AO_LOG_MAIN_DEPLOY; -					a = Integer.parseInt(tokens[2]); +					config_a = Integer.parseInt(tokens[2]);  				} else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {  					cmd = AltosLib.AO_LOG_APOGEE_DELAY; -					a = Integer.parseInt(tokens[2]); +					config_a = Integer.parseInt(tokens[2]);  				} else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {  					cmd = AltosLib.AO_LOG_RADIO_CHANNEL; -					a = Integer.parseInt(tokens[2]); +					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; -					a = Integer.parseInt(tokens[3]); -					b = Integer.parseInt(tokens[5]); +					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; -					a = Integer.parseInt(tokens[2]); +					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; -					a = Integer.parseInt(tokens[3]); +					config_a = Integer.parseInt(tokens[3]);  				} else if (tokens[0].equals("manufacturer")) {  					cmd = AltosLib.AO_LOG_MANUFACTURER;  					data = tokens[1]; @@ -154,38 +165,38 @@ public class AltosEepromMega {  					data = tokens[1];  				} else if (tokens[0].equals("serial-number")) {  					cmd = AltosLib.AO_LOG_SERIAL_NUMBER; -					a = Integer.parseInt(tokens[1]); +					config_a = Integer.parseInt(tokens[1]);  				} else if (tokens[0].equals("log-format")) {  					cmd = AltosLib.AO_LOG_LOG_FORMAT; -					a = Integer.parseInt(tokens[1]); +					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; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else if (tokens[1].equals("sens:")) {  						cmd = AltosLib.AO_LOG_BARO_SENS; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else if (tokens[1].equals("off:")) {  						cmd = AltosLib.AO_LOG_BARO_OFF; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else if (tokens[1].equals("tcs:")) {  						cmd = AltosLib.AO_LOG_BARO_TCS; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else if (tokens[1].equals("tco:")) {  						cmd = AltosLib.AO_LOG_BARO_TCO; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else if (tokens[1].equals("tref:")) {  						cmd = AltosLib.AO_LOG_BARO_TREF; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else if (tokens[1].equals("tempsens:")) {  						cmd = AltosLib.AO_LOG_BARO_TEMPSENS; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else if (tokens[1].equals("crc:")) {  						cmd = AltosLib.AO_LOG_BARO_CRC; -						a = Integer.parseInt(tokens[2]); +						config_a = Integer.parseInt(tokens[2]);  					} else {  						cmd = AltosLib.AO_LOG_INVALID;  						data = line; diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java index 1ab2fcc8..16809089 100644 --- a/altoslib/AltosEepromMegaIterable.java +++ b/altoslib/AltosEepromMegaIterable.java @@ -106,80 +106,47 @@ public class AltosEepromMegaIterable extends AltosRecordIterable {  			eeprom.sensor_tick = record.tick;  			has_accel = true;  			break; -		case AltosLib.AO_LOG_PRESSURE: -			state.pres = record.b; -			state.flight_pres = state.pres; -			if (eeprom.n_pad_samples == 0) { -				eeprom.n_pad_samples++; -				state.ground_pres = state.pres; -			} -			eeprom.seen |= seen_sensor; -			break;  		case AltosLib.AO_LOG_TEMP_VOLT:  			state.v_batt = record.v_batt();  			state.v_pyro = record.v_pbatt(); -			for (int i = 0; i < AltosRecordMM.num_sense; i++) +			for (int i = 0; i < record.nsense(); i++)  				state.sense[i] = record.sense(i);  			eeprom.seen |= seen_temp_volt;  			break; -// -//		case AltosLib.AO_LOG_DEPLOY: -//			state.drogue = record.a; -//			state.main = record.b; -//			eeprom.seen |= seen_deploy; -//			has_ignite = true; -//			break; -  		case AltosLib.AO_LOG_STATE:  			state.state = record.state();  			break;  		case AltosLib.AO_LOG_GPS_TIME:  			eeprom.gps_tick = state.tick; -			AltosGPS old = state.gps;  			state.gps = new AltosGPS(); -			/* GPS date doesn't get repeated through the file */ -			if (old != null) { -				state.gps.year = old.year; -				state.gps.month = old.month; -				state.gps.day = old.day; -			} -			state.gps.hour = (record.a & 0xff); -			state.gps.minute = (record.a >> 8); -			state.gps.second = (record.b & 0xff); +			state.gps.lat = record.latitude() / 1e7; +			state.gps.lon = record.longitude() / 1e7; +			state.gps.alt = record.altitude(); +			state.gps.year = record.year() + 2000; +			state.gps.month = record.month(); +			state.gps.day = record.day(); + +			state.gps.hour = record.hour(); +			state.gps.minute = record.minute(); +			state.gps.second = record.second(); -			int flags = (record.b >> 8); +			int flags = record.flags();  			state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;  			state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;  			state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>  				AltosLib.AO_GPS_NUM_SAT_SHIFT;  			state.new_gps = true;  			has_gps = true; -			break; -		case AltosLib.AO_LOG_GPS_LAT: -			int lat32 = record.a | (record.b << 16); -			state.gps.lat = (double) lat32 / 1e7; -			break; -		case AltosLib.AO_LOG_GPS_LON: -			int lon32 = record.a | (record.b << 16); -			state.gps.lon = (double) lon32 / 1e7; -			break; -		case AltosLib.AO_LOG_GPS_ALT: -			state.gps.alt = record.a; +			eeprom.seen |= seen_gps_time | seen_gps_lat | seen_gps_lon;  			break;  		case AltosLib.AO_LOG_GPS_SAT:  			if (state.tick == eeprom.gps_tick) { -				int svid = record.a; -				int c_n0 = record.b >> 8; -				state.gps.add_sat(svid, c_n0); +				int nsat = record.nsat(); +				for (int i = 0; i < nsat; i++) +					state.gps.add_sat(record.svid(i), record.c_n(i));  			}  			break; -		case AltosLib.AO_LOG_GPS_DATE: -			state.gps.year = (record.a & 0xff) + 2000; -			state.gps.month = record.a >> 8; -			state.gps.day = record.b & 0xff; -			break; -  		case AltosLib.AO_LOG_CONFIG_VERSION:  			break;  		case AltosLib.AO_LOG_MAIN_DEPLOY: @@ -192,8 +159,8 @@ public class AltosEepromMegaIterable extends AltosRecordIterable {  			state.callsign = record.data;  			break;  		case AltosLib.AO_LOG_ACCEL_CAL: -			state.accel_plus_g = record.a; -			state.accel_minus_g = record.b; +			state.accel_plus_g = record.config_a; +			state.accel_minus_g = record.config_b;  			break;  		case AltosLib.AO_LOG_RADIO_CAL:  			break; @@ -202,33 +169,33 @@ public class AltosEepromMegaIterable extends AltosRecordIterable {  		case AltosLib.AO_LOG_PRODUCT:  			break;  		case AltosLib.AO_LOG_SERIAL_NUMBER: -			state.serial = record.a; +			state.serial = record.config_a;  			break;  		case AltosLib.AO_LOG_SOFTWARE_VERSION:  			break;  		case AltosLib.AO_LOG_BARO_RESERVED: -			baro.reserved = record.a; +			baro.reserved = record.config_a;  			break;  		case AltosLib.AO_LOG_BARO_SENS: -			baro.sens =record.a; +			baro.sens =record.config_a;  			break;  		case AltosLib.AO_LOG_BARO_OFF: -			baro.off =record.a; +			baro.off =record.config_a;  			break;  		case AltosLib.AO_LOG_BARO_TCS: -			baro.tcs =record.a; +			baro.tcs =record.config_a;  			break;  		case AltosLib.AO_LOG_BARO_TCO: -			baro.tco =record.a; +			baro.tco =record.config_a;  			break;  		case AltosLib.AO_LOG_BARO_TREF: -			baro.tref =record.a; +			baro.tref =record.config_a;  			break;  		case AltosLib.AO_LOG_BARO_TEMPSENS: -			baro.tempsens =record.a; +			baro.tempsens =record.config_a;  			break;  		case AltosLib.AO_LOG_BARO_CRC: -			baro.crc =record.a; +			baro.crc =record.config_a;  			break;  		}  		state.seen |= eeprom.seen; @@ -287,25 +254,25 @@ public class AltosEepromMegaIterable extends AltosRecordIterable {  				out.printf("# Config version: %s\n", record.data);  				break;  			case AltosLib.AO_LOG_MAIN_DEPLOY: -				out.printf("# Main deploy: %s\n", record.a); +				out.printf("# Main deploy: %s\n", record.config_a);  				break;  			case AltosLib.AO_LOG_APOGEE_DELAY: -				out.printf("# Apogee delay: %s\n", record.a); +				out.printf("# Apogee delay: %s\n", record.config_a);  				break;  			case AltosLib.AO_LOG_RADIO_CHANNEL: -				out.printf("# Radio channel: %s\n", record.a); +				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.a, record.b); +				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.a); +				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.a); +				out.printf ("# Max flight log: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_MANUFACTURER:  				out.printf ("# Manufacturer: %s\n", record.data); @@ -314,74 +281,40 @@ public class AltosEepromMegaIterable extends AltosRecordIterable {  				out.printf ("# Product: %s\n", record.data);  				break;  			case AltosLib.AO_LOG_SERIAL_NUMBER: -				out.printf ("# Serial number: %d\n", record.a); +				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.a); +				out.printf ("# Baro reserved: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_BARO_SENS: -				out.printf ("# Baro sens: %d\n", record.a); +				out.printf ("# Baro sens: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_BARO_OFF: -				out.printf ("# Baro off: %d\n", record.a); +				out.printf ("# Baro off: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_BARO_TCS: -				out.printf ("# Baro tcs: %d\n", record.a); +				out.printf ("# Baro tcs: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_BARO_TCO: -				out.printf ("# Baro tco: %d\n", record.a); +				out.printf ("# Baro tco: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_BARO_TREF: -				out.printf ("# Baro tref: %d\n", record.a); +				out.printf ("# Baro tref: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_BARO_TEMPSENS: -				out.printf ("# Baro tempsens: %d\n", record.a); +				out.printf ("# Baro tempsens: %d\n", record.config_a);  				break;  			case AltosLib.AO_LOG_BARO_CRC: -				out.printf ("# Baro crc: %d\n", record.a); +				out.printf ("# Baro crc: %d\n", record.config_a);  				break;  			}  		}  	}  	/* -	 * Given an AO_LOG_GPS_TIME record with correct time, and one -	 * missing time, rewrite the missing time values with the good -	 * ones, assuming that the difference between them is 'diff' seconds -	 */ -	void update_time(AltosOrderedMegaRecord good, AltosOrderedMegaRecord bad) { - -		int diff = (bad.tick - good.tick + 50) / 100; - -		int hour = (good.a & 0xff); -		int minute = (good.a >> 8); -		int second = (good.b & 0xff); -		int flags = (good.b >> 8); -		int seconds = hour * 3600 + minute * 60 + second; - -		/* Make sure this looks like a good GPS value */ -		if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4) -			flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT); -		flags |= AltosLib.AO_GPS_RUNNING; -		flags |= AltosLib.AO_GPS_VALID; - -		int new_seconds = seconds + diff; -		if (new_seconds < 0) -			new_seconds += 24 * 3600; -		int new_second = (new_seconds % 60); -		int new_minutes = (new_seconds / 60); -		int new_minute = (new_minutes % 60); -		int new_hours = (new_minutes / 60); -		int new_hour = (new_hours % 24); - -		bad.a = new_hour + (new_minute << 8); -		bad.b = new_second + (flags << 8); -	} - -	/*  	 * 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 with GPS data getting timestamps @@ -416,53 +349,11 @@ public class AltosEepromMegaIterable extends AltosRecordIterable {  					continue;  				} -				/* Two firmware bugs caused the loss of some GPS data. -				 * The flight date would never be recorded, and often -				 * the flight time would get overwritten by another -				 * record. Detect the loss of the GPS date and fix up the -				 * missing time records -				 */ -				if (record.cmd == AltosLib.AO_LOG_GPS_DATE) { -					gps_date_record = record; -					continue; -				} - -				/* go back and fix up any missing time values */ -				if (record.cmd == AltosLib.AO_LOG_GPS_TIME) { -					last_gps_time = record; -					if (missing_time) { -						Iterator<AltosOrderedMegaRecord> iterator = records.iterator(); -						while (iterator.hasNext()) { -							AltosOrderedMegaRecord old = iterator.next(); -							if (old.cmd == AltosLib.AO_LOG_GPS_TIME && -							    old.a == -1 && old.b == -1) -							{ -								update_time(record, old); -							} -						} -						missing_time = false; -					} -				} - -				if (record.cmd == AltosLib.AO_LOG_GPS_LAT) { -					if (last_gps_time == null || last_gps_time.tick != record.tick) { -						AltosOrderedMegaRecord add_gps_time = new AltosOrderedMegaRecord(AltosLib.AO_LOG_GPS_TIME, -													 record.tick, -													 -1, -1, index-1); -						if (last_gps_time != null) -							update_time(last_gps_time, add_gps_time); -						else -							missing_time = true; - -						records.add(add_gps_time); -						record.index = index++; -					} -				}  				records.add(record);  				/* Bail after reading the 'landed' record; we're all done */  				if (record.cmd == AltosLib.AO_LOG_STATE && -				    record.a == AltosLib.ao_flight_landed) +				    record.state() == AltosLib.ao_flight_landed)  					break;  			}  		} catch (IOException io) { diff --git a/altoslib/AltosIdleMonitor.java b/altoslib/AltosIdleMonitor.java index 2c4965ff..07d8930d 100644 --- a/altoslib/AltosIdleMonitor.java +++ b/altoslib/AltosIdleMonitor.java @@ -97,7 +97,7 @@ public class AltosIdleMonitor extends Thread {  			else if (has_sensor_mm(config_data))  				record = sensor_mm(config_data);  			else -				record = new AltosRecord(); +				record = new AltosRecordNone();  			if (has_gps(config_data))  				gps = new AltosGPSQuery(link, config_data); diff --git a/altoslib/AltosLib.java b/altoslib/AltosLib.java index 192c445e..07516aeb 100644 --- a/altoslib/AltosLib.java +++ b/altoslib/AltosLib.java @@ -199,7 +199,7 @@ public class AltosLib {  	public static String state_name_capital(int state) {  		if (state < 0 || state_to_string.length <= state) -			return "invalid"; +			return "Invalid";  		return state_to_string_capital[state];  	} diff --git a/altoslib/AltosOrderedMegaRecord.java b/altoslib/AltosOrderedMegaRecord.java index 05423dd9..3aaf7b5b 100644 --- a/altoslib/AltosOrderedMegaRecord.java +++ b/altoslib/AltosOrderedMegaRecord.java @@ -43,18 +43,6 @@ class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable<Altos  		index = in_index;  	} -	public AltosOrderedMegaRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) { -		super(in_cmd, in_tick); -		a = in_a; -		b = in_b; -		index = in_index; -	} - -	public String toString() { -		return String.format("%d.%d %04x %04x %04x", -				     cmd, index, tick, a, b); -	} -  	public int compareTo(AltosOrderedMegaRecord o) {  		int	tick_diff = tick - o.tick;  		if (tick_diff != 0) diff --git a/altoslib/AltosPyro.java b/altoslib/AltosPyro.java new file mode 100644 index 00000000..14051169 --- /dev/null +++ b/altoslib/AltosPyro.java @@ -0,0 +1,293 @@ +/* + * 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; + +import java.util.*; +import java.text.*; +import java.util.concurrent.*; + +public class AltosPyro { +	public static final int pyro_none			= 0x00000000; + +	public static final int pyro_accel_less			= 0x00000001; +	public static final int pyro_accel_greater		= 0x00000002; +	public static final String pyro_accel_less_string	= "a<"; +	public static final String pyro_accel_greater_string	= "a>"; +	public static final String pyro_accel_less_name		= "Acceleration less than (m/s²)"; +	public static final String pyro_accel_greater_name	= "Acceleration greater than (m/s²)"; +	public static final double pyro_accel_scale		= 16.0; + +	public static final int pyro_speed_less			= 0x00000004; +	public static final int pyro_speed_greater		= 0x00000008; +	public static final String pyro_speed_less_string	= "s<"; +	public static final String pyro_speed_greater_string	= "s>"; +	public static final String pyro_speed_less_name		= "Speed less than (m/s)"; +	public static final String pyro_speed_greater_name	= "Speed greater than (m/s)"; +	public static final double pyro_speed_scale		= 16.0; + +	public static final int pyro_height_less		= 0x00000010; +	public static final int pyro_height_greater		= 0x00000020; +	public static final String pyro_height_less_string	= "h<"; +	public static final String pyro_height_greater_string	= "h>"; +	public static final String pyro_height_less_name	= "Height less than (m)"; +	public static final String pyro_height_greater_name	= "Height greater than (m)"; +	public static final double pyro_height_scale		= 1.0; + +	public static final int pyro_orient_less		= 0x00000040; +	public static final int pyro_orient_greater		= 0x00000080; +	public static final String pyro_orient_less_string	= "o<"; +	public static final String pyro_orient_greater_string	= "o>"; +	public static final String pyro_orient_less_name	= "Angle from vertical less than (degrees)"; +	public static final String pyro_orient_greater_name	= "Angle from vertical greater than (degrees)"; +	public static final double pyro_orient_scale		= 1.0; + +	public static final int pyro_time_less			= 0x00000100; +	public static final int pyro_time_greater		= 0x00000200; +	public static final String pyro_time_less_string	= "t<"; +	public static final String pyro_time_greater_string	= "t>"; +	public static final String pyro_time_less_name		= "Time since boost less than (s)"; +	public static final String pyro_time_greater_name	= "Time since boost greater than (s)"; +	public static final double pyro_time_scale		= 100.0; + +	public static final int pyro_ascending			= 0x00000400; +	public static final int pyro_descending			= 0x00000800; +	public static final String pyro_ascending_string	= "A"; +	public static final String pyro_descending_string	= "D"; +	public static final String pyro_ascending_name		= "Ascending"; +	public static final String pyro_descending_name		= "Descending"; + +	public static final int pyro_after_motor		= 0x00001000; +	public static final String pyro_after_motor_string	= "m"; +	public static final String pyro_after_motor_name	= "After motor number"; +	public static final double pyro_after_motor_scale	= 1.0; + +	public static final int pyro_delay			= 0x00002000; +	public static final String pyro_delay_string		= "d"; +	public static final String pyro_delay_name		= "Delay after other conditions (s)"; +	public static final double pyro_delay_scale		= 100.0; + +	public static final int pyro_state_less			= 0x00004000; +	public static final int pyro_state_greater_or_equal  	= 0x00008000; +	public static final String pyro_state_less_string	= "f<"; +	public static final String pyro_state_greater_or_equal_string	= "f>="; +	public static final String pyro_state_less_name		= "Flight state before"; +	public static final String pyro_state_greater_or_equal_name	= "Flight state after"; +	public static final double pyro_state_scale		= 1.0; + +	public static final int	pyro_all			= 0x0000ffff; + +	public static final int pyro_no_value			= (pyro_ascending | +								   pyro_descending); + +	public static final int pyro_state_value		= pyro_state_less | pyro_state_greater_or_equal; + +	private static HashMap<String,Integer> string_to_pyro = new HashMap<String,Integer>(); + +	private static HashMap<Integer,String> pyro_to_string = new HashMap<Integer,String>(); + +	private static HashMap<Integer,String> pyro_to_name = new HashMap<Integer,String>(); + +	private static HashMap<Integer,Double> pyro_to_scale = new HashMap<Integer,Double>(); +	 +	private static void insert_map(int flag, String string, String name, double scale) { +		string_to_pyro.put(string, flag); +		pyro_to_string.put(flag, string); +		pyro_to_name.put(flag, name); +		pyro_to_scale.put(flag, scale); +	} +	 +	public static int string_to_pyro(String name) { +		if (string_to_pyro.containsKey(name)) +			return string_to_pyro.get(name); +		return pyro_none; +	} + +	public static String pyro_to_string(int flag) { +		if (pyro_to_string.containsKey(flag)) +			return pyro_to_string.get(flag); +		return null; +	} + +	public static String pyro_to_name(int flag) { +		if (pyro_to_name.containsKey(flag)) +			return pyro_to_name.get(flag); +		return null; +	} + +	public static double pyro_to_scale(int flag) { +		if (pyro_to_scale.containsKey(flag)) +			return pyro_to_scale.get(flag); +		return 1.0; +	} + +	private static void initialize_maps() { +		insert_map(pyro_accel_less, pyro_accel_less_string, pyro_accel_less_name, pyro_accel_scale); +		insert_map(pyro_accel_greater, pyro_accel_greater_string, pyro_accel_greater_name, pyro_accel_scale); + +		insert_map(pyro_speed_less, pyro_speed_less_string, pyro_speed_less_name, pyro_speed_scale); +		insert_map(pyro_speed_greater, pyro_speed_greater_string, pyro_speed_greater_name, pyro_speed_scale); + +		insert_map(pyro_height_less, pyro_height_less_string, pyro_height_less_name, pyro_height_scale); +		insert_map(pyro_height_greater, pyro_height_greater_string, pyro_height_greater_name, pyro_height_scale); + +		insert_map(pyro_orient_less, pyro_orient_less_string, pyro_orient_less_name, pyro_orient_scale); +		insert_map(pyro_orient_greater, pyro_orient_greater_string, pyro_orient_greater_name, pyro_orient_scale); + +		insert_map(pyro_time_less, pyro_time_less_string, pyro_time_less_name, pyro_time_scale); +		insert_map(pyro_time_greater, pyro_time_greater_string, pyro_time_greater_name, pyro_time_scale); + +		insert_map(pyro_ascending, pyro_ascending_string, pyro_ascending_name, 1.0); +		insert_map(pyro_descending, pyro_descending_string, pyro_descending_name, 1.0); + +		insert_map(pyro_after_motor, pyro_after_motor_string, pyro_after_motor_name, 1.0); +		insert_map(pyro_delay, pyro_delay_string, pyro_delay_name, pyro_delay_scale); +		 +		insert_map(pyro_state_less, pyro_state_less_string, pyro_state_less_name, 1.0); +		insert_map(pyro_state_greater_or_equal, pyro_state_greater_or_equal_string, pyro_state_greater_or_equal_name, 1.0); +	} + +	{ +		initialize_maps(); +	} + +	public int	channel; +	public int	flags; +	public int	accel_less, accel_greater; +	public int	speed_less, speed_greater; +	public int	height_less, height_greater; +	public int	orient_less, orient_greater; +	public int	time_less, time_greater; +	public int	delay; +	public int	state_less, state_greater_or_equal; +	public int	motor; + +	public AltosPyro(int in_channel) { +		channel = in_channel; +		flags = 0; +	} + +	private boolean set_ivalue(int flag, int value) { +		switch (flag) { +		case pyro_accel_less:			accel_less = value; break; +		case pyro_accel_greater:		accel_greater = value; break; +		case pyro_speed_less:			speed_less = value; break; +		case pyro_speed_greater:		speed_greater = value; break; +		case pyro_height_less:			height_less = value; break; +		case pyro_height_greater:		height_greater = value; break; +		case pyro_orient_less:			orient_less = value; break; +		case pyro_orient_greater:		orient_greater = value; break; +		case pyro_time_less:			time_less = value; break; +		case pyro_time_greater:			time_greater = value; break; +		case pyro_after_motor:			motor = value; break; +		case pyro_delay:			delay = value; break; +		case pyro_state_less:			state_less = value; break; +		case pyro_state_greater_or_equal:	state_greater_or_equal = value; break; +		default: +			return false; +		} +		return true; +	} + +	public boolean set_value(int flag, double dvalue) { +		return set_ivalue(flag, (int) (dvalue * pyro_to_scale(flag))); +	} + +	private int get_ivalue (int flag) { +		int	value; + +		switch (flag) { +		case pyro_accel_less:			value = accel_less; break; +		case pyro_accel_greater:		value = accel_greater; break; +		case pyro_speed_less:			value = speed_less; break; +		case pyro_speed_greater:		value = speed_greater; break; +		case pyro_height_less:			value = height_less; break; +		case pyro_height_greater:		value = height_greater; break; +		case pyro_orient_less:			value = orient_less; break; +		case pyro_orient_greater:		value = orient_greater; break; +		case pyro_time_less:			value = time_less; break; +		case pyro_time_greater:			value = time_greater; break; +		case pyro_after_motor:			value = motor; break; +		case pyro_delay:			value = delay; break; +		case pyro_state_less:			value = state_less; break; +		case pyro_state_greater_or_equal:	value = state_greater_or_equal; break; +		default:				value = 0; break; +		} +		return value; +	} + +	public double get_value(int flag) { +		return get_ivalue(flag) / pyro_to_scale(flag); +	} + +	public AltosPyro(int in_channel, String line) throws ParseException { +		String[] tokens = line.split("\\s+"); + +		channel = in_channel; +		flags = 0; + +		int i = 0; +		if (tokens[i].equals("Pyro")) +			i += 2; + +		for (; i < tokens.length; i++) { + +			if (tokens[i].equals("<disabled>")) +				break; + +			int	flag = string_to_pyro(tokens[i]); +			if (flag == pyro_none) +				throw new ParseException(String.format("Invalid pyro token \"%s\"", +								       tokens[i]), i); +			flags |= flag; + +			if ((flag & pyro_no_value) == 0) { +				int	value = 0; +				++i; +				try { +					value = AltosLib.fromdec(tokens[i]); +				} catch (NumberFormatException n) { +					throw new ParseException(String.format("Invalid pyro value \"%s\"", +									       tokens[i]), i); +				} +				if (!set_ivalue(flag, value)) +					throw new ParseException(String.format("Internal parser error \"%s\" \"%s\"", +									       tokens[i-1], tokens[i]), i-1); +			} +		} +	} + +	public String toString() { +		String	ret = String.format("%d", channel); + +		for (int flag = 1; flag <= flags; flag <<= 1) { +			if ((flags & flag) != 0) { +				String	add; +				if ((flag & pyro_no_value) == 0) { +					add = String.format(" %s %d", +							    pyro_to_string.get(flag), +							    get_ivalue(flag)); +				} else { +					add = String.format(" %s", +							    pyro_to_string.get(flag)); +				} +				ret = ret.concat(add); +			} +		} +		return ret; +	} +} diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java index 8bab1d0c..09169515 100644 --- a/altoslib/AltosRecord.java +++ b/altoslib/AltosRecord.java @@ -17,7 +17,7 @@  package org.altusmetrum.AltosLib; -public class AltosRecord implements Comparable <AltosRecord>, Cloneable { +public abstract class AltosRecord implements Comparable <AltosRecord>, Cloneable {  	public static final int	seen_flight = 1;  	public static final int	seen_sensor = 2; @@ -43,11 +43,6 @@ public class AltosRecord implements Comparable <AltosRecord>, Cloneable {  	public int	state;  	public int	tick; -	/* Current flight dynamic state */ -	public double	acceleration;	/* m/s² */ -	public double	speed;		/* m/s */ -	public double	height;		/* m */ -  	public AltosGPS	gps;  	public boolean	new_gps; @@ -63,6 +58,11 @@ public class AltosRecord implements Comparable <AltosRecord>, Cloneable {  	public AltosRecordCompanion companion; +	/* Telemetry sources have these values recorded from the flight computer */ +	public double	kalman_height; +	public double	kalman_speed; +	public double	kalman_acceleration; +  	/*  	 * Abstract methods that convert record data  	 * to standard units: @@ -75,76 +75,48 @@ public class AltosRecord implements Comparable <AltosRecord>, Cloneable {  	 *	temperature:	°C  	 */ -	public double raw_pressure() { return MISSING; } - -	public double filtered_pressure() { return MISSING; } - -	public double ground_pressure() { return MISSING; } - -	public double battery_voltage() { return MISSING; } +	abstract public double pressure(); +	abstract public double ground_pressure(); +	abstract public double acceleration(); -	public double main_voltage() { return MISSING; } +	public double altitude() { +		double	p = pressure(); -	public double drogue_voltage() { return MISSING; } - -	public double temperature() { return MISSING; } -	 -	public double acceleration() { return MISSING; } - -	public double accel_speed() { return MISSING; } - -	public AltosIMU imu() { return null; } - -	public AltosMag mag() { return null; } - -	/* -	 * Convert various pressure values to altitude -	 */ - -	public double raw_altitude() { -		double p = raw_pressure();  		if (p == MISSING)  			return MISSING;  		return AltosConvert.pressure_to_altitude(p);  	}  	public double ground_altitude() { -		double p = ground_pressure(); +		double	p = ground_pressure(); +  		if (p == MISSING)  			return MISSING;  		return AltosConvert.pressure_to_altitude(p);  	} -	public double filtered_altitude() { -		double	ga = ground_altitude(); -		if (height != MISSING && ga != MISSING) -			return height + ga; +	public double height() { +		double	g = ground_altitude(); +		double	a = altitude(); -		double	p = filtered_pressure(); -		if (p == MISSING) -			return raw_altitude(); -		return AltosConvert.pressure_to_altitude(p); +		if (g == MISSING) +			return MISSING; +		if (a == MISSING) +			return MISSING; +		return a - g;  	} -	public double filtered_height() { -		if (height != MISSING) -			return height; +	public double battery_voltage() { return MISSING; } -		double f = filtered_altitude(); -		double g = ground_altitude(); -		if (f == MISSING || g == MISSING) -			return MISSING; -		return f - g; -	} +	public double main_voltage() { return MISSING; } -	public double raw_height() { -		double r = raw_altitude(); -		double g = ground_altitude(); +	public double drogue_voltage() { return MISSING; } -		if (r == MISSING || g == MISSING) -			return height; -		return r - g; -	} +	public double temperature() { return MISSING; } +	 +	public AltosIMU imu() { return null; } + +	public AltosMag mag() { return null; }  	public String state() {  		return AltosLib.state_name(state); @@ -164,12 +136,12 @@ public class AltosRecord implements Comparable <AltosRecord>, Cloneable {  		status = old.status;  		state = old.state;  		tick = old.tick; -		acceleration = old.acceleration; -		speed = old.speed; -		height = old.height;  		gps = new AltosGPS(old.gps);  		new_gps = old.new_gps;  		companion = old.companion; +		kalman_acceleration = old.kalman_acceleration; +		kalman_speed = old.kalman_speed; +		kalman_height = old.kalman_height;  	}  	public AltosRecord clone() { @@ -192,11 +164,12 @@ public class AltosRecord implements Comparable <AltosRecord>, Cloneable {  		status = 0;  		state = AltosLib.ao_flight_startup;  		tick = 0; -		acceleration = MISSING; -		speed = MISSING; -		height = MISSING;  		gps = new AltosGPS();  		new_gps = false;  		companion = null; + +		kalman_acceleration = MISSING; +		kalman_speed = MISSING; +		kalman_height = MISSING;  	}  } diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java index 5f952f7a..9f529234 100644 --- a/altoslib/AltosRecordMM.java +++ b/altoslib/AltosRecordMM.java @@ -19,6 +19,7 @@ package org.altusmetrum.AltosLib;  public class AltosRecordMM extends AltosRecord { +	/* Sensor values */  	public int	accel;  	public int	pres;  	public int	temp; @@ -45,16 +46,12 @@ public class AltosRecordMM extends AltosRecord {  		return raw / 4095.0;  	} -	public double raw_pressure() { +	public double pressure() {  		if (pres != MISSING)  			return pres;  		return MISSING;  	} -	public double filtered_pressure() { -		return raw_pressure(); -	} -  	public double ground_pressure() {  		if (ground_pres != MISSING)  			return ground_pres; @@ -98,9 +95,6 @@ public class AltosRecordMM extends AltosRecord {  	}  	public double acceleration() { -		if (acceleration != MISSING) -			return acceleration; -  		if (ground_accel == MISSING || accel == MISSING)  			return MISSING; @@ -110,10 +104,6 @@ public class AltosRecordMM extends AltosRecord {  		return (ground_accel - accel) / accel_counts_per_mss();  	} -	public double accel_speed() { -		return speed; -	} -  	public void copy (AltosRecordMM old) {  		super.copy(old); diff --git a/altoslib/AltosRecordNone.java b/altoslib/AltosRecordNone.java new file mode 100644 index 00000000..ca0a5fe3 --- /dev/null +++ b/altoslib/AltosRecordNone.java @@ -0,0 +1,34 @@ +/* + * 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; + +public class AltosRecordNone extends AltosRecord { + +	public double pressure() { return MISSING; } +	public double ground_pressure() { return MISSING; } +	public double temperature() { return MISSING; } +	public double acceleration() { return MISSING; } + +	public AltosRecordNone(AltosRecord old) { +		super.copy(old); +	} + +	public AltosRecordNone() { +		super(); +	} +} diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java index 37accef6..9530be31 100644 --- a/altoslib/AltosRecordTM.java +++ b/altoslib/AltosRecordTM.java @@ -18,6 +18,8 @@  package org.altusmetrum.AltosLib;  public class AltosRecordTM extends AltosRecord { + +	/* Sensor values */  	public int	accel;  	public int	pres;  	public int	temp; @@ -57,18 +59,12 @@ public class AltosRecordTM extends AltosRecord {  		return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;  	} -	public double raw_pressure() { +	public double pressure() {  		if (pres == MISSING)  			return MISSING;  		return barometer_to_pressure(pres);  	} -	public double filtered_pressure() { -		if (flight_pres == MISSING) -			return MISSING; -		return barometer_to_pressure(flight_pres); -	} -  	public double ground_pressure() {  		if (ground_pres == MISSING)  			return MISSING; @@ -121,22 +117,11 @@ public class AltosRecordTM extends AltosRecord {  	}  	public double acceleration() { -		if (acceleration != MISSING) -			return acceleration; -  		if (ground_accel == MISSING || accel == MISSING)  			return MISSING;  		return (ground_accel - accel) / accel_counts_per_mss();  	} -	public double accel_speed() { -		if (speed != MISSING) -			return speed; -		if (flight_vel == MISSING) -			return MISSING; -		return flight_vel / (accel_counts_per_mss() * 100.0); -	} -  	public void copy(AltosRecordTM old) {  		super.copy(old); diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 2e4d8870..f28dd1c6 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -40,17 +40,17 @@ public class AltosState {  	public double	ground_altitude;  	public double	altitude;  	public double	height; -	public double	speed;  	public double	acceleration;  	public double	battery;  	public double	temperature;  	public double	main_sense;  	public double	drogue_sense; +	public double	accel_speed;  	public double	baro_speed;  	public double	max_height;  	public double	max_acceleration; -	public double	max_speed; +	public double	max_accel_speed;  	public double	max_baro_speed;  	public AltosGPS	gps; @@ -76,20 +76,39 @@ public class AltosState {  	public int	speak_tick;  	public double	speak_altitude; -	public void init (AltosRecord cur, AltosState prev_state) { -		//int		i; -		//AltosRecord prev; +	public double speed() { +		if (ascent) +			return accel_speed; +		else +			return baro_speed; +	} + +	public double max_speed() { +		if (max_accel_speed != 0) +			return max_accel_speed; +		return max_baro_speed; +	} +	public void init (AltosRecord cur, AltosState prev_state) {  		data = cur;  		ground_altitude = data.ground_altitude(); -		altitude = data.raw_altitude(); -		height = data.filtered_height(); + +		altitude = data.altitude(); + +		if (data.kalman_height != AltosRecord.MISSING) +			height = data.kalman_height; +		else { +			if (prev_state != null) +				height = (prev_state.height * 15 + altitude - ground_altitude) / 16.0; +		}  		report_time = System.currentTimeMillis(); -		acceleration = data.acceleration(); -		speed = data.accel_speed(); +		if (data.kalman_acceleration != AltosRecord.MISSING) +			acceleration = data.kalman_acceleration; +		else +			acceleration = data.acceleration();  		temperature = data.temperature();  		drogue_sense = data.drogue_voltage();  		main_sense = data.main_voltage(); @@ -108,7 +127,7 @@ public class AltosState {  			pad_alt = prev_state.pad_alt;  			max_height = prev_state.max_height;  			max_acceleration = prev_state.max_acceleration; -			max_speed = prev_state.max_speed; +			max_accel_speed = prev_state.max_accel_speed;  			max_baro_speed = prev_state.max_baro_speed;  			imu = prev_state.imu;  			mag = prev_state.mag; @@ -119,23 +138,39 @@ public class AltosState {  			time_change = (tick - prev_state.tick) / 100.0; -			/* compute barometric speed */ +			if (data.kalman_speed != AltosRecord.MISSING) { +				baro_speed = accel_speed = data.kalman_speed; +			} else { +				/* compute barometric speed */ -			double height_change = height - prev_state.height; -			if (data.speed != AltosRecord.MISSING) -				baro_speed = data.speed; -			else { +				double height_change = height - prev_state.height;  				if (time_change > 0)  					baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0;  				else  					baro_speed = prev_state.baro_speed; + +				if (acceleration == AltosRecord.MISSING) { +					/* Fill in mising acceleration value */ +					accel_speed = baro_speed; +					if (time_change > 0) +						acceleration = (accel_speed - prev_state.accel_speed) / time_change; +					else +						acceleration = prev_state.acceleration; +				} else { +					/* compute accelerometer speed */ +					accel_speed = prev_state.accel_speed + acceleration * time_change; +				}  			} +  		} else {  			npad = 0;  			ngps = 0;  			gps = null;  			baro_speed = 0; +			accel_speed = 0;  			time_change = 0; +			if (acceleration == AltosRecord.MISSING) +				acceleration = 0;  		}  		time = tick / 100.0; @@ -180,8 +215,8 @@ public class AltosState {  		/* Only look at accelerometer data under boost */  		if (boost && acceleration > max_acceleration && acceleration != AltosRecord.MISSING)  			max_acceleration = acceleration; -		if (boost && speed > max_speed && speed != AltosRecord.MISSING) -			max_speed = speed; +		if (boost && accel_speed > max_accel_speed && accel_speed != AltosRecord.MISSING) +			max_accel_speed = accel_speed;  		if (boost && baro_speed > max_baro_speed && baro_speed != AltosRecord.MISSING)  			max_baro_speed = baro_speed; diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java index 21176069..43189794 100644 --- a/altoslib/AltosTelemetryRecordLegacy.java +++ b/altoslib/AltosTelemetryRecordLegacy.java @@ -257,9 +257,9 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord {  		record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING);  		/* flight computer values */ -		record.acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); -		record.speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); -		record.height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING); +		record.kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0); +		record.kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0); +		record.kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING);  		record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING);  		record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING); @@ -334,9 +334,9 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord {  		/* Old TeleDongle code with kalman-reporting TeleMetrum code */  		if ((record.flight_vel & 0xffff0000) == 0x80000000) { -			record.speed = ((short) record.flight_vel) / 16.0; -			record.acceleration = record.flight_accel / 16.0; -			record.height = record.flight_pres; +			record.kalman_speed = ((short) record.flight_vel) / 16.0; +			record.kalman_acceleration = record.flight_accel / 16.0; +			record.kalman_height = record.flight_pres;  			record.flight_vel = AltosRecord.MISSING;  			record.flight_pres = AltosRecord.MISSING;  			record.flight_accel = AltosRecord.MISSING; @@ -455,9 +455,9 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord {  		record.accel_minus_g = int16(19);  		if (uint16(11) == 0x8000) { -			record.acceleration = int16(5); -			record.speed = int16(9); -			record.height = int16(13); +			record.kalman_acceleration = int16(5); +			record.kalman_speed = int16(9); +			record.kalman_height = int16(13);  			record.flight_accel = AltosRecord.MISSING;  			record.flight_vel = AltosRecord.MISSING;  			record.flight_pres = AltosRecord.MISSING; @@ -465,9 +465,9 @@ public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord {  			record.flight_accel = int16(5);  			record.flight_vel = uint32(9);  			record.flight_pres = int16(13); -			record.acceleration = AltosRecord.MISSING; -			record.speed = AltosRecord.MISSING; -			record.height = AltosRecord.MISSING; +			record.kalman_acceleration = AltosRecord.MISSING; +			record.kalman_speed = AltosRecord.MISSING; +			record.kalman_height = AltosRecord.MISSING;  		}  		record.gps = null; diff --git a/altoslib/AltosTelemetryRecordMegaData.java b/altoslib/AltosTelemetryRecordMegaData.java index 8f55d238..16a7b80c 100644 --- a/altoslib/AltosTelemetryRecordMegaData.java +++ b/altoslib/AltosTelemetryRecordMegaData.java @@ -83,9 +83,9 @@ public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw {  		next.accel_plus_g = accel_plus_g;  		next.accel_minus_g = accel_minus_g; -		next.acceleration = acceleration / 16.0; -		next.speed = speed / 16.0; -		next.height = height; +		next.kalman_acceleration = acceleration / 16.0; +		next.kalman_speed = speed / 16.0; +		next.kalman_height = height;  		next.seen |= AltosRecord.seen_flight | AltosRecord.seen_temp_volt; diff --git a/altoslib/AltosTelemetryRecordRaw.java b/altoslib/AltosTelemetryRecordRaw.java index fbb373d5..c21da6fc 100644 --- a/altoslib/AltosTelemetryRecordRaw.java +++ b/altoslib/AltosTelemetryRecordRaw.java @@ -65,7 +65,7 @@ public class AltosTelemetryRecordRaw extends AltosTelemetryRecord {  		if (previous != null)  			next = previous.clone();  		else -			next = new AltosRecord(); +			next = new AltosRecordNone();  		next.serial = serial;  		next.tick = tick;  		return next; diff --git a/altoslib/AltosTelemetryRecordSensor.java b/altoslib/AltosTelemetryRecordSensor.java index 319a91b3..f1fc156c 100644 --- a/altoslib/AltosTelemetryRecordSensor.java +++ b/altoslib/AltosTelemetryRecordSensor.java @@ -86,9 +86,9 @@ public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw {  			next.main = AltosRecord.MISSING;  		} -		next.acceleration = acceleration / 16.0; -		next.speed = speed / 16.0; -		next.height = height; +		next.kalman_acceleration = acceleration / 16.0; +		next.kalman_speed = speed / 16.0; +		next.kalman_height = height;  		next.ground_pres = ground_pres;  		if (type == packet_type_TM_sensor) { diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index b56d8af1..2579a650 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -46,6 +46,7 @@ AltosLib_JAVA = \  	$(SRC)/AltosRecordCompanion.java \  	$(SRC)/AltosRecordIterable.java \  	$(SRC)/AltosRecord.java \ +	$(SRC)/AltosRecordNone.java \  	$(SRC)/AltosRecordTM.java \  	$(SRC)/AltosRecordMM.java \  	$(SRC)/AltosReplayReader.java \ @@ -74,7 +75,8 @@ AltosLib_JAVA = \  	$(SRC)/AltosDistance.java \  	$(SRC)/AltosHeight.java \  	$(SRC)/AltosSpeed.java \ -	$(SRC)/AltosAccel.java +	$(SRC)/AltosAccel.java \ +	$(SRC)/AltosPyro.java  JAR=AltosLib.jar diff --git a/altosui/AltosAscent.java b/altosui/AltosAscent.java index 007c74ec..a05c4404 100644 --- a/altosui/AltosAscent.java +++ b/altosui/AltosAscent.java @@ -251,7 +251,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {  	class Speed extends AscentValueHold {  		void show (AltosState state, int crc_errors) { -			double speed = state.speed; +			double speed = state.accel_speed;  			if (!state.ascent)  				speed = state.baro_speed;  			show(AltosConvert.speed, speed); diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java index f8cc1ed6..1c929a7c 100644 --- a/altosui/AltosCSV.java +++ b/altosui/AltosCSV.java @@ -128,10 +128,10 @@ public class AltosCSV implements AltosWriter {  	void write_basic(AltosRecord record) {  		out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",  			   record.acceleration(), -			   record.raw_pressure(), -			   record.raw_altitude(), -			   record.raw_height(), -			   record.accel_speed(), +			   record.pressure(), +			   record.altitude(), +			   record.height(), +			   state.accel_speed,  			   state.baro_speed,  			   record.temperature(),  			   record.battery_voltage(), diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 44e5a3fa..44c6239a 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -22,6 +22,7 @@ import javax.swing.*;  import java.io.*;  import java.util.concurrent.*;  import org.altusmetrum.AltosLib.*; +import java.text.*;  public class AltosConfig implements ActionListener { @@ -78,6 +79,8 @@ public class AltosConfig implements ActionListener {  	string_ref	version;  	string_ref	product;  	string_ref	callsign; +	int_ref		npyro; +	AltosPyro[]	pyros;  	AltosConfigUI	config_ui;  	boolean		serial_started;  	boolean		made_visible; @@ -162,6 +165,8 @@ public class AltosConfig implements ActionListener {  		config_ui.set_ignite_mode(ignite_mode.get());  		config_ui.set_pad_orientation(pad_orientation.get());  		config_ui.set_callsign(callsign.get()); +		config_ui.set_pyros(pyros); +		config_ui.set_has_pyro(npyro.get() > 0);  		config_ui.set_clean();  		if (!made_visible) {  			made_visible = true; @@ -169,6 +174,8 @@ public class AltosConfig implements ActionListener {  		}  	} +	int	pyro; +  	void process_line(String line) {  		if (line == null) {  			abort(); @@ -179,6 +186,18 @@ public class AltosConfig implements ActionListener {  				update_ui();  			return;  		} +		if (pyro < npyro.get()) { +			if (pyros == null) +				pyros = new AltosPyro[npyro.get()]; + +			try { +				pyros[pyro] = new AltosPyro(pyro, line); +			} catch (ParseException e) { +				System.out.printf ("pyro parse failed %s\n", line); +			} +			++pyro; +			return; +		}  		get_int(line, "serial-number", serial);  		get_int(line, "log-format", log_format);  		get_int(line, "Main deploy:", main_deploy); @@ -200,6 +219,7 @@ public class AltosConfig implements ActionListener {  		get_string(line, "Callsign:", callsign);  		get_string(line,"software-version", version);  		get_string(line,"product", product); +		get_int(line, "Pyro-count:", npyro);  	}  	final static int	serial_mode_read = 0; @@ -243,6 +263,8 @@ public class AltosConfig implements ActionListener {  			callsign.set("N0CALL");  			version.set("unknown");  			product.set("unknown"); +			pyro = 0; +			npyro.set(0);  		}  		void get_data() { @@ -304,6 +326,12 @@ public class AltosConfig implements ActionListener {  					serial_line.printf("c i %d\n", ignite_mode.get());  				if (pad_orientation.get() >= 0)  					serial_line.printf("c o %d\n", pad_orientation.get()); +				if (pyros.length > 0) { +					for (int p = 0; p < pyros.length; p++) { +						serial_line.printf("c P %s\n", +								   pyros[p].toString()); +					} +				}  				serial_line.printf("c w\n");  			} catch (InterruptedException ie) {  			} catch (TimeoutException te) { @@ -431,6 +459,9 @@ public class AltosConfig implements ActionListener {  		if (pad_orientation.get() >= 0)  			pad_orientation.set(config_ui.pad_orientation());  		callsign.set(config_ui.callsign()); +		if (npyro.get() > 0) { +			pyros = config_ui.pyros(); +		}  		run_serial_thread(serial_mode_save);  	} @@ -477,13 +508,14 @@ public class AltosConfig implements ActionListener {  		callsign = new string_ref("N0CALL");  		version = new string_ref("unknown");  		product = new string_ref("unknown"); +		npyro = new int_ref(0);  		device = AltosDeviceDialog.show(owner, Altos.product_any);  		if (device != null) {  			try {  				serial_line = new AltosSerial(device);  				try { -					if (!device.matchProduct(Altos.product_altimeter)) +					if (device.matchProduct(Altos.product_basestation))  						remote = true;  					init_ui();  				} catch (InterruptedException ie) { diff --git a/altosui/AltosConfigPyroUI.java b/altosui/AltosConfigPyroUI.java new file mode 100644 index 00000000..17adb15f --- /dev/null +++ b/altosui/AltosConfigPyroUI.java @@ -0,0 +1,288 @@ +/* + * 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 altosui; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; +import org.altusmetrum.AltosLib.*; + +public class AltosConfigPyroUI +	extends AltosDialog +	implements ItemListener, DocumentListener +{ +	AltosConfigUI	owner; +	Container	pane; + +	static Insets il = new Insets(4,4,4,4); +	static Insets ir = new Insets(4,4,4,4); + +	static String[] state_names; + +	static void make_state_names() { +		if (state_names == null) { + +			state_names = new String[AltosLib.ao_flight_landed - AltosLib.ao_flight_boost + 1]; +			for (int state = AltosLib.ao_flight_boost; state <= AltosLib.ao_flight_landed; state++) +				state_names[state - AltosLib.ao_flight_boost] = AltosLib.state_name_capital(state); +		} +	} + +	class PyroItem implements ItemListener, DocumentListener +	{ +		public int		flag; +		public JRadioButton	enable; +		public JTextField	value; +		public JComboBox	combo; +		AltosConfigPyroUI	ui; + +		public void set_enable(boolean enable) { +			if (value != null) +				value.setEnabled(enable); +			if (combo != null) +				combo.setEnabled(enable); +		} + +		public void itemStateChanged(ItemEvent e) { +			set_enable(enable.isSelected()); +			ui.set_dirty(); +		} + +		public void changedUpdate(DocumentEvent e) { +			ui.set_dirty(); +		} + +		public void insertUpdate(DocumentEvent e) { +			ui.set_dirty(); +		} + +		public void removeUpdate(DocumentEvent e) { +			ui.set_dirty(); +		} + +		public void set(boolean new_enable, double new_value) { +			enable.setSelected(new_enable); +			set_enable(new_enable); +			if (value != null) { +				double	scale = AltosPyro.pyro_to_scale(flag); +				String	format = "%6.0f"; +				if (scale >= 10) +					format = "%6.1f"; +				else if (scale >= 100) +					format = "%6.2f"; +				value.setText(String.format(format, new_value)); +			} +			if (combo != null) +				if (new_value >= AltosLib.ao_flight_boost && new_value <= AltosLib.ao_flight_landed) +					combo.setSelectedIndex((int) new_value - AltosLib.ao_flight_boost); +		} + +		public boolean enabled() { +			return enable.isSelected(); +		} + +		public double value() { +			if (value != null) +				return Double.parseDouble(value.getText()); +			if (combo != null) +				return combo.getSelectedIndex() + AltosLib.ao_flight_boost; +			return 0; +		} + +		public PyroItem(AltosConfigPyroUI in_ui, int in_flag, int x, int y) { + +			ui = in_ui; +			flag = in_flag; + +			GridBagConstraints	c; +			c = new GridBagConstraints(); +			c.gridx = x; c.gridy = y; +			c.gridwidth = 1; +			c.fill = GridBagConstraints.NONE; +			c.anchor = GridBagConstraints.LINE_START; +			c.insets = il; +			enable = new JRadioButton(); +			enable.addItemListener(this); +			pane.add(enable, c); +			 +			if ((flag & AltosPyro.pyro_no_value) == 0) { +				c = new GridBagConstraints(); +				c.gridx = x+1; c.gridy = y; +				c.gridwidth = 1; +				c.fill = GridBagConstraints.NONE; +				c.anchor = GridBagConstraints.LINE_START; +				c.insets = il; +				if ((flag & AltosPyro.pyro_state_value) != 0) { +					make_state_names(); +					combo = new JComboBox(state_names); +					combo.addItemListener(this); +					pane.add(combo, c); +				} else { +					value = new JTextField(10); +					value.getDocument().addDocumentListener(this); +					pane.add(value, c); +				} +			} +		} +	} + +	class PyroColumn { +		public PyroItem[]	items; +		public JLabel		label; +		int			channel; + +		public void set(AltosPyro pyro) { +			int row = 0; +			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) { +				if ((AltosPyro.pyro_all & flag) != 0) { +					items[row].set((pyro.flags & flag) != 0, +						       pyro.get_value(flag)); +					row++; +				} +			} +		} + +		public AltosPyro get() { +			AltosPyro	p = new AltosPyro(channel); + +			int row = 0; +			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) { +				if ((AltosPyro.pyro_all & flag) != 0) { +					if (items[row].enabled()) { +						System.out.printf ("Flag %x enabled\n", flag); +						p.flags |= flag; +						p.set_value(flag, items[row].value()); +					} +					row++; +				} +			} +			System.out.printf ("Pyro %x %s\n", p.flags, p.toString()); +			return p; +		} + +		public PyroColumn(AltosConfigPyroUI ui, int x, int y, int in_channel) { + +			channel = in_channel; + +			int	nrow = 0; +			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) +				if ((flag & AltosPyro.pyro_all) != 0) +					nrow++; + +			items = new PyroItem[nrow]; +			int row = 0; +			 +			GridBagConstraints	c; +			c = new GridBagConstraints(); +			c.gridx = x; c.gridy = y; +			c.gridwidth = 2; +			c.fill = GridBagConstraints.NONE; +			c.anchor = GridBagConstraints.CENTER; +			c.insets = il; +			label = new JLabel(String.format("Pyro Channel %d", channel)); +			pane.add(label, c); +			y++; + +			for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) +				if ((flag & AltosPyro.pyro_all) != 0) { +					items[row] = new PyroItem(ui, flag, x, y + row); +					row++; +				} +		} +	} + +	PyroColumn[]	columns; + +	public void set_pyros(AltosPyro[] pyros) { +		for (int i = 0; i < pyros.length; i++) { +			if (pyros[i].channel < columns.length) +				columns[pyros[i].channel].set(pyros[i]); +		} +	} + +	public AltosPyro[] get_pyros() { +		AltosPyro[]	pyros = new AltosPyro[columns.length]; +		for (int c = 0; c < columns.length; c++) +			pyros[c] = columns[c].get(); +		return pyros; +	} + +	public void set_dirty() { +		owner.set_dirty(); +	} + +	public void itemStateChanged(ItemEvent e) { +		owner.set_dirty(); +	} + +	public void changedUpdate(DocumentEvent e) { +		owner.set_dirty(); +	} + +	public void insertUpdate(DocumentEvent e) { +		owner.set_dirty(); +	} + +	public void removeUpdate(DocumentEvent e) { +		owner.set_dirty(); +	} + +	public AltosConfigPyroUI(AltosConfigUI in_owner, AltosPyro[] pyros) { + +		super(in_owner, "Configure Pyro Channels", false); + +		owner = in_owner; + +		GridBagConstraints	c; + +		pane = getContentPane(); +		pane.setLayout(new GridBagLayout()); + +		int	row = 1; + +		for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) { +			String	n; + +			n = AltosPyro.pyro_to_name(flag); +			if (n != null) { +				c = new GridBagConstraints(); +				c.gridx = 0; c.gridy = row; +				c.gridwidth = 1; +				c.fill = GridBagConstraints.NONE; +				c.anchor = GridBagConstraints.LINE_START; +				c.insets = il; +				JLabel label = new JLabel(n); +				pane.add(label, c); +				row++; +			} +		} + +		columns = new PyroColumn[pyros.length]; + +		for (int i = 0; i < pyros.length; i++) { +			columns[i] = new PyroColumn(this, i*2 + 1, 0, i); +			columns[i].set(pyros[i]); +		} +	} + +	public void make_visible() { +		pack(); +		setVisible(true); +	} +} diff --git a/altosui/AltosConfigUI.java b/altosui/AltosConfigUI.java index dd34a9cf..feac053b 100644 --- a/altosui/AltosConfigUI.java +++ b/altosui/AltosConfigUI.java @@ -29,7 +29,6 @@ public class AltosConfigUI  {  	Container	pane; -	Box		box;  	JLabel		product_label;  	JLabel		version_label;  	JLabel		serial_label; @@ -62,11 +61,15 @@ public class AltosConfigUI  	JComboBox	pad_orientation_value;  	JTextField	callsign_value; +	JButton		pyro; +  	JButton		save;  	JButton		reset;  	JButton		reboot;  	JButton		close; +	AltosPyro[]	pyros; +  	ActionListener	listener;  	static String[] main_deploy_values = { @@ -510,6 +513,20 @@ public class AltosConfigUI  		set_pad_orientation_tool_tip();  		row++; +		/* Pyro channels */ +		c = new GridBagConstraints(); +		c.gridx = 4; c.gridy = row; +		c.gridwidth = 4; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		c.ipady = 5; +		pyro = new JButton("Configure Pyro Channels"); +		pane.add(pyro, c); +		pyro.addActionListener(this); +		pyro.setActionCommand("Pyro"); +		row++; +  		/* Buttons */  		c = new GridBagConstraints();  		c.gridx = 0; c.gridy = row; @@ -582,10 +599,30 @@ public class AltosConfigUI  		return true;  	} +	void set_dirty() { +		dirty = true; +		save.setEnabled(true); +	} + +	public void set_clean() { +		dirty = false; +		save.setEnabled(false); +	} + +	AltosConfigPyroUI	pyro_ui; +  	/* Listen for events from our buttons */  	public void actionPerformed(ActionEvent e) {  		String	cmd = e.getActionCommand(); +		if (cmd.equals("Pyro")) { +			if (pyro_ui == null && pyros != null) { +				pyro_ui = new AltosConfigPyroUI(this, pyros); +				pyro_ui.make_visible(); +			} +			return; +		} +  		if (cmd.equals("Close") || cmd.equals("Reboot"))  			if (!check_dirty(cmd))  				return; @@ -594,25 +631,25 @@ public class AltosConfigUI  			setVisible(false);  			dispose();  		} -		dirty = false; +		set_clean();  	}  	/* ItemListener interface method */  	public void itemStateChanged(ItemEvent e) { -		dirty = true; +		set_dirty();  	}  	/* DocumentListener interface methods */  	public void changedUpdate(DocumentEvent e) { -		dirty = true; +		set_dirty();  	}  	public void insertUpdate(DocumentEvent e) { -		dirty = true; +		set_dirty();  	}  	public void removeUpdate(DocumentEvent e) { -		dirty = true; +		set_dirty();  	}  	/* Let the config code hook on a listener */ @@ -725,8 +762,7 @@ public class AltosConfigUI  	}  	public void set_flight_log_max(int new_flight_log_max) { -		if (new_flight_log_max == 0) -			flight_log_max_value.setEnabled(false); +		flight_log_max_value.setEnabled(new_flight_log_max > 0);  		flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max));  		set_flight_log_max_tool_tip();  	} @@ -793,7 +829,19 @@ public class AltosConfigUI  			return -1;  	} -	public void set_clean() { -		dirty = false; +	public void set_has_pyro(boolean has_pyro) { +		pyro.setEnabled(has_pyro); +	} + +	public void set_pyros(AltosPyro[] new_pyros) { +		pyros = new_pyros; +		if (pyro_ui != null) +			pyro_ui.set_pyros(pyros); +	} + +	public AltosPyro[] pyros() { +		if (pyro_ui != null) +			pyros = pyro_ui.get_pyros(); +		return pyros;  	}  } diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java index 4d2f321e..a8a2ca49 100644 --- a/altosui/AltosDataChooser.java +++ b/altosui/AltosDataChooser.java @@ -70,6 +70,12 @@ public class AltosDataChooser extends JFileChooser {  	public AltosDataChooser(JFrame in_frame) {  		frame = in_frame;  		setDialogTitle("Select Flight Record File"); +		setFileFilter(new FileNameExtensionFilter("TeleMetrum eeprom file", +							  "eeprom")); +		setFileFilter(new FileNameExtensionFilter("Telemetry file", +							  "telem")); +		setFileFilter(new FileNameExtensionFilter("MegaMetrum eeprom file", +							  "mega"));  		setFileFilter(new FileNameExtensionFilter("Flight data file",  							  "telem", "eeprom", "mega"));  		setCurrentDirectory(AltosUIPreferences.logdir()); diff --git a/altosui/AltosDataPoint.java b/altosui/AltosDataPoint.java index 5e077320..4956e9f3 100644 --- a/altosui/AltosDataPoint.java +++ b/altosui/AltosDataPoint.java @@ -16,11 +16,8 @@ interface AltosDataPoint {      String state_name();      double acceleration(); -    double pressure(); -    double altitude();      double height(); -    double accel_speed(); -    double baro_speed(); +    double speed();      double temperature();      double battery_voltage();      double drogue_voltage(); diff --git a/altosui/AltosDataPointReader.java b/altosui/AltosDataPointReader.java index 2316cf97..88df081f 100644 --- a/altosui/AltosDataPointReader.java +++ b/altosui/AltosDataPointReader.java @@ -12,7 +12,6 @@ import org.altusmetrum.AltosLib.*;  class AltosDataPointReader implements Iterable<AltosDataPoint> {      Iterator<AltosRecord> iter;      AltosState state; -    AltosRecord record;      boolean has_gps;      boolean has_accel;      boolean has_ignite; @@ -22,7 +21,7 @@ class AltosDataPointReader implements Iterable<AltosDataPoint> {      public AltosDataPointReader(AltosRecordIterable reader) {          this.iter = reader.iterator();          this.state = null; -	has_accel = reader.has_accel(); +	has_accel = true;  	has_gps = reader.has_gps();  	has_ignite = reader.has_ignite();      } @@ -30,35 +29,31 @@ class AltosDataPointReader implements Iterable<AltosDataPoint> {      private void read_next_record()           throws NoSuchElementException      { -        record = iter.next(); -        state = new AltosState(record, state); +        state = new AltosState(iter.next(), state);      }      private AltosDataPoint current_dp() { -        assert this.record != null; +        assert this.state != null;          return new AltosDataPoint() { -            public int version() { return record.version; } -            public int serial() { return record.serial; } -            public int flight() { return record.flight; } -            public String callsign() { return record.callsign; } -            public double time() { return record.time; } -            public double rssi() { return record.rssi; } +            public int version() { return state.data.version; } +            public int serial() { return state.data.serial; } +            public int flight() { return state.data.flight; } +            public String callsign() { return state.data.callsign; } +            public double time() { return state.data.time; } +            public double rssi() { return state.data.rssi; } -            public int state() { return record.state; } -            public String state_name() { return record.state(); } +            public int state() { return state.state; } +            public String state_name() { return state.data.state(); } -            public double acceleration() { return record.acceleration(); } -            public double pressure() { return record.raw_pressure(); } -            public double altitude() { return record.raw_altitude(); } -	    public double height() { return record.raw_height(); } -            public double accel_speed() { return record.accel_speed(); } -            public double baro_speed() { return state.baro_speed; } -            public double temperature() { return record.temperature(); } -            public double battery_voltage() { return record.battery_voltage(); } -            public double drogue_voltage() { return record.drogue_voltage(); } -            public double main_voltage() { return record.main_voltage(); } -	    public boolean has_accel() { return has_accel; } +            public double acceleration() { return state.acceleration; } +	    public double height() { return state.height; } +	    public double speed() { return state.speed(); } +            public double temperature() { return state.temperature; } +            public double battery_voltage() { return state.battery; } +            public double drogue_voltage() { return state.drogue_sense; } +            public double main_voltage() { return state.main_sense; } +	    public boolean has_accel() { return true; } // return state.acceleration != AltosRecord.MISSING; }          };      } @@ -68,14 +63,14 @@ class AltosDataPointReader implements Iterable<AltosDataPoint> {                  throw new UnsupportedOperationException();               }              public boolean hasNext() { -		if (record != null && record.state == Altos.ao_flight_landed) +		if (state != null && state.state == Altos.ao_flight_landed)  		    return false;                  return iter.hasNext();              }              public AltosDataPoint next() {  		do {  		    read_next_record(); -		} while (record.time < -1.0 && hasNext()); +		} while (state.data.time < -1.0 && hasNext());                  return current_dp();              }          }; diff --git a/altosui/AltosDescent.java b/altosui/AltosDescent.java index a71cdc10..2ea7cbfa 100644 --- a/altosui/AltosDescent.java +++ b/altosui/AltosDescent.java @@ -256,7 +256,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {  	class Speed extends DescentValue {  		void show (AltosState state, int crc_errors) { -			double speed = state.speed; +			double speed = state.accel_speed;  			if (!state.ascent)  				speed = state.baro_speed;  			show(AltosConvert.speed, speed); diff --git a/altosui/AltosDialog.java b/altosui/AltosDialog.java index eac371aa..c2a9d6e6 100644 --- a/altosui/AltosDialog.java +++ b/altosui/AltosDialog.java @@ -45,6 +45,12 @@ public class AltosDialog extends JDialog implements AltosUIListener {  		addWindowListener(new AltosDialogListener());  	} +	public AltosDialog(Dialog dialog, String label, boolean modal) { +		super(dialog, label, modal); +		AltosUIPreferences.register_ui_listener(this); +		addWindowListener(new AltosDialogListener()); +	} +  	public AltosDialog(Frame frame, boolean modal) {  		super(frame, modal);  		AltosUIPreferences.register_ui_listener(this); diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java index f7a1d03e..1ba70c7e 100644 --- a/altosui/AltosDisplayThread.java +++ b/altosui/AltosDisplayThread.java @@ -197,7 +197,7 @@ public class AltosDisplayThread extends Thread {  			if ((old_state == null || old_state.state <= Altos.ao_flight_boost) &&  			    state.state > Altos.ao_flight_boost) {  				voice.speak("max speed: %s.", -					    AltosConvert.speed.say_units(state.max_speed + 0.5)); +					    AltosConvert.speed.say_units(state.max_accel_speed + 0.5));  				ret = true;  			} else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) &&  				   state.state >= Altos.ao_flight_drogue) { diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index a5e99749..21b46740 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -283,7 +283,7 @@ public class AltosEepromDownload implements Runnable {  				if (r.cmd == Altos.AO_LOG_GPS_TIME) {  					year = 2000 + r.data8(14);  					month = r.data8(15); -					day = r.data8(14); +					day = r.data8(16);  					want_file = true;  				} diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java index e48cb608..1653ca57 100644 --- a/altosui/AltosFlightStats.java +++ b/altosui/AltosFlightStats.java @@ -24,7 +24,7 @@ public class AltosFlightStats {  	double		max_height;  	double		max_speed;  	double		max_acceleration; -	double[]	state_speed = new double[Altos.ao_flight_invalid + 1]; +	double[]	state_accel_speed = new double[Altos.ao_flight_invalid + 1];  	double[]	state_baro_speed = new double[Altos.ao_flight_invalid + 1];  	double[]	state_accel = new double[Altos.ao_flight_invalid + 1];  	int[]		state_count = new int[Altos.ao_flight_invalid + 1]; @@ -123,7 +123,7 @@ public class AltosFlightStats {  					}  				}  				state_accel[state.state] += state.acceleration; -				state_speed[state.state] += state.speed; +				state_accel_speed[state.state] += state.accel_speed;  				state_baro_speed[state.state] += state.baro_speed;  				state_count[state.state]++;  				if (state_start[state.state] == 0.0) @@ -131,8 +131,8 @@ public class AltosFlightStats {  				if (state_end[state.state] < state.time)  					state_end[state.state] = state.time;  				max_height = state.max_height; -				if (state.max_speed != 0) -					max_speed = state.max_speed; +				if (state.max_accel_speed != 0) +					max_speed = state.max_accel_speed;  				else  					max_speed = state.max_baro_speed;  				max_acceleration = state.max_acceleration; @@ -140,7 +140,7 @@ public class AltosFlightStats {  		}  		for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) {  			if (state_count[s] > 0) { -				state_speed[s] /= state_count[s]; +				state_accel_speed[s] /= state_count[s];  				state_baro_speed[s] /= state_count[s];  				state_accel[s] /= state_count[s];  			} diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index cb8e3d20..f59f70ba 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -40,12 +40,7 @@ public class AltosGraphUI extends AltosFrame          AltosGraphTime.Element speed =  		new AltosGraphTime.TimeSeries(String.format("Speed (%s)", AltosConvert.speed.show_units()), "Vertical Speed", green) {                   public void gotTimeData(double time, AltosDataPoint d) { -		    double	speed; -		    if (d.state() < Altos.ao_flight_drogue && d.has_accel()) { -			speed = d.accel_speed(); -                    } else { -			speed = d.baro_speed(); -                    } +		    double	speed = d.speed();  		    if (speed != AltosRecord.MISSING)  			    series.add(time, AltosConvert.speed.value(speed));                  } diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java index 86e02ab1..11d1b0c1 100644 --- a/altosui/AltosInfoTable.java +++ b/altosui/AltosInfoTable.java @@ -114,8 +114,8 @@ public class AltosInfoTable extends JTable {  		info_add_row(0, "Max height", "%6.0f    m", state.max_height);  		info_add_row(0, "Acceleration", "%8.1f  m/s²", state.acceleration);  		info_add_row(0, "Max acceleration", "%8.1f  m/s²", state.max_acceleration); -		info_add_row(0, "Speed", "%8.1f  m/s", state.ascent ? state.speed : state.baro_speed); -		info_add_row(0, "Max Speed", "%8.1f  m/s", state.max_speed); +		info_add_row(0, "Speed", "%8.1f  m/s", state.speed()); +		info_add_row(0, "Max Speed", "%8.1f  m/s", state.max_accel_speed);  		info_add_row(0, "Temperature", "%9.2f °C", state.temperature);  		info_add_row(0, "Battery", "%9.2f V", state.battery);  		if (state.drogue_sense != AltosRecord.MISSING) diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java index 57339b19..281638bf 100644 --- a/altosui/AltosKML.java +++ b/altosui/AltosKML.java @@ -109,7 +109,7 @@ public class AltosKML implements AltosWriter {  		AltosGPS	gps = record.gps;  		out.printf(kml_coord_fmt,  			   gps.lon, gps.lat, -			   record.filtered_altitude(), (double) gps.alt, +			   record.altitude(), (double) gps.alt,  			   record.time, gps.nsat);  	} diff --git a/altosui/AltosLanded.java b/altosui/AltosLanded.java index 57c2d476..5e073f7d 100644 --- a/altosui/AltosLanded.java +++ b/altosui/AltosLanded.java @@ -173,7 +173,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio  	class Speed extends LandedValue {  		void show (AltosState state, int crc_errors) { -			show(AltosConvert.speed, state.max_speed); +			show(AltosConvert.speed, state.max_speed());  		}  		public Speed (GridBagLayout layout, int y) {  			super (layout, y, "Maximum Speed"); @@ -250,6 +250,9 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio  					} else if (filename.endsWith("telem")) {  						FileInputStream in = new FileInputStream(file);  						records = new AltosTelemetryIterable(in); +					} else if (filename.endsWith("mega")) { +						FileInputStream in = new FileInputStream(file); +						records = new AltosEepromMegaIterable(in);  					} else {  						throw new FileNotFoundException(filename);  					} diff --git a/altosui/Makefile.am b/altosui/Makefile.am index de7a86c0..306a396e 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -24,6 +24,7 @@ altosui_JAVA = \  	AltosConfig.java \  	AltosConfigFreqUI.java \  	AltosConfigUI.java \ +	AltosConfigPyroUI.java \  	AltosConfigureUI.java \  	AltosConfigTD.java \  	AltosConfigTDUI.java \ diff --git a/src/Makefile b/src/Makefile index b8828d46..1949e554 100644 --- a/src/Makefile +++ b/src/Makefile @@ -27,7 +27,7 @@ ifneq ($(shell which sdcc),)  endif  ifneq ($(shell which avr-gcc),) -	SUBDIRS += telescience-v0.1 telepyro-v0.1 +	SUBDIRS += telescience-v0.1 telescience-pwm telepyro-v0.1  endif  ifneq ($(shell which arm-none-eabi-gcc),) diff --git a/src/avr/ao_adc_avr.c b/src/avr/ao_adc_avr.c index 3a262977..231512b2 100644 --- a/src/avr/ao_adc_avr.c +++ b/src/avr/ao_adc_avr.c @@ -16,6 +16,7 @@   */  #include "ao.h" +#include "ao_pwmin.h"  volatile __xdata struct ao_data	ao_data_ring[AO_DATA_RING];  volatile __data uint8_t		ao_data_head; @@ -93,9 +94,13 @@ ISR(ADC_vect)  	value = ADCL;  	value |= (ADCH << 8);  	ao_data_ring[ao_data_head].adc.adc[ao_adc_channel] = value; -	if (++ao_adc_channel < NUM_ADC) +	if (++ao_adc_channel < NUM_ADC - HAS_ICP3_COUNT)  		ao_adc_start();  	else { +#if HAS_ICP3_COUNT +		/* steal last adc channel for pwm input */ +		ao_data_ring[ao_data_head].adc.adc[ao_adc_channel] = ao_icp3_count; +#endif  		ADCSRA = ADCSRA_INIT;  		ao_data_ring[ao_data_head].tick = ao_time();  		ao_data_head = ao_data_ring_next(ao_data_head); diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h index a14d0ade..96659aaf 100644 --- a/src/avr/ao_arch.h +++ b/src/avr/ao_arch.h @@ -37,7 +37,9 @@   * AVR definitions and code fragments for AltOS   */ +#ifndef AO_STACK_SIZE  #define AO_STACK_SIZE	116 +#endif  /* Various definitions to make GCC look more like SDCC */ diff --git a/src/avr/ao_pins.h b/src/avr/ao_pins.h index bc423ff7..a08e87fa 100644 --- a/src/avr/ao_pins.h +++ b/src/avr/ao_pins.h @@ -32,7 +32,7 @@  	#define HAS_BEEP		0  #endif -#ifdef TELESCIENCE +#if defined(TELESCIENCE) || defined(TELESCIENCE_PWM)  	#define LEDS_AVAILABLE		0  	#define HAS_USB			1  	#define HAS_LOG			1 @@ -47,6 +47,11 @@  	#define AVR_VCC_5V	       	0  	#define AVR_VCC_3V3		1  	#define AVR_CLOCK		8000000UL +#ifdef TELESCIENCE_PWM +	#define HAS_ICP3_COUNT		1 +#else +	#define HAS_ICP3_COUNT		0 +#endif  	#define SPI_CS_PORT		PORTE  	#define SPI_CS_DIR		DDRE @@ -64,6 +69,7 @@  #endif  #ifdef TELEPYRO +	#define AO_STACK_SIZE		104  	#define LEDS_AVAILABLE		0  	#define HAS_USB			1  	#define HAS_LOG			0 @@ -81,6 +87,7 @@  	#define IS_COMPANION		1  	#define HAS_ORIENT		0  	#define ao_storage_pos_t	uint16_t +	#define HAS_ICP3_COUNT		0  	#define AVR_VCC_5V	       	0  	#define AVR_VCC_3V3		1 diff --git a/src/avr/ao_pwmin.c b/src/avr/ao_pwmin.c new file mode 100644 index 00000000..84397357 --- /dev/null +++ b/src/avr/ao_pwmin.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2012 Robert D. Garbee <robert@gag.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_pwmin.h" + +/*  + * This code implements a PWM input using ICP3.   + * + * The initial use is to measure wind speed in the ULA/Ball summer intern  + * project payload developed at Challenger Middle School.   + */ + +volatile __data uint16_t ao_icp3_count = 0; +volatile __data uint16_t ao_icp3_last = 0; + +uint16_t ao_icp3(void) +{ +	uint16_t	v; +	ao_arch_critical( +		v = ao_icp3_count; +		); +	return v; +} + +static void +ao_pwmin_display(void) __reentrant +{ +	/* display the most recent value */ +	printf("icp 3: %5u\n", ao_icp3()); + +} + + +ISR(TIMER3_CAPT_vect) +{ +	 +	uint8_t lo = ICR3L;  +	uint8_t hi = ICR3H; +	uint16_t ao_icp3_this = (hi <<8) | lo; +	 +	/* handling counter rollovers */ +	if (ao_icp3_this >= ao_icp3_last) +		ao_icp3_count = ao_icp3_this - ao_icp3_last; +	else  +		ao_icp3_count = ao_icp3_this + (65536 - ao_icp3_last); +	ao_icp3_last = ao_icp3_this; +} + +__code struct ao_cmds ao_pwmin_cmds[] = { +	{ ao_pwmin_display,	"p\0PWM input" }, +	{ 0, NULL }, +}; + +void +ao_pwmin_init(void) +{ +	/* do hardware setup here */ +	TCCR3A = ((0 << WGM31) |        /* normal mode, OCR3A */ +                  (0 << WGM30));        /* normal mode, OCR3A */ +        TCCR3B = ((1 << ICNC3) |        /* input capture noise canceler on */ +                  (0 << ICES3) |        /* input capture on falling edge (don't care) */ +                  (0 << WGM33) |        /* normal mode, OCR3A */ +                  (0 << WGM32) |        /* normal mode, OCR3A */ +                  (3 << CS30));         /* clk/64 from prescaler */ + +    	 + +        TIMSK3 = (1 << ICIE3);         /* Interrupt on input compare */ + +		/* set the spike filter bit in the TCCR3B register */ + +	ao_cmd_register(&ao_pwmin_cmds[0]); +} + + diff --git a/src/avr/ao_pwmin.h b/src/avr/ao_pwmin.h new file mode 100644 index 00000000..8097d399 --- /dev/null +++ b/src/avr/ao_pwmin.h @@ -0,0 +1,20 @@ +/* + * Copyright © 2012 Robert D. Garbee <robert@gag.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. + */ + +void ao_pwmin_init(void); + +extern volatile __data uint16_t ao_icp3_count; diff --git a/src/core/ao_log.h b/src/core/ao_log.h index eaaca444..4eaed420 100644 --- a/src/core/ao_log.h +++ b/src/core/ao_log.h @@ -197,15 +197,18 @@ struct ao_log_mega {  	uint8_t			csum;			/* 1 */  	uint16_t		tick;			/* 2 */  	union {						/* 4 */ +		/* AO_LOG_FLIGHT */  		struct {  			uint16_t	flight;		/* 4 */  			int16_t		ground_accel;	/* 6 */  			uint32_t	ground_pres;	/* 8 */  		} flight;				/* 12 */ +		/* AO_LOG_STATE */  		struct {  			uint16_t	state;  			uint16_t	reason;  		} state; +		/* AO_LOG_SENSOR */  		struct {  			uint32_t	pres;		/* 4 */  			uint32_t	temp;		/* 8 */ @@ -220,12 +223,14 @@ struct ao_log_mega {  			int16_t		mag_z;		/* 28 */  			int16_t		accel;		/* 30 */  		} sensor;	/* 32 */ +		/* AO_LOG_TEMP_VOLT */  		struct {  			int16_t		v_batt;		/* 4 */  			int16_t		v_pbatt;	/* 6 */  			int16_t		n_sense;	/* 8 */  			int16_t		sense[10];	/* 10 */  		} volt;					/* 30 */ +		/* AO_LOG_GPS_TIME */  		struct {  			int32_t		latitude;	/* 4 */  			int32_t		longitude;	/* 8 */ @@ -239,6 +244,7 @@ struct ao_log_mega {  			uint8_t		day;		/* 20 */  			uint8_t		pad;		/* 21 */  		} gps;	/* 22 */ +		/* AO_LOG_GPS_SAT */  		struct {  			uint16_t	channels;	/* 4 */  			struct { diff --git a/src/core/ao_pyro.c b/src/core/ao_pyro.c index 4f37e979..aac8fda5 100644 --- a/src/core/ao_pyro.c +++ b/src/core/ao_pyro.c @@ -113,6 +113,15 @@ ao_pyro_ready(struct ao_pyro *pyro)  			/* handled separately */  			continue; +		case ao_pyro_state_less: +			if (ao_flight_state < pyro->state_less) +				continue; +			break; +		case ao_pyro_state_greater_or_equal: +			if (ao_flight_state >= pyro->state_greater_or_equal) +				continue; +			break; +  		default:  			continue;  		} @@ -166,7 +175,7 @@ uint8_t	ao_pyro_wakeup;  static void  ao_pyro(void)  { -	uint8_t		p; +	uint8_t		p, any_waiting;  	struct ao_pyro	*pyro;  	ao_config_get(); @@ -177,6 +186,7 @@ ao_pyro(void)  		ao_alarm(AO_MS_TO_TICKS(100));  		ao_sleep(&ao_pyro_wakeup);  		ao_clear_alarm(); +		any_waiting = 0;  		for (p = 0; p < AO_PYRO_NUM; p++) {  			pyro = &ao_config.pyro[p]; @@ -190,6 +200,7 @@ ao_pyro(void)  			if (!pyro->flags)  				continue; +			any_waiting = 1;  			/* Check pyro state to see if it shoule fire  			 */  			if (!pyro->delay_done) { @@ -213,7 +224,10 @@ ao_pyro(void)  			ao_pyro_fire(p);  		} +		if (!any_waiting) +			break;  	} +	ao_exit();  }  __xdata struct ao_task ao_pyro_task; @@ -257,6 +271,9 @@ const struct {  	{ "t<",	ao_pyro_time_less,	offsetof(struct ao_pyro, time_less), HELP("time less (s * 100)") },  	{ "t>",	ao_pyro_time_greater,	offsetof(struct ao_pyro, time_greater), HELP("time greater (s * 100)")  }, +	{ "f<",	ao_pyro_state_less,	offsetof(struct ao_pyro, state_less), HELP("state less") }, +	{ "f>=",ao_pyro_state_greater_or_equal,	offsetof(struct ao_pyro, state_greater_or_equal), HELP("state greater or equal")  }, +  	{ "A", ao_pyro_ascending,	NO_VALUE, HELP("ascending") },  	{ "D", ao_pyro_descending,	NO_VALUE, HELP("descending") }, diff --git a/src/core/ao_pyro.h b/src/core/ao_pyro.h index 5deb69d0..cde850ad 100644 --- a/src/core/ao_pyro.h +++ b/src/core/ao_pyro.h @@ -42,6 +42,9 @@ enum ao_pyro_flag {  	ao_pyro_after_motor		= 0x00001000,  	ao_pyro_delay			= 0x00002000, + +	ao_pyro_state_less		= 0x00004000, +	ao_pyro_state_greater_or_equal  = 0x00008000,  };  struct ao_pyro { @@ -52,6 +55,7 @@ struct ao_pyro {  	int16_t			orient_less, orient_greater;  	int16_t			time_less, time_greater;  	int16_t			delay; +	uint8_t			state_less, state_greater_or_equal;  	int16_t			motor;  	uint16_t		delay_done;  	uint8_t			fired; diff --git a/src/product/ao_telescience.c b/src/product/ao_telescience.c index 45b6d40e..d448d318 100644 --- a/src/product/ao_telescience.c +++ b/src/product/ao_telescience.c @@ -16,6 +16,9 @@   */  #include "ao.h" +#if HAS_ICP3_COUNT +#include "ao_pwmin.h" +#endif  int  main(void) @@ -34,6 +37,9 @@ main(void)  	ao_usb_init();  	ao_adc_init();  	ao_log_single_init(); +#if HAS_ICP3_COUNT +	ao_pwmin_init(); +#endif  	ao_start_scheduler();  	return 0;  } diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index 1132f748..f3011d3f 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -266,6 +266,7 @@ ao_clock_init(void)  	stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF); +#if DEBUG_THE_CLOCK  	/* Output SYSCLK on PA8 for measurments */  	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); @@ -276,4 +277,5 @@ ao_clock_init(void)  	stm_rcc.cfgr |= (STM_RCC_CFGR_MCOPRE_DIV_1 << STM_RCC_CFGR_MCOPRE);  	stm_rcc.cfgr |= (STM_RCC_CFGR_MCOSEL_HSE << STM_RCC_CFGR_MCOSEL); +#endif  } diff --git a/src/telepyro-v0.1/Makefile b/src/telepyro-v0.1/Makefile index 2ccd565f..6743ba66 100644 --- a/src/telepyro-v0.1/Makefile +++ b/src/telepyro-v0.1/Makefile @@ -96,7 +96,7 @@ ao_product.o: ao_product.c ao_product.h  distclean:	clean  clean: -	rm -f $(OBJ) +	rm -f $(OBJ) $(PROG) $(PROG).hex  	rm -f ao_product.h  install: diff --git a/src/telescience-pwm/.gitignore b/src/telescience-pwm/.gitignore new file mode 100644 index 00000000..dfccadf8 --- /dev/null +++ b/src/telescience-pwm/.gitignore @@ -0,0 +1,2 @@ +telescience-v0.1* +ao_product.h diff --git a/src/telescience-pwm/Makefile b/src/telescience-pwm/Makefile new file mode 100644 index 00000000..43d77e2e --- /dev/null +++ b/src/telescience-pwm/Makefile @@ -0,0 +1,116 @@ +# +# AltOS build +# +# +vpath % ..:../core:../product:../drivers:../avr +vpath ao-make-product.5c ../util + +MCU=atmega32u4 +DUDECPUTYPE=m32u4 +#PROGRAMMER=stk500v2 -P usb +PROGRAMMER=usbtiny +LOADCMD=avrdude +LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w: +CC=avr-gcc +OBJCOPY=avr-objcopy + +ifndef VERSION +include ../Version +endif + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_usb.h \ +	ao_pins.h \ +	ao_product.h + +# +# Common AltOS sources +# +TELESCIENCE_STORAGE= \ +	ao_m25.c \ +	ao_spi_usart.c \ +	ao_storage.c + +TELESCIENCE_LOG= \ +	ao_log_single.c \ +	ao_log_telescience.c + +ALTOS_SRC = \ +	ao_clock.c \ +	ao_cmd.c \ +	ao_mutex.c \ +	ao_panic.c \ +	ao_product.c \ +	ao_stdio.c \ +	ao_task.c \ +	ao_timer.c \ +	ao_led.c \ +	ao_avr_stdio.c \ +	ao_romconfig.c \ +	ao_usb_avr.c \ +	ao_adc_avr.c \ +	ao_science_slave.c \ +	ao_spi_slave.c \ +	ao_pwmin.c \ +	$(TELESCIENCE_STORAGE)\ +	$(TELESCIENCE_LOG) + +PRODUCT=TeleScience-PWM +MCU=atmega32u4 +PRODUCT_DEF=-DTELESCIENCE -DTELESCIENCE_PWM +IDPRODUCT=0x0011 +CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I.. +CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR + +NICKLE=nickle + +PROG=telescience-pwm + +SRC=$(ALTOS_SRC) ao_telescience.c +OBJ=$(SRC:.c=.o) + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf "  $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: $(PROG) + +CHECK=sh ../util/check-avr-mem + +$(PROG): Makefile $(OBJ) +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) +	$(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1) + +$(PROG).hex: $(PROG) +	avr-size $(PROG) +	$(OBJCOPY) -R .eeprom -O ihex $(PROG) $@ + + +load: $(PROG).hex +	$(LOADCMD) $(LOADARG)$(PROG).hex + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +ao_product.o: ao_product.c ao_product.h + +%.o : %.c $(INC) +	$(call quiet,CC) -c $(CFLAGS) $< + +distclean:	clean + +clean: +	rm -f *.o $(PROG) $(PROG).hex +	rm -f ao_product.h + +install: + +uninstall: + +$(OBJ): ao_product.h $(INC) diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 0df9a5d7..7180f02d 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -39,7 +39,7 @@  #define AO_ADC_NUM_SENSE	6  #define HAS_MS5607		1  #define HAS_MPU6000		1 -#define HAS_MMA655X		0 +#define HAS_MMA655X		1  struct ao_adc {  	int16_t			sense[AO_ADC_NUM_SENSE]; @@ -622,6 +622,9 @@ ao_sleep(void *wchan)  					ao_data_static.mpu6000.gyro_x = int16(bytes, 14);  					ao_data_static.mpu6000.gyro_y = -int16(bytes, 16);  					ao_data_static.mpu6000.gyro_z = int16(bytes, 18); +#if HAS_MMA655X +					ao_data_static.mma655x = int16(bytes, 26); +#endif  					if (ao_records_read == 0)  						ao_ground_mpu6000 = ao_data_static.mpu6000;  					else if (ao_records_read < 10) { diff --git a/src/test/run-mm b/src/test/run-mm new file mode 100755 index 00000000..6f3d97a2 --- /dev/null +++ b/src/test/run-mm @@ -0,0 +1,41 @@ +#!/bin/sh + +DIR=~/misc/rockets/flights + +for i in "$@"; do +case "$i" in +    */*) +    file="$i" +    ;; +    *) +    file="$DIR/$i" +    ;; +esac +./ao_flight_test_mm "$file" > run-out.mm + +#./ao_flight_test_accel "$file" > run-out.accel +#"run-out.accel" using 1:9 with lines lt 4 axes x1y1 title "accel height",\ +#"run-out.accel" using 1:11 with lines lt 4 axes x1y2 title "accel speed",\ +#"run-out.accel" using 1:13 with lines lt 4 axes x1y2 title "accel accel",\ +#"run-out.accel" using 1:15 with lines lt 4 axes x1y1 title "accel drogue",\ +#"run-out.accel" using 1:17 with lines lt 4 axes x1y1 title "accel main",\ +# + +gnuplot << EOF +set ylabel "altitude (m)" +set y2label "velocity (m/s), acceleration(m/s²)" +set xlabel "time (s)" +set xtics border out nomirror +set ytics border out nomirror +set y2tics border out nomirror +set title "$i" +plot "run-out.mm" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\ +"run-out.mm" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\ +"run-out.mm" using 1:21 with lines lt 2 axes x1y1 title "mm height",\ +"run-out.mm" using 1:23 with lines lt 2 axes x1y2 title "mm speed",\ +"run-out.mm" using 1:25 with lines lt 2 axes x1y2 title "mm accel",\ +"run-out.mm" using 1:29 with lines lt 2 axes x1y1 title "mm drogue",\ +"run-out.mm" using 1:31 with lines lt 2 axes x1y1 title "mm main" +pause mouse close +EOF +done
\ No newline at end of file diff --git a/src/util/check-avr-mem b/src/util/check-avr-mem index 7956f0aa..7956f0aa 100644..100755 --- a/src/util/check-avr-mem +++ b/src/util/check-avr-mem | 
