Ok, way too big a patch, but things were in rough shape.
This patch adds support for the radio, both transmit and receive.
Then, because I could no longer run the TeleMetrum code on the TI
dongle, I ended up building a separate image for the TI board, which
involved creating a mechanism for having multiple command sets and splitting
code for different functions into different files.
-PROG=altos
-CC=sdcc
-NO_OPT=--nogcse --noinvariant --noinduction --nojtbound --noloopreverse \
- --nolabelopt --nooverlay --peep-asm
-DEBUG=--debug
+#
+# AltOS build
+#
+#
+CC=/usr/bin/sdcc
-CFLAGS=--model-small $(DEBUG) --less-pedantic --opt-code-speed
+CFLAGS=--model-small --debug --opt-code-speed
-LDFLAGS=--out-fmt-ihx
-LDFLAGS_FLASH=$(LDFLAGS) --code-loc 0x0000 --code-size 0x8000 \
+LDFLAGS=--out-fmt-ihx --code-loc 0x0000 --code-size 0x8000 \
--xram-loc 0xf000 --xram-size 0xf00 --iram-size 0xff
INC = \
ao.h \
cc1111.h \
- altitude.h
+ altitude.h \
+ 25lc1024.h
-SRC = \
- ao_adc.c \
- ao_beep.c \
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
ao_cmd.c \
- ao_convert.c \
ao_dbg.c \
ao_dma.c \
- ao_ee.c \
- ao_flight.c \
- ao_gps.c \
- ao_led.c \
- ao_log.c \
ao_mutex.c \
ao_panic.c \
- ao_report.c \
- ao_serial.c \
ao_task.c \
ao_timer.c \
- ao_usb.c \
- ao_main.c \
_bp.c
+
+#
+# Shared AltOS drivers
+#
+ALTOS_DRIVER_SRC = \
+ ao_beep.c \
+ ao_led.c \
+ ao_radio.c \
+ ao_stdio.c \
+ ao_usb.c
+
+TELE_COMMON_SRC = \
+ ao_gps_print.c
+
+#
+# Receiver code
+#
+TELE_RECEIVER_SRC =\
+ ao_monitor.c
+
+#
+# Shared Tele drivers (on TeleMetrum, TeleTerra, TeleDongle)
+#
+
+TELE_DRIVER_SRC = \
+ ao_convert.c \
+ ao_gps.c \
+ ao_serial.c
+
+#
+# Drivers only on TeleMetrum
+#
+TM_DRIVER_SRC = \
+ ao_adc.c \
+ ao_ee.c
+
+#
+# Tasks run on TeleMetrum
+#
+TM_TASK_SRC = \
+ ao_flight.c \
+ ao_log.c \
+ ao_report.c \
+ ao_telemetry.c \
+ ao_telemetrum.c
+
+#
+# All sources for TeleMetrum
+#
+TM_SRC = \
+ $(ALTOS_SRC) \
+ $(ALTOS_DRIVER_SRC) \
+ $(TELE_DRIVER_SRC) \
+ $(TELE_COMMON_SRC) \
+ $(TM_DRIVER_SRC) \
+ $(TM_TASK_SRC)
+
+TI_TASK_SRC = \
+ ao_tidongle.c
+
+#
+# All sources for the TI debug dongle
+#
+TI_SRC = \
+ $(ALTOS_SRC) \
+ $(ALTOS_DRIVER_SRC) \
+ $(TELE_RECEIVER_SRC) \
+ $(TELE_COMMON_SRC) \
+ $(TI_TASK_SRC)
+SRC = \
+ $(ALTOS_SRC) \
+ $(ALTOS_DRIVER_SRC) \
+ $(TELE_DRIVER_SRC) \
+ $(TELE_RECEIVER_SRC) \
+ $(TELE_COMMON_SRC) \
+ $(TM_DRIVER_SRC) \
+ $(TM_TASK_SRC) \
+ $(TI_TASK_SRC)
+
+TM_REL=$(TM_SRC:.c=.rel)
+TI_REL=$(TI_SRC:.c=.rel)
+
ADB=$(SRC:.c=.adb)
ASM=$(SRC:.c=.asm)
LNK=$(SRC:.c=.lnk)
RST=$(SRC:.c=.rst)
SYM=$(SRC:.c=.sym)
-PROGS=$(PROG).ihx
+PROGS=telemetrum.ihx tidongle.ihx
PCDB=$(PROGS:.ihx=.cdb)
PLNK=$(PROGS:.ihx=.lnk)
PMAP=$(PROGS:.ihx=.map)
all: $(PROGS)
-$(PROG).ihx: $(REL) Makefile
- $(CC) $(LDFLAGS_FLASH) $(CFLAGS) -o $(PROG).ihx $(REL)
- sh check-stack ao.h $(PROG).mem
+telemetrum.ihx: $(TM_REL) Makefile
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(TM_REL)
+ sh check-stack ao.h telemetrum.mem
+
+tidongle.ihx: $(TI_REL) Makefile
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(TI_REL)
+ sh check-stack ao.h tidongle.mem
+
+tidongle.ihx: telemetrum.ihx
altitude.h: make-altitude
nickle make-altitude > altitude.h
/* Stack runs from above the allocated __data space to 0xfe, which avoids
* writing to 0xff as that triggers the stack overflow indicator
*/
-#define AO_STACK_START 0x62
+#define AO_STACK_START 0x68
#define AO_STACK_END 0xfe
#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1)
*/
/* Suspend the current task until wchan is awoken */
-int
+void
ao_sleep(__xdata void *wchan);
/* Wake all tasks sleeping on wchan */
-int
+void
ao_wakeup(__xdata void *wchan);
/* Yield the processor to another task */
#define AO_PANIC_MUTEX 3 /* Mis-using mutex API */
#define AO_PANIC_EE 4 /* Mis-using eeprom API */
#define AO_PANIC_LOG 5 /* Failing to read/write log data */
+#define AO_PANIC_CMD 6 /* Too many command sets registered */
/* Stop the operating system, beeping and blinking the reason */
void
void
ao_delay(uint16_t ticks);
+/* Set the ADC interval */
+void
+ao_timer_set_adc_interval(uint8_t interval) __critical;
+
/* Timer interrupt */
void
ao_timer_isr(void) interrupt 9;
ao_adc_get(__xdata struct ao_adc *packet);
/* The A/D interrupt handler */
+#if !AO_NO_ADC_ISR
void
ao_adc_isr(void) interrupt 1;
+#endif
/* Initialize the A/D converter */
void
/*
* ao_cmd.c
*/
+
+enum ao_cmd_status {
+ ao_cmd_success = 0,
+ ao_cmd_lex_error = 1,
+ ao_cmd_syntax_error = 2,
+};
+
+extern __xdata uint16_t ao_cmd_lex_i;
+extern __xdata uint8_t ao_cmd_lex_c;
+extern __xdata enum ao_cmd_status ao_cmd_status;
+
+void
+ao_cmd_lex(void);
+
+void
+ao_cmd_put8(uint8_t v);
+
+void
+ao_cmd_put16(uint16_t v);
+
+void
+ao_cmd_white(void);
+
+void
+ao_cmd_hex(void);
+
+struct ao_cmds {
+ uint8_t cmd;
+ void (*func)(void);
+ const char *help;
+};
+
+void
+ao_cmd_register(__code struct ao_cmds *cmds);
+
void
ao_cmd_init(void);
* ao_log.c
*/
+/* Structure containing GPS position, either lat or lon */
+
+struct ao_gps_pos {
+ uint8_t degrees;
+ uint8_t minutes;
+ uint16_t minutes_fraction; /* in units of 1/10000 minutes */
+};
+
/*
* The data log is recorded in the eeprom as a sequence
* of data packets.
#define AO_LOG_TEMP_VOLT 'T'
#define AO_LOG_DEPLOY 'D'
#define AO_LOG_STATE 'S'
+#define AO_LOG_GPS_TIME 'G'
+#define AO_LOG_GPS_LAT 'N'
+#define AO_LOG_GPS_LON 'W'
+#define AO_LOG_GPS_ALT 'H'
#define AO_LOG_POS_NONE (~0UL)
uint16_t state;
uint16_t reason;
} state;
+ struct {
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t flags;
+ } gps_time;
+ struct ao_gps_pos gps_latitude;
+ struct ao_gps_pos gps_longitude;
+ struct {
+ int16_t altitude;
+ uint16_t unused;
+ } gps_altitude;
struct {
uint16_t d0;
uint16_t d1;
*/
enum ao_flight_state {
- ao_flight_startup,
- ao_flight_idle,
- ao_flight_launchpad,
- ao_flight_boost,
- ao_flight_coast,
- ao_flight_apogee,
- ao_flight_drogue,
- ao_flight_main,
- ao_flight_landed,
- ao_flight_invalid
+ ao_flight_startup = 0,
+ ao_flight_idle = 1,
+ ao_flight_launchpad = 2,
+ ao_flight_boost = 3,
+ ao_flight_coast = 4,
+ ao_flight_apogee = 5,
+ ao_flight_drogue = 6,
+ ao_flight_main = 7,
+ ao_flight_landed = 8,
+ ao_flight_invalid = 9
};
extern __xdata struct ao_adc ao_flight_data;
* ao_report.c
*/
-void
-ao_report_notify(void);
-
void
ao_report_init(void);
ao_temp_to_dC(int16_t temp) __reentrant;
int16_t
-ao_accel_to_dm_per_s2(int16_t accel)
-{
- return (998 - (accel >> 4)) * 3300 / 2047;
-}
+ao_accel_to_cm_per_s2(int16_t accel) __reentrant;
/*
* ao_dbg.c
* ao_serial.c
*/
+#if !AO_NO_SERIAL_ISR
void
ao_serial_rx1_isr(void) interrupt 3;
void
ao_serial_tx1_isr(void) interrupt 14;
+#endif
uint8_t
ao_serial_getchar(void) __critical;
* ao_gps.c
*/
-struct ao_gps_pos {
- uint8_t degrees;
- uint8_t minutes;
- uint16_t minutes_fraction; /* in units of 1/10000 minutes */
-};
-
#define AO_GPS_NUM_SAT_MASK (0xf << 0)
#define AO_GPS_NUM_SAT_SHIFT (0)
void
ao_gps(void);
+void
+ao_gps_print(__xdata struct ao_gps_data *gps_data);
+
void
ao_gps_init(void);
+/*
+ * ao_telemetry.c
+ */
+
+#define AO_TELEMETRY_SENSOR 1
+#define AO_TELEMETRY_GPS 2
+
+struct ao_telemetry {
+ uint8_t addr;
+ uint8_t type;
+ uint8_t flight_state;
+ union {
+ struct ao_adc adc;
+ struct ao_gps_data gps;
+ } u;
+};
+
+void
+ao_telemetry_send(__xdata struct ao_telemetry *telemetry) __reentrant;
+
+void
+ao_telemetry_init(void);
+
+/*
+ * ao_radio.c
+ */
+
+void
+ao_radio_send(__xdata struct ao_telemetry *telemetry) __reentrant;
+
+struct ao_radio_recv {
+ struct ao_telemetry telemetry;
+ uint8_t rssi;
+ uint8_t status;
+};
+
+void
+ao_radio_recv(__xdata struct ao_radio_recv *recv) __reentrant;
+
+void
+ao_radio_init(void);
+
+/*
+ * ao_monitor.c
+ */
+
+void
+ao_monitor(void);
+
+void
+ao_monitor_init(void);
+
+/*
+ * ao_stdio.c
+ */
+
+void
+flush(void);
#endif /* _AO_H_ */
}
}
+static void
+ao_adc_dump(void)
+{
+ __xdata struct ao_adc packet;
+ ao_adc_get(&packet);
+ printf("tick: %5u accel: %4d pres: %4d temp: %4d batt: %4d drogue: %4d main: %4d\n",
+ packet.tick, packet.accel >> 4, packet.pres >> 4, packet.temp >> 4,
+ packet.sense_d >> 4, packet.sense_m >> 4);
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+ { 'a', ao_adc_dump, "a Display current ADC values\n" },
+ { 0, ao_adc_dump, NULL },
+};
+
void
ao_adc_init(void)
{
/* enable interrupts */
ADCIF = 0;
IEN0 |= IEN0_ADCIE;
+ ao_cmd_register(&ao_adc_cmds[0]);
}
#include "ao.h"
-#define LEX_ERROR 1
-#define SYNTAX_ERROR 2
-#define SUCCESS 0
-
-static __xdata uint16_t lex_i;
-static __xdata uint8_t lex_c;
-static __xdata uint8_t lex_status;
+__xdata uint16_t ao_cmd_lex_i;
+__xdata uint8_t ao_cmd_lex_c;
+__xdata enum ao_cmd_status ao_cmd_status;
static __xdata uint8_t lex_echo;
#define CMD_LEN 32
static __xdata uint8_t cmd_len;
static __xdata uint8_t cmd_i;
-void
-putchar(char c)
-{
- if (c == '\n')
- ao_usb_putchar('\r');
- ao_usb_putchar((uint8_t) c);
-}
-
-void
-flush(void)
-{
- ao_usb_flush();
-}
-
-char
-getchar(void)
-{
- return (char) ao_usb_getchar();
-}
-
static void
put_string(char *s)
{
if (c == '\n') {
if (lex_echo)
- put_string ("\n");
+ putchar('\n');
break;
}
cmd_i = 0;
}
-static void
-lex(void)
+void
+ao_cmd_lex(void)
{
- lex_c = '\n';
+ ao_cmd_lex_c = '\n';
if (cmd_i < cmd_len)
- lex_c = cmd_line[cmd_i++];
+ ao_cmd_lex_c = cmd_line[cmd_i++];
}
static void
}
void
-put16(uint16_t v)
+ao_cmd_put16(uint16_t v)
{
int8_t i;
for (i = 3; i >= 0; i--)
}
void
-put8(uint8_t v)
+ao_cmd_put8(uint8_t v)
{
putnibble((v >> 4) & 0xf);
putnibble(v & 0xf);
}
-#define NUM_LEN 7
-
void
-puti(int i)
+ao_cmd_white(void)
{
- static uint8_t __xdata num_buffer[NUM_LEN];
- uint8_t __xdata * __xdata num_ptr = num_buffer + NUM_LEN;
- uint8_t __xdata neg = 0;
-
- *--num_ptr = '\0';
- if (i < 0) {
- i = -i;
- neg = 1;
- }
- do {
- *--num_ptr = '0' + i % 10;
- i /= 10;
- } while (i);
- if (neg)
- *--num_ptr = '-';
- while (num_ptr != num_buffer)
- *--num_ptr = ' ';
- put_string(num_buffer);
+ while (ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t')
+ ao_cmd_lex();
}
-
-static void
-white(void)
-{
- while (lex_c == ' ' || lex_c == '\t')
- lex();
-}
-
-static void
-hex(void)
+void
+ao_cmd_hex(void)
{
- __xdata uint8_t r = LEX_ERROR;
+ __xdata uint8_t r = ao_cmd_lex_error;
- lex_i = 0;
- white();
+ ao_cmd_lex_i = 0;
+ ao_cmd_white();
for(;;) {
- if ('0' <= lex_c && lex_c <= '9')
- lex_i = (lex_i << 4) | (lex_c - '0');
- else if ('a' <= lex_c && lex_c <= 'f')
- lex_i = (lex_i << 4) | (lex_c - 'a' + 10);
- else if ('A' <= lex_c && lex_c <= 'F')
- lex_i = (lex_i << 4) | (lex_c - 'A' + 10);
+ if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+ ao_cmd_lex_i = (ao_cmd_lex_i << 4) | (ao_cmd_lex_c - '0');
+ else if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f')
+ ao_cmd_lex_i = (ao_cmd_lex_i << 4) | (ao_cmd_lex_c - 'a' + 10);
+ else if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F')
+ ao_cmd_lex_i = (ao_cmd_lex_i << 4) | (ao_cmd_lex_c - 'A' + 10);
else
break;
- r = SUCCESS;
- lex();
+ r = ao_cmd_success;
+ ao_cmd_lex();
}
- if (r != SUCCESS)
- lex_status = r;
+ if (r != ao_cmd_success)
+ ao_cmd_status = r;
}
#if 0
static void
decimal(void)
{
- __xdata uint8_t r = LEX_ERROR;
+ __xdata uint8_t r = ao_cmd_lex_error;
- lex_i = 0;
- white();
+ ao_cmd_lex_i = 0;
+ ao_cmd_white();
for(;;) {
- if ('0' <= lex_c && lex_c <= '9')
- lex_i = (lex_i * 10 ) | (lex_c - '0');
+ if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+ ao_cmd_lex_i = (ao_cmd_lex_i * 10 ) | (ao_cmd_lex_c - '0');
else
break;
- r = SUCCESS;
- lex();
+ r = ao_cmd_success;
+ ao_cmd_lex();
}
- if (r != SUCCESS)
- lex_status = r;
+ if (r != ao_cmd_success)
+ ao_cmd_status = r;
}
#endif
static void
eol(void)
{
- while (lex_c != '\n')
- lex();
-}
-
-static void
-adc_dump(void)
-{
- __xdata struct ao_adc packet;
- ao_adc_get(&packet);
- put_string("tick: ");
- puti(packet.tick);
- put_string(" accel: ");
- puti(packet.accel >> 4);
- put_string(" pres: ");
- puti(packet.pres >> 4);
- put_string(" temp: ");
- puti(packet.temp >> 4);
- put_string(" batt: ");
- puti(packet.v_batt >> 4);
- put_string(" drogue: ");
- puti(packet.sense_d >> 4);
- put_string(" main: ");
- puti(packet.sense_m >> 4);
- put_string("\n");
-}
-
-static void
-gps_dump(void) __reentrant
-{
- ao_mutex_get(&ao_gps_mutex);
- if (ao_gps_data.flags & AO_GPS_VALID) {
- printf("GPS %2d:%02d:%02d %2d°%2d.%04d'%c %2d°%2d.%04d'%c %5dm %2d sat\n",
- ao_gps_data.hour,
- ao_gps_data.minute,
- ao_gps_data.second,
- ao_gps_data.latitude.degrees,
- ao_gps_data.latitude.minutes,
- ao_gps_data.latitude.minutes_fraction,
- (ao_gps_data.flags & AO_GPS_LATITUDE_MASK) == AO_GPS_LATITUDE_NORTH ?
- 'N' : 'S',
- ao_gps_data.longitude.degrees,
- ao_gps_data.longitude.minutes,
- ao_gps_data.longitude.minutes_fraction,
- (ao_gps_data.flags & AO_GPS_LONGITUDE_MASK) == AO_GPS_LONGITUDE_WEST ?
- 'W' : 'E',
- ao_gps_data.altitude,
- (ao_gps_data.flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
- } else {
- printf("GPS %2d sat\n",
- (ao_gps_data.flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);;
- }
- ao_mutex_put(&ao_gps_mutex);
+ while (ao_cmd_lex_c != '\n')
+ ao_cmd_lex();
}
static void
__xdata uint16_t c;
__xdata uint8_t * __xdata start, * __xdata end;
- hex();
- start = (uint8_t __xdata *) lex_i;
- hex();
- end = (uint8_t __xdata *) lex_i;
- if (lex_status != SUCCESS)
+ ao_cmd_hex();
+ start = (uint8_t __xdata *) ao_cmd_lex_i;
+ ao_cmd_hex();
+ end = (uint8_t __xdata *) ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
return;
c = 0;
while (start <= end) {
if ((c & 7) == 0) {
if (c)
- put_string("\n");
- put16((uint16_t) start);
+ putchar('\n');
+ ao_cmd_put16((uint16_t) start);
}
putchar(' ');
- put8(*start);
+ ao_cmd_put8(*start);
++c;
start++;
}
- put_string("\n");
-}
-
-static void
-ee_dump(void)
-{
- __xdata uint8_t b;
- __xdata uint16_t block;
- __xdata uint8_t i;
-
- hex();
- block = lex_i;
- if (lex_status != SUCCESS)
- return;
- i = 0;
- do {
- if ((i & 7) == 0) {
- if (i)
- put_string("\n");
- put16((uint16_t) i);
- }
- putchar(' ');
- ao_ee_read(((uint32_t) block << 8) | i, &b, 1);
- put8(b);
- ++i;
- } while (i != 0);
- put_string("\n");
-}
-
-static void
-ee_store(void)
-{
- __xdata uint16_t block;
- __xdata uint8_t i;
- __xdata uint16_t len;
- __xdata uint8_t b;
- __xdata uint32_t addr;
-
- hex();
- block = lex_i;
- hex();
- i = lex_i;
- addr = ((uint32_t) block << 8) | i;
- hex();
- len = lex_i;
- if (lex_status != SUCCESS)
- return;
- while (len--) {
- hex();
- if (lex_status != SUCCESS)
- return;
- b = lex_i;
- ao_ee_write(addr, &b, 1);
- addr++;
- }
- ao_ee_flush();
+ putchar('\n');
}
static void
echo(void)
{
- hex();
- lex_echo = lex_i != 0;
-}
-
-static void
-debug_enable(void)
-{
- ao_dbg_debug_mode();
-}
-
-static void
-debug_reset(void)
-{
- ao_dbg_reset();
-}
-
-static void
-debug_put(void)
-{
- for (;;) {
- white ();
- if (lex_c == '\n')
- break;
- hex();
- if (lex_status != SUCCESS)
- break;
- ao_dbg_send_byte(lex_i);
- }
-}
-
-static void
-debug_get(void)
-{
- __xdata uint16_t count;
- __xdata uint16_t i;
- __xdata uint8_t byte;
- hex();
- if (lex_status != SUCCESS)
- return;
- count = lex_i;
- if (count > 256) {
- lex_status = SYNTAX_ERROR;
- return;
- }
- for (i = 0; i < count; i++) {
- if (i && (i & 7) == 0)
- put_string("\n");
- byte = ao_dbg_recv_byte();
- put8(byte);
- putchar(' ');
- }
- put_string("\n");
+ ao_cmd_hex();
+ lex_echo = ao_cmd_lex_i != 0;
}
-static uint8_t
-getnibble(void)
-{
- __xdata uint8_t c;
-
- c = getchar();
- if ('0' <= c && c <= '9')
- return c - '0';
- if ('a' <= c && c <= 'f')
- return c - ('a' - 10);
- if ('A' <= c && c <= 'F')
- return c - ('A' - 10);
- lex_status = LEX_ERROR;
- return 0;
-}
+static const uint8_t help_txt[] = "All numbers are in hex";
-static void
-debug_input(void)
-{
- __xdata uint16_t count;
- __xdata uint16_t addr;
- __xdata uint8_t b;
- __xdata uint8_t i;
+#define NUM_CMDS 8
- hex();
- count = lex_i;
- hex();
- addr = lex_i;
- if (lex_status != SUCCESS)
- return;
- ao_dbg_start_transfer(addr);
- i = 0;
- while (count--) {
- if (!(i++ & 7))
- put_string("\n");
- b = ao_dbg_read_byte();
- put8(b);
- }
- ao_dbg_end_transfer();
- put_string("\n");
-}
-
-static void
-debug_output(void)
-{
- __xdata uint16_t count;
- __xdata uint16_t addr;
- __xdata uint8_t b;
-
- hex();
- count = lex_i;
- hex();
- addr = lex_i;
- if (lex_status != SUCCESS)
- return;
- ao_dbg_start_transfer(addr);
- while (count--) {
- b = getnibble() << 4;
- b |= getnibble();
- if (lex_status != SUCCESS)
- return;
- ao_dbg_write_byte(b);
- }
- ao_dbg_end_transfer();
-}
-
-static void
-dump_log(void)
-{
- __xdata uint8_t more;
-
- for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) {
- putchar(ao_log_dump.type);
- putchar(' ');
- put16(ao_log_dump.tick);
- putchar(' ');
- put16(ao_log_dump.u.anon.d0);
- putchar(' ');
- put16(ao_log_dump.u.anon.d1);
- putchar('\n');
- }
-}
-
-static void
-send_serial(void)
-{
- white();
- while (lex_c != '\n') {
- ao_serial_putchar(lex_c);
- lex();
- }
-}
-
-static const uint8_t help_txt[] =
- "All numbers are in hex\n"
- "? Print this message\n"
- "a Display current ADC values\n"
- "g Display current GPS values\n"
- "d <start> <end> Dump memory\n"
- "e <block> Dump a block of EEPROM data\n"
- "w <block> <start> <len> <data> ... Write data to EEPROM\n"
- "l Dump last flight log\n"
- "E <0 off, 1 on> Set command echo mode\n"
- "S<data> Send data to serial line\n"
- "T Show task states\n"
- "\n"
- "Target debug commands:\n"
- "D Enable debug mode\n"
- "R Reset target\n"
- "P <byte> ... Put data to debug port\n"
- "G <count> Get data from debug port\n"
- "O <count> <addr> Output <count> bytes to target at <addr>\n"
- "I <count> <addr> Input <count> bytes to target at <addr>\n"
-;
+static __code struct ao_cmds *__xdata (ao_cmds[NUM_CMDS]);
+static __xdata uint8_t ao_ncmds;
static void
help(void)
{
- put_string(help_txt);
+ __xdata uint8_t cmds;
+ __xdata uint8_t cmd;
+ puts(help_txt);
+ for (cmds = 0; cmds < ao_ncmds; cmds++)
+ for (cmd = 0; ao_cmds[cmds][cmd].cmd; cmd++)
+ puts(ao_cmds[cmds][cmd].help);
}
static void
report(void)
{
- switch(lex_status) {
- case LEX_ERROR:
- case SYNTAX_ERROR:
- put_string("Syntax error\n");
- lex_status = 0;
+ switch(ao_cmd_status) {
+ case ao_cmd_lex_error:
+ case ao_cmd_syntax_error:
+ puts("Syntax error");
+ ao_cmd_status = 0;
break;
}
}
+void
+ao_cmd_register(__code struct ao_cmds *cmds)
+{
+ if (ao_ncmds >= NUM_CMDS)
+ ao_panic(AO_PANIC_CMD);
+ ao_cmds[ao_ncmds++] = cmds;
+}
+
void
ao_cmd(void *parameters)
{
__xdata uint8_t c;
+ __xdata uint8_t cmd, cmds;
(void) parameters;
lex_echo = 1;
for (;;) {
readline();
- lex();
- white();
- c = lex_c;
- lex();
- switch (c) {
- case '?':
- help();
- break;
- case 'd':
- dump();
- break;
- case 'a':
- adc_dump();
- break;
- case 'g':
- gps_dump();
- break;
- case 'e':
- ee_dump();
- break;
- case 'w':
- ee_store();
- break;
- case 'l':
- dump_log();
- break;
- case 'T':
- ao_task_info();
- break;
- case 'S':
- send_serial();
- break;
- case 'E':
- echo();
- break;
- case 'D':
- debug_enable();
- break;
- case 'R':
- debug_reset();
- break;
- case 'P':
- debug_put();
- break;
- case 'G':
- debug_get();
- break;
- case 'I':
- debug_input();
- break;
- case 'O':
- debug_output();
- break;
- case '\r':
- case '\n':
- break;
- default:
- lex_status = SYNTAX_ERROR;
- break;
+ ao_cmd_lex();
+ ao_cmd_white();
+ c = ao_cmd_lex_c;
+ ao_cmd_lex();
+ if (c == '\r' || c == '\n')
+ continue;
+ cmd = 0;
+ for (cmds = 0; cmds < ao_ncmds; cmds++) {
+ for (cmd = 0; ao_cmds[cmds][cmd].cmd != '\0'; cmd++)
+ if (ao_cmds[cmds][cmd].cmd == c)
+ break;
+ if (ao_cmds[cmds][cmd].cmd)
+ break;
}
+ if (ao_cmds[cmds][cmd].cmd)
+ (*ao_cmds[cmds][cmd].func);
+ else
+ ao_cmd_status = ao_cmd_syntax_error;
report();
}
-
}
__xdata struct ao_task ao_cmd_task;
+__code struct ao_cmds ao_base_cmds[] = {
+ { '?', help, "? Print this message" },
+ { 'T', ao_task_info, "T Show task states\n" },
+ { 'E', echo, "E <0 off, 1 on> Set command echo mode\n" },
+ { 'd', dump, "d <start> <end> Dump memory\n" },
+ { 0, help, NULL },
+};
+
void
ao_cmd_init(void)
{
+ ao_cmd_register(&ao_base_cmds[0]);
ao_add_task(&ao_cmd_task, ao_cmd, "cmd");
}
}
int16_t
-ao_accel_to_cm_per_s2(int16_t accel) __reentrant;
+ao_accel_to_cm_per_s2(int16_t accel) __reentrant
+{
+ /* this is wrong */
+ return (998 - (accel >> 4)) * 3300 / 2047;
+}
ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
}
+static void
+debug_enable(void)
+{
+ ao_dbg_debug_mode();
+}
+
+static void
+debug_reset(void)
+{
+ ao_dbg_reset();
+}
+
+static void
+debug_put(void)
+{
+ for (;;) {
+ ao_cmd_white ();
+ if (ao_cmd_lex_c == '\n')
+ break;
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ break;
+ ao_dbg_send_byte(ao_cmd_lex_i);
+ }
+}
+
+static void
+debug_get(void)
+{
+ __xdata uint16_t count;
+ __xdata uint16_t i;
+ __xdata uint8_t byte;
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ count = ao_cmd_lex_i;
+ if (count > 256) {
+ ao_cmd_status = ao_cmd_syntax_error;
+ return;
+ }
+ for (i = 0; i < count; i++) {
+ if (i && (i & 7) == 0)
+ putchar('\n');
+ byte = ao_dbg_recv_byte();
+ ao_cmd_put8(byte);
+ putchar(' ');
+ }
+ putchar('\n');
+}
+
+static uint8_t
+getnibble(void)
+{
+ __xdata uint8_t c;
+
+ c = getchar();
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - ('a' - 10);
+ if ('A' <= c && c <= 'F')
+ return c - ('A' - 10);
+ ao_cmd_status = ao_cmd_lex_error;
+ return 0;
+}
+
+static void
+debug_input(void)
+{
+ __xdata uint16_t count;
+ __xdata uint16_t addr;
+ __xdata uint8_t b;
+ __xdata uint8_t i;
+
+ ao_cmd_hex();
+ count = ao_cmd_lex_i;
+ ao_cmd_hex();
+ addr = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_start_transfer(addr);
+ i = 0;
+ while (count--) {
+ if (!(i++ & 7))
+ putchar('\n');
+ b = ao_dbg_read_byte();
+ ao_cmd_put8(b);
+ }
+ ao_dbg_end_transfer();
+ putchar('\n');
+}
+
+static void
+debug_output(void)
+{
+ __xdata uint16_t count;
+ __xdata uint16_t addr;
+ __xdata uint8_t b;
+
+ ao_cmd_hex();
+ count = ao_cmd_lex_i;
+ ao_cmd_hex();
+ addr = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_start_transfer(addr);
+ while (count--) {
+ b = getnibble() << 4;
+ b |= getnibble();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_dbg_write_byte(b);
+ }
+ ao_dbg_end_transfer();
+}
+
+__code struct ao_cmds ao_dbg_cmds[7] = {
+ { 'D', debug_enable, "D Enable debug mode\n" },
+ { 'G', debug_get, "G <count> Get data from debug port\n" },
+ { 'I', debug_input, "I <count> <addr> Input <count> bytes to target at <addr>\n" },
+ { 'O', debug_output, "O <count> <addr> Output <count> bytes to target at <addr>\n" },
+ { 'P', debug_put, "P <byte> ... Put data to debug port\n" },
+ { 'R', debug_reset, "R Reset target\n" },
+ { 0, debug_reset, 0 },
+};
+
+void
+ao_dbg_init(void)
+{
+ ao_cmd_register(&ao_dbg_cmds[0]);
+}
DMAARM = 0x80 | mask;
nop(); nop(); nop(); nop();
nop(); nop(); nop(); nop();
+ *(ao_dma_done[id]) = 0;
DMAARM = mask;
nop(); nop(); nop(); nop();
nop(); nop(); nop(); nop();
nop();
- *(ao_dma_done[id]) = 0;
}
void
return 1;
}
+static void
+ee_dump(void)
+{
+ __xdata uint8_t b;
+ __xdata uint16_t block;
+ __xdata uint8_t i;
+
+ ao_cmd_hex();
+ block = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ i = 0;
+ do {
+ if ((i & 7) == 0) {
+ if (i)
+ putchar('\n');
+ ao_cmd_put16((uint16_t) i);
+ }
+ putchar(' ');
+ ao_ee_read(((uint32_t) block << 8) | i, &b, 1);
+ ao_cmd_put8(b);
+ ++i;
+ } while (i != 0);
+ putchar('\n');
+}
+
+static void
+ee_store(void)
+{
+ __xdata uint16_t block;
+ __xdata uint8_t i;
+ __xdata uint16_t len;
+ __xdata uint8_t b;
+ __xdata uint32_t addr;
+
+ ao_cmd_hex();
+ block = ao_cmd_lex_i;
+ ao_cmd_hex();
+ i = ao_cmd_lex_i;
+ addr = ((uint32_t) block << 8) | i;
+ ao_cmd_hex();
+ len = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ while (len--) {
+ ao_cmd_hex();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ b = ao_cmd_lex_i;
+ ao_ee_write(addr, &b, 1);
+ addr++;
+ }
+ ao_ee_flush();
+}
+
+__code struct ao_cmds ao_ee_cmds[] = {
+ { 'e', ee_dump, "e <block> Dump a block of EEPROM data\n" },
+ { 'w', ee_store, "w <block> <start> <len> <data> ... Write data to EEPROM\n" },
+ { 0, ee_store, NULL },
+};
+
/*
* To initialize the chip, set up the CS line and
* the SPI interface
UxGCR_CPHA_FIRST_EDGE |
UxGCR_ORDER_MSB |
(17 << UxGCR_BAUD_E_SHIFT));
+ ao_cmd_register(&ao_ee_cmds[0]);
}
ao_interval_end = ao_flight_tick;
- if (ao_flight_accel < ACCEL_NOSE_UP) {
+ /* Go to launchpad state if the nose is pointing up and the battery is charged */
+ if (ao_flight_accel < ACCEL_NOSE_UP && ao_flight_data.v_batt > 23000) {
ao_flight_state = ao_flight_launchpad;
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
} else {
ao_flight_state = ao_flight_idle;
- ao_report_notify();
+
+ /* Turn on the Green LED in idle mode
+ * This also happens to bring the USB up for the TI board
+ */
+ ao_led_on(AO_LED_GREEN);
+ ao_timer_set_adc_interval(100);
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
}
/* signal successful initialization by turning off the LED */
ao_led_off(AO_LED_RED);
{
ao_flight_state = ao_flight_boost;
ao_log_start();
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
break;
}
break;
(int16_t) (ao_flight_data.tick - ao_launch_time) > BOOST_TICKS_MAX)
{
ao_flight_state = ao_flight_coast;
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
break;
}
break;
ao_min_pres = ao_flight_pres;
if (ao_flight_pres - BARO_APOGEE > ao_min_pres) {
ao_flight_state = ao_flight_apogee;
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
}
break;
case ao_flight_apogee:
// ao_ignite(AO_IGNITE_DROGUE);
ao_flight_state = ao_flight_drogue;
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
break;
case ao_flight_drogue:
if (ao_flight_pres >= ao_main_pres) {
// ao_ignite(AO_IGNITE_MAIN);
ao_flight_state = ao_flight_main;
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
}
if ((ao_interval_max_pres - ao_interval_min_pres) < BARO_LAND) {
ao_flight_state = ao_flight_landed;
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
}
break;
case ao_flight_main:
if ((ao_interval_max_pres - ao_interval_min_pres) < BARO_LAND) {
ao_flight_state = ao_flight_landed;
- ao_report_notify();
+ ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
}
break;
case ao_flight_landed:
#include "ao.h"
-__xdata struct ao_task ao_gps_task;
-
#define AO_GPS_LEADER 6
static const uint8_t ao_gps_header[] = "GPGGA,";
ao_gps_error = 1;
if (!ao_gps_error) {
ao_mutex_get(&ao_gps_mutex);
- memcpy(&ao_gps_data, &ao_gps_next, sizeof (ao_gps_data));
+ memcpy(&ao_gps_data, &ao_gps_next, sizeof (struct ao_gps_data));
ao_mutex_put(&ao_gps_mutex);
ao_wakeup(&ao_gps_data);
}
}
}
+void
+ao_gps_report(void)
+{
+ static __xdata struct ao_log_record gps_log;
+ static __xdata struct ao_telemetry gps_telemetry;
+ static __xdata struct ao_gps_data gps_data;
+
+ for (;;) {
+ ao_sleep(&ao_gps_data);
+ ao_mutex_get(&ao_gps_mutex);
+ memcpy(&gps_data, &ao_gps_data, sizeof (struct ao_gps_data));
+ ao_mutex_put(&ao_gps_mutex);
+
+ gps_log.tick = ao_time();
+ gps_log.type = AO_LOG_GPS_TIME;
+ gps_log.u.gps_time.hour = gps_data.hour;
+ gps_log.u.gps_time.minute = gps_data.minute;
+ gps_log.u.gps_time.second = gps_data.second;
+ gps_log.u.gps_time.flags = gps_data.flags;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_LAT;
+ gps_log.u.gps_latitude.degrees = gps_data.latitude.degrees;
+ gps_log.u.gps_latitude.minutes = gps_data.latitude.minutes;
+ gps_log.u.gps_latitude.minutes_fraction = gps_data.latitude.minutes_fraction;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_LON;
+ gps_log.u.gps_longitude.degrees = gps_data.longitude.degrees;
+ gps_log.u.gps_longitude.minutes = gps_data.longitude.minutes;
+ gps_log.u.gps_longitude.minutes_fraction = gps_data.longitude.minutes_fraction;
+ ao_log_data(&gps_log);
+ gps_log.type = AO_LOG_GPS_ALT;
+ gps_log.u.gps_altitude.altitude = gps_data.altitude;
+ gps_log.u.gps_altitude.unused = 0xffff;
+ ao_log_data(&gps_log);
+ gps_telemetry.type = AO_TELEMETRY_GPS;
+ memcpy(&gps_telemetry.u.gps, &gps_data, sizeof (struct ao_gps_data));
+ ao_telemetry_send(&gps_telemetry);
+ }
+
+}
+
+__xdata struct ao_task ao_gps_task;
+__xdata struct ao_task ao_gps_report_task;
+
+static void
+gps_dump(void) __reentrant
+{
+ ao_mutex_get(&ao_gps_mutex);
+ ao_gps_print(&ao_gps_data);
+ ao_mutex_put(&ao_gps_mutex);
+}
+
+__code struct ao_cmds ao_gps_cmds[] = {
+ { 'g', gps_dump, "g Display current GPS values\n" },
+ { 0, gps_dump, NULL },
+};
+
void
ao_gps_init(void)
{
ao_add_task(&ao_gps_task, ao_gps, "gps");
+ ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
+ ao_cmd_register(&ao_gps_cmds[0]);
}
--- /dev/null
+/*
+ * Copyright © 2009 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.
+ */
+
+#include "ao.h"
+
+void
+ao_gps_print(__xdata struct ao_gps_data *gps_data) __reentrant
+{
+ if (gps_data->flags & AO_GPS_VALID) {
+ printf("GPS %2d:%02d:%02d %2d°%2d.%04d'%c %2d°%2d.%04d'%c %5dm %2d sat\n",
+ gps_data->hour,
+ gps_data->minute,
+ gps_data->second,
+ gps_data->latitude.degrees,
+ gps_data->latitude.minutes,
+ gps_data->latitude.minutes_fraction,
+ (gps_data->flags & AO_GPS_LATITUDE_MASK) == AO_GPS_LATITUDE_NORTH ?
+ 'N' : 'S',
+ gps_data->longitude.degrees,
+ gps_data->longitude.minutes,
+ gps_data->longitude.minutes_fraction,
+ (gps_data->flags & AO_GPS_LONGITUDE_MASK) == AO_GPS_LONGITUDE_WEST ?
+ 'W' : 'E',
+ gps_data->altitude,
+ (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
+ } else {
+ printf("GPS %2d sat\n",
+ (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);;
+ }
+}
+
ao_log_flush();
}
+static void
+dump_log(void)
+{
+ __xdata uint8_t more;
+
+ for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) {
+ printf("%c %4x %4x %4x\n",
+ ao_log_dump.type,
+ ao_log_dump.tick,
+ ao_log_dump.u.anon.d0,
+ ao_log_dump.u.anon.d1);
+ }
+}
+
+__code struct ao_cmds ao_log_cmds[] = {
+ { 'l', dump_log, "l Dump last flight log\n" },
+ { 0, dump_log, NULL },
+};
+
static __xdata struct ao_task ao_log_task;
void
/* Create a task to log events to eeprom */
ao_add_task(&ao_log_task, ao_log, "log");
+ ao_cmd_register(&ao_log_cmds[0]);
}
ao_usb_init();
ao_serial_init();
ao_gps_init();
+ ao_telemetry_init();
+ ao_radio_init();
ao_start_scheduler();
}
--- /dev/null
+/*
+ * $Id: $
+ *
+ * Copyright © 2009 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ao.h"
+
+const char const * const ao_state_names[] = {
+ "startup", "idle", "pad", "boost", "coast",
+ "apogee", "drogue", "main", "landed", "invalid"
+};
+
+void
+ao_monitor(void)
+{
+ __xdata struct ao_radio_recv recv;
+ uint8_t state;
+
+ for (;;) {
+ ao_radio_recv(&recv);
+ state = recv.telemetry.flight_state;
+ if (state > ao_flight_invalid)
+ state = ao_flight_invalid;
+ printf ("SERIAL %3d RSSI %3d STATUS %02x STATE %s ",
+ recv.telemetry.addr, recv.rssi, recv.status,
+ ao_state_names[state]);
+ if (!(recv.status & PKT_APPEND_STATUS_1_CRC_OK))
+ printf("CRC INVALID ");
+ switch (recv.telemetry.type) {
+ case AO_TELEMETRY_SENSOR:
+ printf("%5u a: %d p: %d t: %d v: %d d: %d m: %d\n",
+ recv.telemetry.u.adc.tick,
+ recv.telemetry.u.adc.accel,
+ recv.telemetry.u.adc.pres,
+ recv.telemetry.u.adc.temp,
+ recv.telemetry.u.adc.v_batt,
+ recv.telemetry.u.adc.sense_d,
+ recv.telemetry.u.adc.sense_m);
+ break;
+ case AO_TELEMETRY_GPS:
+ ao_gps_print(&recv.telemetry.u.gps);
+ break;
+ }
+ ao_usb_flush();
+ }
+}
+
+__xdata struct ao_task ao_monitor_task;
+
+void
+ao_monitor_init(void)
+{
+ ao_add_task(&ao_monitor_task, ao_monitor, "monitor");
+}
uint8_t n;
__critical for (;;) {
+ ao_panic_delay(20);
for (n = 0; n < 5; n++) {
ao_led_on(AO_LED_RED);
ao_beep(AO_BEEP_HIGH);
}
ao_beep(AO_BEEP_OFF);
ao_panic_delay(2);
+#pragma disable_warning 126
for (n = 0; n < reason; n++) {
ao_led_on(AO_LED_RED);
ao_beep(AO_BEEP_MID);
ao_beep(AO_BEEP_OFF);
ao_panic_delay(10);
}
- ao_panic_delay(20);
}
}
--- /dev/null
+/*
+ * Copyright © 2009 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.
+ */
+
+#include "ao.h"
+
+/* Values from SmartRF® Studio for:
+ *
+ * Deviation: 20.507812 kHz
+ * Datarate: 38.360596 kBaud
+ * Modulation: GFSK
+ * RF Freq: 434.549927 MHz
+ * Channel: 99.975586 kHz
+ * Channel: 0
+ * RX filter: 93.75 kHz
+ */
+
+/*
+ * For 434.550MHz, the frequency value is:
+ *
+ * 434.550e6 / (24e6 / 2**16) = 1186611.2
+ */
+
+#define FREQ_CONTROL 1186611
+
+/*
+ * For IF freq of 140.62kHz, the IF value is:
+ *
+ * 140.62e3 / (24e6 / 2**10) = 6
+ */
+
+#define IF_FREQ_CONTROL 6
+
+/*
+ * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are
+ *
+ * BW = 24e6 / (8 * (4 + M) * 2 ** E)
+ *
+ * So, M = 0 and E = 3
+ */
+
+#define CHANBW_M 0
+#define CHANBW_E 3
+
+/*
+ * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are:
+ *
+ * R = (256 + M) * 2** E * 24e6 / 2**28
+ *
+ * So M is 163 and E is 10
+ */
+
+#define DRATE_E 10
+#define DRATE_M 163
+
+/*
+ * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are:
+ *
+ * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E
+ *
+ * So M is 6 and E is 3
+ */
+
+#define DEVIATION_M 6
+#define DEVIATION_E 3
+
+/* This are from the table for 433MHz */
+
+#define RF_POWER_M30_DBM 0x12
+#define RF_POWER_M20_DBM 0x0e
+#define RF_POWER_M15_DBM 0x1d
+#define RF_POWER_M10_DBM 0x34
+#define RF_POWER_M5_DBM 0x2c
+#define RF_POWER_0_DBM 0x60
+#define RF_POWER_5_DBM 0x84
+#define RF_POWER_7_DBM 0xc8
+#define RF_POWER_10_DBM 0xc0
+
+#define RF_POWER RF_POWER_0_DBM
+
+static __code uint8_t radio_setup[] = {
+ RF_PA_TABLE7_OFF, RF_POWER,
+ RF_PA_TABLE6_OFF, RF_POWER,
+ RF_PA_TABLE5_OFF, RF_POWER,
+ RF_PA_TABLE4_OFF, RF_POWER,
+ RF_PA_TABLE3_OFF, RF_POWER,
+ RF_PA_TABLE2_OFF, RF_POWER,
+ RF_PA_TABLE1_OFF, RF_POWER,
+ RF_PA_TABLE0_OFF, RF_POWER,
+
+ RF_FREQ2_OFF, (FREQ_CONTROL >> 16) & 0xff,
+ RF_FREQ1_OFF, (FREQ_CONTROL >> 8) & 0xff,
+ RF_FREQ0_OFF, (FREQ_CONTROL >> 0) & 0xff,
+
+ RF_FSCTRL1_OFF, (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT),
+ RF_FSCTRL0_OFF, (0 << RF_FSCTRL0_FREQOFF_SHIFT),
+
+ RF_MDMCFG4_OFF, ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+ (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+ (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+ RF_MDMCFG3_OFF, (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+ RF_MDMCFG2_OFF, (RF_MDMCFG2_DEM_DCFILT_OFF |
+ RF_MDMCFG2_MOD_FORMAT_GFSK |
+ RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+ RF_MDMCFG1_OFF, (RF_MDMCFG1_FEC_EN |
+ RF_MDMCFG1_NUM_PREAMBLE_4 |
+ (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+ RF_MDMCFG0_OFF, (17 << RF_MDMCFG0_CHANSPC_M_SHIFT),
+
+ RF_CHANNR_OFF, 0,
+
+ RF_DEVIATN_OFF, ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+ (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+
+ /* SmartRF says set LODIV_BUF_CURRENT_TX to 0
+ * And, we're not using power ramping, so use PA_POWER 0
+ */
+ RF_FREND0_OFF, ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) |
+ (0 << RF_FREND0_PA_POWER_SHIFT)),
+
+ RF_FREND1_OFF, ((1 << RF_FREND1_LNA_CURRENT_SHIFT) |
+ (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) |
+ (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) |
+ (2 << RF_FREND1_MIX_CURRENT_SHIFT)),
+
+ RF_FSCAL3_OFF, 0xE9,
+ RF_FSCAL2_OFF, 0x0A,
+ RF_FSCAL1_OFF, 0x00,
+ RF_FSCAL0_OFF, 0x1F,
+
+ RF_TEST2_OFF, 0x88,
+ RF_TEST1_OFF, 0x31,
+ RF_TEST0_OFF, 0x09,
+
+ /* default sync values */
+ RF_SYNC1_OFF, 0xD3,
+ RF_SYNC0_OFF, 0x91,
+
+ /* max packet length */
+ RF_PKTLEN_OFF, sizeof (struct ao_telemetry),
+
+ RF_PKTCTRL1_OFF, ((1 << PKTCTRL1_PQT_SHIFT)|
+ PKTCTRL1_APPEND_STATUS|
+ PKTCTRL1_ADR_CHK_NONE),
+ RF_PKTCTRL0_OFF, (RF_PKTCTRL0_WHITE_DATA|
+ RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+ RF_PKTCTRL0_CRC_EN|
+ RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+ RF_ADDR_OFF, 0x00,
+ RF_MCSM2_OFF, (RF_MCSM2_RX_TIME_END_OF_PACKET),
+ RF_MCSM1_OFF, (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING|
+ RF_MCSM1_RXOFF_MODE_IDLE|
+ RF_MCSM1_TXOFF_MODE_IDLE),
+ RF_MCSM0_OFF, (RF_MCSM0_FS_AUTOCAL_FROM_IDLE|
+ RF_MCSM0_MAGIC_3|
+ RF_MCSM0_CLOSE_IN_RX_0DB),
+ RF_FOCCFG_OFF, (RF_FOCCFG_FOC_PRE_K_3K,
+ RF_FOCCFG_FOC_POST_K_PRE_K,
+ RF_FOCCFG_FOC_LIMIT_BW_OVER_4),
+ RF_BSCFG_OFF, (RF_BSCFG_BS_PRE_K_2K|
+ RF_BSCFG_BS_PRE_KP_3KP|
+ RF_BSCFG_BS_POST_KI_PRE_KI|
+ RF_BSCFG_BS_POST_KP_PRE_KP|
+ RF_BSCFG_BS_LIMIT_0),
+ RF_AGCCTRL2_OFF, 0x43,
+ RF_AGCCTRL1_OFF, 0x40,
+ RF_AGCCTRL0_OFF, 0x91,
+
+ RF_IOCFG2_OFF, 0x00,
+ RF_IOCFG1_OFF, 0x00,
+ RF_IOCFG0_OFF, 0x00,
+};
+
+__xdata uint8_t ao_radio_dma;
+__xdata uint8_t ao_radio_dma_done;
+__xdata uint8_t ao_radio_mutex;
+
+static void
+ao_radio_idle(void)
+{
+ if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
+ {
+ RFST = RFST_SIDLE;
+ do {
+ ao_yield();
+ } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
+ }
+}
+
+void
+ao_radio_send(__xdata struct ao_telemetry *telemetry) __reentrant
+{
+ ao_mutex_get(&ao_radio_mutex);
+ ao_radio_idle();
+ ao_dma_set_transfer(ao_radio_dma,
+ telemetry,
+ &RFDXADDR,
+ sizeof (struct ao_telemetry),
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_1 |
+ DMA_CFG1_DESTINC_0 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_STX;
+ while (!ao_radio_dma_done)
+ ao_sleep(&ao_radio_dma_done);
+ ao_mutex_put(&ao_radio_mutex);
+}
+
+void
+ao_radio_recv(__xdata struct ao_radio_recv *radio) __reentrant
+{
+ ao_mutex_get(&ao_radio_mutex);
+ ao_radio_idle();
+ ao_dma_set_transfer(ao_radio_dma,
+ &RFDXADDR,
+ radio,
+ sizeof (struct ao_radio_recv),
+ DMA_CFG0_WORDSIZE_8 |
+ DMA_CFG0_TMODE_SINGLE |
+ DMA_CFG0_TRIGGER_RADIO,
+ DMA_CFG1_SRCINC_0 |
+ DMA_CFG1_DESTINC_1 |
+ DMA_CFG1_PRIORITY_HIGH);
+ ao_dma_start(ao_radio_dma);
+ RFST = RFST_SRX;
+ while (!ao_radio_dma_done)
+ ao_sleep(&ao_radio_dma_done);
+ ao_mutex_put(&ao_radio_mutex);
+}
+
+void
+ao_radio_init(void)
+{
+ uint8_t i;
+ for (i = 0; i < sizeof (radio_setup); i += 2)
+ RF[radio_setup[i]] = radio_setup[i+1];
+ ao_radio_dma_done = 1;
+ ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
+}
+
pause(AO_MS_TO_TICKS(400));
}
-void
-ao_report_notify(void)
-{
- ao_wakeup(&ao_report_state);
-}
-
void
ao_report(void)
{
ao_report_beep();
__critical {
while (ao_report_state == ao_flight_state)
- ao_sleep(&ao_report_state);
+ ao_sleep(DATA_TO_XDATA(&ao_flight_state));
ao_report_state = ao_flight_state;
}
}
ao_serial_tx1_start();
}
+static void
+send_serial(void)
+{
+ ao_cmd_white();
+ while (ao_cmd_lex_c != '\n') {
+ ao_serial_putchar(ao_cmd_lex_c);
+ ao_cmd_lex();
+ }
+}
+
+__code struct ao_cmds ao_serial_cmds[] = {
+ { 'S', send_serial, "S<data> Send data to serial line\n" },
+ { 0, send_serial, NULL },
+};
+
void
ao_serial_init(void)
{
IEN0 |= IEN0_URX1IE;
IEN2 |= IEN2_UTX1IE;
+
+ ao_cmd_register(&ao_serial_cmds[0]);
}
--- /dev/null
+/*
+ * Copyright © 2009 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.
+ */
+
+#include "ao.h"
+
+/*
+ * Basic I/O functions to support SDCC stdio package
+ */
+
+void
+putchar(char c)
+{
+ if (c == '\n')
+ ao_usb_putchar('\r');
+ ao_usb_putchar((uint8_t) c);
+}
+
+void
+flush(void)
+{
+ ao_usb_flush();
+}
+
+char
+getchar(void)
+{
+ return (char) ao_usb_getchar();
+}
_endasm;
}
-int
+void
ao_sleep(__xdata void *wchan)
{
__critical {
- ao_cur_task->wchan = wchan;
+ ao_cur_task->wchan = wchan;
}
ao_yield();
}
-int
+void
ao_wakeup(__xdata void *wchan)
{
uint8_t i;
--- /dev/null
+/*
+ * Copyright © 2009 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.
+ */
+
+#include "ao.h"
+
+void
+main(void)
+{
+ CLKCON = 0;
+ while (!(SLEEP & SLEEP_XOSC_STB))
+ ;
+
+ /* Turn on the red LED until the system is stable */
+ ao_led_init();
+ ao_led_on(AO_LED_RED);
+
+ ao_timer_init();
+ ao_adc_init();
+ ao_beep_init();
+ ao_cmd_init();
+ ao_ee_init();
+ ao_flight_init();
+ ao_log_init();
+ ao_report_init();
+ ao_usb_init();
+ ao_serial_init();
+ ao_gps_init();
+ ao_telemetry_init();
+ ao_radio_init();
+ ao_start_scheduler();
+}
--- /dev/null
+/*
+ * Copyright © 2009 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.
+ */
+
+#include "ao.h"
+
+/* XXX make serial numbers real */
+
+uint8_t ao_serial_number = 2;
+
+void
+ao_telemetry_send(__xdata struct ao_telemetry *telemetry) __reentrant
+{
+ if (ao_flight_state != ao_flight_idle && ao_flight_state != ao_flight_startup) {
+ telemetry->addr = ao_serial_number;
+ telemetry->flight_state = ao_flight_state;
+ ao_radio_send(telemetry);
+ }
+}
+
+void
+ao_telemetry(void)
+{
+ static __xdata struct ao_radio_recv recv;
+ static uint8_t state;
+
+ while (ao_flight_state == ao_flight_startup || ao_flight_state == ao_flight_idle)
+ ao_sleep(DATA_TO_XDATA(&ao_flight_state));
+
+ recv.telemetry.type = AO_TELEMETRY_SENSOR;
+ for (;;) {
+ ao_adc_get(&recv.telemetry.u.adc);
+ ao_telemetry_send(&recv.telemetry);
+ ao_delay(AO_MS_TO_TICKS(1000));
+ }
+}
+
+__xdata struct ao_task ao_telemetry_task;
+
+void
+ao_telemetry_init()
+{
+ ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry");
+}
--- /dev/null
+/*
+ * Copyright © 2009 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.
+ */
+
+#define AO_NO_SERIAL_ISR 1
+#define AO_NO_ADC_ISR 1
+#include "ao.h"
+
+void
+main(void)
+{
+ CLKCON = 0;
+ while (!(SLEEP & SLEEP_XOSC_STB))
+ ;
+
+ /* Turn on the LED until the system is stable */
+ ao_led_init();
+ ao_led_on(AO_LED_RED);
+ ao_timer_init();
+ ao_cmd_init();
+ ao_usb_init();
+ ao_monitor_init();
+ ao_radio_init();
+ ao_start_scheduler();
+}
+
+/* Stub for systems which have no ADC */
+void
+ao_adc_poll(void)
+{
+}
#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */
#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */
-__data uint8_t ao_adc_interval = 1;
-__data uint8_t ao_adc_count;
+volatile __data uint8_t ao_adc_interval = 1;
+volatile __data uint8_t ao_adc_count;
void ao_timer_isr(void) interrupt 9
{
ao_wakeup(DATA_TO_XDATA(&ao_tick_count));
}
+void
+ao_timer_set_adc_interval(uint8_t interval) __critical
+{
+ ao_adc_interval = interval;
+}
+
void
ao_timer_init(void)
{
/* set the sample rate */
T1CC0H = T1_SAMPLE_TIME >> 8;
- T1CC0L = T1_SAMPLE_TIME;
+ T1CC0L = (uint8_t) T1_SAMPLE_TIME;
T1CCTL0 = T1CCTL_MODE_COMPARE;
T1CCTL1 = 0;
USBCS0 = cs0;
}
-#define LE_WORD(x) ((x)&0xFF),((x)>>8)
+#define LE_WORD(x) ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
/* CDC definitions */
#define CS_INTERFACE 0x24
}
break;
case AO_USB_RECIP_INTERFACE:
+ #pragma disable_warning 110
switch(ao_usb_setup.request) {
case AO_USB_REQ_GET_STATUS:
ao_usb_ep0_queue_byte(0);
sfr at 0xc2 U0BAUD;
sfr at 0xfa U1BAUD;
+/* Radio */
+
+sfr at 0xD9 RFD;
+__xdata at (0xDFD9) volatile uint8_t RFDXADDR;
+
+sfr at 0xE9 RFIF;
+#define RFIF_IM_TXUNF (1 << 7)
+#define RFIF_IM_RXOVF (1 << 6)
+#define RFIF_IM_TIMEOUT (1 << 5)
+#define RFIF_IM_DONE (1 << 4)
+#define RFIF_IM_CS (1 << 3)
+#define RFIF_IM_PQT (1 << 2)
+#define RFIF_IM_CCA (1 << 1)
+#define RFIF_IM_SFD (1 << 0)
+
+sfr at 0xE1 RFST;
+
+#define RFST_SFSTXON 0x00
+#define RFST_SCAL 0x01
+#define RFST_SRX 0x02
+#define RFST_STX 0x03
+#define RFST_SIDLE 0x04
+
+__xdata __at (0xdf00) uint8_t RF[0x3c];
+
+__xdata __at (0xdf2f) uint8_t RF_IOCFG2;
+#define RF_IOCFG2_OFF 0x2f
+
+__xdata __at (0xdf30) uint8_t RF_IOCFG1;
+#define RF_IOCFG1_OFF 0x30
+
+__xdata __at (0xdf31) uint8_t RF_IOCFG0;
+#define RF_IOCFG0_OFF 0x31
+
+__xdata __at (0xdf00) uint8_t RF_SYNC1;
+#define RF_SYNC1_OFF 0x00
+
+__xdata __at (0xdf01) uint8_t RF_SYNC0;
+#define RF_SYNC0_OFF 0x01
+
+__xdata __at (0xdf02) uint8_t RF_PKTLEN;
+#define RF_PKTLEN_OFF 0x02
+
+__xdata __at (0xdf03) uint8_t RF_PKTCTRL1;
+#define RF_PKTCTRL1_OFF 0x03
+#define PKTCTRL1_PQT_MASK (0x7 << 5)
+#define PKTCTRL1_PQT_SHIFT 5
+#define PKTCTRL1_APPEND_STATUS (1 << 2)
+#define PKTCTRL1_ADR_CHK_NONE (0 << 0)
+#define PKTCTRL1_ADR_CHK_NO_BROADCAST (1 << 0)
+#define PKTCTRL1_ADR_CHK_00_BROADCAST (2 << 0)
+#define PKTCTRL1_ADR_CHK_00_FF_BROADCAST (3 << 0)
+
+/* If APPEND_STATUS is used, two bytes will be added to the packet data */
+#define PKT_APPEND_STATUS_0_RSSI_MASK (0xff)
+#define PKT_APPEND_STATUS_0_RSSI_SHIFT 0
+#define PKT_APPEND_STATUS_1_CRC_OK (1 << 7)
+#define PKT_APPEND_STATUS_1_LQI_MASK (0x7f)
+#define PKT_APPEND_STATUS_1_LQI_SHIFT 0
+
+__xdata __at (0xdf04) uint8_t RF_PKTCTRL0;
+#define RF_PKTCTRL0_OFF 0x04
+#define RF_PKTCTRL0_WHITE_DATA (1 << 6)
+#define RF_PKTCTRL0_PKT_FORMAT_NORMAL (0 << 4)
+#define RF_PKTCTRL0_PKT_FORMAT_RANDOM (2 << 4)
+#define RF_PKTCTRL0_CRC_EN (1 << 2)
+#define RF_PKTCTRL0_LENGTH_CONFIG_FIXED (0 << 0)
+#define RF_PKTCTRL0_LENGTH_CONFIG_VARIABLE (1 << 0)
+
+__xdata __at (0xdf05) uint8_t RF_ADDR;
+#define RF_ADDR_OFF 0x05
+
+__xdata __at (0xdf06) uint8_t RF_CHANNR;
+#define RF_CHANNR_OFF 0x06
+
+__xdata __at (0xdf07) uint8_t RF_FSCTRL1;
+#define RF_FSCTRL1_OFF 0x07
+
+#define RF_FSCTRL1_FREQ_IF_SHIFT (0)
+
+__xdata __at (0xdf08) uint8_t RF_FSCTRL0;
+#define RF_FSCTRL0_OFF 0x08
+
+#define RF_FSCTRL0_FREQOFF_SHIFT (0)
+
+__xdata __at (0xdf09) uint8_t RF_FREQ2;
+#define RF_FREQ2_OFF 0x09
+
+__xdata __at (0xdf0a) uint8_t RF_FREQ1;
+#define RF_FREQ1_OFF 0x0a
+
+__xdata __at (0xdf0b) uint8_t RF_FREQ0;
+#define RF_FREQ0_OFF 0x0b
+
+__xdata __at (0xdf0c) uint8_t RF_MDMCFG4;
+#define RF_MDMCFG4_OFF 0x0c
+
+#define RF_MDMCFG4_CHANBW_E_SHIFT 6
+#define RF_MDMCFG4_CHANBW_M_SHIFT 4
+#define RF_MDMCFG4_DRATE_E_SHIFT 0
+
+__xdata __at (0xdf0d) uint8_t RF_MDMCFG3;
+#define RF_MDMCFG3_OFF 0x0d
+
+#define RF_MDMCFG3_DRATE_M_SHIFT 0
+
+__xdata __at (0xdf0e) uint8_t RF_MDMCFG2;
+#define RF_MDMCFG2_OFF 0x0e
+
+#define RF_MDMCFG2_DEM_DCFILT_OFF (1 << 7)
+#define RF_MDMCFG2_DEM_DCFILT_ON (0 << 7)
+
+#define RF_MDMCFG2_MOD_FORMAT_MASK (7 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_2_FSK (0 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_GFSK (1 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_ASK_OOK (3 << 4)
+#define RF_MDMCFG2_MOD_FORMAT_MSK (7 << 4)
+
+#define RF_MDMCFG2_MANCHESTER_EN (1 << 3)
+
+#define RF_MDMCFG2_SYNC_MODE_MASK (0x7 << 0)
+#define RF_MDMCFG2_SYNC_MODE_NONE (0x0 << 0)
+#define RF_MDMCFG2_SYNC_MODE_15_16 (0x1 << 0)
+#define RF_MDMCFG2_SYNC_MODE_16_16 (0x2 << 0)
+#define RF_MDMCFG2_SYNC_MODE_30_32 (0x3 << 0)
+#define RF_MDMCFG2_SYNC_MODE_NONE_THRES (0x4 << 0)
+#define RF_MDMCFG2_SYNC_MODE_15_16_THRES (0x5 << 0)
+#define RF_MDMCFG2_SYNC_MODE_16_16_THRES (0x6 << 0)
+#define RF_MDMCFG2_SYNC_MODE_30_32_THRES (0x7 << 0)
+
+__xdata __at (0xdf0f) uint8_t RF_MDMCFG1;
+#define RF_MDMCFG1_OFF 0x0f
+
+#define RF_MDMCFG1_FEC_EN (1 << 7)
+#define RF_MDMCFG1_FEC_DIS (0 << 7)
+
+#define RF_MDMCFG1_NUM_PREAMBLE_MASK (7 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_2 (0 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_3 (1 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_4 (2 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_6 (3 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_8 (4 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_12 (5 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_16 (6 << 4)
+#define RF_MDMCFG1_NUM_PREAMBLE_24 (7 << 4)
+
+#define RF_MDMCFG1_CHANSPC_E_MASK (3 << 0)
+#define RF_MDMCFG1_CHANSPC_E_SHIFT (0)
+
+__xdata __at (0xdf10) uint8_t RF_MDMCFG0;
+#define RF_MDMCFG0_OFF 0x10
+
+#define RF_MDMCFG0_CHANSPC_M_SHIFT (0)
+
+__xdata __at (0xdf11) uint8_t RF_DEVIATN;
+#define RF_DEVIATN_OFF 0x11
+
+#define RF_DEVIATN_DEVIATION_E_SHIFT 4
+#define RF_DEVIATN_DEVIATION_M_SHIFT 0
+
+__xdata __at (0xdf12) uint8_t RF_MCSM2;
+#define RF_MCSM2_OFF 0x12
+#define RF_MCSM2_RX_TIME_RSSI (1 << 4)
+#define RF_MCSM2_RX_TIME_QUAL (1 << 3)
+#define RF_MCSM2_RX_TIME_MASK (0x7)
+#define RF_MCSM2_RX_TIME_SHIFT 0
+#define RF_MCSM2_RX_TIME_END_OF_PACKET (7)
+
+__xdata __at (0xdf13) uint8_t RF_MCSM1;
+#define RF_MCSM1_OFF 0x13
+#define RF_MCSM1_CCA_MODE_ALWAYS (0 << 4)
+#define RF_MCSM1_CCA_MODE_RSSI_BELOW (1 << 4)
+#define RF_MCSM1_CCA_MODE_UNLESS_RECEIVING (2 << 4)
+#define RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING (3 << 4)
+#define RF_MCSM1_RXOFF_MODE_IDLE (0 << 2)
+#define RF_MCSM1_RXOFF_MODE_FSTXON (1 << 2)
+#define RF_MCSM1_RXOFF_MODE_TX (2 << 2)
+#define RF_MCSM1_RXOFF_MODE_RX (3 << 2)
+#define RF_MCSM1_TXOFF_MODE_IDLE (0 << 0)
+#define RF_MCSM1_TXOFF_MODE_FSTXON (1 << 0)
+#define RF_MCSM1_TXOFF_MODE_TX (2 << 0)
+#define RF_MCSM1_TXOFF_MODE_RX (3 << 0)
+
+__xdata __at (0xdf14) uint8_t RF_MCSM0;
+#define RF_MCSM0_OFF 0x14
+#define RF_MCSM0_FS_AUTOCAL_NEVER (0 << 4)
+#define RF_MCSM0_FS_AUTOCAL_FROM_IDLE (1 << 4)
+#define RF_MCSM0_FS_AUTOCAL_TO_IDLE (2 << 4)
+#define RF_MCSM0_FS_AUTOCAL_TO_IDLE_EVERY_4 (3 << 4)
+#define RF_MCSM0_MAGIC_3 (1 << 3)
+#define RF_MCSM0_MAGIC_2 (1 << 2)
+#define RF_MCSM0_CLOSE_IN_RX_0DB (0 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_6DB (1 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_12DB (2 << 0)
+#define RF_MCSM0_CLOSE_IN_RX_18DB (3 << 0)
+
+__xdata __at (0xdf15) uint8_t RF_FOCCFG;
+#define RF_FOCCFG_OFF 0x15
+#define RF_FOCCFG_FOC_BS_CS_GATE (1 << 5)
+#define RF_FOCCFG_FOC_PRE_K_1K (0 << 3)
+#define RF_FOCCFG_FOC_PRE_K_2K (1 << 3)
+#define RF_FOCCFG_FOC_PRE_K_3K (2 << 3)
+#define RF_FOCCFG_FOC_PRE_K_4K (3 << 3)
+#define RF_FOCCFG_FOC_POST_K_PRE_K (0 << 2)
+#define RF_FOCCFG_FOC_POST_K_PRE_K_OVER_2 (1 << 2)
+#define RF_FOCCFG_FOC_LIMIT_0 (0 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_8 (1 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_4 (2 << 0)
+#define RF_FOCCFG_FOC_LIMIT_BW_OVER_2 (3 << 0)
+
+__xdata __at (0xdf16) uint8_t RF_BSCFG;
+#define RF_BSCFG_OFF 0x16
+#define RF_BSCFG_BS_PRE_K_1K (0 << 6)
+#define RF_BSCFG_BS_PRE_K_2K (1 << 6)
+#define RF_BSCFG_BS_PRE_K_3K (2 << 6)
+#define RF_BSCFG_BS_PRE_K_4K (3 << 6)
+#define RF_BSCFG_BS_PRE_KP_1KP (0 << 4)
+#define RF_BSCFG_BS_PRE_KP_2KP (1 << 4)
+#define RF_BSCFG_BS_PRE_KP_3KP (2 << 4)
+#define RF_BSCFG_BS_PRE_KP_4KP (3 << 4)
+#define RF_BSCFG_BS_POST_KI_PRE_KI (0 << 3)
+#define RF_BSCFG_BS_POST_KI_PRE_KI_OVER_2 (1 << 3)
+#define RF_BSCFG_BS_POST_KP_PRE_KP (0 << 2)
+#define RF_BSCFG_BS_POST_KP_PRE_KP_OVER_2 (1 << 2)
+#define RF_BSCFG_BS_LIMIT_0 (0 << 0)
+#define RF_BSCFG_BS_LIMIT_3_125 (1 << 0)
+#define RF_BSCFG_BS_LIMIT_6_25 (2 << 0)
+#define RF_BSCFG_BS_LIMIT_12_5 (3 << 0)
+
+__xdata __at (0xdf17) uint8_t RF_AGCCTRL2;
+#define RF_AGCCTRL2_OFF 0x17
+
+__xdata __at (0xdf18) uint8_t RF_AGCCTRL1;
+#define RF_AGCCTRL1_OFF 0x18
+
+__xdata __at (0xdf19) uint8_t RF_AGCCTRL0;
+#define RF_AGCCTRL0_OFF 0x19
+
+__xdata __at (0xdf1a) uint8_t RF_FREND1;
+#define RF_FREND1_OFF 0x1a
+
+#define RF_FREND1_LNA_CURRENT_SHIFT 6
+#define RF_FREND1_LNA2MIX_CURRENT_SHIFT 4
+#define RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT 2
+#define RF_FREND1_MIX_CURRENT_SHIFT 0
+
+__xdata __at (0xdf1b) uint8_t RF_FREND0;
+#define RF_FREND0_OFF 0x1b
+
+#define RF_FREND0_LODIV_BUF_CURRENT_TX_MASK (0x3 << 4)
+#define RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT 4
+#define RF_FREND0_PA_POWER_MASK (0x7)
+#define RF_FREND0_PA_POWER_SHIFT 0
+
+__xdata __at (0xdf1c) uint8_t RF_FSCAL3;
+#define RF_FSCAL3_OFF 0x1c
+
+__xdata __at (0xdf1d) uint8_t RF_FSCAL2;
+#define RF_FSCAL2_OFF 0x1d
+
+__xdata __at (0xdf1e) uint8_t RF_FSCAL1;
+#define RF_FSCAL1_OFF 0x1e
+
+__xdata __at (0xdf1f) uint8_t RF_FSCAL0;
+#define RF_FSCAL0_OFF 0x1f
+
+__xdata __at (0xdf23) uint8_t RF_TEST2;
+#define RF_TEST2_OFF 0x23
+
+#define RF_TEST2_NORMAL_MAGIC 0x88
+#define RF_TEST2_RX_LOW_DATA_RATE_MAGIC 0x81
+
+__xdata __at (0xdf24) uint8_t RF_TEST1;
+#define RF_TEST1_OFF 0x24
+
+#define RF_TEST1_TX_MAGIC 0x31
+#define RF_TEST1_RX_LOW_DATA_RATE_MAGIC 0x35
+
+__xdata __at (0xdf25) uint8_t RF_TEST0;
+#define RF_TEST0_OFF 0x25
+
+#define RF_TEST0_7_2_MASK (0xfc)
+#define RF_TEST0_VCO_SEL_CAL_EN (1 << 1)
+#define RF_TEST0_0_MASK (1)
+
+/* These are undocumented, and must be computed
+ * using the provided tool.
+ */
+__xdata __at (0xdf27) uint8_t RF_PA_TABLE7;
+#define RF_PA_TABLE7_OFF 0x27
+
+__xdata __at (0xdf28) uint8_t RF_PA_TABLE6;
+#define RF_PA_TABLE6_OFF 0x28
+
+__xdata __at (0xdf29) uint8_t RF_PA_TABLE5;
+#define RF_PA_TABLE5_OFF 0x29
+
+__xdata __at (0xdf2a) uint8_t RF_PA_TABLE4;
+#define RF_PA_TABLE4_OFF 0x2a
+
+__xdata __at (0xdf2b) uint8_t RF_PA_TABLE3;
+#define RF_PA_TABLE3_OFF 0x2b
+
+__xdata __at (0xdf2c) uint8_t RF_PA_TABLE2;
+#define RF_PA_TABLE2_OFF 0x2c
+
+__xdata __at (0xdf2d) uint8_t RF_PA_TABLE1;
+#define RF_PA_TABLE1_OFF 0x2d
+
+__xdata __at (0xdf2e) uint8_t RF_PA_TABLE0;
+#define RF_PA_TABLE0_OFF 0x2e
+
+__xdata __at (0xdf36) uint8_t RF_PARTNUM;
+#define RF_PARTNUM_OFF 0x36
+
+__xdata __at (0xdf37) uint8_t RF_VERSION;
+#define RF_VERSION_OFF 0x37
+
+__xdata __at (0xdf38) uint8_t RF_FREQEST;
+#define RF_FREQEST_OFF 0x38
+
+__xdata __at (0xdf39) uint8_t RF_LQI;
+#define RF_LQI_OFF 0x39
+
+#define RF_LQI_CRC_OK (1 << 7)
+#define RF_LQI_LQI_EST_MASK (0x7f)
+
+__xdata __at (0xdf3a) uint8_t RF_RSSI;
+#define RF_RSSI_OFF 0x3a
+
+__xdata __at (0xdf3b) uint8_t RF_MARCSTATE;
+#define RF_MARCSTATE_OFF 0x3b
+
+#define RF_MARCSTATE_MASK 0x1f
+#define RF_MARCSTATE_SLEEP 0x00
+#define RF_MARCSTATE_IDLE 0x01
+#define RF_MARCSTATE_VCOON_MC 0x03
+#define RF_MARCSTATE_REGON_MC 0x04
+#define RF_MARCSTATE_MANCAL 0x05
+#define RF_MARCSTATE_VCOON 0x06
+#define RF_MARCSTATE_REGON 0x07
+#define RF_MARCSTATE_STARTCAL 0x08
+#define RF_MARCSTATE_BWBOOST 0x09
+#define RF_MARCSTATE_FS_LOCK 0x0a
+#define RF_MARCSTATE_IFADCON 0x0b
+#define RF_MARCSTATE_ENDCAL 0x0c
+#define RF_MARCSTATE_RX 0x0d
+#define RF_MARCSTATE_RX_END 0x0e
+#define RF_MARCSTATE_RX_RST 0x0f
+#define RF_MARCSTATE_TXRX_SWITCH 0x10
+#define RF_MARCSTATE_RX_OVERFLOW 0x11
+#define RF_MARCSTATE_FSTXON 0x12
+#define RF_MARCSTATE_TX 0x13
+#define RF_MARCSTATE_TX_END 0x14
+#define RF_MARCSTATE_RXTX_SWITCH 0x15
+#define RF_MARCSTATE_TX_UNDERFLOW 0x16
+
+
+__xdata __at (0xdf3c) uint8_t RF_PKTSTATUS;
+#define RF_PKTSTATUS_OFF 0x3c
+
+#define RF_PKTSTATUS_CRC_OK (1 << 7)
+#define RF_PKTSTATUS_CS (1 << 6)
+#define RF_PKTSTATUS_PQT_REACHED (1 << 5)
+#define RF_PKTSTATUS_CCA (1 << 4)
+#define RF_PKTSTATUS_SFD (1 << 3)
+
+__xdata __at (0xdf3d) uint8_t RF_VCO_VC_DAC;
+#define RF_VCO_VC_DAC_OFF 0x3d
+
#endif
HEADER=$1
MEM=$2
-HEADER_STACK=`awk '/#define AO_STACK_START/ {print $3}' $HEADER`
-MEM_STACK=`awk '/Stack starts at/ {print $4}' $MEM`
+HEADER_STACK=`awk '/#define AO_STACK_START/ {print $3}' $HEADER | nickle`
+MEM_STACK=`awk '/Stack starts at/ {print $4}' $MEM | nickle`
-if [ "$HEADER_STACK" != "$MEM_STACK" ]; then
- echo "Set AO_STACK_START to $MEM_STACK"
+if [ "$HEADER_STACK" -lt "$MEM_STACK" ]; then
+ echo "Set AO_STACK_START to at least $MEM_STACK"
exit 1
else
exit 0