#define AO_GPS_VALID (1 << 4)
#define AO_GPS_RUNNING (1 << 5)
#define AO_GPS_DATE_VALID (1 << 6)
+#define AO_GPS_COURSE_VALID (1 << 7)
extern __xdata uint16_t ao_gps_tick;
* ao_telemetry.c
*/
-#define AO_MAX_CALLSIGN 8
-#define AO_TELEMETRY_VERSION 3
+#define AO_MAX_CALLSIGN 8
struct ao_telemetry {
uint16_t serial;
void
ao_monitor(void);
+#define AO_MONITORING_OFF 0
+#define AO_MONITORING_FULL 1
+#define AO_MONITORING_TINY 2
+
void
ao_set_monitor(uint8_t monitoring);
#ifndef AO_GPS_TEST
#include "ao.h"
#endif
-
-struct ao_gps_split {
- uint8_t positive;
- uint8_t degrees;
- uint8_t minutes;
- uint16_t minutes_fraction;
-};
-
-static void
-ao_gps_split(int32_t v, __xdata struct ao_gps_split *split) __reentrant
-{
- uint32_t minutes_e7;
-
- split->positive = 1;
- if (v < 0) {
- v = -v;
- split->positive = 0;
- }
- split->degrees = v / 10000000;
- minutes_e7 = (v % 10000000) * 60;
- split->minutes = minutes_e7 / 10000000;
- split->minutes_fraction = (minutes_e7 % 10000000) / 1000;
-}
+#include "ao_telem.h"
void
ao_gps_print(__xdata struct ao_gps_data *gps_data) __reentrant
{
- printf("GPS %2d sat",
+ char state;
+
+ if (gps_data->flags & AO_GPS_VALID)
+ state = AO_TELEM_GPS_STATE_LOCKED;
+ else if (gps_data->flags & AO_GPS_RUNNING)
+ state = AO_TELEM_GPS_STATE_UNLOCKED;
+ else
+ state = AO_TELEM_GPS_STATE_ERROR;
+ printf(AO_TELEM_GPS_STATE " %c "
+ AO_TELEM_GPS_NUM_SAT " %d ",
+ state,
(gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
- if (gps_data->flags & AO_GPS_VALID) {
- static __xdata struct ao_gps_split lat, lon;
- int16_t climb, climb_int, climb_frac;
+ if (!(gps_data->flags & AO_GPS_VALID))
+ return;
+ printf(AO_TELEM_GPS_LATITUDE " %ld "
+ AO_TELEM_GPS_LONGITUDE " %ld "
+ AO_TELEM_GPS_ALTITUDE " %d ",
+ gps_data->latitude,
+ gps_data->longitude,
+ gps_data->altitude);
- ao_gps_split(gps_data->latitude, &lat);
- ao_gps_split(gps_data->longitude, &lon);
- if (gps_data->flags & AO_GPS_DATE_VALID)
- printf(" 20%02d-%02d-%02d",
- gps_data->year,
- gps_data->month,
- gps_data->day);
- else
- printf (" 0000-00-00");
- printf(" %2d:%02d:%02d",
- gps_data->hour,
- gps_data->minute,
- gps_data->second);
- printf(" %2d°%02d.%04d'%c %2d°%02d.%04d'%c %5dm",
- lat.degrees,
- lat.minutes,
- lat.minutes_fraction,
- lat.positive ? 'N' : 'S',
- lon.degrees,
- lon.minutes,
- lon.minutes_fraction,
- lon.positive ? 'E' : 'W',
- gps_data->altitude);
- climb = gps_data->climb_rate;
- if (climb >= 0) {
- climb_int = climb / 100;
- climb_frac = climb % 100;
- } else {
- climb = -climb;
- climb_int = -(climb / 100);
- climb_frac = climb % 100;
- }
- printf(" %5u.%02dm/s(H) %d° %5d.%02dm/s(V)",
- gps_data->ground_speed / 100,
- gps_data->ground_speed % 100,
- gps_data->course * 2,
- climb / 100,
- climb % 100);
- printf(" %d.%d(hdop) %5u(herr) %5u(verr)",
- gps_data->hdop / 5,
- (gps_data->hdop * 2) % 10,
+ if (gps_data->flags & AO_GPS_DATE_VALID)
+ printf(AO_TELEM_GPS_YEAR " %d "
+ AO_TELEM_GPS_MONTH " %d "
+ AO_TELEM_GPS_DAY " %d ",
+ gps_data->year,
+ gps_data->month,
+ gps_data->day);
+
+ printf(AO_TELEM_GPS_HOUR " %d "
+ AO_TELEM_GPS_MINUTE " %d "
+ AO_TELEM_GPS_SECOND " %d ",
+ gps_data->hour,
+ gps_data->minute,
+ gps_data->second);
+
+ printf(AO_TELEM_GPS_HDOP " %d ",
+ gps_data->hdop * 2);
+
+ if (gps_data->flags & AO_GPS_COURSE_VALID) {
+ printf(AO_TELEM_GPS_HERROR " %d "
+ AO_TELEM_GPS_VERROR " %d "
+ AO_TELEM_GPS_VERTICAL_SPEED " %d "
+ AO_TELEM_GPS_HORIZONTAL_SPEED " %d "
+ AO_TELEM_GPS_COURSE " %d ",
gps_data->h_error,
- gps_data->v_error);
- } else if (gps_data->flags & AO_GPS_RUNNING) {
- printf(" unlocked");
- } else {
- printf (" not-connected");
+ gps_data->v_error,
+ gps_data->climb_rate,
+ gps_data->ground_speed,
+ (int) gps_data->course * 2);
}
}
{
uint8_t c, n, v;
__xdata struct ao_gps_sat_data *sat;
- printf("SAT ");
+
n = gps_tracking_data->channels;
- if (n == 0) {
- printf("not-connected");
+ if (n == 0)
return;
- }
+
sat = gps_tracking_data->sats;
v = 0;
for (c = 0; c < n; c++) {
v++;
sat++;
}
- printf("%d ", v);
+
+ printf (AO_TELEM_SAT_NUM " %d ",
+ v);
+
sat = gps_tracking_data->sats;
+ v = 0;
for (c = 0; c < n; c++) {
- if (sat->svid)
- printf (" %3d %3d",
- sat->svid,
- sat->c_n_1);
+ if (sat->svid) {
+ printf (AO_TELEM_SAT_SVID "%d %d "
+ AO_TELEM_SAT_C_N_0 "%d %d ",
+ v, sat->svid,
+ v, sat->c_n_1);
+ v++;
+ }
sat++;
}
}
ao_gps_data.course = ao_sirf_data.course / 200;
ao_gps_data.hdop = ao_sirf_data.hdop;
ao_gps_data.climb_rate = ao_sirf_data.climb_rate;
+ ao_gps_data.flags |= AO_GPS_COURSE_VALID;
if (ao_sirf_data.h_error > 6553500)
ao_gps_data.h_error = 65535;
else
#define AO_GPS_VALID (1 << 4)
#define AO_GPS_RUNNING (1 << 5)
#define AO_GPS_DATE_VALID (1 << 6)
+#define AO_GPS_COURSE_VALID (1 << 7)
struct ao_gps_data {
uint8_t year;
#define AO_GPS_VALID (1 << 4)
#define AO_GPS_RUNNING (1 << 5)
#define AO_GPS_DATE_VALID (1 << 6)
+#define AO_GPS_COURSE_VALID (1 << 7)
struct ao_gps_data {
uint8_t year;
*/
#include "ao.h"
+#include "ao_telem.h"
__xdata uint8_t ao_monitoring;
__pdata uint8_t ao_monitor_led;
void
ao_monitor(void)
{
- __xdata struct ao_telemetry_recv recv;
__xdata char callsign[AO_MAX_CALLSIGN+1];
+ __xdata union {
+ struct ao_telemetry_recv full;
+ struct ao_telemetry_tiny_recv tiny;
+ } u;
+
+#define recv (u.full)
+#define recv_tiny (u.tiny)
+
uint8_t state;
int16_t rssi;
for (;;) {
__critical while (!ao_monitoring)
ao_sleep(&ao_monitoring);
- if (!ao_radio_recv(&recv, sizeof (recv)))
- continue;
- state = recv.telemetry.flight_state;
-
- /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */
- rssi = (int16_t) (recv.rssi >> 1) - 74;
- memcpy(callsign, recv.telemetry.callsign, AO_MAX_CALLSIGN);
- if (state > ao_flight_invalid)
- state = ao_flight_invalid;
- if (recv.status & PKT_APPEND_STATUS_1_CRC_OK) {
- printf("VERSION %d CALL %s SERIAL %d FLIGHT %5u RSSI %4d STATUS %02x STATE %7s ",
- AO_TELEMETRY_VERSION,
- callsign,
- recv.telemetry.serial,
- recv.telemetry.flight,
- rssi, recv.status,
- ao_state_names[state]);
- printf("%5u a: %5d p: %5d t: %5d v: %5d d: %5d m: %5d "
- "fa: %5d ga: %d fv: %7ld fp: %5d gp: %5d a+: %5d a-: %5d ",
- recv.telemetry.adc.tick,
- recv.telemetry.adc.accel,
- recv.telemetry.adc.pres,
- recv.telemetry.adc.temp,
- recv.telemetry.adc.v_batt,
- recv.telemetry.adc.sense_d,
- recv.telemetry.adc.sense_m,
- recv.telemetry.flight_accel,
- recv.telemetry.ground_accel,
- recv.telemetry.flight_vel,
- recv.telemetry.flight_pres,
- recv.telemetry.ground_pres,
- recv.telemetry.accel_plus_g,
- recv.telemetry.accel_minus_g);
- ao_gps_print(&recv.telemetry.gps);
- putchar(' ');
- ao_gps_tracking_print(&recv.telemetry.gps_tracking);
- putchar('\n');
- ao_rssi_set(rssi);
+ if (ao_monitoring == AO_MONITORING_FULL) {
+ if (!ao_radio_recv(&recv, sizeof (struct ao_telemetry_recv)))
+ continue;
+
+ state = recv.telemetry.flight_state;
+
+ /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */
+ rssi = (int16_t) (recv.rssi >> 1) - 74;
+ memcpy(callsign, recv.telemetry.callsign, AO_MAX_CALLSIGN);
+ if (state > ao_flight_invalid)
+ state = ao_flight_invalid;
+ if (recv.status & PKT_APPEND_STATUS_1_CRC_OK) {
+
+ /* General header fields */
+ printf(AO_TELEM_VERSION " %d "
+ AO_TELEM_CALL " %s "
+ AO_TELEM_SERIAL " %d "
+ AO_TELEM_FLIGHT " %d "
+ AO_TELEM_RSSI " %d "
+ AO_TELEM_STATE " %s "
+ AO_TELEM_TICK " %d ",
+ AO_TELEMETRY_VERSION,
+ callsign,
+ recv.telemetry.serial,
+ recv.telemetry.flight,
+ rssi,
+ ao_state_names[state],
+ recv.telemetry.adc.tick);
+
+ /* Raw sensor values */
+ printf(AO_TELEM_RAW_ACCEL " %d "
+ AO_TELEM_RAW_BARO " %d "
+ AO_TELEM_RAW_THERMO " %d "
+ AO_TELEM_RAW_BATT " %d "
+ AO_TELEM_RAW_DROGUE " %d "
+ AO_TELEM_RAW_MAIN " %d ",
+ recv.telemetry.adc.accel,
+ recv.telemetry.adc.pres,
+ recv.telemetry.adc.temp,
+ recv.telemetry.adc.v_batt,
+ recv.telemetry.adc.sense_d,
+ recv.telemetry.adc.sense_m);
+
+ /* Sensor calibration values */
+ printf(AO_TELEM_CAL_ACCEL_GROUND " %d "
+ AO_TELEM_CAL_BARO_GROUND " %d "
+ AO_TELEM_CAL_ACCEL_PLUS " %d "
+ AO_TELEM_CAL_ACCEL_MINUS " %d ",
+ recv.telemetry.ground_accel,
+ recv.telemetry.ground_pres,
+ recv.telemetry.accel_plus_g,
+ recv.telemetry.accel_minus_g);
+
+#if 0
+ /* Kalman state values */
+ printf(AO_TELEM_KALMAN_HEIGHT " %d "
+ AO_TELEM_KALMAN_SPEED " %d "
+ AO_TELEM_KALMAN_ACCEL " %d ",
+ recv.telemetry.height,
+ recv.telemetry.speed,
+ recv.telemetry.accel);
+#else
+ /* Ad-hoc flight values */
+ printf(AO_TELEM_ADHOC_ACCEL " %d "
+ AO_TELEM_ADHOC_SPEED " %ld "
+ AO_TELEM_ADHOC_BARO " %d ",
+ recv.telemetry.flight_accel,
+ recv.telemetry.flight_vel,
+ recv.telemetry.flight_pres);
+#endif
+ ao_gps_print(&recv.telemetry.gps);
+ ao_gps_tracking_print(&recv.telemetry.gps_tracking);
+ putchar('\n');
+ ao_rssi_set(rssi);
+ } else {
+ printf("CRC INVALID RSSI %3d\n", rssi);
+ }
} else {
- printf("CRC INVALID RSSI %3d\n", rssi);
+ if (!ao_radio_recv(&recv_tiny, sizeof (struct ao_telemetry_tiny_recv)))
+ continue;
+
+ state = recv_tiny.telemetry_tiny.flight_state;
+
+ /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */
+ rssi = (int16_t) (recv_tiny.rssi >> 1) - 74;
+ memcpy(callsign, recv_tiny.telemetry_tiny.callsign, AO_MAX_CALLSIGN);
+ if (state > ao_flight_invalid)
+ state = ao_flight_invalid;
+ if (recv_tiny.status & PKT_APPEND_STATUS_1_CRC_OK) {
+ /* General header fields */
+ printf(AO_TELEM_VERSION " %d "
+ AO_TELEM_CALL " %s "
+ AO_TELEM_SERIAL " %d "
+ AO_TELEM_FLIGHT " %d "
+ AO_TELEM_RSSI " %d "
+ AO_TELEM_STATE " %s "
+ AO_TELEM_TICK " %d ",
+ AO_TELEMETRY_VERSION,
+ callsign,
+ recv_tiny.telemetry_tiny.serial,
+ recv_tiny.telemetry_tiny.flight,
+ rssi,
+ ao_state_names[state],
+ recv_tiny.telemetry_tiny.adc.tick);
+
+ /* Raw sensor values */
+ printf(AO_TELEM_RAW_BARO " %d "
+ AO_TELEM_RAW_THERMO " %d "
+ AO_TELEM_RAW_BATT " %d "
+ AO_TELEM_RAW_DROGUE " %d "
+ AO_TELEM_RAW_MAIN " %d ",
+ recv_tiny.telemetry_tiny.adc.pres,
+ recv_tiny.telemetry_tiny.adc.temp,
+ recv_tiny.telemetry_tiny.adc.v_batt,
+ recv_tiny.telemetry_tiny.adc.sense_d,
+ recv_tiny.telemetry_tiny.adc.sense_m);
+
+ /* Sensor calibration values */
+ printf(AO_TELEM_CAL_BARO_GROUND " %d ",
+ recv_tiny.telemetry_tiny.ground_pres);
+
+#if 1
+ /* Kalman state values */
+ printf(AO_TELEM_KALMAN_HEIGHT " %d "
+ AO_TELEM_KALMAN_SPEED " %d "
+ AO_TELEM_KALMAN_ACCEL " %d\n",
+ recv_tiny.telemetry_tiny.height,
+ recv_tiny.telemetry_tiny.speed,
+ recv_tiny.telemetry_tiny.accel);
+#else
+ /* Ad-hoc flight values */
+ printf(AO_TELEM_ADHOC_ACCEL " %d "
+ AO_TELEM_ADHOC_SPEED " %ld "
+ AO_TELEM_ADHOC_BARO " %d\n",
+ recv_tiny.telemetry_tiny.flight_accel,
+ recv_tiny.telemetry_tiny.flight_vel,
+ recv_tiny.telemetry_tiny.flight_pres);
+#endif
+ ao_rssi_set(rssi);
+ } else {
+ printf("CRC INVALID RSSI %3d\n", rssi);
+ }
}
ao_usb_flush();
ao_led_toggle(ao_monitor_led);
void
ao_set_monitor(uint8_t monitoring)
{
+ if (ao_monitoring)
+ ao_radio_recv_abort();
ao_monitoring = monitoring;
ao_wakeup(&ao_monitoring);
- if (!ao_monitoring)
- ao_radio_recv_abort();
}
static void
set_monitor(void)
{
ao_cmd_hex();
- ao_set_monitor(ao_cmd_lex_i != 0);
+ ao_set_monitor(ao_cmd_lex_i);
}
__code struct ao_cmds ao_monitor_cmds[] = {
- { set_monitor, "m <0 off, 1 on>\0Enable/disable radio monitoring" },
+ { set_monitor, "m <0 off, 1 full, 2 tiny>\0Enable/disable radio monitoring" },
{ 0, NULL },
};
--- /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.
+ */
+
+#ifndef _AO_TELEM_H_
+#define _AO_TELEM_H_
+
+#define AO_TELEMETRY_VERSION 4
+
+/*
+ * Telemetry version 4 and higher format:
+ *
+ * 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)
+ */
+
+#define AO_TELEM_VERSION "VERSION"
+#define AO_TELEM_CALL "c"
+#define AO_TELEM_SERIAL "n"
+#define AO_TELEM_FLIGHT "f"
+#define AO_TELEM_RSSI "r"
+#define AO_TELEM_STATE "s"
+#define 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)
+ */
+
+#define AO_TELEM_RAW_ACCEL "r_a"
+#define AO_TELEM_RAW_BARO "r_b"
+#define AO_TELEM_RAW_THERMO "r_t"
+#define AO_TELEM_RAW_BATT "r_v"
+#define AO_TELEM_RAW_DROGUE "r_d"
+#define 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
+ */
+
+#define AO_TELEM_CAL_ACCEL_GROUND "c_a"
+#define AO_TELEM_CAL_BARO_GROUND "c_b"
+#define AO_TELEM_CAL_ACCEL_PLUS "c_p"
+#define 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)
+ */
+
+#define AO_TELEM_KALMAN_HEIGHT "k_h"
+#define AO_TELEM_KALMAN_SPEED "k_s"
+#define 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)
+ */
+
+#define AO_TELEM_ADHOC_ACCEL "a_a"
+#define AO_TELEM_ADHOC_SPEED "a_s"
+#define 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)
+ */
+
+#define AO_TELEM_GPS_STATE "g_s"
+#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_NUM_SAT "g_n"
+#define AO_TELEM_GPS_LATITUDE "g_ns"
+#define AO_TELEM_GPS_LONGITUDE "g_ew"
+#define AO_TELEM_GPS_ALTITUDE "g_a"
+#define AO_TELEM_GPS_YEAR "g_Y"
+#define AO_TELEM_GPS_MONTH "g_M"
+#define AO_TELEM_GPS_DAY "g_D"
+#define AO_TELEM_GPS_HOUR "g_h"
+#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_COURSE "g_c"
+#define AO_TELEM_GPS_HDOP "g_hd"
+#define AO_TELEM_GPS_VDOP "g_vd"
+#define AO_TELEM_GPS_HERROR "g_he"
+#define 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
+ * ...
+ */
+
+#define AO_TELEM_SAT_NUM "s_n"
+#define AO_TELEM_SAT_SVID "s_v"
+#define AO_TELEM_SAT_C_N_0 "s_c"
+
+#endif /* _AO_TELEM_H_ */