--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_1;
+
+import java.text.*;
+
+public class AltosEepromMini {
+ public int cmd;
+ public int tick;
+ public boolean valid;
+ public String data;
+ public int config_a, config_b;
+
+ public int data8[];
+
+ public static final int record_length = 16;
+ static final int header_length = 4;
+ static final int data_length = record_length - header_length;
+
+ public int data8(int i) {
+ return data8[i];
+ }
+
+ public int data16(int i) {
+ return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16;
+ }
+
+ public int data24(int i) {
+ return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16);
+ }
+
+ public int data32(int i) {
+ return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
+ }
+
+ /* AO_LOG_FLIGHT elements */
+ public int flight() { return data16(0); }
+ public int ground_pres() { return data32(4); }
+
+ /* AO_LOG_STATE elements */
+ public int state() { return data16(0); }
+ public int reason() { return data16(2); }
+
+ /* AO_LOG_SENSOR elements */
+ public int pres() { return data24(0); }
+ public int temp() { return data24(3); }
+ public int sense_a() { return data16(6); }
+ public int sense_m() { return data16(8); }
+ public int v_batt() { return data16(10); }
+
+ public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException {
+ cmd = chunk.data(start);
+
+ valid = !chunk.erased(start, record_length);
+ if (valid) {
+ if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
+ throw new ParseException(String.format("invalid checksum at 0x%x",
+ chunk.address + start), 0);
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ }
+
+ tick = chunk.data16(start+2);
+
+ data8 = new int[data_length];
+ for (int i = 0; i < data_length; i++)
+ data8[i] = chunk.data(start + header_length + i);
+ }
+
+ public AltosEepromMini (String line) {
+ valid = false;
+ tick = 0;
+
+ if (line == null) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ line = "";
+ } else {
+ try {
+ String[] tokens = line.split("\\s+");
+
+ if (tokens[0].length() == 1) {
+ if (tokens.length != 2 + data_length) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ data = line;
+ } else {
+ cmd = tokens[0].codePointAt(0);
+ tick = Integer.parseInt(tokens[1],16);
+ valid = true;
+ data8 = new int[data_length];
+ for (int i = 0; i < data_length; i++)
+ data8[i] = Integer.parseInt(tokens[2 + i],16);
+ }
+ } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+ cmd = AltosLib.AO_LOG_CONFIG_VERSION;
+ data = tokens[2];
+ } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+ cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+ cmd = AltosLib.AO_LOG_APOGEE_DELAY;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+ cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Callsign:")) {
+ cmd = AltosLib.AO_LOG_CALLSIGN;
+ data = tokens[1].replaceAll("\"","");
+ } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+ cmd = AltosLib.AO_LOG_ACCEL_CAL;
+ config_a = Integer.parseInt(tokens[3]);
+ config_b = Integer.parseInt(tokens[5]);
+ } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+ cmd = AltosLib.AO_LOG_RADIO_CAL;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
+ cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
+ config_a = Integer.parseInt(tokens[3]);
+ } else if (tokens[0].equals("manufacturer")) {
+ cmd = AltosLib.AO_LOG_MANUFACTURER;
+ data = tokens[1];
+ } else if (tokens[0].equals("product")) {
+ cmd = AltosLib.AO_LOG_PRODUCT;
+ data = tokens[1];
+ } else if (tokens[0].equals("serial-number")) {
+ cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
+ config_a = Integer.parseInt(tokens[1]);
+ } else if (tokens[0].equals("log-format")) {
+ cmd = AltosLib.AO_LOG_LOG_FORMAT;
+ config_a = Integer.parseInt(tokens[1]);
+ } else if (tokens[0].equals("software-version")) {
+ cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
+ data = tokens[1];
+ } else if (tokens[0].equals("ms5607")) {
+ if (tokens[1].equals("reserved:")) {
+ cmd = AltosLib.AO_LOG_BARO_RESERVED;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("sens:")) {
+ cmd = AltosLib.AO_LOG_BARO_SENS;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("off:")) {
+ cmd = AltosLib.AO_LOG_BARO_OFF;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tcs:")) {
+ cmd = AltosLib.AO_LOG_BARO_TCS;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tco:")) {
+ cmd = AltosLib.AO_LOG_BARO_TCO;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tref:")) {
+ cmd = AltosLib.AO_LOG_BARO_TREF;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("tempsens:")) {
+ cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
+ config_a = Integer.parseInt(tokens[2]);
+ } else if (tokens[1].equals("crc:")) {
+ cmd = AltosLib.AO_LOG_BARO_CRC;
+ config_a = Integer.parseInt(tokens[2]);
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ data = line;
+ }
+ } else {
+ cmd = AltosLib.AO_LOG_INVALID;
+ data = line;
+ }
+ } catch (NumberFormatException ne) {
+ cmd = AltosLib.AO_LOG_INVALID;
+ data = line;
+ }
+ }
+ }
+
+ public AltosEepromMini(int in_cmd, int in_tick) {
+ cmd = in_cmd;
+ tick = in_tick;
+ valid = true;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_1;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromMiniIterable extends AltosRecordIterable {
+
+ static final int seen_flight = 1;
+ static final int seen_sensor = 2;
+
+ static final int seen_basic = seen_flight|seen_sensor;
+
+ boolean has_accel;
+ boolean has_gps;
+ boolean has_ignite;
+
+ AltosEepromMini flight_record;
+
+ TreeSet<AltosOrderedMiniRecord> records;
+
+ AltosMs5607 baro;
+
+ LinkedList<AltosRecord> list;
+
+ class EepromState {
+ int seen;
+ int n_pad_samples;
+ double ground_pres;
+ int boost_tick;
+ int sensor_tick;
+
+ EepromState() {
+ seen = 0;
+ n_pad_samples = 0;
+ ground_pres = 0.0;
+ }
+ }
+
+ void update_state(AltosRecordMini state, AltosEepromMini record, EepromState eeprom) {
+ state.tick = record.tick;
+ switch (record.cmd) {
+ case AltosLib.AO_LOG_FLIGHT:
+ eeprom.seen |= seen_flight;
+ state.ground_pres = record.ground_pres();
+ state.flight_pres = state.ground_pres;
+ state.flight = record.data16(0);
+ eeprom.boost_tick = record.tick;
+ break;
+ case AltosLib.AO_LOG_SENSOR:
+ baro.set(record.pres(), record.temp());
+ state.pres = baro.pa;
+ state.temp = baro.cc;
+ state.sense_m = record.sense_m();
+ state.sense_a = record.sense_a();
+ state.v_batt = record.v_batt();
+ if (state.state < AltosLib.ao_flight_boost) {
+ eeprom.n_pad_samples++;
+ eeprom.ground_pres += state.pres;
+ state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
+ state.flight_pres = state.ground_pres;
+ } else {
+ state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
+ }
+ if ((eeprom.seen & seen_sensor) == 0)
+ eeprom.sensor_tick = record.tick - 1;
+ eeprom.seen |= seen_sensor;
+ eeprom.sensor_tick = record.tick;
+ break;
+ case AltosLib.AO_LOG_STATE:
+ state.state = record.state();
+ break;
+ case AltosLib.AO_LOG_CONFIG_VERSION:
+ break;
+ case AltosLib.AO_LOG_MAIN_DEPLOY:
+ break;
+ case AltosLib.AO_LOG_APOGEE_DELAY:
+ break;
+ case AltosLib.AO_LOG_RADIO_CHANNEL:
+ break;
+ case AltosLib.AO_LOG_CALLSIGN:
+ state.callsign = record.data;
+ break;
+ case AltosLib.AO_LOG_RADIO_CAL:
+ break;
+ case AltosLib.AO_LOG_MANUFACTURER:
+ break;
+ case AltosLib.AO_LOG_PRODUCT:
+ break;
+ case AltosLib.AO_LOG_SERIAL_NUMBER:
+ state.serial = record.config_a;
+ break;
+ case AltosLib.AO_LOG_SOFTWARE_VERSION:
+ break;
+ case AltosLib.AO_LOG_BARO_RESERVED:
+ baro.reserved = record.config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_SENS:
+ baro.sens =record.config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_OFF:
+ baro.off =record.config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TCS:
+ baro.tcs =record.config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TCO:
+ baro.tco =record.config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TREF:
+ baro.tref =record.config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_TEMPSENS:
+ baro.tempsens =record.config_a;
+ break;
+ case AltosLib.AO_LOG_BARO_CRC:
+ baro.crc =record.config_a;
+ break;
+ }
+ state.seen |= eeprom.seen;
+ }
+
+ LinkedList<AltosRecord> make_list() {
+ LinkedList<AltosRecord> list = new LinkedList<AltosRecord>();
+ Iterator<AltosOrderedMiniRecord> iterator = records.iterator();
+ AltosOrderedMiniRecord record = null;
+ AltosRecordMini state = new AltosRecordMini();
+ //boolean last_reported = false;
+ EepromState eeprom = new EepromState();
+
+ state.state = AltosLib.ao_flight_pad;
+
+ /* Pull in static data from the flight records */
+ if (flight_record != null)
+ update_state(state, flight_record, eeprom);
+
+ while (iterator.hasNext()) {
+ record = iterator.next();
+ if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
+ AltosRecordMini r = state.clone();
+ r.time = (r.tick - eeprom.boost_tick) / 100.0;
+ list.add(r);
+ }
+ update_state(state, record, eeprom);
+ }
+ AltosRecordMini r = state.clone();
+ r.time = (r.tick - eeprom.boost_tick) / 100.0;
+ list.add(r);
+ return list;
+ }
+
+ public Iterator<AltosRecord> iterator() {
+ if (list == null)
+ list = make_list();
+ return list.iterator();
+ }
+
+ public boolean has_gps() { return has_gps; }
+ public boolean has_accel() { return has_accel; }
+ public boolean has_ignite() { return has_ignite; }
+
+ public void write_comments(PrintStream out) {
+ Iterator<AltosOrderedMiniRecord> iterator = records.iterator();
+ out.printf("# Comments\n");
+ while (iterator.hasNext()) {
+ AltosOrderedMiniRecord record = iterator.next();
+ switch (record.cmd) {
+ case AltosLib.AO_LOG_CONFIG_VERSION:
+ out.printf("# Config version: %s\n", record.data);
+ break;
+ case AltosLib.AO_LOG_MAIN_DEPLOY:
+ out.printf("# Main deploy: %s\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_APOGEE_DELAY:
+ out.printf("# Apogee delay: %s\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_RADIO_CHANNEL:
+ out.printf("# Radio channel: %s\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_CALLSIGN:
+ out.printf("# Callsign: %s\n", record.data);
+ break;
+ case AltosLib.AO_LOG_ACCEL_CAL:
+ out.printf ("# Accel cal: %d %d\n", record.config_a, record.config_b);
+ break;
+ case AltosLib.AO_LOG_RADIO_CAL:
+ out.printf ("# Radio cal: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
+ out.printf ("# Max flight log: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_MANUFACTURER:
+ out.printf ("# Manufacturer: %s\n", record.data);
+ break;
+ case AltosLib.AO_LOG_PRODUCT:
+ out.printf ("# Product: %s\n", record.data);
+ break;
+ case AltosLib.AO_LOG_SERIAL_NUMBER:
+ out.printf ("# Serial number: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_SOFTWARE_VERSION:
+ out.printf ("# Software version: %s\n", record.data);
+ break;
+ case AltosLib.AO_LOG_BARO_RESERVED:
+ out.printf ("# Baro reserved: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_SENS:
+ out.printf ("# Baro sens: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_OFF:
+ out.printf ("# Baro off: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TCS:
+ out.printf ("# Baro tcs: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TCO:
+ out.printf ("# Baro tco: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TREF:
+ out.printf ("# Baro tref: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_TEMPSENS:
+ out.printf ("# Baro tempsens: %d\n", record.config_a);
+ break;
+ case AltosLib.AO_LOG_BARO_CRC:
+ out.printf ("# Baro crc: %d\n", record.config_a);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Read the whole file, dumping records into a RB tree so
+ * we can enumerate them in time order -- the eeprom data
+ * are sometimes out of order
+ */
+ public AltosEepromMiniIterable (FileInputStream input) {
+ records = new TreeSet<AltosOrderedMiniRecord>();
+
+ AltosOrderedMiniRecord last_gps_time = null;
+
+ baro = new AltosMs5607();
+
+ int index = 0;
+ int prev_tick = 0;
+ boolean prev_tick_valid = false;
+ boolean missing_time = false;
+
+ try {
+ for (;;) {
+ String line = AltosLib.gets(input);
+ if (line == null)
+ break;
+ AltosOrderedMiniRecord record = new AltosOrderedMiniRecord(line, index++, prev_tick, prev_tick_valid);
+ if (record.cmd == AltosLib.AO_LOG_INVALID)
+ continue;
+ prev_tick = record.tick;
+ if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
+ prev_tick_valid = true;
+ if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
+ flight_record = record;
+ continue;
+ }
+
+ records.add(record);
+
+ /* Bail after reading the 'landed' record; we're all done */
+ if (record.cmd == AltosLib.AO_LOG_STATE &&
+ record.state() == AltosLib.ao_flight_landed)
+ break;
+ }
+ } catch (IOException io) {
+ } catch (ParseException pe) {
+ }
+ try {
+ input.close();
+ } catch (IOException ie) {
+ }
+ }
+}
public static final int AO_LOG_FORMAT_TELEMETRY = 3;
public static final int AO_LOG_FORMAT_TELESCIENCE = 4;
public static final int AO_LOG_FORMAT_TELEMEGA = 5;
+ public static final int AO_LOG_FORMAT_MINI = 6;
public static final int AO_LOG_FORMAT_NONE = 127;
public static boolean isspace(int c) {
--- /dev/null
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_1;
+
+import java.text.ParseException;
+
+/*
+ * AltosRecords with an index field so they can be sorted by tick while preserving
+ * the original ordering for elements with matching ticks
+ */
+class AltosOrderedMiniRecord extends AltosEepromMini implements Comparable<AltosOrderedMiniRecord> {
+
+ public int index;
+
+ public AltosOrderedMiniRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
+ throws ParseException {
+ super(line);
+ if (prev_tick_valid) {
+ tick |= (prev_tick & ~0xffff);
+ if (tick < prev_tick) {
+ if (prev_tick - tick > 0x8000)
+ tick += 0x10000;
+ } else {
+ if (tick - prev_tick > 0x8000)
+ tick -= 0x10000;
+ }
+ }
+ index = in_index;
+ }
+
+ public int compareTo(AltosOrderedMiniRecord o) {
+ int tick_diff = tick - o.tick;
+ if (tick_diff != 0)
+ return tick_diff;
+ return index - o.index;
+ }
+}
--- /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_1;
+
+public class AltosRecordMini extends AltosRecord {
+
+ /* Sensor values */
+ public int pres;
+ public int temp;
+
+ public int sense_a;
+ public int sense_m;
+ public int v_batt;
+
+ public int ground_pres;
+
+ public int flight_accel;
+ public int flight_vel;
+ public int flight_pres;
+
+ static double adc(int raw) {
+ return raw / 4095.0;
+ }
+
+ public double pressure() {
+ if (pres != MISSING)
+ return pres;
+ return MISSING;
+ }
+
+ public double temperature() {
+ if (temp != MISSING)
+ return temp;
+ return MISSING;
+ }
+
+ public double ground_pressure() {
+ if (ground_pres != MISSING)
+ return ground_pres;
+ return MISSING;
+ }
+
+ public double battery_voltage() {
+ if (v_batt != MISSING)
+ return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0;
+ return MISSING;
+ }
+
+ static double pyro(int raw) {
+ if (raw != MISSING)
+ return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0;
+ return MISSING;
+ }
+
+ public double main_voltage() {
+ return pyro(sense_m);
+ }
+
+ public double apogee_voltage() {
+ return pyro(sense_a);
+ }
+
+ public void copy (AltosRecordMini old) {
+ super.copy(old);
+
+ pres = old.pres;
+ temp = old.temp;
+
+ sense_a = old.sense_a;
+ sense_m = old.sense_m;
+ v_batt = old.v_batt;
+
+ ground_pres = old.ground_pres;
+
+ flight_accel = old.flight_accel;
+ flight_vel = old.flight_vel;
+ flight_pres = old.flight_pres;
+ }
+
+
+
+ public AltosRecordMini clone() {
+ return new AltosRecordMini(this);
+ }
+
+ void make_missing() {
+
+ pres = MISSING;
+
+ sense_a = MISSING;
+ sense_m = MISSING;
+ v_batt = MISSING;
+
+ ground_pres = MISSING;
+
+ flight_accel = 0;
+ flight_vel = 0;
+ flight_pres = 0;
+ }
+
+ public AltosRecordMini(AltosRecord old) {
+ super.copy(old);
+ make_missing();
+ }
+
+ public AltosRecordMini(AltosRecordMini old) {
+ copy(old);
+ }
+
+ public AltosRecordMini() {
+ super();
+ make_missing();
+ }
+}
AltosEepromMegaIterable.java \
AltosEepromRecord.java \
AltosEepromTeleScience.java \
+ AltosEepromMini.java \
+ AltosEepromMiniIterable.java \
AltosFile.java \
AltosFlash.java \
AltosFlashListener.java \
AltosMs5607Query.java \
AltosOrderedRecord.java \
AltosOrderedMegaRecord.java \
+ AltosOrderedMiniRecord.java \
AltosParse.java \
AltosPreferences.java \
AltosPreferencesBackend.java \
AltosRecordNone.java \
AltosRecordTM.java \
AltosRecordMM.java \
+ AltosRecordMini.java \
AltosReplayReader.java \
AltosRomconfig.java \
AltosSensorMM.java \
} else if (filename.endsWith("mega")) {
FileInputStream in = new FileInputStream(file);
return new AltosEepromMegaIterable(in);
+ } else if (filename.endsWith("mini")) {
+ FileInputStream in = new FileInputStream(file);
+ return new AltosEepromMiniIterable(in);
} else {
throw new FileNotFoundException();
}
"telem"));
setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file",
"mega"));
+ setFileFilter(new FileNameExtensionFilter("EasyMini eeprom file",
+ "mini"));
setFileFilter(new FileNameExtensionFilter("Flight data file",
- "telem", "eeprom", "mega"));
+ "telem", "eeprom", "mega", "mini"));
setCurrentDirectory(AltosUIPreferences.logdir());
}
}
CheckFile(false);
}
+ void LogMini(AltosEepromMini r) throws IOException {
+ if (r.cmd != Altos.AO_LOG_INVALID) {
+ String log_line = String.format("%c %4x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+ r.cmd, r.tick,
+ r.data8[0], r.data8[1], r.data8[2], r.data8[3],
+ r.data8[4], r.data8[5], r.data8[6], r.data8[7],
+ r.data8[8], r.data8[9], r.data8[10], r.data8[11]);
+ if (eeprom_file != null)
+ eeprom_file.write(log_line);
+ else
+ eeprom_pending.add(log_line);
+ }
+ }
+
+ void CaptureMini(AltosEepromChunk eechunk) throws IOException {
+ boolean any_valid = false;
+
+ extension = "mini";
+ set_serial(flights.config_data.serial);
+ for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromMini.record_length) {
+ try {
+ AltosEepromMini r = new AltosEepromMini(eechunk, i);
+ if (r.cmd == Altos.AO_LOG_FLIGHT)
+ set_flight(r.data16(0));
+
+ /* Monitor state transitions to update display */
+ if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) <= Altos.ao_flight_landed) {
+ state = r.data16(0);
+ if (state > Altos.ao_flight_pad)
+ want_file = true;
+ }
+
+ if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) == Altos.ao_flight_landed)
+ done = true;
+ any_valid = true;
+ LogMini(r);
+ } catch (ParseException pe) {
+ if (parse_exception == null)
+ parse_exception = pe;
+ }
+ }
+ if (!any_valid)
+ done = true;
+
+ CheckFile(false);
+ }
+
void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException {
}
case AltosLib.AO_LOG_FORMAT_TELEMEGA:
extension = "mega";
CaptureMega(eechunk);
+ case AltosLib.AO_LOG_FORMAT_MINI:
+ extension = "mini";
+ CaptureMini(eechunk);
}
}
CheckFile(true);
} else if (filename.endsWith("mega")) {
FileInputStream in = new FileInputStream(file);
records = new AltosEepromMegaIterable(in);
+ } else if (filename.endsWith("mini")) {
+ FileInputStream in = new FileInputStream(file);
+ records = new AltosEepromMiniIterable(in);
} else {
throw new FileNotFoundException(filename);
}
return new AltosEepromIterable(in);
else if (file.getName().endsWith("mega"))
return new AltosEepromMegaIterable(in);
+ else if (file.getName().endsWith("mini"))
+ return new AltosEepromMiniIterable(in);
else
return new AltosTelemetryIterable(in);
} catch (FileNotFoundException fe) {
recs = new AltosEepromIterable(in);
} else if (file.getName().endsWith("mega")) {
recs = new AltosEepromMegaIterable(in);
+ } else if (file.getName().endsWith("mini")) {
+ recs = new AltosEepromMiniIterable(in);
} else {
recs = new AltosTelemetryIterable(in);
}
#define AO_LOG_FORMAT_TELEMETRY 3 /* 32 byte ao_telemetry records */
#define AO_LOG_FORMAT_TELESCIENCE 4 /* 32 byte typed telescience records */
#define AO_LOG_FORMAT_TELEMEGA 5 /* 32 byte typed telemega records */
+#define AO_LOG_FORMAT_MINI 6 /* 16-byte MS5607 baro only */
#define AO_LOG_FORMAT_NONE 127 /* No log at all */
extern __code uint8_t ao_log_format;
} u;
};
+struct ao_log_mini {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ uint16_t r6;
+ uint32_t ground_pres; /* 8 */
+ } flight;
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state; /* 4 */
+ uint16_t reason; /* 6 */
+ } state;
+ /* AO_LOG_SENSOR */
+ struct {
+ uint8_t pres[3]; /* 4 */
+ uint8_t temp[3]; /* 7 */
+ int16_t sense_a; /* 10 */
+ int16_t sense_m; /* 12 */
+ int16_t v_batt; /* 14 */
+ } sensor; /* 16 */
+ } u; /* 16 */
+}; /* 16 */
+
+static inline void
+ao_log_pack24(uint8_t *dst, uint32_t value) {
+ dst[0] = value;
+ dst[1] = value >> 8;
+ dst[2] = value >> 16;
+}
+
/* Write a record to the eeprom log */
uint8_t
ao_log_data(__xdata struct ao_log_record *log) __reentrant;
uint8_t
ao_log_mega(__xdata struct ao_log_mega *log) __reentrant;
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant;
+
void
ao_log_flush(void);
--- /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.
+ */
+
+#include "ao.h"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_mini log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_MINI;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_mini); i++)
+ sum += *b++;
+ return -sum;
+}
+
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant
+{
+ uint8_t wrote = 0;
+ /* set checksum */
+ log->csum = 0;
+ log->csum = ao_log_csum((__xdata uint8_t *) log);
+ ao_mutex_get(&ao_log_mutex); {
+ if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+ ao_log_stop();
+ if (ao_log_running) {
+ wrote = 1;
+ ao_storage_write(ao_log_current_pos,
+ log,
+ sizeof (struct ao_log_mini));
+ ao_log_current_pos += sizeof (struct ao_log_mini);
+ }
+ } ao_mutex_put(&ao_log_mutex);
+ return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+ if (ao_log_csum((uint8_t *) &log) != 0)
+ return 0;
+ return 1;
+}
+
+static __data uint8_t ao_log_data_pos;
+
+/* a hack to make sure that ao_log_minis fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mini))] ;
+
+#ifndef AO_SENSOR_INTERVAL_ASCENT
+#define AO_SENSOR_INTERVAL_ASCENT 1
+#define AO_SENSOR_INTERVAL_DESCENT 10
+#endif
+
+void
+ao_log(void)
+{
+ __pdata uint16_t next_sensor, next_other;
+ uint8_t i;
+
+ ao_storage_setup();
+
+ ao_log_scan();
+
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+#if HAS_FLIGHT
+ log.type = AO_LOG_FLIGHT;
+ log.tick = ao_sample_tick;
+ log.u.flight.flight = ao_flight_number;
+ log.u.flight.ground_pres = ao_ground_pres;
+ ao_log_mini(&log);
+#endif
+
+ /* Write the whole contents of the ring to the log
+ * when starting up.
+ */
+ ao_log_data_pos = ao_data_ring_next(ao_data_head);
+ next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick;
+ ao_log_state = ao_flight_startup;
+ for (;;) {
+ /* Write samples to EEPROM */
+ while (ao_log_data_pos != ao_data_head) {
+ log.tick = ao_data_ring[ao_log_data_pos].tick;
+ if ((int16_t) (log.tick - next_sensor) >= 0) {
+ log.type = AO_LOG_SENSOR;
+ ao_log_pack24(log.u.sensor.pres,
+ ao_data_ring[ao_log_data_pos].ms5607_raw.pres);
+ ao_log_pack24(log.u.sensor.temp,
+ ao_data_ring[ao_log_data_pos].ms5607_raw.temp);
+ log.u.sensor.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
+ log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
+ log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+ ao_log_mini(&log);
+ if (ao_log_state <= ao_flight_coast)
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+ else
+ next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+ }
+ ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+ }
+#if HAS_FLIGHT
+ /* Write state change to EEPROM */
+ if (ao_flight_state != ao_log_state) {
+ ao_log_state = ao_flight_state;
+ log.type = AO_LOG_STATE;
+ log.tick = ao_time();
+ log.u.state.state = ao_log_state;
+ log.u.state.reason = 0;
+ ao_log_mini(&log);
+
+ if (ao_log_state == ao_flight_landed)
+ ao_log_stop();
+ }
+#endif
+
+ ao_log_flush();
+
+ /* Wait for a while */
+ ao_delay(AO_MS_TO_TICKS(100));
+
+ /* Stop logging when told to */
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+ }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+ if (!ao_storage_read(ao_log_pos(slot),
+ &log,
+ sizeof (struct ao_log_mini)))
+ return 0;
+
+ if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+ return log.u.flight.flight;
+ return 0;
+}
ao_led_lpc.c \
ao_task.c \
ao_log.c \
- ao_log_tiny.c \
+ ao_log_mini.c \
ao_cmd.c \
ao_config.c \
ao_timer_lpc.c \
#define AO_ADC_2 1
struct ao_adc {
- int16_t sense_d;
+ int16_t sense_a;
int16_t sense_m;
int16_t v_batt;
};
#define AO_IGNITER_MAIN_PIN 3
#define AO_IGNITER_SET_MAIN(v) ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v)
+#define AO_SENSE_DROGUE(p) ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p) ((p)->adc.sense_m)
+
#define AO_ADC_DUMP(p) \
- printf("tick: %5u drogue: %5d main: %5d batt: %5d\n", \
- (p)->tick, (p)->adc.sense_d, (p)->adc.sense_m, (p)->adc.v_batt)
+ printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \
+ (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)