install:
-ao_flight_test: ao_flight.c ao_flight_test.c
+ao_flight_test: ao_flight.c ao_flight_test.c ao_host.h
cc -g -o $@ ao_flight_test.c
-ao_gps_test: ao_gps.c ao_gps_test.c ao_host.h
+ao_gps_test: ao_gps.c ao_gps_test.c ao_gps_print.c ao_host.h
cc -g -o $@ ao_gps_test.c
#define AO_LOG_GPS_LAT 'N'
#define AO_LOG_GPS_LON 'W'
#define AO_LOG_GPS_ALT 'H'
+#define AO_LOG_GPS_SAT 'V'
#define AO_LOG_POS_NONE (~0UL)
int16_t altitude;
uint16_t unused;
} gps_altitude;
+ struct {
+ uint16_t svid;
+ uint8_t state;
+ uint8_t c_n;
+ uint8_t unused;
+ } gps_sat;
struct {
uint16_t d0;
uint16_t d1;
uint16_t v_error; /* m */
};
+#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
+#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
+#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
+#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
+#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
+#define SIRF_SAT_CODE_LOCKED (1 << 5)
+#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
+#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
+
+struct ao_gps_sat_data {
+ uint8_t svid;
+ uint8_t state;
+ uint8_t c_n_1;
+};
+
+struct ao_gps_tracking_data {
+ uint8_t channels;
+ struct ao_gps_sat_data sats[12];
+};
+
extern __xdata uint8_t ao_gps_mutex;
extern __xdata struct ao_gps_data ao_gps_data;
+extern __xdata struct ao_gps_tracking_data ao_gps_tracking_data;
void
ao_gps(void);
void
ao_gps_print(__xdata struct ao_gps_data *gps_data);
+void
+ao_gps_tracking_print(__xdata struct ao_gps_tracking_data *gps_tracking_data);
+
void
ao_gps_init(void);
struct ao_adc adc;
struct ao_gps_data gps;
char callsign[AO_MAX_CALLSIGN];
+ struct ao_gps_tracking_data gps_tracking;
};
/* Set delay between telemetry reports (0 to disable) */
#define DBG_RESET_N_PIN (P0_5)
static void
-ao_dbg_send_bits(uint8_t msk, uint8_t val)
+ao_dbg_send_bits(uint8_t msk, uint8_t val) __reentrant
{
P0 = (P0 & ~msk) | (val & msk);
_asm
__xdata uint8_t ao_gps_mutex;
__xdata struct ao_gps_data ao_gps_data;
+__xdata struct ao_gps_tracking_data ao_gps_tracking_data;
static const char ao_gps_set_nmea[] = "\r\n$PSRF100,0,57600,8,1,0*37\r\n";
static __xdata struct sirf_geodetic_nav_data ao_sirf_data;
+struct sirf_measured_sat_data {
+ uint8_t svid;
+ uint16_t state;
+ uint8_t c_n_1;
+};
+
+struct sirf_measured_tracker_data {
+ int16_t gps_week;
+ uint32_t gps_tow;
+ uint8_t channels;
+ struct sirf_measured_sat_data sats[12];
+};
+
+static __xdata struct sirf_measured_tracker_data ao_sirf_tracker_data;
+
static __pdata uint16_t ao_sirf_cksum;
static __pdata uint16_t ao_sirf_len;
return c;
}
+static char __xdata *sirf_target;
+
static void sirf_u16(uint8_t offset)
{
- uint16_t __xdata *ptr = (uint16_t __xdata *) (((char __xdata *) &ao_sirf_data) + offset);
+ uint16_t __xdata *ptr = (uint16_t __xdata *) (sirf_target + offset);
uint16_t val;
val = data_byte() << 8;
static void sirf_u8(uint8_t offset)
{
- uint8_t __xdata *ptr = (uint8_t __xdata *) (((char __xdata *) &ao_sirf_data) + offset);
+ uint8_t __xdata *ptr = (uint8_t __xdata *) (sirf_target + offset);
uint8_t val;
val = data_byte ();
*ptr = val;
}
-static void sirf_u32(uint8_t offset)
+static void sirf_u32(uint8_t offset) __reentrant
{
- uint32_t __xdata *ptr = (uint32_t __xdata *) (((char __xdata *) &ao_sirf_data) + offset);
+ uint32_t __xdata *ptr = (uint32_t __xdata *) (sirf_target + offset);
uint32_t val;
val = ((uint32_t) data_byte ()) << 24;
#define SIRF_U8 2
#define SIRF_U16 3
#define SIRF_U32 4
+#define SIRF_U8X10 5
struct sirf_packet_parse {
uint8_t type;
uint8_t offset;
};
+static void
+ao_sirf_parse(void __xdata *target, const struct sirf_packet_parse *parse) __reentrant
+{
+ uint8_t i, offset, j;
+
+ sirf_target = target;
+ for (i = 0; ; i++) {
+ offset = parse[i].offset;
+ switch (parse[i].type) {
+ case SIRF_END:
+ return;
+ case SIRF_DISCARD:
+ sirf_discard(offset);
+ break;
+ case SIRF_U8:
+ sirf_u8(offset);
+ break;
+ case SIRF_U16:
+ sirf_u16(offset);
+ break;
+ case SIRF_U32:
+ sirf_u32(offset);
+ break;
+ case SIRF_U8X10:
+ for (j = 10; j--;)
+ sirf_u8(offset++);
+ break;
+ }
+ }
+}
+
static const struct sirf_packet_parse geodetic_nav_data_packet[] = {
{ SIRF_DISCARD, 2 }, /* 1 nav valid */
{ SIRF_U16, offsetof(struct sirf_geodetic_nav_data, nav_type) }, /* 3 */
};
static void
-ao_sirf_parse_41(void)
+ao_sirf_parse_41(void) __reentrant
{
- uint8_t i, offset;
+ ao_sirf_parse(&ao_sirf_data, geodetic_nav_data_packet);
+}
- for (i = 0; ; i++) {
- offset = geodetic_nav_data_packet[i].offset;
- switch (geodetic_nav_data_packet[i].type) {
- case SIRF_END:
- return;
- case SIRF_DISCARD:
- sirf_discard(offset);
- break;
- case SIRF_U8:
- sirf_u8(offset);
- break;
- case SIRF_U16:
- sirf_u16(offset);
- break;
- case SIRF_U32:
- sirf_u32(offset);
- break;
- }
- }
+static const struct sirf_packet_parse measured_tracker_data_packet[] = {
+ { SIRF_U16, offsetof (struct sirf_measured_tracker_data, gps_week) }, /* 1 week */
+ { SIRF_U32, offsetof (struct sirf_measured_tracker_data, gps_tow) }, /* 3 time of week */
+ { SIRF_U8, offsetof (struct sirf_measured_tracker_data, channels) }, /* 7 channels */
+ { SIRF_END, 0 },
+};
+
+static const struct sirf_packet_parse measured_sat_data_packet[] = {
+ { SIRF_U8, offsetof (struct sirf_measured_sat_data, svid) }, /* 0 SV id */
+ { SIRF_DISCARD, 2 }, /* 1 azimuth, 2 elevation */
+ { SIRF_U16, offsetof (struct sirf_measured_sat_data, state) }, /* 2 state */
+ { SIRF_U8, offsetof (struct sirf_measured_sat_data, c_n_1) }, /* C/N0 1 */
+ { SIRF_DISCARD, 9 }, /* C/N0 2-10 */
+ { SIRF_END, 0 },
+};
+
+static void
+ao_sirf_parse_4(void) __reentrant
+{
+ uint8_t i;
+ ao_sirf_parse(&ao_sirf_tracker_data, measured_tracker_data_packet);
+ for (i = 0; i < 12; i++)
+ ao_sirf_parse(&ao_sirf_tracker_data.sats[i], measured_sat_data_packet);
}
static void
static const uint8_t sirf_disable[] = {
2,
- 4,
9,
10,
27,
for (i = 0; i < sizeof (sirf_disable); i++)
ao_sirf_set_message_rate(sirf_disable[i], 0);
ao_sirf_set_message_rate(41, 1);
+ ao_sirf_set_message_rate(4, 1);
}
for (;;) {
/* Locate the begining of the next record */
break;
ao_sirf_parse_41();
break;
+ case 4:
+ if (ao_sirf_len < 187)
+ break;
+ ao_sirf_parse_4();
+ break;
}
if (ao_sirf_len != 0)
continue;
ao_mutex_put(&ao_gps_mutex);
ao_wakeup(&ao_gps_data);
break;
+ case 4:
+ ao_mutex_get(&ao_gps_mutex);
+ ao_gps_tracking_data.channels = ao_sirf_tracker_data.channels;
+ for (i = 0; i < 12; i++) {
+ ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid;
+ ao_gps_tracking_data.sats[i].state = (uint8_t) ao_sirf_tracker_data.sats[i].state;
+ ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1;
+ }
+ ao_mutex_put(&ao_gps_mutex);
+ ao_wakeup(&ao_gps_tracking_data);
+ break;
}
}
}
{
ao_mutex_get(&ao_gps_mutex);
ao_gps_print(&ao_gps_data);
+ putchar('\n');
+ ao_gps_tracking_print(&ao_gps_tracking_data);
+ putchar('\n');
ao_mutex_put(&ao_gps_mutex);
}
gps_data->course * 2,
climb / 100,
climb % 100);
- printf(" %d.%d(hdop) %5u(herr) %5u(verr)\n",
+ printf(" %d.%d(hdop) %5u(herr) %5u(verr)",
gps_data->hdop / 5,
(gps_data->hdop * 2) % 10,
gps_data->h_error,
gps_data->v_error);
} else if (gps_data->flags & AO_GPS_RUNNING) {
- printf(" unlocked\n");
+ printf(" unlocked");
} else {
- printf (" not-connected\n");
+ printf (" not-connected");
}
}
+
+void
+ao_gps_tracking_print(__xdata struct ao_gps_tracking_data *gps_tracking_data) __reentrant
+{
+ 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\n");
+ return;
+ }
+ sat = gps_tracking_data->sats;
+ v = 0;
+ for (c = 0; c < n; c++) {
+ if (sat->svid && sat->state)
+ v++;
+ sat++;
+ }
+ printf("%d ", v);
+ sat = gps_tracking_data->sats;
+ for (c = 0; c < n; c++) {
+ if (sat->svid && sat->state)
+ printf (" %3d %02x %3d",
+ sat->svid,
+ sat->state,
+ sat->c_n_1);
+ sat++;
+ }
+ printf ("\n");
+}
}
}
+void
+ao_gps_tracking_report(void)
+{
+ static __xdata struct ao_log_record gps_log;
+ static __xdata struct ao_gps_tracking_data gps_tracking_data;
+ uint8_t c, n;
+
+ for (;;) {
+ ao_sleep(&ao_gps_tracking_data);
+ ao_mutex_get(&ao_gps_mutex);
+ memcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (struct ao_gps_tracking_data));
+ ao_mutex_put(&ao_gps_mutex);
+
+ if (!(n = gps_tracking_data.channels))
+ continue;
+
+ gps_log.tick = ao_time();
+ gps_log.type = AO_LOG_GPS_SAT;
+ for (c = 0; c < n; c++)
+ if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid) &&
+ (gps_log.u.gps_sat.state = gps_tracking_data.sats[c].state))
+ {
+ gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
+ gps_log.u.gps_sat.unused = 0;
+ ao_log_data(&gps_log);
+ }
+ }
+}
+
__xdata struct ao_task ao_gps_report_task;
+__xdata struct ao_task ao_gps_tracking_report_task;
void
ao_gps_report_init(void)
{
ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
+ ao_add_task(&ao_gps_tracking_report_task, ao_gps_tracking_report, "gps_tracking_report");
}
uint16_t v_error; /* m */
};
+#define SIRF_SAT_STATE_ACQUIRED (1 << 0)
+#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1)
+#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2)
+#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3)
+#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4)
+#define SIRF_SAT_CODE_LOCKED (1 << 5)
+#define SIRF_SAT_ACQUISITION_FAILED (1 << 6)
+#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7)
+
+struct ao_gps_sat_data {
+ uint8_t svid;
+ uint8_t state;
+ uint8_t c_n_1;
+};
+
+struct ao_gps_tracking_data {
+ uint8_t channels;
+ struct ao_gps_sat_data sats[12];
+};
+
void
ao_mutex_get(uint8_t *mutex)
{
static char input_queue[QUEUE_LEN];
int input_head, input_tail;
+#include <sys/time.h>
+
+int
+get_millis(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
static void
check_sirf_message(char *from, uint8_t *msg, int len)
}
encoded_len = (msg[2] << 8) | msg[3];
id = msg[4];
+/* printf ("%9d: %3d\n", get_millis(), id); */
if (encoded_len != len - 8) {
- printf ("length mismatch (got %d, wanted %d)\n",
- len - 8, encoded_len);
+ if (id != 52)
+ printf ("length mismatch (got %d, wanted %d)\n",
+ len - 8, encoded_len);
return;
}
encoded_cksum = (msg[len - 4] << 8) | msg[len-3];
return;
}
id = msg[4];
- if (id == 41) {
+ switch (id) {
+ case 41:{
int off = 4;
uint8_t id;
printf ("Geodetic Navigation Data (41):\n");
printf ("\tNav valid %04x\n", nav_valid);
printf ("\tNav type %04x\n", nav_type);
- printf ("\tWeek %d\n", week);
- printf ("\tTOW %d\n", tow);
- printf ("\tyear %d\n", year);
- printf ("\tmonth %d\n", month);
- printf ("\tday %d\n", day);
- printf ("\thour %d\n", hour);
- printf ("\tminute %d\n", minute);
- printf ("\tsecond %g\n", second / 1000.0);
+ printf ("\tWeek %5d", week);
+ printf (" TOW %9d", tow);
+ printf (" %4d-%2d-%2d %02d:%02d:%07.4f\n",
+ year, month, day,
+ hour, minute, second / 1000.0);
printf ("\tsats: %08x\n", sat_list);
- printf ("\tlat: %g\n", lat / 1.0e7);
- printf ("\tlon: %g\n", lon / 1.0e7);
- printf ("\talt_ell: %g\n", alt_ell / 100.0);
- printf ("\talt_msll: %g\n", alt_msl / 100.0);
- printf ("\tdatum: %d\n", datum);
- printf ("\tground speed: %g\n", sog / 100.0);
- printf ("\tcourse: %g\n", cog / 100.0);
- printf ("\tclimb: %g\n", climb_rate / 100.0);
- printf ("\theading rate: %g\n", heading_rate / 100.0);
- printf ("\th error: %g\n", h_error / 100.0);
- printf ("\tv error: %g\n", v_error / 100.0);
- printf ("\tt error: %g\n", t_error / 100.0);
- printf ("\th vel error: %g\n", h_v_error / 100.0);
- } else {
+ printf ("\tlat: %g", lat / 1.0e7);
+ printf (" lon: %g", lon / 1.0e7);
+ printf (" alt_ell: %g", alt_ell / 100.0);
+ printf (" alt_msll: %g", alt_msl / 100.0);
+ printf (" datum: %d\n", datum);
+ printf ("\tground speed: %g", sog / 100.0);
+ printf (" course: %g", cog / 100.0);
+ printf (" climb: %g", climb_rate / 100.0);
+ printf (" heading rate: %g\n", heading_rate / 100.0);
+ printf ("\th error: %g", h_error / 100.0);
+ printf (" v error: %g", v_error / 100.0);
+ printf (" t error: %g", t_error / 100.0);
+ printf (" h vel error: %g\n", h_v_error / 100.0);
+ break;
+ }
+ case 4: {
+ int off = 4;
+ uint8_t id;
+ int16_t gps_week;
+ uint32_t gps_tow;
+ uint8_t channels;
+ int j, k;
+
+ get_u8(id);
+ get_u16(gps_week);
+ get_u32(gps_tow);
+ get_u8(channels);
+
+ printf ("Measured Tracker Data (4):\n");
+ printf ("GPS week: %d\n", gps_week);
+ printf ("GPS time of week: %d\n", gps_tow);
+ printf ("channels: %d\n", channels);
+ for (j = 0; j < 12; j++) {
+ uint8_t svid, azimuth, elevation;
+ uint16_t state;
+ uint8_t c_n[10];
+ get_u8(svid);
+ get_u8(azimuth);
+ get_u8(elevation);
+ get_u16(state);
+ for (k = 0; k < 10; k++) {
+ get_u8(c_n[k]);
+ }
+ printf ("Sat %3d:", svid);
+ printf (" aziumuth: %6.1f", azimuth * 1.5);
+ printf (" elevation: %6.1f", elevation * 0.5);
+ printf (" state: 0x%02x", state);
+ printf (" c_n:");
+ for (k = 0; k < 10; k++)
+ printf(" %3d", c_n[k]);
+ if (state & SIRF_SAT_STATE_ACQUIRED)
+ printf(" acq,");
+ if (state & SIRF_SAT_STATE_CARRIER_PHASE_VALID)
+ printf(" car,");
+ if (state & SIRF_SAT_BIT_SYNC_COMPLETE)
+ printf(" bit,");
+ if (state & SIRF_SAT_SUBFRAME_SYNC_COMPLETE)
+ printf(" sub,");
+ if (state & SIRF_SAT_CARRIER_PULLIN_COMPLETE)
+ printf(" pullin,");
+ if (state & SIRF_SAT_CODE_LOCKED)
+ printf(" code,");
+ if (state & SIRF_SAT_ACQUISITION_FAILED)
+ printf(" fail,");
+ if (state & SIRF_SAT_EPHEMERIS_AVAILABLE)
+ printf(" ephem,");
+ printf ("\n");
+ }
+ break;
+ }
+ default:
return;
printf ("%s %4d:", from, encoded_len);
for (i = 4; i < len - 4; i++) {
#include "ao_gps.c"
void
-ao_dump_state(void)
+ao_dump_state(void *wchan)
{
double lat, lon;
+ int i;
+ if (wchan == &ao_gps_data)
+ ao_gps_print(&ao_gps_data);
+ else
+ ao_gps_tracking_print(&ao_gps_tracking_data);
+ putchar('\n');
+ return;
printf ("%02d:%02d:%02d",
ao_gps_data.hour, ao_gps_data.minute,
ao_gps_data.second);
ao_gps_data.hdop / 5.0,
ao_gps_data.h_error, ao_gps_data.v_error);
printf("\n");
+ printf ("\t");
+ for (i = 0; i < 12; i++)
+ printf (" %2d(%02x)",
+ ao_gps_tracking_data.sats[i].svid,
+ ao_gps_tracking_data.sats[i].state);
+ printf ("\n");
}
int
return fd;
}
+#include <getopt.h>
+
+static const struct option options[] = {
+ { .name = "tty", .has_arg = 1, .val = 'T' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--tty <tty-name>]\n", program);
+ exit(1);
+}
+
int
main (int argc, char **argv)
{
- char *gps_file = "/dev/ttyUSB0";
+ char *tty = "/dev/ttyUSB0";
+ int c;
- ao_gps_fd = ao_gps_open(gps_file);
+ while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) {
+ switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ ao_gps_fd = ao_gps_open(tty);
if (ao_gps_fd < 0) {
- perror (gps_file);
+ perror (tty);
exit (1);
}
ao_gps_setup();
#define ao_led_on(l)
#define ao_led_off(l)
#define ao_timer_set_adc_interval(i)
-#define ao_wakeup(wchan) ao_dump_state()
+#define ao_wakeup(wchan) ao_dump_state(wchan)
#define ao_cmd_register(c)
#define ao_usb_disable()
#define ao_telemetry_set_interval(x)
FILE *emulator_in;
void
-ao_dump_state(void);
+ao_dump_state(void *wchan);
void
ao_sleep(void *wchan);
recv.telemetry.flight_pres,
recv.telemetry.ground_pres);
ao_gps_print(&recv.telemetry.gps);
+ putchar(' ');
+ ao_gps_tracking_print(&recv.telemetry.gps_tracking);
+ putchar('\n');
ao_rssi_set((int) recv.rssi - 74);
} else {
printf("CRC INVALID RSSI %3d\n", (int) recv.rssi - 74);
ao_adc_get(&telemetry.adc);
ao_mutex_get(&ao_gps_mutex);
memcpy(&telemetry.gps, &ao_gps_data, sizeof (struct ao_gps_data));
+ memcpy(&telemetry.gps_tracking, &ao_gps_tracking_data, sizeof (struct ao_gps_tracking_data));
ao_mutex_put(&ao_gps_mutex);
ao_radio_send(&telemetry);
ao_delay(ao_telemetry_interval);