Initial Commit - Copy from Altus Metrum AltOS
This commit is contained in:
578
altoslib/AltosCSV.java
Normal file
578
altoslib/AltosCSV.java
Normal file
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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_14;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class AltosCSV implements AltosWriter {
|
||||
File name;
|
||||
PrintStream out;
|
||||
boolean header_written;
|
||||
boolean seen_boost;
|
||||
int boost_tick;
|
||||
|
||||
boolean has_call;
|
||||
boolean has_basic;
|
||||
boolean has_accel;
|
||||
boolean has_baro;
|
||||
boolean has_pyro;
|
||||
boolean has_radio;
|
||||
boolean has_battery;
|
||||
boolean has_flight_state;
|
||||
boolean has_3d_accel;
|
||||
boolean has_imu;
|
||||
boolean has_igniter;
|
||||
boolean has_gps;
|
||||
boolean has_gps_sat;
|
||||
boolean has_companion;
|
||||
boolean has_motor_pressure;
|
||||
|
||||
AltosFlightSeries series;
|
||||
int[] indices;
|
||||
|
||||
static final int ALTOS_CSV_VERSION = 6;
|
||||
|
||||
/* Version 4 format:
|
||||
*
|
||||
* General info
|
||||
* version number
|
||||
* serial number
|
||||
* flight number
|
||||
* callsign
|
||||
* time (seconds since boost)
|
||||
*
|
||||
* Radio info (if available)
|
||||
* rssi
|
||||
* link quality
|
||||
*
|
||||
* Flight status
|
||||
* state
|
||||
* state name
|
||||
*
|
||||
* Basic sensors
|
||||
* acceleration (m/s²)
|
||||
* pressure (mBar)
|
||||
* altitude (m)
|
||||
* height (m)
|
||||
* accelerometer speed (m/s)
|
||||
* barometer speed (m/s)
|
||||
* temp (°C)
|
||||
* drogue (V)
|
||||
* main (V)
|
||||
*
|
||||
* Battery
|
||||
* battery (V)
|
||||
*
|
||||
* Advanced sensors (if available)
|
||||
* accel_x (m/s²)
|
||||
* accel_y (m/s²)
|
||||
* accel_z (m/s²)
|
||||
* gyro_x (d/s)
|
||||
* gyro_y (d/s)
|
||||
* gyro_z (d/s)
|
||||
* mag_x (g)
|
||||
* mag_y (g)
|
||||
* mag_z (g)
|
||||
* tilt (d)
|
||||
*
|
||||
* Extra igniter voltages (if available)
|
||||
* pyro (V)
|
||||
* igniter_a (V)
|
||||
* igniter_b (V)
|
||||
* igniter_c (V)
|
||||
* igniter_d (V)
|
||||
*
|
||||
* GPS data (if available)
|
||||
* 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)
|
||||
* from_pad_dist (m)
|
||||
* from_pad_azimuth (deg true)
|
||||
* from_pad_range (m)
|
||||
* from_pad_elevation (deg from horizon)
|
||||
* pdop
|
||||
* hdop
|
||||
* vdop
|
||||
*
|
||||
* GPS Sat data
|
||||
* C/N0 data for all 32 valid SDIDs
|
||||
*
|
||||
* Companion data
|
||||
* companion_id (1-255. 10 is TeleScience)
|
||||
* time of last companion data (seconds since boost)
|
||||
* update_period (0.1-2.55 minimum telemetry interval)
|
||||
* channels (0-12)
|
||||
* channel data for all 12 possible channels
|
||||
*/
|
||||
|
||||
void write_general_header() {
|
||||
out.printf(Locale.ROOT,"version,serial,flight");
|
||||
if (series.cal_data().callsign != null)
|
||||
out.printf(Locale.ROOT,",call");
|
||||
out.printf(Locale.ROOT,",time");
|
||||
}
|
||||
|
||||
double time() {
|
||||
return series.time(indices);
|
||||
}
|
||||
|
||||
void write_general() {
|
||||
out.printf(Locale.ROOT,"%s, %d, %d",
|
||||
ALTOS_CSV_VERSION,
|
||||
series.cal_data().serial,
|
||||
series.cal_data().flight);
|
||||
if (series.cal_data().callsign != null)
|
||||
out.printf(Locale.ROOT,",%s", series.cal_data().callsign);
|
||||
out.printf(Locale.ROOT,", %8.2f", time());
|
||||
}
|
||||
|
||||
void write_radio_header() {
|
||||
out.printf(Locale.ROOT,"rssi,lqi");
|
||||
}
|
||||
|
||||
int rssi() {
|
||||
return (int) series.value(AltosFlightSeries.rssi_name, indices);
|
||||
}
|
||||
|
||||
int status() {
|
||||
return (int) series.value(AltosFlightSeries.status_name, indices);
|
||||
}
|
||||
|
||||
void write_radio() {
|
||||
out.printf(Locale.ROOT,"%4d, %3d",
|
||||
rssi(), status() & 0x7f);
|
||||
}
|
||||
|
||||
void write_flight_header() {
|
||||
out.printf(Locale.ROOT,"state,state_name");
|
||||
}
|
||||
|
||||
int state() {
|
||||
return (int) series.value(AltosFlightSeries.state_name, indices);
|
||||
}
|
||||
|
||||
void write_flight() {
|
||||
int state = state();
|
||||
out.printf(Locale.ROOT,"%2d,%8s", state, AltosLib.state_name(state));
|
||||
}
|
||||
|
||||
void write_basic_header() {
|
||||
if (has_accel)
|
||||
out.printf(Locale.ROOT,"acceleration,");
|
||||
if (has_baro)
|
||||
out.printf(Locale.ROOT,"pressure,altitude,");
|
||||
out.printf(Locale.ROOT,"height,speed");
|
||||
if (has_baro)
|
||||
out.printf(Locale.ROOT,",temperature");
|
||||
if (has_pyro)
|
||||
out.printf(Locale.ROOT,",drogue_voltage,main_voltage");
|
||||
}
|
||||
|
||||
double acceleration() { return series.value(AltosFlightSeries.accel_name, indices); }
|
||||
double pressure() { return series.value(AltosFlightSeries.pressure_name, indices); }
|
||||
double altitude() { return series.value(AltosFlightSeries.altitude_name, indices); }
|
||||
double height() { return series.value(AltosFlightSeries.height_name, indices); }
|
||||
double speed() { return series.value(AltosFlightSeries.speed_name, indices); }
|
||||
double temperature() { return series.value(AltosFlightSeries.temperature_name, indices); }
|
||||
double apogee_voltage() { return series.value(AltosFlightSeries.apogee_voltage_name, indices); }
|
||||
double main_voltage() { return series.value(AltosFlightSeries.main_voltage_name, indices); }
|
||||
|
||||
void write_basic() {
|
||||
if (has_accel)
|
||||
out.printf(Locale.ROOT,"%8.2f,", acceleration());
|
||||
if (has_baro)
|
||||
out.printf(Locale.ROOT,"%10.2f,%8.2f,",
|
||||
pressure(), altitude());
|
||||
out.printf(Locale.ROOT,"%8.2f,%8.2f",
|
||||
height(), speed());
|
||||
if (has_baro)
|
||||
out.printf(Locale.ROOT,",%5.1f", temperature());
|
||||
if (has_pyro)
|
||||
out.printf(Locale.ROOT,",%5.2f,%5.2f",
|
||||
apogee_voltage(),
|
||||
main_voltage());
|
||||
}
|
||||
|
||||
void write_battery_header() {
|
||||
out.printf(Locale.ROOT,"battery_voltage");
|
||||
}
|
||||
|
||||
double battery_voltage() { return series.value(AltosFlightSeries.battery_voltage_name, indices); }
|
||||
|
||||
void write_battery() {
|
||||
out.printf(Locale.ROOT,"%5.2f", battery_voltage());
|
||||
}
|
||||
|
||||
void write_motor_pressure_header() {
|
||||
out.printf(Locale.ROOT,"motor_pressure");
|
||||
}
|
||||
|
||||
double motor_pressure() { return series.value(AltosFlightSeries.motor_pressure_name, indices); }
|
||||
|
||||
void write_motor_pressure() {
|
||||
out.printf(Locale.ROOT,"%10.1f", motor_pressure());
|
||||
}
|
||||
|
||||
void write_3d_accel_header() {
|
||||
out.printf(Locale.ROOT,"accel_x,accel_y,accel_z");
|
||||
}
|
||||
|
||||
double accel_along() { return series.value(AltosFlightSeries.accel_along_name, indices); }
|
||||
double accel_across() { return series.value(AltosFlightSeries.accel_across_name, indices); }
|
||||
double accel_through() { return series.value(AltosFlightSeries.accel_through_name, indices); }
|
||||
|
||||
void write_3d_accel() {
|
||||
out.printf(Locale.ROOT,"%7.2f,%7.2f,%7.2f",
|
||||
accel_along(), accel_across(), accel_through());
|
||||
}
|
||||
|
||||
void write_imu_header() {
|
||||
out.printf(Locale.ROOT,"gyro_roll,gyro_pitch,gyro_yaw,mag_x,mag_y,mag_z,tilt");
|
||||
}
|
||||
|
||||
double gyro_roll() { return series.value(AltosFlightSeries.gyro_roll_name, indices); }
|
||||
double gyro_pitch() { return series.value(AltosFlightSeries.gyro_pitch_name, indices); }
|
||||
double gyro_yaw() { return series.value(AltosFlightSeries.gyro_yaw_name, indices); }
|
||||
|
||||
double mag_along() { return series.value(AltosFlightSeries.mag_along_name, indices); }
|
||||
double mag_across() { return series.value(AltosFlightSeries.mag_across_name, indices); }
|
||||
double mag_through() { return series.value(AltosFlightSeries.mag_through_name, indices); }
|
||||
|
||||
double tilt() { return series.value(AltosFlightSeries.orient_name, indices); }
|
||||
|
||||
void write_imu() {
|
||||
out.printf(Locale.ROOT,"%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f,%7.2f",
|
||||
gyro_roll(), gyro_pitch(), gyro_yaw(),
|
||||
mag_along(), mag_across(), mag_through(),
|
||||
tilt());
|
||||
}
|
||||
|
||||
void write_igniter_header() {
|
||||
out.printf(Locale.ROOT,"pyro");
|
||||
for (int i = 0; i < series.igniter_voltage.length; i++)
|
||||
out.printf(Locale.ROOT,",%s", AltosLib.igniter_short_name(i));
|
||||
}
|
||||
|
||||
double pyro() { return series.value(AltosFlightSeries.pyro_voltage_name, indices); }
|
||||
|
||||
double igniter_value(int channel) { return series.value(series.igniter_voltage_name(channel), indices); }
|
||||
|
||||
void write_igniter() {
|
||||
out.printf(Locale.ROOT,"%5.2f", pyro());
|
||||
for (int i = 0; i < series.igniter_voltage.length; i++)
|
||||
out.printf(Locale.ROOT,",%5.2f", igniter_value(i));
|
||||
}
|
||||
|
||||
void write_gps_header() {
|
||||
out.printf(Locale.ROOT,"connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,pdop,hdop,vdop");
|
||||
}
|
||||
|
||||
void write_gps() {
|
||||
AltosGPS gps = series.gps_before(series.time(indices));
|
||||
|
||||
AltosGreatCircle from_pad;
|
||||
|
||||
if (series.cal_data().gps_pad != null && gps != null)
|
||||
from_pad = new AltosGreatCircle(series.cal_data().gps_pad, gps);
|
||||
else
|
||||
from_pad = new AltosGreatCircle();
|
||||
|
||||
if (gps == null)
|
||||
gps = new AltosGPS();
|
||||
|
||||
out.printf(Locale.ROOT,"%2d,%2d,%3d,%12.7f,%12.7f,%8.1f,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f,%6.1f,%6.1f",
|
||||
gps.connected?1:0,
|
||||
gps.locked?1:0,
|
||||
gps.nsat,
|
||||
gps.lat,
|
||||
gps.lon,
|
||||
gps.alt,
|
||||
gps.year,
|
||||
gps.month,
|
||||
gps.day,
|
||||
gps.hour,
|
||||
gps.minute,
|
||||
gps.second,
|
||||
from_pad.distance,
|
||||
from_pad.range,
|
||||
from_pad.bearing,
|
||||
from_pad.elevation,
|
||||
gps.pdop,
|
||||
gps.hdop,
|
||||
gps.vdop);
|
||||
}
|
||||
|
||||
void write_gps_sat_header() {
|
||||
for(int i = 1; i <= 32; i++) {
|
||||
out.printf(Locale.ROOT,"sat%02d", i);
|
||||
if (i != 32)
|
||||
out.printf(Locale.ROOT,",");
|
||||
}
|
||||
}
|
||||
|
||||
void write_gps_sat() {
|
||||
AltosGPS gps = series.gps_before(series.time(indices));
|
||||
for(int i = 1; i <= 32; i++) {
|
||||
int c_n0 = 0;
|
||||
if (gps != null && gps.cc_gps_sat != null) {
|
||||
for(int j = 0; j < gps.cc_gps_sat.length; j++)
|
||||
if (gps.cc_gps_sat[j].svid == i) {
|
||||
c_n0 = gps.cc_gps_sat[j].c_n0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.printf ("%3d", c_n0);
|
||||
if (i != 32)
|
||||
out.printf(Locale.ROOT,",");
|
||||
}
|
||||
}
|
||||
|
||||
void write_companion_header() {
|
||||
/*
|
||||
out.printf(Locale.ROOT,"companion_id,companion_time,companion_update,companion_channels");
|
||||
for (int i = 0; i < 12; i++)
|
||||
out.printf(Locale.ROOT,",companion_%02d", i);
|
||||
*/
|
||||
}
|
||||
|
||||
void write_companion() {
|
||||
/*
|
||||
AltosCompanion companion = state.companion;
|
||||
|
||||
int channels_written = 0;
|
||||
if (companion == null) {
|
||||
out.printf(Locale.ROOT,"0,0,0,0");
|
||||
} else {
|
||||
out.printf(Locale.ROOT,"%3d,%5.2f,%5.2f,%2d",
|
||||
companion.board_id,
|
||||
(companion.tick - boost_tick) / 100.0,
|
||||
companion.update_period / 100.0,
|
||||
companion.channels);
|
||||
for (; channels_written < companion.channels; channels_written++)
|
||||
out.printf(Locale.ROOT,",%5d", companion.companion_data[channels_written]);
|
||||
}
|
||||
for (; channels_written < 12; channels_written++)
|
||||
out.printf(Locale.ROOT,",0");
|
||||
*/
|
||||
}
|
||||
|
||||
void write_header() {
|
||||
out.printf(Locale.ROOT,"#"); write_general_header();
|
||||
if (has_radio) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_radio_header();
|
||||
}
|
||||
if (has_flight_state) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_flight_header();
|
||||
}
|
||||
if (has_basic) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_basic_header();
|
||||
}
|
||||
if (has_battery) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_battery_header();
|
||||
}
|
||||
if (has_motor_pressure) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_motor_pressure_header();
|
||||
}
|
||||
if (has_3d_accel) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_3d_accel_header();
|
||||
}
|
||||
if (has_imu) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_imu_header();
|
||||
}
|
||||
if (has_igniter) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_igniter_header();
|
||||
}
|
||||
if (has_gps) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_gps_header();
|
||||
}
|
||||
if (has_gps_sat) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_gps_sat_header();
|
||||
}
|
||||
if (has_companion) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_companion_header();
|
||||
}
|
||||
out.printf ("\n");
|
||||
}
|
||||
|
||||
void write_one() {
|
||||
write_general();
|
||||
if (has_radio) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_radio();
|
||||
}
|
||||
if (has_flight_state) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_flight();
|
||||
}
|
||||
if (has_basic) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_basic();
|
||||
}
|
||||
if (has_battery) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_battery();
|
||||
}
|
||||
if (has_motor_pressure) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_motor_pressure();
|
||||
}
|
||||
if (has_3d_accel) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_3d_accel();
|
||||
}
|
||||
if (has_imu) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_imu();
|
||||
}
|
||||
if (has_igniter) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_igniter();
|
||||
}
|
||||
if (has_gps) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_gps();
|
||||
}
|
||||
if (has_gps_sat) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_gps_sat();
|
||||
}
|
||||
if (has_companion) {
|
||||
out.printf(Locale.ROOT,",");
|
||||
write_companion();
|
||||
}
|
||||
out.printf ("\n");
|
||||
}
|
||||
|
||||
private void write() {
|
||||
if (state() == AltosLib.ao_flight_startup)
|
||||
return;
|
||||
if (!header_written) {
|
||||
write_header();
|
||||
header_written = true;
|
||||
}
|
||||
write_one();
|
||||
}
|
||||
|
||||
private PrintStream out() {
|
||||
return out;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void write(AltosFlightSeries series) {
|
||||
// series.write_comments(out());
|
||||
|
||||
this.series = series;
|
||||
|
||||
series.finish();
|
||||
|
||||
has_radio = false;
|
||||
has_flight_state = false;
|
||||
has_basic = false;
|
||||
has_accel = false;
|
||||
has_baro = false;
|
||||
has_pyro = false;
|
||||
has_battery = false;
|
||||
has_motor_pressure = false;
|
||||
has_3d_accel = false;
|
||||
has_imu = false;
|
||||
has_igniter = false;
|
||||
has_gps = false;
|
||||
has_gps_sat = false;
|
||||
has_companion = false;
|
||||
|
||||
if (series.has_series(AltosFlightSeries.rssi_name))
|
||||
has_radio = true;
|
||||
if (series.has_series(AltosFlightSeries.state_name))
|
||||
has_flight_state = true;
|
||||
if (series.has_series(AltosFlightSeries.accel_name)) {
|
||||
has_basic = true;
|
||||
has_accel = true;
|
||||
}
|
||||
if (series.has_series(AltosFlightSeries.pressure_name)) {
|
||||
has_basic = true;
|
||||
has_baro = true;
|
||||
}
|
||||
if (series.has_series(AltosFlightSeries.apogee_voltage_name))
|
||||
has_pyro = true;
|
||||
if (series.has_series(AltosFlightSeries.battery_voltage_name))
|
||||
has_battery = true;
|
||||
if (series.has_series(AltosFlightSeries.motor_pressure_name))
|
||||
has_motor_pressure = true;
|
||||
if (series.has_series(AltosFlightSeries.accel_across_name))
|
||||
has_3d_accel = true;
|
||||
if (series.has_series(AltosFlightSeries.gyro_roll_name))
|
||||
has_imu = true;
|
||||
if (series.has_series(AltosFlightSeries.pyro_voltage_name))
|
||||
has_igniter = true;
|
||||
|
||||
if (series.gps_series != null)
|
||||
has_gps = true;
|
||||
if (series.sats_in_view != null)
|
||||
has_gps_sat = true;
|
||||
/*
|
||||
if (state.companion != null)
|
||||
has_companion = true;
|
||||
*/
|
||||
|
||||
indices = series.indices();
|
||||
|
||||
for (;;) {
|
||||
write();
|
||||
if (!series.step_indices(indices))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public AltosCSV(PrintStream in_out, File in_name) {
|
||||
name = in_name;
|
||||
out = in_out;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user