/* * Copyright © 2010 Keith Packard * * 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)); } }