*
* 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.
+ * 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
*/
#include "ao.h"
+#include <ao_flight.h>
#include <math.h>
-static __xdata struct ao_telemetry_sensor ao_tel_sensor;
-static __xdata struct ao_telemetry_location ao_tel_location;
-static __xdata struct ao_telemetry_configuration ao_tel_config;
-static __xdata int16_t ao_tel_max_speed;
-static __xdata int16_t ao_tel_max_height;
+static struct ao_telemetry_sensor ao_tel_sensor;
+static struct ao_telemetry_location ao_tel_location;
+static struct ao_telemetry_configuration ao_tel_config;
+static int16_t ao_tel_max_speed;
+static int16_t ao_tel_max_height;
static int8_t ao_tel_rssi;
-static __xdata char ao_lcd_line[17];
-static __xdata char ao_state_name[] = "SIPBFCDMLI";
+static char ao_lcd_line[17];
+static char ao_state_name[] = "SIPBFCDMLI";
static void
ao_terraui_line(uint8_t addr)
return '-';
}
-static __code char ao_progress[4] = { '\011', '\012', '\014', '\013' };
+static const char ao_progress[4] = { '\011', '\012', '\014', '\013' };
static uint8_t ao_telem_progress;
static uint8_t ao_gps_progress;
static void
-ao_terraui_info(void)
+ao_terraui_startup(void)
+{
+ sprintf(ao_lcd_line, "%-16.16s", ao_product);
+ ao_terraui_line(AO_LCD_ADDR(0,0));
+ sprintf(ao_lcd_line, "%-8.8s %5u ", ao_version, ao_serial_number);
+ ao_terraui_line(AO_LCD_ADDR(1,0));
+}
+
+static void
+ao_terraui_info_firstline(void)
{
sprintf(ao_lcd_line, "S %4d %7.7s %c",
ao_tel_sensor.serial,
ao_tel_config.callsign,
ao_terraui_state());
ao_terraui_line(AO_LCD_ADDR(0,0));
+}
+
+static void
+ao_terraui_info(void)
+{
+ ao_terraui_info_firstline();
sprintf(ao_lcd_line, "F %4d RSSI%4d%c",
ao_tel_config.flight,
ao_tel_rssi,
return d;
}
-static uint32_t
+static int32_t
dist(int32_t d)
{
- int32_t m;
+ uint32_t m;
+ uint8_t neg = 0;
- if (d < 0)
+ if (d < 0) {
d = -d;
+ neg = 1;
+ }
- m = 1000000;
+ m = 10000000;
while (d >= (2147483647 / 111198)) {
d /= 10;
m /= 10;
}
- return (d * 111198) / m;
+ d = (d * 111198) / m;
+ if (neg)
+ d = -d;
+ return d;
}
-static __code uint8_t cos_table[] = {
+static const uint8_t cos_table[] = {
0, /* 0 */
0, /* 1 */
0, /* 2 */
1, /* 54 */
};
-static __code uint8_t tan_table[] = {
+static const uint8_t tan_table[] = {
0, /* 0 */
4, /* 1 */
9, /* 2 */
247, /* 44 */
};
-int16_t ao_atan2(int32_t dy, int32_t dx) __reentrant
+int16_t ao_atan2(int32_t dy, int32_t dx)
{
int8_t m = 1;
int16_t a = 0;
}
if (dy > dx) {
- int t;
+ int32_t t;
t = dy; dy = dx; dx = t;
a = a + m * 90;
m = -m;
}
- r = ((dy << 8) + (dx >> 1)) / dx;
+ dy = dy << 8;
+ dy = (dy + (dx >> 1)) / dx;
+ r = dy;
for (t = 0; t < 44; t++)
if (tan_table[t] >= r)
break;
return t * m + a;
}
-static __pdata uint32_t lon_dist, lat_dist;
-static __pdata uint32_t ground_dist, range;
-static __pdata int16_t bearing, elevation;
+static int32_t lon_dist, lat_dist;
+static uint32_t ground_dist, range;
+static uint8_t dist_in_km;
+static int16_t bearing, elevation;
static void
ao_terraui_lat_dist(void)
}
static void
-ao_terraui_lon_dist(void)
+ao_terraui_lon_dist(void)
{
uint8_t c = cos_table[ao_gps_data.latitude >> 24];
- lon_dist = dist(ao_tel_location.longitude - ao_gps_data.longitude);
- if (c)
- lon_dist = ((uint32_t) lon_dist * c) >> 8;
+ lon_dist = ao_tel_location.longitude;
+
+ /* check if it's shorter to go the other way around */
+ if ((int16_t) (lon_dist >> 24) < (int16_t) (ao_gps_data.longitude >> 24) - (int16_t) (1800000000 >> 24))
+ lon_dist += 3600000000ul;
+ lon_dist = dist(lon_dist - ao_gps_data.longitude);
+ if (c) {
+ if (lon_dist & 0x7f800000)
+ lon_dist = (lon_dist >> 8) * c;
+ else
+ lon_dist = (lon_dist * (int16_t) c) >> 8;
+ }
}
+static int32_t sqr(int32_t x) { return x * x; }
+
static void
ao_terraui_compute(void)
{
+ uint16_t h = ao_tel_sensor.height;
+
ao_terraui_lat_dist();
ao_terraui_lon_dist();
- ground_dist = ao_sqrt (lat_dist * lat_dist + lon_dist * lon_dist);
+ if (lat_dist > 32767 || lon_dist > 32767) {
+ dist_in_km = 1;
+ ground_dist = sqr(lat_dist/1000) + sqr(lon_dist/1000);
+ h = h/1000;
+ } else {
+ dist_in_km = 0;
+ ground_dist = sqr(lat_dist) + sqr(lon_dist);
+ }
+ ground_dist = ao_sqrt (ground_dist);
range = ao_sqrt(ground_dist * ground_dist + ao_tel_sensor.height * ao_tel_sensor.height);
- bearing = ao_atan2(lat_dist, lon_dist);
+ bearing = ao_atan2(lon_dist, lat_dist);
+ if (bearing < 0)
+ bearing += 360;
elevation = ao_atan2(ao_tel_sensor.height, ground_dist);
}
}
static void
-ao_terraui_coord(int32_t c, char plus, char minus, char extra) __reentrant
+ao_terraui_recover(void)
+{
+ ao_terraui_compute();
+ sprintf(ao_lcd_line, "\007 %4d \005 %3d %c",
+ bearing, elevation,
+ ao_terraui_state());
+ ao_terraui_line(AO_LCD_ADDR(0,0));
+ sprintf(ao_lcd_line, "R%5ld%cRSSI%4d%c",
+ ground_dist, dist_in_km ? 'k' : ' ',
+ ao_tel_rssi,
+ ao_progress[ao_telem_progress]);
+ ao_terraui_line(AO_LCD_ADDR(1,0));
+}
+
+static void
+ao_terraui_coord(int32_t c, char plus, char minus, char extra)
{
uint16_t d;
uint8_t m;
}
static void
-ao_terraui_local(void) __reentrant
+ao_terraui_local(void)
{
ao_terraui_coord(ao_gps_data.latitude, 'n', 's',
ao_terraui_local_gps());
ao_terraui_line(AO_LCD_ADDR(1,0));
}
+static uint8_t ao_set_freq;
+static uint32_t ao_set_freq_orig;
+
static void
-ao_terraui_config(void)
+ao_terraui_freq(void)
{
+ uint16_t MHz;
+ uint16_t frac;
+ MHz = ao_config.frequency / 1000;
+ frac = ao_config.frequency % 1000;
+ ao_terraui_info_firstline();
+ sprintf(ao_lcd_line, "Freq: %3d.%03d MHz", MHz, frac);
+ ao_terraui_line(AO_LCD_ADDR(1,0));
+ ao_lcd_goto(AO_LCD_ADDR(1,11));
+}
+
+static void
+ao_terraui_freq_start(void)
+{
+ ao_set_freq = 1;
+ ao_set_freq_orig = ao_config.frequency;
+ ao_lcd_cursor_on();
}
-enum ao_page {
- ao_page_info,
- ao_page_pad,
- ao_page_ascent,
- ao_page_descent,
- ao_page_remote,
- ao_page_local,
+static void
+ao_terraui_freq_button(char b) {
+
+ switch (b) {
+ case 0:
+ return;
+ case 1:
+ if (ao_config.frequency > 430000)
+ ao_config.frequency -= 100;
+ break;
+ case 2:
+ ao_set_freq = 0;
+ ao_lcd_cursor_off();
+ if (ao_set_freq_orig != ao_config.frequency)
+ ao_config_put();
+ return;
+ case 3:
+ if (ao_config.frequency < 438000)
+ ao_config.frequency += 100;
+ break;
+
+ }
+ ao_config_set_radio();
+ ao_radio_recv_abort();
+}
+
+static const void (*const ao_terraui_page[])(void) = {
+ ao_terraui_startup,
+ ao_terraui_info,
+ ao_terraui_pad,
+ ao_terraui_ascent,
+ ao_terraui_descent,
+ ao_terraui_recover,
+ ao_terraui_remote,
+ ao_terraui_local,
};
+#define NUM_PAGE (sizeof (ao_terraui_page)/sizeof (ao_terraui_page[0]))
+
+static uint8_t ao_current_page = 0;
+static uint8_t ao_shown_about = 3;
+
static void
ao_terraui(void)
{
- enum ao_page cur_page = ao_page_info;
-
ao_lcd_start();
+
+ ao_delay(AO_MS_TO_TICKS(100));
+ ao_button_clear();
+
for (;;) {
char b;
- switch (cur_page) {
- case ao_page_info:
- ao_terraui_info();
- break;
- case ao_page_pad:
- ao_terraui_pad();
- break;
- case ao_page_ascent:
- ao_terraui_ascent();
- break;
- case ao_page_descent:
- ao_terraui_descent();
- break;
- case ao_page_remote:
- ao_terraui_remote();
- break;
- case ao_page_local:
- ao_terraui_local();
- break;
- }
- ao_alarm(AO_SEC_TO_TICKS(1));
- b = ao_button_get();
- ao_clear_alarm();
+ if (ao_set_freq)
+ ao_terraui_freq();
+ else
+ ao_terraui_page[ao_current_page]();
+ b = ao_button_get(AO_SEC_TO_TICKS(1));
+
+ if (b > 0) {
+ ao_beep_for(AO_BEEP_HIGH, AO_MS_TO_TICKS(10));
+ ao_shown_about = 0;
+ }
+
+ if (ao_set_freq) {
+ ao_terraui_freq_button(b);
+ continue;
+ }
switch (b) {
case 0:
+ if (ao_shown_about) {
+ if (--ao_shown_about == 0)
+ ao_current_page = 2;
+ }
break;
case 1:
- if (cur_page == ao_page_local)
- cur_page = ao_page_info;
- else
- cur_page++;
- ao_beep_for(AO_BEEP_HIGH, AO_MS_TO_TICKS(50));
+ ao_current_page++;
+ if (ao_current_page >= NUM_PAGE)
+ ao_current_page = 0;
break;
case 2:
- ao_beep_for(AO_BEEP_LOW, AO_MS_TO_TICKS(200));
+ ao_terraui_freq_start();
break;
case 3:
- if (cur_page == ao_page_info)
- cur_page = ao_page_local;
- else
- cur_page--;
- ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(50));
+ if (ao_current_page == 0)
+ ao_current_page = NUM_PAGE;
+ ao_current_page--;
break;
}
}
}
-__xdata static struct ao_task ao_terraui_task;
+static struct ao_task ao_terraui_task;
static void
ao_terramonitor(void)
uint8_t monitor;
monitor = ao_monitor_head;
+ ao_monitor_set(sizeof (struct ao_telemetry_generic));
for (monitor = ao_monitor_head;;
monitor = ao_monitor_ring_next(monitor))
{
while (monitor == ao_monitor_head)
- ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
+ ao_sleep(&ao_monitor_head);
if (ao_monitoring != sizeof (union ao_telemetry_all))
continue;
if (!(ao_monitor_ring[monitor].all.status & PKT_APPEND_STATUS_1_CRC_OK))
continue;
- ao_tel_rssi = (ao_monitor_ring[monitor].all.rssi >> 1) - 74;
+ ao_tel_rssi = AO_RSSI_FROM_RADIO(ao_monitor_ring[monitor].all.rssi);
switch (ao_monitor_ring[monitor].all.telemetry.generic.type) {
case AO_TELEMETRY_SENSOR_TELEMETRUM:
case AO_TELEMETRY_SENSOR_TELEMINI:
case AO_TELEMETRY_SENSOR_TELENANO:
- ao_xmemcpy(&ao_tel_sensor, &ao_monitor_ring[monitor], sizeof (ao_tel_sensor));
+ memcpy(&ao_tel_sensor, &ao_monitor_ring[monitor], sizeof (ao_tel_sensor));
if (ao_tel_sensor.state < ao_flight_boost) {
ao_tel_max_speed = 0;
ao_tel_max_height = 0;
ao_telem_progress = (ao_telem_progress + 1) & 0x3;
break;
case AO_TELEMETRY_LOCATION:
- ao_xmemcpy(&ao_tel_location, &ao_monitor_ring[monitor], sizeof (ao_tel_location));
+ memcpy(&ao_tel_location, &ao_monitor_ring[monitor], sizeof (ao_tel_location));
break;
case AO_TELEMETRY_CONFIGURATION:
- ao_xmemcpy(&ao_tel_config, &ao_monitor_ring[monitor], sizeof (ao_tel_config));
+ memcpy(&ao_tel_config, &ao_monitor_ring[monitor], sizeof (ao_tel_config));
}
}
}
-__xdata static struct ao_task ao_terramonitor_task;
+static struct ao_task ao_terramonitor_task;
static void
ao_terragps(void)
{
- uint16_t gps_tick = ao_gps_progress;
+ AO_TICK_TYPE gps_tick = ao_gps_progress;
for (;;) {
while (ao_gps_tick == gps_tick)
- ao_sleep(&ao_gps_data);
+ ao_sleep(&ao_gps_new);
gps_tick = ao_gps_tick;
ao_gps_progress = (ao_gps_progress + 1) & 3;
}
}
-__xdata static struct ao_task ao_terragps_task;
+static struct ao_task ao_terragps_task;
void
ao_terraui_init(void)