void reset() {
value.setText("");
}
+
+ void show() {
+ label.show();
+ value.show();
+ }
+
+ void hide() {
+ label.hide();
+ value.hide();
+ }
public AscentValue (GridBagLayout layout, int y, String text) {
GridBagConstraints c = new GridBagConstraints();
c.weighty = 1;
class Lat extends AscentValue {
void show (AltosState state, int crc_errors) {
+ show();
if (state.gps != null)
value.setText(pos(state.gps.lat,"N", "S"));
else
class Lon extends AscentValue {
void show (AltosState state, int crc_errors) {
+ show();
if (state.gps != null)
value.setText(pos(state.gps.lon,"E", "W"));
else
}
public void show(AltosState state, int crc_errors) {
- lat.show(state, crc_errors);
- lon.show(state, crc_errors);
+ if (state.gps != null) {
+ lat.show(state, crc_errors);
+ lon.show(state, crc_errors);
+ } else {
+ lat.hide();
+ lon.hide();
+ }
height.show(state, crc_errors);
main.show(state, crc_errors);
apogee.show(state, crc_errors);
* drogue (V)
* main (V)
*
- * GPS data
+ * GPS data (if available)
* connected (1/0)
* locked (1/0)
* nsat (used for solution)
}
}
- void write_header() {
+ void write_header(boolean gps) {
out.printf("#"); write_general_header();
out.printf(","); write_flight_header();
out.printf(","); write_basic_header();
- out.printf(","); write_gps_header();
- out.printf(","); write_gps_sat_header();
+ if (gps) {
+ out.printf(","); write_gps_header();
+ out.printf(","); write_gps_sat_header();
+ }
out.printf ("\n");
}
state = new AltosState(record, state);
write_general(record); out.printf(",");
write_flight(record); out.printf(",");
- write_basic(record); out.printf(",");
- write_gps(record); out.printf(",");
- write_gps_sat(record);
+ write_basic(record);
+ if (record.gps != null) {
+ out.printf(",");
+ write_gps(record); out.printf(",");
+ write_gps_sat(record);
+ }
out.printf ("\n");
}
public void write(AltosRecord record) {
if (!header_written) {
- write_header();
+ write_header(record.gps != null);
header_written = true;
}
if (!seen_boost) {
write(r);
}
- public AltosCSV(File in_name) throws FileNotFoundException {
+ public AltosCSV(PrintStream in_out, File in_name) {
name = in_name;
- out = new PrintStream(name);
+ out = in_out;
pad_records = new LinkedList<AltosRecord>();
}
+ public AltosCSV(File in_name) throws FileNotFoundException {
+ this(new PrintStream(in_name), in_name);
+ }
+
public AltosCSV(String in_string) throws FileNotFoundException {
this(new File(in_string));
}
AltosState state;
AltosRecord record;
+ final static int MISSING = AltosRecord.MISSING;
+
public AltosDataPointReader(Iterable<AltosRecord> reader) {
this.iter = reader.iterator();
this.state = null;
AltosLights lights;
abstract void show(AltosState state, int crc_errors);
+
+ void show() {
+ label.show();
+ value.show();
+ lights.show();
+ }
+
+ void hide() {
+ label.hide();
+ value.hide();
+ lights.hide();
+ }
+
void reset() {
value.setText("");
lights.set(false);
abstract void show(AltosState state, int crc_errors);
+ void show() {
+ label.show();
+ value.show();
+ }
+
+ void hide() {
+ label.hide();
+ value.hide();
+ }
+
void show(String format, double v) {
value.setText(String.format(format, v));
}
value2.setText("");
}
+ void show() {
+ label.show();
+ value1.show();
+ value2.show();
+ }
+
+ void hide() {
+ label.hide();
+ value1.hide();
+ value2.hide();
+ }
+
abstract void show(AltosState state, int crc_errors);
+
void show(String v1, String v2) {
+ show();
value1.setText(v1);
value2.setText(v2);
}
void show(String f1, double v1, String f2, double v2) {
+ show();
value1.setText(String.format(f1, v1));
value2.setText(String.format(f2, v2));
}
class Main extends DescentStatus {
void show (AltosState state, int crc_errors) {
+ show();
value.setText(String.format("%4.2f V", state.main_sense));
lights.set(state.main_sense > 3.2);
}
public void show(AltosState state, int crc_errors) {
height.show(state, crc_errors);
speed.show(state, crc_errors);
- bearing.show(state, crc_errors);
- range.show(state, crc_errors);
- elevation.show(state, crc_errors);
- lat.show(state, crc_errors);
- lon.show(state, crc_errors);
+ if (state.gps != null) {
+ bearing.show(state, crc_errors);
+ range.show(state, crc_errors);
+ elevation.show(state, crc_errors);
+ lat.show(state, crc_errors);
+ lon.show(state, crc_errors);
+ } else {
+ bearing.hide();
+ range.hide();
+ elevation.hide();
+ lat.hide();
+ lon.hide();
+ }
main.show(state, crc_errors);
apogee.show(state, crc_errors);
}
import java.util.concurrent.LinkedBlockingQueue;
public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
- String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
- Object[][] statusData = { { "0", "pad", "-50", "0" } };
-
AltosVoice voice;
AltosFlightReader reader;
AltosDisplayThread thread;
AltosDescent descent;
AltosLanded landed;
AltosSiteMap sitemap;
+ boolean has_map;
private AltosFlightStatus flightStatus;
private AltosInfoTable flightInfo;
public void show(AltosState state, int crc_errors) {
JComponent tab = which_tab(state);
+ try {
pad.show(state, crc_errors);
ascent.show(state, crc_errors);
descent.show(state, crc_errors);
}
flightStatus.show(state, crc_errors);
flightInfo.show(state, crc_errors);
- sitemap.show(state, crc_errors);
+ if (state.gps != null) {
+ if (!has_map) {
+ pane.add("Site Map", sitemap);
+ has_map = true;
+ }
+ sitemap.show(state, crc_errors);
+ } else {
+ if (has_map) {
+ pane.remove(sitemap);
+ has_map = false;
+ }
+ }
+ } catch (Exception e) {
+ System.out.print("Show exception" + e);
+ }
}
public void set_exit_on_close() {
pane.add("Table", new JScrollPane(flightInfo));
sitemap = new AltosSiteMap();
- pane.add("Site Map", sitemap);
+ has_map = false;
/* Make the tabbed pane use the rest of the window space */
c.gridx = 0;
int c_n0;
}
+ final static int MISSING = AltosRecord.MISSING;
+
int nsat;
boolean locked;
boolean connected;
- boolean date_valid;
double lat; /* degrees (+N -S) */
double lon; /* degrees (+E -W) */
int alt; /* m */
int minute;
int second;
- int gps_extended; /* has extra data */
double ground_speed; /* m/s */
int course; /* degrees */
double climb_rate; /* m/s */
- double hdop; /* unitless? */
+ double hdop; /* unitless */
+ double vdop; /* unitless */
int h_error; /* m */
int v_error; /* m */
hour = minute = second = 0;
}
+ public AltosGPS(AltosTelemetryMap map) throws ParseException {
+ String state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE,
+ AltosTelemetry.AO_TELEM_GPS_STATE_ERROR);
+
+ nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0);
+ if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) {
+ connected = true;
+ locked = true;
+ lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7);
+ lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7);
+ alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING);
+ year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING);
+ if (year != MISSING)
+ year += 2000;
+ month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING);
+ day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING);
+
+ hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0);
+ minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0);
+ second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0);
+
+ ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED,
+ AltosRecord.MISSING, 1/100.0);
+ course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE,
+ AltosRecord.MISSING);
+ hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0);
+ vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0);
+ h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING);
+ v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING);
+ } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) {
+ connected = true;
+ locked = false;
+ } else {
+ connected = false;
+ locked = false;
+ }
+ }
+
public AltosGPS(String[] words, int i, int version) throws ParseException {
AltosParse.word(words[i++], "GPS");
nsat = AltosParse.parse_int(words[i++]);
nsat = old.nsat;
locked = old.locked;
connected = old.connected;
- date_valid = old.date_valid;
lat = old.lat; /* degrees (+N -S) */
lon = old.lon; /* degrees (+E -W) */
alt = old.alt; /* m */
minute = old.minute;
second = old.second;
- gps_extended = old.gps_extended; /* has extra data */
ground_speed = old.ground_speed; /* m/s */
course = old.course; /* degrees */
climb_rate = old.climb_rate; /* m/s */
value.setText("");
}
+ void show() {
+ label.show();
+ value.show();
+ }
+
+ void hide() {
+ label.hide();
+ value.hide();
+ }
+
void show(String format, double v) {
+ show();
value.setText(String.format(format, v));
}
+
public LandedValue (GridBagLayout layout, int y, String text) {
GridBagConstraints c = new GridBagConstraints();
c.weighty = 1;
class Lat extends LandedValue {
void show (AltosState state, int crc_errors) {
+ show();
if (state.gps != null)
value.setText(pos(state.gps.lat,"N", "S"));
else
class Lon extends LandedValue {
void show (AltosState state, int crc_errors) {
+ show();
if (state.gps != null)
value.setText(pos(state.gps.lon,"E", "W"));
else
class Bearing extends LandedValue {
void show (AltosState state, int crc_errors) {
+ show();
if (state.from_pad != null)
show("%3.0f°", state.from_pad.bearing);
else
class Distance extends LandedValue {
void show (AltosState state, int crc_errors) {
+ show();
if (state.from_pad != null)
show("%6.0f m", state.from_pad.distance);
else
}
public void show(AltosState state, int crc_errors) {
- bearing.show(state, crc_errors);
- distance.show(state, crc_errors);
- lat.show(state, crc_errors);
- lon.show(state, crc_errors);
+ if (state.gps != null) {
+ bearing.show(state, crc_errors);
+ distance.show(state, crc_errors);
+ lat.show(state, crc_errors);
+ lon.show(state, crc_errors);
+ } else {
+ bearing.hide();
+ distance.hide();
+ lat.hide();
+ lon.hide();
+ }
height.show(state, crc_errors);
speed.show(state, crc_errors);
accel.show(state, crc_errors);
lights.set(false);
}
+ public void show() {
+ label.show();
+ value.show();
+ lights.show();
+ }
+
+ public void hide() {
+ label.hide();
+ value.hide();
+ lights.hide();
+ }
+
public LaunchStatus (GridBagLayout layout, int y, String text) {
GridBagConstraints c = new GridBagConstraints();
c.weighty = 1;
JTextField value;
void show(AltosState state, int crc_errors) {}
+ void show() {
+ label.show();
+ value.show();
+ }
+
+ void hide() {
+ label.hide();
+ value.hide();
+ }
+
void reset() {
value.setText("");
}
class GPSLocked extends LaunchStatus {
void show (AltosState state, int crc_errors) {
+ show();
value.setText(String.format("%4d sats", state.gps.nsat));
lights.set(state.gps.locked && state.gps.nsat >= 4);
}
class GPSReady extends LaunchStatus {
void show (AltosState state, int crc_errors) {
+ show();
if (state.gps_ready)
value.setText("Ready");
else
class PadLat extends LaunchValue {
void show (AltosState state, int crc_errors) {
+ show();
value.setText(pos(state.pad_lat,"N", "S"));
}
public PadLat (GridBagLayout layout, int y) {
class PadLon extends LaunchValue {
void show (AltosState state, int crc_errors) {
+ show();
value.setText(pos(state.pad_lon,"E", "W"));
}
public PadLon (GridBagLayout layout, int y) {
battery.show(state, crc_errors);
apogee.show(state, crc_errors);
main.show(state, crc_errors);
- gps_locked.show(state, crc_errors);
- gps_ready.show(state, crc_errors);
- pad_lat.show(state, crc_errors);
- pad_lon.show(state, crc_errors);
pad_alt.show(state, crc_errors);
+ if (state.gps != null) {
+ gps_locked.show(state, crc_errors);
+ gps_ready.show(state, crc_errors);
+ pad_lat.show(state, crc_errors);
+ pad_lon.show(state, crc_errors);
+ } else {
+ gps_locked.hide();
+ gps_ready.hide();
+ pad_lat.hide();
+ pad_lon.hide();
+ }
}
public AltosPad() {
import java.io.*;
public class AltosRecord {
+ final static int MISSING = 0x7fffffff;
+
int version;
String callsign;
int serial;
int status;
int state;
int tick;
+
int accel;
int pres;
int temp;
int batt;
int drogue;
int main;
- int flight_accel;
+
int ground_accel;
- int flight_vel;
- int flight_pres;
int ground_pres;
int accel_plus_g;
int accel_minus_g;
+
+ double acceleration;
+ double speed;
+ double height;
+
+ int flight_accel;
+ int flight_vel;
+ int flight_pres;
+
AltosGPS gps;
double time; /* seconds since boost */
}
public double raw_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;
return barometer_to_pressure(ground_pres);
}
- public double filtered_altitude() {
- return AltosConvert.pressure_to_altitude(filtered_pressure());
- }
-
public double raw_altitude() {
- return AltosConvert.pressure_to_altitude(raw_pressure());
+ double p = raw_pressure();
+ if (p == MISSING)
+ return MISSING;
+ return AltosConvert.pressure_to_altitude(p);
}
public double ground_altitude() {
- return AltosConvert.pressure_to_altitude(ground_pressure());
+ double p = ground_pressure();
+ if (p == MISSING)
+ return MISSING;
+ return AltosConvert.pressure_to_altitude(p);
+ }
+
+ public double filtered_altitude() {
+ if (height != MISSING && ground_pres != MISSING)
+ return height + ground_altitude();
+
+ double p = filtered_pressure();
+ if (p == MISSING)
+ return MISSING;
+ return AltosConvert.pressure_to_altitude(p);
}
public double filtered_height() {
- return filtered_altitude() - ground_altitude();
+ if (height != MISSING)
+ return height;
+
+ double f = filtered_altitude();
+ double g = ground_altitude();
+ if (f == MISSING || g == MISSING)
+ return MISSING;
+ return f - g;
}
public double raw_height() {
- return raw_altitude() - ground_altitude();
+ double r = raw_altitude();
+ double g = ground_altitude();
+
+ if (r == MISSING || g == MISSING)
+ return MISSING;
+ return r - g;
}
public double battery_voltage() {
+ if (batt == MISSING)
+ return MISSING;
return AltosConvert.cc_battery_to_voltage(batt);
}
public double main_voltage() {
+ if (main == MISSING)
+ return MISSING;
return AltosConvert.cc_ignitor_to_voltage(main);
}
public double drogue_voltage() {
+ if (drogue == MISSING)
+ return MISSING;
return AltosConvert.cc_ignitor_to_voltage(drogue);
}
}
public double temperature() {
+ if (temp == MISSING)
+ return MISSING;
return thermometer_to_temperature(temp);
}
return counts_per_g / 9.80665;
}
+
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() {
- double speed = flight_vel / (accel_counts_per_mss() * 100.0);
- return speed;
+ if (speed != MISSING)
+ return speed;
+ if (flight_vel == MISSING)
+ return MISSING;
+ return flight_vel / (accel_counts_per_mss() * 100.0);
}
public String state() {
int last_state = -1;
public void show(final AltosState state, final int crc_errors) {
// if insufficient gps data, nothing to update
- if (state.gps == null)
- return;
if (!state.gps.locked && state.gps.nsat < 4)
return;
data = cur;
ground_altitude = data.ground_altitude();
- height = data.filtered_altitude() - ground_altitude;
+ height = data.filtered_height();
+ System.out.printf("height %g\n", height);
report_time = System.currentTimeMillis();
/* compute barometric speed */
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 (data.speed != AltosRecord.MISSING)
+ baro_speed = data.speed;
+ else {
+ if (time_change > 0)
+ baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0;
+ else
+ baro_speed = prev_state.baro_speed;
+ }
} else {
npad = 0;
ngps = 0;
/*
- * The telemetry data stream is a bit of a mess at present, with no consistent
- * formatting. In particular, the GPS data is formatted for viewing instead of parsing.
- * However, the key feature is that every telemetry line contains all of the information
- * necessary to describe the current rocket state, including the calibration values
+ * Version 4 is a replacement with consistent syntax. Each telemetry line
+ * contains a sequence of space-separated names and values, the values are
+ * either integers or strings. The names are all unique. All values are
+ * optional
+ *
+ * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
+ * r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
+ * a_s 0 a_b 26439 g_s u g_n 0 s_n 0
+ *
+ * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
+ * r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
+ *
+ * General header fields
+ *
+ * Name Value
+ *
+ * VERSION Telemetry version number (4 or more). Must be first.
+ * c Callsign (string, no spaces allowed)
+ * n Flight unit serial number (integer)
+ * f Flight number (integer)
+ * r Packet RSSI value (integer)
+ * s Flight computer state (string, no spaces allowed)
+ * t Flight computer clock (integer in centiseconds)
+ *
+ * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
+ * in 1/2dB increments while this protocol provides only integers. So,
+ * the syntax didn't change just the interpretation of the RSSI
+ * values.
+ *
+ * Version 2 of the telemetry data stream is a bit of a mess, with no
+ * consistent formatting. In particular, the GPS data is formatted for
+ * viewing instead of parsing. However, the key feature is that every
+ * telemetry line contains all of the information necessary to
+ * describe the current rocket state, including the calibration values
* for accelerometer and barometer.
*
* GPS unlocked:
* GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \
* 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \
* SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26
+ *
*/
public class AltosTelemetry extends AltosRecord {
- public AltosTelemetry(String line) throws ParseException, AltosCRCException {
- String[] words = line.split("\\s+");
- int i = 0;
+ /*
+ * General header fields
+ *
+ * Name Value
+ *
+ * VERSION Telemetry version number (4 or more). Must be first.
+ * c Callsign (string, no spaces allowed)
+ * n Flight unit serial number (integer)
+ * f Flight number (integer)
+ * r Packet RSSI value (integer)
+ * s Flight computer state (string, no spaces allowed)
+ * t Flight computer clock (integer in centiseconds)
+ */
- if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
- i += 2;
- AltosParse.word(words[i++], "RSSI");
- rssi = AltosParse.parse_int(words[i++]);
- throw new AltosCRCException(rssi);
- }
- if (words[i].equals("CALL")) {
- version = 0;
- } else {
- AltosParse.word (words[i++], "VERSION");
- version = AltosParse.parse_int(words[i++]);
- }
+ final static String AO_TELEM_VERSION = "VERSION";
+ final static String AO_TELEM_CALL = "c";
+ final static String AO_TELEM_SERIAL = "n";
+ final static String AO_TELEM_FLIGHT = "f";
+ final static String AO_TELEM_RSSI = "r";
+ final static String AO_TELEM_STATE = "s";
+ final static String AO_TELEM_TICK = "t";
+
+ /*
+ * Raw sensor values
+ *
+ * Name Value
+ * r_a Accelerometer reading (integer)
+ * r_b Barometer reading (integer)
+ * r_t Thermometer reading (integer)
+ * r_v Battery reading (integer)
+ * r_d Drogue continuity (integer)
+ * r_m Main continuity (integer)
+ */
+
+ final static String AO_TELEM_RAW_ACCEL = "r_a";
+ final static String AO_TELEM_RAW_BARO = "r_b";
+ final static String AO_TELEM_RAW_THERMO = "r_t";
+ final static String AO_TELEM_RAW_BATT = "r_v";
+ final static String AO_TELEM_RAW_DROGUE = "r_d";
+ final static String AO_TELEM_RAW_MAIN = "r_m";
+
+ /*
+ * Sensor calibration values
+ *
+ * Name Value
+ * c_a Ground accelerometer reading (integer)
+ * c_b Ground barometer reading (integer)
+ * c_p Accelerometer reading for +1g
+ * c_m Accelerometer reading for -1g
+ */
+
+ final static String AO_TELEM_CAL_ACCEL_GROUND = "c_a";
+ final static String AO_TELEM_CAL_BARO_GROUND = "c_b";
+ final static String AO_TELEM_CAL_ACCEL_PLUS = "c_p";
+ final static String AO_TELEM_CAL_ACCEL_MINUS = "c_m";
+
+ /*
+ * Kalman state values
+ *
+ * Name Value
+ * k_h Height above pad (integer, meters)
+ * k_s Vertical speeed (integer, m/s * 16)
+ * k_a Vertical acceleration (integer, m/s² * 16)
+ */
+
+ final static String AO_TELEM_KALMAN_HEIGHT = "k_h";
+ final static String AO_TELEM_KALMAN_SPEED = "k_s";
+ final static String AO_TELEM_KALMAN_ACCEL = "k_a";
+
+ /*
+ * Ad-hoc flight values
+ *
+ * Name Value
+ * a_a Acceleration (integer, sensor units)
+ * a_s Speed (integer, integrated acceleration value)
+ * a_b Barometer reading (integer, sensor units)
+ */
+
+ final static String AO_TELEM_ADHOC_ACCEL = "a_a";
+ final static String AO_TELEM_ADHOC_SPEED = "a_s";
+ final static String AO_TELEM_ADHOC_BARO = "a_b";
+
+ /*
+ * GPS values
+ *
+ * Name Value
+ * g_s GPS state (string):
+ * l locked
+ * u unlocked
+ * e error (missing or broken)
+ * g_n Number of sats used in solution
+ * g_ns Latitude (degrees * 10e7)
+ * g_ew Longitude (degrees * 10e7)
+ * g_a Altitude (integer meters)
+ * g_Y GPS year (integer)
+ * g_M GPS month (integer - 1-12)
+ * g_D GPS day (integer - 1-31)
+ * g_h GPS hour (integer - 0-23)
+ * g_m GPS minute (integer - 0-59)
+ * g_s GPS second (integer - 0-59)
+ * g_v GPS vertical speed (integer, cm/sec)
+ * g_s GPS horizontal speed (integer, cm/sec)
+ * g_c GPS course (integer, 0-359)
+ * g_hd GPS hdop (integer * 10)
+ * g_vd GPS vdop (integer * 10)
+ * g_he GPS h error (integer)
+ * g_ve GPS v error (integer)
+ */
+
+ final static String AO_TELEM_GPS_STATE = "g";
+ final static String AO_TELEM_GPS_STATE_LOCKED = "l";
+ final static String AO_TELEM_GPS_STATE_UNLOCKED = "u";
+ final static String AO_TELEM_GPS_STATE_ERROR = "e";
+ final static String AO_TELEM_GPS_NUM_SAT = "g_n";
+ final static String AO_TELEM_GPS_LATITUDE = "g_ns";
+ final static String AO_TELEM_GPS_LONGITUDE = "g_ew";
+ final static String AO_TELEM_GPS_ALTITUDE = "g_a";
+ final static String AO_TELEM_GPS_YEAR = "g_Y";
+ final static String AO_TELEM_GPS_MONTH = "g_M";
+ final static String AO_TELEM_GPS_DAY = "g_D";
+ final static String AO_TELEM_GPS_HOUR = "g_h";
+ final static String AO_TELEM_GPS_MINUTE = "g_m";
+ final static String AO_TELEM_GPS_SECOND = "g_s";
+ final static String AO_TELEM_GPS_VERTICAL_SPEED = "g_v";
+ final static String AO_TELEM_GPS_HORIZONTAL_SPEED = "g_g";
+ final static String AO_TELEM_GPS_COURSE = "g_c";
+ final static String AO_TELEM_GPS_HDOP = "g_hd";
+ final static String AO_TELEM_GPS_VDOP = "g_vd";
+ final static String AO_TELEM_GPS_HERROR = "g_he";
+ final static String AO_TELEM_GPS_VERROR = "g_ve";
+
+ /*
+ * GPS satellite values
+ *
+ * Name Value
+ * s_n Number of satellites reported (integer)
+ * s_v0 Space vehicle ID (integer) for report 0
+ * s_c0 C/N0 number (integer) for report 0
+ * s_v1 Space vehicle ID (integer) for report 1
+ * s_c1 C/N0 number (integer) for report 1
+ * ...
+ */
+
+ final static String AO_TELEM_SAT_NUM = "s_n";
+ final static String AO_TELEM_SAT_SVID = "s_v";
+ final static String AO_TELEM_SAT_C_N_0 = "s_c";
+
+ private void parse_v4(String[] words, int i) throws ParseException {
+ AltosTelemetryMap map = new AltosTelemetryMap(words, i);
+
+ callsign = map.get_string(AO_TELEM_CALL, "N0CALL");
+ serial = map.get_int(AO_TELEM_SERIAL, MISSING);
+ flight = map.get_int(AO_TELEM_FLIGHT, MISSING);
+ rssi = map.get_int(AO_TELEM_RSSI, MISSING);
+ state = Altos.state(map.get_string(AO_TELEM_STATE, "invalid"));
+ tick = map.get_int(AO_TELEM_TICK, 0);
+
+ /* raw sensor values */
+ accel = map.get_int(AO_TELEM_RAW_ACCEL, MISSING);
+ pres = map.get_int(AO_TELEM_RAW_BARO, MISSING);
+ temp = map.get_int(AO_TELEM_RAW_THERMO, MISSING);
+ batt = map.get_int(AO_TELEM_RAW_BATT, MISSING);
+ drogue = map.get_int(AO_TELEM_RAW_DROGUE, MISSING);
+ main = map.get_int(AO_TELEM_RAW_MAIN, MISSING);
+
+ /* sensor calibration information */
+ ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, MISSING);
+ ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, MISSING);
+ accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, MISSING);
+ accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, MISSING);
+
+ /* flight computer values */
+ acceleration = map.get_int(AO_TELEM_KALMAN_ACCEL, MISSING);
+ if (acceleration != MISSING)
+ acceleration /= 16.0;
+ speed = map.get_int(AO_TELEM_KALMAN_SPEED, MISSING);
+ if (speed != MISSING)
+ speed /= 16.0;
+ height = map.get_int(AO_TELEM_KALMAN_HEIGHT, MISSING);
+
+ flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, MISSING);
+ flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, MISSING);
+ flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, MISSING);
+
+ if (map.has(AO_TELEM_GPS_STATE))
+ gps = new AltosGPS(map);
+ else
+ gps = null;
+ }
+
+ private void parse_legacy(String[] words, int i) throws ParseException {
AltosParse.word (words[i++], "CALL");
callsign = words[i++];
gps = new AltosGPS(words, i, version);
}
+
+ public AltosTelemetry(String line) throws ParseException, AltosCRCException {
+ String[] words = line.split("\\s+");
+ int i = 0;
+
+ if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
+ i += 2;
+ AltosParse.word(words[i++], "RSSI");
+ rssi = AltosParse.parse_int(words[i++]);
+ throw new AltosCRCException(rssi);
+ }
+ if (words[i].equals("CALL")) {
+ version = 0;
+ } else {
+ AltosParse.word (words[i++], "VERSION");
+ version = AltosParse.parse_int(words[i++]);
+ }
+
+ if (version < 4)
+ parse_legacy(words, i);
+ else
+ parse_v4(words, i);
+ }
}
} catch (ParseException pe) {
System.out.printf("parse exception %s\n", pe.getMessage());
} catch (AltosCRCException ce) {
- System.out.printf("crc error\n");
}
}
} catch (IOException io) {
if (input.equals(output)) {
System.out.printf("Not processing '%s'\n", input);
} else {
- AltosWriter writer = open_csv(output);
+ AltosWriter writer = open_csv("/dev/stdout");
if (writer != null) {
writer.write(iterable);
writer.close();
AltosRecord.java \
AltosRecordIterable.java \
AltosTelemetryReader.java \
+ AltosTelemetryMap.java \
AltosReplayReader.java \
AltosRomconfig.java \
AltosRomconfigUI.java \
* GPS values
*
* Name Value
- * g_s GPS state (string):
+ * g GPS state (string):
* l locked
* u unlocked
* e error (missing or broken)
* g_m GPS minute (integer - 0-59)
* g_s GPS second (integer - 0-59)
* g_v GPS vertical speed (integer, cm/sec)
- * g_s GPS horizontal speed (integer, cm/sec)
+ * g_g GPS horizontal speed (integer, cm/sec)
* g_c GPS course (integer, 0-359)
* g_hd GPS hdop (integer * 10)
* g_vd GPS vdop (integer * 10)
* g_ve GPS v error (integer)
*/
-#define AO_TELEM_GPS_STATE "g_s"
+#define AO_TELEM_GPS_STATE "g"
#define AO_TELEM_GPS_STATE_LOCKED 'l'
#define AO_TELEM_GPS_STATE_UNLOCKED 'u'
#define AO_TELEM_GPS_STATE_ERROR 'e'
#define AO_TELEM_GPS_MINUTE "g_m"
#define AO_TELEM_GPS_SECOND "g_s"
#define AO_TELEM_GPS_VERTICAL_SPEED "g_v"
-#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_s"
+#define AO_TELEM_GPS_HORIZONTAL_SPEED "g_g"
#define AO_TELEM_GPS_COURSE "g_c"
#define AO_TELEM_GPS_HDOP "g_hd"
#define AO_TELEM_GPS_VDOP "g_vd"