--- /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 altosui;
+
+import java.lang.*;
+import java.io.*;
+import altosui.AltosRecord;
+
+public class AltosCSV {
+ File name;
+ PrintStream out;
+ boolean header_written;
+
+ static final int ALTOS_CSV_VERSION = 1;
+
+ /* Version 1 format:
+ *
+ * General info
+ * version number
+ * serial number
+ * flight number
+ * callsign
+ * time (seconds since boost)
+ *
+ * Flight status
+ * state
+ * state name
+ *
+ * Basic sensors
+ * acceleration (m/s²)
+ * pressure (mBar)
+ * altitude (m)
+ * accelerometer speed (m/s)
+ * barometer speed (m/s)
+ * temp (°C)
+ * battery (V)
+ * drogue (V)
+ * main (V)
+ *
+ * GPS data
+ * connected (1/0)
+ * locked (1/0)
+ * nsat (used for solution)
+ * latitude (°)
+ * longitude (°)
+ * altitude (m)
+ * year (e.g. 2010)
+ * month (1-12)
+ * day (1-31)
+ * hour (0-23)
+ * minute (0-59)
+ * second (0-59)
+ *
+ * GPS Sat data
+ * hdop
+ * C/N0 data for all 32 valid SDIDs
+ */
+
+ void write_general_header() {
+ out.printf("version serial flight call time");
+ }
+
+ void write_general(AltosRecord record) {
+ out.printf("%s,%d,%d,%s,%d",
+ record.version, record.serial, record.flight, record.callsign, record.tick);
+ }
+
+ void write_flight_header() {
+ out.printf("state state_name");
+ }
+
+ void write_flight(AltosRecord record) {
+ out.printf("%d,%s", record.state, record.state());
+ }
+
+ void write_header() {
+ out.printf("# "); write_general_header();
+ out.printf(" "); write_flight_header();
+ out.printf ("\n");
+ }
+
+ public void write(AltosRecord record) {
+ if (!header_written) {
+ write_header();
+ header_written = true;
+ }
+ write_general(record); out.printf(",");
+ write_flight(record);
+ out.printf ("\n");
+ }
+
+ public PrintStream out() {
+ return out;
+ }
+
+ public AltosCSV(File in_name) throws FileNotFoundException {
+ name = in_name;
+ out = new PrintStream(name);
+ }
+}
}
}
-public class AltosEepromReader {
+public class AltosEepromReader extends AltosReader {
static final int seen_flight = 1;
static final int seen_sensor = 2;
int gps_tick;
- FileInputStream input;
+ boolean saw_boost;
+
+ int boost_tick;
public AltosRecord read() throws IOException, ParseException {
for (;;) {
}
record = record_iterator.next();
- if ((seen & seen_basic) == seen_basic && record.tick != state.tick)
- return new AltosRecord(state);
+ if ((seen & seen_basic) == seen_basic && record.tick != state.tick) {
+ AltosRecord r = new AltosRecord(state);
+ r.time = (r.tick - boost_tick) / 100.0;
+ return r;
+ }
}
state.tick = record.tick;
}
}
+ public void write_comments(PrintStream out) {
+ Iterator<AltosOrderedRecord> iterator = records.iterator();
+ while (iterator.hasNext()) {
+ AltosOrderedRecord record = iterator.next();
+ switch (record.cmd) {
+ case Altos.AO_LOG_CONFIG_VERSION:
+ out.printf("# Config version: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_MAIN_DEPLOY:
+ out.printf("# Main deploy: %s\n", record.a);
+ break;
+ case Altos.AO_LOG_APOGEE_DELAY:
+ out.printf("# Apogee delay: %s\n", record.a);
+ break;
+ case Altos.AO_LOG_RADIO_CHANNEL:
+ out.printf("# Radio channel: %s\n", record.a);
+ break;
+ case Altos.AO_LOG_CALLSIGN:
+ out.printf("# Callsign: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_ACCEL_CAL:
+ out.printf ("# Accel cal: %d %d\n", record.a, record.b);
+ break;
+ case Altos.AO_LOG_RADIO_CAL:
+ out.printf ("# Radio cal: %d %d\n", record.a);
+ break;
+ case Altos.AO_LOG_MANUFACTURER:
+ out.printf ("# Manufacturer: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_PRODUCT:
+ out.printf ("# Product: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_SERIAL_NUMBER:
+ out.printf ("# Serial number: %d\n", record.a);
+ break;
+ case Altos.AO_LOG_SOFTWARE_VERSION:
+ out.printf ("# Software version: %s\n", record.data);
+ break;
+ }
+ }
+ }
+
/*
* Read the whole file, dumping records into a RB tree so
* we can enumerate them in time order -- the eeprom data
* matching the first packet out of the GPS unit but not
* written until the final GPS packet has been received.
*/
- public AltosEepromReader (FileInputStream in_input) {
+ public AltosEepromReader (FileInputStream input) {
state = new AltosRecord();
state.state = Altos.ao_flight_pad;
state.accel_plus_g = 15758;
state.accel_minus_g = 16294;
- input = in_input;
seen = 0;
records = new TreeSet<AltosOrderedRecord>();
if (record == null)
break;
tick = record.tick;
+ if (!saw_boost && record.cmd == Altos.AO_LOG_STATE &&
+ record.a == Altos.ao_flight_boost)
+ {
+ saw_boost = true;
+ boost_tick = state.tick;
+ }
records.add(record);
}
} catch (IOException io) {
} catch (ParseException pe) {
}
record_iterator = records.iterator();
+ try {
+ input.close();
+ } catch (IOException ie) {
+ }
}
}
--- /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 altosui;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+import altosui.AltosRecord;
+
+public class AltosReader {
+ public AltosRecord read() throws IOException, ParseException { return null; }
+}
int accel_minus_g;
AltosGPS gps;
+ double time; /* seconds since boost */
+
/*
* Values for our MP3H6115A pressure sensor
*
--- /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 altosui;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import altosui.AltosTelemetry;
+
+public class AltosTelemetryReader extends AltosReader {
+ LinkedList<AltosRecord> records;
+
+ Iterator<AltosRecord> record_iterator;
+
+ int boost_tick;
+
+ public AltosRecord read() throws IOException, ParseException {
+ AltosRecord r;
+ if (!record_iterator.hasNext())
+ return null;
+
+ r = record_iterator.next();
+ r.time = (r.tick - boost_tick) / 100.0;
+ return r;
+ }
+
+ public AltosTelemetryReader (FileInputStream input) {
+ boolean saw_boost = false;
+
+ records = new LinkedList<AltosRecord> ();
+
+ try {
+ for (;;) {
+ String line = AltosRecord.gets(input);
+ if (line == null)
+ break;
+ AltosTelemetry record = new AltosTelemetry(line);
+ if (record == null)
+ break;
+ if (!saw_boost && record.state >= Altos.ao_flight_boost)
+ {
+ saw_boost = true;
+ boost_tick = record.tick;
+ }
+ records.add(record);
+ }
+ } catch (IOException io) {
+ } catch (ParseException pe) {
+ }
+ record_iterator = records.iterator();
+ try {
+ input.close();
+ } catch (IOException ie) {
+ }
+ }
+}
}
}
- class TelemetryThread extends DisplayThread {
-
- String readline() throws InterruptedException { return null; }
-
- AltosRecord read() throws InterruptedException, ParseException {
- return new AltosTelemetry(readline());
- }
- }
-
- class DeviceThread extends TelemetryThread {
+ class DeviceThread extends DisplayThread {
AltosSerial serial;
LinkedBlockingQueue<String> telem;
- String readline() throws InterruptedException {
- return telem.take();
+ AltosRecord read() throws InterruptedException, ParseException {
+ return new AltosTelemetry(telem.take());
}
void close() {
* Open an existing telemetry file and replay it in realtime
*/
- class ReplayTelemetryThread extends TelemetryThread {
- FileInputStream replay;
-
- ReplayTelemetryThread(FileInputStream in, String in_name) {
- replay = in;
- name = in_name;
- }
+ class ReplayThread extends DisplayThread {
+ AltosReader reader;
+ String name;
- String readline() {
+ public AltosRecord read() {
try {
- String line = AltosRecord.gets(replay);
- System.out.printf("telemetry line %s\n", line);
- return line;
- } catch (IOException ee) {
+ return reader.read();
+ } catch (IOException ie) {
JOptionPane.showMessageDialog(AltosUI.this,
name,
"error reading",
JOptionPane.ERROR_MESSAGE);
+ } catch (ParseException pe) {
}
return null;
}
- void close () {
- try {
- replay.close();
- } catch (IOException ee) {
- }
+ public void close () {
report();
}
+ public ReplayThread(AltosReader in_reader, String in_name) {
+ reader = in_reader;
+ }
void update(AltosState state) throws InterruptedException {
/* Make it run in realtime after the rocket leaves the pad */
if (state.state > Altos.ao_flight_pad)
}
}
- class ReplayEepromThread extends DisplayThread {
- FileInputStream replay;
-
- AltosEepromReader reader;
-
- ReplayEepromThread(FileInputStream in, String in_name) {
- replay = in;
- name = in_name;
- reader = new AltosEepromReader (in);
+ class ReplayTelemetryThread extends ReplayThread {
+ ReplayTelemetryThread(FileInputStream in, String in_name) {
+ super(new AltosTelemetryReader(in), in_name);
}
- AltosRecord read () throws ParseException {
- try {
- return reader.read();
- } catch (IOException ee) {
- JOptionPane.showMessageDialog(AltosUI.this,
- name,
- "error reading",
- JOptionPane.ERROR_MESSAGE);
- }
- return null;
- }
+ }
- void close () {
- try {
- replay.close();
- } catch (IOException ee) {
- }
- report();
- }
- void update(AltosState state) throws InterruptedException {
- /* Make it run in realtime after the rocket leaves the pad */
- if (state.state > Altos.ao_flight_pad)
- Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
+ class ReplayEepromThread extends ReplayThread {
+ ReplayEepromThread(FileInputStream in, String in_name) {
+ super(new AltosEepromReader(in), in_name);
}
}
CLASSFILES=\
Altos.class \
AltosConvert.class \
+ AltosCSV.class \
AltosEepromDownload.class \
AltosEepromMonitor.class \
AltosEepromReader.class \
AltosSerial.class \
AltosState.class \
AltosTelemetry.class \
+ AltosTelemetryReader.class \
AltosUI.class \
AltosDevice.class \
AltosDeviceDialog.class \