--- /dev/null
+<?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>
local.properties
bin
gen
+src/org/altusmetrum/AltosDroid/BuildInfo.java
<projects>
</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>
$(SRC_DIR)/TelemetryLogger.java \
$(SRC_DIR)/AltosBluetooth.java \
$(SRC_DIR)/DeviceListActivity.java \
+ $(SRC_DIR)/BuildInfo.java \
$(SRC_DIR)/Dumper.java
all: $(all_target)
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
clean:
$(clean_command)
+.PHONY: $(SRC_DIR)/BuildInfo.java
--- /dev/null
+#!/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
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));
speak(state.data.state());\r
if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&\r
state.state > AltosLib.ao_flight_boost) {\r
- speak(String.format("max speed: %d meters per second.", (int) (state.max_speed + 0.5)));\r
+ speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));\r
spoke = true;\r
} else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&\r
state.state >= AltosLib.ao_flight_drogue) {\r
--- /dev/null
+/*
+ * 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@";
+}
+
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();
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)
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) {}
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"))
public int tick;
public boolean valid;
public String data;
- public int a, b;
+ public int config_a, config_b;
public int data8[];
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); }
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);
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];
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;
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:
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;
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;
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);
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
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) {
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);
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];
}
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)
--- /dev/null
+/*
+ * 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;
+ }
+}
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;
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;
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:
* 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);
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() {
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;
}
}
public class AltosRecordMM extends AltosRecord {
+ /* Sensor values */
public int accel;
public int pres;
public int temp;
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;
}
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() {
- return speed;
- }
-
public void copy (AltosRecordMM old) {
super.copy(old);
--- /dev/null
+/*
+ * 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();
+ }
+}
package org.altusmetrum.AltosLib;
public class AltosRecordTM extends AltosRecord {
+
+ /* Sensor values */
public int accel;
public int pres;
public int temp;
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;
}
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);
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;
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();
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;
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;
/* 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;
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);
/* 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;
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;
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;
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;
if (previous != null)
next = previous.clone();
else
- next = new AltosRecord();
+ next = new AltosRecordNone();
next.serial = serial;
next.tick = tick;
return next;
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) {
$(SRC)/AltosRecordCompanion.java \
$(SRC)/AltosRecordIterable.java \
$(SRC)/AltosRecord.java \
+ $(SRC)/AltosRecordNone.java \
$(SRC)/AltosRecordTM.java \
$(SRC)/AltosRecordMM.java \
$(SRC)/AltosReplayReader.java \
$(SRC)/AltosDistance.java \
$(SRC)/AltosHeight.java \
$(SRC)/AltosSpeed.java \
- $(SRC)/AltosAccel.java
+ $(SRC)/AltosAccel.java \
+ $(SRC)/AltosPyro.java
JAR=AltosLib.jar
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);
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(),
import java.io.*;
import java.util.concurrent.*;
import org.altusmetrum.AltosLib.*;
+import java.text.*;
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;
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;
}
}
+ int pyro;
+
void process_line(String line) {
if (line == null) {
abort();
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);
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;
callsign.set("N0CALL");
version.set("unknown");
product.set("unknown");
+ pyro = 0;
+ npyro.set(0);
}
void get_data() {
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) {
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);
}
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) {
--- /dev/null
+/*
+ * 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);
+ }
+}
{
Container pane;
- Box box;
JLabel product_label;
JLabel version_label;
JLabel serial_label;
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 = {
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;
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;
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 */
}
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();
}
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;
}
}
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());
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();
class AltosDataPointReader implements Iterable<AltosDataPoint> {
Iterator<AltosRecord> iter;
AltosState state;
- AltosRecord record;
boolean has_gps;
boolean has_accel;
boolean has_ignite;
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();
}
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; }
};
}
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();
}
};
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);
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);
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) {
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;
}
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];
}
}
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)
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;
}
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];
}
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));
}
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)
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);
}
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");
} 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);
}
AltosConfig.java \
AltosConfigFreqUI.java \
AltosConfigUI.java \
+ AltosConfigPyroUI.java \
AltosConfigureUI.java \
AltosConfigTD.java \
AltosConfigTDUI.java \
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),)
*/
#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;
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);
* 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 */
#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
#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
#endif
#ifdef TELEPYRO
+ #define AO_STACK_SIZE 104
#define LEDS_AVAILABLE 0
#define HAS_USB 1
#define HAS_LOG 0
#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
--- /dev/null
+/*
+ * 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]);
+}
+
+
--- /dev/null
+/*
+ * 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;
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 */
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 */
uint8_t day; /* 20 */
uint8_t pad; /* 21 */
} gps; /* 22 */
+ /* AO_LOG_GPS_SAT */
struct {
uint16_t channels; /* 4 */
struct {
/* 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;
}
static void
ao_pyro(void)
{
- uint8_t p;
+ uint8_t p, any_waiting;
struct ao_pyro *pyro;
ao_config_get();
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];
if (!pyro->flags)
continue;
+ any_waiting = 1;
/* Check pyro state to see if it shoule fire
*/
if (!pyro->delay_done) {
ao_pyro_fire(p);
}
+ if (!any_waiting)
+ break;
}
+ ao_exit();
}
__xdata struct ao_task ao_pyro_task;
{ "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") },
ao_pyro_after_motor = 0x00001000,
ao_pyro_delay = 0x00002000,
+
+ ao_pyro_state_less = 0x00004000,
+ ao_pyro_state_greater_or_equal = 0x00008000,
};
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;
*/
#include "ao.h"
+#if HAS_ICP3_COUNT
+#include "ao_pwmin.h"
+#endif
int
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;
}
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);
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
}
distclean: clean
clean:
- rm -f $(OBJ)
+ rm -f $(OBJ) $(PROG) $(PROG).hex
rm -f ao_product.h
install:
--- /dev/null
+telescience-v0.1*
+ao_product.h
--- /dev/null
+#
+# 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)
#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];
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) {
--- /dev/null
+#!/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